SSLソケット接続をセットアップしようとしています(クライアントで次のようにしています)
署名済みクライアント証明書を取得するための証明書署名要求を生成します
これで、秘密鍵(CSRで使用)、署名済みクライアント証明書、およびルート証明書(帯域外で取得)ができました。
秘密キーと署名済みクライアント証明書を証明書チェーンに追加し、それをキーマネージャーに追加します。信頼マネージャへのルート証明書。しかし、不正な証明書エラーが発生します。
私は正しい証明書を使用していると確信しています。署名済みクライアント証明書をトラストマネージャーにも追加する必要がありますか?それを試しましたが、まだ運がありません。
//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
ルート証明書もキーストアに追加する必要があります。
サーバー証明書が署名されていて有効であれば、通常どおり接続を開くだけで済みます。
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が使用するキーストアに証明書を追加する必要があります( 便利なコマンド )。
この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/130845