私たちのシステムには、Jetty によって使用されるキー ストアに自己署名証明書を自動的に生成するためのコードがいくつかあります。特定のホストのキーが既に存在する場合は何も起こりませんが、存在しない場合は、次のように新しいキーを生成します。
public void generateKey(String commonName) {
X500Name x500Name = new X500Name("CN=" + commonName);
CertAndKeyGen keyPair = new CertAndKeyGen("DSA", "SHA1withDSA");
keyPair.generate(1024);
PrivateKey privateKey = keyPair.getPrivateKey();
X509Certificate certificate = keyPair.getSelfCertificate(x500Name, 20*365*24*60*60);
Certificate[] chain = { certificate };
keyStore.setEntry(commonName, privateKey, "secret".toCharArray(), chain);
}
キー ストアにキーと証明書が 1 つしかない限り、これはすべて正常に機能します。複数のキーを取得すると、接続しようとすると奇妙なことが起こります。
java.io.IOException: HTTPS hostname wrong: should be <127.0.0.1>
これは非常に不可解なエラーでしたが、サーバーに接続し、証明書の CN がホスト名と一致することをアサートする単体テストを作成することで、最終的に追跡することができました。私が発見したことは非常に興味深いものでした。Jetty は、クライアントに提示する証明書を恣意的に選択しているようですが、一貫した方法で行われているようです。
例えば:
- 「CN=localhost」と「CN=cheese.mydomain」がキー ストアにある場合、常に「CN=cheese.mydomain」が選択されます。
- 「CN=127.0.0.1」と「CN=cheese.mydomain」がキー ストアにある場合、常に「CN=cheese.mydomain」が選択されます。
- "CN=192.168.222.100" (cheese.mydomain) と "CN=cheese.mydomain" がキー ストアにある場合、常に "CN=192.168.222.100" が選択されます。
ストア内の証明書をループして印刷するコードをいくつか書きましたが、最初の証明書またはそのような些細なことを一貫して選択していないことがわかりました。
では、正確にはどのような基準を使用しているのでしょうか。最初は localhost は特別だと思っていましたが、3 番目の例に完全に戸惑いました。
これは、私の場合は SunX509 である KeyManagerFactory によって何らかの形で決定されると思います。