COSE: Add verification routine of COSE_Mac0

Add verification routine of COSE_Mac0 message structure in
t_cose.
Move the definitions of structure t_cose_parameters and some flags
from t_cose_sign1_verify.h to t_cose_common.h. Thus COSE_Mac0
verification can share those definitions.

Also add HMAC verification functions to verify the tag in
COSE_Mac0.

Change-Id: Icfb69342f183739852ccff101c6fbf8d00395d85
Signed-off-by: David Hu <david.hu@arm.com>
diff --git a/lib/ext/t_cose/CMakeLists.txt b/lib/ext/t_cose/CMakeLists.txt
index 3bf3edf..7b8c560 100644
--- a/lib/ext/t_cose/CMakeLists.txt
+++ b/lib/ext/t_cose/CMakeLists.txt
@@ -46,13 +46,13 @@
 list(APPEND ALL_SRC_C_VERIFY
 	"${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"
-		)
+if (SYMMETRIC_INITIAL_ATTESTATION)
+	list(APPEND ALL_SRC_C_VERIFY "${T_COSE_DIR}/src/t_cose_mac0_verify.c")
+else()
+	list(APPEND ALL_SRC_C_VERIFY "${T_COSE_DIR}/src/t_cose_sign1_verify.c")
 endif()
 
 if (ENABLE_T_COSE_TESTS)
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 c6e8749..f6036f9 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
@@ -451,6 +451,7 @@
            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 :
+           status == PSA_ERROR_INVALID_SIGNATURE   ? T_COSE_ERR_SIG_VERIFY :
                                                      T_COSE_ERR_FAIL;
 }
 
@@ -537,4 +538,63 @@
 
     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_verify_setup(struct t_cose_crypto_hmac *hmac_ctx,
+                                const int                  cose_alg_id,
+                                struct t_cose_key          verify_key)
+{
+    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 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_verify_setup(&hmac_ctx->op_ctx,
+                                   (psa_key_handle_t)verify_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_verify_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);
+}
 #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 0481ac7..c6f2ec6 100644
--- a/lib/ext/t_cose/inc/t_cose_common.h
+++ b/lib/ext/t_cose/inc/t_cose_common.h
@@ -14,6 +14,7 @@
 #define __T_COSE_COMMON_H__
 
 #include <stdint.h>
+#include "q_useful_buf.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -364,6 +365,12 @@
     /** Something is wrong with the crit parameter. */
     T_COSE_ERR_CRIT_PARAMETER = 36,
 
+    /**
+     * When verifying a \c COSE_Mac0, something is wrong with the
+     * format of the CBOR. For example, it is missing something like
+     * the payload.
+     */
+    T_COSE_ERR_MAC0_FORMAT = 37,
 };
 
 
@@ -393,6 +400,41 @@
  */
 #define T_COSE_EMPTY_UINT_CONTENT_TYPE UINT16_MAX+1
 
+/**
+ * The result of parsing a set of COSE header parameters. The pointers
+ * are all back into the COSE structure blob passed in.
+ *
+ * Approximate size on a 64-bit machine is 80 bytes and on a 32-bit
+ * machine is 40.
+ */
+struct t_cose_parameters {
+    /** The algorithm ID. \ref T_COSE_UNSET_ALGORITHM_ID if the algorithm ID
+     * parameter is not present. String type algorithm IDs are not
+     * supported.  See the
+     * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml)
+     * for the algorithms corresponding to the integer values.
+     */
+    int32_t               cose_algorithm_id;
+    /** The COSE key ID. \c NULL_Q_USEFUL_BUF_C if parameter is not
+     * present */
+    struct q_useful_buf_c kid;
+    /** The initialization vector. \c NULL_Q_USEFUL_BUF_C if parameter
+     * is not present */
+    struct q_useful_buf_c iv;
+    /** The partial initialization vector. \c NULL_Q_USEFUL_BUF_C if
+     * parameter is not present */
+    struct q_useful_buf_c partial_iv;
+    /** The content type as a MIME type like
+     * "text/plain". \c NULL_Q_USEFUL_BUF_C if parameter is not present */
+#ifndef T_COSE_DISABLE_CONTENT_TYPE
+    struct q_useful_buf_c content_type_tstr;
+    /** The content type as a CoAP Content-Format
+     * integer. \ref T_COSE_EMPTY_UINT_CONTENT_TYPE if parameter is not
+     * present. Allowed range is 0 to UINT16_MAX per RFC 7252. */
+    uint32_t              content_type_uint;
+#endif /* T_COSE_DISABLE_CONTENT_TYPE */
+};
+
 
 
 
@@ -409,6 +451,42 @@
 #define T_COSE_OPT_OMIT_CBOR_TAG 0x00000002
 
 
+/**
+ * The error \ref T_COSE_ERR_NO_KID is returned if the kid parameter
+ * is missing. Note that the kid parameter is primarily passed on to
+ * the crypto layer so the crypto layer can look up the key. If the
+ * verification key is determined by other than the kid, then it is
+ * fine if there is no kid.
+ */
+#define T_COSE_OPT_REQUIRE_KID 0x00000002
+
+
+/**
+ * Normally this will decode the CBOR presented as a \c COSE_Sign1
+ * or a \c COSE_Mac0 message whether it is tagged using QCBOR tagging
+ * as such or not.
+ * If this option is set, then \ref T_COSE_ERR_INCORRECTLY_TAGGED is
+ * returned if it is not tagged.
+ */
+#define T_COSE_OPT_TAG_REQUIRED  0x00000004
+
+
+/**
+ * This option disables cryptographic signature verification.  With
+ * this option the \c verification_key is not needed.  This is useful
+ * to decode the a COSE message to get the kid (key ID).  The
+ * verification key can be looked up or otherwise obtained by the
+ * caller. Once the key in in hand, the verification function can be
+ * called again to perform the full verification.
+ *
+ * The payload will always be returned whether this is option is given
+ * or not, but it should not be considered secure when this option is
+ * given.
+ *
+ */
+#define T_COSE_OPT_DECODE_ONLY  0x00000008
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/ext/t_cose/inc/t_cose_mac0_verify.h b/lib/ext/t_cose/inc/t_cose_mac0_verify.h
new file mode 100644
index 0000000..1b7c039
--- /dev/null
+++ b/lib/ext/t_cose/inc/t_cose_mac0_verify.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2019, Laurence Lundblade. All rights reserved.
+ * Copyright (c) 2020 Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __T_COSE_MAC0_VERIFY_H_
+#define __T_COSE_MAC0_VERIFY_H_
+
+#include <stdint.h>
+#include "qcbor.h"
+#include "t_cose_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * Context for tag verification.  It is about 24 bytes on a
+ * 64-bit machine and 12 bytes on a 32-bit machine.
+ */
+struct t_cose_mac0_verify_ctx {
+    /* Private data structure */
+    struct t_cose_key     verification_key;
+    int32_t               option_flags;
+};
+
+
+/**
+ * \brief Initialize for \c COSE_Mac0 message verification.
+ *
+ * \param[in,out]  context       The context to initialize.
+ * \param[in]      option_flags  Options controlling the verification.
+ *
+ * This must be called before using the verification context.
+ */
+static void
+t_cose_mac0_verify_init(struct t_cose_mac0_verify_ctx *context,
+                        int32_t                        option_flags);
+
+
+/**
+ * \brief Set key for \c COSE_Mac0 message verification.
+ *
+ * \param[in,out] context      The context of COSE_Mac0 verification
+ * \param[in] verify_key       The verification key to use.
+ *
+ * Look up by kid parameter and fetch the key for MAC verification.
+ * Setup the \ref verify_key structure and fill it in \ref context.
+ */
+static void
+t_cose_mac0_set_verify_key(struct t_cose_mac0_verify_ctx *context,
+                           struct t_cose_key              verify_key);
+
+/**
+ * \brief Verify a COSE_Mac0
+ *
+ * \param[in] context      The context of COSE_Mac0 verification
+ * \param[in] cose_mac0    Pointer and length of CBOR encoded \c COSE_Mac0
+ *                         that is to be verified.
+ * \param[out] payload     Pointer and length of the still CBOR encoded
+ *                         payload
+ *
+ * \return This returns one of the error codes defined by \ref t_cose_err_t.
+ *
+ * Verification involves the following steps.
+ *
+ * The CBOR structure is parsed and verified. It makes sure \c COSE_Mac0
+ * is valid CBOR and that it is tagged as a \c COSE_Mac0.
+ *
+ * The signing algorithm is pulled out of the protected headers.
+ *
+ * The kid (key ID) is parsed out of the unprotected headers if it exists.
+ *
+ * The payload is identified. It doesn't have to be parsed in detail
+ * because it is wrapped in a bstr.
+ *
+ * Finally, the MAC verification is performed if \ref T_COSE_OPT_DECODE_ONLY
+ * is not set in option flag. Otherwise, the verification will be skipped.
+ * The MAC algorithm to use comes from the signing algorithm in the
+ * protected headers.
+ * If the algorithm is not known or not supported this will error out.
+ *
+ * If it is successful, the pointer of the CBOR-encoded payload is
+ * returned.
+ */
+enum t_cose_err_t t_cose_mac0_verify(struct t_cose_mac0_verify_ctx *context,
+                                     struct q_useful_buf_c          cose_mac0,
+                                     struct q_useful_buf_c         *payload,
+                                     struct t_cose_parameters      *parameters);
+
+/* ------------------------------------------------------------------------
+ * Inline implementations of public functions defined above.
+ */
+static inline void
+t_cose_mac0_verify_init(struct t_cose_mac0_verify_ctx *context,
+                        int32_t                        option_flags)
+{
+    context->option_flags = option_flags;
+    context->verification_key = T_COSE_NULL_KEY;
+}
+
+static inline void
+t_cose_mac0_set_verify_key(struct t_cose_mac0_verify_ctx *context,
+                           struct t_cose_key              verify_key)
+{
+    context->verification_key = verify_key;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __T_COSE_MAC0_VERIFY_H_ */
diff --git a/lib/ext/t_cose/inc/t_cose_sign1_verify.h b/lib/ext/t_cose/inc/t_cose_sign1_verify.h
index 11555d7..48ac7c9 100644
--- a/lib/ext/t_cose/inc/t_cose_sign1_verify.h
+++ b/lib/ext/t_cose/inc/t_cose_sign1_verify.h
@@ -52,51 +52,6 @@
 
 
 /**
- * The result of parsing a set of COSE header parameters. The pointers
- * are all back into the \c COSE_Sign1 blob passed in.
- *
- * Approximate size on a 64-bit machine is 80 bytes and on a 32-bit
- * machine is 40.
- */
-struct t_cose_parameters {
-    /** The algorithm ID. \ref T_COSE_UNSET_ALGORITHM_ID if the algorithm ID
-     * parameter is not present. String type algorithm IDs are not
-     * supported.  See the
-     * [IANA COSE Registry](https://www.iana.org/assignments/cose/cose.xhtml)
-     * for the algorithms corresponding to the integer values.
-     */
-    int32_t               cose_algorithm_id;
-    /** The COSE key ID. \c NULL_Q_USEFUL_BUF_C if parameter is not
-     * present */
-    struct q_useful_buf_c kid;
-    /** The initialization vector. \c NULL_Q_USEFUL_BUF_C if parameter
-     * is not present */
-    struct q_useful_buf_c iv;
-    /** The partial initialization vector. \c NULL_Q_USEFUL_BUF_C if
-     * parameter is not present */
-    struct q_useful_buf_c partial_iv;
-    /** The content type as a MIME type like
-     * "text/plain". \c NULL_Q_USEFUL_BUF_C if parameter is not present */
-#ifndef T_COSE_DISABLE_CONTENT_TYPE
-    struct q_useful_buf_c content_type_tstr;
-    /** The content type as a CoAP Content-Format
-     * integer. \ref T_COSE_EMPTY_UINT_CONTENT_TYPE if parameter is not
-     * present. Allowed range is 0 to UINT16_MAX per RFC 7252. */
-    uint32_t              content_type_uint;
-#endif /* T_COSE_DISABLE_CONTENT_TYPE */
-};
-
-
-/**
- * A special COSE algorithm ID that indicates no COSE algorithm ID or an unset
- * COSE algorithm ID.
- */
-#define T_COSE_UNSET_ALGORITHM_ID 0
-
-
-
-
-/**
  * Pass this as \c option_flags to allow verification of short-circuit
  * signatures. This should only be used as a test mode as
  * short-circuit signatures are not secure.
@@ -106,43 +61,6 @@
 #define T_COSE_OPT_ALLOW_SHORT_CIRCUIT 0x00000001
 
 
-/**
- * The error \ref T_COSE_ERR_NO_KID is returned if the kid parameter
- * is missing. Note that the kid parameter is primarily passed on to
- * the crypto layer so the crypto layer can look up the key. If the
- * verification key is determined by other than the kid, then it is
- * fine if there is no kid.
- */
-#define T_COSE_OPT_REQUIRE_KID 0x00000002
-
-
-/**
- * Normally this will decode the CBOR presented as a \c COSE_Sign1
- * message whether it is tagged using QCBOR tagging as such or not.
- * If this option is set, then \ref T_COSE_ERR_INCORRECTLY_TAGGED is
- * returned if it is not tagged.
- */
-#define T_COSE_OPT_TAG_REQUIRED  0x00000004
-
-
-/**
- * See t_cose_sign1_set_verification_key().
- *
- * This option disables cryptographic signature verification.  With
- * this option the \c verification_key is not needed.  This is useful
- * to decode the \c COSE_Sign1 message to get the kid (key ID).  The
- * verification key can be looked up or otherwise obtained by the
- * caller. Once the key in in hand, t_cose_sign1_verify() can be
- * called again to perform the full verification.
- *
- * The payload will always be returned whether this is option is given
- * or not, but it should not be considered secure when this option is
- * given.
- *
- */
-#define T_COSE_OPT_DECODE_ONLY  0x00000008
-
-
 
 /**
  * Context for signature verification.  It is about 24 bytes on a
diff --git a/lib/ext/t_cose/src/t_cose_crypto.h b/lib/ext/t_cose/src/t_cose_crypto.h
index 80263a9..8c98c48 100644
--- a/lib/ext/t_cose/src/t_cose_crypto.h
+++ b/lib/ext/t_cose/src/t_cose_crypto.h
@@ -604,6 +604,46 @@
                                struct q_useful_buf_c     *tag);
 
 /**
+ * \brief Set up a multipart HMAC verification operation
+ *
+ * \param[in,out] hmac_ctx           Pointer to the HMAC context.
+ * \param[in] cose_alg_id            The algorithm used in HMAC.
+ * \param[in] verify_key             Key for HMAC verification
+ *
+ * \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_verify_setup(struct t_cose_crypto_hmac *hmac_ctx,
+                                const int                  cose_alg_id,
+                                struct t_cose_key          verify_key);
+
+/**
+ * \brief Finish the verification 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 verification failed.
+ */
+enum t_cose_err_t
+t_cose_crypto_hmac_verify_finish(struct t_cose_crypto_hmac *hmac_ctx,
+                                 struct q_useful_buf_c      tag);
+
+/**
  * \brief Indicate whether a COSE algorithm is ECDSA or not.
  *
  * \param[in] cose_algorithm_id    The algorithm ID to check.
diff --git a/lib/ext/t_cose/src/t_cose_mac0_verify.c b/lib/ext/t_cose/src/t_cose_mac0_verify.c
new file mode 100644
index 0000000..ce47bb6
--- /dev/null
+++ b/lib/ext/t_cose/src/t_cose_mac0_verify.c
@@ -0,0 +1,185 @@
+/*
+ * 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_verify.h"
+#include "t_cose_parameters.h"
+#include "t_cose_util.h"
+
+/**
+ * \file t_cose_mac0_verify.c
+ *
+ * \brief This verifies t_cose Mac authentication structure without a recipient
+ *        structure.
+ *        Only HMAC is supported so far.
+ */
+
+/*
+ * Public function. See t_cose_mac0.h
+ */
+enum t_cose_err_t t_cose_mac0_verify(struct t_cose_mac0_verify_ctx *context,
+                                     struct q_useful_buf_c          cose_mac0,
+                                     struct q_useful_buf_c         *payload,
+                                     struct t_cose_parameters      *parameters)
+{
+    QCBORDecodeContext            decode_context;
+    QCBORItem                     item;
+    struct q_useful_buf_c         protected_parameters;
+    struct t_cose_parameters      parsed_protected_parameters;
+    struct t_cose_parameters      unprotected_parameters;
+    struct t_cose_label_list      critical_labels;
+    struct t_cose_label_list      unknown_labels;
+    enum t_cose_err_t             return_value;
+    struct q_useful_buf_c         tag;
+    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;
+
+    *payload = NULL_Q_USEFUL_BUF_C;
+
+    QCBORDecode_Init(&decode_context, cose_mac0, QCBOR_DECODE_MODE_NORMAL);
+    /* Calls to QCBORDecode_GetNext() rely on item.uDataType != QCBOR_TYPE_ARRAY
+     * to detect decoding errors rather than checking the return code.
+     */
+
+    /* --  The array of four -- */
+    (void)QCBORDecode_GetNext(&decode_context, &item);
+    if(item.uDataType != QCBOR_TYPE_ARRAY) {
+        return_value = T_COSE_ERR_MAC0_FORMAT;
+        goto Done;
+    }
+
+    if((context->option_flags & T_COSE_OPT_TAG_REQUIRED) &&
+       !QCBORDecode_IsTagged(&decode_context, &item, CBOR_TAG_COSE_MAC0)) {
+        return_value = T_COSE_ERR_INCORRECTLY_TAGGED;
+        goto Done;
+    }
+
+    /* -- Clear list where unknown labels are accumulated -- */
+    clear_label_list(&unknown_labels);
+
+    /* --  Get the protected header parameters -- */
+    (void)QCBORDecode_GetNext(&decode_context, &item);
+    if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+        return_value = T_COSE_ERR_MAC0_FORMAT;
+        goto Done;
+    }
+
+    protected_parameters = item.val.string;
+
+    return_value = parse_protected_header_parameters(protected_parameters,
+                                                   &parsed_protected_parameters,
+                                                   &critical_labels,
+                                                   &unknown_labels);
+    if(return_value != T_COSE_SUCCESS) {
+        goto Done;
+    }
+
+    /* --  Get the unprotected parameters -- */
+    return_value = parse_unprotected_header_parameters(&decode_context,
+                                                       &unprotected_parameters,
+                                                       &unknown_labels);
+    if(return_value != T_COSE_SUCCESS) {
+        goto Done;
+    }
+    if((context->option_flags & T_COSE_OPT_REQUIRE_KID) &&
+        q_useful_buf_c_is_null(unprotected_parameters.kid)) {
+        return_value = T_COSE_ERR_NO_KID;
+        goto Done;
+    }
+
+    /* -- Check critical parameter labels -- */
+    return_value = check_critical_labels(&critical_labels, &unknown_labels);
+    if(return_value != T_COSE_SUCCESS) {
+        goto Done;
+    }
+
+    /* -- Check for duplicate parameters and copy to returned parameters -- */
+    return_value = check_and_copy_parameters(&parsed_protected_parameters,
+                                             &unprotected_parameters,
+                                             parameters);
+    if(return_value != T_COSE_SUCCESS) {
+        goto Done;
+    }
+
+    /* -- Get the payload -- */
+    QCBORDecode_GetNext(&decode_context, &item);
+    if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+        return_value = T_COSE_ERR_MAC0_FORMAT;
+        goto Done;
+    }
+    *payload = item.val.string;
+
+    /* -- Get the tag -- */
+    QCBORDecode_GetNext(&decode_context, &item);
+    if(item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+        return_value = T_COSE_ERR_MAC0_FORMAT;
+        goto Done;
+    }
+    tag = item.val.string;
+
+    /* -- Finish up the CBOR decode -- */
+    /* This check make sure the array only had the expected four
+     * items. Works for definite and indefinite length arrays. Also
+     * make sure there were no extra bytes.
+     */
+    if(QCBORDecode_Finish(&decode_context) != QCBOR_SUCCESS) {
+        return_value = T_COSE_ERR_CBOR_NOT_WELL_FORMED;
+        goto Done;
+    }
+
+    /* -- Skip tag verification if such is requested --*/
+    if(context->option_flags & T_COSE_OPT_DECODE_ONLY) {
+        return_value = T_COSE_SUCCESS;
+        goto Done;
+    }
+
+    /* -- Compute the ToBeMaced -- */
+    return_value = create_tbm(tbm_first_part_buf,
+                              protected_parameters,
+                              &tbm_first_part,
+                              T_COSE_TBM_BARE_PAYLOAD,
+                              *payload);
+    if(return_value) {
+        goto Done;
+    }
+
+    /*
+     * Start the HMAC verification.
+     * 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_verify_setup(&hmac_ctx,
+                                  parsed_protected_parameters.cose_algorithm_id,
+                                  context->verification_key);
+    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;
+    }
+
+    return_value = t_cose_crypto_hmac_update(&hmac_ctx, *payload);
+    if(return_value) {
+        goto Done;
+    }
+
+    return_value = t_cose_crypto_hmac_verify_finish(&hmac_ctx, tag);
+
+Done:
+    return return_value;
+}
diff --git a/lib/ext/t_cose/src/t_cose_parameters.h b/lib/ext/t_cose/src/t_cose_parameters.h
index 8a17cd2..b51e861 100644
--- a/lib/ext/t_cose/src/t_cose_parameters.h
+++ b/lib/ext/t_cose/src/t_cose_parameters.h
@@ -2,6 +2,7 @@
  * t_cose_parameters.h
  *
  * Copyright 2019, Laurence Lundblade
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -12,7 +13,6 @@
 #ifndef t_cose_parameters_h
 #define t_cose_parameters_h
 
-#include "t_cose_sign1_verify.h"
 #include "q_useful_buf.h"
 #include "t_cose_common.h"
 #include <stdint.h>
@@ -58,6 +58,13 @@
 
 
 /**
+ * A special COSE algorithm ID that indicates no COSE algorithm ID or an unset
+ * COSE algorithm ID.
+ */
+#define T_COSE_UNSET_ALGORITHM_ID 0
+
+
+/**
  * \brief Clear a label list to empty.
  *
  * \param[in,out] list The list to clear.