Domanda

Sto usando Java 6 e sto cercando di creare un HttpsURLConnection rispetto a un server remoto utilizzando un certificato client.
Il server utilizza un selfsigned certificato radice, e richiede una password protetta da certificato client è presentato.Ho aggiunto il certificato root del server e il certificato del client di default di java keystore che ho trovato in /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home/lib/security/cacerts (OSX 10.5).Il nome del file dell'archivio sembra suggerire che il certificato client non dovrebbe andarci?

Comunque, l'aggiunta del certificato radice di questo negozio risolto il famigerato javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed' problem.

Tuttavia, sono ora bloccati su come utilizzare il certificato del client.Ho provato due approcci e nessuno mi prende ovunque.
Prima, e preferito, provare:

SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
URL url = new URL("https://somehost.dk:3049");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(sslsocketfactory);
InputStream inputstream = conn.getInputStream();
// The last line fails, and gives:
// javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

Ho provato a saltare il HttpsURLConnection di classe (che non è l'ideale dal momento che voglio parlare HTTP con il server), e fare invece:

SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("somehost.dk", 3049);
InputStream inputstream = sslsocket.getInputStream();
// do anything with the inputstream results in:
// java.net.SocketTimeoutException: Read timed out

Io non sono nemmeno sicuro che il certificato client è il problema qui.

È stato utile?

Soluzione

Infine risolto;). Ha ottenuto un forte indizio qui (Gandalf risposta ha toccato un po 'su di esso pure). I collegamenti mancanti era (soprattutto) il primo dei parametri di seguito, e in qualche misura che ho trascurato la differenza tra archivi di chiavi e truststore.

Il certificato del server autofirmato deve essere importato in un truststore:

  

keytool -import -alias gridserver -file gridserver.crt -storepass $ pass -keystore gridserver.keystore

Queste proprietà devono essere impostati (sia dalla linea di comando, o in codice):

-Djavax.net.ssl.keyStoreType=pkcs12
-Djavax.net.ssl.trustStoreType=jks
-Djavax.net.ssl.keyStore=clientcertificate.p12
-Djavax.net.ssl.trustStore=gridserver.keystore
-Djavax.net.debug=ssl # very verbose debug
-Djavax.net.ssl.keyStorePassword=$PASS
-Djavax.net.ssl.trustStorePassword=$PASS

Lavorare codice di esempio:

SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
URL url = new URL("https://gridserver:3049/cgi-bin/ls.py");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
conn.setSSLSocketFactory(sslsocketfactory);
InputStream inputstream = conn.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);

String string = null;
while ((string = bufferedreader.readLine()) != null) {
    System.out.println("Received " + string);
}

Altri suggerimenti

Anche se non consigliato, è anche possibile disattivare la convalida CERT dello SSL alltogether:

import javax.net.ssl.*;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

public class SSLTool {

  public static void disableCertificateValidation() {
    // Create a trust manager that does not validate certificate chains
    TrustManager[] trustAllCerts = new TrustManager[] { 
      new X509TrustManager() {
        public X509Certificate[] getAcceptedIssuers() { 
          return new X509Certificate[0]; 
        }
        public void checkClientTrusted(X509Certificate[] certs, String authType) {}
        public void checkServerTrusted(X509Certificate[] certs, String authType) {}
    }};

    // Ignore differences between given hostname and certificate hostname
    HostnameVerifier hv = new HostnameVerifier() {
      public boolean verify(String hostname, SSLSession session) { return true; }
    };

    // Install the all-trusting trust manager
    try {
      SSLContext sc = SSLContext.getInstance("SSL");
      sc.init(null, trustAllCerts, new SecureRandom());
      HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
      HttpsURLConnection.setDefaultHostnameVerifier(hv);
    } catch (Exception e) {}
  }
}

Avete impostato il KeyStore e / o in TrustStore sistema?

java -Djavax.net.ssl.keyStore=pathToKeystore -Djavax.net.ssl.keyStorePassword=123456

o dal con il codice

System.setProperty("javax.net.ssl.keyStore", pathToKeyStore);

Lo stesso con javax.net.ssl.trustStore

Se avete a che fare con una chiamata di servizio Web utilizzando il framework Axis, c'è una risposta molto più semplice. Se tutto vogliamo è per il vostro cliente di essere in grado di chiamare il servizio Web SSL e ignorare gli errori del certificato SSL, basta mettere questa dichiarazione prima di richiamare qualsiasi servizio web:

System.setProperty("axis.socketSecureFactory", "org.apache.axis.components.net.SunFakeTrustSocketFactory");

I soliti disclaimer su questo di essere una pessima cosa da fare in un ambiente di produzione applicare.

Ho trovato questo a dell'Asse wiki .

Per me, questo è ciò che ha funzionato usando Apache HttpComponents ~ HttpClient 4.x:

    KeyStore keyStore  = KeyStore.getInstance("PKCS12");
    FileInputStream instream = new FileInputStream(new File("client-p12-keystore.p12"));
    try {
        keyStore.load(instream, "helloworld".toCharArray());
    } finally {
        instream.close();
    }

    // Trust own CA and all self-signed certs
    SSLContext sslcontext = SSLContexts.custom()
        .loadKeyMaterial(keyStore, "helloworld".toCharArray())
        //.loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) //custom trust store
        .build();
    // Allow TLSv1 protocol only
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
        sslcontext,
        new String[] { "TLSv1" },
        null,
        SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); //TODO
    CloseableHttpClient httpclient = HttpClients.custom()
        .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER) //TODO
        .setSSLSocketFactory(sslsf)
        .build();
    try {

        HttpGet httpget = new HttpGet("https://localhost:8443/secure/index");

        System.out.println("executing request" + httpget.getRequestLine());

        CloseableHttpResponse response = httpclient.execute(httpget);
        try {
            HttpEntity entity = response.getEntity();

            System.out.println("----------------------------------------");
            System.out.println(response.getStatusLine());
            if (entity != null) {
                System.out.println("Response content length: " + entity.getContentLength());
            }
            EntityUtils.consume(entity);
        } finally {
            response.close();
        }
    } finally {
        httpclient.close();
    }

Il file P12 contiene il certificato del client e la chiave privata del cliente, creata con BouncyCastle:

public static byte[] convertPEMToPKCS12(final String keyFile, final String cerFile,
    final String password)
    throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException,
    NoSuchProviderException
{
    // Get the private key
    FileReader reader = new FileReader(keyFile);

    PEMParser pem = new PEMParser(reader);
    PEMKeyPair pemKeyPair = ((PEMKeyPair)pem.readObject());
    JcaPEMKeyConverter jcaPEMKeyConverter = new JcaPEMKeyConverter().setProvider("BC");
    KeyPair keyPair = jcaPEMKeyConverter.getKeyPair(pemKeyPair);

    PrivateKey key = keyPair.getPrivate();

    pem.close();
    reader.close();

    // Get the certificate
    reader = new FileReader(cerFile);
    pem = new PEMParser(reader);

    X509CertificateHolder certHolder = (X509CertificateHolder) pem.readObject();
    java.security.cert.Certificate x509Certificate =
        new JcaX509CertificateConverter().setProvider("BC")
            .getCertificate(certHolder);

    pem.close();
    reader.close();

    // Put them into a PKCS12 keystore and write it to a byte[]
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    KeyStore ks = KeyStore.getInstance("PKCS12", "BC");
    ks.load(null);
    ks.setKeyEntry("key-alias", (Key) key, password.toCharArray(),
        new java.security.cert.Certificate[]{x509Certificate});
    ks.store(bos, password.toCharArray());
    bos.close();
    return bos.toByteArray();
}

Io uso il pacchetto client HTTP Apache Commons di fare questo nel mio progetto attuale e funziona benissimo con SSL e un CERT auto-firmato (dopo l'installazione in cacerts come lei ha citato). Si prega di dare un'occhiata qui:

http://hc.apache.org/httpclient-3.x /tutorial.html

http://hc.apache.org/httpclient-3.x /sslguide.html

penso che tu abbia un problema con il certificato del server, non è un certificato valido (credo che questo è ciò che "handshake_failure" si intende in questo caso):

importare il certificato del server nel tuo trustcacerts keystore su JRE del cliente. Questo è fatto facilmente con keytool :

keytool
    -import
    -alias <provide_an_alias>
    -file <certificate_file>
    -keystore <your_path_to_jre>/lib/security/cacerts

Utilizzando il codice qui sotto

-Djavax.net.ssl.keyStoreType=pkcs12

o

System.setProperty("javax.net.ssl.keyStore", pathToKeyStore);

non è affatto necessario.Inoltre non c'è bisogno di creare il proprio personalizzato SSL fabbrica.

Anche io ho riscontrato lo stesso problema, nel mio caso non era un problema completo di certificato di catena non è stato importato in truststores.I certificati di importazione utilizzando utilità keytool diritto ufm certificato principale, inoltre, è possibile aprire cacerts file in blocco note e vedere se la catena di certificati importati o non.Verificare con il nome di alias hai fornito durante l'importazione di certificati, aprire i certificati e vedere quanti non contiene, stesso numero di certificati deve essere presente nel file cacerts.

Anche cacerts il file deve essere configurato nel server è in esecuzione l'applicazione, i due server di autenticazione con chiavi pubbliche/private.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top