diff --git a/crypto_adapters/t_cose_openssl_crypto.c b/crypto_adapters/t_cose_openssl_crypto.c index 48828cbe..926e04d3 100644 --- a/crypto_adapters/t_cose_openssl_crypto.c +++ b/crypto_adapters/t_cose_openssl_crypto.c @@ -1052,7 +1052,7 @@ t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx, * See documentation in t_cose_crypto.h */ enum t_cose_err_t -t_cose_crypto_hmac_compute_setup(struct t_cose_crypto_hmac *hmac_ctx, +t_cose_crypto_hmac_setup(struct t_cose_crypto_hmac *hmac_ctx, struct t_cose_key signing_key, const int32_t cose_alg_id) { @@ -1104,6 +1104,8 @@ t_cose_crypto_hmac_compute_setup(struct t_cose_crypto_hmac *hmac_ctx, return T_COSE_ERR_HMAC_GENERAL_FAIL; } + hmac_ctx->update_error = 1; /* 1 is success in OpenSSL */ + return T_COSE_SUCCESS; } @@ -1111,39 +1113,42 @@ t_cose_crypto_hmac_compute_setup(struct t_cose_crypto_hmac *hmac_ctx, /* * See documentation in t_cose_crypto.h */ -enum t_cose_err_t +void t_cose_crypto_hmac_update(struct t_cose_crypto_hmac *hmac_ctx, struct q_useful_buf_c payload) { - int ossl_result; - - ossl_result = EVP_DigestSignUpdate(hmac_ctx->evp_ctx, payload.ptr, payload.len); - if(ossl_result != 1) { - return T_COSE_ERR_HMAC_GENERAL_FAIL; + if(hmac_ctx->update_error) { /* 1 is no error, 0 means error for OpenSSL */ + if(payload.ptr) { + hmac_ctx->update_error = EVP_DigestSignUpdate(hmac_ctx->evp_ctx, + payload.ptr, + payload.len); + } } - - return T_COSE_SUCCESS; } + /* * See documentation in t_cose_crypto.h */ enum t_cose_err_t -t_cose_crypto_hmac_compute_finish(struct t_cose_crypto_hmac *hmac_ctx, +t_cose_crypto_hmac_finish(struct t_cose_crypto_hmac *hmac_ctx, struct q_useful_buf tag_buf, struct q_useful_buf_c *tag) { - int ossl_result; size_t in_out_len; in_out_len = tag_buf.len; - ossl_result = EVP_DigestSignFinal(hmac_ctx->evp_ctx, tag_buf.ptr, &in_out_len); + if(hmac_ctx->update_error) { + hmac_ctx->update_error = EVP_DigestSignFinal(hmac_ctx->evp_ctx, + tag_buf.ptr, + &in_out_len); + } EVP_MD_CTX_free(hmac_ctx->evp_ctx); EVP_PKEY_free(hmac_ctx->evp_pkey); - if(ossl_result != 1) { + if(hmac_ctx->update_error != 1) { return T_COSE_ERR_HMAC_GENERAL_FAIL; } @@ -1154,43 +1159,6 @@ t_cose_crypto_hmac_compute_finish(struct t_cose_crypto_hmac *hmac_ctx, } -/* - * See documentation in t_cose_crypto.h - */ -// TODO: argument order alignment with t_cose_crypto_hmac_compute_setup -enum t_cose_err_t -t_cose_crypto_hmac_validate_setup(struct t_cose_crypto_hmac *hmac_ctx, - const int32_t cose_alg_id, - struct t_cose_key validation_key) -{ - return t_cose_crypto_hmac_compute_setup(hmac_ctx, validation_key, cose_alg_id); -} - - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_hmac_validate_finish(struct t_cose_crypto_hmac *hmac_ctx, - struct q_useful_buf_c input_tag) -{ - Q_USEFUL_BUF_MAKE_STACK_UB( tag_buf, T_COSE_CRYPTO_HMAC_TAG_MAX_SIZE); - struct q_useful_buf_c computed_tag; - enum t_cose_err_t result; - - result = t_cose_crypto_hmac_compute_finish(hmac_ctx, tag_buf, &computed_tag); - if(result != T_COSE_SUCCESS) { - return result; - } - - if(q_useful_buf_compare(computed_tag, input_tag)) { - return T_COSE_ERR_HMAC_VERIFY; - } - - return T_COSE_SUCCESS; -} - - /* * See documentation in t_cose_crypto.h */ diff --git a/crypto_adapters/t_cose_psa_crypto.c b/crypto_adapters/t_cose_psa_crypto.c index 16151c65..3c1a363d 100644 --- a/crypto_adapters/t_cose_psa_crypto.c +++ b/crypto_adapters/t_cose_psa_crypto.c @@ -552,12 +552,12 @@ psa_status_to_t_cose_error_hmac(psa_status_t status) * See documentation in t_cose_crypto.h */ enum t_cose_err_t -t_cose_crypto_hmac_compute_setup(struct t_cose_crypto_hmac *hmac_ctx, - struct t_cose_key signing_key, - const int32_t cose_alg_id) +t_cose_crypto_hmac_setup(struct t_cose_crypto_hmac *hmac_ctx, + struct t_cose_key signing_key, + const int32_t cose_alg_id) { psa_algorithm_t psa_alg; - psa_status_t psa_ret; + psa_status_t psa_ret; /* Map the algorithm ID */ psa_alg = cose_hmac_alg_id_to_psa(cose_alg_id); @@ -582,103 +582,61 @@ t_cose_crypto_hmac_compute_setup(struct t_cose_crypto_hmac *hmac_ctx, (psa_key_id_t)signing_key.key.handle, psa_alg); + hmac_ctx->status = PSA_SUCCESS; + return psa_status_to_t_cose_error_hmac(psa_ret); } + /* * See documentation in t_cose_crypto.h */ -enum t_cose_err_t +void t_cose_crypto_hmac_update(struct t_cose_crypto_hmac *hmac_ctx, struct q_useful_buf_c payload) { - psa_status_t psa_ret; - - psa_ret = psa_mac_update(&hmac_ctx->op_ctx, - payload.ptr, payload.len); - - return psa_status_to_t_cose_error_hmac(psa_ret); -} - -/* - * See documentation in t_cose_crypto.h - */ -enum t_cose_err_t -t_cose_crypto_hmac_compute_finish(struct t_cose_crypto_hmac *hmac_ctx, - struct q_useful_buf tag_buf, - struct q_useful_buf_c *tag) -{ - psa_status_t psa_ret; - - psa_ret = psa_mac_sign_finish(&hmac_ctx->op_ctx, - tag_buf.ptr, tag_buf.len, - &(tag->len)); - if(psa_ret == PSA_SUCCESS) { - tag->ptr = tag_buf.ptr; + if(hmac_ctx->status != PSA_SUCCESS) { + /* In error state. Nothing to do. */ + return; } - return psa_status_to_t_cose_error_hmac(psa_ret); + hmac_ctx->status = psa_mac_update(&hmac_ctx->op_ctx, + payload.ptr, + payload.len); } + /* * See documentation in t_cose_crypto.h */ enum t_cose_err_t -t_cose_crypto_hmac_validate_setup(struct t_cose_crypto_hmac *hmac_ctx, - const int32_t cose_alg_id, - struct t_cose_key validation_key) +t_cose_crypto_hmac_finish(struct t_cose_crypto_hmac *hmac_ctx, + struct q_useful_buf tag_buf, + struct q_useful_buf_c *tag) { - psa_algorithm_t psa_alg; - psa_status_t psa_ret; - - if(!hmac_ctx) { - return T_COSE_ERR_INVALID_ARGUMENT; - } - - /* Map the algorithm ID */ - psa_alg = cose_hmac_alg_id_to_psa(cose_alg_id); - if(!PSA_ALG_IS_MAC(psa_alg)) { - return T_COSE_ERR_UNSUPPORTED_HMAC_ALG; - } - - /* - * Verify if HMAC algorithm is valid. - * According to COSE (RFC 9053), only SHA-256, SHA-384 and SHA-512 are - * supported in HMAC. - */ - if((psa_alg != PSA_ALG_HMAC(PSA_ALG_SHA_256)) && - (psa_alg != PSA_ALG_HMAC(PSA_ALG_SHA_384)) && - (psa_alg != PSA_ALG_HMAC(PSA_ALG_SHA_512))) { - return T_COSE_ERR_UNSUPPORTED_HMAC_ALG; + if(hmac_ctx->status != PSA_SUCCESS) { + /* Error state. Nothing to do */ + goto done; } - hmac_ctx->op_ctx = psa_mac_operation_init(); + hmac_ctx->status = psa_mac_sign_finish(&hmac_ctx->op_ctx, + tag_buf.ptr, + tag_buf.len, + &(tag->len)); + tag->ptr = tag_buf.ptr; - psa_ret = psa_mac_verify_setup(&hmac_ctx->op_ctx, - (psa_key_id_t)validation_key.key.handle, - psa_alg); - - return psa_status_to_t_cose_error_hmac(psa_ret); +done: + return psa_status_to_t_cose_error_hmac(hmac_ctx->status); } -/* - * See documentation in t_cose_crypto.h +/* The PSA API for MAC validation is not used because it results + * in larger code size overall and because OSSL doesn't have that + * API. There is no issue with a crypto service API that isolates + * the MAC key in an HSM or such by making this choice. It is still + * possible to to do. The MAC tag is a public value so it doesn't + * need to in the HSM. */ -enum t_cose_err_t -t_cose_crypto_hmac_validate_finish(struct t_cose_crypto_hmac *hmac_ctx, - struct q_useful_buf_c tag) -{ - psa_status_t psa_ret; - - if(!hmac_ctx) { - return T_COSE_ERR_INVALID_ARGUMENT; - } - - psa_ret = psa_mac_verify_finish(&hmac_ctx->op_ctx, tag.ptr, tag.len); - - return psa_status_to_t_cose_error_hmac(psa_ret); -} enum t_cose_err_t diff --git a/crypto_adapters/t_cose_test_crypto.c b/crypto_adapters/t_cose_test_crypto.c index e1248b29..4a396728 100644 --- a/crypto_adapters/t_cose_test_crypto.c +++ b/crypto_adapters/t_cose_test_crypto.c @@ -301,9 +301,9 @@ t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx, enum t_cose_err_t -t_cose_crypto_hmac_compute_setup(struct t_cose_crypto_hmac *hmac_ctx, - struct t_cose_key signing_key, - const int32_t cose_alg_id) +t_cose_crypto_hmac_setup(struct t_cose_crypto_hmac *hmac_ctx, + struct t_cose_key signing_key, + const int32_t cose_alg_id) { (void)hmac_ctx; (void)signing_key; @@ -311,19 +311,18 @@ t_cose_crypto_hmac_compute_setup(struct t_cose_crypto_hmac *hmac_ctx, return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; } -enum t_cose_err_t +void t_cose_crypto_hmac_update(struct t_cose_crypto_hmac *hmac_ctx, struct q_useful_buf_c payload) { (void)hmac_ctx; (void)payload; - return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; } enum t_cose_err_t -t_cose_crypto_hmac_compute_finish(struct t_cose_crypto_hmac *hmac_ctx, - struct q_useful_buf tag_buf, - struct q_useful_buf_c *tag) +t_cose_crypto_hmac_finish(struct t_cose_crypto_hmac *hmac_ctx, + struct q_useful_buf tag_buf, + struct q_useful_buf_c *tag) { (void)hmac_ctx; (void)tag_buf; @@ -331,27 +330,6 @@ t_cose_crypto_hmac_compute_finish(struct t_cose_crypto_hmac *hmac_ctx, return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; } -enum t_cose_err_t -t_cose_crypto_hmac_validate_setup(struct t_cose_crypto_hmac *hmac_ctx, - const int32_t cose_alg_id, - struct t_cose_key validation_key) -{ - (void)hmac_ctx; - (void)cose_alg_id; - (void)validation_key; - return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; -} - -enum t_cose_err_t -t_cose_crypto_hmac_validate_finish(struct t_cose_crypto_hmac *hmac_ctx, - struct q_useful_buf_c tag) -{ - (void)hmac_ctx; - (void)tag; - return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG; -} - - /* * See documentation in t_cose_crypto.h diff --git a/inc/t_cose/t_cose_common.h b/inc/t_cose/t_cose_common.h index cacbf46a..9187f109 100644 --- a/inc/t_cose/t_cose_common.h +++ b/inc/t_cose/t_cose_common.h @@ -250,20 +250,6 @@ enum t_cose_key_usage_flags { }; - -/* Private value. Intentionally not documented for Doxygen. - * This is the size allocated for the encoded protected headers. It - * needs to be big enough for make_protected_header() to succeed. It - * currently sized for one header with an algorithm ID up to 32 bits - * long -- one byte for the wrapping map, one byte for the label, 5 - * bytes for the ID. If this is made accidentially too small, QCBOR will - * only return an error, and not overrun any buffers. - * - * 9 extra bytes are added, rounding it up to 16 total, in case some - * other protected header is to be added. - */ -#define T_COSE_MAC0_MAX_SIZE_PROTECTED_PARAMETERS (1 + 1 + 5 + 9) - /* Six: an alg id, a kid, an iv, a content type, one custom, crit list * or: 2 alg IDs, an IV, a kid, a supp_pub_info, one custom. If * this is not enough use t_cose_encrypt_add_param_storage() or diff --git a/inc/t_cose/t_cose_mac_compute.h b/inc/t_cose/t_cose_mac_compute.h index 51b7b85b..8b4ca86b 100644 --- a/inc/t_cose/t_cose_mac_compute.h +++ b/inc/t_cose/t_cose_mac_compute.h @@ -23,12 +23,10 @@ extern "C" { /** * This is the context for creating a \c COSE_Mac structure. The caller * should allocate it and pass it to the functions here. This is - * about 32 bytes so it fits easily on the stack. + * about 72 bytes so it fits easily on the stack. */ struct t_cose_mac_calculate_ctx { /* Private data structure */ - uint8_t protected_parameters_buffer[ - T_COSE_MAC0_MAX_SIZE_PROTECTED_PARAMETERS]; struct q_useful_buf_c protected_parameters; /* The encoded protected parameters */ int32_t cose_algorithm_id; struct t_cose_key mac_key; diff --git a/inc/t_cose/t_cose_standard_constants.h b/inc/t_cose/t_cose_standard_constants.h index 65b2f995..789cf9a6 100644 --- a/inc/t_cose/t_cose_standard_constants.h +++ b/inc/t_cose/t_cose_standard_constants.h @@ -742,4 +742,6 @@ */ #define COSE_MAC_CONTEXT_STRING_MAC0 "MAC0" +#define COSE_MAC_CONTEXT_STRING_MAC "MAC" + #endif /* __T_COSE_STANDARD_CONSTANTS_H__ */ diff --git a/src/t_cose_crypto.h b/src/t_cose_crypto.h index 944df741..98e2e7f9 100644 --- a/src/t_cose_crypto.h +++ b/src/t_cose_crypto.h @@ -551,11 +551,14 @@ struct t_cose_crypto_hmac { #ifdef T_COSE_USE_PSA_CRYPTO /* --- The context for PSA Crypto (MBed Crypto) --- */ psa_mac_operation_t op_ctx; + psa_status_t status; #elif T_COSE_USE_OPENSSL_CRYPTO /* --- The context for OpenSSL crypto --- */ EVP_MD_CTX *evp_ctx; EVP_PKEY *evp_pkey; + int update_error; /* Used to track error return by SHAXXX_Update() */ + #else /* --- Default: generic pointer / handle --- */ @@ -714,9 +717,9 @@ t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx, * Some general failure of the HMAC function. */ enum t_cose_err_t -t_cose_crypto_hmac_compute_setup(struct t_cose_crypto_hmac *hmac_ctx, - struct t_cose_key signing_key, - const int32_t cose_alg_id); +t_cose_crypto_hmac_setup(struct t_cose_crypto_hmac *hmac_ctx, + struct t_cose_key signing_key, + const int32_t cose_alg_id); /** * \brief Add a message fragment to a multipart HMAC operation. @@ -733,7 +736,7 @@ t_cose_crypto_hmac_compute_setup(struct t_cose_crypto_hmac *hmac_ctx, * \retval T_COSE_ERR_FAIL * Some general failure of the HMAC function. */ -enum t_cose_err_t +void t_cose_crypto_hmac_update(struct t_cose_crypto_hmac *hmac_ctx, struct q_useful_buf_c payload); @@ -756,52 +759,9 @@ t_cose_crypto_hmac_update(struct t_cose_crypto_hmac *hmac_ctx, * Some general failure of the HMAC function. */ enum t_cose_err_t -t_cose_crypto_hmac_compute_finish(struct t_cose_crypto_hmac *hmac_ctx, - struct q_useful_buf tag_buf, - struct q_useful_buf_c *tag); - -/** - * \brief Set up a multipart HMAC validation operation. - * - * \param[in,out] hmac_ctx Pointer to the HMAC context. - * \param[in] cose_alg_id The algorithm used in HMAC. - * \param[in] validation_key Key for HMAC validation. - * - * \retval T_COSE_SUCCESS - * Operation succeeds. - * \retval T_COSE_ERR_UNSUPPORTED_SIGNING_ALG - * The algorithm is unsupported. - * \retval T_COSE_ERR_INVALID_ARGUMENT - * Invalid arguments. - * \retval T_COSE_ERR_FAIL - * Some general failure of the HMAC function. - */ -enum t_cose_err_t -t_cose_crypto_hmac_validate_setup(struct t_cose_crypto_hmac *hmac_ctx, - const int32_t cose_alg_id, - struct t_cose_key validation_key); - -/** - * \brief Finish the validation of the HMAC of a message. - * - * \param[in,out] hmac_ctx Pointer to the HMAC context. - * \param[in] tag Pointer and length of the tag. - * - * \retval T_COSE_SUCCESS - * Tag calculation succeeds. - * \retval T_COSE_ERR_INVALID_ARGUMENT - * Invalid arguments. - * \retval T_COSE_ERR_FAIL - * Some general failure of the HMAC function. - * \retval PSA_ERROR_INVALID_SIGNATURE - * HMAC validation failed. - */ -enum t_cose_err_t -t_cose_crypto_hmac_validate_finish(struct t_cose_crypto_hmac *hmac_ctx, - struct q_useful_buf_c tag); - - - +t_cose_crypto_hmac_finish(struct t_cose_crypto_hmac *hmac_ctx, + struct q_useful_buf tag_buf, + struct q_useful_buf_c *tag); // TODO: rename this to have hmac in its name diff --git a/src/t_cose_mac_compute.c b/src/t_cose_mac_compute.c index 1c61c298..827015c0 100644 --- a/src/t_cose_mac_compute.c +++ b/src/t_cose_mac_compute.c @@ -87,16 +87,9 @@ t_cose_mac_encode_tag(struct t_cose_mac_calculate_ctx *me, { enum t_cose_err_t return_value; QCBORError cbor_err; - /* Pointer and length of the completed tag */ - struct q_useful_buf_c tag; - /* Buffer for the actual tag */ - Q_USEFUL_BUF_MAKE_STACK_UB( tag_buf, + struct q_useful_buf_c computed_mac_tag; + Q_USEFUL_BUF_MAKE_STACK_UB( mac_tag_buf, T_COSE_CRYPTO_HMAC_TAG_MAX_SIZE); - struct q_useful_buf_c tbm_first_part; - /* Buffer for the ToBeMaced */ - Q_USEFUL_BUF_MAKE_STACK_UB( tbm_first_part_buf, - T_COSE_SIZE_OF_TBM); - struct t_cose_crypto_hmac hmac_ctx; struct t_cose_sign_inputs mac_input; /* @@ -116,9 +109,8 @@ t_cose_mac_encode_tag(struct t_cose_mac_calculate_ctx *me, if(QCBOREncode_IsBufferNULL(cbor_encode_ctx)) { /* Just calculating sizes. All that is needed is the tag size. */ - tag.ptr = NULL; - tag.len = t_cose_tag_size(me->cose_algorithm_id); - + computed_mac_tag.ptr = NULL; + computed_mac_tag.len = t_cose_tag_size(me->cose_algorithm_id); return_value = T_COSE_SUCCESS; goto CloseArray; } @@ -132,50 +124,20 @@ t_cose_mac_encode_tag(struct t_cose_mac_calculate_ctx *me, mac_input.payload = payload; mac_input.body_protected = me->protected_parameters; mac_input.sign_protected = NULL_Q_USEFUL_BUF_C; /* Never sign-protected for MAC */ - return_value = create_tbm(&mac_input, - tbm_first_part_buf, - &tbm_first_part); - if(return_value) { - goto Done; - } - - /* - * Start the HMAC. - * Calculate the tag of the first part of ToBeMaced and the wrapped - * payload, to save a bigger buffer containing the entire ToBeMaced. - */ - return_value = t_cose_crypto_hmac_compute_setup(&hmac_ctx, - me->mac_key, - me->cose_algorithm_id); - if(return_value) { - goto Done; - } - - /* Compute the tag of the first part. */ - return_value = t_cose_crypto_hmac_update(&hmac_ctx, - q_useful_buf_head(tbm_first_part, - tbm_first_part.len)); - if(return_value) { - goto Done; - } - - /* - * It is assumed that the context payload has been wrapped in a byte - * string in CBOR format. - */ - return_value = t_cose_crypto_hmac_update(&hmac_ctx, payload); - if(return_value) { - goto Done; - } - return_value = t_cose_crypto_hmac_compute_finish(&hmac_ctx, tag_buf, &tag); + return_value = create_tbm(me->cose_algorithm_id, /* in: algorithm ID*/ + me->mac_key, /* in: key */ + true, /* in: is_mac0 (MAC vs MAC0) */ + &mac_input, /* in: struct of all TBM inputs */ + mac_tag_buf, /* in: buffer to output to */ + &computed_mac_tag); /* out: the computed MAC tag */ if(return_value) { goto Done; } CloseArray: /* Add tag to CBOR and close out the array */ - QCBOREncode_AddBytes(cbor_encode_ctx, tag); + QCBOREncode_AddBytes(cbor_encode_ctx, computed_mac_tag); QCBOREncode_CloseArray(cbor_encode_ctx); /* CBOR encoding errors are tracked in the CBOR encoding context diff --git a/src/t_cose_mac_validate.c b/src/t_cose_mac_validate.c index e146fc9a..1805bb1b 100644 --- a/src/t_cose_mac_validate.c +++ b/src/t_cose_mac_validate.c @@ -37,24 +37,20 @@ t_cose_mac_validate_private(struct t_cose_mac_validate_ctx *me, QCBORDecodeContext decode_context; struct q_useful_buf_c protected_parameters; QCBORError qcbor_error; - enum t_cose_err_t return_value; - struct q_useful_buf_c tag = NULL_Q_USEFUL_BUF_C; - struct q_useful_buf_c tbm_first_part; - /* Buffer for the ToBeMaced */ - Q_USEFUL_BUF_MAKE_STACK_UB( tbm_first_part_buf, - T_COSE_SIZE_OF_TBM); - struct t_cose_crypto_hmac hmac_ctx; + struct q_useful_buf_c expected_mac_tag; + struct q_useful_buf_c computed_mac_tag; struct t_cose_parameter *decoded_params; struct t_cose_sign_inputs mac_input; QCBORItem item; uint64_t message_type; + Q_USEFUL_BUF_MAKE_STACK_UB( mac_tag_buf, T_COSE_CRYPTO_HMAC_TAG_MAX_SIZE); decoded_params = NULL; QCBORDecode_Init(&decode_context, cose_mac, QCBOR_DECODE_MODE_NORMAL); - /* --- The array of 4 and type determination and tags --- */ + /* --- The array of 4, type determination and tags --- */ QCBORDecode_EnterArray(&decode_context, &item); return_value = qcbor_decode_error_to_t_cose_error( QCBORDecode_GetError(&decode_context), @@ -63,7 +59,8 @@ t_cose_mac_validate_private(struct t_cose_mac_validate_ctx *me, goto Done; } - const uint64_t mac_tag_nums[] = {T_COSE_OPT_MESSAGE_TYPE_MAC0, CBOR_TAG_INVALID64}; + const uint64_t mac_tag_nums[] = {T_COSE_OPT_MESSAGE_TYPE_MAC0, + CBOR_TAG_INVALID64}; return_value = t_cose_tags_and_type(mac_tag_nums, me->option_flags, &item, @@ -75,7 +72,7 @@ t_cose_mac_validate_private(struct t_cose_mac_validate_ctx *me, } - /* --- The protected parameters --- */ + /* --- The parameters --- */ const struct t_cose_header_location l = {0,0}; decoded_params = NULL; return_value = t_cose_headers_decode(&decode_context, @@ -86,6 +83,7 @@ t_cose_mac_validate_private(struct t_cose_mac_validate_ctx *me, &decoded_params, &protected_parameters); + if(return_value != T_COSE_SUCCESS) { goto Done; } @@ -99,12 +97,12 @@ t_cose_mac_validate_private(struct t_cose_mac_validate_ctx *me, } /* --- The HMAC tag --- */ - QCBORDecode_GetByteString(&decode_context, &tag); + QCBORDecode_GetByteString(&decode_context, &expected_mac_tag); /* --- Finish up the CBOR decode --- */ QCBORDecode_ExitArray(&decode_context); - /* This check make sure the array only had the expected four + /* This check makes sure the array only had the expected four * items. It works for definite and indefinte length arrays. Also * makes sure there were no extra bytes. Also that the payload * and authentication tag were decoded correctly. */ @@ -132,48 +130,27 @@ t_cose_mac_validate_private(struct t_cose_mac_validate_ctx *me, goto Done; } - /* -- Compute the ToBeMaced -- */ + /* -- Compute the ToBeMaced and compare -- */ mac_input.ext_sup_data = ext_sup_data; mac_input.payload = *payload; mac_input.body_protected = protected_parameters; - mac_input.sign_protected = NULL_Q_USEFUL_BUF_C; /* Never sign-protected for MAC */ - return_value = create_tbm(&mac_input, - tbm_first_part_buf, - &tbm_first_part); - if(return_value) { - goto Done; - } - - /* - * Start the HMAC validation. - * Calculate the tag of the first part of ToBeMaced and the wrapped - * payload, to save a bigger buffer containing the entire ToBeMaced. - */ - return_value = t_cose_crypto_hmac_validate_setup(&hmac_ctx, - t_cose_param_find_alg_id_prot(decoded_params), - me->validation_key); - + mac_input.sign_protected = NULL_Q_USEFUL_BUF_C; /* No sign-protected for MAC */ + + return_value = create_tbm(t_cose_param_find_alg_id_prot(decoded_params), + me->validation_key,/* in: the key */ + true, /* in: is_mac0 (MAC vs MAC0) */ + &mac_input, /* in: struct of all TBM inputs */ + mac_tag_buf, /* in: buffer to output to */ + &computed_mac_tag); /* out: the computed MAC tag */ if(return_value) { goto Done; } - /* Compute the tag of the first part. */ - return_value = t_cose_crypto_hmac_update(&hmac_ctx, - q_useful_buf_head(tbm_first_part, - tbm_first_part.len)); - if(return_value) { + if(q_useful_buf_compare(computed_mac_tag, expected_mac_tag)) { + return_value = T_COSE_ERR_HMAC_VERIFY; goto Done; } - return_value = t_cose_crypto_hmac_update(&hmac_ctx, *payload); - if(return_value) { - goto Done; - } - - return_value = t_cose_crypto_hmac_validate_finish(&hmac_ctx, tag); - if(return_value != T_COSE_SUCCESS) { - goto Done; - } /* --- Check for critical parameters --- */ if(!(me->option_flags & T_COSE_OPT_NO_CRIT_PARAM_CHECK)) { diff --git a/src/t_cose_util.c b/src/t_cose_util.c index a1bacfe8..3b0729d9 100644 --- a/src/t_cose_util.c +++ b/src/t_cose_util.c @@ -276,45 +276,80 @@ bits_iv_alg(int32_t cose_algorithm_id) - -// TODO: try to combine with create_tbs_hash so that no buffer for headers -// is needed. Make sure it doesn't make sign-only or mac-only object code big -enum t_cose_err_t -create_tbm(const struct t_cose_sign_inputs *mac_inputs, - struct q_useful_buf tbm_first_part_buf, - struct q_useful_buf_c *tbm_first_part) +/** + * \brief HMAC an encoded bstr without actually encoding it in memory. + * + * @param hmac_ctx HMAC context. + * @param bstr Bytes of the bstr. + * + * If \c bstr is \c NULL_Q_USEFUL_BUF_C, a zero-length bstr will be + * HMAC'd into the output. + */ +static void +hmac_bstr(struct t_cose_crypto_hmac *hmac_ctx, + struct q_useful_buf_c bstr) { - QCBOREncodeContext cbor_encode_ctx; - QCBORError qcbor_result; + Q_USEFUL_BUF_MAKE_STACK_UB (buffer_for_encoded_head, QCBOR_HEAD_BUFFER_SIZE); + struct q_useful_buf_c encoded_head; - /* This builds the CBOR-format to-be-maced bytes */ - QCBOREncode_Init(&cbor_encode_ctx, tbm_first_part_buf); - QCBOREncode_OpenArray(&cbor_encode_ctx); - /* context */ - QCBOREncode_AddText(&cbor_encode_ctx, Q_USEFUL_BUF_FROM_SZ_LITERAL(COSE_MAC_CONTEXT_STRING_MAC0)); + encoded_head = QCBOREncode_EncodeHead(buffer_for_encoded_head, + CBOR_MAJOR_TYPE_BYTE_STRING, + 0, + bstr.len); - /* body_protected */ - QCBOREncode_AddBytes(&cbor_encode_ctx, mac_inputs->body_protected); + /* An encoded bstr is the CBOR head with its length followed by the bytes */ + t_cose_crypto_hmac_update(hmac_ctx, encoded_head); + t_cose_crypto_hmac_update(hmac_ctx, bstr); +} - /* ext_sup_data */ - QCBOREncode_AddBytes(&cbor_encode_ctx, mac_inputs->ext_sup_data); +/* Tried combing the above with hash_bstr. It accepted a function + * pointer for the hash/hmac function. The object code with this was + * slightly smaller with GCC and substantially larger with + * clang/llvm. It was cool, but using the two functions for simplicity + * and substantially smaller clang/llvm code size. + */ - /* The short fake payload, ext_sup_data only the byte string type and length */ - QCBOREncode_AddBytesLenOnly(&cbor_encode_ctx, mac_inputs->payload); - /* Close of the array */ - QCBOREncode_CloseArray(&cbor_encode_ctx); +/* + * Public function. See t_cose_util.h + */ +enum t_cose_err_t +create_tbm(const int32_t cose_alg_id, + struct t_cose_key mac_key, + bool is_mac0, + const struct t_cose_sign_inputs *mac_inputs, + const struct q_useful_buf tag_buf, + struct q_useful_buf_c *mac_tag) +{ + enum t_cose_err_t return_value; + struct t_cose_crypto_hmac hmac_ctx; + struct q_useful_buf_c first_part; - /* get the encoded results, except for payload */ - qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, tbm_first_part); - if(qcbor_result) { - /* Mainly means that the protected_headers were too big - * (which should never happen) - */ - return T_COSE_ERR_SIG_STRUCT; + return_value = t_cose_crypto_hmac_setup(&hmac_ctx, + mac_key, + cose_alg_id); + if(return_value) { + return return_value; } - return T_COSE_SUCCESS; + /* Same approach as hash_bstr(). See comments in hash_bstr() */ + + if(is_mac0) { + /* 0x84 is array of 4, 0x64 is length of a 4 text string in CBOR */ + first_part = Q_USEFUL_BUF_FROM_SZ_LITERAL("\x84\x64" COSE_MAC_CONTEXT_STRING_MAC0); + } else { + /* 0x84 is array of 4, 0x63 is length of a 3 text string in CBOR */ + first_part = Q_USEFUL_BUF_FROM_SZ_LITERAL("\x84\x63" COSE_MAC_CONTEXT_STRING_MAC); + } + t_cose_crypto_hmac_update(&hmac_ctx, first_part); + + hmac_bstr(&hmac_ctx, mac_inputs->body_protected); + hmac_bstr(&hmac_ctx, mac_inputs->ext_sup_data); + hmac_bstr(&hmac_ctx, mac_inputs->payload); + + return_value = t_cose_crypto_hmac_finish(&hmac_ctx, tag_buf, mac_tag); + + return return_value; } diff --git a/src/t_cose_util.h b/src/t_cose_util.h index a0b9e914..8574dd20 100644 --- a/src/t_cose_util.h +++ b/src/t_cose_util.h @@ -19,6 +19,8 @@ #include "qcbor/qcbor_decode.h" #include "t_cose/q_useful_buf.h" #include "t_cose/t_cose_common.h" +#include "t_cose/t_cose_key.h" + #ifdef __cplusplus extern "C" { @@ -95,17 +97,6 @@ t_cose_tags_and_type(const uint64_t *relevant_cose_tag_nums, * ] */ -/** - * This is the size of the first part of the CBOR encoded ToBeMaced - * bytes. It is around 30 bytes. - */ -#define T_COSE_SIZE_OF_TBM \ - 1 + /* For opening the array */ \ - sizeof(COSE_MAC_CONTEXT_STRING_MAC0) + /* "MAC0" */ \ - 2 + /* Overhead for encoding string */ \ - T_COSE_MAC0_MAX_SIZE_PROTECTED_PARAMETERS + /* entire protected headers */ \ - 1 + /* Empty bstr for absent external_aad */ \ - 9 /* The max CBOR length encoding for start of payload */ /** @@ -164,25 +155,29 @@ bits_iv_alg(int32_t cose_algorithm_id); /** * \brief Create the ToBeMaced (TBM) structure bytes for COSE. * - * \param[in] mac_inputs The input to be mac'd -- payload, aad, - * protected headers. - * \param[in] tbm_first_part_buf The buffer to contain the first part. - * \param[out] tbm_first_part Pointer and length of buffer into which - * the resulting TBM is put. + * \param[in] cose_alg_id Which MAC algorithm to use. + * \param[in] mac_key Key used to perform MAC. + * \param[in] mac_inputs The input to be mac'd -- payload, ext supp data, + * protected headers. + * \param[in] is_mac0 COSE_MAC0 or COSE_MAC. + * \param[out] tag_buf Pointer and length of buffer into which the + * computed HMAC tag is put. + * \param[out] mac_tag Pointer and length of computed tag. * * \return This returns one of the error codes defined by \ref t_cose_err_t. * - * \retval T_COSE_ERR_SIG_STRUCT - * Most likely this is because the protected_headers passed in - * is larger than \ref T_COSE_MAC0_MAX_PROT_HEADER. - * \retval T_COSE_ERR_UNSUPPORTED_HASH + * \retval T_COSE_ERR_UNSUPPORTED_HMAC * If the hash algorithm is not known. - * \retval T_COSE_ERR_HASH_GENERAL_FAIL + * \retval T_COSE_ERR_HMAC_GENERAL_FAIL * In case of some general hash failure. */ -enum t_cose_err_t create_tbm(const struct t_cose_sign_inputs *mac_inputs, - struct q_useful_buf tbm_first_part_buf, - struct q_useful_buf_c *tbm_first_part); +enum t_cose_err_t +create_tbm(const int32_t cose_alg_id, + struct t_cose_key mac_key, + bool is_mac0, + const struct t_cose_sign_inputs *mac_inputs, + const struct q_useful_buf tag_buf, + struct q_useful_buf_c *mac_tag); /**