简体   繁体   English

与BouncyCastle签署CSR

[英]Sign CSR with BouncyCastle

I have been looking for the past few days for a solution on my Problem and couldn't find anything. 过去几天我一直在寻找解决问题的方法,但找不到任何东西。 I am missing something in my Code but i cant figure out what :( Somehow when I sign my PKCS#10 the chain is broken. 我的代码中缺少某些内容,但是我无法弄清楚什么:(当我在PKCS#10上签名时,链断了。

Basically i have a server and a client. 基本上我有一个服务器和一个客户端。 I want to have the client send a CSR to the server and the server signs it so they can communicate. 我希望客户端将CSR发送到服务器,并且服务器对其进行签名,以便他们可以进行通信。 Now i did set up a PKCS#12 with BouncyCastle for the Client and i did set up a RootCertificate for the Server (again with BouncyCastle, which is in my understanding just a PKCS#12 with the extension to be able to sign Certificates) In Code it looks like this: 现在,我确实为客户使用BouncyCastle设置了PKCS#12,并且我确实为服务器设置了RootCertificate(再次使用BouncyCastle,在我的理解中,这只是一个PKCS#12,具有能够签名证书的扩展名)编写如下代码:

Provider BC = new BouncyCastleProvider();
Security.addProvider(BC);
//create KeyPair
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
kpGen.initialize(2048, new SecureRandom());
pair = kpGen.generateKeyPair();
//building groundbase for certificate
X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
builder.addRDN(BCStyle.CN, commonName);
builder.addRDN(BCStyle.OU, organizationalUnit);
builder.addRDN(BCStyle.O, organization);
builder.addRDN(BCStyle.L, city);
builder.addRDN(BCStyle.ST, state);
builder.addRDN(BCStyle.C, country);
Date notBefore = new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24); //Yesterday
Date notAfter = new Date(System.currentTimeMillis() +  1000L * 365L * 24L * 60L * 60L); //in a year
BigInteger serial = BigInteger.valueOf(new SecureRandom().nextLong());
//creating a self-signed certificate from information in builder
X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(),
serial, notBefore, notAfter, builder.build(), pair.getPublic());

//The next line will make the difference between a Certificate and a Ca Certificate
certGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));

ContentSigner sigGen = new JcaContentSignerBuilder(").setProvider(BC).build(pair.getPrivate());
X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));

Now i create a CSR for the Client (Client keystore has the just created PKCS#12 at first position): 现在,我为客户端创建一个CSR(客户端密钥库在第一个位置刚创建的PKCS#12):

String alias = keystore.aliases().nextElement();
X509Certificate cert = (X509Certificate) keystore.getCertificate(alias);
X500Name x500name = new JcaX509CertificateHolder(cert).getSubject();
//builder for the PKCS10
PKCS10CertificationRequestBuilder requestBuilder = new JcaPKCS10CertificationRequestBuilder(x500name, cert.getPublicKey());
//algorithm identifier
DefaultSignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder();
DefaultDigestAlgorithmIdentifierFinder digAlgFinder = new DefaultDigestAlgorithmIdentifierFinder();
AlgorithmIdentifier sigAlgId = sigAlgFinder.find("SHA512WithRSA");
digAlgFinder.find(sigAlgId);
//content Signer
JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA512WithRSA");
//and build the Cert
ContentSigner signer = contentSignerBuilder.build((PrivateKey) keystore.getKey(alias, password));
PKCS10CertificationRequest req = requestBuilder.build(signer);
JcaPKCS10CertificationRequest req2 = new JcaPKCS10CertificationRequest(req.getEncoded()).setProvider("BC");

I send this JcaPKCS10CertificationRequest encoded over the network. 我通过网络发送了此JcaPKCS10CertificationRequest编码。 The Server gets it and creates his CA Certificate and now has to sign the PKCS#10 but i am missing something here because he is not including the chain. 服务器获取它并创建他的CA证书,现在必须签署PKCS#10,但是我在这里丢失了一些东西,因为他不包括链。 The Certificate he is creating has the information about the issuer and BasicConstraints but the certification path is only including the Clients Certificate and NOT the Certificate of the Server so it is not trustworthy since the chain is broken. 他正在创建的证书具有有关颁发者和BasicConstraints的信息,但是证书路径仅包括“客户端证书”而不是“服务器证书”,因此由于链已断开,因此它不可信。

This is what i do (Server Keystore has the CA Certificate at position 0, CSR is the JcaPKCS10CertificationRequest): 这是我的工作(服务器密钥库在位置0具有CA证书,CSR是JcaPKCS10CertificationRequest):

String alias = keystore.aliases().nextElement();
// PKCS#12 Root Certificate
X509Certificate cert = (X509Certificate) keystore.getCertificate(alias);
// generated Serial
BigInteger serial = BigInteger.valueOf(new SecureRandom().nextLong());
//identify algorithm
AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA512WithRSA");
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find( sigAlgId );

JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils();
JcaX509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(cert, serial, cert.getNotBefore(), cert.getNotAfter(),
            CSR.getSubject(), CSR.getPublicKey());
certGen.addExtension(Extension.authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(cert));

certGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(false));
certGen.addExtension(Extension.subjectKeyIdentifier, true, extUtils.createSubjectKeyIdentifier(inputCSR.getPublicKey()));
certGen.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment | KeyUsage.dataEncipherment | KeyUsage.nonRepudiation));
ContentSigner signer = new JcaContentSignerBuilder(sigAlgName).setProvider("BC").build((PrivateKey)keystore.getKey(alias, password));
X509CertificateHolder holder = certGen.build(signer);
X509Certificate signedCert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(holder);
signedCert.verify(cert.getPublicKey());
JcaPEMWriter pemWriter = new JcaPEMWriter(new FileWriter(new File("cer.cer")));
pemWriter.writeObject(signedCert);
pemWriter.writeObject(cert);
pemWriter.close();

Now as i said the generated File "cer.cer" has not the Chain in it. 现在,正如我所说,生成的文件“ cer.cer”中没有链。 How can i add the chain? 如何添加链条? Can i then send that signedCert back to the client and it can be used in a ssl handshake? 然后我可以将该签名证书发送回客户端,并且可以在SSL握手中使用吗?

To add the chain, this worked for me 要添加链,这对我有用

After X509CertificateHolder holder = certGen.build(signer); X509CertificateHolder holder = certGen.build(signer);

  byte[] certencoded = holder.toASN1Structure().getEncoded();
  ContentSigner signer = new JcaContentSignerBuilder("SHA1withRSA").build(caPrivateKkey);
  CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
  generator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()).build(signer, cacert));
  generator.addCertificate(new X509CertificateHolder(certencoded));
  generator.addCertificate(new X509CertificateHolder(cacert.getEncoded()));
  CMSTypedData content = new CMSProcessableByteArray(certencoded);
  CMSSignedData signeddata = generator.generate(content, true);

  byte certificateP7b[] = signedData.getEncoded();

With this code you get a Certificate with the full chain in PCKS#7 format. 通过此代码,您将获得PCKS#7格式的完整证书。 If you prefer to work with X509 format 如果您喜欢使用X509格式

public static List<X509Certificate> p7BToX509(byte signedCert[]) throws CertificateException{
    ByteArrayInputStream is = new ByteArrayInputStream( signedCert);
    CertificateFactory cf = CertificateFactory.getInstance( "X.509" );

    ArrayList<X509Certificate> certificates = new ArrayList<X509Certificate>();
    Iterator i = cf.generateCertificates( is ).iterator();
    while ( i.hasNext() ){
       X509Certificate c = (X509Certificate)i.next();
       certificates.add(c);

    }
    return certificates;

}

This is the public certificate. 这是公共证书。 In your client you should have the private key. 在您的客户端中,您应该具有私钥。 These are all elements you need to perform and ssl handshake 这些都是执行和ssl握手所需的所有元素

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

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