aboutsummaryrefslogtreecommitdiff
path: root/unit_tests.py
blob: b38e4ac4a917e7518708be0178b5b41f696a545d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#!/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)