使用BouncyCastle的“轻量级”API验证TLS服务器证书

4
我正在使用Java BouncyCastle所谓的“轻量级”API在TCP套接字上建立TLS连接。
我想要验证由受信任的CA之一签名的服务器提供的证书链。听起来像是每个正常的TLS客户端实现默认都会做的相当普遍的任务,所以我期望这应该很简单。
为了简化问题,我不询问验证除签名/信任链以外的任何内容,例如匹配主机名或检查过期日期。这些检查似乎很容易实现。
如果我正确理解文档,那么有一个TlsAuthentication接口,用户应该实现它。唯一提供的实现是LegacyTlsAuthentication,它适配了现在已经过时的CertificateVerifyer接口,该接口仅有AlwaysValidVerifyer实现(在幕后只是虚拟的"return true;")。
所以,目前我的内容如下:
DefaultTlsClient tlsClient = new DefaultTlsClient() {
    @Override
    public TlsAuthentication getAuthentication() throws IOException {
        TlsAuthentication auth = new TlsAuthentication() {
            @Override
            public void notifyServerCertificate(Certificate serverCertificate) {
                // Here I should validate certificate chain, but this far
                // I only managed to print subjects for debugging purposes.
                for (org.bouncycastle.asn1.x509.Certificate c : serverCertificate.getCerts()) {
                    System.out.println("Certificate: " + c.getSubject().toString());
                }
            }

            @Override
            public TlsCredentials getClientCredentials(CertificateRequest cr) throws IOException {
                return null;
            }
        };
        return auth;
    }
};

socket = new Socket(hostname, port);
tlsHandler = new TlsProtocolHandler(socket.getInputStream(), socket.getOutputStream());
tlsHandler.connect(tlsClient);

然而,我无法理解或找到任何现有的示例来检查一个org.bouncycastle.asn1.x509.Certificate是否已被另一个证书正确签名。请问有人能够为我提供一些指引吗?
由于需要使用默认Java安装不允许的密码套件,因为它们受制于美国加密政策管辖范围,所以我正在使用BounceCastle的专有API。例如,AES256加密需要安装无限制强度策略文件,如果可能的话,我真的很想避免额外的最终用户安装步骤。
2个回答

5
X509CertificateHolder类的isSignatureValid方法适用于您。该方法接受一个参数,即ContentVerifierProvider。您可以通过将证书传递给构造函数来创建X509CertificateHolder。以下代码摘自BC的版本2 API页面,应该能为您提供如何在解决方案中实现此功能的好主意。
ContentVerifierProvider contentVerifierProvider =
   new BcRSAContentVerifierProviderBuilder(
      new DefaultDigestAlgorithmIdentifierFinder()).build(lwPubKey);

if (!certHolder.isSignatureValid(contentVerifierProvider))
{
    System.err.println("signature invalid");
}

"lwPubKey"是签名者的公钥。因此,根据您的证书链有多长,您需要从终端实体证书开始反复调用此方法,并向上处理到自签名根证书。

1

哇,这里有一堆已经过时的类。我为你感到难过。

你需要去的地方是

http://www.cs.berkeley.edu/~jonah/bc/org/bouncycastle/asn1/x509/KeyUsage.html#keyCertSign

keyCertSign将用于颁发CA证书。

您上面的代码serverCertificate.getCerts()将返回一个X509CertificateStructure对象数组(您的链),您可以为每个对象调用toASN1Object()来获取DerEncodable / KeyUsage接口。

希望这能帮到您。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接