webentwicklung-frage-antwort-db.com.de

Stellen Sie eine Verbindung zu einer https-Site mit einem bestimmten p12-Zertifikat her

Die Serverseite hat mir eine .p12-Zertifikatsdatei gegeben, die ich auf meinem Computer angeklickt und installiert habe. Anschließend kann ich über den Browser auf die HTTPS-Site zugreifen. Jetzt möchten sie, dass ich ihre Website mit dem angegebenen Zertifikat crawle. Ich stehe in der allerersten Phase und versuche, die inputStream von der httpsURLConnection zu bekommen. Die Site hat keinen Login. Es wird nur geprüft, ob Sie das Zertifikat haben oder nicht.

Was ich bisher getan habe, war, Firefox zu verwenden, um das Zertifikat in einem .crt-Dateiformat zu exportieren. Dann habe ich den Befehl keytool verwendet, um ihn (die .crt-Datei, nicht den .p12) in den Java-Keystore zu importieren. Dann im Code:

KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
File ksFile = new File(keystorePath);
in = new FileInputStream(ksFile);
ks.load(in, "changeit".toCharArray());
X509Certificate cert = (X509Certificate) ks.getCertificate(certificateAlias);

SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new Java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

HttpsURLConnection con = (HttpsURLConnection) (new URL(urlString)).openConnection();
con.connect();
con.getInputStream();
con.disconnect();

Die getInputStream() gibt mir einen 403-Fehler, der den Zugriff untersagt. Ich habe andere verwandte Themen durchsucht und bin tatsächlich zutiefst verwirrter als zuvor. Würde mich über Antworten sehr freuen.

Weitere Details:

  • Ich habe das Zertifikat gerade erst instanziiert und habe dem Programm keine Art von Schlüsseln (privat, öffentlich usw.) mitgeteilt. Ich glaube, ich muss diese Schlüssel dem Server vorlegen, damit ich weiß, dass ich tatsächlich das Zertifikat habe. Ich habe absolut keine Ahnung, wie das geht, sowohl was die Logik als auch die Syntax angeht.
  • Ich habe den Befehl keytool versucht, die .p12 cert-Datei in den Schlüsselspeicher zu importieren, aber irgendwie wird die Option -pkcs12 vom Keytool nicht erkannt. Jede Idee, wie man dieses .p12-Zertifikat direkt verwenden kann, wäre ebenfalls großartig.
  • trustAllCert ist ein Ein-Element-Array von TrustMangers, bei dem nichts geprüft wird (trust all). Ich weiß nicht, ob ich das weiter benutzen soll. Tatsächlich habe ich jetzt tatsächlich ein einziges Zertifikat, dem ich vertrauen kann. Wie schreibe ich in diesem Fall einen trustManger?
  • Ich habe keine Kontrolle über die Serverseite. Alles, was ich erhielt, ist die URL für den Zugriff auf ihre Site, die unter dem HTTPS-Protokoll steht, und ein .p12-Zertifikat. Die Site hat keinen Login. Wenn das Zertifikat installiert ist, kann ich hineingehen.
27
Namela

Wenn Sie versuchen möchten, die SSL-Konfiguration zu verschlüsseln, können Sie die Ihnen angegebene P12-Datei verwenden, ohne sie in ein JKS konvertieren zu müssen. Außerdem müssen Sie den privaten Schlüssel in P12 verwenden und nicht nur die Zertifikate, die Sie in das JKS kopiert haben. Sie sind sich nicht sicher, ob dies Ihren Bedürfnissen direkt entspricht, aber dies könnte Sie auf den richtigen Weg bringen:

        KeyStore clientStore = KeyStore.getInstance("PKCS12");
        clientStore.load(new FileInputStream("test.p12"), "testPass".toCharArray());

        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(clientStore, "testPass".toCharArray());
        KeyManager[] kms = kmf.getKeyManagers();

        KeyStore trustStore = KeyStore.getInstance("JKS");
        trustStore.load(new FileInputStream("cacerts"), "changeit".toCharArray());

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustStore);
        TrustManager[] tms = tmf.getTrustManagers();

        SSLContext sslContext = null;
        sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kms, tms, new SecureRandom());

        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
        URL url = new URL("https://www.testurl.com");

        HttpsURLConnection urlConn = (HttpsURLConnection) url.openConnection();

Die Konfiguration des trustStore ist optional. Sie können eine JKS mit allen Zertifikaten in der Kette Ihres P12 erstellen oder einfach sicherstellen, dass sie sich in der JAC-Datei cacerts befinden. Wie für keytool können Sie die keytool-Befehle als Referenz auf einem P12 ausführen (geben Sie -storetype pkcs12 an), können jedoch kein P12 in ein JKS importieren. Mit dem Befehl keytool können Sie auch nicht nur einen Schlüssel aus einem P12 exportieren.

Ich habe zurzeit keine Server eingerichtet, um diesen Code zu testen. Versuchen Sie es daher und sehen Sie, ob Sie immer noch den 403-Fehler erhalten.

30
bobz32

Dies als Antwort hinzufügen, da ich mehr Platz zum Schreiben brauche.

Zunächst eine Frage: Wird das Zertifikat von einer vertrauenswürdigen Stelle wie Verisign signiert? Wenn dies nicht der Fall ist, sollte der Truststore über das CA-Zertifikat (normalerweise eine PEM-Datei) verfügen, wodurch das Zertifikat p12 "gültig" wird. Der Standard-Java-Truststore enthält die meisten (wenn nicht alle) CA-Zertifikate von großen Unternehmen wie Verisign und Thawte.

Sie können Ihre App auch testen, um eine Verbindung zum sicheren Server herzustellen, ohne die SSL-Konfiguration zu codieren, jedoch mit einigen Befehlszeilenparametern, zum Beispiel:

Java -Djavax.net.ssl.keyStore=[path_to_p12_cert] \
 -Djavax.net.ssl.keyStorePassword=[p12_password] \
 -Djavax.net.ssl.keyStoreType=PKCS12 \
 -Djavax.net.ssl.trustStore=[path_to_trust_store_with_CA_certificates] \
 -Djavax.net.ssl.trustStorePassword=[trust_store_password] \
 [MainClass]

und dann wird dein Code gerade

HttpsURLConnection con = (HttpsURLConnection) (new URL(urlString)).openConnection();
con.connect();
con.getInputStream();
con.disconnect();

Wenn Sie sich masochistisch fühlen, macht der JSSE ref guide großen Spaß.

4
Augusto

Das hat bei mir funktioniert:

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

    // Trust own CA and all self-signed certs
    SSLContext sslcontext = SSLContexts.custom()
        .loadKeyMaterial(keyStore, "password".toCharArray())
        //.loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
        .build();
    // Allow TLSv1 protocol only
    SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
        sslcontext,
        SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    CloseableHttpClient httpclient = HttpClients.custom()
        .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
        .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();
    }
}
2
EpicPandaForce

Ein einfacher keytool-Befehl würde Ihren .p12-Keystore in den .jks-Keystore exportieren:

keytool -importkeystore -srckeystore keystore.p12 -srcstoretype PKCS12 -deststoretype JKS -destkeystore keystore.jks

0
Rauno Veberson