【问题标题】:Signing a X.509 certificate in Java用 Java 签署 X.509 证书
【发布时间】:2017-03-28 15:01:20
【问题描述】:

我想了解如何签署 x.509 证书。

我已设置 OpenSSL CA 来创建演示证书。证书很好,我可以使用名为 dumpasn1 的工具查看所有相关元素。 从理论上讲,我知道我必须签署名为“tbsCertificate”的结构,该结构复合属性版本、序列号签名、发行者、有效性、主题、subjectPublicKeyInfo 和扩展。

但是,当我尝试在 Java 中模仿它时,不幸的是它不起作用。 我要做的是:

  • 我阅读了 DER 编码证书的“tbsCertificate”部分
  • 然后我从颁发 CA 获得私钥
  • 最后我尝试使用以下代码对 tbsCertificate 结构进行签名:

.

public static void sign(byte [] data) throws Exception  
{
    String algorithm = "SHA256withECDSA";
    PrivateKey privKey;
    KeyPair keyPair;

    keyPair = getKeyPairFomPEM();
    privKey = keyPair.getPrivate();

    Signature ecdsa;
    ecdsa = Signature.getInstance(algorithm, "BC");
    ecdsa.initSign(privKey);
    ecdsa.update(data);
    byte[] baSignature = ecdsa.sign(); 
}

不幸的是,结果与证书中的签名不匹配,所以显然我犯了某种错误。 签名算法与证书中使用的相同(SHA256withECDSA),所以我怀疑我没有选择正确的 tbsCertificate 结构部分。

我的证书大约有 530 字节长。我从偏移量 4 开始读取(跳过初始 SEQUENCE 标记和长度字节)到扩展的末尾(在证书部分开始之前停止)。

谁能告诉我这是否是我必须为“tbsCertificate”结构读取的正确字节数组? 或者我可能犯了什么其他我现在看不到的错误? 证书本身肯定没问题,我使用以下 Java 代码仔细检查了证书和签名算法。

public static X509Certificate loadCertificate(String fileName)
{
    InputStream in;
    byte [] signature;
    X509Certificate cert = null;
    try
    {
        in = new FileInputStream(fileName);
        CertificateFactory factory = CertificateFactory.getInstance("X.509");
        cert = (X509Certificate) factory.generateCertificate(in);
        signature = cert.getSignature();
        System.out.println("Signature Algorithm: " + cert.getSigAlgName());
        System.out.println(signature);
        return cert;
    }
    catch (FileNotFoundException e)
    {
        e.printStackTrace();
    }
    catch (CertificateException e)
    {
        e.printStackTrace();
    }
    return cert;
}

【问题讨论】:

    标签: java certificate x509 signing asn.1


    【解决方案1】:

    ECDSA 不会产生稳定的签名,因此如果您的测试是您产生了相同的答案,那么您将无法正常工作。您可以通过验证针对 tbsCertificate 数据呈现的签名来验证证书上的签名。

    您的方法适用于 RSA 签名,因为这是一种稳定的签名算法(使用 PKCS1 填充,而不是使用 PSS)。

    至于查找 tbsCertificate:您似乎确实知道 DER 编码是什么,但我觉得有必要根据问题中的松散描述提供指导:

    证书的二进制编码形式是 DER。第一个字节将是 0x30((构造的)序列)。下一个字节是序列有多长( 接下来的两个字节是大端长度)。下一个字节将再次是 0x30,即 tbsCertificate 编码值的开始。然后您可以读取该结构的长度,并计算 tbsCertificate 的正确结束偏移量。

    证书结构见RFC 3280。 (RFC 5280 中有更新,但我听说有人说“这没有被批准为标准”。)它也可以与属性证书一起在ITU-T X.509 中使用——这就是 X.509在 X.509 证书来自。我链接到 2012 版是因为 2016 版在付费墙后面。

    【讨论】:

    • 感谢您的回答。我知道 DER 编码并且它以序列开头。我只是不想让这个问题变得更长更复杂。我也知道 RFC 3280,它或多或少对 tbsCertificate 很清楚。如果我正确解释它,它应该从偏移量 4 处的第二个“SEQUENCE”字节开始并延伸到给定的长度。你说 ECDSA 不会产生稳定的签名是什么意思?我想完全按照您的描述进行操作-我想在 tbsCertificate 上运行签名算法以重新创建签名。我认为
    • 我想我现在明白了 stable 的含义 - 感谢您对此事的评论。我原以为我可以重新创建签名。感谢您的提示,我尝试重新签署测试证书,它似乎有效。当我验证修补的证书时,它验证正常。
    • 很高兴我能帮上忙 :)。 StackOverflow 关于“谢谢”的礼仪:如果答案是正确的,请标记它。如果它对您有帮助,您还可以选择支持它。
    猜你喜欢
    • 2017-11-28
    • 2014-09-15
    • 2011-02-24
    • 1970-01-01
    • 1970-01-01
    • 2012-07-22
    • 2018-04-16
    • 2014-09-30
    • 1970-01-01
    相关资源
    最近更新 更多