Discuss this help topic in SecureBlackbox Forum

Create certificate with private key in Windows Certificate Store

Generation of an X.509 certificate using Windows CryptoAPI consists of : (1) generation of a new keypair, and (2) generation of a certificate containing the public key of the new keypair. The latter can also be performed by a third-party CA over the provided new public key.

First, tune up the cryptoprovider:


 // some tune-ups first
TElWin32CryptoProviderOptions(DefaultCryptoProviderManager.Win32CryptoProvider.Options).UseLocalMachineAccount = false;
TElWin32CryptoProviderOptions(DefaultCryptoProviderManager.Win32CryptoProvider.Options).GenerateExportablePrivateKeys = false;
Next, generate a keypair with the following code:

TElPublicKeyMaterial km = new TElRSAKeyMaterial(DefaultCryptoProviderManager.Win32CryptoProvider);

// unique key container name - SBB will generate a pseudorandom name if omitted
km.KeyID = SBStrUtils.Unit.StrToUTF8("{99999999-46AD-4C34-9999-55B00C703F44}");

km.Generate(1024);
km.Persistentiate();

// we'd better read the KeyID back after the generation just in case if the cryptoprovider altered it
string ContainerID = SBStrUtils.Unit.UTF8ToStr(km.KeyID);

// By the end of this stage we have a new keypair in the system store with the Win32 container name in ContainerID

Now that the keypair has been generated, you can either generate an enveloping self-signed certificate, or form a certificate request and send it out to a CA.

To generate a self-signed certificate, use the following code:


// creating and setting up new certificate object
TElX509CertificateEx cert = new TElX509CertificateEx();

cert.SubjectRDN.Add(SBConstants.Unit.SB_CERT_OID_COMMON_NAME, Encoding.UTF8.GetBytes("My new certificate"), SBASN1Tree.Unit.SB_ASN1_PRINTABLESTRING);
// set other SubjectRDN fields here

cert.ValidFrom = DateTime.UtcNow;
cert.ValidTo = DateTime.UtcNow.AddYears(1);
// set other properties, such as extensions, here

// passing our new keypair to the certificate object
cert.SetKeyMaterial(km);
cert.PreserveKeyMaterial = true; // asking the component not to generate a new keypair when generating the certificate

// generating the certificate
// never mind the zero key length as we are using an existing key here
cert.Generate(SBConstants.Unit.SB_CERT_ALGORITHM_SHA256_RSA_ENCRYPTION, 0 /* this really doesn't matter */);

// adding the newly generated certificate to "MY" storage
storage.Add(cert, true, "MY", ContainerID);

Alternatively, you might wish to generate a certificate request from your keypair and send it out to some CA for signing. This can be done with the following code (continue after the km.Generate(2048) call):


TElCertificateRequest req = new TElCertificateRequest();

// passing our new keypair to the request object
req.SetKeyMaterial(km);
req.PreserveKeMaterial = true; // asking the component not to generate a new keypair when generating the request

// generating the request
req.Generate(
  SBConstants.Unit.SB_CERT_ALGORITHM_ID_RSA_ENCRYPTION,  // must match algorithm of the key (RSA)
  0 /* doesn't really matter */,
  SBConstants.Unit.SB_CERT_ALGORITHM_SHA256_RSA_ENCRYPTION // must match algorithm of the key (RSA) and specify the desired hash algorithm (SHA256 here)
);

// save the newly created request to stream
FileStream f = new FileStream("request.req", FileMode.Create);
try
{
  req.SaveToStream(f);
}
finally
{
  f.Close();
}

Now send your request file to the CA. Once you receive a valid certificate back, add it to the Windows storage in the same way as you would do when generating a certificate locally:

// adding the generated certificate to the storage
storage.Add(cert, true, "MY", ContainerID);
Note that the value of the KeyID parameter passed to the Add() method (ContainerID in the above sample) should match the value, which you assigned to the km.KeyID property when generating a key pair. It is up to you how to create and store the key ID between the moment the keypair is added to the Windows storage and the moment you receive the certificate. You can store the key ID in one of the fields of Subject RDN of the certificate request, or (if the business logic allows), generate and use some unique key IDs.

That's generally it. In some cases a totally different, software-based key generation approach might be preferable. It might be the only choice if the CA does not support request-based certificate issuance, or if your device does not support on-board keypair generation. In this case you might consider generating a certificate with purely software means and then importing it together with its private key to the Windows storage. If you are forced to use this method, make sure to destroy all your local copies of the private key after importing it to the Windows storage.

Certificate-related How To articles

Discuss this help topic in SecureBlackbox Forum