使用充气城堡签署企业社会责任

2022-09-01 06:00:56

我找不到任何描述如何使用BC签署CSR的代码/文档。作为输入,我有一个CSR作为字节数组,并希望获得PEM和/或DER格式的证书。

我已经走到了这一步

def signCSR(csrData:Array[Byte], ca:CACertificate, caPassword:String) = {
  val csr = new PKCS10CertificationRequestHolder(csrData)
  val spi = csr.getSubjectPublicKeyInfo

  val ks = new java.security.spec.X509EncodedKeySpec(spi.getDEREncoded())
  val kf = java.security.KeyFactory.getInstance("RSA")
  val pk = kf.generatePublic(ks)

  val (caCert, caPriv) = parsePKCS12(ca.pkcs12data, caPassword)

  val fromDate : java.util.Date = new java.util.Date // FixMe
  val toDate = fromDate // FixMe
  val issuer = PrincipalUtil.getIssuerX509Principal(caCert)
  val contentSigner = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(BC).build(caPriv)
  val serial = BigInt(CertSerialnumber.nextSerialNumber)
  val certgen = new JcaX509v3CertificateBuilder(new X500Name(issuer.getName), serial.bigInteger, fromDate, toDate, csr.getSubject, pk)

我很难弄清楚从证书生成器获取以PEM或DER格式存储它。

还是我一起走错了路?


答案 1

还行。。。我想做同样的事情,对于我的生活,我不知道该怎么做。API 都讨论生成密钥对,然后生成证书,而不是如何对 CSR 进行签名。不知何故,很偶然 - 这是我发现的。

由于 PKCS10 表示请求(CSR)的格式,因此您首先需要将 CSR 放入 PKCS10Holder 中。然后,将其传递给 CertificateBuilder(因为 CertificateGenerator 已被弃用)。传递它的方式是在持有者上调用 getSubject。

这是代码(Java,请根据需要进行调整):

public static X509Certificate sign(PKCS10CertificationRequest inputCSR, PrivateKey caPrivate, KeyPair pair)
        throws InvalidKeyException, NoSuchAlgorithmException,
        NoSuchProviderException, SignatureException, IOException,
        OperatorCreationException, CertificateException {   

    AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder()
            .find("SHA1withRSA");
    AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder()
            .find(sigAlgId);

    AsymmetricKeyParameter foo = PrivateKeyFactory.createKey(caPrivate
            .getEncoded());
    SubjectPublicKeyInfo keyInfo = SubjectPublicKeyInfo.getInstance(pair
            .getPublic().getEncoded());

    PKCS10CertificationRequestHolder pk10Holder = new PKCS10CertificationRequestHolder(inputCSR);
    //in newer version of BC such as 1.51, this is 
    //PKCS10CertificationRequest pk10Holder = new PKCS10CertificationRequest(inputCSR);

    X509v3CertificateBuilder myCertificateGenerator = new X509v3CertificateBuilder(
            new X500Name("CN=issuer"), new BigInteger("1"), new Date(
                    System.currentTimeMillis()), new Date(
                    System.currentTimeMillis() + 30 * 365 * 24 * 60 * 60
                            * 1000), pk10Holder.getSubject(), keyInfo);

    ContentSigner sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId)
            .build(foo);        

    X509CertificateHolder holder = myCertificateGenerator.build(sigGen);
    X509CertificateStructure eeX509CertificateStructure = holder.toASN1Structure(); 
    //in newer version of BC such as 1.51, this is 
    //org.spongycastle.asn1.x509.Certificate eeX509CertificateStructure = holder.toASN1Structure(); 

    CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");

    // Read Certificate
    InputStream is1 = new ByteArrayInputStream(eeX509CertificateStructure.getEncoded());
    X509Certificate theCert = (X509Certificate) cf.generateCertificate(is1);
    is1.close();
    return theCert;
    //return null;
}

如您所见,我已经在此方法之外生成了请求,但将其传入。然后,我有PKCS10CertificationRequestHolder接受它作为构造函数arg。

接下来,在 X509v3CertificateBuilder 参数中,您将看到 pk10Holder.getSubject - 这显然是您所需要的全部?如果缺少某些内容,也请告诉我!!!它对我有用。我正确生成的证书具有我需要的 DN 信息。

维基百科上有一个关于PKCS的杀手部分 - http://en.wikipedia.org/wiki/PKCS


答案 2

以下代码基于上述答案,但将进行编译,并且在给定 PEM 编码的 CSR(由 keytool 导出的那种)的情况下,将返回一个有效的 PEM 编码的 signedData 对象,其中包含已签名的证书链(可通过 keytool 导入的类型)。

哦,这是针对BouncyCastle 1.49的。

import java.security.*;
import java.io.*;
import java.util.Date;
import java.math.BigInteger;
import java.security.cert.X509Certificate;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.asn1.x500.*;
import org.bouncycastle.asn1.pkcs.*;
import org.bouncycastle.openssl.*;
import org.bouncycastle.pkcs.*;
import org.bouncycastle.cert.*;
import org.bouncycastle.cms.*;
import org.bouncycastle.cms.jcajce.*;
import org.bouncycastle.crypto.util.*;
import org.bouncycastle.operator.*;
import org.bouncycastle.operator.bc.*;
import org.bouncycastle.operator.jcajce.*;
import org.bouncycastle.util.encoders.Base64;

/**
 * Given a Keystore containing a private key and certificate and a Reader containing a PEM-encoded
 * Certificiate Signing Request (CSR), sign the CSR with that private key and return the signed
 * certificate as a PEM-encoded PKCS#7 signedData object. The returned value can be written to a file
 * and imported into a Java KeyStore with "keytool -import -trustcacerts -alias subjectalias -file file.pem"
 *
 * @param pemcsr a Reader from which will be read a PEM-encoded CSR (begins "-----BEGIN NEW CERTIFICATE REQUEST-----")
 * @param validity the number of days to sign the Certificate for
 * @param keystore the KeyStore containing the CA signing key
 * @param alias the alias of the CA signing key in the KeyStore
 * @param password the password of the CA signing key in the KeyStore
 *
 * @return a String containing the PEM-encoded signed Certificate (begins "-----BEGIN PKCS #7 SIGNED DATA-----")
 */
public static String signCSR(Reader pemcsr, int validity, KeyStore keystore, String alias, char[] password) throws Exception {
    PrivateKey cakey = (PrivateKey)keystore.getKey(alias, password);
    X509Certificate cacert = (X509Certificate)keystore.getCertificate(alias);
    PEMReader reader = new PEMReader(pemcsr);
    PKCS10CertificationRequest csr = new PKCS10CertificationRequest((CertificationRequest)reader.readObject());

    AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
    AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
    X500Name issuer = new X500Name(cacert.getSubjectX500Principal().getName());
    BigInteger serial = new BigInteger(32, new SecureRandom());
    Date from = new Date();
    Date to = new Date(System.currentTimeMillis() + (validity * 86400000L));

    X509v3CertificateBuilder certgen = new X509v3CertificateBuilder(issuer, serial, from, to, csr.getSubject(), csr.getSubjectPublicKeyInfo());
    certgen.addExtension(X509Extension.basicConstraints, false, new BasicConstraints(false));
    certgen.addExtension(X509Extension.subjectKeyIdentifier, false, new SubjectKeyIdentifier(csr.getSubjectPublicKeyInfo()));
    certgen.addExtension(X509Extension.authorityKeyIdentifier, false, new AuthorityKeyIdentifier(new GeneralNames(new GeneralName(new X509Name(cacert.getSubjectX500Principal().getName()))), cacert.getSerialNumber()));

    ContentSigner signer = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(PrivateKeyFactory.createKey(cakey.getEncoded()));
    X509CertificateHolder holder = certgen.build(signer);
    byte[] certencoded = holder.toASN1Structure().getEncoded();

    CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
    signer = new JcaContentSignerBuilder("SHA1withRSA").build(cakey);
    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);

    ByteArrayOutputStream out = new ByteArrayOutputStream();
    out.write("-----BEGIN PKCS #7 SIGNED DATA-----\n".getBytes("ISO-8859-1"));
    out.write(Base64.encode(signeddata.getEncoded()));
    out.write("\n-----END PKCS #7 SIGNED DATA-----\n".getBytes("ISO-8859-1"));
    out.close();
    return new String(out.toByteArray(), "ISO-8859-1");
}

推荐