/// <summary>
/// Generates asymetric key pair.
/// </summary>
/// <param name='pkcs11'>Initialized PKCS11 wrapper</param>
/// <param name='session'>Read-write session with user logged in</param>
/// <param name='pubKeyId'>Output parameter for public key object handle</param>
/// <param name='privKeyId'>Output parameter for private key object handle</param>
/// <returns>Return value of C_GenerateKeyPair</returns>
public static CKR GenerateKeyPair(Pkcs11 pkcs11, uint session, ref uint pubKeyId, ref uint privKeyId)
{
CKR rv = CKR.CKR_OK;
// The CKA_ID attribute is intended as a means of distinguishing multiple key pairs held by the same subject
byte[] ckaId = new byte[20];
rv = pkcs11.C_GenerateRandom(session, ckaId, Convert.ToUInt32(ckaId.Length));
if (rv != CKR.CKR_OK)
return rv;
// Prepare attribute template of new public key
CK_ATTRIBUTE[] pubKeyTemplate = new CK_ATTRIBUTE[10];
pubKeyTemplate[0] = CkaUtils.CreateAttribute(CKA.CKA_TOKEN, true);
pubKeyTemplate[1] = CkaUtils.CreateAttribute(CKA.CKA_PRIVATE, false);
pubKeyTemplate[2] = CkaUtils.CreateAttribute(CKA.CKA_LABEL, Settings.ApplicationName);
pubKeyTemplate[3] = CkaUtils.CreateAttribute(CKA.CKA_ID, ckaId);
pubKeyTemplate[4] = CkaUtils.CreateAttribute(CKA.CKA_ENCRYPT, true);
pubKeyTemplate[5] = CkaUtils.CreateAttribute(CKA.CKA_VERIFY, true);
pubKeyTemplate[6] = CkaUtils.CreateAttribute(CKA.CKA_VERIFY_RECOVER, true);
pubKeyTemplate[7] = CkaUtils.CreateAttribute(CKA.CKA_WRAP, true);
pubKeyTemplate[8] = CkaUtils.CreateAttribute(CKA.CKA_MODULUS_BITS, 1024);
pubKeyTemplate[9] = CkaUtils.CreateAttribute(CKA.CKA_PUBLIC_EXPONENT, new byte[] { 0x01, 0x00, 0x01 });
// Prepare attribute template of new private key
CK_ATTRIBUTE[] privKeyTemplate = new CK_ATTRIBUTE[9];
privKeyTemplate[0] = CkaUtils.CreateAttribute(CKA.CKA_TOKEN, true);
privKeyTemplate[1] = CkaUtils.CreateAttribute(CKA.CKA_PRIVATE, true);
privKeyTemplate[2] = CkaUtils.CreateAttribute(CKA.CKA_LABEL, Settings.ApplicationName);
privKeyTemplate[3] = CkaUtils.CreateAttribute(CKA.CKA_ID, ckaId);
privKeyTemplate[4] = CkaUtils.CreateAttribute(CKA.CKA_SENSITIVE, true);
privKeyTemplate[5] = CkaUtils.CreateAttribute(CKA.CKA_DECRYPT, true);
privKeyTemplate[6] = CkaUtils.CreateAttribute(CKA.CKA_SIGN, true);
privKeyTemplate[7] = CkaUtils.CreateAttribute(CKA.CKA_SIGN_RECOVER, true);
privKeyTemplate[8] = CkaUtils.CreateAttribute(CKA.CKA_UNWRAP, true);
// Specify key generation mechanism (needs no parameter => no unamanaged memory is needed)
CK_MECHANISM mechanism = CkmUtils.CreateMechanism(CKM.CKM_RSA_PKCS_KEY_PAIR_GEN);
// Generate key pair
rv = pkcs11.C_GenerateKeyPair(session, ref mechanism, pubKeyTemplate, Convert.ToUInt32(pubKeyTemplate.Length), privKeyTemplate, Convert.ToUInt32(privKeyTemplate.Length), ref pubKeyId, ref privKeyId);
// In LowLevelAPI we have to free unmanaged memory taken by attributes
for (int i = 0; i < privKeyTemplate.Length; i++)
{
UnmanagedMemory.Free(ref privKeyTemplate[i].value);
privKeyTemplate[i].valueLen = 0;
}
for (int i = 0; i < pubKeyTemplate.Length; i++)
{
UnmanagedMemory.Free(ref pubKeyTemplate[i].value);
pubKeyTemplate[i].valueLen = 0;
}
return rv;
}