diff options
Diffstat (limited to 'rpc_pkey.c')
-rw-r--r-- | rpc_pkey.c | 104 |
1 files changed, 103 insertions, 1 deletions
@@ -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 }; /* |