From 4be4d40a2af0aecd4b3fe41e33500cfc35442da2 Mon Sep 17 00:00:00 2001 From: Rob Austein Date: Sun, 15 May 2016 23:01:45 -0400 Subject: Use key hashes instead of CKA_ID to name objects in libhal keystore. --- pkcs11.c | 231 +++++++++++++++++++++++++++++++++++++++---------------------- schema.sql | 1 + 2 files changed, 150 insertions(+), 82 deletions(-) diff --git a/pkcs11.c b/pkcs11.c index b5878e5..e08b9ca 100644 --- a/pkcs11.c +++ b/pkcs11.c @@ -188,6 +188,16 @@ typedef enum { #define is_token_handle(_handle_) (((_handle_) & FLAG_HANDLE_TOKEN) != 0) +/* + * Digest algorithm to use when computing a key hashes. This doesn't + * need to be particularly secure, we're just using it to generate + * reasonably unique identifier strings from public keys. We use + * SHA-1 for this because that's what most X.509 implementations use + * for this purpose. + */ + +#define P11_KEY_HASH_ALGORITHM hal_digest_algorithm_sha1 + /* @@ -1345,7 +1355,7 @@ static CK_OBJECT_HANDLE p11_object_create(const p11_session_t *session, } /* - * Construct libhal type code for a key object. + * Construct and store libhal type code for a key object. */ static int p11_object_pkey_type(const CK_OBJECT_HANDLE object_handle, @@ -1380,11 +1390,61 @@ static int p11_object_pkey_type(const CK_OBJECT_HANDLE object_handle, sqlite3_stmt *q = NULL; - return (sql_check_ok(sql_prepare(&q, update_pkey_type)) && - sql_check_ok(sqlite3_bind_int64(q, 1, object_handle)) && - sql_check_ok(sqlite3_bind_int64(q, 2, *pkey_type)) && - sql_check_done(sqlite3_step(q)) && - sql_check_ok(sqlite3_finalize(q))); + int ok = (sql_check_ok(sql_prepare(&q, update_pkey_type)) && + sql_check_ok(sqlite3_bind_int64(q, 1, object_handle)) && + sql_check_ok(sqlite3_bind_int64(q, 2, *pkey_type)) && + sql_check_done(sqlite3_step(q))); + + sqlite3_finalize(q); + return ok; +} + +/* + * Construct and store SKI (key hash) for a key object. + */ + +static int p11_object_pkey_ski(const p11_session_t * const session, + const CK_OBJECT_HANDLE object_handle_1, + const CK_OBJECT_HANDLE object_handle_2, + const uint8_t * const der, const size_t der_len, + uint8_t *ski, const size_t ski_len) +{ + assert(session != NULL && der != NULL && ski != NULL); + + static const char update_pkey_ski[] = + " UPDATE object SET hal_pkey_ski = ?2 WHERE object_handle = ?1"; + + hal_hash_handle_t hash = {HAL_HANDLE_NONE}; + + int ok = hal_check(hal_rpc_hash_initialize(p11_session_hal_client(session), + p11_session_hal_session(session), + &hash, P11_KEY_HASH_ALGORITHM, NULL, 0)); + if (ok) + ok = hal_check(hal_rpc_hash_update(hash, der, der_len)); + + if (hash.handle != HAL_HANDLE_NONE) + ok = hal_check(hal_rpc_hash_finalize(hash, ski, ski_len)) && ok; + + if (!ok) + return 0; + + sqlite3_stmt *q = NULL; + + ok = (sql_check_ok(sql_prepare(&q, update_pkey_ski)) && + sql_check_ok(sqlite3_bind_int64(q, 1, + object_handle_1)) && + sql_check_ok(sqlite3_bind_blob( q, 2, + ski, ski_len, NULL)) && + sql_check_done(sqlite3_step(q))); + + if (ok && object_handle_2 != CK_INVALID_HANDLE) + ok = (sql_check_ok(sqlite3_reset(q)) && + sql_check_ok(sqlite3_bind_int64(q, 1, + object_handle_2)) && + sql_check_done(sqlite3_step(q))); + + sqlite3_finalize(q); + return ok; } /* @@ -1396,8 +1456,6 @@ static int p11_object_pkey_type(const CK_OBJECT_HANDLE object_handle, static inline int p11_object_get_rsa_public_key(const p11_session_t * const session, const CK_OBJECT_HANDLE object_handle, hal_pkey_handle_t *pkey_handle, - const char *flavor, - const uint8_t * const name, const size_t name_len, const hal_key_flags_t flags) { static const char select_format[] = @@ -1405,17 +1463,22 @@ static inline int p11_object_get_rsa_public_key(const p11_session_t * const sess " 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"; + uint8_t keybuf[hal_rsa_key_t_size]; hal_rsa_key_t *key = NULL; sqlite3_stmt *q = NULL; + size_t ski_len = 0; int ok - = (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_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_public(&key, keybuf, sizeof(keybuf), sqlite3_column_blob( q, 0), sqlite3_column_bytes(q, 0), @@ -1423,12 +1486,14 @@ static inline int p11_object_get_rsa_public_key(const p11_session_t * const sess sqlite3_column_bytes(q, 1)))); if (ok) { - uint8_t der[hal_rsa_public_key_to_der_len(key)]; - ok = (hal_check(hal_rsa_public_key_to_der(key, der, NULL, sizeof(der))) && + uint8_t der[hal_rsa_public_key_to_der_len(key)], ski[ski_len]; + ok = (hal_check(hal_rsa_public_key_to_der(key, der, NULL, sizeof(der))) && + p11_object_pkey_ski(session, object_handle, CK_INVALID_HANDLE, + der, sizeof(der), ski, sizeof(ski)) && hal_check(hal_rpc_pkey_load(p11_session_hal_client(session), p11_session_hal_session(session), pkey_handle, HAL_KEY_TYPE_RSA_PUBLIC, - HAL_CURVE_NONE, name, name_len, + HAL_CURVE_NONE, ski, sizeof(ski), der, sizeof(der), flags))); } @@ -1439,8 +1504,6 @@ static inline int p11_object_get_rsa_public_key(const p11_session_t * const sess static inline int p11_object_get_ec_public_key(const p11_session_t * const session, const CK_OBJECT_HANDLE object_handle, hal_pkey_handle_t *pkey_handle, - const char *flavor, - const uint8_t * const name, const size_t name_len, const hal_key_flags_t flags) { static const char select_format[] = @@ -1448,33 +1511,40 @@ static inline int p11_object_get_ec_public_key(const p11_session_t * const sessi " 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"; + 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; int ok - = (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 && + = (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) && + &curve) && hal_check(hal_ecdsa_key_from_ecpoint(&key, keybuf, sizeof(keybuf), sqlite3_column_blob( q, 1), sqlite3_column_bytes(q, 1), curve))); if (ok) { - uint8_t der[hal_ecdsa_public_key_to_der_len(key)]; - ok = (hal_check(hal_ecdsa_public_key_to_der(key, der, NULL, sizeof(der))) && + uint8_t der[hal_ecdsa_public_key_to_der_len(key)], ski[ski_len]; + ok = (hal_check(hal_ecdsa_public_key_to_der(key, der, NULL, sizeof(der))) && + p11_object_pkey_ski(session, object_handle, CK_INVALID_HANDLE, + der, sizeof(der), ski, sizeof(ski)) && hal_check(hal_rpc_pkey_load(p11_session_hal_client(session), p11_session_hal_session(session), pkey_handle, HAL_KEY_TYPE_EC_PUBLIC, - curve, name, name_len, + curve, ski, sizeof(ski), der, sizeof(der), flags))); } @@ -1486,11 +1556,8 @@ static int p11_object_get_pkey_handle(const p11_session_t * const session, const CK_OBJECT_HANDLE object_handle, hal_pkey_handle_t *pkey_handle) { - static const char select_format[] = - " SELECT value, hal_pkey_type FROM %s_attribute NATURAL JOIN object" - " WHERE object_handle = ?1 AND type = %u"; - - const char *flavor = is_token_handle(object_handle) ? "token" : "session"; + static const char select_query[] = + " SELECT hal_pkey_type, hal_pkey_ski FROM object WHERE object_handle = ?1"; hal_key_flags_t flags = is_token_handle(object_handle) ? 0 : HAL_KEY_FLAG_PROXIMATE; hal_key_type_t pkey_type; @@ -1500,15 +1567,15 @@ static int p11_object_get_pkey_handle(const p11_session_t * const session, assert(pkey_handle != NULL); - if (!sql_check_ok(sql_prepare(&q, select_format, flavor, CKA_ID)) || - !sql_check_ok(sqlite3_bind_int64(q, 1, object_handle)) || + if (!sql_check_ok(sql_prepare(&q, select_query)) || + !sql_check_ok(sqlite3_bind_int64(q, 1, object_handle)) || !sql_check_row(sqlite3_step(q))) goto fail; - switch (sqlite3_column_type(q, 1)) { + switch (sqlite3_column_type(q, 0)) { case SQLITE_INTEGER: - pkey_type = (hal_key_type_t) sqlite3_column_int64(q, 1); + pkey_type = (hal_key_type_t) sqlite3_column_int64(q, 0); break; case SQLITE_NULL: @@ -1520,25 +1587,31 @@ static int p11_object_get_pkey_handle(const p11_session_t * const session, goto fail; } - err = hal_rpc_pkey_find(p11_session_hal_client(session), - p11_session_hal_session(session), - pkey_handle, pkey_type, - sqlite3_column_blob(q, 0), - sqlite3_column_bytes(q, 0), - flags); + switch (sqlite3_column_type(q, 1)) { + + case SQLITE_BLOB: + err = hal_rpc_pkey_find(p11_session_hal_client(session), p11_session_hal_session(session), pkey_handle, + pkey_type, sqlite3_column_blob(q, 1), sqlite3_column_bytes(q, 1), flags); + break; + + case SQLITE_NULL: + err = HAL_ERROR_KEY_NOT_FOUND; + break; + + default: + goto fail; + } if (err == HAL_ERROR_KEY_NOT_FOUND) { switch (pkey_type) { case HAL_KEY_TYPE_RSA_PUBLIC: - if (!p11_object_get_rsa_public_key(session, object_handle, pkey_handle, flavor, - sqlite3_column_blob(q, 0), sqlite3_column_bytes(q, 0), flags)) + if (!p11_object_get_rsa_public_key(session, object_handle, pkey_handle, flags)) goto fail; break; case HAL_KEY_TYPE_EC_PUBLIC: - if (!p11_object_get_ec_public_key(session, object_handle, pkey_handle, flavor, - sqlite3_column_blob(q, 0), sqlite3_column_bytes(q, 0), flags)) + if (!p11_object_get_ec_public_key(session, object_handle, pkey_handle, flags)) goto fail; break; @@ -1897,9 +1970,6 @@ static CK_RV p11_template_check_2(const p11_session_t *session, * possible through the object descriptor. * * Key usage handling here is based on RFC 5280 4.2.1.3. - * - * PKCS #11 suggests but does not require CKA_ID values for public and - * private key to match. */ static CK_RV p11_check_keypair_attributes(const p11_session_t *session, @@ -2007,13 +2077,13 @@ static CK_RV generate_keypair_rsa_pkcs(p11_session_t *session, const CK_ATTRIBUTE_PTR pPrivateKeyTemplate, const CK_ULONG ulPrivateKeyAttributeCount, const CK_OBJECT_HANDLE private_handle, - const hal_key_flags_t private_flags, - const uint8_t * const id, const size_t id_len) + const hal_key_flags_t private_flags) { const uint8_t *public_exponent = const_0x010001; size_t public_exponent_len = sizeof(const_0x010001); hal_pkey_handle_t pkey = {HAL_HANDLE_NONE}; CK_ULONG keysize = 0; + size_t ski_len = 0; CK_RV rv; int i; @@ -2039,22 +2109,28 @@ static CK_RV generate_keypair_rsa_pkcs(p11_session_t *session, } } - if (keysize == 0 || id == NULL) + if (keysize == 0) return CKR_TEMPLATE_INCOMPLETE; + if (!hal_check(hal_rpc_hash_get_digest_length(P11_KEY_HASH_ALGORITHM, &ski_len))) + lose(CKR_FUNCTION_FAILED); + if (!hal_check(hal_rpc_pkey_generate_rsa(p11_session_hal_client(session), p11_session_hal_session(session), - &pkey, id, id_len, keysize, + &pkey, (const uint8_t *) "", 0, keysize, public_exponent, public_exponent_len, private_flags))) lose(CKR_FUNCTION_FAILED); { - uint8_t der[hal_rpc_pkey_get_public_key_len(pkey)], keybuf[hal_rsa_key_t_size]; + uint8_t der[hal_rpc_pkey_get_public_key_len(pkey)], keybuf[hal_rsa_key_t_size], ski[ski_len]; size_t der_len, modulus_len; hal_rsa_key_t *key = NULL; if (!hal_check(hal_rpc_pkey_get_public_key(pkey, der, &der_len, sizeof(der))) || + !p11_object_pkey_ski(session, private_handle, public_handle, + der, sizeof(der), ski, sizeof(ski)) || + !hal_check(hal_rpc_pkey_rename(pkey, ski, sizeof(ski))) || !hal_check(hal_rsa_public_key_from_der(&key, keybuf, sizeof(keybuf), der, der_len)) || !hal_check(hal_rsa_key_get_modulus(key, NULL, &modulus_len, 0))) lose(CKR_FUNCTION_FAILED); @@ -2086,13 +2162,13 @@ static CK_RV generate_keypair_ec(p11_session_t *session, const CK_ATTRIBUTE_PTR pPrivateKeyTemplate, const CK_ULONG ulPrivateKeyAttributeCount, const CK_OBJECT_HANDLE private_handle, - const hal_key_flags_t private_flags, - const uint8_t * const id, const size_t id_len) + const hal_key_flags_t private_flags) { hal_pkey_handle_t pkey = {HAL_HANDLE_NONE}; const CK_BYTE *params = NULL; hal_curve_name_t curve; size_t params_len; + size_t ski_len = 0; CK_RV rv; int i; @@ -2112,23 +2188,29 @@ static CK_RV generate_keypair_ec(p11_session_t *session, } } - if (!ec_curve_oid_to_name(params, params_len, &curve) || id == NULL) + if (!ec_curve_oid_to_name(params, params_len, &curve)) return CKR_TEMPLATE_INCOMPLETE; + if (!hal_check(hal_rpc_hash_get_digest_length(P11_KEY_HASH_ALGORITHM, &ski_len))) + lose(CKR_FUNCTION_FAILED); + if (!hal_check(hal_rpc_pkey_generate_ec(p11_session_hal_client(session), p11_session_hal_session(session), - &pkey, id, id_len, curve, + &pkey, (const uint8_t *) "", 0, curve, private_flags)) || !p11_attribute_set(public_handle, CKA_EC_PARAMS, params, params_len) || !p11_attribute_set(private_handle, CKA_EC_PARAMS, params, params_len)) lose(CKR_FUNCTION_FAILED); { - uint8_t der[hal_rpc_pkey_get_public_key_len(pkey)], keybuf[hal_ecdsa_key_t_size]; + uint8_t der[hal_rpc_pkey_get_public_key_len(pkey)], keybuf[hal_ecdsa_key_t_size], ski[ski_len]; hal_ecdsa_key_t *key = NULL; size_t der_len; if (!hal_check(hal_rpc_pkey_get_public_key(pkey, der, &der_len, sizeof(der))) || + !p11_object_pkey_ski(session, private_handle, public_handle, + der, sizeof(der), ski, sizeof(ski)) || + !hal_check(hal_rpc_pkey_rename(pkey, ski, sizeof(ski))) || !hal_check(hal_ecdsa_public_key_from_der(&key, keybuf, sizeof(keybuf), der, der_len))) lose(CKR_FUNCTION_FAILED); @@ -2167,8 +2249,7 @@ static CK_RV generate_keypair(p11_session_t *session, const CK_ATTRIBUTE_PTR pPrivateKeyTemplate, const CK_ULONG ulPrivateKeyAttributeCount, const CK_OBJECT_HANDLE private_handle, - const hal_key_flags_t private_flags, - const uint8_t * const id, const size_t id_len), + const hal_key_flags_t private_flags), const p11_descriptor_t * const public_descriptor, const p11_descriptor_t * const private_descriptor) { @@ -2218,25 +2299,11 @@ static CK_RV generate_keypair(p11_session_t *session, private_descriptor, pMechanism)) == CK_INVALID_HANDLE) lose(CKR_FUNCTION_FAILED); - { - CK_ULONG id_len = 0; - - if (!p11_attribute_get(private_handle, CKA_ID, NULL, &id_len, 0) && - !p11_attribute_get(public_handle, CKA_ID, NULL, &id_len, 0)) - lose(CKR_TEMPLATE_INCOMPLETE); - - uint8_t id[id_len]; - - if (!p11_attribute_get(private_handle, CKA_ID, id, NULL, (size_t) id_len) && - !p11_attribute_get(public_handle, CKA_ID, id, NULL, (size_t) id_len)) - lose(CKR_TEMPLATE_INCOMPLETE); - - if ((rv = mechanism_handler(session, - pPublicKeyTemplate, ulPublicKeyAttributeCount, public_handle, public_flags, - pPrivateKeyTemplate, ulPrivateKeyAttributeCount, private_handle, private_flags, - id, id_len)) != CKR_OK) - goto fail; - } + rv = mechanism_handler(session, + pPublicKeyTemplate, ulPublicKeyAttributeCount, public_handle, public_flags, + pPrivateKeyTemplate, ulPrivateKeyAttributeCount, private_handle, private_flags); + if (rv != CKR_OK) + goto fail; if (!sql_exec("COMMIT")) lose(CKR_FUNCTION_FAILED); diff --git a/schema.sql b/schema.sql index 8a81505..bc984ab 100644 --- a/schema.sql +++ b/schema.sql @@ -64,6 +64,7 @@ CREATE TEMPORARY TABLE IF NOT EXISTS object ( object_handle INTEGER NOT NULL UNIQUE CHECK (object_handle > 0 AND object_handle <= 0xFFFFFFFF), hal_pkey_type INTEGER, + hal_pkey_ski BLOB, session_id INTEGER REFERENCES session ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED, -- cgit v1.2.3