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