1. ホーム
  2. java

SSL証明書のサーバー名はどのように解決されますか/keytoolを使用して代替名を追加できますか?

2023-08-08 19:17:22

質問

これらは、わかりやすくするために別々の質問として表現されることがありますが、すべて同じ問題に関連しています。

SSL証明書のサーバー名はどのように解決されるのですか?

なぜブラウザは証明書のCNフィールドを使用するようですが、Javaのメカニズムは"subject alternative names"だけを見るようなのでしょうか?

keytoolを使用して、SSL証明書に代替名を追加することは可能でしょうか? そうでない場合、代わりにopenSSLを使用することは良い選択でしょうか?

ほんの少しの背景です。 私は、メインサーバーがHTTPSを使用していくつかのサーバーと通信するようにする必要があります。明らかに、すべてのサーバーの SSL 証明書を購入したくないので (多数ある可能性があります)、自己署名証明書を使用したいと思います (私はそれらを生成するために keytool を使用してきました)。OSで証明書を信頼済みとして追加した後、ブラウザ(IEとChrome)は喜んで信頼済みとして接続を受け入れる。しかし、証明書をJavaのcacertsに追加した後でも、Javaはまだ信頼できる接続として受け入れず、以下のExceptionをスローします。

原因:java.security.cert.CertificateException: サブジェクトの代替名がない 現在 at sun.security.util.HostnameChecker.matchIP(HostnameChecker.java:142)。 at sun.security.util.HostnameChecker.match(HostnameChecker.java:75)。 at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkIdentity(X509T rustManagerImpl.java:264) at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted( X509TrustManagerImpl.java:250) at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Clien tHandshaker.java:1185) ... 14件以上

ここからコピーした独自のHostNameVerifierを実装することで、Javaに証明書を信頼させることができることがわかりました。 com.sun.jbi.internal.security.https.DefaultHostnameVerifier を試してみました(ちなみに、HostnameVerifierの引数として渡されたホスト名は正しいので、受理されているはずだと思います)。

ホスト名には、証明書フィールドのCNを使用しています(通常はIPアドレス)。

どなたか、私が何か間違ったことをしているかどうか教えていただき、正しい方向に導いていただけないでしょうか。

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

ホスト名の検証をどのように行うべきかは RFC 6125 これは非常に新しいもので、すべてのプロトコルにこの方法を一般化したものです。 RFC 2818 というように、HTTPSに特化したものでした。(Java 7 が RFC 6125 を使用しているかどうかもわからないし、これでは新しすぎるかもしれない)。

から RFC 2818 (第 3.1 節) :

dNSName タイプの subjectAltName 拡張が存在する場合、それを ID として使用しなければなりません (MUST)。 をIDとして使用しなければならない。そうでない場合は、証明書のSubjectフィールドにある(最も具体的な)Common Name フィールドが使用されなければならない(MUST)。しかし Common Nameの使用は既存の慣行であるが、非推奨であり、認証機関はCommon Nameの使用を推奨する。 認証機関は、代わりにdNSNameを使用することが推奨されます。

[...]

場合によっては、URIはホスト名ではなくIPアドレスで指定されることがあります。 として指定される場合があります。この場合、iPAddress subjectAltName が証明書内に存在し、URI の IP と正確に一致する必要があります。 が証明書内に存在し、URI の IP と正確に一致しなければなりません。

基本的に、あなたが抱えている特定の問題は、ホスト名ではなく IP アドレスを CN に使用しているという事実に起因しています。特に、RFC 2818 の "most specific" が明確に定義されていないため (RFC 6215 の議論を参照)、すべてのツールがこの仕様に厳密に従うわけではないので、一部のブラウザでは動作する可能性があります。

もしあなたが keytool , をJava 7の時点では keytool には、サブジェクト代替名を含めるオプションがあります (ドキュメント内の -ext を使うことができます。 -ext san=dns:www.example.com または -ext san=ip:10.0.0.1 .

EDITです。

OpenSSLでSANを要求するには、以下のように変更します。 openssl.cnf を使って明示的に場所を指定することができます (私の記憶では、グローバルな設定を編集したくない場合は、現在のディレクトリにあるコピーを選びます。 OPENSSL_CONF 環境変数)。

以下のオプションを設定します(最初に括弧内の適切なセクションを見つけます)。

[req]
req_extensions = v3_req

[ v3_req ]
subjectAltName=IP:10.0.0.1
# or subjectAltName=DNS:www.example.com

また、このために(設定ファイルで固定するのではなく)環境変数を使用する素晴らしいトリックがここにあります。 http://www.crsr.net/Notes/SSL.html