aboutsummaryrefslogtreecommitdiff
path: root/rpc_pkey.c
diff options
context:
space:
mode:
Diffstat (limited to 'rpc_pkey.c')
-rw-r--r--rpc_pkey.c494
1 files changed, 403 insertions, 91 deletions
diff --git a/rpc_pkey.c b/rpc_pkey.c
index 48072ce..e0d9bdc 100644
--- a/rpc_pkey.c
+++ b/rpc_pkey.c
@@ -38,6 +38,7 @@
#include "hal.h"
#include "hal_internal.h"
+#include "asn1_internal.h"
#ifndef HAL_STATIC_PKEY_STATE_BLOCKS
#define HAL_STATIC_PKEY_STATE_BLOCKS 0
@@ -56,7 +57,10 @@ static hal_pkey_slot_t pkey_slot[HAL_STATIC_PKEY_STATE_BLOCKS];
*
* The high order bit of the pkey handle is left free for
* HAL_PKEY_HANDLE_TOKEN_FLAG, which is used by the mixed-mode
- * handlers to route calls to the appropriate destination.
+ * handlers to route calls to the appropriate destination. In most
+ * cases this flag is set here, but pkey_local_open() also sets it
+ * directly, so that we can present a unified UUID namespace
+ * regardless of which keystore holds a particular key.
*/
static inline hal_pkey_slot_t *alloc_slot(const hal_key_flags_t flags)
@@ -117,10 +121,10 @@ static inline hal_pkey_slot_t *find_handle(const hal_pkey_handle_t handle)
*
* That's almost the rule that PKCS #11 follows for so-called
* "private" objects (CKA_PRIVATE = CK_TRUE), but PKCS #11 has a more
- * model which not only allows wider visibility to "public" objects
- * (CKA_PRIVATE = CK_FALSE) but also allows write access to "public
- * session" (CKA_PRIVATE = CK_FALSE, CKA_TOKEN = CK_FALSE) objects
- * regardless of login state.
+ * complex model which not only allows wider visibility to "public"
+ * objects (CKA_PRIVATE = CK_FALSE) but also allows write access to
+ * "public session" (CKA_PRIVATE = CK_FALSE, CKA_TOKEN = CK_FALSE)
+ * objects regardless of login state.
*
* PKCS #11 also has a concept of read-only sessions, which we don't
* bother to implement at all on the HSM, since the PIN is required to
@@ -173,29 +177,55 @@ static inline hal_error_t check_writable(const hal_client_handle_t client,
}
/*
+ * PKCS #1.5 encryption requires non-zero random bytes, which is a bit
+ * messy if done in place, so make it a separate function for readability.
+ */
+
+static inline hal_error_t get_nonzero_random(uint8_t *buffer, size_t n)
+{
+ assert(buffer != NULL);
+
+ uint32_t word = 0;
+ hal_error_t err;
+
+ while (n > 0) {
+
+ while ((word & 0xFF) == 0)
+ if ((word & ~0xFF) != 0)
+ word >>= 8;
+ else if ((err = hal_get_random(NULL, &word, sizeof(word))) != HAL_OK)
+ return err;
+
+ *buffer++ = word & 0xFF;
+ word >>= 8;
+ n--;
+ }
+
+ return HAL_OK;
+}
+
+/*
* Pad an octet string with PKCS #1.5 padding for use with RSA.
*
- * For the moment, this only handles type 01 encryption blocks, thus
- * is only suitable for use with signature and verification. If and
- * when we add support for encryption and decryption, this function
- * should be extended to take an argument specifying the block type
- * and include support for generating type 02 encryption blocks.
- * Other than the block type code, the only difference is the padding
- * value: for type 01 it's constant (0xFF), for type 02 it should be
- * non-zero random bytes from the CSPRNG.
+ * This handles type 01 and type 02 encryption blocks. The formats
+ * are identical, except that the padding string is constant 0xFF
+ * bytes for type 01 and non-zero random bytes for type 02.
*
* We use memmove() instead of memcpy() so that the caller can
* construct the data to be padded in the same buffer.
*/
static hal_error_t pkcs1_5_pad(const uint8_t * const data, const size_t data_len,
- uint8_t *block, const size_t block_len)
+ uint8_t *block, const size_t block_len,
+ const uint8_t type)
{
- assert(data != NULL && block != NULL);
+ assert(data != NULL && block != NULL && (type == 0x01 || type == 0x02));
+
+ hal_error_t err;
/*
* Congregation will now please turn to RFC 2313 8.1 as we
- * construct a PKCS #1.5 type 01 encryption block.
+ * construct a PKCS #1.5 type 01 or type 02 encryption block.
*/
if (data_len > block_len - 11)
@@ -204,10 +234,20 @@ static hal_error_t pkcs1_5_pad(const uint8_t * const data, const size_t data_len
memmove(block + block_len - data_len, data, data_len);
block[0] = 0x00;
- block[1] = 0x01;
+ block[1] = type;
+
+ switch (type) {
+
+ case 0x01: /* Signature */
+ memset(block + 2, 0xFF, block_len - 3 - data_len);
+ break;
+
+ case 0x02: /* Encryption */
+ if ((err = get_nonzero_random(block + 2, block_len - 3 - data_len)) != HAL_OK)
+ return err;
+ break;
- /* This is where we'd use non-zero random bytes if constructing a type 02 block. */
- memset(block + 2, 0xFF, block_len - 3 - data_len);
+ }
block[block_len - data_len - 1] = 0x00;
@@ -227,6 +267,44 @@ static inline hal_error_t ks_open_from_flags(hal_ks_t **ks, const hal_key_flags_
}
/*
+ * Fetch a key from a driver.
+ */
+
+static inline hal_error_t ks_fetch_from_driver(const hal_ks_driver_t * const driver,
+ hal_pkey_slot_t *slot,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ hal_ks_t *ks = NULL;
+ hal_error_t err;
+
+ if ((err = hal_ks_open(driver, &ks)) != HAL_OK)
+ return err;
+
+ if ((err = hal_ks_fetch(ks, slot, der, der_len, der_max)) == HAL_OK)
+ err = hal_ks_close(ks);
+ else
+ (void) hal_ks_close(ks);
+
+ return err;
+}
+
+/*
+ * Same thing but from key flag in slot object rather than explict driver.
+ */
+
+static inline hal_error_t ks_fetch_from_flags(hal_pkey_slot_t *slot,
+ uint8_t *der, size_t *der_len, const size_t der_max)
+{
+ assert(slot != NULL);
+
+ return ks_fetch_from_driver((slot->flags & HAL_KEY_FLAG_TOKEN) == 0
+ ? hal_ks_volatile_driver
+ : hal_ks_token_driver,
+ slot, der, der_len, der_max);
+}
+
+
+/*
* Receive key from application, generate a name (UUID), store it, and
* return a key handle and the name.
*/
@@ -234,21 +312,24 @@ static inline hal_error_t ks_open_from_flags(hal_ks_t **ks, const hal_key_flags_
static hal_error_t pkey_local_load(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const hal_key_type_t type,
- const hal_curve_name_t curve,
hal_uuid_t *name,
const uint8_t * const der, const size_t der_len,
const hal_key_flags_t flags)
{
- assert(pkey != NULL && name != NULL);
+ assert(pkey != NULL && name != NULL && der != NULL);
+ hal_curve_name_t curve;
hal_pkey_slot_t *slot;
+ hal_key_type_t type;
hal_ks_t *ks = NULL;
hal_error_t err;
if ((err = check_writable(client, flags)) != HAL_OK)
return err;
+ if ((err = hal_asn1_guess_key_type(&type, &curve, der, der_len)) != HAL_OK)
+ return err;
+
if ((slot = alloc_slot(flags)) == NULL)
return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE;
@@ -284,38 +365,38 @@ static hal_error_t pkey_local_load(const hal_client_handle_t client,
static hal_error_t pkey_local_open(const hal_client_handle_t client,
const hal_session_handle_t session,
hal_pkey_handle_t *pkey,
- const hal_uuid_t * const name,
- const hal_key_flags_t flags)
+ const hal_uuid_t * const name)
{
assert(pkey != NULL && name != NULL);
hal_pkey_slot_t *slot;
- hal_ks_t *ks = NULL;
hal_error_t err;
- if ((err = check_readable(client, flags)) != HAL_OK)
+ if ((err = check_readable(client, 0)) != HAL_OK)
return err;
- if ((slot = alloc_slot(flags)) == NULL)
+ if ((slot = alloc_slot(0)) == NULL)
return HAL_ERROR_NO_KEY_SLOTS_AVAILABLE;
slot->name = *name;
slot->client_handle = client;
slot->session_handle = session;
- if ((err = ks_open_from_flags(&ks, flags)) == HAL_OK &&
- (err = hal_ks_fetch(ks, slot, NULL, NULL, 0)) == HAL_OK)
- err = hal_ks_close(ks);
- else if (ks != NULL)
- (void) hal_ks_close(ks);
+ if ((err = ks_fetch_from_driver(hal_ks_token_driver, slot, NULL, NULL, 0)) == HAL_OK)
+ slot->pkey_handle.handle |= HAL_PKEY_HANDLE_TOKEN_FLAG;
- if (err != HAL_OK) {
- slot->type = HAL_KEY_TYPE_NONE;
- return err;
- }
+ else if (err == HAL_ERROR_KEY_NOT_FOUND)
+ err = ks_fetch_from_driver(hal_ks_volatile_driver, slot, NULL, NULL, 0);
+
+ if (err != HAL_OK)
+ goto fail;
*pkey = slot->pkey_handle;
return HAL_OK;
+
+ fail:
+ memset(slot, 0, sizeof(*slot));
+ return err;
}
/*
@@ -568,16 +649,9 @@ static size_t pkey_local_get_public_key_len(const hal_pkey_handle_t pkey)
hal_ecdsa_key_t *ecdsa_key = NULL;
uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
size_t der_len;
- hal_ks_t *ks = NULL;
hal_error_t err;
- if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
- (err = hal_ks_fetch(ks, slot, der, &der_len, sizeof(der))) == HAL_OK)
- err = hal_ks_close(ks);
- else if (ks != NULL)
- (void) hal_ks_close(ks);
-
- if (err == HAL_OK) {
+ if ((err = ks_fetch_from_flags(slot, der, &der_len, sizeof(der))) == HAL_OK) {
switch (slot->type) {
case HAL_KEY_TYPE_RSA_PUBLIC:
@@ -618,21 +692,15 @@ static hal_error_t pkey_local_get_public_key(const hal_pkey_handle_t pkey,
if (slot == NULL)
return HAL_ERROR_KEY_NOT_FOUND;
- uint8_t keybuf[hal_rsa_key_t_size > hal_ecdsa_key_t_size ? hal_rsa_key_t_size : hal_ecdsa_key_t_size];
+ uint8_t keybuf[hal_rsa_key_t_size > hal_ecdsa_key_t_size
+ ? hal_rsa_key_t_size : hal_ecdsa_key_t_size];
hal_rsa_key_t *rsa_key = NULL;
hal_ecdsa_key_t *ecdsa_key = NULL;
uint8_t buf[HAL_KS_WRAPPED_KEYSIZE];
size_t buf_len;
- hal_ks_t *ks = NULL;
hal_error_t err;
- if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
- (err = hal_ks_fetch(ks, slot, buf, &buf_len, sizeof(buf))) == HAL_OK)
- err = hal_ks_close(ks);
- else if (ks != NULL)
- (void) hal_ks_close(ks);
-
- if (err == HAL_OK) {
+ if ((err = ks_fetch_from_flags(slot, buf, &buf_len, sizeof(buf))) == HAL_OK) {
switch (slot->type) {
case HAL_KEY_TYPE_RSA_PUBLIC:
@@ -699,7 +767,7 @@ static hal_error_t pkey_local_sign_rsa(uint8_t *keybuf, const size_t keybuf_len,
input = signature;
}
- if ((err = pkcs1_5_pad(input, input_len, signature, *signature_len)) != HAL_OK ||
+ if ((err = pkcs1_5_pad(input, input_len, signature, *signature_len, 0x01)) != HAL_OK ||
(err = hal_rsa_decrypt(NULL, key, signature, *signature_len, signature, *signature_len)) != HAL_OK)
return err;
@@ -770,20 +838,18 @@ static hal_error_t pkey_local_sign(const hal_pkey_handle_t pkey,
return HAL_ERROR_UNSUPPORTED_KEY;
}
- uint8_t keybuf[hal_rsa_key_t_size > hal_ecdsa_key_t_size ? hal_rsa_key_t_size : hal_ecdsa_key_t_size];
+ if ((slot->flags & HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE) == 0)
+ return HAL_ERROR_FORBIDDEN;
+
+ uint8_t keybuf[hal_rsa_key_t_size > hal_ecdsa_key_t_size
+ ? hal_rsa_key_t_size : hal_ecdsa_key_t_size];
uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
size_t der_len;
- hal_ks_t *ks = NULL;
hal_error_t err;
- if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
- (err = hal_ks_fetch(ks, slot, der, &der_len, sizeof(der))) == HAL_OK)
- err = hal_ks_close(ks);
- else if (ks != NULL)
- (void) hal_ks_close(ks);
-
- if (err == HAL_OK)
- err = signer(keybuf, sizeof(keybuf), der, der_len, hash, input, input_len, signature, signature_len, signature_max);
+ if ((err = ks_fetch_from_flags(slot, der, &der_len, sizeof(der))) == HAL_OK)
+ err = signer(keybuf, sizeof(keybuf), der, der_len, hash, input, input_len,
+ signature, signature_len, signature_max);
memset(keybuf, 0, sizeof(keybuf));
memset(der, 0, sizeof(der));
@@ -831,7 +897,7 @@ static hal_error_t pkey_local_verify_rsa(uint8_t *keybuf, const size_t keybuf_le
input = expected;
}
- if ((err = pkcs1_5_pad(input, input_len, expected, sizeof(expected))) != HAL_OK ||
+ if ((err = pkcs1_5_pad(input, input_len, expected, sizeof(expected), 0x01)) != HAL_OK ||
(err = hal_rsa_encrypt(NULL, key, signature, signature_len, received, sizeof(received))) != HAL_OK)
return err;
@@ -918,20 +984,18 @@ static hal_error_t pkey_local_verify(const hal_pkey_handle_t pkey,
return HAL_ERROR_UNSUPPORTED_KEY;
}
- uint8_t keybuf[hal_rsa_key_t_size > hal_ecdsa_key_t_size ? hal_rsa_key_t_size : hal_ecdsa_key_t_size];
+ if ((slot->flags & HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE) == 0)
+ return HAL_ERROR_FORBIDDEN;
+
+ uint8_t keybuf[hal_rsa_key_t_size > hal_ecdsa_key_t_size
+ ? hal_rsa_key_t_size : hal_ecdsa_key_t_size];
uint8_t der[HAL_KS_WRAPPED_KEYSIZE];
size_t der_len;
- hal_ks_t *ks = NULL;
hal_error_t err;
- if ((err = ks_open_from_flags(&ks, slot->flags)) == HAL_OK &&
- (err = hal_ks_fetch(ks, slot, der, &der_len, sizeof(der))) == HAL_OK)
- err = hal_ks_close(ks);
- else if (ks != NULL)
- (void) hal_ks_close(ks);
-
- if (err == HAL_OK)
- err = verifier(keybuf, sizeof(keybuf), slot->type, der, der_len, hash, input, input_len, signature, signature_len);
+ if ((err = ks_fetch_from_flags(slot, der, &der_len, sizeof(der))) == HAL_OK)
+ err = verifier(keybuf, sizeof(keybuf), slot->type, der, der_len, hash,
+ input, input_len, signature, signature_len);
memset(keybuf, 0, sizeof(keybuf));
memset(der, 0, sizeof(der));
@@ -939,40 +1003,111 @@ static hal_error_t pkey_local_verify(const hal_pkey_handle_t pkey,
return err;
}
+static inline hal_error_t match_one_keystore(const hal_ks_driver_t * const driver,
+ const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ const hal_key_type_t type,
+ const hal_curve_name_t curve,
+ const hal_key_flags_t mask,
+ const hal_key_flags_t flags,
+ const hal_pkey_attribute_t *attributes,
+ const unsigned attributes_len,
+ hal_uuid_t **result,
+ unsigned *result_len,
+ const unsigned result_max,
+ const hal_uuid_t * const previous_uuid)
+{
+ hal_ks_t *ks = NULL;
+ hal_error_t err;
+ unsigned len;
+
+ if ((err = hal_ks_open(driver, &ks)) != HAL_OK)
+ return err;
+
+ if ((err = hal_ks_match(ks, client, session, type, curve,
+ mask, flags, attributes, attributes_len,
+ *result, &len, result_max - *result_len,
+ previous_uuid)) != HAL_OK) {
+ (void) hal_ks_close(ks);
+ return err;
+ }
+
+ if ((err = hal_ks_close(ks)) != HAL_OK)
+ return err;
+
+ *result += len;
+ *result_len += len;
+
+ return HAL_OK;
+}
+
+typedef enum {
+ MATCH_STATE_START,
+ MATCH_STATE_TOKEN,
+ MATCH_STATE_VOLATILE,
+ MATCH_STATE_DONE
+} match_state_t;
+
static hal_error_t pkey_local_match(const hal_client_handle_t client,
const hal_session_handle_t session,
const hal_key_type_t type,
const hal_curve_name_t curve,
+ const hal_key_flags_t mask,
const hal_key_flags_t flags,
const hal_pkey_attribute_t *attributes,
const unsigned attributes_len,
+ unsigned *state,
hal_uuid_t *result,
unsigned *result_len,
const unsigned result_max,
const hal_uuid_t * const previous_uuid)
{
- hal_ks_t *ks = NULL;
+ assert(state != NULL && result_len != NULL);
+
+ static const hal_uuid_t uuid_zero[1] = {{{0}}};
+ const hal_uuid_t *prev = previous_uuid;
hal_error_t err;
- err = check_readable(client, flags);
+ *result_len = 0;
- if (err == HAL_ERROR_FORBIDDEN) {
- assert(result_len != NULL);
- *result_len = 0;
+ if ((err = check_readable(client, flags)) == HAL_ERROR_FORBIDDEN)
return HAL_OK;
- }
-
- if (err != HAL_OK)
+ else if (err != HAL_OK)
return err;
- if ((err = ks_open_from_flags(&ks, flags)) == HAL_OK &&
- (err = hal_ks_match(ks, client, session, type, curve, flags, attributes, attributes_len,
- result, result_len, result_max, previous_uuid)) == HAL_OK)
- err = hal_ks_close(ks);
- else if (ks != NULL)
- (void) hal_ks_close(ks);
+ switch ((match_state_t) *state) {
- return err;
+ case MATCH_STATE_START:
+ prev = uuid_zero;
+ ++*state;
+
+ case MATCH_STATE_TOKEN:
+ if (((mask & HAL_KEY_FLAG_TOKEN) == 0 || (mask & flags & HAL_KEY_FLAG_TOKEN) != 0) &&
+ (err = match_one_keystore(hal_ks_token_driver, client, session, type, curve,
+ mask, flags, attributes, attributes_len,
+ &result, result_len, result_max - *result_len, prev)) != HAL_OK)
+ return err;
+ if (*result_len == result_max)
+ return HAL_OK;
+ prev = uuid_zero;
+ ++*state;
+
+ case MATCH_STATE_VOLATILE:
+ if (((mask & HAL_KEY_FLAG_TOKEN) == 0 || (mask & flags & HAL_KEY_FLAG_TOKEN) == 0) &&
+ (err = match_one_keystore(hal_ks_volatile_driver, client, session, type, curve,
+ mask, flags, attributes, attributes_len,
+ &result, result_len, result_max - *result_len, prev)) != HAL_OK)
+ return err;
+ if (*result_len == result_max)
+ return HAL_OK;
+ ++*state;
+
+ case MATCH_STATE_DONE:
+ return HAL_OK;
+
+ default:
+ return HAL_ERROR_BAD_ARGUMENTS;
+ }
}
static hal_error_t pkey_local_set_attributes(const hal_pkey_handle_t pkey,
@@ -1023,6 +1158,181 @@ static hal_error_t pkey_local_get_attributes(const hal_pkey_handle_t pkey,
return err;
}
+static hal_error_t pkey_local_export(const hal_pkey_handle_t pkey_handle,
+ const hal_pkey_handle_t kekek_handle,
+ uint8_t *pkcs8, size_t *pkcs8_len, const size_t pkcs8_max,
+ uint8_t *kek, size_t *kek_len, const size_t kek_max)
+{
+ assert(pkcs8 != NULL && pkcs8_len != NULL && kek != NULL && kek_len != NULL && kek_max > KEK_LENGTH);
+
+ uint8_t rsabuf[hal_rsa_key_t_size];
+ hal_rsa_key_t *rsa = NULL;
+ hal_error_t err;
+ size_t len;
+
+ hal_pkey_slot_t * const pkey = find_handle(pkey_handle);
+ hal_pkey_slot_t * const kekek = find_handle(kekek_handle);
+
+ if (pkey == NULL || kekek == NULL)
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ if ((pkey->flags & HAL_KEY_FLAG_EXPORTABLE) == 0)
+ return HAL_ERROR_FORBIDDEN;
+
+ if ((kekek->flags & HAL_KEY_FLAG_USAGE_KEYENCIPHERMENT) == 0)
+ return HAL_ERROR_FORBIDDEN;
+
+ if (kekek->type != HAL_KEY_TYPE_RSA_PRIVATE && kekek->type != HAL_KEY_TYPE_RSA_PUBLIC)
+ return HAL_ERROR_UNSUPPORTED_KEY;
+
+ if (pkcs8_max < HAL_KS_WRAPPED_KEYSIZE)
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+ if ((err = ks_fetch_from_flags(kekek, pkcs8, &len, pkcs8_max)) != HAL_OK)
+ goto fail;
+
+ switch (kekek->type) {
+ case HAL_KEY_TYPE_RSA_PRIVATE:
+ err = hal_rsa_private_key_from_der(&rsa, rsabuf, sizeof(rsabuf), pkcs8, len);
+ break;
+ case HAL_KEY_TYPE_RSA_PUBLIC:
+ err = hal_rsa_public_key_from_der(&rsa, rsabuf, sizeof(rsabuf), pkcs8, len);
+ break;
+ default:
+ err = HAL_ERROR_IMPOSSIBLE;
+ }
+ if (err != HAL_OK)
+ goto fail;
+
+ if ((err = hal_rsa_key_get_modulus(rsa, NULL, kek_len, 0)) != HAL_OK)
+ goto fail;
+
+ if (*kek_len > kek_max) {
+ err = HAL_ERROR_RESULT_TOO_LONG;
+ goto fail;
+ }
+
+ if ((err = ks_fetch_from_flags(pkey, pkcs8, &len, pkcs8_max)) != HAL_OK)
+ goto fail;
+
+ if ((err = hal_get_random(NULL, kek, KEK_LENGTH)) != HAL_OK)
+ goto fail;
+
+ *pkcs8_len = pkcs8_max;
+ if ((err = hal_aes_keywrap(NULL, kek, KEK_LENGTH, pkcs8, len, pkcs8, pkcs8_len)) != HAL_OK)
+ goto fail;
+
+ if ((err = hal_asn1_encode_pkcs8_encryptedprivatekeyinfo(hal_asn1_oid_aesKeyWrap,
+ hal_asn1_oid_aesKeyWrap_len,
+ pkcs8, *pkcs8_len,
+ pkcs8, pkcs8_len, pkcs8_max)) != HAL_OK)
+ goto fail;
+
+ if ((err = pkcs1_5_pad(kek, KEK_LENGTH, kek, *kek_len, 0x02)) != HAL_OK)
+ goto fail;
+
+ if ((err = hal_rsa_encrypt(NULL, rsa, kek, *kek_len, kek, *kek_len)) != HAL_OK)
+ goto fail;
+
+ if ((err = hal_asn1_encode_pkcs8_encryptedprivatekeyinfo(hal_asn1_oid_rsaEncryption,
+ hal_asn1_oid_rsaEncryption_len,
+ kek, *kek_len,
+ kek, kek_len, kek_max)) != HAL_OK)
+ goto fail;
+
+ memset(rsabuf, 0, sizeof(rsabuf));
+ return HAL_OK;
+
+ fail:
+ memset(pkcs8, 0, pkcs8_max);
+ memset(kek, 0, kek_max);
+ memset(rsabuf, 0, sizeof(rsabuf));
+ *pkcs8_len = *kek_len = 0;
+ return err;
+}
+
+static hal_error_t pkey_local_import(const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ hal_pkey_handle_t *pkey,
+ hal_uuid_t *name,
+ const hal_pkey_handle_t kekek_handle,
+ const uint8_t * const pkcs8, const size_t pkcs8_len,
+ const uint8_t * const kek_, const size_t kek_len,
+ const hal_key_flags_t flags)
+{
+ assert(pkey != NULL && name != NULL && pkcs8 != NULL && kek_ != NULL && kek_len > 2);
+
+ uint8_t kek[KEK_LENGTH], rsabuf[hal_rsa_key_t_size], der[HAL_KS_WRAPPED_KEYSIZE], *d;
+ size_t der_len, oid_len, data_len;
+ const uint8_t *oid, *data;
+ hal_rsa_key_t *rsa = NULL;
+ hal_error_t err;
+
+ hal_pkey_slot_t * const kekek = find_handle(kekek_handle);
+
+ if (kekek == NULL)
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ if ((kekek->flags & HAL_KEY_FLAG_USAGE_KEYENCIPHERMENT) == 0)
+ return HAL_ERROR_FORBIDDEN;
+
+ if (kekek->type != HAL_KEY_TYPE_RSA_PRIVATE)
+ return HAL_ERROR_UNSUPPORTED_KEY;
+
+ if ((err = ks_fetch_from_flags(kekek, der, &der_len, sizeof(der))) != HAL_OK)
+ goto fail;
+
+ if ((err = hal_rsa_private_key_from_der(&rsa, rsabuf, sizeof(rsabuf), der, der_len)) != HAL_OK)
+ goto fail;
+
+ if ((err = hal_asn1_decode_pkcs8_encryptedprivatekeyinfo(&oid, &oid_len, &data, &data_len,
+ kek_, kek_len)) != HAL_OK)
+ goto fail;
+
+ if (oid_len != hal_asn1_oid_rsaEncryption_len ||
+ memcmp(oid, hal_asn1_oid_rsaEncryption, oid_len) != 0 ||
+ data_len > sizeof(der) ||
+ data_len < 2) {
+ err = HAL_ERROR_ASN1_PARSE_FAILED;
+ goto fail;
+ }
+
+ if ((err = hal_rsa_decrypt(NULL, rsa, data, data_len, der, data_len)) != HAL_OK)
+ goto fail;
+
+ if ((err = hal_get_random(NULL, kek, sizeof(kek))) != HAL_OK)
+ goto fail;
+
+ d = memchr(der + 2, 0x00, data_len - 2);
+
+ if (der[0] == 0x00 && der[1] == 0x02 && d != NULL && d - der > 10 &&
+ der + data_len == d + 1 + KEK_LENGTH)
+ memcpy(kek, d + 1, sizeof(kek));
+
+ if ((err = hal_asn1_decode_pkcs8_encryptedprivatekeyinfo(&oid, &oid_len, &data, &data_len,
+ pkcs8, pkcs8_len)) != HAL_OK)
+ goto fail;
+
+ if (oid_len != hal_asn1_oid_aesKeyWrap_len ||
+ memcmp(oid, hal_asn1_oid_aesKeyWrap, oid_len) != 0 ||
+ data_len > sizeof(der)) {
+ err = HAL_ERROR_ASN1_PARSE_FAILED;
+ goto fail;
+ }
+
+ der_len = sizeof(der);
+ if ((err = hal_aes_keyunwrap(NULL, kek, sizeof(kek), data, data_len, der, &der_len)) != HAL_OK)
+ goto fail;
+
+ err = hal_rpc_pkey_load(client, session, pkey, name, der, der_len, flags);
+
+ fail:
+ memset(rsabuf, 0, sizeof(rsabuf));
+ memset(kek, 0, sizeof(kek));
+ memset(der, 0, sizeof(der));
+ return err;
+}
+
const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch = {
.load = pkey_local_load,
.open = pkey_local_open,
@@ -1039,7 +1349,9 @@ const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch = {
.verify = pkey_local_verify,
.match = pkey_local_match,
.set_attributes = pkey_local_set_attributes,
- .get_attributes = pkey_local_get_attributes
+ .get_attributes = pkey_local_get_attributes,
+ .export = pkey_local_export,
+ .import = pkey_local_import
};
/*