简体   繁体   English

使用Java中的Bouncy Castle创建具有主题备选方案的PKCS10请求

[英]Create PKCS10 request with subject alternatives using Bouncy Castle in Java

I am currently using bouncy castle to create a PKCS10 request with a single subject as such: 我目前正在使用充气城堡来创建一个PKCS10请求,其中包含一个主题:

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

I now need to add subject alternatives to the PKCS10 request. 我现在需要为PKCS10请求添加主题替代。 I have been unable to figure out how to do this. 我一直无法弄清楚如何做到这一点。 Any suggestions? 有什么建议?

SOLUTION: 解:

Based on the great info provided in the 2nd answer I was able to figure this out. 基于第二个答案中提供的精彩信息,我能够弄明白这一点。 In the working code below XName is a simple class holding the subject name and name type (DNS, RFC822, etc). 在下面的工作代码中,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();

I had the same issue Mike, and I think your problem relates to trying to do this using a JcaPKCS10CertificationRequestBuilder (from the version 2 APIs) instead of by using the deprecated V1 APIs. 我有同样的问题Mike,我认为你的问题与尝试使用JcaPKCS10CertificationRequestBuilder(来自版本2 API)而不是使用已弃用的V1 API有关。

If you go to the BC wiki pages and look for "X.509 Public Key Certificate and Certificate request generation" there is a reasonable description of what to do with the Version 1 APIs, which is very similar to the listing on page 212 of the Wrox book by David Hook, "Beginning Cryptography with Java". 如果您转到BC维基页面并查找“X.509公钥证书和证书请求生成” ,则可以合理地描述如何处理版本1 API,这与第212页上的列表非常相似。 David Hook撰写的Wrox一书,“用Java开始加密”。

The documentation on the wiki for the version 2 APIs is really poor when describing how to create a CSR though. 在描述如何创建CSR时,关于版本2 API的Wiki的文档非常糟糕。

To summarise how to use the v2 APIs, here's some code I have which works which is based on their V2 tests case (the class to look for is below this code listing): 总结一下如何使用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

I'd suggest looking closely at their wiki pages specifically for the v2 API. 我建议仔细查看他们专门针对v2 API的维基页面。

Critically, once you have found the source code for cert.test.PKCS10Test for V2 it all starts to make sense. 重要的是,一旦找到了适用于V2的cert.test.PKCS10Test的源代码,一切都开始有意义了。 Finally, I use this JavaScript hex dumper for ASN1 to check that it is coming out correctly. 最后,我使用这个用于ASN1的JavaScript十六进制转储程序来检查它是否正确输出。

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

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