Tre*_*kaz 18 java ssl jetty certificate
我们的系统中有一些代码用于自动生成自签名证书到密钥存储区,然后由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);
}
Run Code Online (Sandbox Code Playgroud)
只要密钥库中只有一个密钥和证书,这一切都可以正常工作.一旦你有多个密钥,当你尝试连接时会发生奇怪的事情:
java.io.IOException: HTTPS hostname wrong: should be <127.0.0.1>
Run Code Online (Sandbox Code Playgroud)
这是一个非常神秘的错误,但我终于设法通过编写连接到服务器的单元测试来跟踪它,并断言证书上的CN与主机名匹配.我发现非常有趣 - Jetty似乎随意选择向客户提供哪种证书,但是以一致的方式.
例如:
我编写了一些代码,这些代码循环遍历商店中的证书以将其打印出来,并发现它并非始终如一地选择第一个证书或类似的任何小问题.
那么它究竟使用什么标准呢?最初我认为localhost很特别,但第三个例子完全让我感到困惑.
我认为这是由KeyManagerFactory以某种方式决定的,在我的情况下是SunX509.
Bru*_*uno 15
这确实最终由KeyManager
(通常从a获得KeyManagerFactory
)决定.
密钥库可以在不同的别名下存储许多证书.如果certAlias
在Jetty配置中没有显式配置别名,则SunX509
实现将选择它找到的第一个别名,其中包含私钥和所选密码套件的正确类型的密钥(通常是RSA,但在您的情况下可能是DSA)这里).如果你看一下Sun提供程序的实现,那么选择逻辑会有更多的内容,但你不应该真正依赖顺序,只需要别名.
你当然可以给码头自己SSLContext
用自己X509KeyManager
选择的别名.你必须实现:
chooseServerAlias(String keyType, Principal[] issuers, Socket socket)
Run Code Online (Sandbox Code Playgroud)
不幸的是,除了keyType
和之外issuers
,所有你做出决定的都是它socket
自己.充其量,您获得的有用信息是本地IP地址和远程IP地址.
除非您的服务器在同一端口上侦听多个IP地址,否则您将始终获得相同的本地IP地址.(在这里,很明显,你至少有两个:127.0.0.1
和192.168.222.100
,但我怀疑你是不是除了自己的测试在本地主机很感兴趣.)您需要在服务器端的服务器名称指示(SNI)的支持,能够使基于请求的主机名(由支持它的客户端)做出的决定.不幸的是,SNI仅在Java 7中引入,但仅在客户端引入.
您将面临的另一个问题是Java客户端会抱怨Subject DN的CN中的IP地址.有些浏览器会容忍这种情况,但这不符合HTTPS规范(RFC 2818).IP地址必须是IP地址类型的主题备用名称条目.
归档时间: |
|
查看次数: |
7504 次 |
最近记录: |