簡體   English   中英

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

[英]How to connect to a secure website using SSL in Java with a pkcs12 file?

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

請幫忙。

對於遇到類似情況的任何人,我能夠解決上面的問題,如下所示:

  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

由於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 (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);
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,然后嘗試。 這確實是解決方案。:)

此示例顯示如何在現有套接字上層疊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();

我意識到這篇文章可能已經過時,但我仍然想請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 );
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM