1
  1. 我正在创建 CA 根证书,然后使用 Bouncy Castle 库创建自签名机器证书,如下所示。我在下面列出了整个实现。我能够创建受密码保护的 .PFX 文件。

  2. 尽管我创建了 CA 根证书,但我没有安装它,因为它已经安装在机器上(具有相同的主题和颁发者)。除此之外,我不确定原始 CAR 根证书 (MyCARoot.cer) 是如何创建的,但它是通过以下命令安装的:

    certmgr.exe /add MyCARoot.cer /c /s /r localMachine root

  3. 在某些时候,我能够安装使用 certutil.exe 创建的自签名机器证书 (.PFX),但是现在它总是返回上述错误。

  4. 我的问题针对一个或多个领域:

    • 我下面的实现是否正确 - 我是否错过了“允许私钥导出”或类似的东西......
    • 整个方法是否正确 - 我切换到它是因为我需要手动创建和安装自签名机器证书,而不是使用 makecert.exe 和 pvk2pfx.exe 一起提示用户输入私钥密码 4 次。 ..
    • 如何验证我生成的 .pfx 是否正确?(除了尝试使用 certutil.exe 安装它?

              AsymmetricKeyParameter caPrivateKey = null;
      
          try
          {
              // Create Root CA certificate
              X509Certificate2 x509 = CertMaker.GenerateCACertificate(mSubject, ref caPrivateKey);
      
              // Save certificate to file
              byte[] certBytes = x509.Export(X509ContentType.Cert, mRootCaPwd);
              string certFilePath = Path.Combine(mInstallPath, mSubject + ".cer");
              File.WriteAllBytes(certFilePath, certBytes);
          }
          catch(Exception ex)
          {
              Log.Verbose(ex);
              TextLog.Info("Failed to generate CA Root Certificate");
              return;
          }
      
          if (caPrivateKey == null)
          {
              Log.Verbose("Failed to generate CA Root Certificate: Failed to generate private key.");
              TextLog.Info("Failed to generate CA Root Certificate: Failed to generate private key.");
              return;
          }
          try
          {
              X509Certificate2 cert = CertMaker.GenerateSelfSignedCertificate(mSubject, mIssuer, caPrivateKey);
      
              // Save certificate to file
              byte[] certBytes = cert.Export(X509ContentType.Pkcs12, mComputerCertPwd);
              string filename = String.Format("MyServer_{0}.pfx", mSubject);
              string certFilePath = Path.Combine(mInstallPath, filename);
              File.WriteAllBytes(certFilePath, certBytes);
          }
          catch(Exception ex)
          {
              Log.Verbose("Failed to generate Machine Certificate." + ex.Message);
              TextLog.Info("Failed to generate Machine Certificate.");
          }
      

和功能实现:

       public static X509Certificate2 GenerateSelfSignedCertificate(string subjectName, string issuerName, AsymmetricKeyParameter issuerPrivKey, int keyStrength = 4096)
    {
        using (Log.VerboseCall())
        {
            try
            {
                // Generating Random Numbers
                var randomGenerator = new CryptoApiRandomGenerator();
                var random = new SecureRandom(randomGenerator);
                Log.Verbose("Generated Random Numbers");

                ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA512WITHRSA", issuerPrivKey, random);
                Log.Verbose("Generated SignatureFactory");

                // The Certificate Generator
                var certificateGenerator = new X509V3CertificateGenerator();
                certificateGenerator.AddExtension(X509Extensions.ExtendedKeyUsage.Id, true, new ExtendedKeyUsage(KeyPurposeID.IdKPServerAuth));

                // Serial Number
                var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
                certificateGenerator.SetSerialNumber(serialNumber);

                Log.Verbose("Added Serial Number to CertificateGenerator");

                // Issuer and Subject Name
                X509Name subjectDN = new X509Name("CN=" + subjectName);
                X509Name issuerDN = new X509Name("CN=" + issuerName);
                certificateGenerator.SetIssuerDN(issuerDN);
                certificateGenerator.SetSubjectDN(subjectDN);

                Log.Verbose("Had set Subject Name and Issuer Name");

                // Valid For
                var notBefore = DateTime.UtcNow.Date;
                var notAfter = notBefore.AddYears(100);

                certificateGenerator.SetNotBefore(notBefore);
                certificateGenerator.SetNotAfter(notAfter);

                // Subject Public Key
                AsymmetricCipherKeyPair subjectKeyPair;
                var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
                var keyPairGenerator = new RsaKeyPairGenerator();
                keyPairGenerator.Init(keyGenerationParameters);
                subjectKeyPair = keyPairGenerator.GenerateKeyPair();

                certificateGenerator.SetPublicKey(subjectKeyPair.Public);

                Log.Verbose("Had generated and set Subject Public Key");

                // Generating the Certificate
                var issuerKeyPair = subjectKeyPair;

                // NOTE #1
                // In another reference I saw this - instead
                //var dotNetPrivateKey = ToDotNetKey(privateKey);
                //var dotNetCert = new X509Certificate2(DotNetUtilities.ToX509Certificate(newCert));
                //dotNetCert.PrivateKey = dotNetPrivateKey;

                // self-signed certificate
                var certificate = certificateGenerator.Generate(signatureFactory);
                var dotNetPrivateKey = ToDotNetKey((RsaPrivateCrtKeyParameters)subjectKeyPair.Private);

                Log.Verbose("Generated Certificate");

                // correcponding private key
                PrivateKeyInfo info = PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private);

                Log.Verbose("Created Private Key");

                // merge into X509Certificate2
                var x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded());

                Log.Verbose("Generated Encoded Certificate");

                var seq = (Asn1Sequence)Asn1Object.FromByteArray(info.ParsePrivateKey().GetDerEncoded());
                if (seq.Count != 9)
                    throw new PemException("Malformed sequence in RSA private key");

                RsaPrivateKeyStructure rsa = RsaPrivateKeyStructure.GetInstance(seq);
                RsaPrivateCrtKeyParameters rsaparams = new RsaPrivateCrtKeyParameters(rsa.Modulus, rsa.PublicExponent,
                                                                                      rsa.PrivateExponent, rsa.Prime1,
                                                                                      rsa.Prime2, rsa.Exponent1,
                                                                                      rsa.Exponent2, rsa.Coefficient);

                Log.Verbose("Generated RSA Key Parameters");

                x509.PrivateKey = DotNetUtilities.ToRSA(rsaparams);
                Log.Verbose("Had set CA Private Key");

                return x509;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed to create Self-Signed Machine certificate: {0}", ex.Message);
                return null;
            }
        }
    }

    /// <summary>
    /// Generate Self-Signed Root CA Certificate
    /// </summary>
    /// <param name="subjectName"></param>
    /// <param name="CaPrivateKey"></param>
    /// <returns>Returns the X509 certificate and reference to Root CA Private Key</returns>
    public static X509Certificate2 GenerateCACertificate(string subjectName, ref AsymmetricKeyParameter CaPrivateKey)
    {
        using (Log.VerboseCall())
        {
            try
            {
                int keyStrength = 4096;

                // Generating Random Numbers
                CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator();
                SecureRandom random = new SecureRandom(randomGenerator);

                Log.Verbose("Generated Random Numbers");

                // The Certificate Generator
                X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();

                // Serial Number
                BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
                certificateGenerator.SetSerialNumber(serialNumber);

                Log.Verbose("Added Serial Number to CertificateGenerator");

                // Issuer and Subject Name
                X509Name subjectDN = new X509Name("CN="+subjectName);
                X509Name issuerDN = subjectDN;
                certificateGenerator.SetIssuerDN(issuerDN);
                certificateGenerator.SetSubjectDN(subjectDN);

                Log.Verbose("Had set Subject Name and Issuer Name");

                // Valid For
                var notBefore = DateTime.UtcNow.Date;
                var notAfter = notBefore.AddYears(100);

                certificateGenerator.SetNotBefore(notBefore);
                certificateGenerator.SetNotAfter(notAfter);

                // Subject Public Key
                AsymmetricCipherKeyPair subjectKeyPair;
                var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
                var keyPairGenerator = new RsaKeyPairGenerator();
                keyPairGenerator.Init(keyGenerationParameters);
                subjectKeyPair = keyPairGenerator.GenerateKeyPair();

                certificateGenerator.SetPublicKey(subjectKeyPair.Public);

                Log.Verbose("Had generated and set Subject Public Key");

                // Generating the Certificate
                AsymmetricCipherKeyPair issuerKeyPair = subjectKeyPair;
                ISignatureFactory signatureFactory = new Asn1SignatureFactory("SHA512WITHRSA", issuerKeyPair.Private, random);

                Log.Verbose("Created SignatureFactory");

                // selfsign certificate
                // certificateGenerator.Generate signs the certificate using the private key, 
                // but doesn't put the private key in the certificate, which wouldn't make sense.
                Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(signatureFactory);
                X509Certificate2 x509 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certificate.GetEncoded());

                Log.Verbose("Generated CA Root Certificate");

                CaPrivateKey = issuerKeyPair.Private;

                Log.Verbose("Had set CA Private Key");

                return x509;
            }
            catch (Exception ex)
            {
                Log.VerboseFormat("Failed to create Root CA certificate: {0}", ex.Message);
                return null;
            }
        }
    }

    /// <summary>
    /// See NOTE #1
    /// </summary>
    /// <param name="privateKey"></param>
    /// <returns></returns>
    public static AsymmetricAlgorithm ToDotNetKey(RsaPrivateCrtKeyParameters privateKey)
    {
        // If you don't do this (cspParams), when you execute the netsh command you get the error 1312. i.e. of the netsh command:
        //
        // netsh http add sslcert ipport = 192.168.0.15:8081 certhash =‎5424476237fc2785ed2d0fd620a9131d7c999f6f appid = { 02639d71 - 0935 - 35e8 - 9d1b - 9dd1a2a34627 }

        var cspParams = new CspParameters
        {
            KeyContainerName = Guid.NewGuid().ToString(),
            KeyNumber = (int)KeyNumber.Exchange,
            Flags = CspProviderFlags.UseMachineKeyStore
        };

        var rsaProvider = new RSACryptoServiceProvider(cspParams);
        var parameters = new RSAParameters
        {
            Modulus = privateKey.Modulus.ToByteArrayUnsigned(),
            P = privateKey.P.ToByteArrayUnsigned(),
            Q = privateKey.Q.ToByteArrayUnsigned(),
            DP = privateKey.DP.ToByteArrayUnsigned(),
            DQ = privateKey.DQ.ToByteArrayUnsigned(),
            InverseQ = privateKey.QInv.ToByteArrayUnsigned(),
            D = privateKey.Exponent.ToByteArrayUnsigned(),
            Exponent = privateKey.PublicExponent.ToByteArrayUnsigned()
        };

        rsaProvider.ImportParameters(parameters);
        return rsaProvider;
    }
4

0 回答 0