diff options
-rw-r--r-- | pkcs11.c | 243 | ||||
-rw-r--r-- | py11/attributes.py | 6 |
2 files changed, 205 insertions, 44 deletions
@@ -726,13 +726,13 @@ static int p11_attribute_get(const CK_OBJECT_HANDLE object_handle, * Wrappers to set and get CK_BBOOL and CK_ULONG values. */ -#if 0 - static int p11_attribute_set_bbool(const CK_OBJECT_HANDLE object_handle, const CK_ATTRIBUTE_TYPE type, const CK_BBOOL value) { return p11_attribute_set(object_handle, type, &value, sizeof(value)); } +#if 0 + static int p11_attribute_set_ulong(const CK_OBJECT_HANDLE object_handle, const CK_ATTRIBUTE_TYPE type, const CK_ULONG value) { return p11_attribute_set(object_handle, type, &value, sizeof(value)); @@ -761,10 +761,8 @@ static int p11_attribute_find_in_template(const CK_ATTRIBUTE_TYPE type, const CK_ATTRIBUTE_PTR template, const CK_ULONG length) { - int i; - if (template != NULL) - for (i = 0; i < length; i++) + for (int i = 0; i < length; i++) if (template[i].type == type) return i; @@ -772,6 +770,19 @@ static int p11_attribute_find_in_template(const CK_ATTRIBUTE_TYPE type, } /* + * Find an attribute in a CK_ATTRIBUTE_PTR template. Returns pointer + * to attribute value, or NULL if not found. + */ + +static void *p11_attribute_find_value_in_template(const CK_ATTRIBUTE_TYPE type, + const CK_ATTRIBUTE_PTR template, + const CK_ULONG length) +{ + const int i = p11_attribute_find_in_template(type, template, length); + return i < 0 ? NULL : template[i].pValue; +} + +/* * Map a keyusage-related attribute to a keyusage bit flag. * * Assumes that calling code has already checked whether this @@ -1676,8 +1687,7 @@ static int psnprintf(void *buffer_, size_t size, const char *format, ...) /* * Template checking and key generation. * - * This may need refactoring at some point, eg, when we add support - * for C_CreateObject(). + * The checking code needs refactoring to support C_CreateObject(). */ /* @@ -1686,16 +1696,17 @@ static int psnprintf(void *buffer_, size_t size, const char *format, ...) * attribute type. */ -static CK_RV p11_check_keypair_attributes_check_template_1(const CK_ATTRIBUTE_TYPE type, - const void * const val, - const size_t len, - const p11_descriptor_t * const descriptor) +static CK_RV p11_template_check_1(const CK_ATTRIBUTE_TYPE type, + const void * const val, + const size_t len, + const p11_descriptor_t * const descriptor, + unsigned long forbidden_flag) { const p11_attribute_descriptor_t * const atd = p11_find_attribute_in_descriptor(descriptor, type); CK_RV rv; /* Attribute not allowed or not allowed for key generation */ - if (atd == NULL || (atd->flags & P11_DESCRIPTOR_FORBIDDEN_BY_GENERATE) != 0) + if (atd == NULL || (atd->flags & forbidden_flag) != 0) lose(CKR_ATTRIBUTE_TYPE_INVALID); /* NULL or wrong-sized attribute values */ @@ -1710,13 +1721,14 @@ static CK_RV p11_check_keypair_attributes_check_template_1(const CK_ATTRIBUTE_TY if (atd->value != NULL && (atd->flags & P11_DESCRIPTOR_DEFAULT_VALUE) == 0 && memcmp(val, atd->value, atd->length) != 0) lose(CKR_TEMPLATE_INCONSISTENT); +#warning Add _LATCH checks here? + rv = CKR_OK; fail: #if DEBUG_PKCS11 if (rv != CKR_OK) - fprintf(stderr, "p11_check_keypair_attributes_check_template_1() rejected attribute 0x%08lx\n", - (unsigned long) type); + fprintf(stderr, "p11_template_check_1() rejected attribute 0x%08lx\n", (unsigned long) type); #endif return rv; } @@ -1726,10 +1738,12 @@ static CK_RV p11_check_keypair_attributes_check_template_1(const CK_ATTRIBUTE_TY * required for that template has been specified exactly once. */ -static CK_RV p11_check_keypair_attributes_check_template_2(const p11_session_t *session, - const p11_descriptor_t * const descriptor, - const CK_ATTRIBUTE_PTR template, - const CK_ULONG template_length) +static CK_RV p11_template_check_2(const p11_session_t *session, + const p11_descriptor_t * const descriptor, + const CK_ATTRIBUTE_PTR template, + const CK_ULONG template_length, + unsigned long required_flag, + unsigned long forbidden_flag) { const CK_BBOOL *object_is_private; CK_RV rv; @@ -1743,11 +1757,7 @@ static CK_RV p11_check_keypair_attributes_check_template_2(const p11_session_t * case CKS_RO_PUBLIC_SESSION: case CKS_RW_PUBLIC_SESSION: case CKS_RW_SO_FUNCTIONS: - if ((i = p11_attribute_find_in_template(CKA_PRIVATE, template, template_length)) >= 0) { - assert(template[i].pValue != NULL); - object_is_private = template[i].pValue; - } - else { + if ((object_is_private = p11_attribute_find_value_in_template(CKA_PRIVATE, template, template_length)) == NULL) { const p11_attribute_descriptor_t * const atd = p11_find_attribute_in_descriptor(descriptor, CKA_PRIVATE); assert(atd != NULL && atd->value != NULL); object_is_private = atd->value; @@ -1758,8 +1768,8 @@ static CK_RV p11_check_keypair_attributes_check_template_2(const p11_session_t * for (i = 0; i < descriptor->n_attributes; i++) { const p11_attribute_descriptor_t * const atd = &descriptor->attributes[i]; - const int required_by_api = (atd->flags & P11_DESCRIPTOR_REQUIRED_BY_GENERATE) != 0; - const int forbidden_by_api = (atd->flags & P11_DESCRIPTOR_FORBIDDEN_BY_GENERATE) != 0; + const int required_by_api = (atd->flags & required_flag) != 0; + const int forbidden_by_api = (atd->flags & forbidden_flag) != 0; const int in_descriptor = (atd->flags & P11_DESCRIPTOR_DEFAULT_VALUE) != 0 || atd->value != NULL; const int pos_in_template = p11_attribute_find_in_template(atd->type, template, template_length); @@ -1835,7 +1845,8 @@ static CK_RV p11_check_keypair_attributes(const p11_session_t *session, const void * const val = pPublicKeyTemplate[i].pValue; const size_t len = pPublicKeyTemplate[i].ulValueLen; - if ((rv = p11_check_keypair_attributes_check_template_1(type, val, len, public_descriptor)) != CKR_OK) + if ((rv = p11_template_check_1(type, val, len, public_descriptor, + P11_DESCRIPTOR_FORBIDDEN_BY_GENERATE)) != CKR_OK) goto fail; p11_attribute_apply_keyusage(&public_keyusage, type, val); @@ -1846,7 +1857,8 @@ static CK_RV p11_check_keypair_attributes(const p11_session_t *session, const void * const val = pPrivateKeyTemplate[i].pValue; const size_t len = pPrivateKeyTemplate[i].ulValueLen; - if ((rv = p11_check_keypair_attributes_check_template_1(type, val, len, private_descriptor)) != CKR_OK) + if ((rv = p11_template_check_1(type, val, len, private_descriptor, + P11_DESCRIPTOR_FORBIDDEN_BY_GENERATE)) != CKR_OK) goto fail; p11_attribute_apply_keyusage(&private_keyusage, type, val); @@ -1864,14 +1876,18 @@ static CK_RV p11_check_keypair_attributes(const p11_session_t *session, * Check that all required attributes have been specified. */ - if ((rv = p11_check_keypair_attributes_check_template_2(session, - public_descriptor, - pPublicKeyTemplate, - ulPublicKeyAttributeCount)) != CKR_OK || - (rv = p11_check_keypair_attributes_check_template_2(session, - private_descriptor, - pPrivateKeyTemplate, - ulPrivateKeyAttributeCount)) != CKR_OK) + if ((rv = p11_template_check_2(session, + public_descriptor, + pPublicKeyTemplate, + ulPublicKeyAttributeCount, + P11_DESCRIPTOR_REQUIRED_BY_GENERATE, + P11_DESCRIPTOR_FORBIDDEN_BY_GENERATE)) != CKR_OK || + (rv = p11_template_check_2(session, + private_descriptor, + pPrivateKeyTemplate, + ulPrivateKeyAttributeCount, + P11_DESCRIPTOR_REQUIRED_BY_GENERATE, + P11_DESCRIPTOR_FORBIDDEN_BY_GENERATE)) != CKR_OK) goto fail; /* @@ -2100,6 +2116,69 @@ static CK_RV generate_keypair(p11_session_t *session, return rv; } +/* + * Mechanism-independent checks for templates and descriptors when + * import objects via C_CreateObject(). + * + * Fun question exactly how calling code knows what descriptor to + * pass. p11_descriptor_from_key_type() will suffice for key objects. + * Drive off that bridge when we get to it. + */ + +static CK_RV p11_check_create_attributes(const p11_session_t *session, + const CK_ATTRIBUTE_PTR pTemplate, + const CK_ULONG ulCount, + const p11_descriptor_t * const descriptor) +{ + CK_RV rv = CKR_OK; + int i; + + assert(session != NULL && pTemplate != NULL && descriptor != NULL); + + /* + * Read-only sessions can't create objects, doh. + */ + + switch (session->state) { + case CKS_RO_PUBLIC_SESSION: + case CKS_RO_USER_FUNCTIONS: + lose(CKR_SESSION_READ_ONLY); + } + + /* + * Check values provided in the template. + */ + + for (i = 0; i < ulCount; i++) { + const CK_ATTRIBUTE_TYPE type = pTemplate[i].type; + const void * const val = pTemplate[i].pValue; + const size_t len = pTemplate[i].ulValueLen; + + if ((rv = p11_template_check_1(type, val, len, descriptor, + P11_DESCRIPTOR_FORBIDDEN_BY_CREATEOBJECT)) != CKR_OK) + goto fail; + } + + /* + * Check that all required attributes have been specified. + */ + + if ((rv = p11_template_check_2(session, descriptor, pTemplate, ulCount, + P11_DESCRIPTOR_REQUIRED_BY_CREATEOBJECT, + P11_DESCRIPTOR_FORBIDDEN_BY_CREATEOBJECT)) != CKR_OK) + goto fail; + + /* + * If we get this far, we're happy. Maybe. + */ + + rv = CKR_OK; + + fail: + return rv; +} + + /* @@ -3061,6 +3140,91 @@ CK_RV C_Logout(CK_SESSION_HANDLE hSession) mutex_unlock_return_with_rv(rv, p11_global_mutex); } +CK_RV C_CreateObject(CK_SESSION_HANDLE hSession, + CK_ATTRIBUTE_PTR pTemplate, + CK_ULONG ulCount, + CK_OBJECT_HANDLE_PTR phObject) +{ + ENTER_PUBLIC_FUNCTION(C_CreateObject); + + p11_session_t *session; + CK_RV rv; + + mutex_lock_or_return_failure(p11_global_mutex); + + if ((session = p11_session_find(hSession)) == NULL) + lose(CKR_SESSION_HANDLE_INVALID); + + if (pTemplate == NULL || phObject == NULL) + lose(CKR_ARGUMENTS_BAD); + + const CK_OBJECT_CLASS * const cka_class = p11_attribute_find_value_in_template(CKA_CLASS, pTemplate, ulCount); + const CK_KEY_TYPE * const cka_key_type = p11_attribute_find_value_in_template(CKA_KEY_TYPE, pTemplate, ulCount); + const CK_BBOOL * const cka_token = p11_attribute_find_value_in_template(CKA_TOKEN, pTemplate, ulCount); + + if (cka_class == NULL) + lose(CKR_TEMPLATE_INCOMPLETE); + + switch (*cka_class) { + case CKO_PUBLIC_KEY: + case CKO_PRIVATE_KEY: + case CKO_SECRET_KEY: + break; + default: + lose(CKR_TEMPLATE_INCONSISTENT); + } + + if (cka_key_type == NULL) + lose(CKR_TEMPLATE_INCOMPLETE); + + const p11_descriptor_t * const + descriptor = p11_descriptor_from_key_type(*cka_class, *cka_key_type); + + if (descriptor == NULL) + lose(CKR_TEMPLATE_INCONSISTENT); + + if ((rv = p11_check_create_attributes(session, pTemplate, ulCount, descriptor)) != CKR_OK) + goto fail; + + switch (session->state) { + case CKS_RO_PUBLIC_SESSION: + case CKS_RO_USER_FUNCTIONS: + if (cka_token != NULL && *cka_token) + lose(CKR_SESSION_READ_ONLY); + } + + if (!sql_exec("BEGIN")) + lose(CKR_FUNCTION_FAILED); + + const handle_flavor_t flavor + = cka_token == NULL ? handle_flavor_session_object : p11_handle_flavor_from_cka_token(cka_token); + + CK_OBJECT_HANDLE handle = p11_object_create(session, flavor, pTemplate, ulCount, descriptor, NULL); + + if (!p11_attribute_set_bbool(handle, CKA_LOCAL, CK_FALSE)) + lose(CKR_FUNCTION_FAILED); + + switch (*cka_class) { + case CKO_PRIVATE_KEY: + case CKO_SECRET_KEY: + if (!p11_attribute_set_bbool(handle, CKA_ALWAYS_SENSITIVE, CK_FALSE) || + !p11_attribute_set_bbool(handle, CKA_NEVER_EXTRACTABLE, CK_FALSE)) + lose(CKR_FUNCTION_FAILED); + } + + if (!sql_exec("COMMIT")) + lose(CKR_FUNCTION_FAILED); + + *phObject = handle; + + return mutex_unlock(p11_global_mutex); + + fail: + if (!sql_exec("ROLLBACK")) + rv = CKR_GENERAL_ERROR; + mutex_unlock_return_with_rv(rv, p11_global_mutex); +} + CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) { @@ -4237,15 +4401,6 @@ CK_RV C_SetOperationState(CK_SESSION_HANDLE hSession, return CKR_FUNCTION_NOT_SUPPORTED; } -CK_RV C_CreateObject(CK_SESSION_HANDLE hSession, - CK_ATTRIBUTE_PTR pTemplate, - CK_ULONG ulCount, - CK_OBJECT_HANDLE_PTR phObject) -{ - ENTER_PUBLIC_FUNCTION(C_CreateObject); - return CKR_FUNCTION_NOT_SUPPORTED; -} - CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, diff --git a/py11/attributes.py b/py11/attributes.py index 7c90768..32cf940 100644 --- a/py11/attributes.py +++ b/py11/attributes.py @@ -93,3 +93,9 @@ class AttributeDB(object): template[i].pValue = create_string_buffer(v) template[i].ulValueLen = len(v) return template + + def attribute_name(self, code): + return self.db[code].name + + def attribute_code(self, name): + return self.db[name].code |