在 Java 中签署 X.509 证书

Signing a X.509 certificate in Java

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

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

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

.

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(跳过初始序列标记和长度字节)开始读取到扩展的末尾(在证书部分开始之前停止)。

谁能告诉我这是否是我必须为 "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;
}

ECDSA 不会产生稳定的签名,所以如果您的测试是您产生了相同的答案,那是行不通的。您可以通过验证针对 tbsCertificate 数据提供的签名来验证证书上的签名。

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

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

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

可以在 RFC 3280. (There's an update in RFC 5280 but I've heard people say "that didn't get approved as a standard".) It's also available, along with attribute certificates, in ITU-T X.509 中找到证书结构 -- 这是 X.509 证书中的 X.509 的来源。我链接到 2012 版是因为 2016 版是付费专区。