diff options
-rw-r--r-- | pkcs11.c | 189 |
1 files changed, 175 insertions, 14 deletions
@@ -1351,6 +1351,15 @@ static CK_OBJECT_HANDLE p11_object_create(const p11_session_t *session, * Now populate attributes, starting with the application's * template, which we assume has already been blessed by the API * function that called this method. + * + * If the attribute is flagged as sensitive in the descriptor, we + * don't store it in SQL. Generally, this only arises for private + * key components of objects created with C_CreateObject(), but in + * theory there are some corner cases in which a user could choose + * to mark a private key as extractable and not sensitive, so we + * might have to back-fill missing values in those cases if anyone + * ever thinks up a sane reason for supporting them. For now, assume + * that private keys are bloody well supposed to be private. */ for (i = 0; i < template_length; i++) { @@ -1358,6 +1367,9 @@ static CK_OBJECT_HANDLE p11_object_create(const p11_session_t *session, const void * val = template[i].pValue; const int len = template[i].ulValueLen; + if (p11_attribute_is_sensitive(descriptor, type)) + continue; + if (!sql_check_ok(sqlite3_reset(q)) || !sql_check_ok(sqlite3_bind_int64(q, 2, type)) || !sql_check_ok(sqlite3_bind_blob( q, 3, val, len, NULL)) || @@ -1473,7 +1485,7 @@ static int p11_object_bind_pkey(const p11_session_t * const session, } /* - * Create pkeys to go with PKCS #11 public key objects loaded by C_CreateObject(). + * Create pkeys to go with PKCS #11 key objects loaded by C_CreateObject(). */ static inline int p11_object_create_rsa_public_key(const p11_session_t * const session, @@ -1571,6 +1583,159 @@ static inline int p11_object_create_ec_public_key(const p11_session_t * const se return ok; } +static inline int p11_object_create_rsa_private_key(const p11_session_t * const session, + const CK_OBJECT_HANDLE object_handle, + const hal_key_flags_t flags, + const CK_ATTRIBUTE_PTR const template, + const CK_ULONG template_len) +{ + static const char select_format[] = + " WITH a (type, value) " + " AS (SELECT type, value FROM %s_attribute NATURAL JOIN object WHERE object_handle = ?1)" + " SELECT a1.value, a2.value FROM a AS a1, a AS a2 WHERE a1.type = %u AND a2.type = %u"; + + const char *flavor = is_token_handle(object_handle) ? "token" : "session"; + + hal_pkey_handle_t pkey = {HAL_HANDLE_NONE}; + uint8_t keybuf[hal_rsa_key_t_size]; + hal_rsa_key_t *key = NULL; + sqlite3_stmt *q = NULL; + size_t ski_len = 0; + + const uint8_t *cka_private_exponent = NULL; size_t cka_private_exponent_len = 0; + const uint8_t *cka_prime_1 = NULL; size_t cka_prime_1_len = 0; + const uint8_t *cka_prime_2 = NULL; size_t cka_prime_2_len = 0; + const uint8_t *cka_exponent_1 = NULL; size_t cka_exponent_1_len = 0; + const uint8_t *cka_exponent_2 = NULL; size_t cka_exponent_2_len = 0; + const uint8_t *cka_coefficient = NULL; size_t cka_coefficient_len = 0; + + for (int i = 0; i < template_len; i++) { + switch (template[i].type) { + case CKA_PRIVATE_EXPONENT: + cka_private_exponent = template[i].pValue; cka_private_exponent_len = template[i].ulValueLen; + break; + case CKA_PRIME_1: + cka_prime_1 = template[i].pValue; cka_prime_1_len = template[i].ulValueLen; + break; + case CKA_PRIME_2: + cka_prime_2 = template[i].pValue; cka_prime_2_len = template[i].ulValueLen; + break; + case CKA_EXPONENT_1: + cka_exponent_1 = template[i].pValue; cka_exponent_1_len = template[i].ulValueLen; + break; + case CKA_EXPONENT_2: + cka_exponent_2 = template[i].pValue; cka_exponent_2_len = template[i].ulValueLen; + break; + case CKA_COEFFICIENT: + cka_coefficient = template[i].pValue; cka_coefficient_len = template[i].ulValueLen; + break; + } + } + + int ok + = (hal_check(hal_rpc_hash_get_digest_length(P11_KEY_HASH_ALGORITHM, &ski_len)) && + sql_check_ok(sql_prepare(&q, select_format, flavor, CKA_MODULUS, CKA_PUBLIC_EXPONENT)) && + sql_check_ok(sqlite3_bind_int64(q, 1, object_handle)) && + sql_check_row(sqlite3_step(q)) && + sqlite3_column_type(q, 0) == SQLITE_BLOB && + sqlite3_column_type(q, 1) == SQLITE_BLOB && + hal_check(hal_rsa_key_load_private(&key, keybuf, sizeof(keybuf), + sqlite3_column_blob( q, 0), sqlite3_column_bytes(q, 0), + sqlite3_column_blob( q, 1), sqlite3_column_bytes(q, 1), + cka_private_exponent, cka_private_exponent_len, + cka_prime_1, cka_prime_1_len, + cka_prime_2, cka_prime_2_len, + cka_coefficient, cka_coefficient_len, + cka_exponent_1, cka_exponent_1_len, + cka_exponent_2, cka_exponent_2_len))); + + if (ok) { + const size_t private_len = hal_rsa_private_key_to_der_len(key); + const size_t public_len = hal_rsa_public_key_to_der_len(key); + uint8_t der[public_len > private_len ? public_len : private_len], ski[ski_len]; + ok = (hal_check(hal_rsa_public_key_to_der(key, der, NULL, sizeof(der))) && + p11_object_bind_pkey(session, HAL_KEY_TYPE_RSA_PRIVATE, HAL_KEY_TYPE_NONE, + object_handle, CK_INVALID_HANDLE, + der, public_len, ski, sizeof(ski)) && + hal_check(hal_rsa_private_key_to_der(key, der, NULL, sizeof(der))) && + hal_check(hal_rpc_pkey_load(p11_session_hal_client(session), + p11_session_hal_session(session), + &pkey, HAL_KEY_TYPE_RSA_PRIVATE, HAL_CURVE_NONE, + ski, sizeof(ski), der, private_len, flags))); + memset(der, 0, sizeof(der)); + } + + memset(keybuf, 0, sizeof(keybuf)); + (void) hal_rpc_pkey_close(pkey); + sqlite3_finalize(q); + return ok; +} + +static inline int p11_object_create_ec_private_key(const p11_session_t * const session, + const CK_OBJECT_HANDLE object_handle, + const hal_key_flags_t flags, + const CK_ATTRIBUTE_PTR const template, + const CK_ULONG template_len) +{ + static const char select_format[] = + " WITH a (type, value) " + " AS (SELECT type, value FROM %s_attribute NATURAL JOIN object WHERE object_handle = ?1)" + " SELECT a1.value, a2.value FROM a AS a1, a AS a2 WHERE a1.type = %u AND a2.type = %u"; + + const char *flavor = is_token_handle(object_handle) ? "token" : "session"; + + hal_pkey_handle_t pkey = {HAL_HANDLE_NONE}; + uint8_t keybuf[hal_ecdsa_key_t_size]; + hal_ecdsa_key_t *key = NULL; + hal_curve_name_t curve; + sqlite3_stmt *q = NULL; + size_t ski_len = 0; + const uint8_t *ecpoint = NULL; + size_t ecpoint_len = 0; + + const uint8_t *cka_value = NULL; size_t cka_value_len = 0; + + for (int i = 0; i < template_len; i++) + if (template[i].type == CKA_VALUE) + cka_value = template[i].pValue, cka_value_len = template[i].ulValueLen; + + int ok + = (hal_check(hal_rpc_hash_get_digest_length(P11_KEY_HASH_ALGORITHM, &ski_len)) && + sql_check_ok(sql_prepare(&q, select_format, flavor, CKA_EC_PARAMS, CKA_EC_POINT)) && + sql_check_ok(sqlite3_bind_int64(q, 1, object_handle)) && + sql_check_row(sqlite3_step(q)) && + sqlite3_column_type(q, 0) == SQLITE_BLOB && + sqlite3_column_type(q, 1) == SQLITE_BLOB && + ec_curve_oid_to_name(sqlite3_column_blob( q, 0), sqlite3_column_bytes(q, 0), &curve) && + ((ecpoint_len = sqlite3_column_bytes(q, 1)) & 1) != 0 && + *(ecpoint = sqlite3_column_blob( q, 1)) == 0x04 && + hal_check(hal_ecdsa_key_load_private(&key, keybuf, sizeof(keybuf), curve, + ecpoint + 1 + 0 * ecpoint_len / 2, ecpoint_len / 2, + ecpoint + 1 + 0 * ecpoint_len / 2, ecpoint_len / 2, + cka_value, cka_value_len))); + + if (ok) { + const size_t private_len = hal_ecdsa_private_key_to_der_len(key); + const size_t public_len = hal_ecdsa_public_key_to_der_len(key); + uint8_t der[public_len > private_len ? public_len : private_len], ski[ski_len]; + ok = (hal_check(hal_ecdsa_public_key_to_der(key, der, NULL, sizeof(der))) && + p11_object_bind_pkey(session, HAL_KEY_TYPE_EC_PRIVATE, HAL_KEY_TYPE_NONE, + object_handle, CK_INVALID_HANDLE, + der, public_len, ski, sizeof(ski)) && + hal_check(hal_ecdsa_private_key_to_der(key, der, NULL, sizeof(der))) && + hal_check(hal_rpc_pkey_load(p11_session_hal_client(session), + p11_session_hal_session(session), + &pkey, HAL_KEY_TYPE_EC_PRIVATE, curve, + ski, sizeof(ski), der, private_len, flags))); + memset(der, 0, sizeof(der)); + } + + memset(keybuf, 0, sizeof(keybuf)); + (void) hal_rpc_pkey_close(pkey); + sqlite3_finalize(q); + return ok; +} + /* * Given a PKCS #11 object, obtain a libhal pkey handle. */ @@ -3174,19 +3339,7 @@ CK_RV C_CreateObject(CK_SESSION_HANDLE hSession, lose(CKR_SESSION_READ_ONLY); } - /* - * The above checks notwithstanding, we don't (yet) know how to - * create anything but CKO_PUBLIC_KEY objects here. - * - * The main problem issue is that we need to be very sure that - * sensitive attributes don't get put in publicly-readable storage, - * which will require filtering creation of sensitive attributes in - * p11_object_create(). - * - * Which we need to do anyway, eventually, but let's get handling of - * keys we generate ourselves working properly (again) first. - */ - if (*cka_class != CKO_PUBLIC_KEY) + if (flavor == handle_flavor_session_object && *cka_class == CKO_PRIVATE_KEY) lose(CKR_TEMPLATE_INCONSISTENT); if (!sql_exec("BEGIN")) @@ -3219,6 +3372,14 @@ CK_RV C_CreateObject(CK_SESSION_HANDLE hSession, !p11_object_create_ec_public_key(session, handle, flags)) goto fail; + if (*cka_class == CKO_PRIVATE_KEY && *cka_key_type == CKK_RSA && + !p11_object_create_rsa_private_key(session, handle, flags, pTemplate, ulCount)) + goto fail; + + if (*cka_class == CKO_PRIVATE_KEY && *cka_key_type == CKK_EC && + !p11_object_create_ec_private_key(session, handle, flags, pTemplate, ulCount)) + goto fail; + if (!sql_exec("COMMIT")) lose(CKR_FUNCTION_FAILED); |