#!/usr/bin/env python import unittest from py11 import * from py11.mutex import MutexDB p11 = None so_pin = "fnord" user_pin = "fnord" only_slot = 0 verbose = True class TestInit(unittest.TestCase): """ Test all the flavors of C_Initialize(). """ def test_mutex_none(self): p11.C_Initialize() def test_mutex_os(self): p11.C_Initialize(CKF_OS_LOCKING_OK) def test_mutex_user(self): mdb = MutexDB() p11.C_Initialize(0, mdb.create, mdb.destroy, mdb.lock, mdb.unlock) def test_mutex_both(self): mdb = MutexDB() p11.C_Initialize(CKF_OS_LOCKING_OK, mdb.create, mdb.destroy, mdb.lock, mdb.unlock) def tearDown(self): p11.C_Finalize() class TestDevice(unittest.TestCase): """ Test basic device stuff like C_GetSlotList(), C_OpenSession(), and C_Login(). """ @classmethod def setUpClass(cls): p11.C_Initialize() @classmethod def tearDownClass(cls): p11.C_Finalize() def tearDown(self): p11.C_CloseAllSessions(only_slot) def test_getSlots(self): self.assertEqual(p11.C_GetSlotList(), [only_slot]) def test_getTokenInfo(self): token_info = p11.C_GetTokenInfo(only_slot) self.assertIsInstance(token_info, CK_TOKEN_INFO) self.assertEqual(token_info.label.rstrip(), "Cryptech Token") def test_sessions_serial(self): rw_session = p11.C_OpenSession(only_slot, CKF_RW_SESSION | CKF_SERIAL_SESSION) ro_session = p11.C_OpenSession(only_slot, CKF_SERIAL_SESSION) def test_sessions_parallel(self): # Cooked API doesn't allow the user to make this mistake, so we # have to use the raw API to test it. from ctypes import byref handle = CK_SESSION_HANDLE() notify = CK_NOTIFY() with self.assertRaises(CKR_SESSION_PARALLEL_NOT_SUPPORTED): p11.so.C_OpenSession(only_slot, CKF_RW_SESSION, None, notify, byref(handle)) with self.assertRaises(CKR_SESSION_PARALLEL_NOT_SUPPORTED): p11.so.C_OpenSession(only_slot, 0, None, notify, byref(handle)) def test_login_user(self): rw_session = p11.C_OpenSession(only_slot, CKF_RW_SESSION | CKF_SERIAL_SESSION) ro_session = p11.C_OpenSession(only_slot, CKF_SERIAL_SESSION) p11.C_Login(ro_session, CKU_USER, user_pin) p11.C_Logout(ro_session) def test_login_so(self): rw_session = p11.C_OpenSession(only_slot, CKF_RW_SESSION | CKF_SERIAL_SESSION) ro_session = p11.C_OpenSession(only_slot, CKF_SERIAL_SESSION) self.assertRaises(CKR_SESSION_READ_ONLY_EXISTS, p11.C_Login, ro_session, CKU_SO, so_pin) p11.C_CloseSession(ro_session) p11.C_Login(rw_session, CKU_SO, so_pin) self.assertRaises(CKR_SESSION_READ_WRITE_SO_EXISTS, p11.C_OpenSession, only_slot, CKF_SERIAL_SESSION) p11.C_Logout(rw_session) def test_random(self): # Testing that what this produces really is random seems beyond # the scope of a unit test. session = p11.C_OpenSession(only_slot) n = 17 random = p11.C_GenerateRandom(session, n) self.assertIsInstance(random, str) self.assertEqual(len(random), n) class TestKeys(unittest.TestCase): """ Tests involving keys. """ oid_p256 = "".join(chr(i) for i in (0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07)) oid_p384 = "".join(chr(i) for i in (0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22)) oid_p521 = "".join(chr(i) for i in (0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23)) @classmethod def setUpClass(cls): p11.C_Initialize() @classmethod def tearDownClass(cls): p11.C_Finalize() def setUp(self): self.session = p11.C_OpenSession(only_slot) p11.C_Login(self.session, CKU_USER, user_pin) def tearDown(self): p11.C_CloseAllSessions(only_slot) del self.session def assertIsKeypair(self, public_key, private_key = None): if isinstance(public_key, tuple) and private_key is None: public_key, private_key = public_key self.assertIsInstance(public_key, (int, long)) self.assertIsInstance(private_key, (int, long)) # Could do something clever here like use C_GetAttributeValue() to # examine the objects. Maybe later. def test_keygen_ec_p256(self): self.assertIsKeypair( p11.C_GenerateKeyPair(self.session, CKM_EC_KEY_PAIR_GEN, CKA_TOKEN = False, CKA_ID = "EC-P256", CKA_EC_PARAMS = self.oid_p256, CKA_SIGN = True, CKA_VERIFY = True)) self.assertIsKeypair( p11.C_GenerateKeyPair(self.session, CKM_EC_KEY_PAIR_GEN, CKA_TOKEN = True, CKA_ID = "EC-P256", CKA_EC_PARAMS = self.oid_p256, CKA_SIGN = True, CKA_VERIFY = True)) self.assertIsKeypair( p11.C_GenerateKeyPair(self.session, CKM_EC_KEY_PAIR_GEN, public_CKA_TOKEN = False, private_CKA_TOKEN = True, CKA_ID = "EC-P256", CKA_EC_PARAMS = self.oid_p256, CKA_SIGN = True, CKA_VERIFY = True)) self.assertIsKeypair( p11.C_GenerateKeyPair(self.session, CKM_EC_KEY_PAIR_GEN, public_CKA_TOKEN = True, private_CKA_TOKEN = False, CKA_ID = "EC-P256", CKA_EC_PARAMS = self.oid_p256, CKA_SIGN = True, CKA_VERIFY = True)) def test_gen_sign_verify_ecdsa_p256_sha256(self): public_key, private_key = p11.C_GenerateKeyPair(self.session, CKM_EC_KEY_PAIR_GEN, CKA_TOKEN = False, CKA_ID = "EC-P256", CKA_EC_PARAMS = self.oid_p256, CKA_SIGN = True, CKA_VERIFY = True) self.assertIsKeypair(public_key, private_key) hamster = "Your mother was a hamster" p11.C_SignInit(self.session, CKM_ECDSA_SHA256, private_key) sig = p11.C_Sign(self.session, hamster) self.assertIsInstance(sig, str) p11.C_VerifyInit(self.session, CKM_ECDSA_SHA256, public_key) p11.C_Verify(self.session, hamster, sig) def setUpModule(): global p11 p11 = PKCS11("./libpkcs11.so") import os, subprocess if verbose: print "Initializing database" db = os.path.abspath("unit_tests.db") if os.path.exists(db): os.unlink(db) os.environ["PKCS11_DATABASE"] = db subprocess.Popen(("./p11util", "-sup"), stdin = subprocess.PIPE).communicate("%s\n%s\n" % (so_pin, user_pin)) if verbose: print "Setup complete" def tearDownModule(): import os os.unlink(os.environ["PKCS11_DATABASE"]) if __name__ == "__main__": unittest.main(verbosity = 2 if verbose else 1)