21

SSLソケット接続をセットアップしようとしています(そしてクライアントで次のことを行っています)

  1. 署名されたクライアント証明書を取得するために証明書署名要求を生成します

  2. これで、秘密鍵(CSR中に使用)、署名されたクライアント証明書、およびルート証明書(帯域外で取得)ができました。

  3. 秘密鍵と署名されたクライアント証明書を証明書チェーンに追加し、それを鍵マネージャーに追加します。トラストマネージャーへのルート証明書。しかし、私は悪い証明書エラーを受け取ります。

私は正しい証明書を使用していると確信しています。署名されたクライアント証明書をトラストマネージャーにも追加する必要がありますか?それを試してみましたが、まだ運がありません。

//I add the private key and the client cert to KeyStore ks
FileInputStream certificateStream = new FileInputStream(clientCertFile);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
java.security.cert.Certificate[] chain = {};
chain = certificateFactory.generateCertificates(certificateStream).toArray(chain);
certificateStream.close();
String privateKeyEntryPassword = "123";
ks.setEntry("abc", new KeyStore.PrivateKeyEntry(privateKey, chain),
        new KeyStore.PasswordProtection(privateKeyEntryPassword.toCharArray()));

//Add the root certificate to keystore jks
FileInputStream is = new FileInputStream(new File(filename));
CertificateFactory cf = CertificateFactory.getInstance("X.509");
java.security.cert.X509Certificate cert = (X509Certificate) cf.generateCertificate(is);
System.out.println("Certificate Information: ");
System.out.println(cert.getSubjectDN().toString());
jks.setCertificateEntry(cert.getSubjectDN().toString(), cert);

//Initialize the keymanager and trustmanager and add them to the SSL context
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "123".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(jks);

ここで作成する必要のある証明書チェーンの種類はありますか?
これらのコンポーネントを備えたp12もあり、非常によく似たコードを使用して、キーマネージャーに秘密鍵を追加し、p12からトラストマネージャーにルート証明書を追加して、それを機能させることができました。しかし今、私はそれをp12なしで動作させる必要があります。

編集:スタックトレースが要求されました。これで十分だといいのですが。(注:ファイル名をマスクしました)

Caused by: javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1720)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:954)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1165)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1149)
at client.abc2.openSocketConnection(abc2.java:33)
at client.abc1.runClient(abc1.java:63)
at screens.app.abc.validateLogin(abc.java:197)
... 32 more
4

3 に答える 3

19

キーストアにもルート証明書を追加する必要があります。

于 2012-08-03T21:54:41.970 に答える
0

これらの2行を削除すると、このエラーが発生しました。キーストアに適切な証明書があることがわかっている場合は、コードが適切なキーストアを参照していることを確認してください。

System.setProperty("javax.net.ssl.keyStore", <keystorePath>));
System.setProperty("javax.net.ssl.keyStorePassword",<keystorePassword>));

私もこのVM引数が必要でした: -Djavax.net.ssl.trustStore=/app/certs/keystore.jk 詳細についてはここを参照してください: https ://stackoverflow.com/a/34311797/1308453

于 2017-06-29T22:38:43.390 に答える
-3

サーバー証明書が署名されて有効である場合は、通常どおり接続を開くだけで済みます。

import java.net.*;
import java.io.*;

public class URLConnectionReader {
    public static void main(String[] args) throws Exception {
        URL google = new URL("https://www.google.com/");
        URLConnection yc = google.openConnection();
        BufferedReader in = new BufferedReader(new InputStreamReader(
                                    yc.getInputStream()));
        String inputLine;
        while ((inputLine = in.readLine()) != null) 
            System.out.println(inputLine);
        in.close();
    }
}

URLには、SSLの使用を示すHTTPSスキーマがあることに注意してください。

サーバーの証明書が署名されているが、証明書にあるものとは異なるIPアドレス/ドメイン名を使用してアクセスしている場合は、次の方法でホスト名の検証をバイパスできます。

HostnameVerifier hv = new HostnameVerifier() {
    public boolean verify(String urlHostName,SSLSession session) {
        return true;
    }
};

HttpsURLConnection.setDefaultHostnameVerifier(hv);

証明書が署名されていない場合は、JVMで使用されるキーストアに証明書を追加する必要があります(便利なコマンド)。

于 2012-08-03T18:00:34.253 に答える