Smartcard PKCS11 AES Key Gen Failure

4

I am attempting to create an AES 256 key on an ACOS5-64 smartcard and OMNIKEY 3121 card reader, using PKCS11 in python (using the PyKCS11 library). So far, all the "standard" operations seem to work with regards to asymmetric crypto. I have run plenty of code samples and pkcs11-tool commands, to initialize the token, set/change PINs, create RSA keypairs, etc. So, the drivers are all functional (pcscd, CCID, PKCS11 middleware).

The following code is causing a problem:

from PyKCS11 import *
import getpass
libacospkcs = '/usr/lib/libacospkcs11.so'

def createTokenAES256(lbl):
   pkcs11 = PyKCS11Lib()
   pkcs11.load(libacospkcs)
   theOnlySlot = pkcs11.getSlotList()[0]
   session = pkcs11.openSession(theOnlySlot, CKF_SERIAL_SESSION | CKF_RW_SESSION)
   PIN = getpass.getpass('Enter User PIN to login:')
   session.login(PIN)

   t = pkcs11.getTokenInfo(theOnlySlot)
   print t.label
   print t.model
   print t.serialNumber

   template = (
      (CKA_CLASS, CKO_SECRET_KEY),
      (CKA_KEY_TYPE, CKK_AES),
      (CKA_VALUE_LEN, 32),
      (CKA_LABEL, "A"),
      (CKA_PRIVATE, True),
      (CKA_SENSITIVE, True),
      (CKA_ENCRYPT, True),
      (CKA_DECRYPT, True),
      (CKA_TOKEN, True),
      (CKA_WRAP, True),
      (CKA_UNWRAP, True),
      (CKA_EXTRACTABLE, False))
   ckattr = session._template2ckattrlist(template)
   m = LowLevel.CK_MECHANISM()
   m.mechanism = LowLevel.CKM_AES_KEY_GEN

   key = LowLevel.CK_OBJECT_HANDLE()
   returnValue = pkcs11.lib.C_GenerateKey( session.session, m, ckattr, key)

   if returnValue != CKR_OK:
      raise PyKCS11Error(returnValue)

# Now run the method to create the key
createTokenAES256('TestAESKey')

However, I get an error when running it:

~/projects/smartcard $ python testpkcs11again.py 
Enter User PIN to login:
Token #A                        
ACOS5-64        
30A740C8704A
Traceback (most recent call last):
  File "testcreateaes.py", line 43, in <module>
    createTokenAES256('TestAESKey')
  File "testcreateaes.py", line 40, in createTokenAES256
    raise PyKCS11Error(returnValue)
PyKCS11.PyKCS11Error: CKR_ATTRIBUTE_VALUE_INVALID (0x00000013)

The thing is that if I switch the CKA_TOKEN line to False, then it "works". Of course, by setting that to false, it makes the key a session object instead of a token object (i.e. after I logout, the key is wiped). Using pkcs11-tool with --list-objects, the key is not there. I can use the ACSCMU (GUI tool for token admin), I can create an AES key in the "Secret Key Manager" and it does create a persistent key. But I have no way to see what the ACSCMU is doing to make it persistent (it may not be using PKCS11 at all).

If I had to guess the problem, I'd guess that it has to do with the session. If CKA_TOKEN=True is invalid, then it seems the token is not actually in RW mode (as suggested by the CKF_RW_SESSION in the 9th line). So far, I'm not sure what else to try or how to debug this.

python
aes
smartcard
pkcs#11
asked on Stack Overflow May 7, 2015 by Alan CR

2 Answers

6

Figured it out on my own after a ton of digging through tons of examples: CKA_ID is a required attribute if you are going to make a persistent (CKA_TOKEN=True) object. Not sure how I was supposed to know that (never saw it in any documentation), but indeed it works beautifully after I've added that.

This code should work if you have you drivers setup properly:

from PyKCS11 import *
import getpass
libacospkcs = '/usr/lib/libacospkcs11.so'

def createTokenAES256(label):
   pkcs11 = PyKCS11Lib()
   pkcs11.load(libacospkcs)
   theOnlySlot = pkcs11.getSlotList()[0]
   session = pkcs11.openSession(theOnlySlot, CKF_SERIAL_SESSION | CKF_RW_SESSION)
   PIN = getpass.getpass('Enter User PIN to login:')
   session.login(PIN)

   print pkcs11.getTokenInfo(theOnlySlot)

   template = (
      (CKA_CLASS, CKO_SECRET_KEY),
      (CKA_KEY_TYPE, CKK_AES),
      (CKA_VALUE_LEN, 32),
      (CKA_LABEL, label),
      (CKA_ID, "1244"),
      (CKA_PRIVATE, True),
      (CKA_SENSITIVE, True),
      (CKA_ENCRYPT, True),
      (CKA_DECRYPT, True),
      (CKA_TOKEN, True),
      (CKA_WRAP, True),
      (CKA_UNWRAP, True),
      (CKA_EXTRACTABLE, False))
   ckattr = session._template2ckattrlist(template)
   m = LowLevel.CK_MECHANISM()
   m.mechanism = LowLevel.CKM_AES_KEY_GEN

   key = LowLevel.CK_OBJECT_HANDLE()
   returnValue = pkcs11.lib.C_GenerateKey( session.session, m, ckattr, key)

   if returnValue != CKR_OK:
      raise PyKCS11Error(returnValue)

# Now execute the above to create AES256 key
createTokenAES256('TestKey')

After this, I can logout of the card and see the new object using pkcs11-tool:

$ pkcs11-tool --module=/usr/lib/libacospkcs11.so --list-objects
Using slot 0 with a present token (0x0)
Secret Key Object; unknown key algorithm 31
  label:      TestKey
  ID:         31323434
  Usage:      encrypt, decrypt, wrap, unwrap, derive
answered on Stack Overflow May 7, 2015 by Alan CR • edited May 8, 2015 by Alan CR
0

IMO there is nothing you can do about it but contact the producer of libacospkcs11.so and ask for an explanation. You will most likely be directed to the documentation which will state that symmetric keys can be created only as a session objects and all operations with such keys are performed in SW (not in the card) - this is rather a common practice with most of the commercially available cards and middleware suites.

BTW you can also try to call C_GetMechanismInfo for CKM_AES_KEY_GEN mechanism (and also other AES mechanisms you are planning to use) and check whether the CKF_HW flag is set in the response. This flag indicates whether the mechanism is performed by the device or in the software.

answered on Stack Overflow May 7, 2015 by jariq

User contributions licensed under CC BY-SA 3.0