1. ホーム

[解決済み】Java HTTPSクライアント証明書認証

2022-04-04 10:13:54

質問

を始めたばかりです。 HTTPS/SSL/TLS で、証明書による認証の際にクライアントが何を提示することになっているのか、少し混乱しています。

私はJavaクライアントを書いているのですが、このクライアントは単純な POST のデータを特定の URL . この部分はうまくいくのですが、唯一の問題は、この処理は HTTPS . その HTTPS の部分は、かなり簡単に扱えます。 HTTPclient を使うか、Javaの組み込みの HTTPS をサポート)、クライアント証明書による認証で行き詰っています。ここにすでに非常に似た質問があることに気づきましたが、私はまだ自分のコードで試していません(すぐにそうするつもりです)。私の現在の問題は、-私が何をしようとも-Javaクライアントが証明書を一緒に送らないということです(私はこれを PCAP をダンプします)。

証明書による認証の際に、クライアントがサーバーに提示することになる具体的な内容を知りたいのですが(特にJavaの場合 - それが重要であれば)。これは JKS ファイル、または PKCS#12 ? クライアント証明書だけなのか、鍵なのか?もしそうなら、どの鍵ですか?さまざまな種類のファイルや証明書の種類などについては、かなり混乱しています。

前にも言いましたが、私は初めて HTTPS/SSL/TLS エッセイでなくても良いので、良い記事へのリンクでも良いので、背景情報もお願いします。

どのように解決するのか?

ようやく全ての問題を解決することができたので、自分自身の質問に答えます。これらは、私が特定の問題を解決するために使用した設定/ファイルです。

その クライアントのキーストア PKCS#12形式 を含むファイル

  1. クライアントの パブリック 証明書(この例では自己署名したCAによって署名されたもの)。
  2. クライアントの プライベート キー

これを生成するために、私はOpenSSLの pkcs12 というコマンドを使うなどしています。

openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12 -name "Whatever"

ヒント は、最新のOpenSSLを入手するようにしてください。 ではなく バージョン 0.9.8h には、PKCS#12 ファイルを正しく生成できないバグがあるようだからです。

このPKCS#12ファイルは、サーバーがクライアントの認証を明示的に要求した場合に、Javaクライアントがサーバーにクライアント証明書を提示するために使用されます。を参照してください。 ウィキペディアのTLSに関する記事 は、クライアント証明書認証のプロトコルが実際にどのように動作するかの概要を説明します(ここでクライアントの秘密鍵が必要な理由も説明しています)。

その クライアントのトラストストア は、ストレートに JKS形式 を含むファイルです。 ルート または 中間CA証明書 . これらのCA証明書は、どのエンドポイントとの通信が許可されるかを決定します。この場合、クライアントはトラストストアのCAによって署名された証明書を提示するサーバーに接続することができるようになります。

生成するには、例えば、標準的なJavaのkeytoolを使用することができます。

keytool -genkey -dname "cn=CLIENT" -alias truststorekey -keyalg RSA -keystore ./client-truststore.jks -keypass whatever -storepass whatever
keytool -import -keystore ./client-truststore.jks -file myca.crt -alias myca

このトラストストアを用いて、クライアントは、以下の方法で識別される CA によって署名された証明書を提示するすべてのサーバと、完全な SSL ハンドシェイクを行おうとします。 myca.crt .

上記のファイルは、厳密にはクライアントのみのものです。サーバもセットアップしたい場合は、サーバ独自の鍵およびトラストストアのファイルが必要です。Javaクライアントとサーバ(Tomcatを使用)の両方を完全に動作させる例を設定するための素晴らしいウォークスルーは、次のサイトで見つけることができます。 このサイト .

課題/備考/Tips

  1. クライアント証明書認証 は、サーバーによってのみ強制することができます。
  2. ( 重要! ) サーバーがクライアント証明書を要求するとき(TLSハンドシェイクの一部として)、証明書要求の一部として信頼できるCAのリストも提供されます。認証のために提示したいクライアント証明書が ではない これらのCAによって署名されたものは、全く表示されません(私見ですが、これは奇妙な動作だと思います、しかし、何か理由があるのでしょう)。これは私の問題の主な原因でした。というのも、相手が私の自己署名付きクライアント証明書を受け入れるようにサーバーを適切に設定していなかったため、リクエストでクライアント証明書を適切に提供しなかった私の側に問題があると思い込んでしまったのです。
  3. Wiresharkを入手する。これは素晴らしいSSL/HTTPSパケット分析機能を持ち、デバッグや問題の発見をするのに非常に役立ちます。と似ています。 -Djavax.net.debug=ssl が、より構造化されており、Java SSLデバッグの出力に違和感がある場合は、(間違いなく)より簡単に解釈することができます。
  4. Apache の httpclient ライブラリを使用することは完全に可能です。httpclientを使用する場合は、宛先URLをHTTPSに置き換えて、以下のJVM引数を追加するだけです(これは、HTTP/HTTPSでデータを送受信するために使用したいライブラリに関係なく、他のクライアントでも同じです)。

    -Djavax.net.debug=ssl
    -Djavax.net.ssl.keyStoreType=pkcs12
    -Djavax.net.ssl.keyStore=client.p12
    -Djavax.net.ssl.keyStorePassword=whatever
    -Djavax.net.ssl.trustStoreType=jks
    -Djavax.net.ssl.trustStore=client-truststore.jks
    -Djavax.net.ssl.trustStorePassword=whatever