HSM using label of key object in PKCS11

3

This block of code is loading a cryptoki.so library and retrieving slot info. This is getting a list of objects in slot num. 0. I don't need to access all the keys to perform a few functions, just a specific key pair. Is there a way to get a single desired token by using the label name, object ID, or handle?

pkcs11 = PyKCS11.PyKCS11Lib()
pkcs11.load(lib)
pkcs11.initialize()
info = pkcs11.getInfo()
i = pkcs11.getSlotInfo(0)
pkcs11.openSession(0)

print "Library manufacturerID: " + info.manufacturerID

slots = pkcs11.getSlotList()
print "Available Slots:", len(slots)

for s in slots:
try:
    i = pkcs11.getSlotInfo(s)
    print "Slot no:", s
    print format_normal % ("slotDescription", i.slotDescription.strip())
    print format_normal % ("manufacturerID", i.manufacturerID.strip())

    t = pkcs11.getTokenInfo(s)
    print "TokenInfo"
    print format_normal % ("label", t.label.strip())
    print format_normal % ("manufacturerID", t.manufacturerID.strip())
    print format_normal % ("model", t.model.strip())


    session = pkcs11.openSession(s)
    print "Opened session 0x%08X" % session.session.value()
    if pin_available:
        try:
            session.login(pin=pin)
        except:
            print "login failed, exception:", str(sys.exc_info()[1])

    objects = session.findObjects()
    print
    print "Found %d objects: %s" % (len(objects), [x.value() for x in objects])

The specific script i'm running only has a few commands defined, such as -pin --sign --decrypt --lib do i need to define a common pkcs11-tool such as --init-token or --token-label to pass it as an argument when executing my script ? Or can i directly assign a variable to the desired LabelName within the python script?

So from command line i'm running

$./Test.py --pin=pass and getting the following

Library manufacturerID: Safenet, Inc.                   
Available Slots: 4
Slot no: 0
  slotDescription: ProtectServer K5E:00045
  manufacturerID: SafeNet Inc.
TokenInfo
  label: CKM
  manufacturerID: SafeNet Inc.
  model: K5E:PL25
Opened session 0x00000002

Found 52 objects: [5021, 5022, 5014, 5016, 4, 5, 6, 7, 8, 9, 16, 18, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 5313, 5314, 4982, 5325, 5326, 5328, 5329, 5331, 5332, 5335, 5018, 4962, 5020, 4963, 5357, 5358, 5360, 5361, 5363, 5364, 5366, 5367, 5369, 5370, 5372, 5373, 5375, 5376]

I'm ultimately trying to get only one of these objects to run some tests.For instance objectID = 201603040001 contains a private/cert file. I want to specify this particular handle. The actual label is something like 000103...3A0. How can I define this so I don't get the rest of the objects inside the library.

Here's the a list of just a couple of the HSM objects

 HANDLE LABEL                  TYPE                       OBJECT-ID
  5314 00000103000003A1       X509PublicKeyCertificate   201603040001
  5313 00000103000003A1       RSAPrivateKey              201603040001

I'm trying to pull just one of the Labels.

Here's the defined usage

def usage():
    print "Usage:", sys.argv[0],
    print "[-p pin][--pin=pin]",
    print "[-s slot][--slot=slot]",
    print "[-c lib][--lib=lib]",
    print "[-h][--help]",
    print "[-o][--opensession]"

try:
    opts, args = getopt.getopt(sys.argv[1:], "p:c:Sd:h:s", ["pin=", "lib=", "sign", "decrypt", "help","slot="])
except getopt.GetoptError:
    # print help information and exit:
    usage()
    sys.exit(2)

I'm not aware of how I can add an argument so I can use --sign with just a specific label. End game I want to use $./Test.py --pin=pass --sign --label "00000103000003A4" or by handle $./Test.py --pin=pass --sign --handle=5313

UPDATED from suggested comments below. still having trouble getting attributes for rsa private key and cert. Using the specific token has worked but those objects inside of it are returning bad attribute types

   t = pkcs11.getTokenInfo(s)
    print "TokenInfo"
    if 'CKM' == t.label.decode('ascii').strip():
            tokenInfo = pkcs11.getTokenInfo(slot)
    if '00000103000003A1' == tokenInfo.label.decode('ascii').strip():
            print format_normal % ("label", t.label.strip())
            print format_normal % ("manufacturerID", t.manufacturerID.strip())
            print format_normal % ("model", t.model.strip())


            session = pkcs11.openSession(s)
    print("Opened session 0x%08X" % session.session.value())
    if pin_available:
        try:
            if (pin is None) and \
                    (PyKCS11.CKF_PROTECTED_AUTHENTICATION_PATH & t.flags):
                print("\nEnter your PIN for %s on the pinpad" % t.label.strip())
            session.login(pin=pin)
        except:
            print("login failed, exception:", str(sys.exc_info()[1]))
            break

    objects = session.findObjects([(CKA_LABEL, "00000103000003A4")])
    print()
    print("Found %d objects: %s" % (len(objects), [x.value() for x in objects]))

    all_attributes = list(PyKCS11.CKA.keys())
    # only use the integer values and not the strings like 'CKM_RSA_PKCS'
    all_attributes.remove(PyKCS11.CKA_PRIVATE_EXPONENT)
    all_attributes.remove(PyKCS11.CKA_PRIME_1)
    all_attributes.remove(PyKCS11.CKA_PRIME_2)
    all_attributes.remove(PyKCS11.CKA_EXPONENT_1)
    all_attributes.remove(PyKCS11.CKA_EXPONENT_2)
    all_attributes.remove(PyKCS11.CKA_COEFFICIENT)
    all_attributes = [e for e in all_attributes if isinstance(e, int)]

          n_obj = 1
    for o in objects:
        print()
        print((red + "==================== Object: %d ====================" + normal) % o.value())
        n_obj += 1
        try:
            attributes = session.getAttributeValue(o, all_attributes)
        except PyKCS11.PyKCS11Error as e:
            continue    
        attrDict = dict(zip(all_attributes, attributes))
        if attrDict[PyKCS11.CKA_CLASS] == PyKCS11.CKO_PRIVATE_KEY \
           and attrDict[PyKCS11.CKA_KEY_TYPE] == PyKCS11.CKK_RSA:
            m = attrDict[PyKCS11.CKA_MODULUS]
            e = attrDict[PyKCS11.CKA_PUBLIC_EXPONENT]
            if m and e:
                mx = eval(b'0x' + ''.join("%02X" %c for c in m))
                ex = eval(b'0x' + ''.join("%02X" %c for c in e))
            if sign:
                try:
                    toSign = "12345678901234567890123456789012"  # 32 bytes, SHA256 digest
                    print("* Signing with object 0x%08X following data: %s" % (o.value(), toSign))
                    signature = session.sign(o, toSign)
                    sx = eval(b'0x' + ''.join("%02X" % c for c in signature))
                    print("Signature:")
                    print(dump(''.join(map(chr, signature))))
                    if m and e:
                        print("Verifying using following public key:")
                        print("Modulus:")
                        print(dump(''.join(map(chr, m))))
                        print("Exponent:")
                        print(dump(''.join(map(chr, e))))
                        decrypted = pow(sx, ex, mx)  # RSA
                        print("Decrypted:")
                        d = binascii.unhexlify(hexx(decrypted))
                        print(dump(d))
                        if toSign == d[-20:]:
                            print("*** signature VERIFIED!\n")

the following is what prints. nothing seems to be working using the specific objects, there are no error messages

Slot no: 0
  slotDescription: ProtectServer K5E:00045
  manufacturerID: SafeNet Inc.
TokenInfo
Opened session 0x00000002

Found 2 objects: [5328, 5329]

==================== Object: 5328 ====================

==================== Object: 5329 ====================
python
encryption
cryptography
pkcs#11
hsm
asked on Stack Overflow Oct 7, 2016 by DJ2 • edited May 27, 2019 by cardamom

1 Answer

2

You can work only with one token by checking its label before use, e.g.:

tokenInfo = pkcs11.getTokenInfo(slot)
if 'DesiredTokenLabel' == tokenInfo.label.decode('ascii').strip():
    # Start working with this particular token
    session = pkcs11.openSession(s)

You can enumerate only specific object using a template argument for the findObjects call, e.g.:

# get objects labelled "PRIV"
objects = session.findObjects([(CKA_LABEL, "PRIV")])

# get all private key objects
objects = session.findObjects([(CKA_CLASS, CKO_PRIVATE_KEY)])

# get all private key objects labelled "PRIV"
objects = session.findObjects([(CKA_CLASS, CKO_PRIVATE_KEY),(CKA_LABEL, "PRIV")])

# get all RSA private key objects labelled "PRIV"
objects = session.findObjects([(CKA_CLASS, CKO_PRIVATE_KEY),(CKA_KEY_TYPE, CKK_RSA),(CKA_LABEL, "PRIV")])

Below is an example code with hard-coded parameters:

from PyKCS11 import *

pkcs11 = PyKCS11.PyKCS11Lib()
pkcs11.load("your module path...")
slots = pkcs11.getSlotList()
for s in slots:
    t = pkcs11.getTokenInfo(s)
    if 'CKM' == t.label.decode('ascii').strip():
        session = pkcs11.openSession(s)
        objects = session.findObjects([(CKA_LABEL, "00000103000003A1")])
        print ("Found %d objects: %s" % (len(objects), [x.value() for x in objects]))

Please note that it is Python 3 as I can't use PyKCS11 in Python 2.x right now.

Soma additional (random) notes:

  • do not rely on handles -- they may (and will) be different for different program runs

  • your program's command line arguments are up to you -- you must decide yourself if your program needs arguments like --token-label

Disclaimer: I am not that into python so please do validate my thoughts

Good luck!

EDIT(Regarding you recent edit)>

No error is (most probably) shown because the exception is caught and ignored:

try:
    attributes = session.getAttributeValue(o, all_attributes)
except PyKCS11.PyKCS11Error as e:
    continue
answered on Stack Overflow Oct 10, 2016 by vlp • edited Oct 14, 2016 by vlp

User contributions licensed under CC BY-SA 3.0