next up previous contents
Next: Example 3: Signing data Up: PKCS #11 Previous: Example 1: Reading keys   Contents

Example 2: Generating a key pair



If we use the same initialization code as we did in 3.4, well get an error when we try to generate the key pair; CKR_SESSION_READ_ONLY. So we have to change one thing there:

CK_SESSION_HANDLE
start_session(CK_SLOT_ID slotId)
{
     CK_RV rv;
     CK_SESSION_HANDLE session;
     rv = C_OpenSession(slotId,
                        CKF_SERIAL_SESSION | CKF_RW_SESSION,
                        NULL,
                        NULL,
                        &session);
     check_return_value(rv, "open session");
     return session;
}

So when we have that, we can create the keypair creation call. Again, we define templates first. Two this time, one for the public key, and one for the private key.

We set the mechanism, the number of bits in the modulus, and the exponent (to RSA_F4, or 65537, or 0x101).

We define a general boolean variable true, which we use a few times to set flags.

void
create_key_pair(CK_SESSION_HANDLE session)
{
     CK_RV rv;
     CK_OBJECT_HANDLE publicKey, privateKey;
     CK_MECHANISM mechanism = {
          CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
     };
     CK_ULONG modulusBits = 1024;
     CK_BYTE publicExponent[] = { 1, 0, 1 };
     CK_BYTE subject[] = "mykey";
     CK_BYTE id[] = {0xa1};
     CK_BBOOL true = CK_TRUE;
     CK_ATTRIBUTE publicKeyTemplate[] = {
          {CKA_ID, id, 3},
          {CKA_LABEL, subject, 5},
          {CKA_TOKEN, &true, sizeof(true)},
          {CKA_ENCRYPT, &true, sizeof(true)},
          {CKA_VERIFY, &true, sizeof(true)},
          {CKA_WRAP, &true, sizeof(true)},
          {CKA_MODULUS_BITS, &modulusBits, sizeof(modulusBits)},
          {CKA_PUBLIC_EXPONENT, publicExponent, 3}
     };
     CK_ATTRIBUTE privateKeyTemplate[] = {
          {CKA_ID, id, sizeof(id)},
          {CKA_LABEL, subject, 5},
          {CKA_TOKEN, &true, sizeof(true)},
          {CKA_PRIVATE, &true, sizeof(true)},
          {CKA_SENSITIVE, &true, sizeof(true)},
          {CKA_DECRYPT, &true, sizeof(true)},
          {CKA_SIGN, &true, sizeof(true)},
          {CKA_UNWRAP, &true, sizeof(true)}
     };

     rv = C_GenerateKeyPair(session,
                            &mechanism,
                            publicKeyTemplate, 8,
                            privateKeyTemplate, 8,
                            &publicKey,
                            &privateKey);
     check_return_value(rv, "generate key pair");
}

Most data in these templates is hardcoded. Of course, for an actual application, these need to be provided in a more dynamic way.

The templates themselves should be straightforward, for the public key:

  1. We want the id to be a1. A key id is a computer-readable identifier
  2. We want the label to be 'mykey'. A key label is a human-readable identifier
  3. We want the key to be stored on the token. If this value is not set, the key will not be stored, and will be destroyed once the current session is closed.
  4. We want the key to be used for encryption
  5. We want the key to be used for verification
  6. We want the key to be able to encrypt other key data
  7. We want a modulus size of 1024 bits
  8. We want the exponent to be 65537

And for the private key:

  1. We want the id to be a1
  2. We want the label to be 'mykey'
  3. We want the key to be stored on the token
  4. We want the key to only be usable by logged-in users
  5. We want the sensitive key data to always be kept inside the token
  6. We want the key to be used for decryption
  7. We want the key to be used for signing
  8. We want the key to be able to decrypt other key data

There are, of course, a lot of other options. This also depends on the exact mechanism, and what it can do. To find this out, you will have to consult the PKCS #11 specification.

Some tokens (for instance our Eutron ITSEC CryptoIdentity), will not allow keys to be used for multiple purposes. In that case you would get an error code CKR_GENERAL_ERROR, along with a message to specify a specific key usage. In that case, remove the (CKA_)WRAP, UNWRAP, ENCRYPT, and DECRYPT lines from the template. Do not forget to lower the number 8 to 6 in the call to C_GenerateKeyPair.

Since we hardcoded the necessary variables, you should be able to use the same main() function as in example 1, with only the call to read_private_keys replaced by create_key_pair.


next up previous contents
Next: Example 3: Signing data Up: PKCS #11 Previous: Example 1: Reading keys   Contents
Written by Jelte Jansen
© NLnet Labs, May 13, 2008
jelte@nlnetlabs.nl