【问题标题】:Java Security - X509 Certificate Verification with Public KeyJava 安全 - 使用公钥的 X509 证书验证
【发布时间】:2016-02-03 06:01:04
【问题描述】:

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

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

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

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

【问题讨论】:

  • 首先我在这方面也没有经验,所以我只有一个系统可以在代码中禁用此检查,但不建议用于 PROD 环境,因为我知道你没有要进行此验证,因为它将由 JVM(SSL 协议的 JSSE 实现)处理,并且 JVM 提供它,您应该将“cacert”文件添加到您的 JRE 环境中,更多信息在 nakov.com/blog/2009/07/16/…java-samples.com/showtutorial.php?tutorialid=210
  • 您可以在此 repo 中看到的证书验证示例:github.com/esig/dss/blob/…
  • 其实我们没有cacert文件。禁用验证对我来说不是解决方案。问题更多的是“验证证书签名”。感谢您的回答@erhun
  • 我的工作更多的是字节操作。感谢@Krzysiek 的回答
  • @mismanc 顺便说一句。我认为您正在寻找这个:stackoverflow.com/a/3152396/1630872

标签: java rsa digital-signature x509certificate sha256


【解决方案1】:

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

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

因此,您最终可能会得到一个包含信任锚和中间 CA 的 KeyStore。从那里开始,您需要形成链并验证从根 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);

但请注意,必须正确处理许多more nuances and details,以使实施真正安全。错误的证书路径检查是安全问题的常见原因。

【讨论】:

  • 首先感谢您的说明性回答。当我检查即将到来的字节数组包时,我发现我没有“我的密码”。所以我想是PCKS7格式的证书。你怎么看?你有这方面的信息吗?
  • 我猜 PCKS7 和“我的密码”问题无关紧要。
  • PKCS#7 文件被称为 PKI 信封,它们的目的是携带数字签名数据,您在问题中问的是如何验证证书而不是如何验证任意文件的数字签名.那将是另一个问题,由于您是stackoverflow的新手,请阅读stackoverflow.com/help/how-to-askstackoverflow.com/help/someone-answers
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-02
  • 1970-01-01
  • 1970-01-01
  • 2020-05-23
  • 1970-01-01
  • 2019-08-09
  • 2012-09-28
相关资源
最近更新 更多