我正在通过SSLSocket连接到使用证书进行握手的远程主机。由于我们不使用具有所有证书颁发机构的默认JVM信任库,因此我需要将远程主机证书添加到我的信任库。
如何从SSLSocket获取我应该信任的证书?它似乎确实检索它们我需要使用似乎需要握手的SSLSession。 为什么我们需要执行握手才能检索证书?
是否有任何工具允许提取使用的远程主机证书?
答案 0 :(得分:4)
实际上,握手期间会出示证书,以便服务器可以识别自己,并最终为客户端提供相同的信息。
当你这样做时:
SSLContext context = SSLContext.getInstance("TLS");
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
[...]
SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
SSLSocket socket = (SSLSocket)factory.createSocket(host, port);
try {
socket.startHandshake();
socket.close();
} catch (SSLException e) {
e.printStackTrace(System.out);
}
如果你没有在startHandshake()上获得异常,则意味着证书由于某种原因已经被信任(直接出现在密钥库中,由可信实体签名)。
是否发生异常,您可以访问下载的链:
X509Certificate[] chain = tm.chain;
if (chain == null) {
// error in downloading certificate chain
return;
}
// loop through chain
for (int i = 0; i < chain.length; i++) {
X509Certificate cert = chain[i];
[....]
}
使用X509Certificate对象实例,您实际上可以更新您的第k个密钥库:
X509Certificate cert = chain[k];
String alias = host + "-" + (k + 1);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
[...]
ks.setCertificateEntry(alias, cert);
OutputStream out = new FileOutputStream("jssecacerts");
ks.store(out, passphrase);
out.close();
查看here以获取完整的样本。
或者,为您信任的服务器下载证书的另一种更安全的方法是使用openssl命令:
# openssl s_client -showcerts -connect $SERVER:$PORT 2>&1 | \
sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' >/tmp/$SERVERNAME.cert
然后照常导入keytool
。
答案 1 :(得分:3)
通常,您不应该从SSLSocket
获得您应该信任的证书,而应该是您独立获得的配置设置,作为您想要信任的参考。
您似乎想要做的是获取第一个连接的证书,希望没有拦截该连接,然后将其用作后续连接的参考(类似于SSH通常所做的事情,当您不必知道第一个连接上的服务器密钥的指纹,但检查以后是否得到相同的信息。
安全方面,这并不理想,因为初始连接可能被MITM攻击者截获(这会使所有后续连接都受到攻击),但这肯定是一种降低风险的方法。理想情况下,您应该将该证书与您以其他方式获得的已知参考进行比较。
您可以使用自定义X509TrustManager
在握手期间访问远程证书(或者您可以禁用信任验证并稍后获取证书),然后您可以使用该证书初始化SSLContext
,从中您可以获得SSLSocketFactory
。在信任管理器中禁用信任验证通常是一个坏主意(因为它打开了与MITM攻击的连接),但是为此目的可以接受。您可能对InstallCert
实用程序感兴趣,该实用程序应该或多或少地执行您所需要的工作。
为什么我们需要在访问服务器之前进行握手 证书?
这是在握手期间完成的,因为SSL / TLS套接字API的目的是为应用程序层提供一个可以认为是安全的套接字,并在该阶段或多或少地使用普通套接字。通常,对于JSSE(或通常是其他SSL / TLS堆栈)的大多数用途,作为使用该堆栈的应用程序开发人员,您不希望必须明确地进行验证。在握手期间检查证书也建议作为TLS specification:
的一部分收到服务器hello done消息后,客户端应该 验证服务器是否提供了有效证书(如果需要) 并检查服务器hello参数是否可以接受。