PyKCS11 samples codes¶
Unblock a user PIN¶
#!/usr/bin/env python3
# Copyright (C) 2006-2014 Ludovic Rousseau <ludovic.rousseau@free.fr>
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
from __future__ import print_function
import PyKCS11
pin = "1234"
puk = "1234"
pkcs11 = PyKCS11.PyKCS11Lib()
pkcs11.load()
slot = pkcs11.getSlotList(tokenPresent=True)[0]
session = pkcs11.openSession(slot, PyKCS11.CKF_RW_SESSION)
session.login(puk, PyKCS11.CKU_SO)
session.initPin(pin)
session.logout()
session.closeSession()
Generate a key pair¶
#!/usr/bin/env python3
# Copyright (C) 2015 Roman Pasechnik
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
from PyKCS11 import *
# the key_id has to be the same for both objects
key_id = (0x22,)
pkcs11 = PyKCS11Lib()
pkcs11.load() # define environment variable PYKCS11LIB=YourPKCS11Lib
# get 1st slot
slot = pkcs11.getSlotList(tokenPresent=True)[0]
session = pkcs11.openSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION)
session.login("1234")
pubTemplate = [
(CKA_CLASS, CKO_PUBLIC_KEY),
(CKA_TOKEN, CK_TRUE),
(CKA_PRIVATE, CK_FALSE),
(CKA_MODULUS_BITS, 0x0400),
(CKA_PUBLIC_EXPONENT, (0x01, 0x00, 0x01)),
(CKA_ENCRYPT, CK_TRUE),
(CKA_VERIFY, CK_TRUE),
(CKA_VERIFY_RECOVER, CK_TRUE),
(CKA_WRAP, CK_TRUE),
(CKA_LABEL, "My Public Key"),
(CKA_ID, key_id),
]
privTemplate = [
(CKA_CLASS, CKO_PRIVATE_KEY),
(CKA_TOKEN, CK_TRUE),
(CKA_PRIVATE, CK_TRUE),
(CKA_DECRYPT, CK_TRUE),
(CKA_SIGN, CK_TRUE),
(CKA_SIGN_RECOVER, CK_TRUE),
(CKA_UNWRAP, CK_TRUE),
(CKA_ID, key_id),
]
(pubKey, privKey) = session.generateKeyPair(pubTemplate, privTemplate)
# logout
session.logout()
session.closeSession()
Encrypt and decrypt¶
#!/usr/bin/env python3
# Copyright (C) 2015 Roman Pasechnik
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
from __future__ import print_function
from PyKCS11 import *
import binascii
pkcs11 = PyKCS11Lib()
pkcs11.load() # define environment variable PYKCS11LIB=YourPKCS11Lib
# get 1st slot
slot = pkcs11.getSlotList(tokenPresent=True)[0]
session = pkcs11.openSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION)
session.login("1234")
# "Hello world" in hex
message = "48656c6c6f20776f726c640d0a"
# get first public and private keys
pubKey = session.findObjects([(CKA_CLASS, CKO_PUBLIC_KEY)])[0]
privKey = session.findObjects([(CKA_CLASS, CKO_PRIVATE_KEY)])[0]
enc = session.encrypt(pubKey, binascii.unhexlify(message))
dec = session.decrypt(privKey, enc)
print("\nmessage: " + message)
print("\nencrypted: {}".format(binascii.hexlify(bytearray(enc))))
print("\ndecrypted: {}".format(bytearray(dec)))
# logout
session.logout()
session.closeSession()
Get token events¶
#!/usr/bin/env python3
# Copyright (C) 2009-2014 Ludovic Rousseau (ludovic.rousseau@free.fr)
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
from __future__ import print_function
import PyKCS11
import getinfo
if __name__ == "__main__":
import getopt
import sys
def usage():
print("Usage:", sys.argv[0], end=" ")
print("[-p pin][--pin=pin] (use 'NULL' for pinpad)", end=" ")
print("[-c lib][--lib=lib]", end=" ")
print("[-h][--help]", end=" ")
print("[-o][--opensession]")
print("[-f][--full]")
try:
opts, args = getopt.getopt(
sys.argv[1:],
"p:c:homf",
["pin=", "lib=", "help", "opensession", "mechanisms", "full"],
)
except getopt.GetoptError:
# print help information and exit:
usage()
sys.exit(2)
lib = None
pin = ""
open_session = False
pin_available = False
list_mechanisms = False
full = False
for o, a in opts:
if o in ("-h", "--help"):
usage()
sys.exit()
if o in ("-p", "--pin"):
pin = a
if pin == "NULL":
pin = None
pin_available = True
open_session = True
if o in ("-c", "--lib"):
lib = a
if o in ("-o", "--opensession"):
open_session = True
if o in ("-m", "--mechanisms"):
list_mechanisms = True
if o in ("-f", "--full"):
full = True
gi = getinfo.getInfo(lib)
gi.getInfo()
slots = gi.pkcs11.getSlotList()
print("Available Slots:", len(slots), slots)
if len(slots) == 0:
sys.exit(2)
while True:
print("waiting...")
slot = gi.pkcs11.waitForSlotEvent()
try:
print("Slot %d changed" % slot)
gi.getSlotInfo(slot, 0, len(slots))
if full:
gi.getSessionInfo(slot, pin)
gi.getTokenInfo(slot)
if list_mechanisms:
gi.getMechanismInfo(slot)
except PyKCS11.PyKCS11Error as e:
print("Error:", e)
Get a public key modulus¶
#!/usr/bin/env python3
# Copyright (C) 2015 Roman Pasechnik
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
from __future__ import print_function
from PyKCS11 import *
import binascii
pkcs11 = PyKCS11Lib()
pkcs11.load() # define environment variable PYKCS11LIB=YourPKCS11Lib
# get 1st slot
slot = pkcs11.getSlotList(tokenPresent=True)[0]
session = pkcs11.openSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION)
session.login("1234")
# key ID in hex (has to be tuple, that's why trailing comma)
keyID = (0x22,)
# find public key and print modulus
pubKey = session.findObjects([(CKA_CLASS, CKO_PUBLIC_KEY), (CKA_ID, keyID)])[0]
modulus = session.getAttributeValue(pubKey, [CKA_MODULUS])[0]
print("\nmodulus: {}".format(binascii.hexlify(bytearray(modulus))))
# logout
session.logout()
session.closeSession()
RSA sign & verify¶
#!/usr/bin/env python3
# Copyright (C) 2015 Roman Pasechnik
# Copyright (C) 2018 Ludovic Rousseau
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
from PyKCS11 import *
import binascii
pkcs11 = PyKCS11Lib()
pkcs11.load() # define environment variable PYKCS11LIB=YourPKCS11Lib
# get 1st slot
slot = pkcs11.getSlotList(tokenPresent=True)[0]
session = pkcs11.openSession(slot, CKF_SERIAL_SESSION | CKF_RW_SESSION)
session.login("1234")
# message to sign
toSign = "Hello World!"
mechanism = Mechanism(CKM_SHA256_RSA_PKCS, None)
# find first private key and compute signature
privKey = session.findObjects([(CKA_CLASS, CKO_PRIVATE_KEY)])[0]
signature = session.sign(privKey, toSign, mechanism)
print("\nsignature: {}".format(binascii.hexlify(bytearray(signature))))
# find first public key and verify signature
pubKey = session.findObjects([(CKA_CLASS, CKO_PUBLIC_KEY)])[0]
result = session.verify(pubKey, toSign, signature, mechanism)
print("\nVerified:", result)
# logout
session.logout()
session.closeSession()
Get token information¶
#!/usr/bin/env python3
# Copyright (C) 2006-2014 Ludovic Rousseau (ludovic.rousseau@free.fr)
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
from __future__ import print_function
import PyKCS11
import platform
import sys
class getInfo(object):
red = blue = magenta = normal = ""
def colorize(self, text, arg):
print(self.magenta + text + self.blue, arg, self.normal)
def display(self, obj, indent=""):
dico = obj.to_dict()
for key in sorted(dico.keys()):
type = obj.fields[key]
left = indent + key + ":"
if type == "flags":
self.colorize(left, ", ".join(dico[key]))
elif type == "pair":
self.colorize(left, "%d.%d" % dico[key])
else:
self.colorize(left, dico[key])
def __init__(self, lib=None):
if sys.stdout.isatty() and platform.system().lower() != "windows":
self.red = "\x1b[01;31m"
self.blue = "\x1b[34m"
self.magenta = "\x1b[35m"
self.normal = "\x1b[0m"
self.pkcs11 = PyKCS11.PyKCS11Lib()
self.pkcs11.load(lib)
def getSlotInfo(self, slot, slot_index, nb_slots):
print()
print(
self.red
+ "Slot %d/%d (number %d):" % (slot_index, nb_slots, slot)
+ self.normal
)
self.display(self.pkcs11.getSlotInfo(slot), " ")
def getTokenInfo(self, slot):
print(" TokenInfo")
self.display(self.pkcs11.getTokenInfo(slot), " ")
def getMechanismInfo(self, slot):
print(" Mechanism list: ")
m = self.pkcs11.getMechanismList(slot)
for x in m:
self.colorize(" ", x)
i = self.pkcs11.getMechanismInfo(slot, x)
if not i.flags & PyKCS11.CKF_DIGEST:
if i.ulMinKeySize != PyKCS11.CK_UNAVAILABLE_INFORMATION:
self.colorize(" ulMinKeySize:", i.ulMinKeySize)
if i.ulMaxKeySize != PyKCS11.CK_UNAVAILABLE_INFORMATION:
self.colorize(" ulMaxKeySize:", i.ulMaxKeySize)
self.colorize(" flags:", ", ".join(i.flags2text()))
def getInfo(self):
self.display(self.pkcs11.getInfo())
def getSessionInfo(self, slot, pin=""):
print(" SessionInfo", end=" ")
session = self.pkcs11.openSession(slot)
if pin != "":
if pin is None:
print("(using pinpad)")
else:
print("(using pin: %s)" % pin)
session.login(pin)
else:
print()
self.display(session.getSessionInfo(), " ")
if pin:
session.logout()
def usage():
print("Usage:", sys.argv[0], end=" ")
print("[-a][--all]", end=" ")
print("[-p pin][--pin=pin] (use 'NULL' for pinpad)", end=" ")
print("[-s slot][--slot=slot]", end=" ")
print("[-c lib][--lib=lib]", end=" ")
print("[-m][--mechanisms]", end=" ")
print("[-h][--help]")
if __name__ == "__main__":
import getopt
try:
opts, args = getopt.getopt(
sys.argv[1:],
"p:s:c:ham",
["pin=", "slot=", "lib=", "help", "all", "mechanisms"],
)
except getopt.GetoptError:
# print help information and exit:
usage()
sys.exit(2)
slot = None
lib = None
pin = ""
token_present = True
list_mechanisms = False
for o, a in opts:
if o in ("-h", "--help"):
usage()
sys.exit()
if o in ("-p", "--pin"):
pin = a
if pin == "NULL":
pin = None
if o in ("-s", "--slot"):
slot = int(a)
if o in ("-c", "--lib"):
lib = a
if o in ("-a", "--all"):
token_present = False
if o in ("-m", "--mechanisms"):
list_mechanisms = True
gi = getInfo(lib)
gi.getInfo()
slots = gi.pkcs11.getSlotList(token_present)
print("Available Slots:", len(slots), slots)
if len(slots) == 0:
sys.exit(2)
if slot is not None:
slots = [slots[slot]]
print("Using slot:", slots[0])
slot_index = 0
nb_slots = len(slots)
for slot in slots:
slot_index += 1
try:
gi.getSlotInfo(slot, slot_index, nb_slots)
gi.getSessionInfo(slot, pin)
gi.getTokenInfo(slot)
if list_mechanisms:
gi.getMechanismInfo(slot)
except PyKCS11.PyKCS11Error as e:
print("Error:", e)
Dump all the token objects¶
#!/usr/bin/env python3
# Copyright (C) 2006-2014 Ludovic Rousseau (ludovic.rousseau@free.fr)
#
# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
import PyKCS11
import binascii
import getopt
import sys
import platform
# from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/142812
# Title: Hex dumper
# Submitter: Sebastien Keim (other recipes)
# Last Updated: 2002/08/05
# Version no: 1.0
def dump(src, length=16):
def to_ascii(x):
if x >= 32 and x <= 127:
return chr(x)
else:
return '.'
N = 0
result = ""
while src:
s, src = src[:length], src[length:]
text_hexa = " ".join(["%02X" % x for x in s])
text_ascii = "".join(map(to_ascii , s))
result += "%04X %-*s %s\n" % (N, length * 3, text_hexa, text_ascii)
N += length
return result
def usage():
print("Usage:", sys.argv[0], end=" ")
print("[-a][--all]", end=" ")
print("[-p pin][--pin=pin] (use --pin=NULL for pinpad)", end=" ")
print("[-c lib][--lib=lib]", end=" ")
print("[-s slot][--slot=slot]", end=" ")
print("[-h][--help]", end=" ")
print()
try:
opts, args = getopt.getopt(
sys.argv[1:],
"p:c:Sdhs:a",
["pin=", "lib=", "slot=", "help", "all"],
)
except getopt.GetoptError:
# print help information and exit:
usage()
sys.exit(2)
pin_available = False
lib = None
slot = None
token_present = True
for o, a in opts:
if o in ("-h", "--help"):
usage()
sys.exit()
elif o in ("-p", "--pin"):
pin = a
if pin == "NULL":
pin = None
pin_available = True
elif o in ("-c", "--lib"):
lib = a
print("using PKCS11 lib:", lib)
elif o in ("-s", "--slot"):
slot = int(a)
if o in ("-a", "--all"):
token_present = False
red = blue = magenta = normal = ""
if sys.stdout.isatty() and platform.system().lower() != "windows":
red = "\x1b[01;31m"
blue = "\x1b[34m"
magenta = "\x1b[35m"
normal = "\x1b[0m"
format_long = magenta + " %s:" + blue + " %s (%s)" + normal
format_binary = magenta + " %s:" + blue + " %d bytes" + normal
format_normal = magenta + " %s:" + blue + " %s" + normal
pkcs11 = PyKCS11.PyKCS11Lib()
pkcs11.load(lib)
info = pkcs11.getInfo()
print("Library manufacturerID:", info.manufacturerID)
slots = pkcs11.getSlotList(token_present)
print("Available Slots:", len(slots), slots)
if slot is not None:
slots = [slots[slot]]
print("Using slot:", slots[0])
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()))
print(format_normal % ("hardwareVersion", i.hardwareVersion))
print(format_normal % ("firmwareVersion", i.firmwareVersion))
print(format_normal % ("flags ", ", ".join(i.flags2text())))
if not (i.flags & PyKCS11.CKF_TOKEN_PRESENT):
print(" Token not present")
continue
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:
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 PyKCS11.PyKCS11Error as e:
print("login failed, exception:", e)
break
objects = session.findObjects()
print()
print("Found %d objects: %s" % (len(objects), [x.value() for x in objects]))
all_attributes = list(PyKCS11.CKA.keys())
# remove the CKR_ATTRIBUTE_SENSITIVE attributes since we can't get
# their values and will get an exception instead
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)
# only use the integer values and not the strings like 'CKM_RSA_PKCS'
all_attributes = [e for e in all_attributes if isinstance(e, int)]
n_obj = 1
for o in objects:
print()
print(
(
red
+ "==================== Object: %d/%d (%d) ===================="
+ normal
)
% (n_obj, len(objects), o.value())
)
n_obj += 1
try:
attributes = session.getAttributeValue(o, all_attributes)
except PyKCS11.PyKCS11Error as e:
print("getAttributeValue failed:", e)
continue
attrDict = dict(list(zip(all_attributes, attributes)))
print("Dumping attributes:")
for q, a in zip(all_attributes, attributes):
if a is None:
# undefined (CKR_ATTRIBUTE_TYPE_INVALID) attribute
continue
if q == PyKCS11.CKA_CLASS:
print(format_long % (PyKCS11.CKA[q], PyKCS11.CKO[a], a))
elif q == PyKCS11.CKA_CERTIFICATE_TYPE:
print(format_long % (PyKCS11.CKA[q], PyKCS11.CKC[a], a))
elif q == PyKCS11.CKA_KEY_TYPE:
print(format_long % (PyKCS11.CKA[q], PyKCS11.CKK[a], a))
elif session.isBin(q):
print(format_binary % (PyKCS11.CKA[q], len(a)))
if a:
print(dump(a), end="")
elif q == PyKCS11.CKA_SERIAL_NUMBER:
print(format_binary % (PyKCS11.CKA[q], len(a)))
if a:
print(dump(a), end="")
else:
print(format_normal % (PyKCS11.CKA[q], a))
print()
if pin_available:
try:
session.logout()
except PyKCS11.PyKCS11Error as e:
print("logout failed, exception:", e)
break
session.closeSession()
except PyKCS11.PyKCS11Error as e:
print("Error:", e)
raise