web-dev-qa-db-fra.com

Se connecter à un site https avec un certificat p12 donné

Le côté serveur m'a donné un fichier de certificat .p12 sur lequel j'ai cliqué et installé sur ma machine, puis je peux accéder au site HTTPS par le biais du navigateur. Maintenant, ils veulent que je fouille leur site avec le certificat donné. Je suis coincé à la toute première étape, essayant d'obtenir le inputStream du httpsURLConnection. Le site n'a pas de login. Il vérifie seulement si vous avez le certificat ou non.

Jusqu'ici, j'ai utilisé Firefox pour exporter le certificat dans un format de fichier .crt. Ensuite, j'ai utilisé la commande keytool pour l'importer (le fichier .crt, pas le .p12) dans le magasin de clés Java. Puis dans le 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();

La getInputStream() me donnera un accès interdit d'erreur 403. J'ai effectué des recherches dans d'autres sujets connexes et je suis vraiment plus confus qu'avant de les lire. J'apprécierais grandement les réponses.

Détails supplémentaires:

  • Je viens à peine d'instancier le certificat et je n'ai pas laissé le programme connaître aucune sorte de clé (privée, publique, etc.). Donc, ce que je crois, je dois présenter ces clés au serveur, en lui faisant savoir que je suis en train de détenir le certificat. Je ne sais absolument pas comment faire cela, tant du point de vue de la logique que de la syntaxe.
  • J'ai essayé la commande keytool pour importer le fichier de certificat .p12 dans le magasin de clés mais, d'une manière ou d'une autre, l'option -pkcs12 n'est pas reconnue par le keytool. Toute idée sur la façon d’utiliser directement ce certificat .p12 serait également utile.
  • trustAllCert est un tableau à un élément de TrustMangers qui ne valide rien (approuve tous). Je ne sais pas si je devrais continuer à l'utiliser. En fait, j’ai maintenant un seul cert à faire confiance. Quelle est la bonne façon d'écrire un trustManger dans ce cas?
  • Je n'ai aucun contrôle sur le côté serveur. Tout ce qui m’a été donné, c’est l’URL permettant d’accéder à leur site, qui est sous protocole HTTPS, et un certificat .p12. Le site n'a pas de login. Si le certificat est installé, je peux y aller.
27
Namela

Si vous voulez essayer de coder la configuration SSL, vous pouvez utiliser le fichier P12 qui vous est donné sans avoir à le convertir en JKS. En outre, vous devrez utiliser la clé privée dans le P12, et pas seulement les certificats que vous avez copiés dans le JKS. Vous n'êtes pas sûr que cela convienne directement à vos besoins, mais cela pourrait vous mettre sur la bonne voie:

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

Configurer le trustStore de cette manière est facultatif. Vous pouvez créer un JKS avec tous les certificats de la chaîne de votre P12 ou simplement vous assurer qu'ils se trouvent dans le fichier cacerts de votre JRE. En ce qui concerne keytool, pour référence, vous pouvez exécuter des commandes keytool sur un P12 (spécifiez -storetype pkcs12), mais vous ne pouvez pas importer un P12 dans un JKS. Vous ne pouvez pas non plus exporter uniquement une clé d'un P12 avec la commande keytool.

Je n'ai pas de serveur configuré pour le moment pour tester ce code, alors essayez-le et voyez si vous recevez toujours l'erreur 403.

30
bobz32

Ajouter ceci comme réponse car j'ai besoin de plus d'espace pour écrire.

Premièrement, une question: le certificat est-il signé par une autorité de confiance telle que Verisign? Si ce n'est pas le cas, le fichier de clés certifiées doit avoir le certificat de l'autorité de certification (généralement un fichier .pem) rendant le certificat p12 'valide'. Le Trust Trust Java par défaut contient la plupart (sinon la totalité) des certificats d'autorité de certification de grandes entreprises, telles que Verisign et Thawte.

En outre, vous pouvez tester votre application pour vous connecter au serveur sécurisé sans coder la configuration SSL, mais avec certains paramètres de ligne de commande, par exemple:

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]

et alors votre code devient juste

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

Si vous vous sentez masochiste, le guide de référence JSSE est très amusant.

4
Augusto

C'est ce qui a fonctionné pour moi:

   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

Une simple commande keytool exporterait votre magasin de clés .p12 dans le magasin de clés .jks:

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

0
Rauno Veberson