aboutsummaryrefslogtreecommitdiff
path: root/rpc_pkey.c
diff options
context:
space:
mode:
authorPaul Selkirk <paul@psgd.org>2019-11-06 14:34:00 -0500
committerPaul Selkirk <paul@psgd.org>2019-11-06 14:34:00 -0500
commit323bc8ade3eae73174961bbf604257a1b099fe55 (patch)
tree1559cea03677438ca9a7cb0313b65aa0cfb8f7b5 /rpc_pkey.c
parent9e6edd6082cc8d501e2b062983ed58b01ef677d7 (diff)
Export/import "raw" keys for external storage.
Exported keys are wrapped with the MKM KEK, not a transit KEK, and can only be imported back to the same HSM. The idea is to support operators who have more keys than will fit on the HSM, so they will cycle keys into and out of the HSM as needed. NOTE that hashsig is, as always, special. The hashsig key has an internal index that is updated on every signature. To prevent a hashsig key from being re-imported with an old index (which would compromise the security of the key), the hashsig key is disabled on export, and must be deleted from the HSM before being re-imported.
Diffstat (limited to 'rpc_pkey.c')
-rw-r--r--rpc_pkey.c104
1 files changed, 103 insertions, 1 deletions
diff --git a/rpc_pkey.c b/rpc_pkey.c
index b44eb54..67732ad 100644
--- a/rpc_pkey.c
+++ b/rpc_pkey.c
@@ -1474,6 +1474,106 @@ static hal_error_t pkey_local_import(const hal_client_handle_t client,
return err;
}
+static hal_error_t pkey_local_export_raw(const hal_pkey_handle_t pkey_handle,
+ uint8_t *pkcs8, size_t *pkcs8_len, const size_t pkcs8_max)
+{
+ hal_assert(pkcs8 != NULL && pkcs8_len != NULL);
+
+ uint8_t kek[KEK_LENGTH];
+ size_t kek_len;
+ hal_error_t err;
+ size_t len;
+
+ hal_pkey_slot_t * const pkey = find_handle(pkey_handle);
+
+ if (pkey == NULL)
+ return HAL_ERROR_KEY_NOT_FOUND;
+
+ if ((pkey->flags & HAL_KEY_FLAG_EXPORTABLE) == 0)
+ return HAL_ERROR_FORBIDDEN;
+
+ if (pkcs8_max < HAL_KS_WRAPPED_KEYSIZE)
+ return HAL_ERROR_RESULT_TOO_LONG;
+
+ if ((err = ks_fetch_from_flags(pkey, pkcs8, &len, pkcs8_max)) != HAL_OK)
+ goto fail;
+
+ /* if hashsig, update internal parameters and disable further use */
+ if (pkey->type == HAL_KEY_TYPE_HASHSIG_PRIVATE) {
+ if ((err = hal_hashsig_export_raw(&pkey->name, pkcs8, &len, pkcs8_max)) != HAL_OK)
+ goto fail;
+ pkey->flags &= ~HAL_KEY_FLAG_USAGE_DIGITALSIGNATURE;
+ }
+
+ if ((err = hal_mkm_get_kek(kek, &kek_len, sizeof(kek))) != 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;
+
+ return HAL_OK;
+
+ fail:
+ memset(pkcs8, 0, pkcs8_max);
+ memset(kek, 0, sizeof(kek));
+ *pkcs8_len = 0;
+ return err;
+}
+
+static hal_error_t pkey_local_import_raw(const hal_client_handle_t client,
+ const hal_session_handle_t session,
+ hal_pkey_handle_t *pkey,
+ hal_uuid_t *name,
+ const uint8_t * const pkcs8, const size_t pkcs8_len,
+ const hal_key_flags_t flags)
+{
+ hal_assert(pkey != NULL && name != NULL && pkcs8 != NULL);
+
+ uint8_t kek[KEK_LENGTH], der[HAL_KS_WRAPPED_KEYSIZE];
+ size_t der_len, oid_len, data_len, kek_len;
+ const uint8_t *oid, *data;
+ hal_error_t err;
+
+ 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;
+ }
+
+ if ((err = hal_mkm_get_kek(kek, &kek_len, sizeof(kek))) != HAL_OK)
+ goto fail;
+
+ der_len = sizeof(der);
+ if ((err = hal_aes_keyunwrap(NULL, kek, kek_len, data, data_len, der, &der_len)) != HAL_OK)
+ goto fail;
+
+ hal_key_type_t type;
+ hal_curve_name_t curve;
+ if ((err = hal_asn1_guess_key_type(&type, &curve, der, der_len)) == HAL_OK &&
+ type == HAL_KEY_TYPE_HASHSIG_PRIVATE &&
+ (err = hal_hashsig_import(der, der_len, flags)) != HAL_OK)
+ goto fail;
+
+ err = hal_rpc_pkey_load(client, session, pkey, name, der, der_len, flags);
+
+ fail:
+ 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,
@@ -1493,7 +1593,9 @@ const hal_rpc_pkey_dispatch_t hal_rpc_local_pkey_dispatch = {
.set_attributes = pkey_local_set_attributes,
.get_attributes = pkey_local_get_attributes,
.export = pkey_local_export,
- .import = pkey_local_import
+ .import = pkey_local_import,
+ .export_raw = pkey_local_export_raw,
+ .import_raw = pkey_local_import_raw
};
/*