From aa91f21e5471b30f7a507a9b11ca55e9263b3b3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vesa=20J=C3=A4=C3=A4skel=C3=A4inen?= Date: Fri, 25 Dec 2020 21:18:33 +0200 Subject: [PATCH] pkcs11: Add generic support for key pair generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit only adds common key pair generation support code. Actual mechanism specific key pair generation codes are in their own commits. Specified in: PKCS #11 Cryptographic Token Interface Base Specification Version 2.40 Plus Errata 01 5.13 Key management functions C_GenerateKeyPair Co-developed-by: Etienne Carriere Signed-off-by: Vesa Jääskeläinen --- ta/pkcs11/src/entry.c | 3 + ta/pkcs11/src/pkcs11_attributes.c | 58 +++++++- ta/pkcs11/src/pkcs11_helpers.c | 2 + ta/pkcs11/src/processing.c | 219 ++++++++++++++++++++++++++++++ ta/pkcs11/src/processing.h | 12 ++ 5 files changed, 292 insertions(+), 2 deletions(-) diff --git a/ta/pkcs11/src/entry.c b/ta/pkcs11/src/entry.c index 321d5d4322c..a20fddc23cf 100644 --- a/ta/pkcs11/src/entry.c +++ b/ta/pkcs11/src/entry.c @@ -303,6 +303,9 @@ TEE_Result TA_InvokeCommandEntryPoint(void *tee_session, uint32_t cmd, case PKCS11_CMD_GET_OBJECT_SIZE: rc = entry_get_object_size(client, ptypes, params); break; + case PKCS11_CMD_GENERATE_KEY_PAIR: + rc = entry_generate_key_pair(client, ptypes, params); + break; default: EMSG("Command %#"PRIx32" is not supported", cmd); return TEE_ERROR_NOT_SUPPORTED; diff --git a/ta/pkcs11/src/pkcs11_attributes.c b/ta/pkcs11/src/pkcs11_attributes.c index 6a49a1daf7b..f5e74576792 100644 --- a/ta/pkcs11/src/pkcs11_attributes.c +++ b/ta/pkcs11/src/pkcs11_attributes.c @@ -696,6 +696,7 @@ create_attributes_from_template(struct obj_attrs **out, void *template, trace_attributes_from_api_head("template", template, template_size); switch (function) { case PKCS11_FUNCTION_GENERATE: + case PKCS11_FUNCTION_GENERATE_PAIR: case PKCS11_FUNCTION_IMPORT: break; default: @@ -724,6 +725,19 @@ create_attributes_from_template(struct obj_attrs **out, void *template, } } + /* + * For PKCS11_FUNCTION_GENERATE_PAIR, find the class and type + * based on the mechanism. These will be passed as hint + * sanitize_client_object() and added in temp if not + * already present + */ + if (function == PKCS11_FUNCTION_GENERATE_PAIR) { + switch (mecha) { + default: + TEE_Panic(TEE_ERROR_NOT_SUPPORTED); + } + } + rc = sanitize_client_object(&temp, template, template_size, class, type); if (rc) @@ -794,6 +808,7 @@ create_attributes_from_template(struct obj_attrs **out, void *template, switch (function) { case PKCS11_FUNCTION_GENERATE: + case PKCS11_FUNCTION_GENERATE_PAIR: local = PKCS11_TRUE; break; case PKCS11_FUNCTION_IMPORT: @@ -1060,6 +1075,8 @@ enum pkcs11_rc check_created_attrs(struct obj_attrs *key1, { enum pkcs11_rc rc = PKCS11_CKR_OK; struct obj_attrs *secret = NULL; + struct obj_attrs *private = NULL; + struct obj_attrs *public = NULL; uint32_t max_key_size = 0; uint32_t min_key_size = 0; uint32_t key_length = 0; @@ -1068,12 +1085,37 @@ enum pkcs11_rc check_created_attrs(struct obj_attrs *key1, case PKCS11_CKO_SECRET_KEY: secret = key1; break; + case PKCS11_CKO_PUBLIC_KEY: + public = key1; + break; + case PKCS11_CKO_PRIVATE_KEY: + private = key1; + break; default: return PKCS11_CKR_ATTRIBUTE_VALUE_INVALID; } - if (key2) - return PKCS11_CKR_ATTRIBUTE_VALUE_INVALID; + if (key2) { + switch (get_class(key2)) { + case PKCS11_CKO_PUBLIC_KEY: + public = key2; + if (private == key1) + break; + + return PKCS11_CKR_TEMPLATE_INCONSISTENT; + case PKCS11_CKO_PRIVATE_KEY: + private = key2; + if (public == key1) + break; + + return PKCS11_CKR_TEMPLATE_INCONSISTENT; + default: + return PKCS11_CKR_ATTRIBUTE_VALUE_INVALID; + } + + if (get_key_type(private) != get_key_type(public)) + return PKCS11_CKR_TEMPLATE_INCONSISTENT; + } if (secret) { switch (get_key_type(secret)) { @@ -1096,6 +1138,18 @@ enum pkcs11_rc check_created_attrs(struct obj_attrs *key1, if (rc) return PKCS11_CKR_TEMPLATE_INCOMPLETE; } + if (public) { + switch (get_key_type(public)) { + default: + return PKCS11_CKR_TEMPLATE_INCONSISTENT; + } + } + if (private) { + switch (get_key_type(private)) { + default: + return PKCS11_CKR_TEMPLATE_INCONSISTENT; + } + } get_key_min_max_sizes(get_key_type(key1), &min_key_size, &max_key_size); if (key_length < min_key_size || key_length > max_key_size) { diff --git a/ta/pkcs11/src/pkcs11_helpers.c b/ta/pkcs11/src/pkcs11_helpers.c index c419fd125eb..3390c82ff15 100644 --- a/ta/pkcs11/src/pkcs11_helpers.c +++ b/ta/pkcs11/src/pkcs11_helpers.c @@ -36,6 +36,7 @@ static const struct attr_size attr_ids[] = { PKCS11_ID_SZ(PKCS11_CKA_KEY_TYPE, 4), PKCS11_ID_SZ(PKCS11_CKA_VALUE, 0), PKCS11_ID_SZ(PKCS11_CKA_VALUE_LEN, 4), + PKCS11_ID_SZ(PKCS11_CKA_KEY_GEN_MECHANISM, 4), PKCS11_ID_SZ(PKCS11_CKA_LABEL, 0), PKCS11_ID_SZ(PKCS11_CKA_WRAP_TEMPLATE, 0), PKCS11_ID_SZ(PKCS11_CKA_UNWRAP_TEMPLATE, 0), @@ -175,6 +176,7 @@ static const struct any_id __maybe_unused string_ta_cmd[] = { PKCS11_ID(PKCS11_CMD_FIND_OBJECTS_FINAL), PKCS11_ID(PKCS11_CMD_GET_OBJECT_SIZE), PKCS11_ID(PKCS11_CMD_GET_ATTRIBUTE_VALUE), + PKCS11_ID(PKCS11_CMD_GENERATE_KEY_PAIR), }; static const struct any_id __maybe_unused string_slot_flags[] = { diff --git a/ta/pkcs11/src/processing.c b/ta/pkcs11/src/processing.c index 87388a7b7e5..c1051046edc 100644 --- a/ta/pkcs11/src/processing.c +++ b/ta/pkcs11/src/processing.c @@ -283,6 +283,225 @@ enum pkcs11_rc entry_generate_secret(struct pkcs11_client *client, return rc; } +enum pkcs11_rc alloc_get_tee_attribute_data(TEE_ObjectHandle tee_obj, + uint32_t attribute, + void **data, size_t *size) +{ + TEE_Result res = TEE_ERROR_GENERIC; + void *ptr = NULL; + uint32_t sz = 0; + + res = TEE_GetObjectBufferAttribute(tee_obj, attribute, NULL, &sz); + if (res != TEE_ERROR_SHORT_BUFFER) + return PKCS11_CKR_FUNCTION_FAILED; + + ptr = TEE_Malloc(sz, TEE_USER_MEM_HINT_NO_FILL_ZERO); + if (!ptr) + return PKCS11_CKR_DEVICE_MEMORY; + + res = TEE_GetObjectBufferAttribute(tee_obj, attribute, ptr, &sz); + if (res) { + TEE_Free(ptr); + } else { + *data = ptr; + *size = sz; + } + + return tee2pkcs_error(res); +} + +enum pkcs11_rc tee2pkcs_add_attribute(struct obj_attrs **head, + uint32_t pkcs11_id, + TEE_ObjectHandle tee_obj, + uint32_t tee_id) +{ + enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; + void *a_ptr = NULL; + size_t a_size = 0; + + rc = alloc_get_tee_attribute_data(tee_obj, tee_id, &a_ptr, &a_size); + if (rc) + goto out; + + rc = add_attribute(head, pkcs11_id, a_ptr, a_size); + + TEE_Free(a_ptr); + +out: + if (rc) + EMSG("Failed TEE attribute %#"PRIx32" for %#"PRIx32"/%s", + tee_id, pkcs11_id, id2str_attr(pkcs11_id)); + return rc; +} + +enum pkcs11_rc entry_generate_key_pair(struct pkcs11_client *client, + uint32_t ptypes, TEE_Param *params) +{ + const uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INOUT, + TEE_PARAM_TYPE_NONE, + TEE_PARAM_TYPE_MEMREF_OUTPUT, + TEE_PARAM_TYPE_NONE); + TEE_Param *ctrl = params; + TEE_Param *out = params + 2; + enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; + struct serialargs ctrlargs = { }; + struct pkcs11_session *session = NULL; + struct pkcs11_attribute_head *proc_params = NULL; + struct obj_attrs *pub_head = NULL; + struct obj_attrs *priv_head = NULL; + struct pkcs11_object_head *template = NULL; + size_t template_size = 0; + uint32_t pubkey_handle = 0; + uint32_t privkey_handle = 0; + uint32_t *hdl_ptr = NULL; + size_t out_ref_size = sizeof(pubkey_handle) + sizeof(privkey_handle); + + if (!client || ptypes != exp_pt || out->memref.size != out_ref_size) + return PKCS11_CKR_ARGUMENTS_BAD; + + serialargs_init(&ctrlargs, ctrl->memref.buffer, ctrl->memref.size); + + rc = serialargs_get_session_from_handle(&ctrlargs, client, &session); + if (rc) + return rc; + + /* Get mechanism parameters */ + rc = serialargs_alloc_get_one_attribute(&ctrlargs, &proc_params); + if (rc) + return rc; + + /* Get and check public key attributes */ + rc = serialargs_alloc_get_attributes(&ctrlargs, &template); + if (rc) + goto out; + + rc = get_ready_session(session); + if (rc) + goto out; + + rc = check_mechanism_against_processing(session, proc_params->id, + PKCS11_FUNCTION_GENERATE_PAIR, + PKCS11_FUNC_STEP_INIT); + if (rc) + goto out; + + template_size = sizeof(*template) + template->attrs_size; + + rc = create_attributes_from_template(&pub_head, + template, template_size, NULL, + PKCS11_FUNCTION_GENERATE_PAIR, + proc_params->id, + PKCS11_CKO_PUBLIC_KEY); + if (rc) + goto out; + + TEE_Free(template); + template = NULL; + + rc = serialargs_alloc_get_attributes(&ctrlargs, &template); + if (rc) + goto out; + + if (serialargs_remaining_bytes(&ctrlargs)) { + rc = PKCS11_CKR_ARGUMENTS_BAD; + goto out; + } + + template_size = sizeof(*template) + template->attrs_size; + + rc = create_attributes_from_template(&priv_head, + template, template_size, NULL, + PKCS11_FUNCTION_GENERATE_PAIR, + proc_params->id, + PKCS11_CKO_PRIVATE_KEY); + if (rc) + goto out; + + TEE_Free(template); + template = NULL; + + /* Generate CKA_ID for keys if not specified by the templates */ + rc = add_missing_attribute_id(&pub_head, &priv_head); + if (rc) + goto out; + + /* Check created object against processing and token state */ + rc = check_created_attrs(pub_head, priv_head); + if (rc) + goto out; + + rc = check_created_attrs_against_processing(proc_params->id, pub_head); + if (rc) + goto out; + + rc = check_created_attrs_against_processing(proc_params->id, priv_head); + if (rc) + goto out; + + rc = check_created_attrs_against_token(session, pub_head); + if (rc) + goto out; + + rc = check_created_attrs_against_token(session, priv_head); + if (rc) + goto out; + + /* Generate key pair */ + switch (proc_params->id) { + default: + rc = PKCS11_CKR_MECHANISM_INVALID; + break; + } + if (rc) + goto out; + + TEE_Free(proc_params); + proc_params = NULL; + + /* + * Object is ready, register it and return a handle. + */ + rc = create_object(session, pub_head, &pubkey_handle); + if (rc) + goto out; + + /* + * Now obj_handle (through the related struct pkcs11_object instance) + * owns the serialized buffer that holds the object attributes. + * We reset local pub_head to NULL to mark that ownership has been + * transferred. + */ + pub_head = NULL; + + rc = create_object(session, priv_head, &privkey_handle); + if (rc) + goto out; + + /* Ownership has been transferred so mark it with NULL */ + priv_head = NULL; + + hdl_ptr = (uint32_t *)out->memref.buffer; + + TEE_MemMove(hdl_ptr, &pubkey_handle, sizeof(pubkey_handle)); + TEE_MemMove(hdl_ptr + 1, &privkey_handle, sizeof(privkey_handle)); + + pubkey_handle = 0; + privkey_handle = 0; + + DMSG("PKCS11 session %"PRIu32": create key pair %#"PRIx32"/%#"PRIx32, + session->handle, privkey_handle, pubkey_handle); + +out: + if (pubkey_handle) + destroy_object(session, pubkey_handle, false); + TEE_Free(priv_head); + TEE_Free(pub_head); + TEE_Free(template); + TEE_Free(proc_params); + + return rc; +} + /* * entry_processing_init - Generic entry for initializing a processing * diff --git a/ta/pkcs11/src/processing.h b/ta/pkcs11/src/processing.h index afeaf2aae4d..526dfea4ae8 100644 --- a/ta/pkcs11/src/processing.h +++ b/ta/pkcs11/src/processing.h @@ -21,6 +21,9 @@ struct active_processing; enum pkcs11_rc entry_generate_secret(struct pkcs11_client *client, uint32_t ptypes, TEE_Param *params); +enum pkcs11_rc entry_generate_key_pair(struct pkcs11_client *client, + uint32_t ptypes, TEE_Param *params); + enum pkcs11_rc entry_processing_init(struct pkcs11_client *client, uint32_t ptypes, TEE_Param *params, enum processing_func function); @@ -37,6 +40,15 @@ size_t get_object_key_bit_size(struct pkcs11_object *obj); void release_active_processing(struct pkcs11_session *session); +enum pkcs11_rc alloc_get_tee_attribute_data(TEE_ObjectHandle tee_obj, + uint32_t attribute, + void **data, size_t *size); + +enum pkcs11_rc tee2pkcs_add_attribute(struct obj_attrs **head, + uint32_t pkcs11_id, + TEE_ObjectHandle tee_obj, + uint32_t tee_id); + /* * Symmetric crypto algorithm specific functions */