简体   繁体   English

用Java签名X.509证书

[英]Signing a X.509 certificate in Java

I want to find out how to sign a x.509 certificate. 我想了解如何签署x.509证书。

I have set up an OpenSSL CA to create a demo certificate. 我已经设置了OpenSSL CA以创建演示证书。 The certificate is fine and I can see all relevant elements using a tool called dumpasn1. 该证书很好,我可以使用称为dumpasn1的工具查看所有相关元素。 Theoretically I know I have to sign the structure called "tbsCertificate" which compounds the attributes version , serial number signature, issuer, validity, subject, subjectPublicKeyInfo and the extensions. 从理论上讲,我知道我必须对称为“ tbsCertificate”的结构进行签名,该结构包含属性版本,序列号签名,发行者,有效性,主题,subjectPublicKeyInfo和扩展名。

However, when I try to mimic that in Java, unfortunately it does not work. 但是,当我尝试在Java中模仿它时,不幸的是它不起作用。 What I do is: 我要做的是:

  • I read the "tbsCertificate"-portion of the DER-encoded certificate 我阅读了DER编码证书的“ tbsCertificate”部分
  • then I get the private key from the issuing CA 然后我从签发的CA获得私钥
  • last I try to sign the tbsCertificate-structure by using the following code: 最后,我尝试使用以下代码对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(); 
}

Unfortunately the result does not match the signature in the certificate, so obviously I made some kind of error. 不幸的是,结果与证书中的签名不匹配,因此显然我犯了某种错误。 The signature algorithm is the same that is used in the certificate (SHA256withECDSA), so I suspect that I did not choose the right portion of the tbsCertificate structure. 签名算法与证书(SHA256withECDSA)中使用的算法相同,因此我怀疑我没有选择tbsCertificate结构的正确部分。

My certificate is about 530 bytes long. 我的证书长约530字节。 I start reading from offset 4 (skipping the initial SEQUENCE tag and length bytes) to the end of the extensions (stopping before the begin of the certificate section). 我从偏移量4开始读取(跳过初始SEQUENCE标签和长度字节)到扩展的末尾(在证书部分开始之前停止)。

Can anybody tell if this is the right array of bytes I have to read for the "tbsCertificate" structure? 谁能说出这是否是我必须为“ tbsCertificate”结构读取的正确字节数组? Or what other error may I have made that I just don't see right now? 还是我现在看不到的其他错误是什么? The certificate itself is definitively ok, I double checked the certificate and the signing algorithm using the following Java code. 证书本身肯定可以,我使用以下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 doesn't produce stable signatures, so if your test is that you produced the same answer that won't work. ECDSA不会产生稳定的签名,因此如果您的测试是您产生了相同的答案,那将是行不通的。 You can verify the signature over a certificate by verifying the signature presented against the tbsCertificate data. 您可以通过针对tbsCertificate数据验证提供的签名来验证证书上的签名。

Your approach would work with an RSA signature, since that's a stable signature algorithm (with PKCS1 padding, not with PSS). 您的方法可以使用RSA签名,因为这是一种稳定的签名算法(使用PKCS1填充,而不使用PSS)。

As for finding the tbsCertificate: You do seem to have an idea of what the DER encoding is, but I feel compelled to provide guidance based on the loose description in the question: 至于找到tbsCertificate:您似乎对DER编码有一个大概的了解,但是我不得不基于问题的松散描述提供指导:

The binary encoded form of the certificate is in DER. 证书的二进制编码形式为DER。 The first byte will be 0x30 ((constructed) SEQUENCE). 第一个字节为0x30((构造的)SEQUENCE)。 The next byte is either how long the sequence is (< 0x80) or how long the length is (0x82 => the next two bytes are the big-endian length). 下一个字节是序列的长度(<0x80)或长度是多少(0x82 =>接下来的两个字节是big-endian长度)。 The next byte will again be 0x30, the start of the tbsCertificate encoded value. 下一个字节将再次为0x30,即tbsCertificate编码值的开始。 Then you can read the length of that structure, and compute the correct end offset for the tbsCertificate. 然后,您可以读取该结构的长度,并为tbsCertificate计算正确的末端偏移量。

The certificate structure can be found in RFC 3280 . 证书结构可以在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 -- which is where the X.509 in X.509 Certificate comes from. RFC 5280中有一个更新,但是我听说有人说“没有被批准为标准”。)它也与ITU-T X.509一起提供属性证书,这是X的所在X.509证书中的.509来自。 I linked to the 2012 version because the 2016 version is behind a paywall. 我链接到2012版本是因为2016版本在付费专区后面。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM