次のように、Bouncy Castle ライブラリを使用して、CA ルート証明書と自己署名マシン証明書を作成しています。実装全体を以下にリストします。パスワードで保護された .PFX ファイルを作成できます。
CA ルート証明書を作成しましたが、マシンに既にインストールされているため (サブジェクトと発行者が同じ)、インストールしません。それに加えて、元の CAR ルート証明書 (MyCARoot.cer) がどのように作成されたのかはわかりませんが、次のコマンドでインストールされます。
certmgr.exe /add MyCARoot.cer /c /s /r localMachine ルート
ある時点で、certutil.exe を使用して作成した自己署名マシン証明書 (.PFX) をインストールできましたが、現在は常に上記のエラーが返されます。
ここでの私の質問は、1 つ以上の領域を対象としています。
- 以下の私の実装が正しいかどうか-「秘密鍵のエクスポートを許可する」などの何かを見逃していましたか...
- アプローチ全体が正しいかどうか - 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;
}