将签名添加到证书

时间:2016-09-27 18:23:26

标签: certificate bouncycastle

我有一些奇怪的要求,我必须忍受。我需要通过我的加密系统TBS证书,他们将签名并发回一个签名字符串,我需要将其合并到证书中以签署证书。

在SO上查看com.ibm.security.x509.X509CertImpl和各种BouncyCastle帖子,我无法了解如何做到这一点。

问题:

这可能吗? 如果是这样,怎么样?

2 个答案:

答案 0 :(得分:0)

我将参考BouncyCastle X509v3CertificateBuilder类(pkix jar)的源代码,并根据您的需要进行调整。请注意,此类使用V3TBSCertificateGenerator生成TBSCertificate。这是一个可以DER编码的ASN.1对象。然后,您可以获得由“加密系统”签名的DER编码。然后参考X509v3CertificateBuilder.build()方法,了解如何将TBS证书和签名放在最终的X.509证书中。

答案 1 :(得分:0)

我已经汇总了一个显示一种方法的例子。大部分代码都是从bouncycastle pkix或lwcrypto库中窃取的,但任何错误几乎都是我的。下面关注的最重要的方法是generateCert。其余的代码是用于驱动测试的测试工具。

代码专门编写为只需要bounycastle bcpkix和lwcrypto jar。如果使用bcprov jar而不是lwcrypto,它可以稍微缩短。

import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.TBSCertificate;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.bc.BcX509v3CertificateBuilder;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder;

import javax.security.auth.x500.X500Principal;
import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Date;

public class Main {

    private static class TBSCertPlusSignature {
        private final byte[] encodedTbsCert;
        private final byte[] signature;

        public TBSCertPlusSignature(byte[] encodedTbsCert, byte[] signature) {
            this.encodedTbsCert = encodedTbsCert;
            this.signature = signature;
        }

        public byte[] getEncodedTbsCert() {
            return encodedTbsCert;
        }

        public byte[] getSignature() {
            return signature;
        }
    }

    private static TBSCertPlusSignature makeTestCert(KeyPair keyPair) throws Exception {
        Date now = new Date();
        Date nowPlus1Hour = new Date(now.getTime() + 1000 * 60 * 60 * 1L);
        byte[] encodedName = new X500Principal("CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US").getEncoded();
        X500Name issuer = X500Name.getInstance(encodedName);
        X500Name subject = issuer;
        RSAPublicKey rsaPub = (RSAPublicKey) keyPair.getPublic();
        RSAKeyParameters rsaPubParams = new RSAKeyParameters(false, rsaPub.getModulus(), rsaPub.getPublicExponent());
        BcX509v3CertificateBuilder certBuilder = new BcX509v3CertificateBuilder(
                issuer,
                BigInteger.valueOf(100L),
                now,
                nowPlus1Hour,
                subject,
                rsaPubParams
        );


        AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSA");
        AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
        RSAPrivateCrtKey rsaPriv = (RSAPrivateCrtKey) keyPair.getPrivate();
        RSAPrivateCrtKeyParameters rsaPrivParams = new RSAPrivateCrtKeyParameters(
                rsaPriv.getModulus(),
                rsaPriv.getPublicExponent(),
                rsaPriv.getPrivateExponent(),
                rsaPriv.getPrimeP(),
                rsaPriv.getPrimeQ(),
                rsaPriv.getPrimeExponentP(),
                rsaPriv.getPrimeExponentQ(),
                rsaPriv.getCrtCoefficient()
        );

        ContentSigner contentSigner = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(rsaPrivParams);
        final X509CertificateHolder x509CertificateHolder = certBuilder.build(contentSigner);
        byte[] tbsCertDER = x509CertificateHolder.toASN1Structure().getTBSCertificate().getEncoded();
        byte[] signature = x509CertificateHolder.getSignature();
        return new TBSCertPlusSignature(tbsCertDER, signature);
    }


    private static X509Certificate generateCert(byte[] tbsCertEncoded, byte[] signature) throws Exception {
        // Given the der encoded TBS cert and signature, create the corresponding X509 certificate

        TBSCertificate tbsCert = TBSCertificate.getInstance(tbsCertEncoded);

        ASN1EncodableVector v = new ASN1EncodableVector();

        v.add(tbsCert);
        v.add(tbsCert.getSignature());
        v.add(new DERBitString(signature));

        DERSequence derSequence = new DERSequence(v);
        ByteArrayInputStream baos = new ByteArrayInputStream(derSequence.getEncoded());
        return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(baos);
    }


    public static void main(String[] args) throws Exception {

        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(1024);
        KeyPair keyPair = kpg.generateKeyPair();

        TBSCertPlusSignature testData = makeTestCert(keyPair);

        X509Certificate x509Cert = generateCert(testData.getEncodedTbsCert(), testData.getSignature());

        // Verify the signature

        x509Cert.verify(keyPair.getPublic());

        // Print the cert

        PublicKey publicKey = x509Cert.getPublicKey();
        System.out.println(x509Cert);

    }
}