I’m creating a CSR file to request a certificate from AD CA, and I need to obtain both the public and private keys for use in digital signatures. However, in response from AD CA, I only receive the public key, and the private key is not exportable. How can I set the Exportable flag to true in the request, or is there something else I need to do to obtain an exportable private key in .pfx format?
// Constructing osVersion extension
DerObjectIdentifier osVersionOID = new DerObjectIdentifier("1.3.6.1.4.1.311.13.2.3");
...
// Constructing extensionRequest extension
DerObjectIdentifier extensionRequestOID = new DerObjectIdentifier("1.2.840.113549.1.9.14");
DerObjectIdentifier subjectKeyIdentifierOID = new DerObjectIdentifier("2.5.29.14");
...
// Constructing requestClientInfo extension
DerObjectIdentifier requestClientInfoOID = new DerObjectIdentifier("1.3.6.1.4.1.311.21.20");
...
DerObjectIdentifier enrolmentCSPOID = new DerObjectIdentifier("1.3.6.1.4.1.311.13.2.2");
...
// Constructing the CSR
Asn1EncodableVector csrAttributes = new Asn1EncodableVector();
csrAttributes.Add(osVersionExtension);
csrAttributes.Add(extensionRequestExtension);
csrAttributes.Add(requestClientInfoExtension);
csrAttributes.Add(enrolmentCSPExtension);
// Generate RSA key pair
RsaKeyPairGenerator generator = new RsaKeyPairGenerator();
generator.Init(new Org.BouncyCastle.Crypto.KeyGenerationParameters(new SecureRandom(), 2048));
AsymmetricCipherKeyPair keyPair = generator.GenerateKeyPair();
// Make private key exportable
CspParameters cspParams = new CspParameters()
{
KeyContainerName = Guid.NewGuid().ToString(),
KeyNumber = (int)KeyNumber.Exchange,
Flags = CspProviderFlags.UseMachineKeyStore //CspProviderFlags.NoPrompt | CspProviderFlags.UseMachineKeyStore | CspProviderFlags.UseExistingKey
};
var privateKey = (RsaPrivateCrtKeyParameters)keyPair.Private;
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(cspParams);
// rsaProvider.ExportParameters(true);
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);
rsaProvider.PersistKeyInCsp = true;
Console.WriteLine("CSR Exportable:" + rsaProvider.CspKeyContainerInfo.Exportable);
Console.WriteLine("CSR PublicOnly:" + rsaProvider.PublicOnly);
AsymmetricCipherKeyPair bcKeyPair = DotNetUtilities.GetRsaKeyPair(rsaProvider);
// Create CSR
Pkcs10CertificationRequest csr = new Pkcs10CertificationRequest("SHA256WITHRSA",
new X509Name("CN=AD User Name"), //
bcKeyPair.Public, //keyPair.Public,
new DerSet(csrAttributes),
bcKeyPair.Private);
// Output CSR
Console.WriteLine("CSR in PEM format:");
Console.WriteLine(PemEncodeCsr(csr));
Console.ReadLine();
}
static string PemEncodeCsr(Pkcs10CertificationRequest csr)
{
return "-----BEGIN CERTIFICATE REQUEST-----n" +
Convert.ToBase64String(csr.GetEncoded(), Base64FormattingOptions.InsertLineBreaks) +
"n-----END CERTIFICATE REQUEST-----";
}
I tried to change the flags in CspParameters, but it doesn’t affect the result.
RemX is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.