Java 安全性 - 使用公钥进行 X509 证书验证

mis*_*anc 4 java rsa sha256 digital-signature x509certificate

我正在做的一个项目有这么多安全操作。我以前从未遇到过安全问题。因此,我的问题可以是初学者级别。

在我的问题中,我得到一个字节数组数据,它有一个证书和一些其他参数。我需要验证此证书及其签名。但我无法处理签名验证。事实上,我不知道我应该使用哪个公钥来验证。

代码如下。感谢帮助..!

public boolean startValidation(PublicKey publicKey) {
    CertificateFactory cf;
    try {
         cf = CertificateFactory.getInstance("X.509");
    } catch (CertificateException e) {
        e.printStackTrace();
        return false;
    }
    try {
        certificate = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(certBytes));
    } catch (CertificateException e) {
        e.printStackTrace();
        setCertError(0);
        return false;
    }
    if (!checkProvider()){
        setCertError(1);
        return false;
    }

    boolean[] usages = certificate.getKeyUsage();
    boolean usage = usages[0] && usages[2];
    if (!usage){
        setCertError(2);
    }

    try {
        certificate.checkValidity();
    } catch (CertificateNotYetValidException e) {
        e.printStackTrace();
        setCertError(3);
        return false;
    } catch (CertificateExpiredException e) {
        e.printStackTrace();
        setCertError(4);
        return false;
    }

    System.out.println("Sign Algorithm Name " + certificate.getSigAlgName());
    //Output is SHA256WithRSAEncryption

   // Problem area
    try {
        Signature signature = Signature.getInstance("SHA256WithRSA");
        signature.initVerify(publicKey); //Should I use this certificate.getPublicKey() or what ??
        if(signature.verify(certificate.getSignature())){
            System.out.println("Accepted");
        }else System.out.println("Failure");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (SignatureException e) {
        e.printStackTrace();
    }

    System.out.println("Public Key Format " + publicKey.getFormat() + "\nPublic Key Algorithm " + publicKey.getAlgorithm() );
    System.out.println("Subject DN -> " + certificate.getSubjectDN().getName());


    return true;
}
Run Code Online (Sandbox Code Playgroud)

Zor*_*art 10

典型的 PKI 系统使用证书颁发机构向主题颁发证书(通过签名)。通过签署证书颁发机构形成从 CA 到主体证书的链,如果 CA1(根 CA)发出 CA2(中间 CA)的证书,而后者又发出主体的证书,则该链可以包含多个 CA。这在 Internet(对于 SSL/TLS)和数字签名方案中非常常见。

因此,您很可能至少需要一个 CA 的证书,并且它是用于验证主体证书的公钥。您的程序也可以支持多个独立的 CA。您的程序接受的 CA 通常称为Trust Anchors。将信任锚保存在KeyStore中也非常方便。

因此,您最终可能会得到一个包含信任锚和中间 CA 的密钥库。从那里开始,您需要形成链并验证下巴中从根 CA(信任锚)到您尝试验证的主题证书的所有证书的签名。

对于正确的证书验证,除了链的签名之外,您还需要检查其他内容,例如密钥使用、基本约束、撤销信息等。所有这些都在证书路径验证中的RFC5280中指定。

幸运的是,已经有CertPath API形式的 Java API可以帮助您解决这个问题。一个适合您的用例的非常基本的示例是:

final CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");

final X509Certificate certificateToCheck = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(certBytes));

final KeyStore trustStore = KeyStore.getInstance("JKS");
InputStream keyStoreStream = ...
trustStore.load(keyStoreStrem, "your password".toCharArray());

final CertPathBuilder certPathBuilder = CertPathBuilder.getInstance("PKIX");
final X509CertSelector certSelector = new X509CertSelector();
certSelector.setCertificate(certificateToCheck);

final CertPathParameters certPathParameters = new PKIXBuilderParameters(trustStore, certSelector);
final CertPathBuilderResult certPathBuilderResult = certPathBuilder.build(certPathParameters);
final CertPath certPath = certPathBuilderResult.getCertPath();

final CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX");
final PKIXParameters validationParameters = new PKIXParameters(trustStore);
validationParameters.setRevocationEnabled(true); // if you want to check CRL
final X509CertSelector keyUsageSelector = new X509CertSelector();
keyUsageSelector.setKeyUsage(new boolean[] { true, false, true }); // to check digitalSignature and keyEncipherment bits
validationParameters.setTargetCertConstraints(keyUsageSelector);
final PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult) certPathValidator.validate(certPath, validationParameters);

System.out.println(result);
Run Code Online (Sandbox Code Playgroud)

但请注意,为了使实施真正安全,必须正确解决更多细微差别和细节。错误的证书路径检查是安全问题的常见原因。