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
|
"""
PKCS#11 Tests
The following environment variables will influence the behaviour of test cases:
- PKCS11_MODULE, mandatory, points to the library/DLL to use for testing
- PKCS11_TOKEN_LABEL, mandatory, contains the token label
- PKCS11_TOKEN_PIN, optional (default is None), contains the PIN/passphrase of the token
- PKCS11_TOKEN_SO_PIN, optional (default is same as PKCS11_TOKEN_PIN), security officer PIN
- OPENSSL_PATH, optional, path to openssl executable (i.e. the folder that contains it)
"""
import os
import shutil
import unittest
from functools import wraps
from warnings import warn
import pkcs11
try:
LIB = os.environ['PKCS11_MODULE']
except KeyError:
raise RuntimeError("Must define `PKCS11_MODULE' to run tests.")
try:
TOKEN = os.environ['PKCS11_TOKEN_LABEL']
except KeyError:
raise RuntimeError("Must define `PKCS11_TOKEN_LABEL' to run tests.")
TOKEN_PIN = os.environ.get('PKCS11_TOKEN_PIN') # Can be None
if TOKEN_PIN is None:
warn("`PKCS11_TOKEN_PIN' env variable is unset.")
TOKEN_SO_PIN = os.environ.get('PKCS11_TOKEN_SO_PIN')
if TOKEN_SO_PIN is None:
TOKEN_SO_PIN = TOKEN_PIN
warn("`PKCS11_TOKEN_SO_PIN' env variable is unset. Using value from `PKCS11_TOKEN_PIN'")
OPENSSL = shutil.which('openssl', path=os.environ.get('OPENSSL_PATH'))
if OPENSSL is None:
warn("Path to OpenSSL not found. Please adjust `PATH' or define `OPENSSL_PATH'")
class TestCase(unittest.TestCase):
"""Base test case, optionally creates a token and a session."""
with_token = True
"""Creates a token for this test case."""
with_session = True
"""Creates a session for this test case."""
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.lib = lib = pkcs11.lib(LIB)
if cls.with_token or cls.with_session:
cls.token = lib.get_token(token_label=TOKEN)
def setUp(self):
super().setUp()
if self.with_session:
self.session = self.token.open(user_pin=TOKEN_PIN)
def tearDown(self):
if self.with_session:
self.session.close()
super().tearDown()
def requires(*mechanisms):
"""
Decorates a function or class as requiring mechanisms, else they are
skipped.
"""
def check_requirements(self):
"""Determine what, if any, required mechanisms are unavailable."""
unavailable = set(mechanisms) - self.token.slot.get_mechanisms()
if unavailable:
raise unittest.SkipTest("Requires %s"
% ', '.join(map(str, unavailable)))
def inner(func):
@wraps(func)
def wrapper(self, *args, **kwargs):
check_requirements(self)
return func(self, *args, **kwargs)
return wrapper
return inner
def xfail(condition):
"""Mark a test that's expected to fail for a given condition."""
def inner(func):
if condition:
return unittest.expectedFailure(func)
else:
return func
return inner
class Is:
"""
Test what device we're using.
"""
# trick: str.endswith() can accept tuples,
# see https://stackoverflow.com/questions/18351951/check-if-string-ends-with-one-of-the-strings-from-a-list
softhsm2 = LIB.lower().endswith(('libsofthsm2.so', 'libsofthsm2.dylib', 'softhsm2.dll', 'softhsm2-x64.dll'))
nfast = LIB.lower().endswith(('libcknfast.so', 'cknfast.dll'))
opencryptoki = LIB.endswith('libopencryptoki.so')
travis = os.environ.get('TRAVIS') == 'true'
class Avail:
"""
Test if a resource is available
"""
# openssl is searched across the exec path. Optionally, OPENSSL_PATH env variable can be defined
# in case there is no direct path to it (i.e. PATH does not point to it)
openssl = OPENSSL is not None
class Only:
"""
Limit tests to given conditions
"""
softhsm2 = unittest.skipUnless(Is.softhsm2, "SoftHSMv2 only")
openssl = unittest.skipUnless(Avail.openssl, "openssl not found in the path")
class Not:
"""
Ignore tests for given devices
"""
softhsm2 = unittest.skipIf(Is.softhsm2, "Not supported by SoftHSMv2")
nfast = unittest.skipIf(Is.nfast, "Not supported by nFast")
opencryptoki = unittest.skipIf(Is.opencryptoki,
"Not supported by OpenCryptoki")
class FIXME:
"""
Tests is broken on this platform.
"""
softhsm2 = xfail(Is.softhsm2)
nfast = xfail(Is.nfast)
opencryptoki = xfail(Is.opencryptoki)
travis = xfail(Is.travis)
|