Java 安全 - 使用公钥的 X509 证书验证

标签 java rsa digital-signature x509certificate sha256

我正在从事的项目有很多安全操作。我以前从未遇到过安全问题。因此,我的问题可以是初级水平。

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

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

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;
}

最佳答案

典型的 PKI 系统使用 Certificate Authorities向主题颁发证书(通过签名)。通过签署证书颁发机构形成从 CA 到主体证书的链,如果 CA1(根 CA)签发 CA2(中间 CA)证书,则该链可以包含多个 CA,其中turn 唱出受试者的证书。这在互联网(对于 SSL/TLS)和数字签名场景中很常见。

因此您很可能至少需要一个 CA 的证书和它的公钥来验证主体的证书。您的程序也可以支持多个独立的 CA。您的程序接受的 CA 通常称为 Trust Anchors .将信任 anchor 保持在 KeyStore 中也很方便。

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

为了进行正确的证书验证,除了链的签名之外,您还需要检查其他内容,例如 key 使用、基本约束、吊销信息等。所有这些都在 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);

但请注意有很多more nuances and details必须妥善解决这个问题,以便真正安全地实现。错误的证书路径检查是安全问题的常见原因。

关于Java 安全 - 使用公钥的 X509 证书验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33493109/

相关文章:

java - 当一个 @Around 建议无法继续时,建议优先级问题

java - 安卓测试 : Can I send sms to the emulator number from test method?

python - P12 中 pyOpenSSL 中的 RSA key 参数

java - 如何在Java中仅使用证书而不使用私钥来签署pdf文件?

java - iText 数字签名损坏 PDF/A 2b

java - JMenuItem退出不退出

java - 从java调用批处理需要从当前批处理文件夹启动

node.js - 如何在nodejs中将大的十六进制值转换为整数?

java - C# 创建的数字签名与 Java 验证不匹配

c++ - Windows 8 的驱动程序签名要求有何变化?