Как подключиться к безопасному веб-сайту, используя SSL в Java с файлом pkcs12? - PullRequest
18 голосов
/ 11 февраля 2009

У меня есть файл 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 ]

21 голосов
/ 21 февраля 2009

Для любого, кто сталкивался с подобной ситуацией, я мог решить вышеупомянутую проблему следующим образом:

  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 в $JAVA_HOME/jre/lib/security/cacerts, пароль: 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

5 голосов
/ 30 мая 2012

Я не могу комментировать из-за порога 50pt, но я не думаю, что ответ, представленный в 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");
4 голосов
/ 14 июня 2009

Это пример использования ТОЛЬКО файла p12, он не оптимизирован, но работает. Файл pkcs12, сгенерированный OpenSSL мной. Пример, как загрузить файл 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);
4 голосов
/ 11 февраля 2009

Похоже, что вы извлекаете свой сертификат из хранилища ключей PKCS # 12 и создаете новое хранилище ключей Java (с типом "JKS"). Строго не нужно указывать пароль хранилища доверенных сертификатов (хотя его использование позволяет проверить целостность корневых сертификатов).

Итак, попробуйте вашу программу с only следующим набором свойств SSL. Список, указанный в вашем вопросе, является слишком точным и может вызывать проблемы.

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

Кроме того, использование файла PKCS # 12 непосредственно в качестве хранилища доверенных сертификатов должно работать, пока сертификат CA обнаруживается как «доверенная» запись. Но в этом случае вы должны будете указать свойство javax.net.ssl.trustStoreType как "PKCS12".

Попробуйте только с этими свойствами. Если вы получаете ту же ошибку, я подозреваю, что ваша проблема не в хранилище ключей. Если это все еще происходит, опубликуйте больше трассировки стека в своем вопросе, чтобы сузить проблему.


Новая ошибка «параметр trustAnchors должен быть не пустым» может быть связана с установкой свойства javax.net.ssl.trustStore для файла, который не существует; если файл не может быть открыт, создается пустое хранилище ключей, что приведет к этой ошибке.

1 голос
/ 08 июля 2013

Следующие шаги помогут вам решить вашу проблему.

Шаги: developer_identity.cer <= скачать с Apple mykey.p12 <= Ваш закрытый ключ </p>

Следующие команды:

    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, а затем попробуйте. Это действительно решение .:)

1 голос
/ 03 марта 2013
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;
}
1 голос
/ 19 ноября 2009

В этом примере показано, как можно накладывать 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();
0 голосов
/ 19 октября 2009

Я понимаю, что эта статья может быть устаревшей, но все же я хотел бы попросить 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 );
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...