aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Hu <david.hu@arm.com>2020-01-25 12:25:41 +0800
committerDavid Hu <david.hu@arm.com>2020-06-22 02:33:00 +0000
commit333ca93b117ef3605de9127ee479268aee75348c (patch)
tree6695fd6b4f867df3c0988514c67af23ce016e2d7
parent574f713fe672f67f0a64969bf774d7e1bd1ed39c (diff)
downloadtrusted-firmware-m-333ca93b117ef3605de9127ee479268aee75348c.tar.gz
COSE: Add COSE_Mac0 support in t_cose library
Add t_cose_mac0_init() and t_cose_mac0_finish() to complete COSE_Mac0 structure. Implement HMAC operations for COSE_Mac0 based on PSA crypto MAC operations. Change-Id: Ic55a34d24100adb1c839b0d3ff7cb4d2da09d4cb Signed-off-by: David Hu <david.hu@arm.com>
-rw-r--r--lib/ext/t_cose/CMakeLists.txt31
-rw-r--r--lib/ext/t_cose/crypto_adapters/t_cose_psa_crypto.c137
-rw-r--r--lib/ext/t_cose/inc/t_cose_common.h62
-rw-r--r--lib/ext/t_cose/inc/t_cose_mac0_sign.h229
-rw-r--r--lib/ext/t_cose/inc/t_cose_sign1_sign.h13
-rw-r--r--lib/ext/t_cose/src/t_cose_crypto.h113
-rw-r--r--lib/ext/t_cose/src/t_cose_mac0_sign.c305
-rw-r--r--lib/ext/t_cose/src/t_cose_standard_constants.h8
-rw-r--r--lib/ext/t_cose/src/t_cose_util.c61
-rw-r--r--lib/ext/t_cose/src/t_cose_util.h70
10 files changed, 1007 insertions, 22 deletions
diff --git a/lib/ext/t_cose/CMakeLists.txt b/lib/ext/t_cose/CMakeLists.txt
index 91064e799c..406c9bc246 100644
--- a/lib/ext/t_cose/CMakeLists.txt
+++ b/lib/ext/t_cose/CMakeLists.txt
@@ -28,19 +28,33 @@ endif()
#Append all our source files to global lists.
list(APPEND ALL_SRC_C_SIGN
- "${T_COSE_DIR}/src/t_cose_sign1_sign.c"
"${T_COSE_DIR}/src/t_cose_util.c"
"${T_COSE_DIR}/src/t_cose_parameters.c"
"${T_COSE_DIR}/crypto_adapters/t_cose_psa_crypto.c"
)
+if (SYMMETRIC_INITIAL_ATTESTATION)
+ list(APPEND T_COSE_COMPILE_TIME_CONFIG "T_COSE_DISABLE_SIGN1")
+
+ list(APPEND ALL_SRC_C_SIGN "${T_COSE_DIR}/src/t_cose_mac0_sign.c")
+else()
+ list(APPEND T_COSE_COMPILE_TIME_CONFIG "T_COSE_DISABLE_MAC0")
+
+ list(APPEND ALL_SRC_C_SIGN "${T_COSE_DIR}/src/t_cose_sign1_sign.c")
+endif()
+
list(APPEND ALL_SRC_C_VERIFY
- "${T_COSE_DIR}/src/t_cose_sign1_verify.c"
"${T_COSE_DIR}/src/t_cose_util.c"
"${T_COSE_DIR}/src/t_cose_parameters.c"
- "${T_COSE_DIR}/crypto_adapters/t_cose_psa_crypto.c"
)
+if (NOT SYMMETRIC_INITIAL_ATTESTATION)
+ list(APPEND ALL_SRC_C_VERIFY
+ "${T_COSE_DIR}/src/t_cose_sign1_verify.c"
+ "${T_COSE_DIR}/crypto_adapters/t_cose_psa_crypto.c"
+ )
+endif()
+
list(APPEND ALL_SRC_C_TEST
"${T_COSE_DIR}/test/run_tests.c"
"${T_COSE_DIR}/test/t_cose_make_psa_test_key.c"
@@ -65,13 +79,18 @@ add_library(tfm_t_cose_test OBJECT ${ALL_SRC_C_TEST})
list(APPEND T_COSE_COMPILE_TIME_CONFIG
"T_COSE_USE_PSA_CRYPTO"
- "T_COSE_DISABLE_ES384"
- "T_COSE_DISABLE_ES512"
"T_COSE_DISABLE_CONTENT_TYPE"
- "T_COSE_DISABLE_SIGN_VERIFY_TESTS"
"T_COSE_USE_PSA_CRYPTO_FROM_TFM"
)
+if (NOT SYMMETRIC_INITIAL_ATTESTATION)
+ list(APPEND T_COSE_COMPILE_TIME_CONFIG
+ "T_COSE_DISABLE_ES384"
+ "T_COSE_DISABLE_ES512"
+ "T_COSE_DISABLE_SIGN_VERIFY_TESTS"
+ )
+endif()
+
if (NOT ATTEST_INCLUDE_TEST_CODE)
list(APPEND T_COSE_COMPILE_TIME_CONFIG "T_COSE_DISABLE_SHORT_CIRCUIT_SIGN")
endif()
diff --git a/lib/ext/t_cose/crypto_adapters/t_cose_psa_crypto.c b/lib/ext/t_cose/crypto_adapters/t_cose_psa_crypto.c
index 927e626511..c6e8749db4 100644
--- a/lib/ext/t_cose/crypto_adapters/t_cose_psa_crypto.c
+++ b/lib/ext/t_cose/crypto_adapters/t_cose_psa_crypto.c
@@ -2,6 +2,7 @@
* t_cose_psa_crypto.c
*
* Copyright 2019, Laurence Lundblade
+ * Copyright (c) 2020, Arm Limited. All rights reserved
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -12,10 +13,10 @@
/**
* \file t_cose_psa_crypto.c
*
- * \brief Crypto Adaptation for t_cose to use ARM's PSA ECDSA and hashes.
+ * \brief Crypto Adaptation for t_cose to use ARM's PSA Crypto APIs.
*
* This connects up the abstract interface in t_cose_crypto.h to the
- * implementations of ECDSA signing and hashing in ARM's PSA crypto
+ * implementations of ECDSA signing, hashing and HMAC in ARM's PSA crypto
* library.
*
* This adapter layer doesn't bloat the implementation as everything
@@ -60,7 +61,7 @@
/* Avoid compiler warning due to unused argument */
#define ARG_UNUSED(arg) (void)(arg)
-
+#ifndef T_COSE_DISABLE_SIGN1
/**
* \brief Map a COSE signing algorithm ID to a PSA signing algorithm ID
*
@@ -407,3 +408,133 @@ t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx,
Done:
return psa_status_to_t_cose_error_hash(hash_ctx->status);
}
+#endif /* !T_COSE_DISABLE_SIGN1 */
+
+#ifndef T_COSE_DISABLE_MAC0
+/**
+ * \brief Convert COSE algorithm ID to a PSA HMAC algorithm ID
+ *
+ * \param[in] cose_hmac_alg_id The COSE-based ID for the
+ *
+ * \return PSA-based MAC algorithm ID, or a vendor flag in the case of error.
+ *
+ */
+static inline psa_algorithm_t cose_hmac_alg_id_to_psa(int32_t cose_hmac_alg_id)
+{
+ switch(cose_hmac_alg_id) {
+ case T_COSE_ALGORITHM_HMAC256:
+ return PSA_ALG_HMAC(PSA_ALG_SHA_256);
+ case T_COSE_ALGORITHM_HMAC384:
+ return PSA_ALG_HMAC(PSA_ALG_SHA_384);
+ case T_COSE_ALGORITHM_HMAC512:
+ return PSA_ALG_HMAC(PSA_ALG_SHA_512);
+ default:
+ return PSA_ALG_VENDOR_FLAG;
+ }
+}
+
+/**
+ * \brief Map a PSA error into a t_cose error for HMAC.
+ *
+ * \param[in] status The PSA status.
+ *
+ * \return The \ref t_cose_err_t.
+ */
+static enum t_cose_err_t
+psa_status_to_t_cose_error_hmac(psa_status_t status)
+{
+ /* Intentionally limited to just this minimum set of errors to
+ * save object code as hashes don't really fail much
+ */
+ return status == PSA_SUCCESS ? T_COSE_SUCCESS :
+ status == PSA_ERROR_NOT_SUPPORTED ? T_COSE_ERR_UNSUPPORTED_HASH :
+ status == PSA_ERROR_INVALID_ARGUMENT ? T_COSE_ERR_INVALID_ARGUMENT :
+ status == PSA_ERROR_INSUFFICIENT_MEMORY ? T_COSE_ERR_INSUFFICIENT_MEMORY :
+ status == PSA_ERROR_BUFFER_TOO_SMALL ? T_COSE_ERR_TOO_SMALL :
+ T_COSE_ERR_FAIL;
+}
+
+/*
+ * See documentation in t_cose_crypto.h
+ */
+enum t_cose_err_t
+t_cose_crypto_hmac_sign_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;
+
+ 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_SIGNING_ALG;
+ }
+
+ /*
+ * Verify if HMAC algorithm is valid.
+ * According to COSE (RFC 8152), only SHA-256, SHA-384 and SHA-512 are
+ * supported in COSE_Mac0 with 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_SIGNING_ALG;
+ }
+
+ hmac_ctx->op_ctx = psa_mac_operation_init();
+
+ psa_ret = psa_mac_sign_setup(&hmac_ctx->op_ctx,
+ (psa_key_handle_t)signing_key.k.key_handle,
+ psa_alg);
+
+ 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_update(struct t_cose_crypto_hmac *hmac_ctx,
+ struct q_useful_buf_c payload)
+{
+ psa_status_t psa_ret;
+
+ if(!hmac_ctx) {
+ return T_COSE_ERR_INVALID_ARGUMENT;
+ }
+
+ 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_sign_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;
+
+ if(!hmac_ctx) {
+ return T_COSE_ERR_INVALID_ARGUMENT;
+ }
+
+ 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;
+ }
+
+ return psa_status_to_t_cose_error_hmac(psa_ret);
+}
+#endif /* !T_COSE_DISABLE_MAC0 */
diff --git a/lib/ext/t_cose/inc/t_cose_common.h b/lib/ext/t_cose/inc/t_cose_common.h
index 17ca21adb6..0481ac7e15 100644
--- a/lib/ext/t_cose/inc/t_cose_common.h
+++ b/lib/ext/t_cose/inc/t_cose_common.h
@@ -2,6 +2,7 @@
* t_cose_common.h
*
* Copyright 2019, Laurence Lundblade
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -88,7 +89,41 @@ extern "C" {
*/
#define T_COSE_ALGORITHM_ES512 -36
+/**
+ * \def T_COSE_ALGORITHM_HMAC256
+ *
+ * \brief Indicates HMAC with SHA256
+ *
+ * This value comes from the
+ * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml).
+ *
+ * Value for \ref COSE_HEADER_PARAM_ALG to indicate HMAC w/ SHA-256
+ */
+#define T_COSE_ALGORITHM_HMAC256 5
+/**
+ * \def T_COSE_ALGORITHM_HMAC384
+ *
+ * \brief Indicates HMAC with SHA384
+ *
+ * This value comes from the
+ * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml).
+ *
+ * Value for \ref COSE_HEADER_PARAM_ALG to indicate HMAC w/ SHA-384
+ */
+#define T_COSE_ALGORITHM_HMAC384 6
+
+/**
+ * \def T_COSE_ALGORITHM_HMAC512
+ *
+ * \brief Indicates HMAC with SHA512
+ *
+ * This value comes from the
+ * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml).
+ *
+ * Value for \ref COSE_HEADER_PARAM_ALG to indicate HMAC w/ SHA-512
+ */
+#define T_COSE_ALGORITHM_HMAC512 7
/**
@@ -154,6 +189,18 @@ struct t_cose_key {
*/
#define T_COSE_SIGN1_MAX_SIZE_PROTECTED_PARAMETERS (1+1+5+17)
+/* 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)
/**
* Error codes return by t_cose.
@@ -347,6 +394,21 @@ enum t_cose_err_t {
#define T_COSE_EMPTY_UINT_CONTENT_TYPE UINT16_MAX+1
+
+
+/**
+ * An \c option_flag to not add the CBOR type 6 tag for a COSE message.
+ * Some uses of COSE may require this tag be absent because its COSE
+ * message type is known from surrounding context.
+ *
+ * Or said another way, per the COSE RFC, this code produces a \c
+ * COSE_Sign1_Tagged/ \c COSE_Mac0_Tagged by default and
+ * a \c COSE_Sign1/ \c COSE_Mac0 when this flag is set.
+ * The only difference between these two is the CBOR tag.
+ */
+#define T_COSE_OPT_OMIT_CBOR_TAG 0x00000002
+
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/ext/t_cose/inc/t_cose_mac0_sign.h b/lib/ext/t_cose/inc/t_cose_mac0_sign.h
new file mode 100644
index 0000000000..c3839f5f0d
--- /dev/null
+++ b/lib/ext/t_cose/inc/t_cose_mac0_sign.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+ * Copyright (c) 2020 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __T_COSE_MAC0_SIGN_H_
+#define __T_COSE_MAC0_SIGN_H_
+
+#include <stdint.h>
+#include "qcbor.h"
+#include "t_cose_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * This is the context for creating a \c COSE_Mac0 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.
+ */
+struct t_cose_mac0_sign_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 signing_key;
+ int32_t option_flags;
+ struct q_useful_buf_c kid;
+#ifndef T_COSE_DISABLE_CONTENT_TYPE
+ uint32_t content_type_uint;
+ const char *content_type_tstr;
+#endif
+};
+
+
+/**
+ * \brief Initialize to start creating a \c COSE_Mac0.
+ *
+ * \param[in] context The t_cose signing context.
+ * \param[in] option_flags One of \c T_COSE_OPT_XXXX.
+ * \param[in] cose_algorithm_id The algorithm to generate the authentication
+ * tag, for example
+ * \ref T_COSE_ALGORITHM_HMAC256.
+ *
+ * Initialize the \ref t_cose_mac0_sign_ctx context. Typically, no
+ * \c option_flags are needed and 0 is passed. A \c cose_algorithm_id
+ * must always be given.
+ *
+ * The algorithm ID space is from
+ * [COSE (RFC8152)](https://tools.ietf.org/html/rfc8152) and the
+ * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml).
+ * \ref T_COSE_ALGORITHM_HMAC256 is defined here for convenience.
+ * So far, only HMAC is supported in \c COSE_Mac0.
+ *
+ * Errors such as the passing of an unsupported \c cose_algorithm_id
+ * are reported when t_cose_mac0_encode_parameters() is called.
+ */
+static void
+t_cose_mac0_sign_init(struct t_cose_mac0_sign_ctx *me,
+ int32_t option_flags,
+ int32_t cose_algorithm_id);
+
+/**
+ * \brief Set the key and kid (key ID) for signing.
+ *
+ * \param[in] context The t_cose signing context.
+ * \param[in] signing_key The signing key to use or \ref T_COSE_NULL_KEY.
+ * \param[in] kid COSE key ID parameter or \c NULL_Q_USEFUL_BUF_C.
+ *
+ * This needs to be called to set the signing key to use. The \c kid
+ * may be omitted by giving \c NULL_Q_USEFUL_BUF_C.
+ */
+static void
+t_cose_mac0_set_signing_key(struct t_cose_mac0_sign_ctx *context,
+ struct t_cose_key signing_key,
+ struct q_useful_buf_c kid);
+
+/**
+ * \brief Output first part and parameters for a \c COSE_Mac0 message.
+ *
+ * \param[in] context The t_cose signing context.
+ * \param[in] cbor_encode_ctx Encoding context to output to.
+ *
+ * t_cose_mac0_sign_init() and t_cose_mac0_set_signing_key() must be
+ * called before calling this.
+ *
+ * When this is called, the opening parts of the \c COSE_Mac0 message
+ * are output to the \c cbor_encode_ctx.
+ *
+ * After this is called, the CBOR-formatted payload must be written to
+ * the \c cbor_encode_ctx by calling all the various
+ * \c QCBOREncode_AddXxx calls. It can be as simple or complex as needed.
+ *
+ * To complete the \c COSE_Mac0 call t_cose_mac0_encode_tag().
+ *
+ * The \c cbor_encode_ctx must have been initialized with an output
+ * buffer to hold the \c COSE_Mac0 header parameters, the payload and the
+ * signature.
+ *
+ * This and t_cose_mac0_encode_tag() can be used to calculate
+ * the size of the \c COSE_Mac0 in the way \c QCBOREncode is usually
+ * used to calculate sizes. In this case the \c t_cose_mac0_sign_ctx must
+ * be initialized with the options, algorithm, key and kid just as
+ * normal as these are needed to calculate the size. Then set up the
+ * QCBOR encoder context with a \c NULL pointer and large length like
+ * \c UINT32_MAX. Call t_cose_mac0_encode_parameters(), then format
+ * the payload into the encoder context, then call
+ * t_cose_mac0_encode_tag(). Finally call \c
+ * QCBOREncode_FinishGetSize() to get the length.
+ */
+enum t_cose_err_t
+t_cose_mac0_encode_parameters(struct t_cose_mac0_sign_ctx *context,
+ QCBOREncodeContext *cbor_encode_ctx);
+
+/**
+ * \brief Finish a \c COSE_Mac0 message by outputting the authentication tag.
+ *
+ * \param[in] context The t_cose signing context.
+ * \param[in] cbor_encode_ctx Encoding context to output to.
+ *
+ * \return This returns one of the error codes defined by \ref t_cose_err_t.
+ *
+ * Call this to complete creation of a tagged \c COSE_Mac0 started
+ * with t_cose_mac0_encode_parameters().
+ *
+ * This is when the cryptographic MAC algorithm is run.
+ *
+ * The completed \c COSE_Mac0 message is retrieved from the
+ * \c cbor_encode_ctx by calling \c QCBOREncode_Finish().
+ */
+enum t_cose_err_t
+t_cose_mac0_encode_tag(struct t_cose_mac0_sign_ctx *context,
+ QCBOREncodeContext *cbor_encode_ctx);
+
+
+#ifndef T_COSE_DISABLE_CONTENT_TYPE
+/**
+ * \brief Set the payload content type using CoAP content types.
+ *
+ * \param[in] context The t_cose signing context.
+ * \param[in] content_type The content type of the payload as defined
+ * in the IANA CoAP Content-Formats registry.
+ *
+ * It is not allowed to have both a CoAP and MIME content type. This
+ * error will show up when t_cose_mac0_encode_parameters() is called
+ * as no error is returned by this function.
+ *
+ * The IANA CoAP Content-Formats registry is found
+ * [here](https://www.iana.org/assignments/core-parameters/core-parameters.xhtml#content-formats).
+ */
+static inline void
+t_cose_mac0_set_content_type_uint(struct t_cose_mac0_sign_ctx *context,
+ uint16_t content_type);
+
+/**
+ * \brief Set the payload content type using MIME content types.
+ *
+ * \param[in] context The t_cose signing context.
+ * \param[in] content_type The content type of the payload as defined
+ * in the IANA Media Types registry.
+
+ *
+ * It is not allowed to have both a CoAP and MIME content type. This
+ * error will show up when t_cose_mac0_encode_parameters() is called.
+ *
+ * The IANA Media Types registry can be found
+ * [here](https://www.iana.org/assignments/media-types/media-types.xhtml).
+ * These have been known as MIME types in the past.
+ */
+static inline void
+t_cose_mac0_set_content_type_tstr(struct t_cose_mac0_sign_ctx *context,
+ const char *content_type);
+#endif /* T_COSE_DISABLE_CONTENT_TYPE */
+
+/* ------------------------------------------------------------------------
+ * Inline implementations of public functions defined above.
+ */
+static inline void
+t_cose_mac0_sign_init(struct t_cose_mac0_sign_ctx *me,
+ int32_t option_flags,
+ int32_t cose_algorithm_id)
+{
+ memset(me, 0, sizeof(*me));
+
+#ifndef T_COSE_DISABLE_CONTENT_TYPE
+ /* Only member for which 0 is not the empty state */
+ me->content_type_uint = T_COSE_EMPTY_UINT_CONTENT_TYPE;
+#endif
+
+ me->cose_algorithm_id = cose_algorithm_id;
+ me->option_flags = option_flags;
+}
+
+static inline void
+t_cose_mac0_set_signing_key(struct t_cose_mac0_sign_ctx *me,
+ struct t_cose_key signing_key,
+ struct q_useful_buf_c kid)
+{
+ me->kid = kid;
+ me->signing_key = signing_key;
+}
+
+
+#ifndef T_COSE_DISABLE_CONTENT_TYPE
+static inline void
+t_cose_mac0_set_content_type_uint(struct t_cose_mac0_sign_ctx *me,
+ uint16_t content_type)
+{
+ me->content_type_uint = content_type;
+}
+
+static inline void
+t_cose_mac0_set_content_type_tstr(struct t_cose_mac0_sign_ctx *me,
+ const char *content_type)
+{
+ me->content_type_tstr = content_type;
+}
+#endif /* T_COSE_DISABLE_CONTENT_TYPE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __T_COSE_MAC0_SIGN_H_ */
diff --git a/lib/ext/t_cose/inc/t_cose_sign1_sign.h b/lib/ext/t_cose/inc/t_cose_sign1_sign.h
index fcb3fbe2da..0dcf0962d8 100644
--- a/lib/ext/t_cose/inc/t_cose_sign1_sign.h
+++ b/lib/ext/t_cose/inc/t_cose_sign1_sign.h
@@ -104,19 +104,6 @@ struct t_cose_sign1_sign_ctx {
#define T_COSE_OPT_SHORT_CIRCUIT_SIG 0x00000001
-/**
- * An \c option_flag for t_cose_sign1_sign_init() to not add the CBOR
- * type 6 tag for \c COSE_Sign1 whose value is 18. Some uses of COSE
- * may require this tag be absent because it is known that it is a \c
- * COSE_Sign1 from surrounding context.
- *
- * Or said another way, per the COSE RFC, this code produces a \c
- * COSE_Sign1_Tagged by default and a \c COSE_Sign1 when this flag is
- * set. The only difference between these two is the CBOR tag.
- */
-#define T_COSE_OPT_OMIT_CBOR_TAG 0x00000002
-
-
/**
diff --git a/lib/ext/t_cose/src/t_cose_crypto.h b/lib/ext/t_cose/src/t_cose_crypto.h
index ec68ae458e..80263a90ba 100644
--- a/lib/ext/t_cose/src/t_cose_crypto.h
+++ b/lib/ext/t_cose/src/t_cose_crypto.h
@@ -2,6 +2,7 @@
* t_cose_crypto.h
*
* Copyright 2019, Laurence Lundblade
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -371,6 +372,23 @@ struct t_cose_crypto_hash {
};
+/**
+ * The context for use with the HMAC adaptation layer here.
+ * Borrow the structure of t_cose_crypto_hash.
+ */
+struct t_cose_crypto_hmac {
+ #ifdef T_COSE_USE_PSA_CRYPTO
+ /* --- The context for PSA Crypto (MBed Crypto) --- */
+ psa_mac_operation_t op_ctx;
+ #else
+ /* --- Default: generic pointer / handle --- */
+ union {
+ void *ptr;
+ uint64_t handle;
+ } context;
+ int64_t status;
+ #endif
+};
/**
* The size of the output of SHA-256.
@@ -391,6 +409,26 @@ struct t_cose_crypto_hash {
*/
#define T_COSE_CRYPTO_SHA512_SIZE 64
+/**
+ * Size of the signature (tag) output for the HMAC-SHA256.
+ */
+#define T_COSE_CRYPTO_HMAC256_TAG_SIZE T_COSE_CRYPTO_SHA256_SIZE
+
+/**
+ * Size of the signature (tag) output for the HMAC-SHA384.
+ */
+#define T_COSE_CRYPTO_HMAC384_TAG_SIZE T_COSE_CRYPTO_SHA384_SIZE
+
+/**
+ * Size of the signature (tag) output for the HMAC-SHA512.
+ */
+#define T_COSE_CRYPTO_HMAC512_TAG_SIZE T_COSE_CRYPTO_SHA512_SIZE
+
+/**
+ * Max size of the tag output for the HMAC operations.
+ */
+#define T_COSE_CRYPTO_HMAC_TAG_MAX_SIZE T_COSE_CRYPTO_SHA512_SIZE
+
/**
* The maximum needed to hold a hash. It is smaller and less stack is used
@@ -502,7 +540,68 @@ t_cose_crypto_hash_finish(struct t_cose_crypto_hash *hash_ctx,
struct q_useful_buf buffer_to_hold_result,
struct q_useful_buf_c *hash_result);
+/**
+ * \brief Set up a multipart HMAC calculation operation
+ *
+ * \param[in,out] hmac_ctx Pointer to the HMAC context.
+ * \param[in] signing_key The key for the HMAC operation
+ * \param[in] cose_alg_id The algorithm used in HMAC.
+ *
+ * \retval T_COSE_SUCCESS
+ * Tag calculation 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_sign_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
+ *
+ * \param[in,out] hmac_ctx Pointer to the HMAC context.
+ * \param[in] payload Pointer and length of payload
+ *
+ * \retval T_COSE_SUCCESS
+ * Tag calculation succeeds.
+ * \retval T_COSE_ERR_SIG_BUFFER_SIZE
+ * The size of the buffer to hold the tag result was too small.
+ * \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_update(struct t_cose_crypto_hmac *hmac_ctx,
+ struct q_useful_buf_c payload);
+/**
+ * \brief Finish the calculation of the HMAC of a message.
+ *
+ * \param[in,out] hmac_ctx Pointer to the HMAC context.
+ * \param[in] tag_buf Pointer and length into which
+ * the resulting tag is put.
+ * \param[out] tag Pointer and length of the
+ * resulting tag.
+ *
+ * \retval T_COSE_SUCCESS
+ * Tag calculation succeeds.
+ * \retval T_COSE_ERR_SIG_BUFFER_SIZE
+ * The size of the buffer to hold the tag result was too small.
+ * \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_sign_finish(struct t_cose_crypto_hmac *hmac_ctx,
+ struct q_useful_buf tag_buf,
+ struct q_useful_buf_c *tag);
/**
* \brief Indicate whether a COSE algorithm is ECDSA or not.
@@ -571,6 +670,20 @@ static inline bool t_cose_algorithm_is_ecdsa(int32_t cose_algorithm_id)
return t_cose_check_list(cose_algorithm_id, ecdsa_list);
}
+static inline size_t t_cose_tag_size(int32_t cose_alg_id)
+{
+ switch(cose_alg_id) {
+ case T_COSE_ALGORITHM_HMAC256:
+ return T_COSE_CRYPTO_HMAC256_TAG_SIZE;
+ case T_COSE_ALGORITHM_HMAC384:
+ return T_COSE_CRYPTO_HMAC384_TAG_SIZE;
+ case T_COSE_ALGORITHM_HMAC512:
+ return T_COSE_CRYPTO_HMAC512_TAG_SIZE;
+ default:
+ return INT32_MAX;
+ }
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/ext/t_cose/src/t_cose_mac0_sign.c b/lib/ext/t_cose/src/t_cose_mac0_sign.c
new file mode 100644
index 0000000000..7a57409768
--- /dev/null
+++ b/lib/ext/t_cose/src/t_cose_mac0_sign.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+#include "qcbor.h"
+#include "t_cose_crypto.h"
+#include "t_cose_mac0_sign.h"
+#include "t_cose_util.h"
+
+/**
+ * \file t_cose_mac0_sign.c
+ *
+ * \brief This creates t_cose Mac authentication structure without a recipient
+ * structure.
+ * Only HMAC is supported so far.
+ */
+
+/**
+ * \brief Makes the protected header parameters for COSE.
+ *
+ * \param[in] cose_algorithm_id The COSE algorithm ID to put in the
+ * header parameters.
+ * \param[in] buffer_for_parameters Pointer and length of buffer into which
+ * the resulting encoded protected
+ * parameters is put. See return value.
+ *
+ * \return The pointer and length of the encoded protected
+ * parameters is returned, or \c NULL_Q_USEFUL_BUF_C if this fails.
+ * This will have the same pointer as \c buffer_for_parameters,
+ * but the pointer is conts and the length is that of the valid
+ * data, not of the size of the buffer.
+ *
+ * The protected parameters are returned in fully encoded CBOR format as
+ * they are added to the \c COSE_Mac0 message as a binary string. This is
+ * different from the unprotected parameters which are not handled this
+ * way.
+ *
+ * This returns \c NULL_Q_USEFUL_BUF_C if buffer_for_parameters was too
+ * small. See also definition of \c T_COSE_MAC0_MAX_SIZE_PROTECTED_PARAMETERS
+ */
+static inline struct q_useful_buf_c
+encode_protected_parameters(int32_t cose_algorithm_id,
+ struct q_useful_buf buffer_for_parameters)
+{
+ /* approximate stack use on 32-bit machine:
+ * CBOR encode context 148
+ * local use: 20
+ * total: 168
+ */
+ struct q_useful_buf_c protected_parameters;
+ QCBORError qcbor_result;
+ QCBOREncodeContext cbor_encode_ctx;
+ struct q_useful_buf_c return_value;
+
+ QCBOREncode_Init(&cbor_encode_ctx, buffer_for_parameters);
+ QCBOREncode_OpenMap(&cbor_encode_ctx);
+ QCBOREncode_AddInt64ToMapN(&cbor_encode_ctx,
+ COSE_HEADER_PARAM_ALG,
+ cose_algorithm_id);
+ QCBOREncode_CloseMap(&cbor_encode_ctx);
+ qcbor_result = QCBOREncode_Finish(&cbor_encode_ctx, &protected_parameters);
+
+ if(qcbor_result == QCBOR_SUCCESS) {
+ return_value = protected_parameters;
+ } else {
+ return_value = NULL_Q_USEFUL_BUF_C;
+ }
+
+ return return_value;
+}
+
+/**
+ * \brief Add the unprotected parameters to a CBOR encoding context
+ *
+ * \param[in] me The t_cose signing context.
+ * \param[in] kid The key ID.
+ * \param[in] cbor_encode_ctx CBOR encoding context to output to
+ *
+ * No error is returned. If an error occurred it will be returned when
+ * \c QCBOR_Finish() is called on \c cbor_encode_ctx.
+ *
+ * The unprotected parameters added by this are the kid and content type.
+ */
+static inline enum t_cose_err_t
+add_unprotected_parameters(const struct t_cose_mac0_sign_ctx *me,
+ const struct q_useful_buf_c kid,
+ QCBOREncodeContext *cbor_encode_ctx)
+{
+ QCBOREncode_OpenMap(cbor_encode_ctx);
+
+ if(!q_useful_buf_c_is_null_or_empty(kid)) {
+ QCBOREncode_AddBytesToMapN(cbor_encode_ctx,
+ COSE_HEADER_PARAM_KID,
+ kid);
+ }
+
+#ifndef T_COSE_DISABLE_CONTENT_TYPE
+ if(me->content_type_uint != T_COSE_EMPTY_UINT_CONTENT_TYPE &&
+ me->content_type_tstr != NULL) {
+ /* Both the string and int content types are not allowed */
+ return T_COSE_ERR_DUPLICATE_PARAMETER;
+ }
+
+ if(me->content_type_uint != T_COSE_EMPTY_UINT_CONTENT_TYPE) {
+ QCBOREncode_AddUInt64ToMapN(cbor_encode_ctx,
+ COSE_HEADER_PARAM_CONTENT_TYPE,
+ me->content_type_uint);
+ }
+
+ if(me->content_type_tstr != NULL) {
+ QCBOREncode_AddSZStringToMapN(cbor_encode_ctx,
+ COSE_HEADER_PARAM_CONTENT_TYPE,
+ me->content_type_tstr);
+ }
+#else
+ (void)me; /* avoid unused parameter warning */
+#endif
+
+ QCBOREncode_CloseMap(cbor_encode_ctx);
+
+ return T_COSE_SUCCESS;
+}
+
+/*
+ * Public function. See t_cose_mac0.h
+ */
+enum t_cose_err_t
+t_cose_mac0_encode_parameters(struct t_cose_mac0_sign_ctx *me,
+ QCBOREncodeContext *cbor_encode_ctx)
+
+{
+ size_t tag_len;
+ enum t_cose_err_t return_value;
+ struct q_useful_buf buffer_for_protected_parameters;
+ struct q_useful_buf_c kid;
+
+ /*
+ * Check the algorithm now by getting the algorithm as an early
+ * error check even though it is not used until later.
+ */
+ tag_len = t_cose_tag_size(me->cose_algorithm_id);
+ if(tag_len == INT32_MAX) {
+ return T_COSE_ERR_UNSUPPORTED_SIGNING_ALG;
+ }
+
+ /* Add the CBOR tag indicating COSE_Mac0 */
+ if(!(me->option_flags & T_COSE_OPT_OMIT_CBOR_TAG)) {
+ QCBOREncode_AddTag(cbor_encode_ctx, CBOR_TAG_COSE_MAC0);
+ }
+
+ /* Get started with the tagged array that holds the parts of
+ * a COSE_Mac0 message
+ */
+ QCBOREncode_OpenArray(cbor_encode_ctx);
+
+ /* The protected headers, which are added as a wrapped bstr */
+ buffer_for_protected_parameters =
+ Q_USEFUL_BUF_FROM_BYTE_ARRAY(me->protected_parameters_buffer);
+ me->protected_parameters =
+ encode_protected_parameters(me->cose_algorithm_id,
+ buffer_for_protected_parameters);
+ if(q_useful_buf_c_is_null(me->protected_parameters)) {
+ /* The sizing of storage for protected headers is
+ * off (should never happen in tested, released code)
+ */
+ return_value = T_COSE_ERR_MAKING_PROTECTED;
+ goto Done;
+ }
+ /* The use of _AddBytes here achieves the bstr wrapping */
+ QCBOREncode_AddBytes(cbor_encode_ctx, me->protected_parameters);
+
+ /* The Unprotected parameters */
+ /* Get the kid because it goes into the parameters that are about
+ * to be made.
+ */
+ kid = me->kid;
+
+ return_value = add_unprotected_parameters(me, kid, cbor_encode_ctx);
+ if(return_value != T_COSE_SUCCESS) {
+ goto Done;
+ }
+
+ QCBOREncode_BstrWrap(cbor_encode_ctx);
+
+ /*
+ * Any failures in CBOR encoding will be caught in finish
+ * when the CBOR encoding is closed off. No need to track
+ * here as the CBOR encoder tracks it internally.
+ */
+
+Done:
+ return return_value;
+}
+
+/*
+ * Public function. See t_cose_mac0.h
+ */
+enum t_cose_err_t
+t_cose_mac0_encode_tag(struct t_cose_mac0_sign_ctx *me,
+ QCBOREncodeContext *cbor_encode_ctx)
+
+{
+ 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,
+ T_COSE_CRYPTO_HMAC_TAG_MAX_SIZE);
+ struct q_useful_buf_c tbm_first_part;
+ /* Buffer for the ToBeMaced */
+ UsefulBuf_MAKE_STACK_UB( tbm_first_part_buf,
+ T_COSE_SIZE_OF_TBM);
+ struct t_cose_crypto_hmac hmac_ctx;
+ struct q_useful_buf_c maced_payload;
+
+ QCBOREncode_CloseBstrWrap(cbor_encode_ctx, &maced_payload);
+
+ /* Check that there are no CBOR encoding errors before proceeding
+ * with hashing and tagging. This is not actually necessary as the
+ * errors will be caught correctly later, but it does make it a
+ * bit easier for the caller to debug problems.
+ */
+ cbor_err = QCBOREncode_GetErrorState(cbor_encode_ctx);
+ if(cbor_err == QCBOR_ERR_BUFFER_TOO_SMALL) {
+ return_value = T_COSE_ERR_TOO_SMALL;
+ goto Done;
+ } else if(cbor_err != QCBOR_SUCCESS) {
+ return_value = T_COSE_ERR_CBOR_FORMATTING;
+ goto Done;
+ }
+
+ 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);
+
+ return_value = T_COSE_SUCCESS;
+ goto CloseArray;
+ }
+
+ /* Create the hash of the ToBeMaced bytes. Inputs to the
+ * MAC are the protected parameters, the payload that is
+ * getting MACed.
+ */
+ return_value = create_tbm(tbm_first_part_buf,
+ me->protected_parameters,
+ &tbm_first_part,
+ T_COSE_TBM_PAYLOAD_IS_BSTR_WRAPPED,
+ maced_payload);
+ 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_sign_setup(&hmac_ctx,
+ me->signing_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, maced_payload);
+ if(return_value) {
+ goto Done;
+ }
+
+ return_value = t_cose_crypto_hmac_sign_finish(&hmac_ctx, tag_buf, &tag);
+ if(return_value) {
+ goto Done;
+ }
+
+CloseArray:
+ /* Add tag to CBOR and close out the array */
+ QCBOREncode_AddBytes(cbor_encode_ctx, tag);
+ QCBOREncode_CloseArray(cbor_encode_ctx);
+
+ /* CBOR encoding errors are tracked in the CBOR encoding context
+ * and handled in the layer above this
+ */
+
+Done:
+ return return_value;
+}
diff --git a/lib/ext/t_cose/src/t_cose_standard_constants.h b/lib/ext/t_cose/src/t_cose_standard_constants.h
index 886dc1f58d..4f8f9a734e 100644
--- a/lib/ext/t_cose/src/t_cose_standard_constants.h
+++ b/lib/ext/t_cose/src/t_cose_standard_constants.h
@@ -2,6 +2,7 @@
* t_cose_standard_constants.h
*
* Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -401,5 +402,12 @@
*/
#define COSE_SIG_CONTEXT_STRING_SIGNATURE1 "Signature1"
+/**
+ * \def COSE_MAC_CONTEXT_STRING_MAC0
+ *
+ * \brief This is a string constant used by COSE to label \c COSE_Mac0
+ * structures. See RFC 8152, section 6.3.
+ */
+#define COSE_MAC_CONTEXT_STRING_MAC0 "MAC0"
#endif /* __T_COSE_STANDARD_CONSTANTS_H__ */
diff --git a/lib/ext/t_cose/src/t_cose_util.c b/lib/ext/t_cose/src/t_cose_util.c
index a0fae2d1cc..b6c9f11fa7 100644
--- a/lib/ext/t_cose/src/t_cose_util.c
+++ b/lib/ext/t_cose/src/t_cose_util.c
@@ -2,6 +2,7 @@
* t_cose_util.c
*
* Copyright 2019, Laurence Lundblade
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -49,6 +50,65 @@ int32_t hash_alg_id_from_sig_alg_id(int32_t cose_algorithm_id)
}
+#ifndef T_COSE_DISABLE_MAC0
+enum t_cose_err_t create_tbm(UsefulBuf tbm_first_part_buf,
+ struct q_useful_buf_c protected_headers,
+ struct q_useful_buf_c *tbm_first_part,
+ enum t_cose_tbm_payload_mode_t payload_mode,
+ struct q_useful_buf_c payload)
+{
+ QCBOREncodeContext cbor_encode_ctx;
+ QCBORError qcbor_result;
+ size_t bytes_to_omit;
+
+ /* 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_AddSZString(&cbor_encode_ctx, COSE_MAC_CONTEXT_STRING_MAC0);
+ /* body_protected */
+ QCBOREncode_AddBytes(&cbor_encode_ctx, protected_headers);
+
+ /* external_aad. There is none so an empty bstr */
+ QCBOREncode_AddBytes(&cbor_encode_ctx, NULL_Q_USEFUL_BUF_C);
+
+ /* The short fake payload. */
+ if(payload_mode == T_COSE_TBM_PAYLOAD_IS_BSTR_WRAPPED) {
+ /* Fake payload is just an empty bstr. It is here only
+ * to make the array count right. It must be omitted
+ * in the actual MAC below
+ */
+ bytes_to_omit = 1;
+ QCBOREncode_AddBytes(&cbor_encode_ctx, NULL_Q_USEFUL_BUF_C);
+ } else {
+ /* Fake payload is the type and length of the wrapping
+ * bstr. It gets MACed with the first part, so no
+ * bytes to omit.
+ */
+ bytes_to_omit = 0;
+ QCBOREncode_AddBytesLenOnly(&cbor_encode_ctx, payload);
+ }
+
+ /* Close of the array */
+ QCBOREncode_CloseArray(&cbor_encode_ctx);
+
+ /* 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;
+ }
+
+ tbm_first_part->len -= bytes_to_omit;
+
+ return T_COSE_SUCCESS;
+}
+#endif /* !T_COSE_DISABLE_MAC0 */
+
+
+#ifndef T_COSE_DISABLE_SIGN1
/*
* Format of to-be-signed bytes used by create_tbs_hash(). This is
* defined in COSE (RFC 8152) section 4.4. It is the input to the
@@ -198,6 +258,7 @@ enum t_cose_err_t create_tbs_hash(int32_t cose_algorithm_id,
Done:
return return_value;
}
+#endif /* !T_COSE_DISABLE_SIGN1 */
#ifndef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
diff --git a/lib/ext/t_cose/src/t_cose_util.h b/lib/ext/t_cose/src/t_cose_util.h
index b171d039cc..c2542b2637 100644
--- a/lib/ext/t_cose/src/t_cose_util.h
+++ b/lib/ext/t_cose/src/t_cose_util.h
@@ -2,6 +2,7 @@
* t_cose_util.h
*
* Copyright 2019, Laurence Lundblade
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -46,6 +47,22 @@ enum t_cose_tbs_hash_mode_t {
};
+/**
+ * The modes in which the payload is passed to create_tbm(). This
+ * exists so the ToBeMaced bytes can be hashed in two separate chunks and
+ * avoids needing a second buffer the size of the payload in the
+ * t_cose implementation.
+ */
+enum t_cose_tbm_payload_mode_t {
+ /** The bytes passed for the payload include a wrapping bstr so
+ * one does not need to be added.
+ */
+ T_COSE_TBM_PAYLOAD_IS_BSTR_WRAPPED,
+ /** The bytes passed for the payload do NOT have a wrapping bstr
+ * so one must be added.
+ */
+ T_COSE_TBM_BARE_PAYLOAD
+};
/**
* This value represents an invalid or in-error algorithm ID. The
@@ -56,6 +73,32 @@ enum t_cose_tbs_hash_mode_t {
#define T_COSE_INVALID_ALGORITHM_ID COSE_ALGORITHM_RESERVED
+/*
+ * Format of ToBeMaced bytes
+ * This is defined in COSE (RFC 8152) section 6.2. It is the input to the HMAC
+ * operation.
+ *
+ * MAC_structure = [
+ * context : "MAC0",
+ * protected : empty_or_serialized_map,
+ * external_aad : bstr,
+ * payload : bstr
+ * ]
+ */
+
+/**
+ * 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 */
+
+
/**
* \brief Return hash algorithm ID from a signature algorithm ID
*
@@ -83,6 +126,33 @@ enum t_cose_tbs_hash_mode_t {
*/
int32_t hash_alg_id_from_sig_alg_id(int32_t cose_algorithm_id);
+/**
+ * \brief Create the ToBeMaced (TBM) structure bytes for COSE.
+ *
+ * \param[in] tbm_first_part_buf The buffer to contain the first part
+ * \param[in] protected_headers The CBOR encoded protected headers.
+ * \param[out] tbm_first_part Pointer and length of buffer into which
+ * the resulting TBM is put.
+ * \param[in] payload_mode See \ref t_cose_tbm_payload_mode_t.
+ * \param[in] payload The CBOR encoded payload. It may or may
+ * not have a wrapping bstr per
+ * \c payload_mode.
+ *
+ * \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
+ * If the hash algorithm is not known.
+ * \retval T_COSE_ERR_HASH_GENERAL_FAIL
+ * In case of some general hash failure.
+ */
+enum t_cose_err_t create_tbm(UsefulBuf tbm_first_part_buf,
+ struct q_useful_buf_c protected_headers,
+ struct q_useful_buf_c *tbm_first_part,
+ enum t_cose_tbm_payload_mode_t payload_mode,
+ struct q_useful_buf_c payload);
/**
* \brief Create the hash of the to-be-signed (TBS) bytes for COSE.