[Cryptech-Commits] [sw/pkcs11] 05/07: Support for adding private keys via C_CreateObject().

git at cryptech.is git at cryptech.is
Mon Jun 13 19:48:00 UTC 2016


This is an automated email from the git hooks/post-receive script.

sra at hactrn.net pushed a commit to branch master
in repository sw/pkcs11.

commit f266fbc28d1f76c5712d2e60876aa3748ecdd9b6
Author: Rob Austein <sra at hactrn.net>
AuthorDate: Mon Jun 13 01:50:53 2016 -0400

    Support for adding private keys via C_CreateObject().
---
 pkcs11.c | 189 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file 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);
 



More information about the Commits mailing list