2009-02-11 6 views
17

J'ai un fichier pkcs12. Je dois l'utiliser pour me connecter à une page Web en utilisant le protocole https. Je suis tombé sur un code où afin de se connecter à une page Web sécurisée i besoin de définir les propriétés système suivantes:Comment se connecter à un site Web sécurisé en utilisant SSL en Java avec un fichier pkcs12?

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

Je le fichier p12 (pkcs12). Tout ce dont j'ai besoin est un fichier de truststore.

I extrait les certificats à l'aide:

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

maintenant converti le fichier PEM cert der

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

Adding le fichier der à un keystore

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

Maintenant je le truststore, mais quand je l'utilise, j'obtiens l'erreur suivante

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) 

Mise à jour: Après avoir retiré certaines propriétés et la mise seulement "trustStore", "trustStorePassword" et "trustStoreType" bien, je suis l'exception suivante

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

Aide S'il vous plaît.

+0

Si vous pouviez poster plus de trace de la pile (informations provenant des cadres de la pile, pas seulement le message d'exception), je vais y jeter un coup d'oeil. – erickson

+0

Une autre chose à vérifier est que votre emplacement de magasin de confiance est correctement spécifié; Si javax.net.ssl.trustStore est spécifié mais n'existe pas, un magasin de confiance vide est créé à la volée. Votre nouveau message d'erreur donne l'impression que cela pourrait se produire. – erickson

Répondre

18

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

  1. régénèrent 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. importer le certificat CA du serveur dans un TrustStore (soit le vôtre, soit le keystore java au $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.

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

+0

Ecrire une réponse à votre propre question et l'accepter est un peu discutable si vous me demandez. Un peu comme vous upvoting (ce qui n'est bien sûr pas possible) – Fredrik

+32

@Fredrik - semble parfaitement raisonnable pour moi. Je pense qu'il y a probablement quelque chose dans la FAQ. –

4

Il semble que vous extrayez votre certificat du magasin de clés PKCS # 12 et créez un nouveau magasin de clés Java (de type "JKS"). Vous n'êtes pas obligé de fournir un mot de passe de confiance (même si vous en utilisez un vous permet de tester l'intégrité de vos certificats racine).

Alors, essayez votre programme avec seulement les propriétés SSL suivantes définies. La liste affichée dans votre question est sur-spécifiée et peut causer des problèmes.

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

Aussi, en utilisant le fichier PKCS # 12 directement en tant que magasin de confiance devrait fonctionner, tant que le certificat CA est détecté comme une entrée « de confiance ». Mais dans ce cas, vous devrez également spécifier la propriété javax.net.ssl.trustStoreType en tant que "PKCS12".

Essayez ces propriétés uniquement. 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, publiez plus de trace de pile dans votre question pour réduire le problème.


La nouvelle erreur «le paramètre trustAnchors doit être vide, » pourrait être due à définir la propriété javax.net.ssl.trustStore dans un fichier qui n'existe pas; Si le fichier ne peut pas être ouvert, un magasin de clés vide créé, ce qui conduirait à cette erreur.

+0

Je définis uniquement les propriétés que vous avez spécifiées, maintenant je reçois l'exception suivante: "InvalidAlogrithmException: le paramètre trustAnchors doit être non vide" – user27221

+0

Je veux juste remercier cette réponse car je ne savais pas que "en utilisant le PKCS # 12 dossier directement que le magasin de confiance devrait fonctionner "et cela a résolu mon propre problème – fabien7474

4

Ceci est un exemple d'utiliser un fichier SEULEMENT p12 ce n'est pas optimazed mais ça marche. Le fichier pkcs12 où généré par OpenSSL par moi. Exemple comment charger le fichier de p12 et de construire la zone d'affectation spéciale de celui-ci ... Il émet des certificats à partir du fichier p12 et ajouter de bonnes certs à 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); 
0

Je me rends compte que cet article peut être obsolète mais je voudrais demander smithsv pour corriger son code source, il contient beaucoup d'erreurs, j'ai réussi à corriger la plupart d'entre eux mais je ne sais toujours pas quel type d'objet x509 pourrait être.Voici le code source 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); 
    } 
} 
1

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

Essentiellement, cependant, une fois que vous avez le contexte SSL, vous pouvez l'appliquer à un 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(); 
5

Je ne peux pas commenter à cause de la 50pts seuil, mais je ne pense pas que la réponse fournie dans https://stackoverflow.com/a/537344/1341220 est correcte. Ce que vous décrivez est réellement comment vous insérez des certificats de serveur dans le système par défaut truststore:

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

Cela fonctionne, en effet, mais cela signifie que vous ne spécifiez pas vraiment un magasin de confiance locale à votre projet, mais plutôt accepté le certificat universellement dans votre système.

Vous en fait jamais utiliser votre propre truststore que vous avez défini ici:

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

J'ai compris votre point. Mais, je me demande, Est-ce que l'instruction 'System.setProperty' change le magasin de confiance par défaut ou non? Vous avez mentionné dans votre réponse qu'il n'est pas possible d'utiliser le magasin de confiance défini dans le code puisqu'il utilise déjà le magasin par défaut. Est-ce vraiment vrai? Alors quel est le point de 'System.setProperty' si le magasin par défaut n'est pas modifiable? – Salman

0
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

Les étapes suivantes vous aideront à trier votre problème sur.

Étapes: développeur_identity.cer < = téléchargement de 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 

p12 final que nous aurons besoin est un fichier iphone_dev.p12 et le mot de passe.

utilisez ce fichier comme p12, puis essayez. C'est en effet la solution. :)

Questions connexes