【问题标题】:My code can verify self signed certificate but is failing when VeriSign issued certificate is used我的代码可以验证自签名证书,但在使用 VeriSign 颁发的证书时失败
【发布时间】:2014-10-28 11:37:23
【问题描述】:

我的应用程序正在使用 java 安全 API 对文件进行签名和验证。 签名时,我使用 PFX 文件和密码作为输入,签名后我使用字节生成签名文件。 在验证过程中,我使用签名文件、证书文件和签名文件作为输入。 请在下面找到我在验证中使用的代码:

 // KeyFilePath= path of certificate file
 // fileToVerify = path of signed file
 // signatureFilePath = path of signature file



 InputStream inputStream = new FileInputStream(KeyFilePath);
 CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
 X509Certificate x509Certificate = (X509Certificate) certificateFactory.generateCertificate(inputStream);

 // input the signature bytes
 String sigFile = signatureFilePath;

 FileInputStream sigFileInputStream = new FileInputStream(sigFile);
 byte[] sigToVerify = new byte[sigFileInputStream.available()];
 sigFileInputStream.read(sigToVerify);
 sigFileInputStream.close();

 PublicKey pubKey = x509Certificate.getPublicKey();
 Signature signature = Signature.getInstance(signAlgorithm);

 signature.initVerify(pubKey);

 // Update and verify the data
 try {
    FileInputStream dataFileInputStream = new FileInputStream(fileToVerify);
    BufferedInputStream bufferedInputStream = new BufferedInputStream(dataFileInputStream);

    byte[] buffer = new byte[IVerifyDigitalSignature.BYTE_SIZE];
    int bufferedInputStreamLength;

    while (bufferedInputStream.available() != IVerifyDigitalSignature.ZERO_LENGTH) {
        bufferedInputStreamLength = bufferedInputStream.read(buffer);
        signature.update(buffer, IVerifyDigitalSignature.ZERO_LENGTH, bufferedInputStreamLength);
    }

    bufferedInputStream.close();

    // Verify the Signature
    x509Certificate.verify(pubKey);
    verifyDigitalSignature = signature.verify(sigToVerify);

请帮助我解决尚未关闭的问题。

【问题讨论】:

  • byte[] sigToVerify = new byte[sigFileInputStream.available()]; 被记录为 InputStream.available() 的错误使用,因此将其与零进行比较以作为流结束的测试。
  • 自签名证书由其“自己的”密钥签名,或者更准确地说,由其公共部分在证书中的密钥对的私有部分签名。因此x509certificate.verify(pubkey) 成功了,但基本上没用,因为任何攻击者都可以自签名欺诈性证书。 CA 签名的证书由 CA(私有)密钥签名,因此子证书可以并且通常必须通过定位 parent (CA) 证书并使用 that i> pubkey,迭代直到你到达根 CA,它是自签名的,并且只能因为它是手动信任的(通常在信任库文件中)而被信任。 ...
  • ... 除了有效的签名之外,还需要检查证书链是否有效(不是伪造或泄露)的其他一些东西。这通常称为 PKI 验证,或更具体地称为 PKIX 验证,因为该格式(针对 Internet 配置的 X.509 证书等)是最常见的。对于 Java,docs.oracle.com/javase/7/docs/technotes/guides/security/… 是一个相当不错的起点。
  • 感谢@dave_thompson_085 的回复。在我的情况下,我需要通过 Verisign 在 Java 问题中验证具有三个证书链的证书。那么这是否意味着我必须迭代三次才能到达根证书。根据您的评论,我了解到我们需要从 CA 证书中提取公钥。
  • 能否请您告诉我,我需要哪些输入来验证签名,即证书类型、签名文件等。

标签: java security digital-signature


【解决方案1】:

如果您想自己执行此操作, 是的,您必须将链中的证书从信任锚迭代到您想要的证书, 不管它有多长(它可能因不同的 CA、类别和不同的时间而有所不同)。 使用来自“父”(下一个更高级别)证书的公钥验证每个“子”(较低级别)证书上的签名只是一个 其中相当小的一部分;还需要许多其他步骤。 通常只是找到正确的证书可能是个问题;如果你已经有一个正确的链条,你就有了一个良好的开端。 但是你确定你有“正确的”链条吗?给定证书通常有几个可能的链, 有时其中一些是有效的,但其他一些已过期或无法验证。 Verisign 特别发布了我相信所有最近的证书都在其 G5 根目录下,但提供了替代路径 对于不是最新且有时无法更新的依赖项,返回(有效)G1。

大多数情况下的算法在“PKIX”RFC5280中定义, 除了用于撤销的 OCSP RFC6960 而不是 CRL 变得越来越普遍。 您可能会忽略跨层次结构和 NameConstraints,AFAIK 实际上并没有使用它们 由 Verisign 等公共 CA 以及 CA 使用但用户/依赖者不关心的策略内容。 https://security.stackexchange.com/questions/37409/certificate-chain-checking 有一个很好但不完整的介绍。

但是您可能会更好使用 Java(实际上是 JCE 的)CertPathValidator for "PKIX" -- 并且如果需要 CertPathBuilder -- 我已经提到过你。这已经由专家编写和测试。只是调用它 仍然有点复杂,但远没有重写它所做的所有事情那么复杂。

【讨论】:

  • 非常感谢@dave_thompson_085 的详细解释。我尝试了您提到的步骤,并且能够使用其颁发者证书验证服务器证书。
  • 但是我还需要使用签名过程中生成的“签名”文件来验证证书。为此,我在flexiprovider.de/examples/ExampleSMIMEverify.html 上有一个示例,它解决了我的问题,但它指出“验证CA 的证书是可能的,因为示例证书是自签名的。在现实生活中,您会检查此证书链到受信任的 CA,以确保拥有有效的证书。"
  • 那么请您帮助我解决如何解决“将此证书链检查到受信任的 CA 以确保拥有有效证书”的 java 代码提前谢谢
猜你喜欢
  • 1970-01-01
  • 2023-01-13
  • 1970-01-01
  • 1970-01-01
  • 2021-05-20
  • 2021-12-06
  • 1970-01-01
  • 1970-01-01
  • 2015-05-12
相关资源
最近更新 更多