aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorDavid Hu <david.hu@arm.com>2020-01-26 15:28:51 +0800
committerDavid Hu <david.hu@arm.com>2020-06-22 02:33:00 +0000
commitb835f4d199c808265895bb39a32e630c05be8db4 (patch)
treebfda92066d792850039536f522d2446ca325bd9c /test
parent6d2bc65f3fbc215eae6116228902c9c4e65e5a43 (diff)
downloadtrusted-firmware-m-b835f4d199c808265895bb39a32e630c05be8db4.tar.gz
Test: Enable symmetric Initial Attestation decoding
Enable the token decoding process in symmetric key algorithm based Initial Attestation for test. In build type Debug, the symmetric IAK handle is fetched to verify the tag of the generated token, in secure side. Change-Id: I8e3175e5e3586ad80940d5ee9338f9dfc568a1b7 Signed-off-by: David Hu <david.hu@arm.com>
Diffstat (limited to 'test')
-rw-r--r--test/suites/attestation/CMakeLists.inc2
-rw-r--r--test/suites/attestation/attest_symmetric_iat_decode.c159
-rw-r--r--test/suites/attestation/attest_token_decode.c667
-rw-r--r--test/suites/attestation/attest_token_decode.h89
-rw-r--r--test/suites/attestation/attest_token_decode_common.c601
5 files changed, 852 insertions, 666 deletions
diff --git a/test/suites/attestation/CMakeLists.inc b/test/suites/attestation/CMakeLists.inc
index 4c9478f462..f761640e58 100644
--- a/test/suites/attestation/CMakeLists.inc
+++ b/test/suites/attestation/CMakeLists.inc
@@ -38,6 +38,7 @@ elseif(ENABLE_ATTESTATION_SERVICE_TESTS)
list(APPEND ATTEST_TEST_SRC_S
"${ATTESTATION_TEST_DIR}/secure/attestation_s_interface_testsuite.c"
"${ATTESTATION_TEST_DIR}/attest_token_test.c"
+ "${ATTESTATION_TEST_DIR}/attest_token_decode_common.c"
"${ATTESTATION_TEST_DIR}/attest_token_decode.c"
"${ATTESTATION_TEST_DIR}/attest_public_key.c"
"${TFM_ROOT_DIR}/lib/ext/qcbor/util/qcbor_util.c"
@@ -46,6 +47,7 @@ elseif(ENABLE_ATTESTATION_SERVICE_TESTS)
list(APPEND ATTEST_TEST_SRC_NS
"${ATTESTATION_TEST_DIR}/non_secure/attestation_ns_interface_testsuite.c"
"${ATTESTATION_TEST_DIR}/attest_token_test.c"
+ "${ATTESTATION_TEST_DIR}/attest_token_decode_common.c"
"${ATTESTATION_TEST_DIR}/attest_token_decode.c"
"${ATTESTATION_TEST_DIR}/attest_public_key.c"
"${TFM_ROOT_DIR}/lib/ext/qcbor/util/qcbor_util.c"
diff --git a/test/suites/attestation/attest_symmetric_iat_decode.c b/test/suites/attestation/attest_symmetric_iat_decode.c
new file mode 100644
index 0000000000..69c32b0f7d
--- /dev/null
+++ b/test/suites/attestation/attest_symmetric_iat_decode.c
@@ -0,0 +1,159 @@
+/*
+ * attest_symmetric_iat_decode.c
+ *
+ * Copyright (c) 2019, Laurence Lundblade.
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+#include "attest_token_decode.h"
+#include "attestation.h"
+#include "psa/crypto.h"
+#include "q_useful_buf.h"
+#include "qcbor_util.h"
+#include "t_cose_common.h"
+#include "t_cose_mac0_verify.h"
+#include "tfm_plat_crypto_keys.h"
+
+/* Only support HMAC as MAC algorithm in COSE_Mac0 so far */
+#define SYMMETRIC_IAK_MAX_SIZE PSA_MAC_MAX_SIZE
+
+#if DOMAIN_NS == 1U
+/*
+ * Public function. See attest_token_decode.h
+ * It is not allowed to let NS side fetch the symmetric IAK and perform the MAC
+ * verification.
+ */
+enum attest_token_err_t
+attest_token_decode_validate_token(struct attest_token_decode_context *me,
+ struct q_useful_buf_c token)
+{
+ enum t_cose_err_t t_cose_error;
+ enum attest_token_err_t return_value;
+ /* Decode only without signature verification */
+ int32_t t_cose_options = T_COSE_OPT_DECODE_ONLY;
+ struct t_cose_mac0_verify_ctx verify_ctx;
+ struct t_cose_key attest_key = T_COSE_NULL_KEY;
+
+ t_cose_mac0_verify_init(&verify_ctx, t_cose_options);
+
+ t_cose_mac0_set_verify_key(&verify_ctx, attest_key);
+
+ t_cose_error = t_cose_mac0_verify(&verify_ctx,
+ token, /* COSE to verify */
+ &me->payload, /* Payload from token */
+ NULL
+ );
+
+ return_value = map_t_cose_errors(t_cose_error);
+ me->last_error = return_value;
+
+ return return_value;
+}
+#else /* DOMAIN_NS == 1U */
+/*
+ * \note The symmetric Initial Attestation key (IAK) will be fetched for
+ * authentication tag verification in secure test cases.
+ * Authentication tag verification in tests is for debug purpose only.
+ * Do not fetch the IAK outside attestation service in real products.
+ */
+static inline enum attest_token_err_t
+decode_register_verify_key(psa_key_handle_t *verify_key_handle)
+{
+ uint8_t key_buf[SYMMETRIC_IAK_MAX_SIZE];
+ psa_algorithm_t key_alg;
+ psa_key_handle_t key_handle;
+ size_t key_len;
+ enum tfm_plat_err_t plat_res;
+ psa_status_t psa_res;
+ psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
+
+ /* Get the symmetric initial attestation key for HMAC operation */
+ plat_res = tfm_plat_get_symmetric_iak(key_buf, sizeof(key_buf),
+ &key_len, &key_alg);
+ if (plat_res != TFM_PLAT_ERR_SUCCESS) {
+ return ATTEST_TOKEN_ERR_VERIFICATION_KEY;
+ }
+
+ /*
+ * Verify if HMAC algorithm is valid.
+ * According to COSE (RFC 8152), only SHA-256, SHA-384 and SHA-512 are
+ * supported in HMAC.
+ */
+ if ((key_alg != PSA_ALG_HMAC(PSA_ALG_SHA_256)) && \
+ (key_alg != PSA_ALG_HMAC(PSA_ALG_SHA_384)) && \
+ (key_alg != PSA_ALG_HMAC(PSA_ALG_SHA_512))) {
+ return ATTEST_TOKEN_ERR_VERIFICATION_KEY;
+ }
+
+ /* Setup the key attributes */
+ psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_VERIFY);
+ psa_set_key_algorithm(&key_attributes, key_alg);
+ psa_set_key_type(&key_attributes, PSA_KEY_TYPE_HMAC);
+
+ /* Register the symmetric key to Crypto service */
+ psa_res = psa_import_key(&key_attributes, key_buf, key_len, &key_handle);
+ if (psa_res != PSA_SUCCESS) {
+ return ATTEST_TOKEN_ERR_VERIFICATION_KEY;
+ }
+
+ *verify_key_handle = key_handle;
+
+ return ATTEST_TOKEN_ERR_SUCCESS;
+}
+
+static inline enum attest_token_err_t
+decode_unregister_verify_key(psa_key_handle_t verify_key_handle)
+{
+ psa_status_t status;
+
+ status = psa_destroy_key(verify_key_handle);
+ if (status == PSA_SUCCESS) {
+ return ATTEST_TOKEN_ERR_SUCCESS;
+ }
+
+ return ATTEST_TOKEN_ERR_GENERAL;
+}
+
+/*
+ * Public function. See attest_token_decode.h
+ * Decode the received COSE_Mac0 structure and verify the tag.
+ */
+enum attest_token_err_t
+attest_token_decode_validate_token(struct attest_token_decode_context *me,
+ struct q_useful_buf_c token)
+{
+ enum t_cose_err_t t_cose_error;
+ enum attest_token_err_t return_value;
+ int32_t t_cose_options = 0;
+ struct t_cose_mac0_verify_ctx verify_ctx;
+ struct t_cose_key attest_key;
+ psa_key_handle_t key_handle;
+
+ return_value = decode_register_verify_key(&key_handle);
+ if (return_value != ATTEST_TOKEN_ERR_SUCCESS) {
+ return return_value;
+ }
+
+ t_cose_mac0_verify_init(&verify_ctx, t_cose_options);
+
+ attest_key.crypto_lib = T_COSE_CRYPTO_LIB_PSA;
+ attest_key.k.key_handle = (uint64_t)key_handle;
+ t_cose_mac0_set_verify_key(&verify_ctx, attest_key);
+
+ t_cose_error = t_cose_mac0_verify(&verify_ctx,
+ token, /* COSE to verify */
+ &me->payload, /* Payload from token */
+ NULL);
+
+ return_value = map_t_cose_errors(t_cose_error);
+ me->last_error = return_value;
+
+ decode_unregister_verify_key(key_handle);
+
+ return return_value;
+}
+#endif /* DOMAIN_NS == 1U */
diff --git a/test/suites/attestation/attest_token_decode.c b/test/suites/attestation/attest_token_decode.c
index 18fef5e073..90fbcf5299 100644
--- a/test/suites/attestation/attest_token_decode.c
+++ b/test/suites/attestation/attest_token_decode.c
@@ -20,129 +20,8 @@
/**
* \file attest_token_decode.c
*
- * \brief Attestation token decoder.
- *
- * This decodes and verifies an attestation token giving access to the
- * data items in the token. The data items are also known as claims.
- *
- * This is written primarily as tests for the token encoder, though it
- * close to a full commercial token decoder. The main thing missing is
- * a thorough test suite for it. Test before commercial use is
- * important as this is a parser / decoder and thus subject to attack
- * by malicious input. It does however, use QCBOR for most base
- * parsing, and QCBOR is thoroughly tested and commercial.
- *
- * This is oriented around the Arm-defined initial attestation token.
- *
- * \c uint_fast8_t is used for type and nest levels. They are
- * 8-bit quantities, but making using uint8_t variables
- * and parameters can result in bigger, slower code.
- * \c uint_fast8_t is part of \c <stdint.h>. It is not
- * used in structures where it is more important to keep
- * the size smaller.
- */
-
-
-/**
- * Compute the bit indicating a claim is present
+ * \brief Attestation token decoder for COSE_Sign1.
*/
-#define CLAIM_PRESENT_BIT(item_index) (0x01U << (item_index))
-
-
-/*
- * Public function. See attest_token_decode.h
- */
-void attest_token_decode_init(struct attest_token_decode_context *me,
- uint32_t options)
-{
- memset(me, 0, sizeof(struct attest_token_decode_context));
- me->options = options;
- me->last_error = ATTEST_TOKEN_ERR_NO_VALID_TOKEN;
-}
-
-
-/**
-
- \brief Map t_cose errors into attestation token errors
-
- \param[in] t_cose_error The t_cose error to map
-
- \return The attestation token error.
- */
-static inline enum attest_token_err_t
-map_t_cose_errors(enum t_cose_err_t t_cose_error)
-{
- switch (t_cose_error) {
- case T_COSE_SUCCESS:
- return ATTEST_TOKEN_ERR_SUCCESS;
- break;
- case T_COSE_ERR_UNSUPPORTED_SIGNING_ALG:
- return ATTEST_TOKEN_ERR_UNSUPPORTED_SIG_ALG;
- break;
- case T_COSE_ERR_UNSUPPORTED_HASH:
- return ATTEST_TOKEN_ERR_HASH_UNAVAILABLE;
- break;
- case T_COSE_ERR_CBOR_NOT_WELL_FORMED:
- return ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED;
- break;
- case T_COSE_ERR_INSUFFICIENT_MEMORY:
- return ATTEST_TOKEN_ERR_INSUFFICIENT_MEMORY;
- break;
- case T_COSE_ERR_TAMPERING_DETECTED:
- return ATTEST_TOKEN_ERR_TAMPERING_DETECTED;
- break;
- case T_COSE_ERR_CBOR_FORMATTING:
- return ATTEST_TOKEN_ERR_CBOR_FORMATTING;
- break;
- case T_COSE_ERR_TOO_SMALL:
- return ATTEST_TOKEN_ERR_TOO_SMALL;
- break;
-
- case T_COSE_ERR_PARAMETER_CBOR:
- case T_COSE_ERR_NON_INTEGER_ALG_ID:
- return ATTEST_TOKEN_ERR_CBOR_STRUCTURE;
- break;
-
- case T_COSE_ERR_SIG_VERIFY:
- case T_COSE_ERR_SHORT_CIRCUIT_SIG:
- return ATTEST_TOKEN_ERR_COSE_SIGN1_VALIDATION;
- break;
-
- case T_COSE_ERR_SIGN1_FORMAT:
- case T_COSE_ERR_NO_ALG_ID:
- case T_COSE_ERR_NO_KID:
- case T_COSE_ERR_BAD_SHORT_CIRCUIT_KID:
- case T_COSE_ERR_SIG_STRUCT:
- return ATTEST_TOKEN_ERR_COSE_SIGN1_FORMAT;
- break;
-
- case T_COSE_ERR_UNKNOWN_KEY:
- case T_COSE_ERR_WRONG_TYPE_OF_KEY:
- return ATTEST_TOKEN_ERR_VERIFICATION_KEY;
- break;
-
- case T_COSE_ERR_MAKING_PROTECTED:
- case T_COSE_ERR_HASH_GENERAL_FAIL:
- case T_COSE_ERR_HASH_BUFFER_SIZE:
- case T_COSE_ERR_SIG_BUFFER_SIZE:
- case T_COSE_ERR_INVALID_ARGUMENT:
- case T_COSE_ERR_FAIL:
- case T_COSE_ERR_SIG_FAIL:
- case T_COSE_ERR_TOO_MANY_PARAMETERS:
- case T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER:
- case T_COSE_ERR_SHORT_CIRCUIT_SIG_DISABLED:
- case T_COSE_ERR_INCORRECT_KEY_FOR_LIB:
- case T_COSE_ERR_BAD_CONTENT_TYPE:
- case T_COSE_ERR_INCORRECTLY_TAGGED:
- case T_COSE_ERR_EMPTY_KEY:
- case T_COSE_ERR_DUPLICATE_PARAMETER:
- case T_COSE_ERR_PARAMETER_NOT_PROTECTED:
- case T_COSE_ERR_CRIT_PARAMETER:
- default:
- return ATTEST_TOKEN_ERR_GENERAL;
- }
-}
-
/*
* Public function. See attest_token_decode.h
@@ -190,547 +69,3 @@ attest_token_decode_validate_token(struct attest_token_decode_context *me,
return return_value;
}
-
-
-/*
- * Public function. See attest_token_decode.h
- */
-enum attest_token_err_t
-attest_token_decode_get_bstr(struct attest_token_decode_context *me,
- int32_t label,
- struct q_useful_buf_c *claim)
-{
- enum attest_token_err_t return_value;
- QCBORItem item;
-
- if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
- return_value = me->last_error;
- *claim = NULL_Q_USEFUL_BUF_C;
- goto Done;
- }
-
- return_value = qcbor_util_get_top_level_item_in_map(me->payload,
- label,
- QCBOR_TYPE_BYTE_STRING,
- &item);
- if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
- goto Done;
- }
-
- *claim = item.val.string;
-
-Done:
- return return_value;
-}
-
-
-/*
- * Public function. See attest_token_decode.h
- */
-enum attest_token_err_t
-attest_token_decode_get_tstr(struct attest_token_decode_context *me,
- int32_t label,
- struct q_useful_buf_c *claim)
-{
- enum attest_token_err_t return_value;
- QCBORItem item;
-
- if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
- return_value = me->last_error;
- *claim = NULL_Q_USEFUL_BUF_C;
- goto Done;
- }
-
- return_value = qcbor_util_get_top_level_item_in_map(me->payload,
- label,
- QCBOR_TYPE_TEXT_STRING,
- &item);
- if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
- goto Done;
- }
-
- *claim = item.val.string;
-
-Done:
- return return_value;
-}
-
-
-/*
- * Public function. See attest_token_decode.h
- */
-enum attest_token_err_t
-attest_token_decode_get_int(struct attest_token_decode_context *me,
- int32_t label,
- int64_t *integer)
-{
- enum attest_token_err_t return_value;
- QCBORItem item;
- QCBORDecodeContext decode_context;
-
- if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
- return_value = me->last_error;
- *integer = 0;
- goto Done;
- }
-
- QCBORDecode_Init(&decode_context, me->payload, QCBOR_DECODE_MODE_NORMAL);
-
- return_value = qcbor_util_get_item_in_map(&decode_context,
- label,
- &item);
- if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
- goto Done;
- }
-
- if(QCBORDecode_Finish(&decode_context)) {
- return_value = ATTEST_TOKEN_ERR_CBOR_STRUCTURE;
- }
-
- if(item.uDataType == QCBOR_TYPE_INT64) {
- *integer = item.val.int64;
- } else if(item.uDataType == QCBOR_TYPE_UINT64) {
- if(item.val.uint64 < INT64_MAX) {
- *integer = (int64_t)item.val.uint64;
- } else {
- return_value = ATTEST_TOKEN_ERR_INTEGER_VALUE;
- }
- } else {
- return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
- }
-
-Done:
- return return_value;
-}
-
-
-/*
- * Public function. See attest_token_decode.h
- */
-enum attest_token_err_t
-attest_token_decode_get_uint(struct attest_token_decode_context *me,
- int32_t label,
- uint64_t *integer)
-{
- enum attest_token_err_t return_value;
- QCBORItem item;
- QCBORDecodeContext decode_context;
-
- if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
- return_value = me->last_error;
- *integer = 0;
- goto Done;
- }
-
- QCBORDecode_Init(&decode_context, me->payload, QCBOR_DECODE_MODE_NORMAL);
-
- return_value = qcbor_util_get_item_in_map(&decode_context,
- label,
- &item);
- if(return_value != 0) {
- goto Done;
- }
-
- if(QCBORDecode_Finish(&decode_context)) {
- return_value = ATTEST_TOKEN_ERR_CBOR_STRUCTURE;
- }
-
- if(item.uDataType == QCBOR_TYPE_UINT64) {
- *integer = item.val.uint64;
- } else if(item.uDataType == QCBOR_TYPE_INT64) {
- if(item.val.int64 >= 0) {
- *integer = (uint64_t)item.val.int64;
- } else {
- return_value = ATTEST_TOKEN_ERR_INTEGER_VALUE;
- }
- } else {
- return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
- }
-
-Done:
- return return_value;
-}
-
-
-/*
- * Public function. See attest_token_decode.h
- */
-enum attest_token_err_t
-attest_token_decode_get_payload(struct attest_token_decode_context *me,
- struct q_useful_buf_c *payload)
-{
- enum attest_token_err_t return_value;
-
- if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
- return_value = me->last_error;
- *payload = NULL_Q_USEFUL_BUF_C;
- goto Done;
- }
-
- if(q_useful_buf_c_is_null_or_empty(me->payload)) {
- return_value = ATTEST_TOKEN_ERR_NO_VALID_TOKEN;
- goto Done;
- }
-
- *payload = me->payload;
- return_value = ATTEST_TOKEN_ERR_SUCCESS;
-
-Done:
- return return_value;
-}
-
-
-/*
- * Public function. See attest_token_decode.h
- */
-enum attest_token_err_t
-attest_token_decode_get_iat_simple(struct attest_token_decode_context *me,
- struct attest_token_iat_simple_t *items)
-{
- struct qcbor_util_items_to_get_t list[NUMBER_OF_ITEMS+1];
- QCBORDecodeContext decode_context;
- int64_t client_id_64;
- enum attest_token_err_t return_value;
-
- /* Set all q_useful_bufs to NULL and flags to 0 */
- memset(items, 0, sizeof(struct attest_token_iat_simple_t));
-
- /* Re use flags as array indexes because it works nicely */
- list[NONCE_FLAG].label = EAT_CBOR_ARM_LABEL_CHALLENGE;
- list[UEID_FLAG].label = EAT_CBOR_ARM_LABEL_UEID;
- list[BOOT_SEED_FLAG].label = EAT_CBOR_ARM_LABEL_BOOT_SEED;
- list[HW_VERSION_FLAG].label = EAT_CBOR_ARM_LABEL_HW_VERSION;
- list[IMPLEMENTATION_ID_FLAG].label = EAT_CBOR_ARM_LABEL_IMPLEMENTATION_ID;
- list[CLIENT_ID_FLAG].label = EAT_CBOR_ARM_LABEL_CLIENT_ID;
- list[SECURITY_LIFECYCLE_FLAG].label = EAT_CBOR_ARM_LABEL_SECURITY_LIFECYCLE;
- list[PROFILE_DEFINITION_FLAG].label = EAT_CBOR_ARM_LABEL_PROFILE_DEFINITION;
- list[ORIGINATION_FLAG].label = EAT_CBOR_ARM_LABEL_ORIGINATION;
- list[NUMBER_OF_ITEMS].label = 0; /* terminate the list. */
-
- if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
- return_value = me->last_error;
- goto Done;
- }
-
- QCBORDecode_Init(&decode_context, me->payload, QCBOR_DECODE_MODE_NORMAL);
-
- return_value = qcbor_util_get_items_in_map(&decode_context,
- list);
- if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
- goto Done;
- }
-
- /* ---- NONCE ---- */
- if(list[NONCE_FLAG].item.uDataType == QCBOR_TYPE_BYTE_STRING) {
- items->nonce = list[NONCE_FLAG].item.val.string;
- items->item_flags |= CLAIM_PRESENT_BIT(NONCE_FLAG);
- }
-
- /* ---- UEID -------*/
- if(list[UEID_FLAG].item.uDataType == QCBOR_TYPE_BYTE_STRING) {
- items->ueid = list[UEID_FLAG].item.val.string;
- items->item_flags |= CLAIM_PRESENT_BIT(UEID_FLAG);
- }
-
- /* ---- BOOT SEED -------*/
- if(list[BOOT_SEED_FLAG].item.uDataType == QCBOR_TYPE_BYTE_STRING) {
- items->boot_seed = list[BOOT_SEED_FLAG].item.val.string;
- items->item_flags |= CLAIM_PRESENT_BIT(BOOT_SEED_FLAG);\
- }
-
- /* ---- HW VERSION -------*/
- if(list[HW_VERSION_FLAG].item.uDataType == QCBOR_TYPE_TEXT_STRING) {
- items->hw_version = list[HW_VERSION_FLAG].item.val.string;
- items->item_flags |= CLAIM_PRESENT_BIT(HW_VERSION_FLAG);
-
- }
-
- /* ----IMPLEMENTATION ID -------*/
- if(list[IMPLEMENTATION_ID_FLAG].item.uDataType == QCBOR_TYPE_BYTE_STRING) {
- items->implementation_id = list[IMPLEMENTATION_ID_FLAG].item.val.string;
- items->item_flags |= CLAIM_PRESENT_BIT(IMPLEMENTATION_ID_FLAG);
- }
-
- /* ----CLIENT ID -------*/
- if(list[CLIENT_ID_FLAG].item.uDataType == QCBOR_TYPE_INT64) {
- client_id_64 = list[CLIENT_ID_FLAG].item.val.int64;
- if(client_id_64 < INT32_MAX || client_id_64 > INT32_MIN) {
- items->client_id = (int32_t)client_id_64;
- items->item_flags |= CLAIM_PRESENT_BIT(CLIENT_ID_FLAG);
- }
- }
-
- /* ----SECURITY LIFECYCLE -------*/
- if(list[SECURITY_LIFECYCLE_FLAG].item.uDataType == QCBOR_TYPE_INT64) {
- if(list[SECURITY_LIFECYCLE_FLAG].item.val.int64 < UINT32_MAX) {
- items->security_lifecycle =
- (uint32_t)list[SECURITY_LIFECYCLE_FLAG].item.val.int64;
- items->item_flags |=CLAIM_PRESENT_BIT(SECURITY_LIFECYCLE_FLAG);
- }
- }
-
- /* ---- PROFILE_DEFINITION -------*/
- if(list[PROFILE_DEFINITION_FLAG].item.uDataType == QCBOR_TYPE_TEXT_STRING) {
- items->profile_definition=list[PROFILE_DEFINITION_FLAG].item.val.string;
- items->item_flags |= CLAIM_PRESENT_BIT(PROFILE_DEFINITION_FLAG);
- }
-
- /* ---- ORIGINATION -------*/
- if(list[ORIGINATION_FLAG].item.uDataType == QCBOR_TYPE_TEXT_STRING) {
- items->origination = list[ORIGINATION_FLAG].item.val.string;
- items->item_flags |= CLAIM_PRESENT_BIT(ORIGINATION_FLAG);
- }
-
-Done:
- return return_value;
-}
-
-
-/*
- * Public function. See attest_token_decode.h
- */
-enum attest_token_err_t
-attest_token_get_num_sw_components(struct attest_token_decode_context *me,
- uint32_t *num_sw_components)
-{
- enum attest_token_err_t return_value;
- QCBORItem item;
-
- if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
- return_value = me->last_error;
- goto Done;
- }
-
- return_value = qcbor_util_get_top_level_item_in_map(me->payload,
- EAT_CBOR_ARM_LABEL_SW_COMPONENTS,
- QCBOR_TYPE_ARRAY,
- &item);
- if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
- if(return_value != ATTEST_TOKEN_ERR_NOT_FOUND) {
- /* Something very wrong. Bail out passing on the return_value */
- goto Done;
- } else {
- /* Now decide if it was intentionally left out. */
- return_value = qcbor_util_get_top_level_item_in_map(me->payload,
- EAT_CBOR_ARM_LABEL_NO_SW_COMPONENTS,
- QCBOR_TYPE_INT64,
- &item);
- if(return_value == ATTEST_TOKEN_ERR_SUCCESS) {
- if(item.val.int64 == NO_SW_COMPONENT_FIXED_VALUE) {
- /* Successful omission of SW components. Pass on the
- * success return_value */
- *num_sw_components = 0;
- } else {
- /* Indicator for no SW components malformed */
- return_value = ATTEST_TOKEN_ERR_SW_COMPONENTS_MISSING;
- }
- } else if(return_value == ATTEST_TOKEN_ERR_NOT_FOUND) {
- /* Should have been an indicator for no SW components */
- return_value = ATTEST_TOKEN_ERR_SW_COMPONENTS_MISSING;
- }
- }
- } else {
- /* The SW components claim exists */
- if(item.val.uCount == 0) {
- /* Empty SW component not allowed */
- return_value = ATTEST_TOKEN_ERR_SW_COMPONENTS_MISSING;
- } else {
- /* SUCESSS! Pass on the success return_value */
- /* Note that this assumes the array is definite length */
- *num_sw_components = item.val.uCount;
- }
- }
-
-Done:
- return return_value;
-}
-
-
-/**
- * \brief Decode a single SW component
- *
- * \param[in] decode_context The CBOR decoder context to decode from
- * \param[in] sw_component_item The top-level map item for this SW
- * component.
- * \param[out] sw_component The structure to fill in with decoded data.
- *
- * \return An error from \ref attest_token_err_t.
- *
- */
-static inline enum attest_token_err_t
-decode_sw_component(QCBORDecodeContext *decode_context,
- const QCBORItem *sw_component_item,
- struct attest_token_sw_component_t *sw_component)
-{
- enum attest_token_err_t return_value;
- QCBORItem claim_item;
- QCBORError cbor_error;
- uint_fast8_t next_nest_level; /* nest levels are 8-bit, but a uint8_t
- var is often slower and more code */
-
- if(sw_component_item->uDataType != QCBOR_TYPE_MAP) {
- return_value = ATTEST_TOKEN_ERR_CBOR_STRUCTURE;
- goto Done;
- }
-
- /* Zero it, setting booleans to false, pointers to NULL and
- lengths to 0 */
- memset(sw_component, 0, sizeof(struct attest_token_sw_component_t));
-
- return_value = ATTEST_TOKEN_ERR_SUCCESS;
-
- while(1) {
- cbor_error = QCBORDecode_GetNext(decode_context, &claim_item);
- if(cbor_error != QCBOR_SUCCESS) {
- /* no tolerance for any errors here */
- return_value = ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED;
- goto Done;
- }
-
- if(claim_item.uLabelType == QCBOR_TYPE_INT64) {
- switch(claim_item.label.int64) {
- case EAT_CBOR_SW_COMPONENT_MEASUREMENT_TYPE:
- if(claim_item.uDataType != QCBOR_TYPE_TEXT_STRING) {
- return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
- goto Done;
- }
- sw_component->measurement_type = claim_item.val.string;
- sw_component->item_flags |=
- CLAIM_PRESENT_BIT(SW_MEASUREMENT_TYPE_FLAG);
-
- break;
-
- case EAT_CBOR_SW_COMPONENT_MEASUREMENT_VALUE:
- if(claim_item.uDataType != QCBOR_TYPE_BYTE_STRING) {
- return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
- goto Done;
- }
- sw_component->measurement_val = claim_item.val.string;
- sw_component->item_flags |=
- CLAIM_PRESENT_BIT(SW_MEASURMENT_VAL_FLAG);
- break;
-
- case EAT_CBOR_SW_COMPONENT_VERSION:
- if(claim_item.uDataType != QCBOR_TYPE_TEXT_STRING) {
- return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
- goto Done;
- }
- sw_component->version = claim_item.val.string;
- sw_component->item_flags |=
- CLAIM_PRESENT_BIT(SW_VERSION_FLAG);
- break;
-
- case EAT_CBOR_SW_COMPONENT_SIGNER_ID:
- if(claim_item.uDataType != QCBOR_TYPE_BYTE_STRING) {
- return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
- goto Done;
- }
- sw_component->signer_id = claim_item.val.string;
- sw_component->item_flags |=
- CLAIM_PRESENT_BIT(SW_SIGNER_ID_FLAG);
- break;
-
- case EAT_CBOR_SW_COMPONENT_MEASUREMENT_DESC:
- if(claim_item.uDataType != QCBOR_TYPE_TEXT_STRING) {
- return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
- goto Done;
- }
- sw_component->measurement_desc = claim_item.val.string;
- sw_component->item_flags |=
- CLAIM_PRESENT_BIT(SW_MEASUREMENT_DESC_FLAG);
- break;
- }
- }
-
- if(qcbor_util_consume_item(decode_context,
- &claim_item,
- &next_nest_level)) {
- return_value = ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED;
- goto Done;
- }
- if(next_nest_level < sw_component_item->uNextNestLevel) {
- /* Got all the items in the map */
- break;
- }
- }
-
-Done:
- return return_value;
-}
-
-
-/*
- * Public function. See attest_token_decode.h
- */
-enum attest_token_err_t
-attest_token_get_sw_component(struct attest_token_decode_context *me,
- uint32_t requested_index,
- struct attest_token_sw_component_t *sw_components)
-{
- enum attest_token_err_t return_value;
- QCBORItem sw_components_array_item;
- QCBORDecodeContext decode_context;
- QCBORItem sw_component_item;
- QCBORError qcbor_error;
- uint_fast8_t exit_array_level;
-
- if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
- return_value = me->last_error;
- goto Done;
- }
-
- QCBORDecode_Init(&decode_context, me->payload, QCBOR_DECODE_MODE_NORMAL);
-
- /* Find the map containing all the SW Components */
- return_value = qcbor_util_decode_to_labeled_item(&decode_context,
- EAT_CBOR_ARM_LABEL_SW_COMPONENTS,
- &sw_components_array_item);
- if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
- goto Done;
- }
-
- if(sw_components_array_item.uDataType != QCBOR_TYPE_ARRAY) {
- return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
- goto Done;
- }
-
- exit_array_level = sw_components_array_item.uNextNestLevel;
-
- /* Loop over contents of SW Components array */
- while(1) {
- qcbor_error = QCBORDecode_GetNext(&decode_context, &sw_component_item);
- if(qcbor_error) {
- /* no tolerance for any errors here */
- return_value = ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED;
- goto Done;
- }
-
- if(sw_component_item.uNextNestLevel <= exit_array_level) {
- /* Next item will be outside the array */
- return_value = ATTEST_TOKEN_ERR_NOT_FOUND;
- /* The end of the array containing SW components
- and didn't get to the requested_index. */
- goto Done;
- }
-
- if(requested_index == 0) {
- /* Found the one of interest. Decode it and break out */
- return_value = decode_sw_component(&decode_context,
- &sw_component_item,
- sw_components);
- break; /* The normal, non-error exit from this loop */
- }
-
- /* Every member in the array counts even if they are not
- * what is expected */
- requested_index--;
-
- if(qcbor_util_consume_item(&decode_context, &sw_component_item, NULL)) {
- return_value = ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED;
- goto Done;
- }
- }
-
-Done:
- return return_value;
-}
diff --git a/test/suites/attestation/attest_token_decode.h b/test/suites/attestation/attest_token_decode.h
index b735e59c62..880336bf47 100644
--- a/test/suites/attestation/attest_token_decode.h
+++ b/test/suites/attestation/attest_token_decode.h
@@ -2,6 +2,7 @@
* attest_token_decode.h
*
* Copyright (c) 2019, Laurence Lundblade.
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
@@ -836,6 +837,94 @@ attest_token_decode_get_origination(struct attest_token_decode_context*me,
origination);
}
+/**
+
+ \brief Map t_cose errors into attestation token errors
+
+ \param[in] t_cose_error The t_cose error to map
+
+ \return The attestation token error.
+ */
+static inline enum attest_token_err_t
+map_t_cose_errors(enum t_cose_err_t t_cose_error)
+{
+ switch (t_cose_error) {
+ case T_COSE_SUCCESS:
+ return ATTEST_TOKEN_ERR_SUCCESS;
+ break;
+ case T_COSE_ERR_UNSUPPORTED_SIGNING_ALG:
+ return ATTEST_TOKEN_ERR_UNSUPPORTED_SIG_ALG;
+ break;
+ case T_COSE_ERR_UNSUPPORTED_HASH:
+ return ATTEST_TOKEN_ERR_HASH_UNAVAILABLE;
+ break;
+ case T_COSE_ERR_CBOR_NOT_WELL_FORMED:
+ return ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED;
+ break;
+ case T_COSE_ERR_INSUFFICIENT_MEMORY:
+ return ATTEST_TOKEN_ERR_INSUFFICIENT_MEMORY;
+ break;
+ case T_COSE_ERR_TAMPERING_DETECTED:
+ return ATTEST_TOKEN_ERR_TAMPERING_DETECTED;
+ break;
+ case T_COSE_ERR_CBOR_FORMATTING:
+ return ATTEST_TOKEN_ERR_CBOR_FORMATTING;
+ break;
+ case T_COSE_ERR_TOO_SMALL:
+ return ATTEST_TOKEN_ERR_TOO_SMALL;
+ break;
+
+ case T_COSE_ERR_PARAMETER_CBOR:
+ case T_COSE_ERR_NON_INTEGER_ALG_ID:
+ return ATTEST_TOKEN_ERR_CBOR_STRUCTURE;
+ break;
+
+ case T_COSE_ERR_SIG_VERIFY:
+ case T_COSE_ERR_SHORT_CIRCUIT_SIG:
+ return ATTEST_TOKEN_ERR_COSE_VALIDATION;
+ break;
+
+ case T_COSE_ERR_SIGN1_FORMAT:
+ return ATTEST_TOKEN_ERR_COSE_FORMAT;
+ break;
+
+ case T_COSE_ERR_MAC0_FORMAT:
+ return ATTEST_TOKEN_ERR_COSE_FORMAT;
+ break;
+
+ case T_COSE_ERR_NO_ALG_ID:
+ case T_COSE_ERR_NO_KID:
+ case T_COSE_ERR_BAD_SHORT_CIRCUIT_KID:
+ case T_COSE_ERR_SIG_STRUCT:
+ return ATTEST_TOKEN_ERR_COSE_FORMAT;
+ break;
+
+ case T_COSE_ERR_UNKNOWN_KEY:
+ case T_COSE_ERR_WRONG_TYPE_OF_KEY:
+ return ATTEST_TOKEN_ERR_VERIFICATION_KEY;
+ break;
+
+ case T_COSE_ERR_MAKING_PROTECTED:
+ case T_COSE_ERR_HASH_GENERAL_FAIL:
+ case T_COSE_ERR_HASH_BUFFER_SIZE:
+ case T_COSE_ERR_SIG_BUFFER_SIZE:
+ case T_COSE_ERR_INVALID_ARGUMENT:
+ case T_COSE_ERR_FAIL:
+ case T_COSE_ERR_SIG_FAIL:
+ case T_COSE_ERR_TOO_MANY_PARAMETERS:
+ case T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER:
+ case T_COSE_ERR_SHORT_CIRCUIT_SIG_DISABLED:
+ case T_COSE_ERR_INCORRECT_KEY_FOR_LIB:
+ case T_COSE_ERR_BAD_CONTENT_TYPE:
+ case T_COSE_ERR_INCORRECTLY_TAGGED:
+ case T_COSE_ERR_EMPTY_KEY:
+ case T_COSE_ERR_DUPLICATE_PARAMETER:
+ case T_COSE_ERR_PARAMETER_NOT_PROTECTED:
+ case T_COSE_ERR_CRIT_PARAMETER:
+ default:
+ return ATTEST_TOKEN_ERR_GENERAL;
+ }
+}
#ifdef __cplusplus
}
diff --git a/test/suites/attestation/attest_token_decode_common.c b/test/suites/attestation/attest_token_decode_common.c
new file mode 100644
index 0000000000..52987c9a0d
--- /dev/null
+++ b/test/suites/attestation/attest_token_decode_common.c
@@ -0,0 +1,601 @@
+/*
+ * attest_token_decode_common.c
+ *
+ * Copyright (c) 2019, Laurence Lundblade.
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ */
+
+#include "attest_token_decode.h"
+#include "attestation.h"
+#include "q_useful_buf.h"
+#include "qcbor_util.h"
+
+/**
+ * \file attest_token_decode_common.c
+ *
+ * \brief Common functions in attestation token decoder.
+ *
+ * This decodes and verifies an attestation token giving access to the
+ * data items in the token. The data items are also known as claims.
+ *
+ * This is written primarily as tests for the token encoder, though it
+ * close to a full commercial token decoder. The main thing missing is
+ * a thorough test suite for it. Test before commercial use is
+ * important as this is a parser / decoder and thus subject to attack
+ * by malicious input. It does however, use QCBOR for most base
+ * parsing, and QCBOR is thoroughly tested and commercial.
+ *
+ * This is oriented around the Arm-defined initial attestation token.
+ *
+ * \c uint_fast8_t is used for type and nest levels. They are
+ * 8-bit quantities, but making using uint8_t variables
+ * and parameters can result in bigger, slower code.
+ * \c uint_fast8_t is part of \c <stdint.h>. It is not
+ * used in structures where it is more important to keep
+ * the size smaller.
+ */
+
+
+/**
+ * Compute the bit indicating a claim is present
+ */
+#define CLAIM_PRESENT_BIT(item_index) (0x01U << (item_index))
+
+
+/*
+ * Public function. See attest_token_decode.h
+ */
+void attest_token_decode_init(struct attest_token_decode_context *me,
+ uint32_t options)
+{
+ memset(me, 0, sizeof(struct attest_token_decode_context));
+ me->options = options;
+ me->last_error = ATTEST_TOKEN_ERR_NO_VALID_TOKEN;
+}
+
+/*
+ * Public function. See attest_token_decode.h
+ */
+enum attest_token_err_t
+attest_token_decode_get_bstr(struct attest_token_decode_context *me,
+ int32_t label,
+ struct q_useful_buf_c *claim)
+{
+ enum attest_token_err_t return_value;
+ QCBORItem item;
+
+ if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
+ return_value = me->last_error;
+ *claim = NULL_Q_USEFUL_BUF_C;
+ goto Done;
+ }
+
+ return_value = qcbor_util_get_top_level_item_in_map(me->payload,
+ label,
+ QCBOR_TYPE_BYTE_STRING,
+ &item);
+ if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
+ goto Done;
+ }
+
+ *claim = item.val.string;
+
+Done:
+ return return_value;
+}
+
+
+/*
+ * Public function. See attest_token_decode.h
+ */
+enum attest_token_err_t
+attest_token_decode_get_tstr(struct attest_token_decode_context *me,
+ int32_t label,
+ struct q_useful_buf_c *claim)
+{
+ enum attest_token_err_t return_value;
+ QCBORItem item;
+
+ if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
+ return_value = me->last_error;
+ *claim = NULL_Q_USEFUL_BUF_C;
+ goto Done;
+ }
+
+ return_value = qcbor_util_get_top_level_item_in_map(me->payload,
+ label,
+ QCBOR_TYPE_TEXT_STRING,
+ &item);
+ if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
+ goto Done;
+ }
+
+ *claim = item.val.string;
+
+Done:
+ return return_value;
+}
+
+
+/*
+ * Public function. See attest_token_decode.h
+ */
+enum attest_token_err_t
+attest_token_decode_get_int(struct attest_token_decode_context *me,
+ int32_t label,
+ int64_t *integer)
+{
+ enum attest_token_err_t return_value;
+ QCBORItem item;
+ QCBORDecodeContext decode_context;
+
+ if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
+ return_value = me->last_error;
+ *integer = 0;
+ goto Done;
+ }
+
+ QCBORDecode_Init(&decode_context, me->payload, QCBOR_DECODE_MODE_NORMAL);
+
+ return_value = qcbor_util_get_item_in_map(&decode_context,
+ label,
+ &item);
+ if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
+ goto Done;
+ }
+
+ if(QCBORDecode_Finish(&decode_context)) {
+ return_value = ATTEST_TOKEN_ERR_CBOR_STRUCTURE;
+ }
+
+ if(item.uDataType == QCBOR_TYPE_INT64) {
+ *integer = item.val.int64;
+ } else if(item.uDataType == QCBOR_TYPE_UINT64) {
+ if(item.val.uint64 < INT64_MAX) {
+ *integer = (int64_t)item.val.uint64;
+ } else {
+ return_value = ATTEST_TOKEN_ERR_INTEGER_VALUE;
+ }
+ } else {
+ return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
+ }
+
+Done:
+ return return_value;
+}
+
+
+/*
+ * Public function. See attest_token_decode.h
+ */
+enum attest_token_err_t
+attest_token_decode_get_uint(struct attest_token_decode_context *me,
+ int32_t label,
+ uint64_t *integer)
+{
+ enum attest_token_err_t return_value;
+ QCBORItem item;
+ QCBORDecodeContext decode_context;
+
+ if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
+ return_value = me->last_error;
+ *integer = 0;
+ goto Done;
+ }
+
+ QCBORDecode_Init(&decode_context, me->payload, QCBOR_DECODE_MODE_NORMAL);
+
+ return_value = qcbor_util_get_item_in_map(&decode_context,
+ label,
+ &item);
+ if(return_value != 0) {
+ goto Done;
+ }
+
+ if(QCBORDecode_Finish(&decode_context)) {
+ return_value = ATTEST_TOKEN_ERR_CBOR_STRUCTURE;
+ }
+
+ if(item.uDataType == QCBOR_TYPE_UINT64) {
+ *integer = item.val.uint64;
+ } else if(item.uDataType == QCBOR_TYPE_INT64) {
+ if(item.val.int64 >= 0) {
+ *integer = (uint64_t)item.val.int64;
+ } else {
+ return_value = ATTEST_TOKEN_ERR_INTEGER_VALUE;
+ }
+ } else {
+ return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
+ }
+
+Done:
+ return return_value;
+}
+
+
+/*
+ * Public function. See attest_token_decode.h
+ */
+enum attest_token_err_t
+attest_token_decode_get_payload(struct attest_token_decode_context *me,
+ struct q_useful_buf_c *payload)
+{
+ enum attest_token_err_t return_value;
+
+ if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
+ return_value = me->last_error;
+ *payload = NULL_Q_USEFUL_BUF_C;
+ goto Done;
+ }
+
+ if(q_useful_buf_c_is_null_or_empty(me->payload)) {
+ return_value = ATTEST_TOKEN_ERR_NO_VALID_TOKEN;
+ goto Done;
+ }
+
+ *payload = me->payload;
+ return_value = ATTEST_TOKEN_ERR_SUCCESS;
+
+Done:
+ return return_value;
+}
+
+
+/*
+ * Public function. See attest_token_decode.h
+ */
+enum attest_token_err_t
+attest_token_decode_get_iat_simple(struct attest_token_decode_context *me,
+ struct attest_token_iat_simple_t *items)
+{
+ struct qcbor_util_items_to_get_t list[NUMBER_OF_ITEMS+1];
+ QCBORDecodeContext decode_context;
+ int64_t client_id_64;
+ enum attest_token_err_t return_value;
+
+ /* Set all q_useful_bufs to NULL and flags to 0 */
+ memset(items, 0, sizeof(struct attest_token_iat_simple_t));
+
+ /* Re use flags as array indexes because it works nicely */
+ list[NONCE_FLAG].label = EAT_CBOR_ARM_LABEL_CHALLENGE;
+ list[UEID_FLAG].label = EAT_CBOR_ARM_LABEL_UEID;
+ list[BOOT_SEED_FLAG].label = EAT_CBOR_ARM_LABEL_BOOT_SEED;
+ list[HW_VERSION_FLAG].label = EAT_CBOR_ARM_LABEL_HW_VERSION;
+ list[IMPLEMENTATION_ID_FLAG].label = EAT_CBOR_ARM_LABEL_IMPLEMENTATION_ID;
+ list[CLIENT_ID_FLAG].label = EAT_CBOR_ARM_LABEL_CLIENT_ID;
+ list[SECURITY_LIFECYCLE_FLAG].label = EAT_CBOR_ARM_LABEL_SECURITY_LIFECYCLE;
+ list[PROFILE_DEFINITION_FLAG].label = EAT_CBOR_ARM_LABEL_PROFILE_DEFINITION;
+ list[ORIGINATION_FLAG].label = EAT_CBOR_ARM_LABEL_ORIGINATION;
+ list[NUMBER_OF_ITEMS].label = 0; /* terminate the list. */
+
+ if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
+ return_value = me->last_error;
+ goto Done;
+ }
+
+ QCBORDecode_Init(&decode_context, me->payload, QCBOR_DECODE_MODE_NORMAL);
+
+ return_value = qcbor_util_get_items_in_map(&decode_context,
+ list);
+ if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
+ goto Done;
+ }
+
+ /* ---- NONCE ---- */
+ if(list[NONCE_FLAG].item.uDataType == QCBOR_TYPE_BYTE_STRING) {
+ items->nonce = list[NONCE_FLAG].item.val.string;
+ items->item_flags |= CLAIM_PRESENT_BIT(NONCE_FLAG);
+ }
+
+ /* ---- UEID -------*/
+ if(list[UEID_FLAG].item.uDataType == QCBOR_TYPE_BYTE_STRING) {
+ items->ueid = list[UEID_FLAG].item.val.string;
+ items->item_flags |= CLAIM_PRESENT_BIT(UEID_FLAG);
+ }
+
+ /* ---- BOOT SEED -------*/
+ if(list[BOOT_SEED_FLAG].item.uDataType == QCBOR_TYPE_BYTE_STRING) {
+ items->boot_seed = list[BOOT_SEED_FLAG].item.val.string;
+ items->item_flags |= CLAIM_PRESENT_BIT(BOOT_SEED_FLAG);\
+ }
+
+ /* ---- HW VERSION -------*/
+ if(list[HW_VERSION_FLAG].item.uDataType == QCBOR_TYPE_TEXT_STRING) {
+ items->hw_version = list[HW_VERSION_FLAG].item.val.string;
+ items->item_flags |= CLAIM_PRESENT_BIT(HW_VERSION_FLAG);
+
+ }
+
+ /* ----IMPLEMENTATION ID -------*/
+ if(list[IMPLEMENTATION_ID_FLAG].item.uDataType == QCBOR_TYPE_BYTE_STRING) {
+ items->implementation_id = list[IMPLEMENTATION_ID_FLAG].item.val.string;
+ items->item_flags |= CLAIM_PRESENT_BIT(IMPLEMENTATION_ID_FLAG);
+ }
+
+ /* ----CLIENT ID -------*/
+ if(list[CLIENT_ID_FLAG].item.uDataType == QCBOR_TYPE_INT64) {
+ client_id_64 = list[CLIENT_ID_FLAG].item.val.int64;
+ if(client_id_64 < INT32_MAX || client_id_64 > INT32_MIN) {
+ items->client_id = (int32_t)client_id_64;
+ items->item_flags |= CLAIM_PRESENT_BIT(CLIENT_ID_FLAG);
+ }
+ }
+
+ /* ----SECURITY LIFECYCLE -------*/
+ if(list[SECURITY_LIFECYCLE_FLAG].item.uDataType == QCBOR_TYPE_INT64) {
+ if(list[SECURITY_LIFECYCLE_FLAG].item.val.int64 < UINT32_MAX) {
+ items->security_lifecycle =
+ (uint32_t)list[SECURITY_LIFECYCLE_FLAG].item.val.int64;
+ items->item_flags |=CLAIM_PRESENT_BIT(SECURITY_LIFECYCLE_FLAG);
+ }
+ }
+
+ /* ---- PROFILE_DEFINITION -------*/
+ if(list[PROFILE_DEFINITION_FLAG].item.uDataType == QCBOR_TYPE_TEXT_STRING) {
+ items->profile_definition=list[PROFILE_DEFINITION_FLAG].item.val.string;
+ items->item_flags |= CLAIM_PRESENT_BIT(PROFILE_DEFINITION_FLAG);
+ }
+
+ /* ---- ORIGINATION -------*/
+ if(list[ORIGINATION_FLAG].item.uDataType == QCBOR_TYPE_TEXT_STRING) {
+ items->origination = list[ORIGINATION_FLAG].item.val.string;
+ items->item_flags |= CLAIM_PRESENT_BIT(ORIGINATION_FLAG);
+ }
+
+Done:
+ return return_value;
+}
+
+
+/*
+ * Public function. See attest_token_decode.h
+ */
+enum attest_token_err_t
+attest_token_get_num_sw_components(struct attest_token_decode_context *me,
+ uint32_t *num_sw_components)
+{
+ enum attest_token_err_t return_value;
+ QCBORItem item;
+
+ if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
+ return_value = me->last_error;
+ goto Done;
+ }
+
+ return_value = qcbor_util_get_top_level_item_in_map(me->payload,
+ EAT_CBOR_ARM_LABEL_SW_COMPONENTS,
+ QCBOR_TYPE_ARRAY,
+ &item);
+ if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
+ if(return_value != ATTEST_TOKEN_ERR_NOT_FOUND) {
+ /* Something very wrong. Bail out passing on the return_value */
+ goto Done;
+ } else {
+ /* Now decide if it was intentionally left out. */
+ return_value = qcbor_util_get_top_level_item_in_map(me->payload,
+ EAT_CBOR_ARM_LABEL_NO_SW_COMPONENTS,
+ QCBOR_TYPE_INT64,
+ &item);
+ if(return_value == ATTEST_TOKEN_ERR_SUCCESS) {
+ if(item.val.int64 == NO_SW_COMPONENT_FIXED_VALUE) {
+ /* Successful omission of SW components. Pass on the
+ * success return_value */
+ *num_sw_components = 0;
+ } else {
+ /* Indicator for no SW components malformed */
+ return_value = ATTEST_TOKEN_ERR_SW_COMPONENTS_MISSING;
+ }
+ } else if(return_value == ATTEST_TOKEN_ERR_NOT_FOUND) {
+ /* Should have been an indicator for no SW components */
+ return_value = ATTEST_TOKEN_ERR_SW_COMPONENTS_MISSING;
+ }
+ }
+ } else {
+ /* The SW components claim exists */
+ if(item.val.uCount == 0) {
+ /* Empty SW component not allowed */
+ return_value = ATTEST_TOKEN_ERR_SW_COMPONENTS_MISSING;
+ } else {
+ /* SUCESSS! Pass on the success return_value */
+ /* Note that this assumes the array is definite length */
+ *num_sw_components = item.val.uCount;
+ }
+ }
+
+Done:
+ return return_value;
+}
+
+
+/**
+ * \brief Decode a single SW component
+ *
+ * \param[in] decode_context The CBOR decoder context to decode from
+ * \param[in] sw_component_item The top-level map item for this SW
+ * component.
+ * \param[out] sw_component The structure to fill in with decoded data.
+ *
+ * \return An error from \ref attest_token_err_t.
+ *
+ */
+static inline enum attest_token_err_t
+decode_sw_component(QCBORDecodeContext *decode_context,
+ const QCBORItem *sw_component_item,
+ struct attest_token_sw_component_t *sw_component)
+{
+ enum attest_token_err_t return_value;
+ QCBORItem claim_item;
+ QCBORError cbor_error;
+ uint_fast8_t next_nest_level; /* nest levels are 8-bit, but a uint8_t
+ var is often slower and more code */
+
+ if(sw_component_item->uDataType != QCBOR_TYPE_MAP) {
+ return_value = ATTEST_TOKEN_ERR_CBOR_STRUCTURE;
+ goto Done;
+ }
+
+ /* Zero it, setting booleans to false, pointers to NULL and
+ lengths to 0 */
+ memset(sw_component, 0, sizeof(struct attest_token_sw_component_t));
+
+ return_value = ATTEST_TOKEN_ERR_SUCCESS;
+
+ while(1) {
+ cbor_error = QCBORDecode_GetNext(decode_context, &claim_item);
+ if(cbor_error != QCBOR_SUCCESS) {
+ /* no tolerance for any errors here */
+ return_value = ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED;
+ goto Done;
+ }
+
+ if(claim_item.uLabelType == QCBOR_TYPE_INT64) {
+ switch(claim_item.label.int64) {
+ case EAT_CBOR_SW_COMPONENT_MEASUREMENT_TYPE:
+ if(claim_item.uDataType != QCBOR_TYPE_TEXT_STRING) {
+ return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
+ goto Done;
+ }
+ sw_component->measurement_type = claim_item.val.string;
+ sw_component->item_flags |=
+ CLAIM_PRESENT_BIT(SW_MEASUREMENT_TYPE_FLAG);
+
+ break;
+
+ case EAT_CBOR_SW_COMPONENT_MEASUREMENT_VALUE:
+ if(claim_item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+ return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
+ goto Done;
+ }
+ sw_component->measurement_val = claim_item.val.string;
+ sw_component->item_flags |=
+ CLAIM_PRESENT_BIT(SW_MEASURMENT_VAL_FLAG);
+ break;
+
+ case EAT_CBOR_SW_COMPONENT_VERSION:
+ if(claim_item.uDataType != QCBOR_TYPE_TEXT_STRING) {
+ return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
+ goto Done;
+ }
+ sw_component->version = claim_item.val.string;
+ sw_component->item_flags |=
+ CLAIM_PRESENT_BIT(SW_VERSION_FLAG);
+ break;
+
+ case EAT_CBOR_SW_COMPONENT_SIGNER_ID:
+ if(claim_item.uDataType != QCBOR_TYPE_BYTE_STRING) {
+ return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
+ goto Done;
+ }
+ sw_component->signer_id = claim_item.val.string;
+ sw_component->item_flags |=
+ CLAIM_PRESENT_BIT(SW_SIGNER_ID_FLAG);
+ break;
+
+ case EAT_CBOR_SW_COMPONENT_MEASUREMENT_DESC:
+ if(claim_item.uDataType != QCBOR_TYPE_TEXT_STRING) {
+ return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
+ goto Done;
+ }
+ sw_component->measurement_desc = claim_item.val.string;
+ sw_component->item_flags |=
+ CLAIM_PRESENT_BIT(SW_MEASUREMENT_DESC_FLAG);
+ break;
+ }
+ }
+
+ if(qcbor_util_consume_item(decode_context,
+ &claim_item,
+ &next_nest_level)) {
+ return_value = ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED;
+ goto Done;
+ }
+ if(next_nest_level < sw_component_item->uNextNestLevel) {
+ /* Got all the items in the map */
+ break;
+ }
+ }
+
+Done:
+ return return_value;
+}
+
+
+/*
+ * Public function. See attest_token_decode.h
+ */
+enum attest_token_err_t
+attest_token_get_sw_component(struct attest_token_decode_context *me,
+ uint32_t requested_index,
+ struct attest_token_sw_component_t *sw_components)
+{
+ enum attest_token_err_t return_value;
+ QCBORItem sw_components_array_item;
+ QCBORDecodeContext decode_context;
+ QCBORItem sw_component_item;
+ QCBORError qcbor_error;
+ uint_fast8_t exit_array_level;
+
+ if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
+ return_value = me->last_error;
+ goto Done;
+ }
+
+ QCBORDecode_Init(&decode_context, me->payload, QCBOR_DECODE_MODE_NORMAL);
+
+ /* Find the map containing all the SW Components */
+ return_value = qcbor_util_decode_to_labeled_item(&decode_context,
+ EAT_CBOR_ARM_LABEL_SW_COMPONENTS,
+ &sw_components_array_item);
+ if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
+ goto Done;
+ }
+
+ if(sw_components_array_item.uDataType != QCBOR_TYPE_ARRAY) {
+ return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
+ goto Done;
+ }
+
+ exit_array_level = sw_components_array_item.uNextNestLevel;
+
+ /* Loop over contents of SW Components array */
+ while(1) {
+ qcbor_error = QCBORDecode_GetNext(&decode_context, &sw_component_item);
+ if(qcbor_error) {
+ /* no tolerance for any errors here */
+ return_value = ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED;
+ goto Done;
+ }
+
+ if(sw_component_item.uNextNestLevel <= exit_array_level) {
+ /* Next item will be outside the array */
+ return_value = ATTEST_TOKEN_ERR_NOT_FOUND;
+ /* The end of the array containing SW components
+ and didn't get to the requested_index. */
+ goto Done;
+ }
+
+ if(requested_index == 0) {
+ /* Found the one of interest. Decode it and break out */
+ return_value = decode_sw_component(&decode_context,
+ &sw_component_item,
+ sw_components);
+ break; /* The normal, non-error exit from this loop */
+ }
+
+ /* Every member in the array counts even if they are not
+ * what is expected */
+ requested_index--;
+
+ if(qcbor_util_consume_item(&decode_context, &sw_component_item, NULL)) {
+ return_value = ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED;
+ goto Done;
+ }
+ }
+
+Done:
+ return return_value;
+}