web-dev-qa-db-fra.com

Comment se connecter à un site Web sécurisé utilisant SSL en Java avec un fichier pkcs12?

J'ai un fichier pkcs12. J'ai besoin de l'utiliser pour me connecter à une page Web à l'aide du protocole https. Je suis tombé sur un code dans lequel, pour me connecter à une page Web sécurisée, je dois définir les propriétés système suivantes:

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");

J'ai le fichier p12 (pkcs12). Tout ce dont j'ai besoin est un fichier de magasin de clés de confiance.

J'ai extrait les certificats en utilisant:

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

Maintenant converti le fichier cert PEM en der

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

Ajouter maintenant le fichier der à un magasin de clés

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

Maintenant, j'ai le fichier de clés certifiées, mais lorsque je l'utilise, l'erreur suivante s'affiche

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)

Mettre à jour: Après avoir supprimé certaines propriétés et défini uniquement les propriétés "trustStore", "trustStorePassword" et "trustStoreType", j'ai obtenu l'exception suivante.

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

S'il vous plaît aider.

18
user27221

Pour toute personne rencontrant une situation similaire, j'ai pu résoudre le problème ci-dessus comme suit:

  1. Régénérez votre fichier pkcs12 comme suit:

    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. Importez le certificat de l'autorité de certification depuis le serveur dans un magasin de souvenirs (le vôtre ou le magasin de clés Java dans $Java_HOME/jre/lib/security/cacerts, mot de passe: changeit).

  3. Définissez les propriétés système suivantes:

    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. Test ur url.

Courtesy @ http://forums.Sun.com/thread.jspa?threadID=5296333

21
user27221

Je ne peux pas commenter à cause du seuil de 50 points, mais je ne pense pas que la réponse fournie dans https://stackoverflow.com/a/537344/1341220 soit correcte . Ce que vous décrivez en réalité, c'est comment vous insérez des certificats de serveur dans le magasin de clés par défaut des systèmes:

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

Cela fonctionne, certes, mais cela signifie que vous n'avez pas vraiment spécifié de magasin de clés de confiance local pour votre projet, mais que vous avez accepté le certificat de manière universelle dans votre système.

En fait, vous n'utilisez jamais votre propre fichier de clés de confiance que vous avez défini ici:

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

Il semble que vous extrayiez votre certificat du magasin de clés PKCS # 12 et que vous créez un nouveau magasin de clés Java (de type "JKS"). Vous n'êtes pas obligé de fournir un mot de passe de magasin de données de confiance (bien que son utilisation vous permette de tester l'intégrité de vos certificats racine).

Alors, essayez votre programme avec seulement les propriétés SSL suivantes. La liste affichée dans votre question est sur spécifiée et peut être à l'origine de problèmes.

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

De plus, l'utilisation du fichier PKCS # 12 directement en tant que magasin de confiance devrait fonctionner, à condition que le certificat de l'autorité de certification soit détecté comme une entrée "de confiance". Mais dans ce cas, vous devrez également spécifier la propriété javax.net.ssl.trustStoreType sous la forme "PKCS12".

Essayez avec ces propriétés seulement. Si vous obtenez la même erreur, je soupçonne que votre problème n'est pas le magasin de clés. Si cela se produit toujours, postez davantage de traces de la pile dans votre question afin de réduire le problème.


La nouvelle erreur, "le paramètre trustAnchors doit être non vide", pourrait être due à la définition de la propriété javax.net.ssl.trustStore sur un fichier qui n'existe pas; si le fichier ne peut pas être ouvert, un magasin de clés vide est créé, ce qui entraînerait cette erreur.

4
erickson

Ceci est un exemple pour utiliser UNIQUEMENT le fichier p12 ce n'est pas optimazed mais ça marche . Le fichier pkcs12 a été généré par OpenSSL par moi . Exemple comment charger un fichier p12 et en construire une zone de confiance ....__ Il émet des certificats à partir d'un fichier p12 et ajoute de bons certificats à 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
user122678
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
Mohamad Faisal

Les étapes suivantes vous aideront à résoudre votre problème.

Étapes: Developer_identity.cer <= à télécharger chez Apple Mykey.p12 <= votre clé privée

Commandes à suivre: 

    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

La dernière p12 dont nous aurons besoin est le fichier iphone_dev.p12 et la phrase secrète.

utilisez ce fichier comme votre p12 puis essayez. C'est bien la solution :)

1
Apurv Nerlekar

Cet exemple montre comment vous pouvez superposer SSL sur un socket existant, en obtenant le certificat client à partir d'un fichier PKCS # 12. Cela convient lorsque vous devez vous connecter à un serveur en amont via un proxy et que vous souhaitez gérer vous-même le protocole complet.

Cependant, une fois que vous avez le contexte SSL, vous pouvez l’appliquer à une connexion HttpsURLConnection, etc., etc.

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();
1
Rogan Dawes

Je me rends compte que cet article est peut-être obsolète, mais je voudrais quand même demander à smithsv de corriger son code source. Il contient de nombreuses erreurs. le code source tel que je pense devrait être:

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 );
    }
}
0
Roquen