使用Java中的Bouncy Castle创建带有主题替代的PKCS10请求

时间:2015-12-09 02:52:08

标签: java bouncycastle

我目前正在使用bouncy castle创建一个PKCS10请求,其中包含一个主题:

    X500Principal subject = new X500Principal("CN=foo.bar.com");
    PKCS10CertificationRequestBuilder builder = new JcaPKCS10CertificationRequestBuilder(
            subject, publicKey);

我现在需要为PKCS10请求添加主题替代。我一直无法弄清楚如何做到这一点。有什么建议吗?

解决方案:

根据第二个答案中提供的精彩信息,我能够弄清楚这一点。在下面的工作代码中,XName是一个包含主题名称和名称类型(DNS,RFC822等)的简单类。

        String signerAlgo = "SHA256withRSA";
        ContentSigner signGen = new JcaContentSignerBuilder(signerAlgo).build(privateKey);

        X500Principal subject = new X500Principal(csr.getSubjectAsX500NameString());

        PKCS10CertificationRequestBuilder builder = 
                new JcaPKCS10CertificationRequestBuilder(subject, publicKey);

        /*
         * Add SubjectAlternativeNames (SANs)
         */
        if (csr.getSubjectAlternatives() != null && csr.getSubjectAlternatives().size() > 0) {
            List<GeneralName> namesList = new ArrayList<>();
            for (XName subjectAlt : csr.getSubjectAlternatives()) {
                log.debug(m, d+2, "Adding SubjectAltName: %s", subjectAlt);
                namesList.add(GeneralNameTool.toGeneralName(subjectAlt));
            }

            /*
             * Use ExtensionsGenerator to add individual extensions.
             */
            ExtensionsGenerator extGen = new ExtensionsGenerator();

            GeneralNames subjectAltNames = new GeneralNames(namesList.toArray(new GeneralName [] {}));
            extGen.addExtension(Extension.subjectAlternativeName, false, subjectAltNames);
            builder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, extGen.generate());
        }

        PKCS10CertificationRequest request = builder.build(signGen);

        StringWriter writer = new StringWriter();
        JcaPEMWriter pem = new JcaPEMWriter(writer);
        pem.writeObject(request);
        pem.close();

1 个答案:

答案 0 :(得分:2)

Mike遇到了同样的问题,我认为你的问题与尝试使用JcaPKCS10CertificationRequestBuilder(来自版本2 API)而不是使用已弃用的V1 API有关。

如果您访问BC维基页面并查找"X.509 Public Key Certificate and Certificate request generation",则可以合理地描述如何处理第1版API,这与David的Wrox书籍第212页上的列表非常相似Hook,&#34;用Java开始加密&#34;。

在描述如何创建CSR时,关于版本2 API的Wiki的文档非常糟糕。

总结一下如何使用v2 API,这里有一些基于V2测试用例的代码(要查找的类在此代码清单下面):

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import org.bouncycastle.asn1.DEROctetString;

import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.encoders.Hex;

...

X500NameBuilder x500NameBld = new X500NameBuilder(BCStyle.INSTANCE);

// See e.g. http://javadox.com/org.bouncycastle/\
// bcprov-jdk15on/1.51/org/bouncycastle/asn1/x500/style/BCStyle.html
// for a description of the available RDNs

x500NameBld.addRDN(BCStyle.CN, commonName);
x500NameBld.addRDN(BCStyle.OU, orgCode);
x500NameBld.addRDN(BCStyle.UNIQUE_IDENTIFIER, "64 bit EUID goes here");

X500Name    subject = x500NameBld.build();

/**
 *  My application needs to set the Key Usage section of the CSR 
 * (which for my app has a Criticality of "true" and a value of
 * "digital signature" or "key agreement").
 */

 Extension[] extSigning = new Extension[] {
        new Extension(Extension.basicConstraints, true, 
           new DEROctetString(new BasicConstraints(true))),
           new Extension(Extension.keyUsage, true,
           new DEROctetString(new KeyUsage(KeyUsage.keyCertSign))),
  };

  Extension[] extKeyAgreement = new Extension[] {
        new Extension(Extension.basicConstraints, true, 
           new DEROctetString(new BasicConstraints(true))),
           new Extension(Extension.keyUsage, true, 
           new DEROctetString(new KeyUsage(KeyUsage.keyCertSign))),
   };

   PKCS10CertificationRequest req = 
     new JcaPKCS10CertificationRequestBuilder(
         subject,
         pair.getPublic())
         .addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest,
         new Extensions(isKaFlag==true?extKeyAgreement:extSigning))
         .build(new JcaContentSignerBuilder("SHA256withECDSA")
         .setProvider(BC)                         
         .build(pair.getPrivate()));

    return req;  // The PKCS10 certificate signing request

我建议仔细查看专门针对v2 API的维基页面。

重要的是,一旦你找到了V2的 cert.test.PKCS10Test 的源代码,一切都开始有意义了。最后,我使用this JavaScript hex dumper for ASN1 检查它是否正确出来。