aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2016-06-13 01:50:53 -0400
committerRob Austein <sra@hactrn.net>2016-06-13 01:50:53 -0400
commitf266fbc28d1f76c5712d2e60876aa3748ecdd9b6 (patch)
treedc300640d180c3bdbaf8764abd21c5673d121174
parent43d3149674743b9d31a13c934361a286fb5539d7 (diff)
Support for adding private keys via C_CreateObject().
-rw-r--r--pkcs11.c189
1 files changed, 175 insertions, 14 deletions
diff --git a/pkcs11.c b/pkcs11.c
index dc9bb5b..1ac9326 100644
--- a/pkcs11.c
+++ b/pkcs11.c
@@ -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);