web-dev-qa-db-ja.com

特定のp12証明書を使用してhttpsサイトに接続します

サーバー側から.p12証明書ファイルが提供されました。このファイルをクリックしてマシンにインストールすると、ブラウザーからHTTPSサイトにアクセスできます。今、彼らは私に与えられた証明書で自分のサイトをクロールしてほしいと思っています。最初の段階で、inputStreamからhttpsURLConnectionを取得しようとしています。サイトにはログインがありません。証明書があるかどうかのみをチェックします。

これまでに行ったことは、Firefoxを使用して証明書を.crtファイル形式でエクスポートすることでした。次に、keytoolコマンドを使用して、(= .crtではなく、.p12ファイル)をJavaキーストアにインポートします。その後、コードで:

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

getInputStream()は、403アクセス禁止アクセスを与えます。私は他の関連トピックを検索しましたが、実際にはそれらを読む前よりも深く混乱しています。回答をいただければ幸いです。

追加の詳細:

  • 証明書をインスタンス化しただけで、プログラムにキーの種類(プライベート、パブリックなど)を通知していません。したがって、これらのキーをサーバーに提示し、実際に証明書を保持していることを知らせる必要があると考えています。論理的にも構文的にも、これを行う方法はまったくわかりません。
  • Keytoolコマンドを試して.p12証明書ファイルをキーストアにインポートしましたが、どういうわけか、-pkcs12オプションはkeytoolで認識されません。この.p12証明書を直接使用する方法についてのアイデアも素晴らしいでしょう。
  • trustAllCertは、何も検証しない(すべてを信頼する)TrustMangersの1つの要素の配列です。これを使い続けるべきかどうかわかりません。実際、今では、信頼できる証明書が1つあります。この場合、trustMangerを記述する適切な方法は何ですか?
  • サーバー側を制御することはできません。与えられたのは、HTTPSプロトコルの下にあるサイトにアクセスするためのURLと、.p12証明書のみです。サイトにはログインがありません。証明書がインストールされている場合、私は入ることができます。
31
Namela

SSL構成をコーディングする場合は、指定されたP12ファイルを使用して、JKSに変換する必要はありません。また、JKSにコピーした証明書だけでなく、P12で秘密キーを使用する必要があります。これが直接あなたのニーズに合うかどうかはわかりませんが、これはあなたを正しい道に導くかもしれません:

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

このようにtrustStoreを構成することはオプションです。 P12のチェーン内のすべての証明書を使用してJKSを作成することも、JREのcacertsファイルに証明書があることを確認することもできます。キーツールに関しては、参考のために、P12でkeytoolコマンドを実行できます(-storetype pkcs12を指定します)が、P12をJKSにインポートすることはできません。また、keytoolコマンドを使用してP12からキーのみをエクスポートすることもできません。

現時点では、このコードをテストするためのサーバーがセットアップされていないため、試してみて、まだ403エラーが表示されるかどうかを確認してください。

33
bobz32

書くためにより多くのスペースが必要なので、これを答えとして追加します。

まず、質問:証明書は、Verisignなどの信頼できる機関によって署名されていますか?そうでない場合、トラストストアには、p12証明書を「有効」にするCA証明書(通常は.pemファイル)が必要です。デフォルトのJavaトラストストアには、VerisignやThawteなどの大企業からのCA証明書の大部分(すべてではないにしても)が含まれています。

また、SSL構成をコーディングせずに、安全なサーバーに接続するようにアプリをテストできますが、次のようないくつかのコマンドラインパラメーターを使用できます。

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]

そして、あなたのコードはちょうどになります

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

自虐的だと感じるなら、 JSSE ref guide はとても楽しいです。

4
Augusto

これは私のために働いたものです:

   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();
    }
}
3
EpicPandaForce

簡単なkeytoolコマンドは、.p12キーストアを.jksキーストアにエクスポートします。

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

0
Rauno Veberson