使用bouny castle正确创建带有中间证书的新证书 [英] Correctly creating a new certificate with an intermediate certificate using bouny castle

查看:168
本文介绍了使用bouny castle正确创建带有中间证书的新证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我的问题如下,

基本上我想使用充气城堡(jdk16版本1.46)创建证书链。我对bouncy castle和java.security很新,所以如果我的方法可能完全错误,但无论如何这就是我所做的:

Basically I want to create a certificate chain using bouncy castle (jdk16 version 1.46). I am rather new to bouncy castle and java.security in general so if my approach might be completely wrong, but anyway this is what I did:

到目前为止我能够创建我用作根证书的自签名证书。这是使用以下代码完成的:

So far I am able to create a self signed certificate which I use as the root certificate. This is done using the following code:

//-----create CA certificate with key
KeyPair caPair = Signing.generateKeyPair("DSA", 1024, null, null);

这基本上创建了密钥对,两个空选项用于提供者和安全随机,如果需要。

This basically creates the keypair, the two null options are for a provider and a secure random, if needed.

Map<ASN1ObjectIdentifier, Entry<Boolean, DEREncodable>> caMap = new HashMap<ASN1ObjectIdentifier, Entry<Boolean, DEREncodable>>();
caMap.put(X509Extensions.BasicConstraints, new AbstractMap.SimpleEntry<Boolean, DEREncodable>(true, new BasicConstraints(true)));

//------this creates the self signed certificate        
X509Certificate caCert = X509CertificateGenerator.generateX509Certificate(serial, "CN=CA", "CN=CA", start, end, "SHA1withDSA", caPair.getPrivate(), caPair.getPublic(), null, caMap);

这将创建一个包含所提供属性的证书。

This will create the a certificate with the provided attributes.


  • serial =简单的当前时间(以毫秒为单位)

  • start =基本相同(可能有1或2毫秒的差异)

  • 结束=开始+ 2天

地图只是添加将证书设置为CA的基本约束。我在这里使用地图,因为我希望能够在需要时添加额外的X509扩展。

The map simply adds the basic contraint to set the certificate to be a CA. I use a map here since I want to be able to add additional X509Extensions if need be.

//-----save ca certificate in PEM format
X509CertificateGenerator.savePemX509Certificate(caCert, caPair.getPrivate(), caWriter);

这将使用bouncy caste pem writer将证书和私钥存储在pem文件中。

This will store the certificate and private key in a pem file using the bouncy caste pem writer.

之后生成文件,我也可以安装文件(我使用IE,然后通过Internet Options作为可信CA安装它。证书也显示为有效)。

After that the file is generated and I can install the file as well (I use IE and then install it via the Internet Options as a trusted CA. The certificate is also shown to be valid).

之后我使用以下代码创建中间证书(注意上面的代码在同一范围内,因此这些变量也可用)

After that I create the intermediate certificate, using the following code (note the above code is in the same scope so those variables are available as well)

KeyPair intermediatePair = Signing.generateKeyPair("DSA", 1024, null, null);    

Map<ASN1ObjectIdentifier, Entry<Boolean, DEREncodable>> intermediateMap = new HashMap<ASN1ObjectIdentifier, Entry<Boolean, DEREncodable>>();
intermediateMap.put(X509Extensions.AuthorityKeyIdentifier, new AbstractMap.SimpleEntry<Boolean, DEREncodable>(false, new AuthorityKeyIdentifierStructure(caCert)));
intermediateMap.put(X509Extensions.SubjectKeyIdentifier, new AbstractMap.SimpleEntry<Boolean, DEREncodable>(false, new SubjectKeyIdentifierStructure(intermediatePair.getPublic())));

X509Certificate intermediateCert = X509CertificateGenerator.generateX509Certificate(serial.add(BigInteger.valueOf(1l)), "CN=intermediate", caCert.getSubjectX500Principal().toString(), start, end, "SHA1withDSA", caPair.getPrivate(), intermediatePair.getPublic(), null, intermediateMap);   

//-----save intermediate certificate in PEM format
X509CertificateGenerator.savePemX509Certificate(intermediateCert, intermediatePair.getPrivate(), intermediateWriter);

这个程序基本相同,但是我添加了额外的X509Extensions:

The procedure is bascially the same, however I add additional X509Extensions:


  • X509Extensions.AuthorityKeyIdentifier =将CA证书设置为中间人父级

  • X509Extensions.SubjectKeyIdentifier =使用生成公钥作为证书

此外,CA用作发行者,CA私钥用于创建中间证书。

furthermore the CA is used as the issuer and the CA private key is used to create the intermediate certificate.

这也有效,我可以安装中间证书(再次使用IE),还显示父证书是生成的CA证书,证书有效。

This also works and I can install the intermediate certificate (using IE again), it is also shown that the parent certififcate is the generated CA certificate and that the certificate is valid.

现在出现了一个棘手的部分,我猜错了。我现在使用中间证书创建一个新证书,使用以下代码。

Now comes the tricky part where I am making a mistake I guess. I now create a new certificate using the intermediate certificate, using the following code.

KeyPair endPair = Signing.generateKeyPair("DSA", 1024, null, null);

Map<ASN1ObjectIdentifier, Entry<Boolean, DEREncodable>> endMap = new HashMap<ASN1ObjectIdentifier, Entry<Boolean, DEREncodable>>();
endMap.put(X509Extensions.AuthorityKeyIdentifier, new AbstractMap.SimpleEntry<Boolean, DEREncodable>(false, new AuthorityKeyIdentifierStructure(intermediateCert)));
endMap.put(X509Extensions.SubjectKeyIdentifier, new AbstractMap.SimpleEntry<Boolean, DEREncodable>(false, new SubjectKeyIdentifierStructure(endPair.getPublic())));

X509Certificate endCert = X509CertificateGenerator.generateX509Certificate(serial.add(BigInteger.valueOf(1l)), "CN=end", intermediateCert.getSubjectX500Principal().toString(), start, end, "SHA1withDSA", intermediatePair.getPrivate(), endPair.getPublic(), null, endMap);

X509CertificateGenerator.savePemX509Certificate(endCert, endPair.getPrivate(), endWriter);

基本上与创建中间证书相同。但是我现在使用以下X509Extension设置:

Essentially it is the same as creating the intermediate certificate. However I now use the following X509Extension settings:


  • X509Extensions.AuthorityKeyIdentifier =将中间证书设置为证书父级

  • X509Extensions.SubjectKeyIdentifier =使用生成的公钥作为证书

此外,中间证书也用作发行人及其私钥用于创建证书。

Also the intermediate certificate is used as the issuer and its private key is used to create the certificate.

我也可以安装新证书但是当我检查是否(再次是IE)时,它显示证书无效,因为此CA无权签发证书,或证书不能用作终端实体。

I can also install the new certificate but when I examine if (again IE), it shows that the certificate is however invalid because "This CA is either not entitled to issue certificates or the certificate can not be used as an end-entity."

所以我不知何故需要启用中间证书我也可以通过添加一些KeyUsages / ExtendedKeyUsage来创建新证书。

So I somehow need to enable the intermediate certificate to be able to create new certificates as well, by adding some KeyUsages/ExtendedKeyUsage I assume.

有人知道我如何启用中间证书来做我需要它做的事情或者如果我在基因上做错了什么ral?

Does someone know how I enable the intermediate certificate to do what I need it to do or if I do something wrong in general ?

编辑1:

好的,我忘了提供创建证书的方法的代码和一个以PEM格式保存它(我将其重命名为 savePemX509Certificate ,因为旧版本是错误的)。

So okay I forgot to provide the code for the method which created the certificate and the one that saved it in PEM format (I renamed it to savePemX509Certificate since the old one was misguiding).

证书生成代码:

public static X509Certificate generateX509Certificate(BigInteger serialnumber, String subject, String issuer, Date start , Date end, String signAlgorithm, PrivateKey privateKey, PublicKey publicKey, String provider, Map<ASN1ObjectIdentifier, Entry<Boolean, DEREncodable>> map) throws CertificateEncodingException, InvalidKeyException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException
{
    if(serialnumber!=null && subject!=null && issuer!=null && start!=null && end!=null && signAlgorithm !=null && privateKey!=null && publicKey!=null)
    {
        //-----GENERATE THE X509 CERTIFICATE
        X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
        X509Principal dnSubject = new X509Principal(subject);
        X509Principal dnIssuer = new X509Principal(issuer);

        certGen.setSerialNumber(serialnumber);
        certGen.setSubjectDN(dnSubject);
        certGen.setIssuerDN(dnIssuer);
        certGen.setNotBefore(start);
        certGen.setNotAfter(end);
        certGen.setPublicKey(publicKey);
        certGen.setSignatureAlgorithm(signAlgorithm);

        //-----insert extension if needed
        if(map!=null)
            for(ASN1ObjectIdentifier extension : map.keySet())
                certGen.addExtension(extension, map.get(extension).getKey(), map.get(extension).getValue());

        return certGen.generate(privateKey, provider);  
    }
    return null;
}

保存证书和密钥的代码:

Code for the saveing of the certificate and key:

public static boolean savePemX509Certificate(X509Certificate cert, PrivateKey key, Writer writer) throws NoSuchAlgorithmException, NoSuchProviderException, CertificateEncodingException, SignatureException, InvalidKeyException, IOException 
{       
    if(cert!=null && key!=null && writer!=null)
    {               
        PEMWriter pemWriter = new PEMWriter(writer);
        pemWriter.writeObject(cert);
        pemWriter.flush();

        if(key!=null)
        {
            pemWriter.writeObject(key);
            pemWriter.flush();
        }
        pemWriter.close();
        return true;
        }
    return false;
}

正如您所见,我基本上将证书和密钥放在文件中,就这样。结果是以下,对我来说似乎很好。

As you can see I basically put the certificate and the key in the file, thats all. The result is the following and seems good to me.

-----BEGIN CERTIFICATE-----
MIICdjCCAjagAwIBAgIGAUDuXLRLMAkGByqGSM44BAMwDTELMAkGA1UEAwwCQ0Ew
HhcNMTMwOTA1MTM0MzA3WhcNMTMwOTA3MTM0MzA3WjANMQswCQYDVQQDDAJDQTCC
AbcwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADD
Hj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gE
exAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/Ii
Axmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4
V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozI
puE8FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4Vrl
nwaSi2ZegHtVJWQBTDv+z0kqA4GEAAKBgAeFoGATLbIr8+QNuxcbYJ7RhbefKWSC
Br67Pp4Ynikxx8FZN4kCjGX7pwT1KffN3gta7jxIXNM5G3IFbs4XnYljh5TbdnjP
9Ge3kxpwncsbMQfCqIwHh8T5gh55KaxH7yYV2mrtEEqj7NBL4thQhJe2WGwgkB9U
NxNmLoMq3m4poyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAJ
BgcqhkjOOAQDAy8AMCwCFFm5ybLY09y8y2uGsEnpceffy2KaAhQIyshgy3ohCLxQ
q3CmnvC+cfT2VQ==
-----END CERTIFICATE-----
-----BEGIN DSA PRIVATE KEY-----
MIIBuwIBAAKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR
+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb
+DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdg
UI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlX
TAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCj
rh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQB
TDv+z0kqAoGAB4WgYBMtsivz5A27FxtgntGFt58pZIIGvrs+nhieKTHHwVk3iQKM
ZfunBPUp983eC1ruPEhc0zkbcgVuzhediWOHlNt2eM/0Z7eTGnCdyxsxB8KojAeH
xPmCHnkprEfvJhXaau0QSqPs0Evi2FCEl7ZYbCCQH1Q3E2YugyrebikCFDJCJHtt
NWB4LWYc4y4QvJ/l46ap
-----END DSA PRIVATE KEY-----

因此,在gtrig为我提供了创建证书的正确方法之后,我最终使用此方法创建了正常或自签名(如果私钥是fr与公钥相同的keyPair是证书

So after gtrig provided me with the correct way to create the certificate, I ended up using this method to create either a normal or self signed (if the private key is from the same keyPair as the public key that is) certificate

public static X509Certificate createX509V3Certificate(X500Principal name, BigInteger serial, Date start, Date end, PublicKey pubKey, String algorithm, PrivateKey privateKey, Map<ASN1ObjectIdentifier, Entry<Boolean, ASN1Object>> map, X509Certificate parentCert) throws IOException, OperatorCreationException, CertificateException
{
    if(serial!=null && start!=null && end!=null && name!=null && pubKey!=null && algorithm!=null && privateKey!=null)
    {
        ContentSigner signer = new JcaContentSignerBuilder(algorithm).build(privateKey);
        X509v3CertificateBuilder certBldr = null;
        if(parentCert==null)
            certBldr = new JcaX509v3CertificateBuilder(name, serial, start, end, name, pubKey);
        else
            certBldr = new JcaX509v3CertificateBuilder(parentCert, serial, start, end, name, pubKey);

        if(map!=null)
            for(ASN1ObjectIdentifier extension : map.keySet())
                certBldr.addExtension(extension, map.get(extension).getKey(), map.get(extension).getValue());

        return new JcaX509CertificateConverter().setProvider("BC").getCertificate(certBldr.build(signer));  
    }
    return null;
}


推荐答案

方式出现问题你正在创建PEM文件。你正在使用一个名为 generateSelfSignedPemX509Certificate 的方法,但你真的不想要一个自签名证书,你想要一个由中间私钥签名的结束证书,而你想要一个由CA私钥签名的中间证书。

Something looks wrong with the way you're creating the PEM files. You're using a method called, generateSelfSignedPemX509Certificate, but you don't really want a self-signed certificate, you want an end certificate signed by the intermediate private key, and you want an intermediate certificate signed by the CA private key.

另外,你需要基本约束密钥用法证书上的扩展名。

Also, you need basic constraints and key usage extensions on your certificates.

为了创建由其他实体签名的证书(非自签名),我使用这些方法从Bouncy Castle创建结束证书。

For creating certificates signed by other entities (non-self-signed), I use these methods from Bouncy Castle to create an "end" certificate.

  ASN1Sequence seq= 
     (ASN1Sequence) new ASN1InputStream(parentPubKey.getEncoded()).readObject();

  SubjectPublicKeyInfo parentPubKeyInfo = new SubjectPublicKeyInfo(seq);

  ContentSigner signer = new JcaContentSignerBuilder(algorithm).build(parentPrivKey);

  X509v3CertificateBuilder certBldr = 
     new JcaX509v3CertificateBuilder(
        parentCert, 
        serialNum,
        startDate, 
        endDate, 
        distName, 
        pubKey)
     .addExtension(
           new ASN1ObjectIdentifier("2.5.29.35"),
           false,
           new AuthorityKeyIdentifier(parentPubKeyInfo))
     .addExtension(
        new ASN1ObjectIdentifier("2.5.29.19"), 
        false,
        new BasicConstraints(false)) // true if it is allowed to sign other certs
     .addExtension(
        new ASN1ObjectIdentifier("2.5.29.15"),
        true,
        new X509KeyUsage(
           X509KeyUsage.digitalSignature |
           X509KeyUsage.nonRepudiation   |
           X509KeyUsage.keyEncipherment  |
           X509KeyUsage.dataEncipherment));

  // Build/sign the certificate.
  X509CertificateHolder certHolder = certBldr.build(signer);

  X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC)
     .getCertificate(certHolder);

对于CA或中间证书,您需要添加 SubjectKeyIdentifier 扩展名。此外, BasicConstraints 应为 true ,KeyUsage应为:

For a CA or intermediate certificate, you'll need to add a SubjectKeyIdentifier extension. Also, BasicConstraints should be true, and KeyUsage should be:

        new X509KeyUsage(
           X509KeyUsage.keyCertSign|
           X509KeyUsage.cRLSign));

这篇关于使用bouny castle正确创建带有中间证书的新证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆