我目前正在尝试通过Java中的SSL / TLS通过Internet传输数据,我希望双方都对自己进行身份验证。我已经实现了KeyManager来加载密钥对并向另一方提供适当的证书。
现在,我正在尝试检查证书,并通过实现自己的TrustManager来做到这一点(双方都持有另一方的证书,所有内容都是自签名的)。但是,getAcceptedIssuers不能像我想要的那样工作,因为即使不返回任何内容,连接仍然可以毫无问题地建立。
为什么不拒绝证书?
protected static class SelectingTrustManager implements X509TrustManager{
final X509TrustManager delegate;
private String[] trustedAliases;
private final KeyStore keystore;
public SelectingTrustManager(X509TrustManager delegate, KeyStore keystore, String[] trustedAliases) {
this.trustedAliases = trustedAliases;
this.keystore = keystore;
this.delegate = delegate;
}
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException{
delegate.checkClientTrusted(chain, authType);
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException{
delegate.checkServerTrusted(chain, authType);
}
public X509Certificate[] getAcceptedIssuers(){
return new X509Certificate[0];
}
}
答案 0 :(得分:1)
您不清楚您的代码是客户端还是服务器,因此我都回答了这两个问题,尽管这仅对服务器重要。
尽管javadoc不是特定的,但是X509TM.getAcceptedIssuers
并不用于决定是否信任已接收的证书或链。这完全由客户端中的checkServerTrusted
或服务器中的checkClientTrusted
完成。
getAcceptedIssuers
的值仅用于并且影响两件事:
(仅)(如果启用了客户端身份验证(通过调用needClientAuth(true)
或wantClientAuth(true)
),则使用其元素中的使用者名称在{中创建CA列表。 {3}}。如果收到,则不必与将用作客户端证书链的信任锚的CA列表相同。实际上,实际上并不需要信任管理器使用信任锚列表,甚至不需要使用server's CertificateRequest
message的其余部分-尽管如果您的“代表”是使用标准{{ 1}} 那。但是,如果您告诉客户使用某些CA的证书,然后不接受这些CA的有效证书链,则您可能会有不满意的客户,这些客户可能会追随您。各种重的,尖锐的和/或其他不愉快的物体。
在 no 'CAs'(长度为0的数组)的特定情况下,客户端可以从其选择的任何CA发送证书,服务器将接受该证书仅在X509[Extended]TrustManager
上。
为完整起见,RFC为客户端定义了扩展,以指定客户端希望服务器证书使用的CA,但是我不知道任何支持此扩展的实现,而Java / JSSE绝对不支持,因此在实践中,服务器要么仅具有一个证书(每个算法),要么基于SNI选择(并且没有其他选择),并且如果客户端不信任该证书,那就太糟糕了。
如果您具有有效的算法约束(如今,即使您未明确设置某些约束,如今通常也会默认执行),它们不会在链中的最后一个证书上强制执行(推定锚)(如果它是由CertPathValidator
返回的证书中的),这些证书被假定为(实际)锚。换句话说,如果证书是信任锚,则即使它使用的算法不符合当前标准(例如MD5或小于1024的RSA),也可能是用户决定信任它。
将证书放入信任库或以其他方式使其成为锚点的人实际上正确地评估了其安全性是Java不会尝试回答的另一个问题。尽管我敢肯定有人会很乐意尝试,但是即使Stackexchange也可能无法做到这一点。 (我不承诺是否会成为其中之一。)