2009-02-11 13 views
17

Ho un file pkcs12. Devo usare questo per connettermi a una pagina web usando il protocollo https. Mi sono imbattuto in un po 'di codice in cui, al fine di connettersi ad una pagina web sicuro ho bisogno di impostare le seguenti proprietà di sistema:Come connettersi a un sito Web sicuro utilizzando SSL in Java con un file 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"); 

Ho il file P12 (PKCS12). Tutto ciò di cui ho bisogno è un file truststore.

ho estratto i certificati utilizzando:

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

ora convertito il file cert PEM a der

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

Ora aggiunta del file der ad un archivio chiavi

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

Ora ho il truststore, ma quando lo uso, ottengo il seguente errore

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) 

Aggiornamento: Dopo aver rimosso alcune proprietà e l'impostazione solo il "trustStore", "trustStorePassword" e la proprietà "trustStoreType", ho ricevuto la seguente eccezione

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

prega di aiuto.

+0

Se potessi pubblicare più tracce dello stack (informazioni dai frame dello stack, non solo il messaggio di eccezione), le darò un'occhiata. – erickson

+0

Un'altra cosa da controllare è che la posizione del tuo negozio di fiducia sia specificata correttamente; se javax.net.ssl.trustStore è specificato ma non esiste, viene creato immediatamente un trust store vuoto. Il tuo nuovo messaggio di errore fa sembrare che questo potrebbe accadere. – erickson

risposta

18

Per chiunque incontrando una situazione simile sono stato in grado di risolvere il problema di cui sopra come segue:

  1. rigenerare il file PKCS12 come segue:

    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. Importare il certificato CA dal server in un TrustStore (o il proprio, o il keystore java in $JAVA_HOME/jre/lib/security/cacerts, password: changeit).

  3. impostare le seguenti proprietà di sistema:

    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.

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

+0

Scrivere una risposta alla tua stessa domanda e accettarla è un po 'discutibile se me lo chiedi. Un po 'come invitare te stesso (che ovviamente non è possibile) – Fredrik

+32

@Fredrik - sembra perfettamente ragionevole per me. Penso che ci sia probabilmente qualcosa nelle FAQ comunque. –

4

Sembra che si stia estraendo il certificato dall'archivio chiavi PKCS # 12 e creando un nuovo archivio chiavi Java (con tipo "JKS"). Non è strettamente necessario fornire una password di fiducia (sebbene l'utilizzo di uno consenta di testare l'integrità dei certificati di root).

Quindi, provare il programma con solo le seguenti proprietà SSL impostate. L'elenco mostrato nella tua domanda è troppo specificato e potrebbe causare problemi.

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

Inoltre, utilizzando i file PKCS # 12 direttamente come il negozio di fiducia dovrebbe funzionare, a patto che il certificato CA viene rilevato come voce "trusted". In tal caso, dovrai specificare la proprietà javax.net.ssl.trustStoreType come "PKCS12".

Provare solo con queste proprietà. Se ricevi lo stesso errore, sospetto che il tuo problema non sia l'archivio delle chiavi. Se si verifica ancora, postare più tracce dello stack nella domanda per restringere il problema.


Il nuovo errore, "il parametro trustAnchors deve essere non vuoto," potrebbe essere dovuto a impostare la proprietà javax.net.ssl.trustStore a un file che non esiste; se il file non può essere aperto, viene creato un keystore vuoto che porta a questo errore.

+0

Ho impostato solo le proprietà che hai specificato, ora ottengo la seguente eccezione: "InvalidAlogrithmException: il parametro trustAnchors deve essere non vuoto" – user27221

+0

Voglio solo ringraziare questa risposta perché non sapevo che "utilizzando PKCS # 12 file direttamente come il trust store dovrebbe funzionare "e questo ha risolto il mio problema – fabien7474

4

Questo è un esempio di utilizzare file di p12 Solo che non è optimazed ma farlo funzionare. Il file pkcs12 dove generato da OpenSSL da me. Esempio come caricare file di p12 e costruire zona di fiducia da essa ... Emette certificati da file p12 e aggiungere buoni certs per 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

Mi rendo conto che questo articolo può essere superata, ma ancora vorrei chiedi a smithsv di correggere il suo codice sorgente, contiene molti errori, sono riuscito a correggere la maggior parte di essi ma ancora non so quale tipo di oggetto potrebbe essere x509.Qui è il codice sorgente come penso dovrebbe essere:

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

Questo esempio mostra come è possibile sovrapporre SSL su un socket esistente, ottenendo il certificato client da un file PKCS # 12 e. È appropriato quando è necessario connettersi a un server upstream tramite un proxy e si desidera gestire autonomamente il protocollo completo.

In sostanza, tuttavia, una volta che hai il contesto SSL, è possibile applicarlo a un HttpsURLConnection, ecc, ecc

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

non posso commentare a causa del 50pts soglia, ma non credo che la risposta fornita in https://stackoverflow.com/a/537344/1341220 è corretta. cosa si sta effettivamente descrivendo è come si inseriscono i certificati di server nel truststore sistemi di default:

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

Questo funziona, anzi, ma significa che non hai davvero specificato un negozio di fiducia locale per il progetto, ma piuttosto accettati il certificato universalmente nel tuo sistema.

In realtà mai utilizzare il proprio truststore che si è definito qui:

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

Ho capito il tuo punto. Ma, mi chiedo, l'istruzione 'System.setProperty' cambia l'archivio di fiducia predefinito o no? Il tuo citato nella tua risposta che non è possibile utilizzare l'archivio di fiducia definisce nel codice poiché lui/lei già utilizza quello predefinito. È proprio vero? Quindi qual è il punto di 'System.setProperty' se l'archivio predefinito non è modificabile? – 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

I passaggi seguenti vi aiuterà a ordinare il vostro problema fuori.

Passi: developer_identity.cer < = download da Apple mykey.P12 < = Your Private chiave

Comandi da seguire:

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 finale che si richiede è il file iphone_dev.p12 e la passphrase.

utilizzare questo file come p12 e quindi provare. Questa è davvero la soluzione :) :)

Problemi correlati