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

时间:2009-02-11 14:32:30

标签: java ssl

我有一个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

请帮助。

8 个答案:

答案 0 :(得分:21)

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

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

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

答案 1 :(得分:5)

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

答案 2 :(得分:4)

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

答案 3 :(得分:4)

这是一个仅使用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 (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);

答案 4 :(得分:1)

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

答案 5 :(得分:1)

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 :(得分:1)

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

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

要遵循的命令:

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

答案 7 :(得分:0)

我意识到这篇文章可能已经过时但我仍然想请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 );
    }
}