如何使用Java中的SSL和pkcs12文件连接到安全的网站?

我有一个pkcs12文件。 我需要使用它来使用https协议连接到网页。 我遇到了一些代码,为了连接到安全的网页,我需要设置以下系统属性:

System.setProperty("javax.net.ssl.trustStore", "myTrustStore"); System.setProperty("javax.net.ssl.trustStorePassword", "changeit"); System.setProperty("javax.net.ssl.keyStoreType", "pkcs12"); System.setProperty("javax.net.ssl.keyStore", "new_cert.p12"); System.setProperty("javax.net.ssl.keyStorePassword", "newpass"); 

我有p12(pkcs12)文件。 我只需要一个信任库文件。

我使用以下方法提取证书:

 openssl.exe pkcs12 -in c:/mykey.p12 -out c:/cert.txt -nokeys -clcerts 

现在将证书PEM文件转换为der

 openssl.exe x509 -in c:/cert.txt -outform DER -out c:/CAcert.der 

现在将der文件添加到密钥库

 keytool -import -file C:/Cacert.der -keystore mytruststore 

现在我有了信任库,但是当我使用它时,我收到以下错误

 Exception in thread "main" java.net.SocketException: java.security.NoSuchAlgorithmException: Error constructing implementation (algorithm: Default, provider: SunJSSE, class: com.sun.net.ssl.internal.ssl.DefaultSSLContextImpl) 

更新:删除某些属性并仅设置“trustStore”,“trustStorePassword”和“trustStoreType”属性后,我得到以下exception

 java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty 

请帮忙。

对于遇到类似情况的人,我能够解决上面的问题,如下所示:

  1. 按如下方式重新生成pkcs12文件:

     openssl pkcs12 -in oldpkcs.p12 -out keys -passout pass:tmp openssl pkcs12 -in keys -export -out new.p12 -passin pass:tmp -passout pass:newpasswd 
  2. 将CA证书从服务器导入TrustStore(您自己的,或$JAVA_HOME/jre/lib/security/cacerts的java密钥库,密码: changeit )。

  3. 设置以下系统属性:

     System.setProperty("javax.net.ssl.trustStore", "myTrustStore"); System.setProperty("javax.net.ssl.trustStorePassword", "changeit"); System.setProperty("javax.net.ssl.keyStoreType", "pkcs12"); System.setProperty("javax.net.ssl.keyStore", "new.p12"); System.setProperty("javax.net.ssl.keyStorePassword", "newpasswd"); 
  4. 测试你的url。

礼貌@ http://forums.sun.com/thread.jspa?threadID=5296333

由于50ps阈值,我无法发表评论,但我不认为https://stackoverflow.com/a/537344/1341220中提供的答案是正确的。 您实际描述的是如何将服务器证书插入系统默认信任库:

 $JAVA_HOME/jre/lib/security/cacerts, password: changeit) 

这确实有效,但这意味着您没有真正指定项目本地的信任存储,而是在系统中普遍接受该证书。

您实际上从未使用您在此处定义的自己的信任库:

 System.setProperty("javax.net.ssl.trustStore", "myTrustStore"); System.setProperty("javax.net.ssl.trustStorePassword", "changeit"); 

您似乎从PKCS#12密钥库中提取证书并创建新的Java密钥库(类型为“JKS”)。 您不必严格提供信任存储密码(尽管使用一个密码可以测试根证书的完整性)。

因此,尝试使用以下SSL属性设置的程序。 您的问题中显示的列表是过度指定的,可能会导致问题。

 System.setProperty("javax.net.ssl.trustStore", "myTrustStore"); System.setProperty("javax.net.ssl.trustStorePassword", "changeit"); 

此外,只要将CA证书检测为“受信任”条目,就可以将PKCS#12文件直接用作信任存储。 但在这种情况下,您还必须将javax.net.ssl.trustStoreType属性指定为"PKCS12"

请尝试使用这些属性。 如果你得到同样的错误,我怀疑你的问题不是密钥库。 如果仍然发生,请在问题中发布更多堆栈跟踪以缩小问题范围。


新错误“trustAnchors参数必须为非空”可能是由于将javax.net.ssl.trustStore属性设置为不存在的文件; 如果无法打开文件,则会创建一个空的密钥库,这会导致此错误。

这是一个仅使用p12文件的例子,它没有被优化但是它有效。 由我在OpenSSL生成的pkcs12文件。 示例如何从中加载p12文件并构建Trust区域…它从p12文件输出证书并向TrustStore添加好的证书

 KeyStore ks=KeyStore.getInstance("pkcs12"); ks.load(new FileInputStream("client_t_c1.p12"),"c1".toCharArray()); KeyStore jks=KeyStore.getInstance("JKS"); jks.load(null); for (Enumerationt=ks.aliases();t.hasMoreElements();) { String alias = t.nextElement(); System.out.println("@:" + alias); if (ks.isKeyEntry(alias)){ Certificate[] a = ks.getCertificateChain(alias); for (int i=0;i0) jks.setCertificateEntry(x509.getSubjectDN().toString(), x509); System.out.println(ks.getCertificateAlias(x509)); System.out.println("ok"); } } } System.out.println("init Stores..."); KeyManagerFactory kmf=KeyManagerFactory.getInstance("SunX509"); kmf.init(ks, "c1".toCharArray()); TrustManagerFactory tmf=TrustManagerFactory.getInstance("SunX509"); tmf.init(jks); SSLContext ctx = SSLContext.getInstance("TLS"); ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 

此示例显示如何在现有套接字上层叠SSL,从PKCS#12文件获取客户端证书。 当您需要通过代理连接到上游服务器并且希望自己处理完整协议时,这是合适的。

但是,基本上,一旦有了SSL上下文,就可以将它应用于HttpsURLConnection等。

 KeyStore ks = KeyStore.getInstance("PKCS12"); InputStream is = ...; char[] ksp = storePassword.toCharArray(); ks.load(is, ksp); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); char[] kp = keyPassword.toCharArray(); kmf.init(ks, kp); sslContext = SSLContext.getInstance("SSLv3"); sslContext.init(kmf.getKeyManagers(), null, null); SSLSocketFactory factory = sslContext.getSocketFactory(); SSLSocket sslsocket = (SSLSocket) factory.createSocket(socket, socket .getInetAddress().getHostName(), socket.getPort(), true); sslsocket.setUseClientMode(true); sslsocket.setSoTimeout(soTimeout); sslsocket.startHandshake(); 
 URL url = new URL("https://test.domain:443"); String keyStore = "server.p12" String keyStorePassword = "changeit"; String keyPassword = "changeit"; String KeyStoreType= "PKCS12"; String KeyManagerAlgorithm = "SunX509"; String SSLVersion = "SSLv3"; public HttpURLConnection getHttpsURLConnection(URL url, String keystore, String keyStorePass,String keyPassword, String KeyStoreType ,String KeyManagerAlgorithm, String SSLVersion) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, FileNotFoundException, IOException, UnrecoverableKeyException, KeyManagementException { System.setProperty("javax.net.debug","ssl,handshake,record"); SSLContext sslcontext = SSLContext.getInstance(SSLVersion); KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerAlgorithm); KeyStore ks = KeyStore.getInstance(KeyStoreType); ks.load(new FileInputStream(keystore), keyStorePass.toCharArray()); kmf.init(ks, keyPassword.toCharArray()); TrustManagerFactory tmf = TrustManagerFactory .getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); TrustManager[] tm = tmf.getTrustManagers(); sslcontext.init(kmf.getKeyManagers(), tm, null); SSLSocketFactory sslSocketFactory = sslcontext.getSocketFactory(); HttpsURLConnection.setDefaultSSLSocketFactory(sslSocketFactory); HttpsURLConnection httpsURLConnection = ( HttpsURLConnection)uRL.openConnection(); return httpsURLConnection; } 

以下步骤将帮助您解决问题。

步骤:developer_identity.cer <=从Apple mykey.p12下载<=您的私钥

要遵循的命令:

  openssl x509 -in developer_identity.cer -inform DER -out developer_identity.pem -outform PEM openssl pkcs12 -nocerts -in mykey.p12 -out mykey.pem openssl pkcs12 -export -inkey mykey.pem -in developer_identity.pem -out iphone_dev.p12 

我们需要的最终p12是iphone_dev.p12文件和密码。

使用此文件作为您的p12,然后尝试。 这确实是解决方案。:)

我意识到这篇文章可能已经过时,但我仍然想请smithsv纠正他的源代码,它包含很多错误,我设法纠正了大部分错误,但仍然不知道x509可能是什么样的对象。这里是我想的源代码应该是:

 import java.io.FileInputStream; import java.security.KeyStore; import java.security.cert.Certificate; import java.util.Enumeration; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManagerFactory; public class Connection2 { public void connect() { /* * This is an example to use ONLY p12 file it's not optimazed but it * work. The pkcs12 file where generated by OpenSSL by me. Example how * to load p12 file and build Trust zone from it... It outputs * certificates from p12 file and add good certs to TrustStore */ KeyStore ks = KeyStore.getInstance( "pkcs12" ); ks.load( new FileInputStream( cert.pfx ), "passwrd".toCharArray() ); KeyStore jks = KeyStore.getInstance( "JKS" ); jks.load( null ); for( Enumeration t = ks.aliases(); t.hasMoreElements(); ) { String alias = (String )t.nextElement(); System.out.println( "@:" + alias ); if( ks.isKeyEntry( alias ) ) { Certificate[] a = ks.getCertificateChain( alias ); for( int i = 0; i == 0; ) jks.setCertificateEntry( x509Cert.getSubjectDN().toString(), x509 ); System.out.println( ks.getCertificateAlias( x509 ) ); System.out.println( "ok" ); } } System.out.println( "init Stores..." ); KeyManagerFactory kmf = KeyManagerFactory.getInstance( "SunX509" ); kmf.init( ks, "c1".toCharArray() ); TrustManagerFactory tmf = TrustManagerFactory.getInstance( "SunX509" ); tmf.init( jks ); SSLContext ctx = SSLContext.getInstance( "TLS" ); ctx.init( kmf.getKeyManagers(), tmf.getTrustManagers(), null ); } }