【问题标题】:Use Specific Private Key to Generate Certificate使用特定私钥生成证书
【发布时间】:2017-01-24 14:30:05
【问题描述】:

我正在使用充气城堡,我想生成一个特定的私钥,而不是生成的随机密钥。

我想提供自己的私钥,但代码不断生成随机密钥。有没有办法指定在充气城堡中使用的确切私钥?

我的代码如下。当我检查生成的证书的公钥时,我总是得到不同的值。我需要我指定的值。

主要

 var cb = new X509CertBuilder(suppliers, "CN=MandarinAS, OU=Scheme42, O=MandarinAS, C=GB",
                    CertStrength.Bits1024);


                   var cert = cb.MakeCertificate(pwd, "CN=Mandarin, OU=CustomerId, OU=Scheme42, O=OrgX, C=GB", 1,keypair);

                    File.WriteAllBytes("Cert.pfx", cert.Export(X509ContentType.Pkcs12, pwd));


                File.WriteAllBytes("Cert.cer", cert.Export(X509ContentType.Cert, pwd));
    var store = new X509Store(storeLocation);
                store.Open(OpenFlags.ReadOnly);

                var myCertificate = new X509Certificate2("Cert.pfx", "password");
                if (myCertificate.PrivateKey !

= null)
            {
                store.Close();

            }
//here i debug and compare the public key values myCertificate is always changing

X509CertBuilder.cs

public class X509CertBuilder
    {
        private const string SignatureAlgorithm = "SHA1WithRSA";
        private readonly int _strength;
        private readonly CryptoApiRandomGenerator _randomGenerator = new CryptoApiRandomGenerator();
        private readonly X509V3CertificateGenerator _certificateGenerator = new X509V3CertificateGenerator();
        private readonly SecureRandom _random;
        private readonly X509Name _issuer;
        private readonly GeneralName[] _generalNames;

        public X509CertBuilder(string[] validWithDomainNames, string issuer, CertStrength certStrength)
        {
            _random = new SecureRandom(_randomGenerator);
            _issuer = new X509Name(issuer);
            _strength = (int) certStrength;

            _generalNames = new GeneralName[validWithDomainNames.Length];
            for (var t = 0; t < validWithDomainNames.Length; t++)
            {
                _generalNames[t] = new GeneralName(new X509Name(validWithDomainNames[t]));
            }
        }

        public X509Certificate2 MakeCertificate(string password, string issuedToDomainName, int validYears, AsymmetricCipherKeyPair mykey=null)
        {
            _certificateGenerator.Reset();

            _certificateGenerator.SetSignatureAlgorithm(SignatureAlgorithm);
            var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue),
                _random);
            _certificateGenerator.SetSerialNumber(serialNumber);

            _certificateGenerator.SetSubjectDN(new X509Name(issuedToDomainName));
            _certificateGenerator.SetIssuerDN(_issuer);

            var subjectAlternativeNames = new Asn1Encodable[_generalNames.Length + 1];
            // first subject alternative name is the same as the subject
            subjectAlternativeNames[0] = new GeneralName(new X509Name(issuedToDomainName));
            for (var t = 1; t <= _generalNames.Length; t++)
            {
                subjectAlternativeNames[t] = _generalNames[t - 1];
            }
            var subjectAlternativeNamesExtension = new DerSequence(subjectAlternativeNames);
            _certificateGenerator.AddExtension(X509Extensions.SubjectAlternativeName.Id, false,
                subjectAlternativeNamesExtension);

            _certificateGenerator.SetNotBefore(DateTime.UtcNow.Date);
            _certificateGenerator.SetNotAfter(DateTime.UtcNow.Date.AddYears(validYears));
            var keyGenerationParameters = new KeyGenerationParameters(_random, _strength);

            var keyPairGenerator = new RsaKeyPairGenerator();


            keyPairGenerator.Init(keyGenerationParameters);
            var subjectKeyPair = keyPairGenerator.GenerateKeyPair();

            _certificateGenerator.SetPublicKey(subjectKeyPair.Public);

            //Previouse auto key
            //var issuerKeyPair = subjectKeyPair;

            //My mykey
            var issuerKeyPair = mykey;
            var certificate = _certificateGenerator.Generate(issuerKeyPair.Private,_random);


            var store = new Pkcs12Store();
            var friendlyName = certificate.SubjectDN.ToString();
            var certificateEntry = new X509CertificateEntry(certificate);
            store.SetCertificateEntry(friendlyName, certificateEntry);
            store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(issuerKeyPair.Private), new[] {certificateEntry});

            using (var stream = new MemoryStream())
            {
                store.Save(stream, password.ToCharArray(), _random);
                return new X509Certificate2(stream.ToArray(), password,
                    X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
            }
        }
    }

【问题讨论】:

    标签: c# encryption x509certificate bouncycastle x509certificate2


    【解决方案1】:

    编辑:对 Java 的回答不正确。 BouncyCastle C# API 不容易在线访问,但我相信你要找的是X509CertificateParser


    如果你有 DER 格式的公钥,你可以简单地将编码的byte[] 传递给java.security.cert.CertificateFactory.generateCertificate(),结果你会得到正确的X509Certificate

        private static X509Certificate formX509Certificate(byte[] encodedCertificate) throws CertificateException {
            try {
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                ByteArrayInputStream bais = new ByteArrayInputStream(encodedCertificate);
                return (X509Certificate) cf.generateCertificate(bais);
            } catch (CertificateException e) {
                logger.error("Error converting the certificate", e);
                throw e;
            }
        }
    

    您对X509CertBuilder 的调用每次都会生成带有新密钥对的新证书。如果您已经生成了密钥对(来自 Java 代码或 OpenSSL 等),只需使用编码的证书值来构建证书对象。

    如果您只有密钥对值但公钥未形成证书,请使用SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());

    /**
         * Generates a self-signed {@link X509Certificate} suitable for use as a Certificate Authority.
         *
         * @param keyPair                 the {@link KeyPair} to generate the {@link X509Certificate} for
         * @param dn                      the distinguished name to user for the {@link X509Certificate}
         * @param signingAlgorithm        the signing algorithm to use for the {@link X509Certificate}
         * @param certificateDurationDays the duration in days for which the {@link X509Certificate} should be valid
         * @return a self-signed {@link X509Certificate} suitable for use as a Certificate Authority
         * @throws CertificateException      if there is an generating the new certificate
         */
        public static X509Certificate generateSelfSignedX509Certificate(KeyPair keyPair, String dn, String signingAlgorithm, int certificateDurationDays)
                throws CertificateException {
            try {
                ContentSigner sigGen = new JcaContentSignerBuilder(signingAlgorithm).setProvider(BouncyCastleProvider.PROVIDER_NAME).build(keyPair.getPrivate());
                SubjectPublicKeyInfo subPubKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
                Date startDate = new Date();
                Date endDate = new Date(startDate.getTime() + TimeUnit.DAYS.toMillis(certificateDurationDays));
    
                X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(
                        reverseX500Name(new X500Name(dn)),
                        getUniqueSerialNumber(),
                        startDate, endDate,
                        reverseX500Name(new X500Name(dn)),
                        subPubKeyInfo);
    
                // Set certificate extensions
                // (1) digitalSignature extension
                certBuilder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment | KeyUsage.dataEncipherment
                        | KeyUsage.keyAgreement | KeyUsage.nonRepudiation | KeyUsage.cRLSign | KeyUsage.keyCertSign));
    
                certBuilder.addExtension(Extension.basicConstraints, false, new BasicConstraints(true));
    
                certBuilder.addExtension(Extension.subjectKeyIdentifier, false, new JcaX509ExtensionUtils().createSubjectKeyIdentifier(keyPair.getPublic()));
    
                certBuilder.addExtension(Extension.authorityKeyIdentifier, false, new JcaX509ExtensionUtils().createAuthorityKeyIdentifier(keyPair.getPublic()));
    
                // (2) extendedKeyUsage extension
                certBuilder.addExtension(Extension.extendedKeyUsage, false, new ExtendedKeyUsage(new KeyPurposeId[]{KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_serverAuth}));
    
                // Sign the certificate
                X509CertificateHolder certificateHolder = certBuilder.build(sigGen);
                return new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getCertificate(certificateHolder);
            } catch (CertIOException | NoSuchAlgorithmException | OperatorCreationException e) {
                throw new CertificateException(e);
            }
        }
    

    【讨论】: