【问题标题】:How to connect to a secure website using SSL in Java with a pkcs12 file?如何通过 pkcs12 文件在 Java 中使用 SSL 连接到安全网站?
【发布时间】:2009-02-11 14:32:29
【问题描述】:

我有一个 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”属性后,出现以下异常

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

请帮忙。

【问题讨论】:

  • 如果您可以发布更多堆栈跟踪信息(来自堆栈帧的信息,而不仅仅是异常消息),我会看看它。
  • 要检查的另一件事是您的信任存储位置是否正确指定;如果指定了 javax.net.ssl.trustStore 但不存在,则会即时创建一个空的信任库。您的新错误消息表明这可能正在发生。

标签: java ssl


【解决方案1】:

对于遇到类似情况的任何人,我都能够通过以下方式解决上述问题:

  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. 测试你的网址。

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

【讨论】:

  • 如果你问我,写一个你自己问题的答案并接受它有点问题。有点像给自己投票(这当然是不可能的)
  • @Fredrik - 对我来说似乎完全合理。不过,我认为常见问题解答中可能有一些内容。
  • 信任库必须真的是 java JKS 格式。我可以使用 .p12 的密钥库吗?
【解决方案2】:

由于 50pts 阈值,我无法发表评论,但我认为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");

【讨论】:

  • 我明白你的意思。但是,我想知道,System.setProperty 语句是否更改了默认信任库?您在回答中提到无法使用代码中定义的信任库,因为他/她已经使用了默认值。这是真的吗?那么如果默认存储不可更改,System.setProperty 的意义何在?
【解决方案3】:

您似乎正在从 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 属性设置为不存在的文件所致;如果文件无法打开,则会创建一个空的密钥库,这将导致此错误。

【讨论】:

  • 我只设置了您指定的属性,现在出现以下异常:“InvalidAlogrithmException: trustAnchors 参数必须为非空”
  • 我只想感谢这个答案,因为我不知道“直接使用 PKCS #12 文件作为信任库应该可以工作”,这解决了我自己的问题
【解决方案4】:

这是一个仅使用 p12 文件的示例,它没有经过优化但可以工作。 我由 OpenSSL 生成的 pkcs12 文件。 示例如何加载 p12 文件并从中构建信任区域... 它从 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 (Enumeration<String>t=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;i<a.length;i++)
        {
            X509Certificate x509 = (X509Certificate)a[i];
            System.out.println(x509.getSubjectDN().toString());
            if (i>0)
                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);

【讨论】:

    【解决方案5】:
    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;
    }
    

    【讨论】:

      【解决方案6】:

      此示例展示了如何在现有套接字之上分层 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();
      

      【讨论】:

        【解决方案7】:

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

        步骤: developer_identity.cer

        要遵循的命令:

            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,然后尝试。这确实是解决方案。:)

        【讨论】:

          【解决方案8】:

          我知道这篇文章可能已经过时了,但我还是想请 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 );
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2021-08-08
            • 2014-04-03
            • 2023-03-09
            • 2023-01-04
            • 2014-02-26
            • 2021-05-20
            • 2021-11-16
            • 2020-03-02
            相关资源
            最近更新 更多