"Fossies" - the Fresh Open Source Software Archive

Member "barbican-12.0.0/barbican/plugin/crypto/pkcs11.py" (14 Apr 2021, 34181 Bytes) of package /linux/misc/openstack/barbican-12.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "pkcs11.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 11.0.0_vs_12.0.0.

    1 # Licensed under the Apache License, Version 2.0 (the "License");
    2 # you may not use this file except in compliance with the License.
    3 # You may obtain a copy of the License at
    4 #
    5 #    http://www.apache.org/licenses/LICENSE-2.0
    6 #
    7 # Unless required by applicable law or agreed to in writing, software
    8 # distributed under the License is distributed on an "AS IS" BASIS,
    9 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
   10 # implied.
   11 # See the License for the specific language governing permissions and
   12 # limitations under the License.
   13 
   14 import collections
   15 import textwrap
   16 
   17 import cffi
   18 from cryptography.hazmat.primitives import padding
   19 import six
   20 
   21 from barbican.common import exception
   22 from barbican.common import utils
   23 from barbican import i18n as u
   24 
   25 LOG = utils.getLogger(__name__)
   26 
   27 Attribute = collections.namedtuple("Attribute", ["type", "value"])
   28 CKAttributes = collections.namedtuple("CKAttributes", ["template", "cffivals"])
   29 CKMechanism = collections.namedtuple("CKMechanism", ["mech", "cffivals"])
   30 Token = collections.namedtuple("Token", ["slot_id", "label", "serial_number"])
   31 
   32 CKR_OK = 0
   33 CKR_CRYPTOKI_ALREADY_INITIALIZED = 0x00000191
   34 CK_TRUE = 1
   35 CKF_RW_SESSION = (1 << 1)
   36 CKF_SERIAL_SESSION = (1 << 2)
   37 CKF_OS_LOCKING_OK = 0x02
   38 CKU_SO = 0
   39 CKU_USER = 1
   40 
   41 CKS_RO_PUBLIC_SESSION = 0
   42 CKS_RO_USER_FUNCTIONS = 1
   43 CKS_RW_PUBLIC_SESSION = 2
   44 CKS_RW_USER_FUNCTIONS = 3
   45 
   46 CKO_SECRET_KEY = 4
   47 CKK_AES = 0x1f
   48 CKK_GENERIC_SECRET = 0x10
   49 CKK_SHA256_HMAC = 0x0000002B
   50 
   51 _KEY_TYPES = {
   52     'CKK_AES': CKK_AES,
   53     'CKK_GENERIC_SECRET': CKK_GENERIC_SECRET,
   54     'CKK_SHA256_HMAC': CKK_SHA256_HMAC
   55 }
   56 
   57 CKA_CLASS = 0
   58 CKA_TOKEN = 1
   59 CKA_PRIVATE = 2
   60 CKA_LABEL = 3
   61 CKA_APPLICATION = 0x10
   62 CKA_VALUE = 0x11
   63 CKA_OBJECT_ID = 0x12
   64 CKA_CERTIFICATE_TYPE = 0x80
   65 CKA_ISSUER = 0x81
   66 CKA_SERIAL_NUMBER = 0x82
   67 CKA_AC_ISSUER = 0x83
   68 CKA_OWNER = 0x84
   69 CKA_ATTR_TYPES = 0x85
   70 CKA_TRUSTED = 0x86
   71 CKA_CERTIFICATE_CATEGORY = 0x87
   72 CKA_JAVA_MIDP_SECURITY_DOMAIN = 0x88
   73 CKA_URL = 0x89
   74 CKA_HASH_OF_SUBJECT_PUBLIC_KEY = 0x8a
   75 CKA_HASH_OF_ISSUER_PUBLIC_KEY = 0x8b
   76 CKA_CHECK_VALUE = 0x90
   77 CKA_KEY_TYPE = 0x100
   78 CKA_SUBJECT = 0x101
   79 CKA_ID = 0x102
   80 CKA_SENSITIVE = 0x103
   81 CKA_ENCRYPT = 0x104
   82 CKA_DECRYPT = 0x105
   83 CKA_WRAP = 0x106
   84 CKA_UNWRAP = 0x107
   85 CKA_SIGN = 0x108
   86 CKA_SIGN_RECOVER = 0x109
   87 CKA_VERIFY = 0x10a
   88 CKA_VERIFY_RECOVER = 0x10b
   89 CKA_DERIVE = 0x10c
   90 CKA_START_DATE = 0x110
   91 CKA_END_DATE = 0x111
   92 CKA_MODULUS = 0x120
   93 CKA_MODULUS_BITS = 0x121
   94 CKA_PUBLIC_EXPONENT = 0x122
   95 CKA_PRIVATE_EXPONENT = 0x123
   96 CKA_PRIME_1 = 0x124
   97 CKA_PRIME_2 = 0x125
   98 CKA_EXPONENT_1 = 0x126
   99 CKA_EXPONENT_2 = 0x127
  100 CKA_COEFFICIENT = 0x128
  101 CKA_PRIME = 0x130
  102 CKA_SUBPRIME = 0x131
  103 CKA_BASE = 0x132
  104 CKA_PRIME_BITS = 0x133
  105 CKA_SUB_PRIME_BITS = 0x134
  106 CKA_VALUE_BITS = 0x160
  107 CKA_VALUE_LEN = 0x161
  108 CKA_EXTRACTABLE = 0x162
  109 CKA_LOCAL = 0x163
  110 CKA_NEVER_EXTRACTABLE = 0x164
  111 CKA_ALWAYS_SENSITIVE = 0x165
  112 CKA_KEY_GEN_MECHANISM = 0x166
  113 CKA_MODIFIABLE = 0x170
  114 CKA_ECDSA_PARAMS = 0x180
  115 CKA_EC_PARAMS = 0x180
  116 CKA_EC_POINT = 0x181
  117 CKA_SECONDARY_AUTH = 0x200
  118 CKA_AUTH_PIN_FLAGS = 0x201
  119 CKA_ALWAYS_AUTHENTICATE = 0x202
  120 CKA_WRAP_WITH_TRUSTED = 0x210
  121 CKA_HW_FEATURE_TYPE = 0x300
  122 CKA_RESET_ON_INIT = 0x301
  123 CKA_HAS_RESET = 0x302
  124 CKA_PIXEL_X = 0x400
  125 CKA_PIXEL_Y = 0x401
  126 CKA_RESOLUTION = 0x402
  127 CKA_CHAR_ROWS = 0x403
  128 CKA_CHAR_COLUMNS = 0x404
  129 CKA_COLOR = 0x405
  130 CKA_BITS_PER_PIXEL = 0x406
  131 CKA_CHAR_SETS = 0x480
  132 CKA_ENCODING_METHODS = 0x481
  133 CKA_MIME_TYPES = 0x482
  134 CKA_MECHANISM_TYPE = 0x500
  135 CKA_REQUIRED_CMS_ATTRIBUTES = 0x501
  136 CKA_DEFAULT_CMS_ATTRIBUTES = 0x502
  137 CKA_SUPPORTED_CMS_ATTRIBUTES = 0x503
  138 
  139 CKM_SHA256_HMAC = 0x251
  140 CKM_AES_KEY_GEN = 0x1080
  141 CKM_AES_CBC = 0x1082
  142 CKM_AES_MAC = 0x1083
  143 CKM_AES_CBC_PAD = 0x1085
  144 CKM_AES_GCM = 0x1087
  145 CKM_AES_KEY_WRAP = 0x1090
  146 CKM_GENERIC_SECRET_KEY_GEN = 0x350
  147 VENDOR_SAFENET_CKM_AES_GCM = 0x8000011c
  148 
  149 # nCipher Vendor-defined Mechanisms
  150 CKM_NC_SHA256_HMAC_KEY_GEN = 0xDE436997
  151 
  152 _ENCRYPTION_MECHANISMS = {
  153     'CKM_AES_CBC': CKM_AES_CBC,
  154     'CKM_AES_GCM': CKM_AES_GCM,
  155     'VENDOR_SAFENET_CKM_AES_GCM': VENDOR_SAFENET_CKM_AES_GCM,
  156 }
  157 
  158 _CBC_IV_SIZE = 16  # bytes
  159 _CBC_BLOCK_SIZE = 128  # bits
  160 
  161 _KEY_GEN_MECHANISMS = {
  162     'CKM_AES_KEY_GEN': CKM_AES_KEY_GEN,
  163     'CKM_NC_SHA256_HMAC_KEY_GEN': CKM_NC_SHA256_HMAC_KEY_GEN,
  164     'CKM_GENERIC_SECRET_KEY_GEN': CKM_GENERIC_SECRET_KEY_GEN,
  165 }
  166 
  167 _KEY_WRAP_MECHANISMS = {
  168     'CKM_SHA256_HMAC': CKM_SHA256_HMAC,
  169     'CKM_AES_MAC': CKM_AES_MAC
  170 }
  171 
  172 CKM_NAMES = dict()
  173 CKM_NAMES.update(_ENCRYPTION_MECHANISMS)
  174 CKM_NAMES.update(_KEY_GEN_MECHANISMS)
  175 CKM_NAMES.update(_KEY_WRAP_MECHANISMS)
  176 
  177 ERROR_CODES = {
  178     1: 'CKR_CANCEL',
  179     2: 'CKR_HOST_MEMORY',
  180     3: 'CKR_SLOT_ID_INVALID',
  181     5: 'CKR_GENERAL_ERROR',
  182     6: 'CKR_FUNCTION_FAILED',
  183     7: 'CKR_ARGUMENTS_BAD',
  184     8: 'CKR_NO_EVENT',
  185     9: 'CKR_NEED_TO_CREATE_THREADS',
  186     0xa: 'CKR_CANT_LOCK',
  187     0x10: 'CKR_ATTRIBUTE_READ_ONLY',
  188     0x11: 'CKR_ATTRIBUTE_SENSITIVE',
  189     0x12: 'CKR_ATTRIBUTE_TYPE_INVALID',
  190     0x13: 'CKR_ATTRIBUTE_VALUE_INVALID',
  191     0x20: 'CKR_DATA_INVALID',
  192     0x21: 'CKR_DATA_LEN_RANGE',
  193     0x30: 'CKR_DEVICE_ERROR',
  194     0x31: 'CKR_DEVICE_MEMORY',
  195     0x32: 'CKR_DEVICE_REMOVED',
  196     0x40: 'CKR_ENCRYPTED_DATA_INVALID',
  197     0x41: 'CKR_ENCRYPTED_DATA_LEN_RANGE',
  198     0x50: 'CKR_FUNCTION_CANCELED',
  199     0x51: 'CKR_FUNCTION_NOT_PARALLEL',
  200     0x54: 'CKR_FUNCTION_NOT_SUPPORTED',
  201     0x60: 'CKR_KEY_HANDLE_INVALID',
  202     0x62: 'CKR_KEY_SIZE_RANGE',
  203     0x63: 'CKR_KEY_TYPE_INCONSISTENT',
  204     0x64: 'CKR_KEY_NOT_NEEDED',
  205     0x65: 'CKR_KEY_CHANGED',
  206     0x66: 'CKR_KEY_NEEDED',
  207     0x67: 'CKR_KEY_INDIGESTIBLE',
  208     0x68: 'CKR_KEY_FUNCTION_NOT_PERMITTED',
  209     0x69: 'CKR_KEY_NOT_WRAPPABLE',
  210     0x6a: 'CKR_KEY_UNEXTRACTABLE',
  211     0x70: 'CKR_MECHANISM_INVALID',
  212     0x71: 'CKR_MECHANISM_PARAM_INVALID',
  213     0x82: 'CKR_OBJECT_HANDLE_INVALID',
  214     0x90: 'CKR_OPERATION_ACTIVE',
  215     0x91: 'CKR_OPERATION_NOT_INITIALIZED',
  216     0xa0: 'CKR_PIN_INCORRECT',
  217     0xa1: 'CKR_PIN_INVALID',
  218     0xa2: 'CKR_PIN_LEN_RANGE',
  219     0xa3: 'CKR_PIN_EXPIRED',
  220     0xa4: 'CKR_PIN_LOCKED',
  221     0xb0: 'CKR_SESSION_CLOSED',
  222     0xb1: 'CKR_SESSION_COUNT',
  223     0xb3: 'CKR_SESSION_HANDLE_INVALID',
  224     0xb4: 'CKR_SESSION_PARALLEL_NOT_SUPPORTED',
  225     0xb5: 'CKR_SESSION_READ_ONLY',
  226     0xb6: 'CKR_SESSION_EXISTS',
  227     0xb7: 'CKR_SESSION_READ_ONLY_EXISTS',
  228     0xb8: 'CKR_SESSION_READ_WRITE_SO_EXISTS',
  229     0xc0: 'CKR_SIGNATURE_INVALID',
  230     0xc1: 'CKR_SIGNATURE_LEN_RANGE',
  231     0xd0: 'CKR_TEMPLATE_INCOMPLETE',
  232     0xd1: 'CKR_TEMPLATE_INCONSISTENT',
  233     0xe0: 'CKR_TOKEN_NOT_PRESENT',
  234     0xe1: 'CKR_TOKEN_NOT_RECOGNIZED',
  235     0xe2: 'CKR_TOKEN_WRITE_PROTECTED',
  236     0xf0: 'CKR_UNWRAPPING_KEY_HANDLE_INVALID',
  237     0xf1: 'CKR_UNWRAPPING_KEY_SIZE_RANGE',
  238     0xf2: 'CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT',
  239     0x100: 'CKR_USER_ALREADY_LOGGED_IN',
  240     0x101: 'CKR_USER_NOT_LOGGED_IN',
  241     0x102: 'CKR_USER_PIN_NOT_INITIALIZED',
  242     0x103: 'CKR_USER_TYPE_INVALID',
  243     0x104: 'CKR_USER_ANOTHER_ALREADY_LOGGED_IN',
  244     0x105: 'CKR_USER_TOO_MANY_TYPES',
  245     0x110: 'CKR_WRAPPED_KEY_INVALID',
  246     0x112: 'CKR_WRAPPED_KEY_LEN_RANGE',
  247     0x113: 'CKR_WRAPPING_KEY_HANDLE_INVALID',
  248     0x114: 'CKR_WRAPPING_KEY_SIZE_RANGE',
  249     0x115: 'CKR_WRAPPING_KEY_TYPE_INCONSISTENT',
  250     0x120: 'CKR_RANDOM_SEED_NOT_SUPPORTED',
  251     0x121: 'CKR_RANDOM_NO_RNG',
  252     0x130: 'CKR_DOMAIN_PARAMS_INVALID',
  253     0x150: 'CKR_BUFFER_TOO_SMALL',
  254     0x160: 'CKR_SAVED_STATE_INVALID',
  255     0x170: 'CKR_INFORMATION_SENSITIVE',
  256     0x180: 'CKR_STATE_UNSAVEABLE',
  257     0x190: 'CKR_CRYPTOKI_NOT_INITIALIZED',
  258     0x191: 'CKR_CRYPTOKI_ALREADY_INITIALIZED',
  259     0x1a0: 'CKR_MUTEX_BAD',
  260     0x1a1: 'CKR_MUTEX_NOT_LOCKED',
  261     0x200: 'CKR_FUNCTION_REJECTED',
  262     1 << 31: 'CKR_VENDOR_DEFINED'
  263 }
  264 
  265 
  266 def build_ffi():
  267     ffi = cffi.FFI()
  268     ffi.cdef(textwrap.dedent("""
  269     typedef unsigned char CK_BYTE;
  270     typedef CK_BYTE CK_CHAR;
  271     typedef CK_BYTE CK_UTF8CHAR;
  272     typedef CK_BYTE CK_BBOOL;
  273     typedef unsigned long CK_ULONG;
  274     typedef unsigned long CK_RV;
  275     typedef unsigned long CK_SESSION_HANDLE;
  276     typedef unsigned long CK_OBJECT_HANDLE;
  277     typedef unsigned long CK_SLOT_ID;
  278     typedef CK_SLOT_ID * CK_SLOT_ID_PTR;
  279     typedef unsigned long CK_FLAGS;
  280     typedef unsigned long CK_STATE;
  281     typedef unsigned long CK_USER_TYPE;
  282     typedef unsigned char * CK_UTF8CHAR_PTR;
  283     typedef void * CK_VOID_PTR;
  284     typedef CK_VOID_PTR * CK_VOID_PTR_PTR;
  285     typedef ... *CK_NOTIFY;
  286 
  287     typedef unsigned long ck_attribute_type_t;
  288     struct ck_attribute {
  289         ck_attribute_type_t type;
  290         void *value;
  291         unsigned long value_len;
  292     };
  293     typedef struct ck_attribute CK_ATTRIBUTE;
  294     typedef CK_ATTRIBUTE *CK_ATTRIBUTE_PTR;
  295 
  296     typedef CK_RV (*CK_CREATEMUTEX)(CK_VOID_PTR_PTR);
  297     typedef CK_RV (*CK_DESTROYMUTEX)(CK_VOID_PTR);
  298     typedef CK_RV (*CK_LOCKMUTEX)(CK_VOID_PTR);
  299     typedef CK_RV (*CK_UNLOCKMUTEX)(CK_VOID_PTR);
  300 
  301     typedef struct CK_C_INITIALIZE_ARGS {
  302         CK_CREATEMUTEX CreateMutex;
  303         CK_DESTROYMUTEX DestroyMutex;
  304         CK_LOCKMUTEX LockMutex;
  305         CK_UNLOCKMUTEX UnlockMutex;
  306         CK_FLAGS flags;
  307         CK_VOID_PTR pReserved;
  308     } CK_C_INITIALIZE_ARGS;
  309 
  310     typedef unsigned long ck_mechanism_type_t;
  311     struct ck_mechanism {
  312         ck_mechanism_type_t mechanism;
  313         void *parameter;
  314         unsigned long parameter_len;
  315     };
  316     typedef struct ck_mechanism CK_MECHANISM;
  317     typedef CK_MECHANISM *CK_MECHANISM_PTR;
  318     typedef CK_BYTE *CK_BYTE_PTR;
  319     typedef CK_ULONG *CK_ULONG_PTR;
  320 
  321     typedef struct CK_VERSION {
  322         CK_BYTE major;
  323         CK_BYTE minor;
  324     } CK_VERSION;
  325 
  326     typedef struct CK_SLOT_INFO {
  327         CK_UTF8CHAR slotDescription[64];
  328         CK_UTF8CHAR manufacturerID[32];
  329         CK_FLAGS    flags;
  330 
  331         CK_VERSION  hardwareVersion;
  332         CK_VERSION  firmwareVersion;
  333     } CK_SLOT_INFO;
  334     typedef CK_SLOT_INFO * CK_SLOT_INFO_PTR;
  335 
  336     typedef struct CK_TOKEN_INFO {
  337         CK_UTF8CHAR label[32];
  338         CK_UTF8CHAR manufacturerID[32];
  339         CK_UTF8CHAR model[16];
  340         CK_CHAR serialNumber[16];
  341         CK_FLAGS flags;
  342 
  343         CK_ULONG ulMaxSessionCount;
  344         CK_ULONG ulSessionCount;
  345         CK_ULONG ulMaxRwSessionCount;
  346         CK_ULONG ulRwSessionCount;
  347         CK_ULONG ulMaxPinLen;
  348         CK_ULONG ulMinPinLen;
  349         CK_ULONG ulTotalPublicMemory;
  350         CK_ULONG ulFreePublicMemory;
  351         CK_ULONG ulTotalPrivateMemory;
  352         CK_ULONG ulFreePrivateMemory;
  353         CK_VERSION hardwareVersion;
  354         CK_VERSION firmwareVersion;
  355         CK_CHAR utcTime[16];
  356     } CK_TOKEN_INFO;
  357     typedef CK_TOKEN_INFO * CK_TOKEN_INFO_PTR;
  358 
  359     typedef struct ck_session_info {
  360         CK_SLOT_ID slot_id;
  361         CK_STATE state;
  362         CK_FLAGS flags;
  363         unsigned long device_error;
  364     } CK_SESSION_INFO;
  365     typedef CK_SESSION_INFO *CK_SESSION_INFO_PTR;
  366 
  367     typedef struct CK_AES_GCM_PARAMS {
  368         char * pIv;
  369         unsigned long ulIvLen;
  370         unsigned long ulIvBits;
  371         char * pAAD;
  372         unsigned long ulAADLen;
  373         unsigned long ulTagBits;
  374     } CK_AES_GCM_PARAMS;
  375     """))
  376     # FUNCTIONS
  377     ffi.cdef(textwrap.dedent("""
  378     CK_RV C_Initialize(void *);
  379     CK_RV C_Finalize(void *);
  380     CK_RV C_OpenSession(CK_SLOT_ID, CK_FLAGS, void *, CK_NOTIFY,
  381                         CK_SESSION_HANDLE *);
  382     CK_RV C_CloseSession(CK_SESSION_HANDLE);
  383     CK_RV C_GetSessionInfo(CK_SESSION_HANDLE, CK_SESSION_INFO_PTR);
  384     CK_RV C_Login(CK_SESSION_HANDLE, CK_USER_TYPE, CK_UTF8CHAR_PTR,
  385                   CK_ULONG);
  386     CK_RV C_GetSlotList(CK_BBOOL, CK_SLOT_ID_PTR, CK_ULONG_PTR);
  387     CK_RV C_GetSlotInfo(CK_SLOT_ID, CK_SLOT_INFO_PTR);
  388     CK_RV C_GetTokenInfo(CK_SLOT_ID, CK_TOKEN_INFO_PTR);
  389     CK_RV C_GetAttributeValue(CK_SESSION_HANDLE, CK_OBJECT_HANDLE,
  390                               CK_ATTRIBUTE *, CK_ULONG);
  391     CK_RV C_SetAttributeValue(CK_SESSION_HANDLE, CK_OBJECT_HANDLE,
  392                               CK_ATTRIBUTE *, CK_ULONG);
  393     CK_RV C_DestroyObject(CK_SESSION_HANDLE, CK_OBJECT_HANDLE);
  394     CK_RV C_FindObjectsInit(CK_SESSION_HANDLE, CK_ATTRIBUTE *, CK_ULONG);
  395     CK_RV C_FindObjects(CK_SESSION_HANDLE, CK_OBJECT_HANDLE *, CK_ULONG,
  396                         CK_ULONG *);
  397     CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE);
  398     CK_RV C_GenerateKey(CK_SESSION_HANDLE, CK_MECHANISM *, CK_ATTRIBUTE *,
  399                         CK_ULONG, CK_OBJECT_HANDLE *);
  400     CK_RV C_UnwrapKey(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE,
  401                       CK_BYTE *, CK_ULONG, CK_ATTRIBUTE *, CK_ULONG,
  402                       CK_OBJECT_HANDLE *);
  403     CK_RV C_WrapKey(CK_SESSION_HANDLE, CK_MECHANISM_PTR, CK_OBJECT_HANDLE,
  404                     CK_OBJECT_HANDLE, CK_BYTE_PTR, CK_ULONG_PTR);
  405     CK_RV C_EncryptInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR,
  406                         CK_OBJECT_HANDLE);
  407     CK_RV C_Encrypt(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG,
  408                     CK_BYTE_PTR, CK_ULONG_PTR);
  409     CK_RV C_DecryptInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR,
  410                         CK_OBJECT_HANDLE);
  411     CK_RV C_Decrypt(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
  412                     CK_ULONG_PTR);
  413     CK_RV C_SignInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR,
  414                      CK_OBJECT_HANDLE);
  415     CK_RV C_Sign(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
  416                  CK_ULONG_PTR);
  417     CK_RV C_VerifyInit(CK_SESSION_HANDLE, CK_MECHANISM_PTR,
  418                        CK_OBJECT_HANDLE);
  419     CK_RV C_Verify(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR,
  420                    CK_ULONG);
  421     CK_RV C_GenerateRandom(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG);
  422     CK_RV C_SeedRandom(CK_SESSION_HANDLE, CK_BYTE_PTR, CK_ULONG);
  423     """))
  424     return ffi
  425 
  426 
  427 class PKCS11(object):
  428     def __init__(self, library_path, login_passphrase, rw_session, slot_id,
  429                  encryption_mechanism=None,
  430                  ffi=None, algorithm=None,
  431                  seed_random_buffer=None,
  432                  generate_iv=None, always_set_cka_sensitive=None,
  433                  hmac_keywrap_mechanism='CKM_SHA256_HMAC',
  434                  token_serial_number=None,
  435                  token_labels=None,
  436                  os_locking_ok=False):
  437         if algorithm:
  438             LOG.warning("WARNING: Using deprecated 'algorithm' argument.")
  439             encryption_mechanism = encryption_mechanism or algorithm
  440 
  441         if encryption_mechanism not in _ENCRYPTION_MECHANISMS:
  442             raise ValueError("Invalid encryption_mechanism.")
  443         self.encrypt_mech = _ENCRYPTION_MECHANISMS[encryption_mechanism]
  444         self.encrypt = getattr(
  445             self,
  446             '_{}_encrypt'.format(encryption_mechanism)
  447         )
  448 
  449         if hmac_keywrap_mechanism not in _KEY_WRAP_MECHANISMS:
  450             raise ValueError("Invalid HMAC keywrap mechanism")
  451 
  452         self.ffi = ffi or build_ffi()
  453         self.lib = self.ffi.dlopen(library_path)
  454 
  455         if os_locking_ok:
  456             init_arg_pt = self.ffi.new("CK_C_INITIALIZE_ARGS *")
  457             init_arg_pt.flags = CKF_OS_LOCKING_OK
  458         else:
  459             init_arg_pt = self.ffi.NULL
  460 
  461         rv = self.lib.C_Initialize(init_arg_pt)
  462         self._check_error(rv)
  463 
  464         # Session options
  465         self.login_passphrase = _to_bytes(login_passphrase)
  466         self.rw_session = rw_session
  467         self.slot_id = self._get_slot_id(
  468             token_serial_number,
  469             token_labels,
  470             slot_id)
  471 
  472         # Algorithm options
  473         self.algorithm = CKM_NAMES[encryption_mechanism]
  474         self.blocksize = 16
  475         self.noncesize = 12
  476         self.gcmtagsize = 16
  477         self.generate_iv = generate_iv
  478         self.always_set_cka_sensitive = always_set_cka_sensitive
  479         self.hmac_keywrap_mechanism = CKM_NAMES[hmac_keywrap_mechanism]
  480 
  481         # Validate configuration and RNG
  482         session = self.get_session()
  483         if seed_random_buffer is not None:
  484             self._seed_random(session, seed_random_buffer)
  485         self._rng_self_test(session)
  486         self.return_session(session)
  487         LOG.debug("Connected to PCKS#11 Token in Slot %s", self.slot_id)
  488 
  489     def _get_slot_id(self, token_serial_number, token_labels, slot_id):
  490         # First find out how many slots with tokens are available
  491         slots_ptr = self.ffi.new("CK_ULONG_PTR")
  492         rv = self.lib.C_GetSlotList(CK_TRUE, self.ffi.NULL, slots_ptr)
  493         self._check_error(rv)
  494 
  495         # Next get the Slot IDs for each of the available slots
  496         slot_ids_ptr = self.ffi.new("CK_SLOT_ID[{}]".format(slots_ptr[0]))
  497         rv = self.lib.C_GetSlotList(CK_TRUE, slot_ids_ptr, slots_ptr)
  498         self._check_error(rv)
  499 
  500         # Gather details from each token
  501         tokens = list()
  502         for id in slot_ids_ptr:
  503             token_info_ptr = self.ffi.new("CK_TOKEN_INFO_PTR")
  504             rv = self.lib.C_GetTokenInfo(id, token_info_ptr)
  505             self._check_error(rv)
  506             token = Token(
  507                 id,
  508                 self.ffi.string(token_info_ptr.label).decode("UTF-8").strip(),
  509                 self.ffi.string(
  510                     token_info_ptr.serialNumber
  511                 ).decode("UTF-8").strip()
  512             )
  513             LOG.debug("Slot %s: label: %s sn: %s",
  514                       token.slot_id,
  515                       token.label,
  516                       token.serial_number)
  517             tokens.append(token)
  518 
  519         # Matching serial number gets highest priority
  520         if token_serial_number:
  521             for token in tokens:
  522                 if token.serial_number == token_serial_number:
  523                     LOG.debug("Found token sn: %s in slot %s",
  524                               token.serial_number,
  525                               token.slot_id)
  526                     if token_labels:
  527                         LOG.warning(
  528                             "Ignoring token_labels: %s from barbican.conf",
  529                             token_labels
  530                         )
  531                     if slot_id:
  532                         LOG.warning("Ignoring slot_id: %s from barbican.conf",
  533                                     slot_id)
  534                     return token.slot_id
  535             raise ValueError("Token Serial Number not found.")
  536 
  537         # Label match is next, raises an error if there's not exactly one match
  538         if token_labels:
  539             for token in tokens:
  540                 if token.label in token_labels:
  541                     LOG.debug("Found token label: %s in slot %s", token.label,
  542                               token.slot_id)
  543                     if slot_id:
  544                         LOG.warning("Ignoring slot_id: %s from barbican.conf",
  545                                     slot_id)
  546                     return token.slot_id
  547             raise ValueError("Token Labels not found.")
  548 
  549         # If we got this far, slot_id was the only param given, so we return it
  550         return slot_id
  551 
  552     def get_session(self):
  553         session = self._open_session(self.slot_id)
  554         # Get session info to check user state
  555         session_info = self._get_session_info(session)
  556         if session_info.state in (CKS_RO_PUBLIC_SESSION,
  557                                   CKS_RW_PUBLIC_SESSION):
  558             # Login public sessions
  559             self._login(self.login_passphrase, session)
  560         return session
  561 
  562     def return_session(self, session):
  563         self._close_session(session)
  564 
  565     def generate_random(self, length, session):
  566         buf = self._generate_random(length, session)
  567         return self.ffi.buffer(buf)[:]
  568 
  569     def get_key_handle(self, key_type, label, session):
  570         attributes = self._build_attributes([
  571             Attribute(CKA_CLASS, CKO_SECRET_KEY),
  572             Attribute(CKA_KEY_TYPE, _KEY_TYPES[key_type]),
  573             Attribute(CKA_LABEL, str(label))
  574         ])
  575         rv = self.lib.C_FindObjectsInit(
  576             session, attributes.template, len(attributes.template)
  577         )
  578         self._check_error(rv)
  579 
  580         count = self.ffi.new("CK_ULONG *")
  581         obj_handle_ptr = self.ffi.new("CK_OBJECT_HANDLE[2]")
  582         rv = self.lib.C_FindObjects(session, obj_handle_ptr, 2, count)
  583         self._check_error(rv)
  584         key = None
  585         if count[0] == 1:
  586             key = obj_handle_ptr[0]
  587         rv = self.lib.C_FindObjectsFinal(session)
  588         self._check_error(rv)
  589         if count[0] > 1:
  590             raise exception.P11CryptoPluginKeyException()
  591         return key
  592 
  593     def _CKM_AES_CBC_encrypt(self, key, pt_data, session):
  594         iv = self._generate_random(_CBC_IV_SIZE, session)
  595         ck_mechanism = self._build_cbc_mechanism(iv)
  596         rv = self.lib.C_EncryptInit(session, ck_mechanism.mech, key)
  597         self._check_error(rv)
  598 
  599         padder = padding.PKCS7(_CBC_BLOCK_SIZE).padder()
  600         padded_pt_data = padder.update(pt_data)
  601         padded_pt_data += padder.finalize()
  602 
  603         pt_len = len(padded_pt_data)
  604         ct_len = self.ffi.new("CK_ULONG *", pt_len)
  605 
  606         ct = self.ffi.new("CK_BYTE[{}]".format(ct_len[0]))
  607         rv = self.lib.C_Encrypt(session, padded_pt_data, pt_len, ct, ct_len)
  608         self._check_error(rv)
  609 
  610         return {
  611             "iv": self.ffi.buffer(iv)[:],
  612             "ct": self.ffi.buffer(ct, ct_len[0])[:]
  613         }
  614 
  615     def _build_cbc_mechanism(self, iv):
  616         mech = self.ffi.new("CK_MECHANISM *")
  617         mech.mechanism = self.encrypt_mech
  618         mech.parameter = iv
  619         mech.parameter_len = _CBC_IV_SIZE
  620         return CKMechanism(mech, None)
  621 
  622     def _CKM_AES_CBC_decrypt(self, key, iv, ct_data, session):
  623         iv = self.ffi.new("CK_BYTE[{}]".format(len(iv)), iv)
  624         ck_mechanism = self._build_cbc_mechanism(iv)
  625         rv = self.lib.C_DecryptInit(session, ck_mechanism.mech, key)
  626         self._check_error(rv)
  627 
  628         ct_len = len(ct_data)
  629         pt_len = self.ffi.new("CK_ULONG *", ct_len)
  630         pt = self.ffi.new("CK_BYTE[{0}]".format(pt_len[0]))
  631         rv = self.lib.C_Decrypt(session, ct_data, ct_len, pt, pt_len)
  632         self._check_error(rv)
  633         pt = self.ffi.buffer(pt, pt_len[0])[:]
  634 
  635         unpadder = padding.PKCS7(_CBC_BLOCK_SIZE).unpadder()
  636         unpadded_pt = unpadder.update(pt)
  637         unpadded_pt += unpadder.finalize()
  638         return unpadded_pt
  639 
  640     def _VENDOR_SAFENET_CKM_AES_GCM_encrypt(self, key, pt_data, session):
  641         iv = None
  642         if self.generate_iv:
  643             iv = self._generate_random(self.noncesize, session)
  644         ck_mechanism = self._build_gcm_mechanism(iv)
  645         rv = self.lib.C_EncryptInit(session, ck_mechanism.mech, key)
  646         self._check_error(rv)
  647 
  648         pt_len = len(pt_data)
  649         if self.generate_iv:
  650             ct_len = self.ffi.new("CK_ULONG *", pt_len + self.gcmtagsize)
  651         else:
  652             ct_len = self.ffi.new("CK_ULONG *", pt_len + self.gcmtagsize * 2)
  653         ct = self.ffi.new("CK_BYTE[{0}]".format(ct_len[0]))
  654         rv = self.lib.C_Encrypt(session, pt_data, pt_len, ct, ct_len)
  655         self._check_error(rv)
  656 
  657         if self.generate_iv:
  658             return {
  659                 "iv": self.ffi.buffer(iv)[:],
  660                 "ct": self.ffi.buffer(ct, ct_len[0])[:]
  661             }
  662         else:
  663             # HSM-generated IVs are appended to the end of the ciphertext
  664             return {
  665                 "iv": self.ffi.buffer(ct, ct_len[0])[-self.gcmtagsize:],
  666                 "ct": self.ffi.buffer(ct, ct_len[0])[:-self.gcmtagsize]
  667             }
  668 
  669     def _build_gcm_mechanism(self, iv=None):
  670         mech = self.ffi.new("CK_MECHANISM *")
  671         mech.mechanism = self.algorithm
  672         gcm = self.ffi.new("CK_AES_GCM_PARAMS *")
  673 
  674         if iv:
  675             iv_len = len(iv)
  676             gcm.pIv = iv
  677             gcm.ulIvLen = iv_len
  678             gcm.ulIvBits = iv_len * 8
  679 
  680         gcm.ulTagBits = self.gcmtagsize * 8
  681         mech.parameter = gcm
  682         mech.parameter_len = 48
  683         return CKMechanism(mech, gcm)
  684 
  685     def _VENDOR_SAFENET_CKM_AES_GCM_decrypt(self, key, iv, ct_data, session):
  686         iv = self.ffi.new("CK_BYTE[{0}]".format(len(iv)), iv)
  687         ck_mechanism = self._build_gcm_mechanism(iv)
  688         rv = self.lib.C_DecryptInit(session, ck_mechanism.mech, key)
  689         self._check_error(rv)
  690 
  691         ct_len = len(ct_data)
  692         pt_len = self.ffi.new("CK_ULONG *", ct_len)
  693         pt = self.ffi.new("CK_BYTE[{0}]".format(pt_len[0]))
  694         rv = self.lib.C_Decrypt(session, ct_data, ct_len, pt, pt_len)
  695         self._check_error(rv)
  696         pt = self.ffi.buffer(pt, pt_len[0])[:]
  697 
  698         # Secrets stored by the old code uses 16 byte IVs, while the new code
  699         # uses 12 byte IVs to be more efficient with GCM. We can use this to
  700         # detect secrets stored by the old code and perform padding removal.
  701         # If we find a 16 byte IV, we check to make sure the decrypted plain
  702         # text is a multiple of the block size, and then that the end of the
  703         # plain text looks like padding, ie the last character is a value
  704         # between 1 and blocksize, and that there are that many consecutive
  705         # bytes of that value at the end. If all of that is true, we remove
  706         # the found padding.
  707         last_byte = ord(pt[-1:])
  708         if len(iv) == self.blocksize and \
  709            (len(pt) % self.blocksize) == 0 and \
  710            1 <= last_byte <= self.blocksize and \
  711            pt.endswith(pt[-1:] * last_byte):
  712             pt = pt[:-last_byte]
  713 
  714         return pt
  715 
  716     def _CKM_AES_GCM_encrypt(self, key, pt_data, session):
  717         return self._VENDOR_SAFENET_CKM_AES_GCM_encrypt(key, pt_data, session)
  718 
  719     def _CKM_AES_GCM_decrypt(self, key, iv, ct_data, session):
  720         return self._VENDOR_SAFENET_CKM_AES_GCM_decrypt(
  721             key, iv, ct_data, session
  722         )
  723 
  724     def decrypt(self, mechanism, key, iv, ct_data, session):
  725         if mechanism not in _ENCRYPTION_MECHANISMS:
  726             raise ValueError(u._("Unsupported decryption mechanism"))
  727         return getattr(self, '_{}_decrypt'.format(mechanism))(
  728             key, iv, ct_data, session
  729         )
  730 
  731     def generate_key(self, key_type, key_length, mechanism, session,
  732                      key_label=None, master_key=False,
  733                      encrypt=False, sign=False, wrap=False):
  734         if not any((encrypt, sign, wrap)):
  735             raise exception.P11CryptoPluginException()
  736         if master_key and not key_label:
  737             raise ValueError(u._("key_label must be set for master_keys"))
  738 
  739         token = master_key
  740         extractable = not master_key
  741         # in some HSMs extractable keys cannot be marked sensitive
  742         sensitive = self.always_set_cka_sensitive or not extractable
  743 
  744         ck_attributes = [
  745             Attribute(CKA_CLASS, CKO_SECRET_KEY),
  746             Attribute(CKA_KEY_TYPE, _KEY_TYPES[key_type]),
  747             Attribute(CKA_VALUE_LEN, key_length),
  748             Attribute(CKA_TOKEN, token),
  749             Attribute(CKA_PRIVATE, True),
  750             Attribute(CKA_SENSITIVE, sensitive),
  751             Attribute(CKA_ENCRYPT, encrypt),
  752             Attribute(CKA_DECRYPT, encrypt),
  753             Attribute(CKA_SIGN, sign),
  754             Attribute(CKA_VERIFY, sign),
  755             Attribute(CKA_WRAP, wrap),
  756             Attribute(CKA_UNWRAP, wrap),
  757             Attribute(CKA_EXTRACTABLE, extractable)
  758         ]
  759         if master_key:
  760             ck_attributes.append(Attribute(CKA_LABEL, key_label))
  761         ck_attributes = self._build_attributes(ck_attributes)
  762         mech = self.ffi.new("CK_MECHANISM *")
  763 
  764         mech.mechanism = _KEY_GEN_MECHANISMS[mechanism]
  765 
  766         obj_handle_ptr = self.ffi.new("CK_OBJECT_HANDLE *")
  767         rv = self.lib.C_GenerateKey(
  768             session, mech, ck_attributes.template, len(ck_attributes.template),
  769             obj_handle_ptr
  770         )
  771         self._check_error(rv)
  772 
  773         return obj_handle_ptr[0]
  774 
  775     def wrap_key(self, wrapping_key, key_to_wrap, session):
  776         mech = self.ffi.new("CK_MECHANISM *")
  777         mech.mechanism = CKM_AES_CBC_PAD
  778         iv = self._generate_random(16, session)
  779         mech.parameter = iv
  780         mech.parameter_len = 16
  781 
  782         # Ask for length of the wrapped key
  783         wrapped_key_len = self.ffi.new("CK_ULONG *")
  784         rv = self.lib.C_WrapKey(
  785             session, mech, wrapping_key, key_to_wrap,
  786             self.ffi.NULL, wrapped_key_len
  787         )
  788         self._check_error(rv)
  789 
  790         # Wrap key
  791         wrapped_key = self.ffi.new("CK_BYTE[{0}]".format(wrapped_key_len[0]))
  792         rv = self.lib.C_WrapKey(
  793             session, mech, wrapping_key, key_to_wrap,
  794             wrapped_key, wrapped_key_len
  795         )
  796         self._check_error(rv)
  797 
  798         return {
  799             'iv': self.ffi.buffer(iv)[:],
  800             'wrapped_key': self.ffi.buffer(wrapped_key, wrapped_key_len[0])[:]
  801         }
  802 
  803     def unwrap_key(self, wrapping_key, iv, wrapped_key, session):
  804         ck_iv = self.ffi.new("CK_BYTE[]", iv)
  805         ck_wrapped_key = self.ffi.new("CK_BYTE[]", wrapped_key)
  806         unwrapped_key = self.ffi.new("CK_OBJECT_HANDLE *")
  807         mech = self.ffi.new("CK_MECHANISM *")
  808         mech.mechanism = CKM_AES_CBC_PAD
  809         mech.parameter = ck_iv
  810         mech.parameter_len = len(iv)
  811 
  812         ck_attributes = self._build_attributes([
  813             Attribute(CKA_CLASS, CKO_SECRET_KEY),
  814             Attribute(CKA_KEY_TYPE, CKK_AES),
  815             Attribute(CKA_TOKEN, False),
  816             Attribute(CKA_PRIVATE, True),
  817             Attribute(CKA_SENSITIVE, True),
  818             Attribute(CKA_ENCRYPT, True),
  819             Attribute(CKA_DECRYPT, True),
  820             Attribute(CKA_EXTRACTABLE, True)
  821         ])
  822         rv = self.lib.C_UnwrapKey(
  823             session, mech, wrapping_key, ck_wrapped_key, len(wrapped_key),
  824             ck_attributes.template, len(ck_attributes.template), unwrapped_key
  825         )
  826         self._check_error(rv)
  827 
  828         return unwrapped_key[0]
  829 
  830     def compute_hmac(self, hmac_key, data, session):
  831         mech = self.ffi.new("CK_MECHANISM *")
  832         mech.mechanism = self.hmac_keywrap_mechanism
  833         rv = self.lib.C_SignInit(session, mech, hmac_key)
  834         self._check_error(rv)
  835 
  836         ck_data = self.ffi.new("CK_BYTE[]", data)
  837         buf = self.ffi.new("CK_BYTE[32]")
  838         buf_len = self.ffi.new("CK_ULONG *", 32)
  839         rv = self.lib.C_Sign(session, ck_data, len(data), buf, buf_len)
  840         self._check_error(rv)
  841         return self.ffi.buffer(buf, buf_len[0])[:]
  842 
  843     def verify_hmac(self, hmac_key, sig, data, session):
  844         mech = self.ffi.new("CK_MECHANISM *")
  845         mech.mechanism = self.hmac_keywrap_mechanism
  846 
  847         rv = self.lib.C_VerifyInit(session, mech, hmac_key)
  848         self._check_error(rv)
  849         ck_data = self.ffi.new("CK_BYTE[]", data)
  850         ck_sig = self.ffi.new("CK_BYTE[]", sig)
  851         rv = self.lib.C_Verify(session, ck_data, len(data), ck_sig, len(sig))
  852         self._check_error(rv)
  853 
  854     def destroy_object(self, obj_handle, session):
  855         rv = self.lib.C_DestroyObject(session, obj_handle)
  856         self._check_error(rv)
  857 
  858     def finalize(self):
  859         rv = self.lib.C_Finalize(self.ffi.NULL)
  860         self._check_error(rv)
  861 
  862     def _check_error(self, value):
  863         if value != CKR_OK and value != CKR_CRYPTOKI_ALREADY_INITIALIZED:
  864             code = ERROR_CODES.get(value, 'CKR_????')
  865             hex_code = "{hex} {code}".format(hex=hex(value), code=code)
  866 
  867             if code == 'CKR_TOKEN_NOT_PRESENT':
  868                 raise exception.P11CryptoTokenException(slot_id=self.slot_id)
  869 
  870             raise exception.P11CryptoPluginException(u._(
  871                 "HSM returned response code: {code}").format(code=hex_code))
  872 
  873     def _seed_random(self, session, seed_random_buffer):
  874         """Call the C_SeedRandom() function with the seed_random data"""
  875         buf = self.ffi.new("CK_BYTE[]", seed_random_buffer.encode())
  876         rv = self.lib.C_SeedRandom(session, buf, len(seed_random_buffer))
  877         self._check_error(rv)
  878 
  879     def _generate_random(self, length, session):
  880         buf = self.ffi.new("CK_BYTE[{0}]".format(length))
  881         rv = self.lib.C_GenerateRandom(session, buf, length)
  882         self._check_error(rv)
  883         return buf
  884 
  885     def _build_attributes(self, attrs):
  886         attributes = self.ffi.new("CK_ATTRIBUTE[{0}]".format(len(attrs)))
  887         val_list = []
  888         for index, attr in enumerate(attrs):
  889             attributes[index].type = attr.type
  890             if isinstance(attr.value, bool):
  891                 val_list.append(self.ffi.new("unsigned char *",
  892                                 int(attr.value)))
  893                 attributes[index].value_len = 1  # sizeof(char) is 1
  894             elif isinstance(attr.value, int):
  895                 # second because bools are also considered ints
  896                 val_list.append(self.ffi.new("CK_ULONG *", attr.value))
  897                 attributes[index].value_len = 8
  898             elif isinstance(attr.value, str):
  899                 buf = attr.value.encode('utf-8')
  900                 val_list.append(self.ffi.new("char []", buf))
  901                 attributes[index].value_len = len(buf)
  902             elif isinstance(attr.value, bytes):
  903                 val_list.append(self.ffi.new("char []", attr.value))
  904                 attributes[index].value_len = len(attr.value)
  905             else:
  906                 raise TypeError(u._("Unknown attribute type provided."))
  907 
  908             attributes[index].value = val_list[-1]
  909 
  910         return CKAttributes(attributes, val_list)
  911 
  912     def _open_session(self, slot):
  913         session_ptr = self.ffi.new("CK_SESSION_HANDLE *")
  914         flags = CKF_SERIAL_SESSION
  915         if self.rw_session:
  916             flags |= CKF_RW_SESSION
  917         rv = self.lib.C_OpenSession(slot, flags, self.ffi.NULL,
  918                                     self.ffi.NULL, session_ptr)
  919         self._check_error(rv)
  920         return session_ptr[0]
  921 
  922     def _close_session(self, session):
  923         rv = self.lib.C_CloseSession(session)
  924         self._check_error(rv)
  925 
  926     def _get_session_info(self, session):
  927         session_info_ptr = self.ffi.new("CK_SESSION_INFO *")
  928         rv = self.lib.C_GetSessionInfo(session, session_info_ptr)
  929         self._check_error(rv)
  930         return session_info_ptr[0]
  931 
  932     def _login(self, password, session):
  933         rv = self.lib.C_Login(session, CKU_USER, password, len(password))
  934         self._check_error(rv)
  935 
  936     def _rng_self_test(self, session):
  937         test_random = self.generate_random(100, session)
  938         if test_random == b'\x00' * 100:
  939             raise exception.P11CryptoPluginException(
  940                 u._("Apparent RNG self-test failure."))
  941 
  942 
  943 def _to_bytes(string):
  944     if isinstance(string, six.binary_type):
  945         return string
  946     else:
  947         return string.encode('UTF-8')