Discuss this help topic in SecureBlackbox Forum

Create certificate with private key on hardware token

Generation of an X.509 certificate on a hardware device 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, open your PKCS#11 device as usual:


TElPKCS11CertStorage storage = new TElPKCS11CertStorage();
TElPKCS11CryptoProvider prov = new TElPKCS11CryptoProvider();
storage.CryptoProvider = prov;
storage.DLLName = @"C:\Windows\System32\mypkcs11driver.dll";
storage.Open();
Open a session in read/write mode and log in:

TElPKCS11SessionInfo sessInfo = storage.OpenSession(0, false);
sessInfo.Login(SBPKCS11Base.Unit.utUser, "pin");
Finally, generate a keypair with the following code:

TElRSAKeyMaterial km = new TElRSAKeyMaterial(sessInfo.CryptoProvider);
km.KeyID = Encoding.UTF8.GetBytes("newkeyid");
km.Generate(2048);

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, 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
cert.Generate(SBConstants.Unit.SB_CERT_ALGORITHM_SHA256_RSA_ENCRYPTION, 64 /* this really doesn't matter */);

// adding the newly generated certificate to the token
storage.PKCS11Options = storage.PKCS11Options &~ SBPKCS11Base.Unit.pcsoCreatePublicKeyObjects; // suppressing creation of a public key object, as the one has been already generated
storage.Add(0, cert, false, false, Encoding.UTF8.GetBytes("newkeyid"), Encoding.UTF8.GetBytes(""));
Note that the value of the KeyID parameter passed to the Add() method should match the value assigned to the km.KeyID property when generating a key pair.

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 token in the same way as you would do when generating a certificate locally:

// adding the generated certificate to the token
storage.PKCS11Options = storage.PKCS11Options &~ SBPKCS11Base.Unit.pcsoCreatePublicKeyObjects; // suppressing creation of a public key object, as the one has already been generated
storage.Add(0, cert, false, false, Encoding.UTF8.GetBytes("newkeyid"), Encoding.UTF8.GetBytes(""));
Note that the value of the KeyID parameter passed to the Add() method should match the value you assigned to the km.KeyID property when generating a key pair.

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 token. 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 hardware device.

Certificate-related How To articles

Discuss this help topic in SecureBlackbox Forum