Подпишите CSR с BouncyCastle

Я искал последние несколько дней для решения моей проблемы и ничего не мог найти. Мне чего-то не хватает в моем коде, но я не могу понять, что :( Каким-то образом, когда я подписываю свой PKCS # 10, цепочка разрывается.

В основном у меня есть сервер и клиент. Я хочу, чтобы клиент отправил CSR на сервер, а сервер подписал его, чтобы они могли общаться. Теперь я настроил PKCS # 12 с BouncyCastle для клиента, и я установил 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));

Теперь я создаю 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");

Я отправляю этот JcaPKCS10CertificationRequest в закодированном виде по сети. Сервер получает его и создает свой сертификат CA и теперь должен подписать PKCS # 10, но я что-то здесь упускаю, потому что он не включает цепочку. Сертификат, который он создает, содержит информацию об эмитенте и основных ограничениях, но путь сертификации включает только сертификат клиента, а НЕ сертификат сервера, поэтому он не заслуживает доверия, поскольку цепочка разорвана.

Вот что я делаю (серверное хранилище ключей имеет сертификат CA в позиции 0, 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();

Теперь, как я уже сказал, в сгенерированном файле «cer.cer» нет цепочки. Как добавить цепочку? Могу ли я отправить этот подписанный сертификат обратно клиенту, и его можно будет использовать в рукопожатии ssl?


person voodoo    schedule 18.02.2016    source источник


Ответы (1)


Чтобы добавить цепочку, это сработало для меня

После 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();

С этим кодом вы получаете сертификат с полной цепочкой в ​​формате PCKS#7. Если вы предпочитаете работать с форматом 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;

}

Это публичный сертификат. В вашем клиенте у вас должен быть закрытый ключ. Это все элементы, которые вам нужно выполнить, и рукопожатие ssl.

person pedrofb    schedule 23.06.2016