diff options
-rw-r--r-- | platform/include/tfm_plat_crypto_keys.h | 14 | ||||
-rw-r--r-- | secure_fw/services/initial_attestation/attest_token.c | 12 | ||||
-rw-r--r-- | secure_fw/services/initial_attestation/attestation_key.c | 232 | ||||
-rw-r--r-- | secure_fw/services/initial_attestation/attestation_key.h | 17 |
4 files changed, 259 insertions, 16 deletions
diff --git a/platform/include/tfm_plat_crypto_keys.h b/platform/include/tfm_plat_crypto_keys.h index 82202f0ca2..7ee9570fc9 100644 --- a/platform/include/tfm_plat_crypto_keys.h +++ b/platform/include/tfm_plat_crypto_keys.h @@ -22,20 +22,6 @@ extern "C" { #endif /** - * Elliptic curve key type identifiers according to RFC8152 (COSE encoding) - * https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves - */ -enum cose_ecc_curve_t { - P_256 = 1, /* NIST P-256 also known as secp256r1 */ - P_384 = 2, /* NIST P-384 also known as secp384r1 */ - P_521 = 3, /* NIST P-521 also known as secp521r1 */ - X25519 = 4, /* X25519 for use with ECDH only */ - X448 = 5, /* X448 for use with ECDH only */ - ED25519 = 6, /* Ed25519 for use with EdDSA only */ - ED448 = 7, /* Ed448 for use with EdDSA only */ -}; - -/** * Structure definition to carry pointer and size information about an Elliptic * curve key which is stored in a buffer(key_buf) in raw format (without * encoding): diff --git a/secure_fw/services/initial_attestation/attest_token.c b/secure_fw/services/initial_attestation/attest_token.c index 78c0ee0fdf..4e582ae1fe 100644 --- a/secure_fw/services/initial_attestation/attest_token.c +++ b/secure_fw/services/initial_attestation/attest_token.c @@ -97,14 +97,24 @@ enum attest_token_err_t attest_token_start(struct attest_token_ctx *me, int32_t t_cose_options = 0; struct t_cose_key attest_key; psa_key_handle_t private_key; + struct q_useful_buf_c attest_key_id = NULL_Q_USEFUL_BUF_C; + /* Remember some of the configuration values */ me->opt_flags = opt_flags; me->key_select = key_select; +#ifdef INCLUDE_TEST_CODE_AND_KEY_ID if (opt_flags & TOKEN_OPT_SHORT_CIRCUIT_SIGN) { t_cose_options |= T_COSE_OPT_SHORT_CIRCUIT_SIG; + } else { + attest_ret = attest_get_initial_attestation_key_id(&attest_key_id); + if (attest_ret != PSA_ATTEST_ERR_SUCCESS) { + return ATTEST_TOKEN_ERR_GENERAL; + } } +#endif + t_cose_sign1_sign_init(&(me->signer_ctx), t_cose_options, cose_alg_id); attest_ret = @@ -117,7 +127,7 @@ enum attest_token_err_t attest_token_start(struct attest_token_ctx *me, t_cose_sign1_set_signing_key(&(me->signer_ctx), attest_key, - NULL_Q_USEFUL_BUF_C); /* No kid */ + attest_key_id); /* Spin up the CBOR encoder */ QCBOREncode_Init(&(me->cbor_enc_ctx), *out_buf); diff --git a/secure_fw/services/initial_attestation/attestation_key.c b/secure_fw/services/initial_attestation/attestation_key.c index 2dcab020cf..7dedd0b8f8 100644 --- a/secure_fw/services/initial_attestation/attestation_key.c +++ b/secure_fw/services/initial_attestation/attestation_key.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2019-2020, Arm Limited. All rights reserved. + * Copyright (c) 2018-2019, Laurence Lundblade. * * SPDX-License-Identifier: BSD-3-Clause * @@ -11,6 +12,9 @@ #include "psa/initial_attestation.h" #include "platform/include/tfm_plat_defs.h" #include "platform/include/tfm_plat_crypto_keys.h" +#include "t_cose_standard_constants.h" +#include "q_useful_buf.h" +#include "qcbor.h" #define ECC_P256_PUBLIC_KEY_SIZE PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(256) @@ -43,6 +47,10 @@ static uint8_t attestation_public_key[ECC_P256_PUBLIC_KEY_SIZE]; /* 65bytes */ static size_t attestation_public_key_len = 0; static psa_ecc_curve_t attestation_key_curve; +#ifdef INCLUDE_TEST_CODE_AND_KEY_ID +static uint8_t attestation_key_id[PSA_HASH_SIZE(PSA_ALG_SHA_256)]; /* 32bytes */ +#endif + enum psa_attest_err_t attest_register_initial_attestation_key() { @@ -161,3 +169,227 @@ attest_get_initial_attestation_public_key(uint8_t **public_key, return PSA_ATTEST_ERR_SUCCESS; } + + +#ifdef INCLUDE_TEST_CODE_AND_KEY_ID + +#define MAX_ENCODED_COSE_KEY_SIZE \ + 1 + /* 1 byte to encode map */ \ + 2 + /* 2 bytes to encode key type */ \ + 2 + /* 2 bytes to encode curve */ \ + 2 * /* the X and Y coordinates at 32 bytes each */ \ + (ECC_P256_COORD_SIZE + 1 + 2) + +/** + * \brief Map PSA curve types to the curve type defined by RFC 8152 + * chapter 13.1. + * + * \param[in] psa_curve PSA curve type definition \ref psa_ecc_curve_t. + * + * \return Return COSE curve type. If mapping is not possible then return + * with -1. + */ +static inline int32_t +attest_map_psa_ecc_curve_to_cose_ecc_curve(psa_ecc_curve_t psa_curve) +{ + int32_t cose_curve; + + /* Note: Mapping is not complete. */ + switch (psa_curve) { + case PSA_ECC_CURVE_SECP256R1: + cose_curve = COSE_ELLIPTIC_CURVE_P_256; + break; + default: + /* Initial attestation currently supports only ECDSA P256 signature + * therefore the other options are not mapped to save object code + */ + cose_curve = -1; + } + + return cose_curve; +} + +/** + * \brief CBOR encode a public key as a \c COSE_Key + * + * \param[in] psa_ecc_curve PSA elliptic curve identifiers + * \param[in] attest_public_key Pointer and length of the buffer, which + * holds the attestation public key encoded as + * defined by SEC1 §2.3.3. + * \param[in] buffer_for_cose_key Pointer and length of buffer into which + * the encoded \c COSE_Key is put. + * \param[out] cose_key Pointer and length of the encoded + * \c COSE_Key. + * + * \return This returns one of the error codes defined by \ref psa_attest_err_t. + * + * \c COSE_Key is the COSE-defined format for serializing a key for + * transmission in a protocol. This function encodes an EC public key + * expressed as an X and Y coordinate. + */ +static enum psa_attest_err_t +attest_encode_key_to_cose_key(psa_ecc_curve_t psa_ecc_curve, + struct q_useful_buf_c attest_public_key, + struct q_useful_buf buffer_for_cose_key, + struct q_useful_buf_c *cose_key) +{ + QCBORError qcbor_result; + QCBOREncodeContext cbor_encode_ctx; + struct q_useful_buf_c x_coord; + struct q_useful_buf_c y_coord; + struct q_useful_buf_c encoded_key_id; + size_t key_coord_len; + int32_t cose_ecc_curve; + uint8_t *x_coord_ptr; + uint8_t *y_coord_ptr; + Q_USEFUL_BUF_MAKE_STACK_UB(buffer_for_x_coord, ECC_P256_COORD_SIZE); + Q_USEFUL_BUF_MAKE_STACK_UB(buffer_for_y_coord, ECC_P256_COORD_SIZE); + + /* Key is made up of a 0x4 byte and two coordinates + * 0x04 || X_COORD || Y_COORD + */ + key_coord_len = (attest_public_key.len - 1) / 2; + x_coord_ptr = ((uint8_t *)attest_public_key.ptr) + 1; + y_coord_ptr = ((uint8_t *)attest_public_key.ptr) + 1 + key_coord_len; + + /* Place they key parts into the x and y buffers. Stars at index 1 to skip + * the 0x4 byte. + */ + x_coord = q_useful_buf_copy_ptr(buffer_for_x_coord, + x_coord_ptr, + key_coord_len); + + y_coord = q_useful_buf_copy_ptr(buffer_for_y_coord, + y_coord_ptr, + key_coord_len); + + if (q_useful_buf_c_is_null(x_coord) || q_useful_buf_c_is_null(y_coord)) { + return PSA_ATTEST_ERR_GENERAL; + } + + cose_ecc_curve = attest_map_psa_ecc_curve_to_cose_ecc_curve(psa_ecc_curve); + if (cose_ecc_curve == -1) { + return PSA_ATTEST_ERR_GENERAL; + } + + /* Encode it into a COSE_Key structure */ + QCBOREncode_Init(&cbor_encode_ctx, buffer_for_cose_key); + QCBOREncode_OpenMap(&cbor_encode_ctx); + QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx, + COSE_KEY_COMMON_KTY, + COSE_KEY_TYPE_EC2); + QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx, + COSE_KEY_PARAM_CRV, + cose_ecc_curve); + QCBOREncode_AddBytesToMapN(&cbor_encode_ctx, + COSE_KEY_PARAM_X_COORDINATE, + x_coord); + QCBOREncode_AddBytesToMapN(&cbor_encode_ctx, + COSE_KEY_PARAM_Y_COORDINATE, + y_coord); + QCBOREncode_CloseMap(&cbor_encode_ctx); + + qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &encoded_key_id); + if (qcbor_result != QCBOR_SUCCESS) { + /* Mainly means that the COSE_Key was too big for buffer_for_cose_key */ + return PSA_ATTEST_ERR_GENERAL; + } + + /* Finish up and return */ + *cose_key = encoded_key_id; + + return PSA_ATTEST_ERR_SUCCESS; +} + +/** + * \brief Make a key ID based on the public key to go in the kid + * unprotected header. + * + * \param[in] psa_ecc_curve PSA elliptic curve identifiers. + * \param[in] attest_public_key Pointer and length of the buffer, which + * holds the attestation public key + * encoded as defined by SEC1 §2.3.3. + * \param[in] buffer_for_attest_key_id Pointer and length of buffer into which + * the encoded \c COSE_Key is put. + * \param[out] attest_key_id Pointer and length of the attestation + * key id. + * + * \return This returns one of the error codes defined by \ref psa_attest_err_t. + */ +enum psa_attest_err_t +attest_get_cose_key_id(psa_ecc_curve_t psa_ecc_curve, + struct q_useful_buf_c attest_public_key, + struct q_useful_buf buffer_for_attest_key_id, + struct q_useful_buf_c *attest_key_id) +{ + enum psa_attest_err_t attest_res; + psa_status_t crypto_res; + struct q_useful_buf_c cose_key; + psa_hash_operation_t hash = psa_hash_operation_init(); + Q_USEFUL_BUF_MAKE_STACK_UB(buffer_for_cose_key, MAX_ENCODED_COSE_KEY_SIZE); + + /* Encode the attestation public key to COSE_Key structure */ + attest_res = attest_encode_key_to_cose_key(psa_ecc_curve, + attest_public_key, + buffer_for_cose_key, + &cose_key); + if(attest_res != PSA_ATTEST_ERR_SUCCESS) { + return attest_res; + } + + crypto_res = psa_hash_setup(&hash, PSA_ALG_SHA_256); + if (crypto_res != PSA_SUCCESS) { + return PSA_ATTEST_ERR_GENERAL; + } + + crypto_res = psa_hash_update(&hash, cose_key.ptr, cose_key.len); + if (crypto_res != PSA_SUCCESS) { + return PSA_ATTEST_ERR_GENERAL; + } + + crypto_res = psa_hash_finish(&hash, + buffer_for_attest_key_id.ptr, + buffer_for_attest_key_id.len, + &buffer_for_attest_key_id.len); + if (crypto_res != PSA_SUCCESS) { + return PSA_ATTEST_ERR_GENERAL; + } + + attest_key_id->ptr = buffer_for_attest_key_id.ptr; + attest_key_id->len = buffer_for_attest_key_id.len; + + return PSA_ATTEST_ERR_SUCCESS; +} + +enum psa_attest_err_t +attest_get_initial_attestation_key_id(struct q_useful_buf_c *attest_key_id) +{ + enum psa_attest_err_t attest_res; + static uint8_t attest_key_id_calculated; + struct q_useful_buf_c buffer_for_attest_public_key; + struct q_useful_buf buffer_for_attest_key_id; + + buffer_for_attest_key_id.ptr = attestation_key_id; + buffer_for_attest_key_id.len = PSA_HASH_SIZE(PSA_ALG_SHA_256); + + /* Needs to calculate only once */ + if (attest_key_id_calculated == 0) { + buffer_for_attest_public_key.ptr = attestation_public_key; + buffer_for_attest_public_key.len = attestation_public_key_len; + + attest_res = attest_get_cose_key_id(attestation_key_curve, + buffer_for_attest_public_key, + buffer_for_attest_key_id, + attest_key_id); + if (attest_res != PSA_ATTEST_ERR_SUCCESS) { + return attest_res; + } + attest_key_id_calculated = 1; + } else { + attest_key_id->ptr = (const void *)buffer_for_attest_key_id.ptr; + attest_key_id->len = buffer_for_attest_key_id.len; + } + + return PSA_ATTEST_ERR_SUCCESS; +} +#endif diff --git a/secure_fw/services/initial_attestation/attestation_key.h b/secure_fw/services/initial_attestation/attestation_key.h index c1b7b3c393..cb35a94d81 100644 --- a/secure_fw/services/initial_attestation/attestation_key.h +++ b/secure_fw/services/initial_attestation/attestation_key.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Arm Limited. All rights reserved. + * Copyright (c) 2019-2020, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * @@ -10,6 +10,7 @@ #include "psa/initial_attestation.h" #include "psa/crypto.h" +#include "q_useful_buf.h" #ifdef __cplusplus extern "C" { @@ -66,6 +67,20 @@ enum psa_attest_err_t attest_get_initial_attestation_public_key(uint8_t **public_key, size_t *public_key_len, psa_ecc_curve_t *public_key_curve); + +/** + * \brief Get the attestation key ID. It is the hash (SHA256) of the COSE_Key + * encoded attestation public key. + * + * \param[out] attest_key_id Pointer and length of the key id. + * + * \retval PSA_ATTEST_ERR_SUCCESS Key id calculated successfully. + * \retval PSA_ATTEST_ERR_GENERAL Key id calculation failed. + + */ +enum psa_attest_err_t +attest_get_initial_attestation_key_id(struct q_useful_buf_c *attest_key_id); + #ifdef __cplusplus } #endif |