From f2a5850e4a072abd592bf38fe27674622ae54bf1 Mon Sep 17 00:00:00 2001 From: Yuichi Sugiyama Date: Wed, 18 Feb 2026 03:06:25 +0000 Subject: [PATCH 01/10] attester: fix PSA attestation token claims per RFC 9783 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Measurement Type: "PRoT" → "ARoT" (TA is an ARoT component) - Implementation ID: move from TA to PTA, platform-specific values (imx8mp-optee-ra-... / qemu-optee-ra-...) - Client ID: derive from caller TA UUID instead of hardcoded value - Signer ID: read SRK hash from OCOTP fuses on i.MX8MP, test fallback on QEMU - Lifecycle: determine from fuse state on i.MX8MP, 0x3000 fallback on QEMU Platform-specific code gated by CFG_NXP_CAAM. Verified on QEMU with CBOR decode of all 5 claims. --- .../optee/optee-os_%.imx.bbappend | 2 + attester/container/Dockerfile | 6 +- .../pta_remote_attestation.h | 2 +- .../remote_attestation/cbor.c | 27 ++++- .../remote_attestation/ocotp.c | 106 +++++++++++++++++ .../remote_attestation/ocotp.h | 23 ++++ .../remote_attestation/remote_attestation.c | 109 ++++++++++++++---- .../remote_attestation/sub.mk | 1 + attester/remote_attestation/host/main.c | 20 ++-- .../ta/include/remote_attestation_ta.h | 10 +- .../ta/remote_attestation_ta.c | 35 +++--- provisoning/data/comid-psa-refval-imx.json | 4 +- provisoning/data/comid-psa-refval-qemu.json | 4 +- 13 files changed, 280 insertions(+), 69 deletions(-) create mode 100644 attester/pta_remote_attestation/remote_attestation/ocotp.c create mode 100644 attester/pta_remote_attestation/remote_attestation/ocotp.h mode change 100644 => 100755 attester/remote_attestation/ta/include/remote_attestation_ta.h mode change 100644 => 100755 attester/remote_attestation/ta/remote_attestation_ta.c diff --git a/attester/container-imx/meta-veraison-attestation/recipes-security/optee/optee-os_%.imx.bbappend b/attester/container-imx/meta-veraison-attestation/recipes-security/optee/optee-os_%.imx.bbappend index 93a1675..29669de 100644 --- a/attester/container-imx/meta-veraison-attestation/recipes-security/optee/optee-os_%.imx.bbappend +++ b/attester/container-imx/meta-veraison-attestation/recipes-security/optee/optee-os_%.imx.bbappend @@ -34,6 +34,8 @@ do_configure:append() { cp ${PTA_SRC}/sign.h ${S}/core/pta/remote_attestation/ cp ${PTA_SRC}/base64.c ${S}/core/pta/remote_attestation/ cp ${PTA_SRC}/base64.h ${S}/core/pta/remote_attestation/ + cp ${PTA_SRC}/ocotp.c ${S}/core/pta/remote_attestation/ + cp ${PTA_SRC}/ocotp.h ${S}/core/pta/remote_attestation/ cp ${PTA_SRC}/sub.mk ${S}/core/pta/remote_attestation/ # Copy qcbor files diff --git a/attester/container/Dockerfile b/attester/container/Dockerfile index 236e75d..58cc000 100644 --- a/attester/container/Dockerfile +++ b/attester/container/Dockerfile @@ -80,7 +80,11 @@ RUN cd ${OPTEE_DIR} \ && repo sync -j$(nproc) \ && cd ${OPTEE_DIR}/build \ && make toolchains -j$(nproc) \ - && make check -j$(nproc) + && sed -i 's/BR2_PACKAGE_OPTEE_RUST_EXAMPLES_EXT ?= y/BR2_PACKAGE_OPTEE_RUST_EXAMPLES_EXT ?= n/' \ + ${OPTEE_DIR}/build/common.mk \ + && sed -i 's/OPTEE_RUST_ENABLE ?= y/OPTEE_RUST_ENABLE ?= n/' \ + ${OPTEE_DIR}/build/common.mk \ + && make -j$(nproc) RUN cd ${OPTEE_DIR}/optee_os/core/pta \ && if ! grep -q "^subdirs-y += remote_attestation" sub.mk; then \ diff --git a/attester/pta_remote_attestation/pta_remote_attestation.h b/attester/pta_remote_attestation/pta_remote_attestation.h index 94b5f4f..671982a 100644 --- a/attester/pta_remote_attestation/pta_remote_attestation.h +++ b/attester/pta_remote_attestation/pta_remote_attestation.h @@ -13,7 +13,7 @@ * * [in] memref[0] Nonce * [out] memref[1] Output buffer - * [in] memref[2] Implementation ID + * [in] memref[2] Caller TA UUID (16 bytes) * [in] memref[3] (optional) Serialized black key for signing * * Return codes: diff --git a/attester/pta_remote_attestation/remote_attestation/cbor.c b/attester/pta_remote_attestation/remote_attestation/cbor.c index 629379a..ba95a4f 100644 --- a/attester/pta_remote_attestation/remote_attestation/cbor.c +++ b/attester/pta_remote_attestation/remote_attestation/cbor.c @@ -87,12 +87,22 @@ UsefulBufC generate_cose(UsefulBufC ubc_cbor_evidence, QCBOREncode_AddTag(&cose_context, CBOR_TAG_COSE_SIGN1); QCBOREncode_OpenArray(&cose_context); + /* Allocate work buffers on heap to avoid PTA stack overflow */ + void *heap_prot = malloc(256); + void *heap_tbs = malloc(512); + if (!heap_prot || !heap_tbs) { + free(heap_prot); + free(heap_tbs); + return NULLUsefulBufC; + } + /* Encode protected header */ - UsefulBuf_MAKE_STACK_UB(buffer_for_protected_parameter, 256); - UsefulBufC protected_parameter = - encode_protected_parameter(buffer_for_protected_parameter); + UsefulBuf buf_prot = {heap_prot, 256}; + UsefulBufC protected_parameter = encode_protected_parameter(buf_prot); if (UsefulBuf_IsNULLC(protected_parameter)) { DMSG("Failed to encode protected header payload"); + free(heap_prot); + free(heap_tbs); return NULLUsefulBufC; } @@ -107,11 +117,13 @@ UsefulBufC generate_cose(UsefulBufC ubc_cbor_evidence, QCBOREncode_AddBytes(&cose_context, ubc_cbor_evidence); /* Encode "To Be Signed" payload */ - UsefulBuf_MAKE_STACK_UB(buffer_for_tbs, 1024); + UsefulBuf buf_tbs = {heap_tbs, 512}; UsefulBufC tbs_payload = create_tbs(protected_parameter, NULLUsefulBufC, - ubc_cbor_evidence, buffer_for_tbs); + ubc_cbor_evidence, buf_tbs); if (UsefulBuf_IsNULLC(tbs_payload)) { DMSG("Failed to encode to-be-signed payload"); + free(heap_prot); + free(heap_tbs); return NULLUsefulBufC; } @@ -122,9 +134,14 @@ UsefulBufC generate_cose(UsefulBufC ubc_cbor_evidence, &signature_len, serialized_black_key, serialized_black_key_len) != TEE_SUCCESS) { DMSG("Failed to sign payload"); + free(heap_prot); + free(heap_tbs); return NULLUsefulBufC; } + free(heap_prot); + free(heap_tbs); + /* Add the signature */ UsefulBufC signature_payload = {signature, signature_len}; QCBOREncode_AddBytes(&cose_context, signature_payload); diff --git a/attester/pta_remote_attestation/remote_attestation/ocotp.c b/attester/pta_remote_attestation/remote_attestation/ocotp.c new file mode 100644 index 0000000..42ef5a1 --- /dev/null +++ b/attester/pta_remote_attestation/remote_attestation/ocotp.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: BSD-2-Clause +/* + * Read SRK hash and security configuration from i.MX8MP OCOTP fuses + * for PSA Attestation Token signer-id and lifecycle claims. + * + * Uses the OP-TEE imx_ocotp driver which properly handles CCM clock + * gating — direct io_read32() on OCOTP registers hangs when the + * OCOTP clock is gated by Linux. + */ + +#include "ocotp.h" + +#include +#include +#include + +static bool srk_is_zero(const uint8_t *buf, size_t len) +{ + size_t i; + for (i = 0; i < len; i++) { + if (buf[i]) + return false; + } + return true; +} + +/* + * Read SRK hash (8 x 32-bit fuse words = 256 bits) from OCOTP. + * Banks 6-7, words 0-3 each, stored as big-endian byte array. + */ +TEE_Result ocotp_read_srk_hash(uint8_t signer_id[OCOTP_SRK_SIZE]) +{ + uint32_t bank, word; + size_t idx = 0; + + for (bank = OCOTP_SRK_BANK_START; bank <= OCOTP_SRK_BANK_END; bank++) { + for (word = 0; word < 4; word++) { + uint32_t val = 0; + TEE_Result res = imx_ocotp_read(bank, word, &val); + + if (res != TEE_SUCCESS) { + EMSG("imx_ocotp_read(bank=%u, word=%u) failed: 0x%x", + bank, word, res); + return res; + } + /* Store as big-endian */ + signer_id[idx++] = (uint8_t)(val >> 24); + signer_id[idx++] = (uint8_t)(val >> 16); + signer_id[idx++] = (uint8_t)(val >> 8); + signer_id[idx++] = (uint8_t)(val); + } + } + + DMSG("OCOTP SRK hash:"); + DHEXDUMP(signer_id, OCOTP_SRK_SIZE); + + return TEE_SUCCESS; +} + +/* + * Determine PSA lifecycle state from OCOTP fuses: + * + * SRK fuses SEC_CONFIG Lifecycle + * all-zero Open 0x1000 (ASSEMBLY_AND_TEST) + * all-zero Closed 0x1000 (ASSEMBLY_AND_TEST, abnormal) + * written Open 0x2000 (ROT_PROVISIONING) + * written Closed 0x3000 (SECURED) + */ +TEE_Result ocotp_get_lifecycle(uint32_t *lifecycle) +{ + uint8_t srk[OCOTP_SRK_SIZE] = {0}; + uint32_t sec_cfg = 0; + bool srk_empty; + bool closed; + TEE_Result res; + + if (!lifecycle) + return TEE_ERROR_GENERIC; + + res = ocotp_read_srk_hash(srk); + if (res != TEE_SUCCESS) + return res; + + srk_empty = srk_is_zero(srk, sizeof(srk)); + + res = imx_ocotp_read(OCOTP_SEC_CONFIG_BANK, OCOTP_SEC_CONFIG_WORD, + &sec_cfg); + if (res != TEE_SUCCESS) { + EMSG("imx_ocotp_read(SEC_CONFIG) failed: 0x%x", res); + return res; + } + closed = (sec_cfg & OCOTP_SEC_CONFIG_BIT) != 0; + + DMSG("OCOTP SEC_CONFIG=0x%08" PRIx32 " closed=%d srk_empty=%d", + sec_cfg, closed, srk_empty); + + if (srk_empty) { + *lifecycle = PSA_LIFECYCLE_ASSEMBLY_AND_TEST; + } else if (!closed) { + *lifecycle = PSA_LIFECYCLE_ROT_PROVISIONING; + } else { + *lifecycle = PSA_LIFECYCLE_SECURED; + } + + return TEE_SUCCESS; +} diff --git a/attester/pta_remote_attestation/remote_attestation/ocotp.h b/attester/pta_remote_attestation/remote_attestation/ocotp.h new file mode 100644 index 0000000..035024b --- /dev/null +++ b/attester/pta_remote_attestation/remote_attestation/ocotp.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +#ifndef PTA_REMOTE_ATTESTATION_OCOTP_H +#define PTA_REMOTE_ATTESTATION_OCOTP_H + +#include +#include + +#define OCOTP_SRK_BANK_START 6 +#define OCOTP_SRK_BANK_END 7 +#define OCOTP_SRK_SIZE 32 + +#define OCOTP_SEC_CONFIG_BANK 1 +#define OCOTP_SEC_CONFIG_WORD 3 +#define OCOTP_SEC_CONFIG_BIT (1U << 25) + +#define PSA_LIFECYCLE_ASSEMBLY_AND_TEST 0x1000 +#define PSA_LIFECYCLE_ROT_PROVISIONING 0x2000 +#define PSA_LIFECYCLE_SECURED 0x3000 + +TEE_Result ocotp_read_srk_hash(uint8_t signer_id[OCOTP_SRK_SIZE]); +TEE_Result ocotp_get_lifecycle(uint32_t *lifecycle); + +#endif /* PTA_REMOTE_ATTESTATION_OCOTP_H */ diff --git a/attester/pta_remote_attestation/remote_attestation/remote_attestation.c b/attester/pta_remote_attestation/remote_attestation/remote_attestation.c index b1acd74..f8dc28e 100644 --- a/attester/pta_remote_attestation/remote_attestation/remote_attestation.c +++ b/attester/pta_remote_attestation/remote_attestation/remote_attestation.c @@ -5,13 +5,14 @@ #include "cbor.h" #include "hash.h" #include "sign.h" +#include #include #include #ifdef CFG_NXP_CAAM -#include #include #include +#include "ocotp.h" #endif #define PTA_NAME "remote_attestation.pta" @@ -21,9 +22,13 @@ #define TEE_SHA256_HASH_SIZE 32 #define EAT_PROFILE "http://arm.com/psa/2.0.0" -#define CLIENT_ID 1 -#define LIFECYCLE 12288 -#define MEASURMENT_TYPE "PRoT" +#define MEASURMENT_TYPE "ARoT" +#ifdef CFG_NXP_CAAM +#define IMPLEMENTATION_ID "imx8mp-optee-ra-0000000000000001" +#else +#define IMPLEMENTATION_ID "qemu-optee-ra-000000000000000001" +#endif +#define IMPLEMENTATION_ID_LEN 32 #define SIGNER_ID_LEN 32 #define INSTANCE_ID_LEN 33 @@ -31,22 +36,17 @@ #define PUBKEY_HEADER_SIZE (PUBKEY_COORD_SIZE + PUBKEY_COORD_SIZE) #define MIN_KEY_PARAM_SIZE (PUBKEY_HEADER_SIZE + 1) +#ifndef CFG_NXP_CAAM /* clang-format off */ -/* - * FIXME: signer_id identifies the firmware signing authority, not the - * attestation key. Per PSA Attestation Token §4.4.1 it is - * SHA-256(signing-public-key). Replace with the real value when - * integrating secure-boot verification. - * - * Reference: - * https://datatracker.ietf.org/doc/draft-tschofenig-rats-psa-token/ - */ -#define SIGNER_ID \ +/* QEMU fallback: test signer-id value (no OCOTP fuses available) */ +#define SIGNER_ID_TEST_VALUE \ 0xac, 0xbb, 0x11, 0xc7, 0xe4, 0xda, 0x21, 0x72, \ 0x05, 0x52, 0x3c, 0xe4, 0xce, 0x1a, 0x24, 0x5a, \ 0xe1, 0xa2, 0x39, 0xae, 0x3c, 0x6b, 0xfd, 0x9e, \ 0x78, 0x71, 0xf7, 0xe5, 0xd8, 0xba, 0xe8, 0x6b /* clang-format on */ +#define LIFECYCLE_DEFAULT 0x3000 +#endif #ifdef CFG_NXP_CAAM static TEE_Result caam_to_tee_status(enum caam_status status) @@ -66,23 +66,54 @@ static TEE_Result caam_to_tee_status(enum caam_status status) } #endif +/* + * Derive a PSA client-id (positive int32) from the calling TA's UUID. + * SHA-256(UUID) lower 31 bits, with bit 31 cleared to guarantee a positive + * value (positive = SPE caller per PSA spec). + */ +static int32_t derive_client_id(const uint8_t *ta_uuid, size_t uuid_len) { + uint8_t hash[TEE_SHA256_HASH_SIZE]; + void *ctx = NULL; + + if (!ta_uuid || uuid_len == 0) + return 1; /* safe fallback */ + + if (crypto_hash_alloc_ctx(&ctx, TEE_ALG_SHA256) != TEE_SUCCESS) + return 1; + if (crypto_hash_init(ctx) != TEE_SUCCESS || + crypto_hash_update(ctx, ta_uuid, uuid_len) != TEE_SUCCESS || + crypto_hash_final(ctx, hash, TEE_SHA256_HASH_SIZE) != TEE_SUCCESS) { + crypto_hash_free_ctx(ctx); + return 1; + } + crypto_hash_free_ctx(ctx); + + /* Take lower 4 bytes of SHA-256 digest, clear sign bit */ + uint32_t raw = ((uint32_t)hash[28] << 24) | ((uint32_t)hash[29] << 16) | + ((uint32_t)hash[30] << 8) | hash[31]; + return (int32_t)(raw & 0x7FFFFFFF); +} + static TEE_Result cmd_get_cbor_evidence(uint32_t param_types, TEE_Param params[TEE_NUM_PARAMS]) { const uint8_t *nonce = params[0].memref.buffer; const size_t nonce_sz = params[0].memref.size; uint8_t *output_buffer = params[1].memref.buffer; size_t *output_buffer_len = ¶ms[1].memref.size; - const uint8_t *psa_implementation_id = params[2].memref.buffer; - const size_t psa_implementation_id_len = params[2].memref.size; + const uint8_t *ta_uuid = params[2].memref.buffer; + const size_t ta_uuid_len = params[2].memref.size; const uint8_t *serialized_black_key = NULL; size_t serialized_black_key_len = 0; TEE_Result status = TEE_SUCCESS; const char eat_profile[] = EAT_PROFILE; - const int psa_client_id = CLIENT_ID; - const int psa_security_lifecycle = LIFECYCLE; const char measurement_type[] = MEASURMENT_TYPE; - const uint8_t signer_id[SIGNER_ID_LEN] = {SIGNER_ID}; + const uint8_t *psa_implementation_id = + (const uint8_t *)IMPLEMENTATION_ID; + const size_t psa_implementation_id_len = IMPLEMENTATION_ID_LEN; + const int psa_client_id = derive_client_id(ta_uuid, ta_uuid_len); + uint8_t signer_id[SIGNER_ID_LEN] = {0}; + int psa_security_lifecycle = 0; uint8_t psa_instance_id[INSTANCE_ID_LEN] = {0}; uint8_t pub_x[PUBKEY_COORD_SIZE] = {0}; uint8_t pub_y[PUBKEY_COORD_SIZE] = {0}; @@ -117,6 +148,27 @@ static TEE_Result cmd_get_cbor_evidence(uint32_t param_types, if (!output_buffer || !(*output_buffer_len)) return TEE_ERROR_BAD_PARAMETERS; + /* Populate signer-id and lifecycle from platform fuses or fallback */ +#ifdef CFG_NXP_CAAM + status = ocotp_read_srk_hash(signer_id); + if (status != TEE_SUCCESS) + return status; + + { + uint32_t lifecycle_val = 0; + status = ocotp_get_lifecycle(&lifecycle_val); + if (status != TEE_SUCCESS) + return status; + psa_security_lifecycle = (int)lifecycle_val; + } +#else + { + const uint8_t fallback_signer[SIGNER_ID_LEN] = {SIGNER_ID_TEST_VALUE}; + memcpy(signer_id, fallback_signer, SIGNER_ID_LEN); + psa_security_lifecycle = LIFECYCLE_DEFAULT; + } +#endif + /* * param[3] wire format (optional): * PubX(32 bytes) || PubY(32 bytes) || key_blob(N bytes) @@ -164,8 +216,18 @@ static TEE_Result cmd_get_cbor_evidence(uint32_t param_types, b64_measurement_value[b64_measurement_value_len] = '\0'; DMSG("b64_measurement_value: %s", b64_measurement_value); + /* Allocate CBOR/COSE work buffers on heap to avoid PTA stack overflow */ + void *heap_cbor = malloc(512); + void *heap_cose = malloc(512); + if (!heap_cbor || !heap_cose) { + free(heap_cbor); + free(heap_cose); + return TEE_ERROR_OUT_OF_MEMORY; + } + UsefulBuf buffuer_for_cbor = {heap_cbor, 512}; + UsefulBuf buffer_for_cose = {heap_cose, 512}; + /* Encode evidence to CBOR */ - UsefulBuf_MAKE_STACK_UB(buffuer_for_cbor, 512); UsefulBufC ubc_cbor_evidence = encode_evidence_to_cbor( eat_profile, psa_client_id, psa_security_lifecycle, psa_implementation_id, psa_implementation_id_len, measurement_type, @@ -173,16 +235,19 @@ static TEE_Result cmd_get_cbor_evidence(uint32_t param_types, nonce_sz, measurement_value, TEE_SHA256_HASH_SIZE, buffuer_for_cbor); if (UsefulBuf_IsNULLC(ubc_cbor_evidence)) { DMSG("Failed to encode evidence to CBOR"); + free(heap_cbor); + free(heap_cose); return TEE_ERROR_GENERIC; } /* Sign the CBOR and generate a COSE evidence */ - UsefulBuf_MAKE_STACK_UB(buffer_for_cose, *output_buffer_len); UsefulBufC cose_evidence = generate_cose(ubc_cbor_evidence, buffer_for_cose, serialized_black_key, serialized_black_key_len); if (UsefulBuf_IsNULLC(cose_evidence)) { DMSG("Failed to encode CBOR to COSE"); + free(heap_cbor); + free(heap_cose); return TEE_ERROR_GENERIC; } @@ -190,6 +255,8 @@ static TEE_Result cmd_get_cbor_evidence(uint32_t param_types, memcpy(output_buffer, cose_evidence.ptr, cose_evidence.len); *output_buffer_len = cose_evidence.len; + free(heap_cbor); + free(heap_cose); return TEE_SUCCESS; } diff --git a/attester/pta_remote_attestation/remote_attestation/sub.mk b/attester/pta_remote_attestation/remote_attestation/sub.mk index 36bc948..21093d7 100644 --- a/attester/pta_remote_attestation/remote_attestation/sub.mk +++ b/attester/pta_remote_attestation/remote_attestation/sub.mk @@ -6,6 +6,7 @@ srcs-$(CFG_REMOTE_ATTESTATION_PTA) += sign.c srcs-$(CFG_REMOTE_ATTESTATION_PTA) += qcbor/qcbor_encode.c srcs-$(CFG_REMOTE_ATTESTATION_PTA) += qcbor/ieee754.c srcs-$(CFG_REMOTE_ATTESTATION_PTA) += qcbor/UsefulBuf.c +srcs-$(CFG_NXP_CAAM) += ocotp.c incdirs-$(CFG_NXP_CAAM_ECC_DRV) += ../../drivers/crypto/caam/include diff --git a/attester/remote_attestation/host/main.c b/attester/remote_attestation/host/main.c index be46eb9..edc648b 100644 --- a/attester/remote_attestation/host/main.c +++ b/attester/remote_attestation/host/main.c @@ -298,31 +298,25 @@ int main(int argc, char *argv[]) { uint8_t cbor_evidence[1024] = {0}; TEEC_Operation op = {0}; - /* Setup implementation ID (required by PTA as param[2]) */ - static const uint8_t impl_id[IMPLEMENTATION_ID_LEN] = IMPLEMENTATION_ID; - if (packed_key_param && packed_key_param_len > 0) { - /* Params: nonce(in), output(out), impl_id(in), packed_key(in) */ + /* Params: nonce(in), output(out), packed_key(in) */ op.paramTypes = TEEC_PARAM_TYPES( TEEC_MEMREF_TEMP_INPUT, TEEC_MEMREF_TEMP_OUTPUT, - TEEC_MEMREF_TEMP_INPUT, TEEC_MEMREF_TEMP_INPUT); + TEEC_MEMREF_TEMP_INPUT, TEEC_NONE); } else { - /* Params: nonce(in), output(out), impl_id(in), none */ + /* Params: nonce(in), output(out) */ op.paramTypes = TEEC_PARAM_TYPES( TEEC_MEMREF_TEMP_INPUT, TEEC_MEMREF_TEMP_OUTPUT, - TEEC_MEMREF_TEMP_INPUT, TEEC_NONE); + TEEC_NONE, TEEC_NONE); } op.params[0].tmpref.buffer = (uint8_t *)session->nonce; op.params[0].tmpref.size = session->nonce_size; op.params[1].tmpref.buffer = cbor_evidence; op.params[1].tmpref.size = sizeof(cbor_evidence); - /* param[2] is implementation_id */ - op.params[2].tmpref.buffer = (void *)impl_id; - op.params[2].tmpref.size = IMPLEMENTATION_ID_LEN; - /* param[3] is packed key: PubX(32) || PubY(32) || key_blob(N) */ + /* param[2] is packed key: PubX(32) || PubY(32) || key_blob(N) */ if (packed_key_param && packed_key_param_len > 0) { - op.params[3].tmpref.buffer = packed_key_param; - op.params[3].tmpref.size = packed_key_param_len; + op.params[2].tmpref.buffer = packed_key_param; + op.params[2].tmpref.size = packed_key_param_len; } printf("\nInvoke TA.\n"); diff --git a/attester/remote_attestation/ta/include/remote_attestation_ta.h b/attester/remote_attestation/ta/include/remote_attestation_ta.h old mode 100644 new mode 100755 index a29c8d7..a4f4eaf --- a/attester/remote_attestation/ta/include/remote_attestation_ta.h +++ b/attester/remote_attestation/ta/include/remote_attestation_ta.h @@ -17,16 +17,12 @@ #define TA_REMOTE_ATTESTATION_CMD_GENERATE_BLACKKEY 1 #define TA_REMOTE_ATTESTATION_CMD_CONVERT_TO_BLACKKEY 2 -/* Implementation ID used in PSA evidence */ -#define IMPLEMENTATION_ID "acme-implementation-id-000000001" -#define IMPLEMENTATION_ID_LEN 32 - /* - * Wire format for param[3] (optional key material): + * Wire format for param[2] (optional key material, Host→TA): * PubX(32 bytes) || PubY(32 bytes) || key_blob(N bytes) * - * When param[3] is provided, its size must be >= MIN_KEY_PARAM_SIZE. - * When param[3] is NONE, the PTA uses the embedded test key. + * When param[2] is provided, its size must be >= MIN_KEY_PARAM_SIZE. + * When param[2] is NONE, the PTA uses the embedded test key. */ #define PUBKEY_COORD_SIZE 32 #define PUBKEY_HEADER_SIZE (PUBKEY_COORD_SIZE + PUBKEY_COORD_SIZE) diff --git a/attester/remote_attestation/ta/remote_attestation_ta.c b/attester/remote_attestation/ta/remote_attestation_ta.c old mode 100644 new mode 100755 index db470fe..7885240 --- a/attester/remote_attestation/ta/remote_attestation_ta.c +++ b/attester/remote_attestation/ta/remote_attestation_ta.c @@ -26,26 +26,29 @@ TEE_Result call_pta_for_cbor_evidence(uint32_t param_types, goto cleanup_return; } + /* + * Host → TA param layout: + * [0] nonce (INPUT) + * [1] output (INOUT or OUTPUT) + * [2] packed key (INPUT, optional) + * [3] unused + */ if (param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, TEE_PARAM_TYPE_MEMREF_INOUT, TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE) && - param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, - TEE_PARAM_TYPE_MEMREF_INOUT, - TEE_PARAM_TYPE_MEMREF_INPUT, - TEE_PARAM_TYPE_NONE) && param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, TEE_PARAM_TYPE_MEMREF_OUTPUT, - TEE_PARAM_TYPE_MEMREF_INPUT, + TEE_PARAM_TYPE_NONE, TEE_PARAM_TYPE_NONE) && param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, TEE_PARAM_TYPE_MEMREF_INOUT, TEE_PARAM_TYPE_MEMREF_INPUT, - TEE_PARAM_TYPE_MEMREF_INPUT) && + TEE_PARAM_TYPE_NONE) && param_types != TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT, TEE_PARAM_TYPE_MEMREF_OUTPUT, TEE_PARAM_TYPE_MEMREF_INPUT, - TEE_PARAM_TYPE_MEMREF_INPUT)) { + TEE_PARAM_TYPE_NONE)) { res = TEE_ERROR_BAD_PARAMETERS; goto cleanup_return; } @@ -72,17 +75,15 @@ TEE_Result call_pta_for_cbor_evidence(uint32_t param_types, goto cleanup_return; } - /* Setup implementation ID */ - const uint8_t psa_implementation_id[IMPLEMENTATION_ID_LEN]; - memcpy((uint8_t *)psa_implementation_id, IMPLEMENTATION_ID, - IMPLEMENTATION_ID_LEN); + /* Send our TA UUID to PTA for client-id derivation */ + TEE_UUID ta_uuid = TA_REMOTE_ATTESTATION_UUID; - /* Optional key blob from host (black key or SW private key d) */ + /* Optional key blob from host (packed key now in params[2]) */ void *key_blob = NULL; size_t key_blob_len = 0; - if (TEE_PARAM_TYPE_GET(param_types, 3) == TEE_PARAM_TYPE_MEMREF_INPUT) { - key_blob = params[3].memref.buffer; - key_blob_len = params[3].memref.size; + if (TEE_PARAM_TYPE_GET(param_types, 2) == TEE_PARAM_TYPE_MEMREF_INPUT) { + key_blob = params[2].memref.buffer; + key_blob_len = params[2].memref.size; if (key_blob && key_blob_len > 0) { key_buf = TEE_Malloc(key_blob_len, 0); if (!key_buf) { @@ -100,8 +101,8 @@ TEE_Result call_pta_for_cbor_evidence(uint32_t param_types, .memref.size = nonce_len}, {.memref.buffer = out_buf, .memref.size = out_len}, - {.memref.buffer = psa_implementation_id, - .memref.size = IMPLEMENTATION_ID_LEN}, + {.memref.buffer = &ta_uuid, + .memref.size = sizeof(ta_uuid)}, {.memref.buffer = NULL, .memref.size = 0}}; if (key_blob && key_blob_len > 0) { diff --git a/provisoning/data/comid-psa-refval-imx.json b/provisoning/data/comid-psa-refval-imx.json index 8e816b1..10f6cd1 100644 --- a/provisoning/data/comid-psa-refval-imx.json +++ b/provisoning/data/comid-psa-refval-imx.json @@ -22,7 +22,7 @@ "class": { "id": { "type": "psa.impl-id", - "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" + "value": "aW14OG1wLW9wdGVlLXJhLTAwMDAwMDAwMDAwMDAwMDE=" }, "vendor": "ACME", "model": "RoadRunner" @@ -33,7 +33,7 @@ "key": { "type": "psa.refval-id", "value": { - "label": "PRoT", + "label": "ARoT", "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" } }, diff --git a/provisoning/data/comid-psa-refval-qemu.json b/provisoning/data/comid-psa-refval-qemu.json index 913dfda..6d98603 100644 --- a/provisoning/data/comid-psa-refval-qemu.json +++ b/provisoning/data/comid-psa-refval-qemu.json @@ -22,7 +22,7 @@ "class": { "id": { "type": "psa.impl-id", - "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" + "value": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=" }, "vendor": "ACME", "model": "RoadRunner" @@ -33,7 +33,7 @@ "key": { "type": "psa.refval-id", "value": { - "label": "PRoT", + "label": "ARoT", "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" } }, From 9de020a599009373e9a6671a94b99e86d25085bc Mon Sep 17 00:00:00 2001 From: Yuichi Sugiyama Date: Wed, 18 Feb 2026 06:16:54 +0000 Subject: [PATCH 02/10] provisioning: update reference values for i.MX8MP device Update comid-psa-refval-imx.json and comid-psa-ta.json with actual device values: - signer-id: SRK hash read from OCOTP fuses - measurement-value: TA memory hash from real hardware - impl-id: platform-specific implementation ID - instance-id and verification key: CAAM-generated keypair --- provisoning/data/comid-psa-refval-imx.json | 4 +- ...omid-psa-ta.json => comid-psa-ta-imx.json} | 2 +- provisoning/data/comid-psa-ta-qemu.json | 44 +++++++++++++++++++ provisoning/run.sh | 11 ++--- 4 files changed, 53 insertions(+), 8 deletions(-) rename provisoning/data/{comid-psa-ta.json => comid-psa-ta-imx.json} (94%) create mode 100644 provisoning/data/comid-psa-ta-qemu.json diff --git a/provisoning/data/comid-psa-refval-imx.json b/provisoning/data/comid-psa-refval-imx.json index 10f6cd1..b1f4614 100644 --- a/provisoning/data/comid-psa-refval-imx.json +++ b/provisoning/data/comid-psa-refval-imx.json @@ -34,12 +34,12 @@ "type": "psa.refval-id", "value": { "label": "ARoT", - "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" + "signer-id": "427zIO3QE+zwfmqkGRPzdhocbmeEF9Bpn5Lk/mBzgf4=" } }, "value": { "digests": [ - "sha-256;6obNp1pkw7W7eaWtjwjSspd2w7JXAJ3+T9N1gzwJXYQ=" + "sha-256;v0A0kWI5jq4tGIGZf+o4ujdq/udWwLgzfrOc2XOb13A=" ] } } diff --git a/provisoning/data/comid-psa-ta.json b/provisoning/data/comid-psa-ta-imx.json similarity index 94% rename from provisoning/data/comid-psa-ta.json rename to provisoning/data/comid-psa-ta-imx.json index cea8c44..8aadb39 100644 --- a/provisoning/data/comid-psa-ta.json +++ b/provisoning/data/comid-psa-ta-imx.json @@ -22,7 +22,7 @@ "class": { "id": { "type": "psa.impl-id", - "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" + "value": "aW14OG1wLW9wdGVlLXJhLTAwMDAwMDAwMDAwMDAwMDE=" }, "vendor": "ACME", "model": "RoadRunner" diff --git a/provisoning/data/comid-psa-ta-qemu.json b/provisoning/data/comid-psa-ta-qemu.json new file mode 100644 index 0000000..b89bd2c --- /dev/null +++ b/provisoning/data/comid-psa-ta-qemu.json @@ -0,0 +1,44 @@ +{ + "lang": "en-GB", + "tag-identity": { + "id": "366D0A0A-5988-45ED-8488-2F2A544F6242", + "version": 0 + }, + "entities": [ + { + "name": "ACME Ltd.", + "regid": "https://acme.example", + "roles": [ + "tagCreator", + "creator", + "maintainer" + ] + } + ], + "triples": { + "attester-verification-keys": [ + { + "environment": { + "class": { + "id": { + "type": "psa.impl-id", + "value": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=" + }, + "vendor": "ACME", + "model": "RoadRunner" + }, + "instance": { + "type": "ueid", + "value": "AZDHHoAwT5jWVWpALAWTszqArL0I5K/5xAKfbhfhA5lR" + } + }, + "verification-keys": [ + { + "type": "pkix-base64-key", + "value": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----" + } + ] + } + ] + } +} diff --git a/provisoning/run.sh b/provisoning/run.sh index 1fdde42..6a4f78b 100755 --- a/provisoning/run.sh +++ b/provisoning/run.sh @@ -9,8 +9,9 @@ source ${THIS_DIR}/../services/deployments/docker/env.bash # Select environment: qemu (default) or imx ENV=${1:-qemu} REFVAL_FILE="${THIS_DIR}/data/comid-psa-refval-${ENV}.json" +TA_FILE="${THIS_DIR}/data/comid-psa-ta-${ENV}.json" -if [[ ! -f "$REFVAL_FILE" ]]; then +if [[ ! -f "$REFVAL_FILE" ]] || [[ ! -f "$TA_FILE" ]]; then echo "Error: Unknown environment '$ENV'. Use 'qemu' or 'imx'." exit 1 fi @@ -19,22 +20,22 @@ echo "Using provisioning data for: $ENV" build_endorsements() { ${VERAISON} -- cocli comid create \ - --template ${THIS_DIR}/data/comid-psa-ta.json \ + --template ${TA_FILE} \ --template ${REFVAL_FILE} \ --output-dir ${THIS_DIR}/data ${VERAISON} -- cocli corim create \ --template ${THIS_DIR}/data/corim-psa.json \ --comid ${THIS_DIR}/data/comid-psa-refval-${ENV}.cbor \ - --comid ${THIS_DIR}/data/comid-psa-ta.cbor \ + --comid ${THIS_DIR}/data/comid-psa-ta-${ENV}.cbor \ --output ${THIS_DIR}/data/psa-endorsements.cbor } submit_endorsements() { $VERAISON -- cocli corim submit \ --corim-file "${THIS_DIR}/data/psa-endorsements.cbor" \ - --api-server "https://provisioning-service:${PROVISIONING_PORT}/endorsement-provisioning/v1/submit" \ + --api-server "https://provisioning-service:8888/endorsement-provisioning/v1/submit" \ --media-type 'application/corim-unsigned+cbor; profile="http://arm.com/psa/iot/1"' \ - --insecure + --ca-cert /tmp/veraison/certs/rootCA.crt } build_endorsements From 268e0a31533d74bec25d3d3301ec2f0062fd18bd Mon Sep 17 00:00:00 2001 From: Yuichi Sugiyama Date: Wed, 18 Feb 2026 15:48:31 +0900 Subject: [PATCH 03/10] docs: update and split English/Japanese documentation - Fix instance-id and comid-psa-ta.json references across all READMEs - Separate English and Japanese into dedicated files (README.md / README-j.md, provisoning/README.md / provisoning/README-j.md) --- README-j.md | 137 ++--- README.md | 909 ++----------------------------- docs/secure-boot-imx8mp-j.md | 72 ++- docs/secure-boot-imx8mp.md | 74 ++- provisoning/README-j.md | 42 +- provisoning/README.md | 118 +--- relying_party/data/evidence.json | 10 +- 7 files changed, 290 insertions(+), 1072 deletions(-) diff --git a/README-j.md b/README-j.md index 60890c4..54fda77 100644 --- a/README-j.md +++ b/README-j.md @@ -1,6 +1,3 @@ - # 日本語解説 OP-TEE Remote Attestation with VERAISON Verification このドキュメントではQEMUとDockerコンテナを用いた[OP-TEE](https://github.com/OP-TEE/optee_os) Remote Attestation 実行環境の構築と、[VERAISON](https://github.com/veraison) Verification を活用した一連の動作を確認手順を説明します。 @@ -21,9 +18,8 @@ OP-TEEはRaspberry Pi 3B+ (Arm Cortex-A TrustZone)でも動作が確認できて ## 実行方法 以下の 0 から 6 の手順に従い、リモートアテステーションの一連の流れをテストしてください。 -i.MX8MP EVK 実機でのアテステーションは[手順 8](#8-imx8mp-実機でのアテステーション) を参照してください。 -i.MX 8M Plus 向け Yocto ビルドと実機でのアテステーションは[手順 8](#8-imx8mp-実機でのアテステーション) を参照してください。i.MX 8M Plus は SD 先頭の `imx-boot` に埋め込まれた `tee.bin` を使用するため、ビルドスクリプトは `imx-boot` の再ビルドと WIC 再パッケージを行います。 +i.MX 8M Plus 向け Yocto ビルドと実機でのアテステーションは[手順 8](#8-imx8mp-実機でのアテステーション) を参照してください。QEMU 向けの Attester 手順のみ確認したい場合は `attester/README.md` を参照してください。 ### 0. このgithubのクローン 最初にgit cloneによりoptee-raのソースを取り寄せます。 @@ -37,11 +33,11 @@ cd optee-ra Veraisonのソースをgithubから取り寄せます。 ```sh git clone https://github.com/veraison/services.git -cd services && git checkout b50b67d && cd .. +cd services && git checkout 8f5734c && cd .. ``` この際に下記のメッセージがでますが、問題ありません。 ``` -Note: switching to 'b50b67d'. +Note: switching to '8f5734c'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this @@ -58,7 +54,7 @@ Or undo this operation with: Turn off this advice by setting config variable advice.detachedHead to false -HEAD is now at b50b67d Merge pull request #208 from aj-stein-nist/patch-1 +HEAD is now at 8f5734c Yogesh's review comments ``` 次にホストマシン上で動作させるサービスを起動します。 @@ -111,8 +107,8 @@ TRUST ANCHORS: "PSA_IOT.hw-model": "RoadRunner", "PSA_IOT.hw-vendor": "ACME", "PSA_IOT.iak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", - "PSA_IOT.inst-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" + "PSA_IOT.impl-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=", + "PSA_IOT.inst-id": "AZDHHoAwT5jWVWpALAWTszqArL0I5K/5xAKfbhfhA5lR" } } @@ -125,9 +121,9 @@ ENDORSEMENTS: "attributes": { "PSA_IOT.hw-model": "RoadRunner", "PSA_IOT.hw-vendor": "ACME", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", + "PSA_IOT.impl-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=", "PSA_IOT.measurement-desc": "sha-256", - "PSA_IOT.measurement-type": "PRoT", + "PSA_IOT.measurement-type": "ARoT", "PSA_IOT.measurement-value": "MbgFqjT4jfR+fK1O4YyQtZUYD0nhXh7GfhM0EmR6tgc=", "PSA_IOT.signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" } @@ -150,11 +146,6 @@ ENDORSEMENTS: ./relying_party/container/start.sh ``` -Verifier が `https://verification-service:8080` 以外で動作している場合は、起動前に `VERIFICATION_SERVICE_URL` を設定してください(デフォルト: `https://verification-service:8080`)。 -```sh -VERIFICATION_SERVICE_URL=https://verification-service:8443 ./relying_party/container/start.sh -``` - 以下のコマンドで Relying Party のログは確認できます。 ```sh docker logs relying-party-service @@ -219,19 +210,21 @@ optee_remote_attestation 正しく実行できた場合、以下のような出力が noromal world のターミナルで得られます。 ```txt -Opened new Veraison client session at http://relying-party-service:8087/challenge-response/v1/session/ed70cc0d-d141-11ee-9588-623338313838 +Opened new Veraison client session at http://relying-party-service:8087/challenge-response/v1/session/82e2edd9-0d53-11f1-9b92-393833646162 -Number of media types accepted: 7 - application/vnd.parallaxsecond.key-attestation.cca +Number of media types accepted: 9 + application/psa-attestation-token + application/eat+cwt; eat_profile="tag:psacertified.org,2023:psa#tfm" application/vnd.parallaxsecond.key-attestation.tpm - application/pem-certificate-chain + application/eat-cwt; profile="http://arm.com/psa/2.0.0" + application/eat-collection; profile="http://arm.com/CCA-SSD/1.0.0" + application/vnd.parallaxsecond.key-attestation.cca + application/eat+cwt; eat_profile="tag:psacertified.org,2019:psa#legacy" application/vnd.enacttrust.tpm-evidence - application/eat-collection; profile=http://arm.com/CCA-SSD/1.0.0 - application/psa-attestation-token - application/eat-cwt; profile=http://arm.com/psa/2.0.0 + application/pem-certificate-chain Nonce size: 32 bytes -Nonce: [0x60, 0x48, 0xbd, 0x24, 0x55, 0xdb, 0x8a, 0x4, 0x6e, 0xcc, 0x7, 0x20, 0x40, 0x26, 0x87, 0xd0, 0x60, 0x72, 0xd, 0x95, 0x45, 0x57, 0x92, 0xa5, 0x36, 0xf4, 0x84, 0x52, 0xd5, 0xee, 0x5d, 0xbe] +Nonce: [0xc4, 0x69, 0xd9, 0x7, 0x4, 0x87, 0xac, 0x71, 0x90, 0x30, 0x1f, 0x6d, 0x17, 0xbb, 0x62, 0x7c, 0x95, 0x8, 0x4f, 0x49, 0x2a, 0x5, 0x83, 0x1b, 0x3d, 0xde, 0x2a, 0x8f, 0x89, 0xd5, 0x41, 0x3c] Completed opening the session. @@ -242,16 +235,14 @@ Invoked TA successfully. Received evidence of CBOR (COSE) format from PTA. -CBOR(COSE) size: 306 -CBOR(COSE): d28443a10126a058e7a71901097818687474703a2f2f61726d2e636f6d2f7073612f322e302e3019095a0119095b19300019095c582061636d652d696d706c656d656e746174696f6e2d69642d30303030303030303119095f81a3016450526f5402582031b805aa34f88df47e7cad4ee18c90b595180f49e15e1ec67e133412647ab607055820acbb11c7e4da217205523ce4ce1a245ae1a239ae3c6bfd9e7871f7e5d8bae86b0a58206048bd2455db8a046ecc0720402687d060720d95455792a536f48452d5ee5dbe190100582101ceebae7b8927a3227e5303cf5e0f1f7b34bb542ad7250ac03fbcde36ec2f15085840fd39ee2aac4f64be2a58c1eca501ec1a3a7528f73bcbe8a90e7e1efda7e2cfce793fd28137c8a966793b605981fa677824867b22e21efcd6908338c4e3083b08 +CBOR(COSE) size: 310 +CBOR(COSE): d28443a10126a058eba71901097818687474703a2f2f61726d2e636f6d2f7073612f322e302e3019095a1a5f7cd29d19095b19300019095c582071656d752d6f707465652d72612d30303030303030303030303030303030303119095f81a3016441526f540258204237fb23701092316805005b86b2ab60f5ffb681e19e67d97a29e0939a04ea30055820acbb11c7e4da217205523ce4ce1a245ae1a239ae3c6bfd9e7871f7e5d8bae86b0a5820c469d9070487ac7190301f6d17bb627c95084f492a05831b3dde2a8f89d5413c19010058210190c71e80304f98d6556a402c0593b33a80acbd08e4aff9c4029f6e17e1039951584032935e3ebc3c2c052b7ec31fd8f22c4be5ad43cf21960db1de916d8a967bbae0bc1fa2dd110329cb3edeef1919beb74018fe7fbae99fab1743e024ec5f698150 Supplying the generated evidence to the server. Received the attestation result from the server. -Raw attestation result (JWT): eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJlYXIudmVyaWZpZXItaWQiOnsiYnVpbGQiOiJOL0EiLCJkZXZlbG9wZXIiOiJWZXJhaXNvbiBQcm9qZWN0In0sImVhdF9ub25jZSI6IllFaTlKRlhiaWdSdXpBY2dRQ2FIMEdCeURaVkZWNUtsTnZTRVV0WHVYYjQ9IiwiZWF0X3Byb2ZpbGUiOiJ0YWc6Z2l0aHViLmNvbSwyMDIzOnZlcmFpc29uL2VhciIsImlhdCI6MTcwODU3OTE1OSwic3VibW9kcyI6eyJQU0FfSU9UIjp7ImVhci5hcHByYWlzYWwtcG9saWN5LWlkIjoicG9saWN5OlBTQV9JT1QiLCJlYXIuc3RhdHVzIjoiYWZmaXJtaW5nIiwiZWFyLnRydXN0d29ydGhpbmVzcy12ZWN0b3IiOnsiY29uZmlndXJhdGlvbiI6MCwiZXhlY3V0YWJsZXMiOjIsImZpbGUtc3lzdGVtIjowLCJoYXJkd2FyZSI6MiwiaW5zdGFuY2UtaWRlbnRpdHkiOjIsInJ1bnRpbWUtb3BhcXVlIjoyLCJzb3VyY2VkLWRhdGEiOjAsInN0b3JhZ2Utb3BhcXVlIjoyfSwiZWFyLnZlcmFpc29uLmFubm90YXRlZC1ldmlkZW5jZSI6eyJlYXQtcHJvZmlsZSI6Imh0dHA6Ly9hcm0uY29tL3BzYS8yLjAuMCIsInBzYS1jbGllbnQtaWQiOjEsInBzYS1pbXBsZW1lbnRhdGlvbi1pZCI6IllXTnRaUzFwYlhCc1pXMWxiblJoZEdsdmJpMXBaQzB3TURBd01EQXdNREU9IiwicHNhLWluc3RhbmNlLWlkIjoiQWM3cnJudUpKNk1pZmxNRHoxNFBIM3MwdTFRcTF5VUt3RCs4M2pic0x4VUkiLCJwc2Etbm9uY2UiOiJZRWk5SkZYYmlnUnV6QWNnUUNhSDBHQnlEWlZGVjVLbE52U0VVdFh1WGI0PSIsInBzYS1zZWN1cml0eS1saWZlY3ljbGUiOjEyMjg4LCJwc2Etc29mdHdhcmUtY29tcG9uZW50cyI6W3sibWVhc3VyZW1lbnQtdHlwZSI6IlBSb1QiLCJtZWFzdXJlbWVudC12YWx1ZSI6Ik1iZ0ZxalQ0amZSK2ZLMU80WXlRdFpVWUQwbmhYaDdHZmhNMEVtUjZ0Z2M9Iiwic2lnbmVyLWlkIjoickxzUngrVGFJWElGVWp6a3pob2tXdUdpT2E0OGEvMmVlSEgzNWRpNjZHcz0ifV19fX19.PCUUBd6tyV2WdXuM07de3-ZFpKdoL-uEP7yeP1zNEJOpEJ9sVUDJkINI3nalh7nno2etEitbQABZxBCsy_6tKg - Disposing client session. Completed sending the evidence and receiving the attestation result. @@ -273,20 +264,14 @@ veraison clear-stores ./provisoning/run.sh qemu ``` ```txt -2024/02/22 05:19:18 Received request: POST /challenge-response/v1/newSession?nonceSize=32 -2024/02/22 05:19:18 Received response: 201 Created -2024/02/22 05:19:19 Received request: POST /challenge-response/v1/session/ed70cc0d-d141-11ee-9588-623338313838 -2024/02/22 05:19:19 Received response: 200 OK -2024/02/22 05:19:19 Attestation result: >> "/tmp/1442613949.jwt" signature successfully verified using "pkey.json" +Attestation result: [claims-set] { "ear.verifier-id": { "build": "N/A", "developer": "Veraison Project" }, - "eat_nonce": "YEi9JFXbigRuzAcgQCaH0GByDZVFV5KlNvSEUtXuXb4=", "eat_profile": "tag:github.com,2023:veraison/ear", - "iat": 1708579159, "submods": { "PSA_IOT": { "ear.appraisal-policy-id": "policy:PSA_IOT", @@ -303,15 +288,14 @@ veraison clear-stores }, "ear.veraison.annotated-evidence": { "eat-profile": "http://arm.com/psa/2.0.0", - "psa-client-id": 1, - "psa-implementation-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", - "psa-instance-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI", - "psa-nonce": "YEi9JFXbigRuzAcgQCaH0GByDZVFV5KlNvSEUtXuXb4=", + "psa-client-id": 1602015901, + "psa-implementation-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=", + "psa-instance-id": "AZDHHoAwT5jWVWpALAWTszqArL0I5K/5xAKfbhfhA5lR", "psa-security-lifecycle": 12288, "psa-software-components": [ { - "measurement-type": "PRoT", - "measurement-value": "MbgFqjT4jfR+fK1O4YyQtZUYD0nhXh7GfhM0EmR6tgc=", + "measurement-type": "ARoT", + "measurement-value": "Qjf7I3AQkjFoBQBbhrKrYPX/toHhnmfZeingk5oE6jA=", "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" } ] @@ -337,21 +321,14 @@ Sourced Data [none]: The Evidence received is insufficient to make a conclusion. #### 6.1. 登録されていない TA からのアテステーションリクエスト -はじめに、録されてない TA から PTA にリクエストを送り、リモートアテステーションが失敗する流れを確認します。例えば、以下のように [`attester/remote_attestation/ta/include/remote_attestation_ta.h`](attester/remote_attestation/ta/include/remote_attestation_ta.h) の `IMPLEMENTATION_ID` を書き換えると、TA のコードハッシュと implementation ID が変わり、PTA が生成する CBOR(COSE) evidence の内容が変わります。これにより、provisioning されているデータと異なるので、アテステーションが失敗するはずです。 +はじめに、録されてない TA から PTA にリクエストを送り、リモートアテステーションが失敗する流れを確認します。例えば、以下のように [`attester/pta_remote_attestation/remote_attestation/remote_attestation.c`](attester/pta_remote_attestation/remote_attestation/remote_attestation.c) の `IMPLEMENTATION_ID` を書き換えると、TA のコードハッシュと implementation ID が変わり、PTA が生成する CBOR(COSE) evidence の内容が変わります。これにより、provisioning されているデータと異なるので、アテステーションが失敗するはずです。 ```c -diff --git a/attester/remote_attestation/ta/include/remote_attestation_ta.h b/attester/remote_attestation/ta/include/remote_attestation_ta.h -index 4380753..d9cad98 100644 ---- a/attester/remote_attestation/ta/include/remote_attestation_ta.h -+++ b/attester/remote_attestation/ta/include/remote_attestation_ta.h -@@ -16,7 +16,7 @@ - #define TA_REMOTE_ATTESTATOIN_CMD_GEN_CBOR_EVIDENCE 0 - +diff --git a/attester/pta_remote_attestation/remote_attestation/remote_attestation.c b/attester/pta_remote_attestation/remote_attestation/remote_attestation.c +--- a/attester/pta_remote_attestation/remote_attestation/remote_attestation.c ++++ b/attester/pta_remote_attestation/remote_attestation/remote_attestation.c /* Implementation ID used in PSA evidence */ --#define IMPLEMENTATION_ID "acme-implementation-id-000000001" -+#define IMPLEMENTATION_ID "acme-implementation-id-000000002" - #define IMPLEMENTATION_ID_LEN 32 - - #if defined(HOST_BUILD) +-#define IMPLEMENTATION_ID "qemu-optee-ra-000000000000000001" ++#define IMPLEMENTATION_ID "qemu-optee-ra-000000000000000002" ``` 実際に、コードを書き換えた後にアテステーションリクエストを送信してみます。手順 4.4. で QEMU を起動したターミナルで `ctrl+c` をして、一度 QEMU を終了します。その後、もう一度手順 4.4 に従い、TA の再ビルド・QEMU の再起動をします。 @@ -412,7 +389,7 @@ D/TC:? 0 cmd_get_cbor_evidence:82 b64_measurement_value: gw9v98IV8ozl5nHpsMwl9W5 ``` この値を provisioning で登録します。そのためには、[`provisoning/data/comid-psa-refval-qemu.json`](provisoning/data/comid-psa-refval-qemu.json) の `digests` の欄を以下のように書き換えてください(実機の場合は `provisoning/data/comid-psa-refval-imx.json` を使います)。 -また、implementation ID も `acme-implementation-id-000000002` に変更しているため、[`provisoning/data/comid-psa-refval-qemu.json`](provisoning/data/comid-psa-refval-qemu.json) と [`provisoning/data/comid-psa-ta.json`](provisoning/data/comid-psa-ta.json) の `psa.impl-id` の欄を以下のように書き換えてください。注意しとして、`psa.impl-id` の欄は implementation ID を base64 エンコードした値を登録する必要があります。例えば、`echo -n "acme-implementation-id-000000002" | base64` のようなコマンドで計算できます。 +また、implementation ID も `qemu-optee-ra-000000000000000002` に変更しているため、[`provisoning/data/comid-psa-refval-qemu.json`](provisoning/data/comid-psa-refval-qemu.json) と [`provisoning/data/comid-psa-ta-qemu.json`](provisoning/data/comid-psa-ta-qemu.json) の `psa.impl-id` の欄を以下のように書き換えてください。注意しとして、`psa.impl-id` の欄は implementation ID を base64 エンコードした値を登録する必要があります。例えば、`echo -n "qemu-optee-ra-000000000000000002" | base64` のようなコマンドで計算できます。 ```txt diff --git a/provisoning/data/comid-psa-refval-qemu.json b/provisoning/data/comid-psa-refval-qemu.json index fd7965a..db675c1 100644 @@ -422,8 +399,8 @@ index fd7965a..db675c1 100644 "class": { "id": { "type": "psa.impl-id", -- "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" -+ "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDI=" +- "value": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=" ++ "value": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDI=" }, "vendor": "ACME", "model": "RoadRunner" @@ -436,16 +413,14 @@ index fd7965a..db675c1 100644 ] } } -diff --git a/provisoning/data/comid-psa-ta.json b/provisoning/data/comid-psa-ta.json -index 7396dbd..9a813c3 100644 ---- a/provisoning/data/comid-psa-ta.json -+++ b/provisoning/data/comid-psa-ta.json -@@ -22,7 +22,7 @@ +diff --git a/provisoning/data/comid-psa-ta-qemu.json b/provisoning/data/comid-psa-ta-qemu.json +--- a/provisoning/data/comid-psa-ta-qemu.json ++++ b/provisoning/data/comid-psa-ta-qemu.json "class": { "id": { "type": "psa.impl-id", -- "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" -+ "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDI=" +- "value": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=" ++ "value": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDI=" }, "vendor": "ACME", "model": "RoadRunner" @@ -463,8 +438,8 @@ TRUST ANCHORS: "PSA_IOT.hw-model": "RoadRunner", "PSA_IOT.hw-vendor": "ACME", "PSA_IOT.iak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", - "PSA_IOT.inst-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" + "PSA_IOT.impl-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=", + "PSA_IOT.inst-id": "AZDHHoAwT5jWVWpALAWTszqArL0I5K/5xAKfbhfhA5lR" } } { @@ -475,8 +450,8 @@ TRUST ANCHORS: "PSA_IOT.hw-model": "RoadRunner", "PSA_IOT.hw-vendor": "ACME", "PSA_IOT.iak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDI=", - "PSA_IOT.inst-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" + "PSA_IOT.impl-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDI=", + "PSA_IOT.inst-id": "AZDHHoAwT5jWVWpALAWTszqArL0I5K/5xAKfbhfhA5lR" } } @@ -489,9 +464,9 @@ ENDORSEMENTS: "attributes": { "PSA_IOT.hw-model": "RoadRunner", "PSA_IOT.hw-vendor": "ACME", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", + "PSA_IOT.impl-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=", "PSA_IOT.measurement-desc": "sha-256", - "PSA_IOT.measurement-type": "PRoT", + "PSA_IOT.measurement-type": "ARoT", "PSA_IOT.measurement-value": "MbgFqjT4jfR+fK1O4YyQtZUYD0nhXh7GfhM0EmR6tgc=", "PSA_IOT.signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" } @@ -503,9 +478,9 @@ ENDORSEMENTS: "attributes": { "PSA_IOT.hw-model": "RoadRunner", "PSA_IOT.hw-vendor": "ACME", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDI=", + "PSA_IOT.impl-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDI=", "PSA_IOT.measurement-desc": "sha-256", - "PSA_IOT.measurement-type": "PRoT", + "PSA_IOT.measurement-type": "ARoT", "PSA_IOT.measurement-value": "gw9v98IV8ozl5nHpsMwl9W5nGGC0bzAYMPShwvff0vY=", "PSA_IOT.signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" } @@ -539,14 +514,14 @@ ENDORSEMENTS: }, "ear.veraison.annotated-evidence": { "eat-profile": "http://arm.com/psa/2.0.0", - "psa-client-id": 1, - "psa-implementation-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDI=", - "psa-instance-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI", + "psa-client-id": 403236456, + "psa-implementation-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDI=", + "psa-instance-id": "AZDHHoAwT5jWVWpALAWTszqArL0I5K/5xAKfbhfhA5lR", "psa-nonce": "yBULiGEcBq8wtk5xwRikzPZt1GAV5n8L0nXgPY03jHo=", "psa-security-lifecycle": 12288, "psa-software-components": [ { - "measurement-type": "PRoT", + "measurement-type": "ARoT", "measurement-value": "gw9v98IV8ozl5nHpsMwl9W5nGGC0bzAYMPShwvff0vY=", "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" } @@ -678,7 +653,7 @@ print(pem.strip()) " ``` -計算した値で `provisoning/data/comid-psa-ta.json` の `instance` と +計算した値で `provisoning/data/comid-psa-ta-imx.json` の `instance` と `verification-keys` を更新してください。 #### 8.1 シナリオ A: 埋め込みテスト鍵 @@ -698,7 +673,7 @@ services/deployments/docker/veraison clear-stores ./provisoning/run.sh imx ``` -デフォルトの `comid-psa-ta.json` にはテスト鍵の trust anchor が設定済みです。 +デフォルトの `comid-psa-ta-imx.json` にはテスト鍵の trust anchor が設定済みです。 **Attestation 実行** (デバイス側): ```bash @@ -731,7 +706,7 @@ Black key generation completed. ``` **手順 2 — Provisioning** (ホスト側): PubX/PubY から instance ID と PEM 公開鍵を -計算し(上記ヘルパー参照)、`comid-psa-ta.json` を更新後: +計算し(上記ヘルパー参照)、`comid-psa-ta-imx.json` を更新後: ```bash services/deployments/docker/veraison clear-stores ./provisoning/run.sh imx @@ -769,7 +744,7 @@ Key conversion completed. 公開鍵 (PubX/PubY) は出力されません。元の鍵ペアから既知のためです。 **手順 2 — Provisioning** (ホスト側): 既知の PubX/PubY から instance ID と -PEM 公開鍵を計算し(上記ヘルパー参照)、`comid-psa-ta.json` を更新後: +PEM 公開鍵を計算し(上記ヘルパー参照)、`comid-psa-ta-imx.json` を更新後: ```bash services/deployments/docker/veraison clear-stores ./provisoning/run.sh imx diff --git a/README.md b/README.md index 60aebb9..7023418 100644 --- a/README.md +++ b/README.md @@ -133,8 +133,8 @@ TRUST ANCHORS: "PSA_IOT.hw-model": "RoadRunner", "PSA_IOT.hw-vendor": "ACME", "PSA_IOT.iak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", - "PSA_IOT.inst-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" + "PSA_IOT.impl-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=", + "PSA_IOT.inst-id": "AZDHHoAwT5jWVWpALAWTszqArL0I5K/5xAKfbhfhA5lR" } } @@ -147,9 +147,9 @@ ENDORSEMENTS: "attributes": { "PSA_IOT.hw-model": "RoadRunner", "PSA_IOT.hw-vendor": "ACME", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", + "PSA_IOT.impl-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=", "PSA_IOT.measurement-desc": "sha-256", - "PSA_IOT.measurement-type": "PRoT", + "PSA_IOT.measurement-type": "ARoT", "PSA_IOT.measurement-value": "MbgFqjT4jfR+fK1O4YyQtZUYD0nhXh7GfhM0EmR6tgc=", "PSA_IOT.signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" } @@ -253,19 +253,21 @@ optee_remote_attestation If executed correctly, you will get the following output on the normal world terminal. ```txt -Opened new Veraison client session at http://relying-party-service:8087/challenge-response/v1/session/ed70cc0d-d141-11ee-9588-623338313838 +Opened new Veraison client session at http://relying-party-service:8087/challenge-response/v1/session/82e2edd9-0d53-11f1-9b92-393833646162 -Number of media types accepted: 7 - application/vnd.parallaxsecond.key-attestation.cca +Number of media types accepted: 9 + application/psa-attestation-token + application/eat+cwt; eat_profile="tag:psacertified.org,2023:psa#tfm" application/vnd.parallaxsecond.key-attestation.tpm - application/pem-certificate-chain + application/eat-cwt; profile="http://arm.com/psa/2.0.0" + application/eat-collection; profile="http://arm.com/CCA-SSD/1.0.0" + application/vnd.parallaxsecond.key-attestation.cca + application/eat+cwt; eat_profile="tag:psacertified.org,2019:psa#legacy" application/vnd.enacttrust.tpm-evidence - application/eat-collection; profile=http://arm.com/CCA-SSD/1.0.0 - application/psa-attestation-token - application/eat-cwt; profile=http://arm.com/psa/2.0.0 + application/pem-certificate-chain Nonce size: 32 bytes -Nonce: [0x60, 0x48, 0xbd, 0x24, 0x55, 0xdb, 0x8a, 0x4, 0x6e, 0xcc, 0x7, 0x20, 0x40, 0x26, 0x87, 0xd0, 0x60, 0x72, 0xd, 0x95, 0x45, 0x57, 0x92, 0xa5, 0x36, 0xf4, 0x84, 0x52, 0xd5, 0xee, 0x5d, 0xbe] +Nonce: [0xc4, 0x69, 0xd9, 0x7, 0x4, 0x87, 0xac, 0x71, 0x90, 0x30, 0x1f, 0x6d, 0x17, 0xbb, 0x62, 0x7c, 0x95, 0x8, 0x4f, 0x49, 0x2a, 0x5, 0x83, 0x1b, 0x3d, 0xde, 0x2a, 0x8f, 0x89, 0xd5, 0x41, 0x3c] Completed opening the session. @@ -276,16 +278,14 @@ Invoked TA successfully. Received evidence of CBOR (COSE) format from PTA. -CBOR(COSE) size: 306 -CBOR(COSE): d28443a10126a058e7a71901097818687474703a2f2f61726d2e636f6d2f7073612f322e302e3019095a0119095b19300019095c582061636d652d696d706c656d656e746174696f6e2d69642d30303030303030303119095f81a3016450526f5402582031b805aa34f88df47e7cad4ee18c90b595180f49e15e1ec67e133412647ab607055820acbb11c7e4da217205523ce4ce1a245ae1a239ae3c6bfd9e7871f7e5d8bae86b0a58206048bd2455db8a046ecc0720402687d060720d95455792a536f48452d5ee5dbe190100582101ceebae7b8927a3227e5303cf5e0f1f7b34bb542ad7250ac03fbcde36ec2f15085840fd39ee2aac4f64be2a58c1eca501ec1a3a7528f73bcbe8a90e7e1efda7e2cfce793fd28137c8a966793b605981fa677824867b22e21efcd6908338c4e3083b08 +CBOR(COSE) size: 310 +CBOR(COSE): d28443a10126a058eba71901097818687474703a2f2f61726d2e636f6d2f7073612f322e302e3019095a1a5f7cd29d19095b19300019095c582071656d752d6f707465652d72612d30303030303030303030303030303030303119095f81a3016441526f540258204237fb23701092316805005b86b2ab60f5ffb681e19e67d97a29e0939a04ea30055820acbb11c7e4da217205523ce4ce1a245ae1a239ae3c6bfd9e7871f7e5d8bae86b0a5820c469d9070487ac7190301f6d17bb627c95084f492a05831b3dde2a8f89d5413c19010058210190c71e80304f98d6556a402c0593b33a80acbd08e4aff9c4029f6e17e1039951584032935e3ebc3c2c052b7ec31fd8f22c4be5ad43cf21960db1de916d8a967bbae0bc1fa2dd110329cb3edeef1919beb74018fe7fbae99fab1743e024ec5f698150 Supplying the generated evidence to the server. Received the attestation result from the server. -Raw attestation result (JWT): eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJlYXIudmVyaWZpZXItaWQiOnsiYnVpbGQiOiJOL0EiLCJkZXZlbG9wZXIiOiJWZXJhaXNvbiBQcm9qZWN0In0sImVhdF9ub25jZSI6IllFaTlKRlhiaWdSdXpBY2dRQ2FIMEdCeURaVkZWNUtsTnZTRVV0WHVYYjQ9IiwiZWF0X3Byb2ZpbGUiOiJ0YWc6Z2l0aHViLmNvbSwyMDIzOnZlcmFpc29uL2VhciIsImlhdCI6MTcwODU3OTE1OSwic3VibW9kcyI6eyJQU0FfSU9UIjp7ImVhci5hcHByYWlzYWwtcG9saWN5LWlkIjoicG9saWN5OlBTQV9JT1QiLCJlYXIuc3RhdHVzIjoiYWZmaXJtaW5nIiwiZWFyLnRydXN0d29ydGhpbmVzcy12ZWN0b3IiOnsiY29uZmlndXJhdGlvbiI6MCwiZXhlY3V0YWJsZXMiOjIsImZpbGUtc3lzdGVtIjowLCJoYXJkd2FyZSI6MiwiaW5zdGFuY2UtaWRlbnRpdHkiOjIsInJ1bnRpbWUtb3BhcXVlIjoyLCJzb3VyY2VkLWRhdGEiOjAsInN0b3JhZ2Utb3BhcXVlIjoyfSwiZWFyLnZlcmFpc29uLmFubm90YXRlZC1ldmlkZW5jZSI6eyJlYXQtcHJvZmlsZSI6Imh0dHA6Ly9hcm0uY29tL3BzYS8yLjAuMCIsInBzYS1jbGllbnQtaWQiOjEsInBzYS1pbXBsZW1lbnRhdGlvbi1pZCI6IllXTnRaUzFwYlhCc1pXMWxiblJoZEdsdmJpMXBaQzB3TURBd01EQXdNREU9IiwicHNhLWluc3RhbmNlLWlkIjoiQWM3cnJudUpKNk1pZmxNRHoxNFBIM3MwdTFRcTF5VUt3RCs4M2pic0x4VUkiLCJwc2Etbm9uY2UiOiJZRWk5SkZYYmlnUnV6QWNnUUNhSDBHQnlEWlZGVjVLbE52U0VVdFh1WGI0PSIsInBzYS1zZWN1cml0eS1saWZlY3ljbGUiOjEyMjg4LCJwc2Etc29mdHdhcmUtY29tcG9uZW50cyI6W3sibWVhc3VyZW1lbnQtdHlwZSI6IlBSb1QiLCJtZWFzdXJlbWVudC12YWx1ZSI6Ik1iZ0ZxalQ0amZSK2ZLMU80WXlRdFpVWUQwbmhYaDdHZmhNMEVtUjZ0Z2M9Iiwic2lnbmVyLWlkIjoickxzUngrVGFJWElGVWp6a3pob2tXdUdpT2E0OGEvMmVlSEgzNWRpNjZHcz0ifV19fX19.PCUUBd6tyV2WdXuM07de3-ZFpKdoL-uEP7yeP1zNEJOpEJ9sVUDJkINI3nalh7nno2etEitbQABZxBCsy_6tKg - Disposing client session. Completed sending the evidence and receiving the attestation result. @@ -308,20 +308,14 @@ veraison clear-stores ``` ```txt -2024/02/22 05:19:18 Received request: POST /challenge-response/v1/newSession?nonceSize=32 -2024/02/22 05:19:18 Received response: 201 Created -2024/02/22 05:19:19 Received request: POST /challenge-response/v1/session/ed70cc0d-d141-11ee-9588-623338313838 -2024/02/22 05:19:19 Received response: 200 OK -2024/02/22 05:19:19 Attestation result: >> "/tmp/1442613949.jwt" signature successfully verified using "pkey.json" +Attestation result: [claims-set] { "ear.verifier-id": { "build": "N/A", "developer": "Veraison Project" }, - "eat_nonce": "YEi9JFXbigRuzAcgQCaH0GByDZVFV5KlNvSEUtXuXb4=", "eat_profile": "tag:github.com,2023:veraison/ear", - "iat": 1708579159, "submods": { "PSA_IOT": { "ear.appraisal-policy-id": "policy:PSA_IOT", @@ -338,15 +332,14 @@ veraison clear-stores }, "ear.veraison.annotated-evidence": { "eat-profile": "http://arm.com/psa/2.0.0", - "psa-client-id": 1, - "psa-implementation-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", - "psa-instance-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI", - "psa-nonce": "YEi9JFXbigRuzAcgQCaH0GByDZVFV5KlNvSEUtXuXb4=", + "psa-client-id": 1602015901, + "psa-implementation-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=", + "psa-instance-id": "AZDHHoAwT5jWVWpALAWTszqArL0I5K/5xAKfbhfhA5lR", "psa-security-lifecycle": 12288, "psa-software-components": [ { - "measurement-type": "PRoT", - "measurement-value": "MbgFqjT4jfR+fK1O4YyQtZUYD0nhXh7GfhM0EmR6tgc=", + "measurement-type": "ARoT", + "measurement-value": "Qjf7I3AQkjFoBQBbhrKrYPX/toHhnmfZeingk5oE6jA=", "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" } ] @@ -373,22 +366,15 @@ So far, we have verified the flow of successful remote attestation. Next, we wil #### 6.1. Attestation Request from an Unregistered TA -First, we will verify the flow where remote attestation fails by sending a request to the PTA from an unregistered TA. For example, if you rewrite the `IMPLEMENTATION_ID` in [`attester/remote_attestation/ta/include/remote_attestation_ta.h`](attester/remote_attestation/ta/include/remote_attestation_ta.h), the code hash and implementation ID of the TA will change, and the content of the CBOR(COSE) evidence generated by the PTA will also change. As a result, since it differs from the provisioned data, attestation should fail. +First, we will verify the flow where remote attestation fails by sending a request to the PTA from an unregistered TA. For example, if you rewrite the `IMPLEMENTATION_ID` in [`attester/pta_remote_attestation/remote_attestation/remote_attestation.c`](attester/pta_remote_attestation/remote_attestation/remote_attestation.c), the code hash and implementation ID of the TA will change, and the content of the CBOR(COSE) evidence generated by the PTA will also change. As a result, since it differs from the provisioned data, attestation should fail. ```c -diff --git a/attester/remote_attestation/ta/include/remote_attestation_ta.h b/attester/remote_attestation/ta/include/remote_attestation_ta.h -index 4380753..d9cad98 100644 ---- a/attester/remote_attestation/ta/include/remote_attestation_ta.h -+++ b/attester/remote_attestation/ta/include/remote_attestation_ta.h -@@ -16,7 +16,7 @@ - #define TA_REMOTE_ATTESTATOIN_CMD_GEN_CBOR_EVIDENCE 0 - +diff --git a/attester/pta_remote_attestation/remote_attestation/remote_attestation.c b/attester/pta_remote_attestation/remote_attestation/remote_attestation.c +--- a/attester/pta_remote_attestation/remote_attestation/remote_attestation.c ++++ b/attester/pta_remote_attestation/remote_attestation/remote_attestation.c /* Implementation ID used in PSA evidence */ --#define IMPLEMENTATION_ID "acme-implementation-id-000000001" -+#define IMPLEMENTATION_ID "acme-implementation-id-000000002" - #define IMPLEMENTATION_ID_LEN 32 - - #if defined(HOST_BUILD) +-#define IMPLEMENTATION_ID "qemu-optee-ra-000000000000000001" ++#define IMPLEMENTATION_ID "qemu-optee-ra-000000000000000002" ``` Actually, after rewriting the code, send the attestation request. In the terminal where you started QEMU in step 4.4, press `ctrl+c` to exit QEMU. Then, follow step 4.4 again to rebuild the TA and restart QEMU. @@ -451,7 +437,7 @@ D/TC:? 0 cmd_get_cbor_evidence:82 b64_measurement_value: gw9v98IV8ozl5nHpsMwl9W5 ``` Register this value with provisioning. To do this, modify the `digests` field in [`provisoning/data/comid-psa-refval-qemu.json`](provisoning/data/comid-psa-refval-qemu.json) as follows (use `provisoning/data/comid-psa-refval-imx.json` for i.MX 8M Plus). -Also, since the implementation ID has been changed to `acme-implementation-id-000000002`, modify the `psa.impl-id` fields in both [`provisoning/data/comid-psa-refval-qemu.json`](provisoning/data/comid-psa-refval-qemu.json) and [`provisoning/data/comid-psa-ta.json`](provisoning/data/comid-psa-ta.json) as follows. Note that the `psa.impl-id` field must register the base64 encoded value of the implementation ID. For example, you can calculate it with a command like `echo -n "acme-implementation-id-000000002" | base64`. +Also, since the implementation ID has been changed to `qemu-optee-ra-000000000000000002`, modify the `psa.impl-id` fields in both [`provisoning/data/comid-psa-refval-qemu.json`](provisoning/data/comid-psa-refval-qemu.json) and [`provisoning/data/comid-psa-ta-qemu.json`](provisoning/data/comid-psa-ta-qemu.json) as follows. Note that the `psa.impl-id` field must register the base64 encoded value of the implementation ID. For example, you can calculate it with a command like `echo -n "qemu-optee-ra-000000000000000002" | base64`. ```txt diff --git a/provisoning/data/comid-psa-refval-qemu.json b/provisoning/data/comid-psa-refval-qemu.json @@ -462,8 +448,8 @@ index fd7965a..db675c1 100644 "class": { "id": { "type": "psa.impl-id", -- "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" -+ "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDI=" +- "value": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=" ++ "value": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDI=" }, "vendor": "ACME", "model": "RoadRunner" @@ -476,16 +462,14 @@ index fd7965a..db675c1 100644 ] } } -diff --git a/provisoning/data/comid-psa-ta.json b/provisoning/data/comid-psa-ta.json -index 7396dbd..9a813c3 100644 ---- a/provisoning/data/comid-psa-ta.json -+++ b/provisoning/data/comid-psa-ta.json -@@ -22,7 +22,7 @@ +diff --git a/provisoning/data/comid-psa-ta-qemu.json b/provisoning/data/comid-psa-ta-qemu.json +--- a/provisoning/data/comid-psa-ta-qemu.json ++++ b/provisoning/data/comid-psa-ta-qemu.json "class": { "id": { "type": "psa.impl-id", -- "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" -+ "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDI=" +- "value": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=" ++ "value": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDI=" }, "vendor": "ACME", "model": "RoadRunner" @@ -503,8 +487,8 @@ TRUST ANCHORS: "PSA_IOT.hw-model": "RoadRunner", "PSA_IOT.hw-vendor": "ACME", "PSA_IOT.iak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", - "PSA_IOT.inst-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" + "PSA_IOT.impl-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=", + "PSA_IOT.inst-id": "AZDHHoAwT5jWVWpALAWTszqArL0I5K/5xAKfbhfhA5lR" } } { @@ -515,8 +499,8 @@ TRUST ANCHORS: "PSA_IOT.hw-model": "RoadRunner", "PSA_IOT.hw-vendor": "ACME", "PSA_IOT.iak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDI=", - "PSA_IOT.inst-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" + "PSA_IOT.impl-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDI=", + "PSA_IOT.inst-id": "AZDHHoAwT5jWVWpALAWTszqArL0I5K/5xAKfbhfhA5lR" } } @@ -529,9 +513,9 @@ ENDORSEMENTS: "attributes": { "PSA_IOT.hw-model": "RoadRunner", "PSA_IOT.hw-vendor": "ACME", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", + "PSA_IOT.impl-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=", "PSA_IOT.measurement-desc": "sha-256", - "PSA_IOT.measurement-type": "PRoT", + "PSA_IOT.measurement-type": "ARoT", "PSA_IOT.measurement-value": "MbgFqjT4jfR+fK1O4YyQtZUYD0nhXh7GfhM0EmR6tgc=", "PSA_IOT.signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" } @@ -543,9 +527,9 @@ ENDORSEMENTS: "attributes": { "PSA_IOT.hw-model": "RoadRunner", "PSA_IOT.hw-vendor": "ACME", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDI=", + "PSA_IOT.impl-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDI=", "PSA_IOT.measurement-desc": "sha-256", - "PSA_IOT.measurement-type": "PRoT", + "PSA_IOT.measurement-type": "ARoT", "PSA_IOT.measurement-value": "gw9v98IV8ozl5nHpsMwl9W5nGGC0bzAYMPShwvff0vY=", "PSA_IOT.signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" } @@ -580,14 +564,14 @@ After that, follow step 4.5 to send the attestation request, and follow step 5 t }, "ear.veraison.annotated-evidence": { "eat-profile": "http://arm.com/psa/2.0.0", - "psa-client-id": 1, - "psa-implementation-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDI=", - "psa-instance-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI", + "psa-client-id": 403236456, + "psa-implementation-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDI=", + "psa-instance-id": "AZDHHoAwT5jWVWpALAWTszqArL0I5K/5xAKfbhfhA5lR", "psa-nonce": "yBULiGEcBq8wtk5xwRikzPZt1GAV5n8L0nXgPY03jHo=", "psa-security-lifecycle": 12288, "psa-software-components": [ { - "measurement-type": "PRoT", + "measurement-type": "ARoT", "measurement-value": "gw9v98IV8ozl5nHpsMwl9W5nGGC0bzAYMPShwvff0vY=", "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" } @@ -722,7 +706,7 @@ print(pem.strip()) ``` Then update the `instance` and `verification-keys` fields in -`provisoning/data/comid-psa-ta.json` with the computed values. +`provisoning/data/comid-psa-ta-imx.json` with the computed values. #### 8.1 Scenario A: Embedded Test Key @@ -741,7 +725,7 @@ services/deployments/docker/veraison clear-stores ./provisoning/run.sh imx ``` -The default `comid-psa-ta.json` already contains the test key trust anchor. +The default `comid-psa-ta-imx.json` already contains the test key trust anchor. **Attestation** (on device): ```bash @@ -775,7 +759,7 @@ Black key generation completed. ``` **Step 2 — Provision** (on host): Compute instance ID and PEM public key -from PubX/PubY (see helper above), update `comid-psa-ta.json`, then: +from PubX/PubY (see helper above), update `comid-psa-ta-imx.json`, then: ```bash services/deployments/docker/veraison clear-stores ./provisoning/run.sh imx @@ -815,7 +799,7 @@ The public key (PubX/PubY) is not output because you already know it from the original key pair. **Step 2 — Provision** (on host): Compute instance ID and PEM public key -from your known PubX/PubY (see helper above), update `comid-psa-ta.json`, +from your known PubX/PubY (see helper above), update `comid-psa-ta-imx.json`, then: ```bash services/deployments/docker/veraison clear-stores @@ -832,792 +816,3 @@ Expected result: `"ear.status": "affirming"` ## Acknowlegement This work was supported by JST, CREST Grant Number JPMJCR21M3 ([ZeroTrust IoT Project](https://zt-iot.nii.ac.jp/en/)), Japan. - - - ---- ---- ---- - - -# 日本語解説 OP-TEE Remote Attestation with VERAISON Verification - -このドキュメントではQEMUとDockerコンテナを用いた[OP-TEE](https://github.com/OP-TEE/optee_os) Remote Attestation 実行環境の構築と、[VERAISON](https://github.com/veraison) Verification を活用した一連の動作を確認手順を説明します。 -OP-TEEはRaspberry Pi 3B+ (Arm Cortex-A TrustZone)でも動作が確認できています。 - -下図はプロビジョニング(0)、リモートアテステーション(1)-(5)、セキュアコミュニケーション(6)の手順を示しています。 -![](OPTEE-RA.png) - -## 前提条件 - -開発物を実行するには以下を満たす環境を準備する必要があります。 - -* Docker がインストールされていること -* Docker デーモンが稼働していること -* Docker 用に30-40GBのディスクが残っていること(`docker system df`で確認できる。容量が少なければ`docker system prune --volumes --all`で確保を勧める。) -* `jq` がインストールされていること(Ubuntu であれば、`sudo apt-get install jq`) - -## 実行方法 - -以下の 0 から 6 の手順に従い、リモートアテステーションの一連の流れをテストしてください。 - -i.MX 8M Plus 向け Yocto ビルドと実機でのアテステーションは[手順 8](#8-imx8mp-実機でのアテステーション) を参照してください。QEMU 向けの Attester 手順のみ確認したい場合は `attester/README.md` を参照してください。 - -### 0. このgithubのクローン -最初にgit cloneによりoptee-raのソースを取り寄せます。 -```sh -git clone https://github.com/iisec-suzaki/optee-ra -cd optee-ra -``` - -### 1. Veraison が提供するサービスの起動 - -Veraisonのソースをgithubから取り寄せます。 -```sh -git clone https://github.com/veraison/services.git -cd services && git checkout 8f5734c && cd .. -``` -この際に下記のメッセージがでますが、問題ありません。 -``` -Note: switching to '8f5734c'. - -You are in 'detached HEAD' state. You can look around, make experimental -changes and commit them, and you can discard any commits you make in this -state without impacting any branches by switching back to a branch. - -If you want to create a new branch to retain commits you create, you may -do so (now or later) by using -c with the switch command. Example: - - git switch -c - -Or undo this operation with: - - git switch - - -Turn off this advice by setting config variable advice.detachedHead to false - -HEAD is now at 8f5734c Yogesh's review comments -``` - -次にホストマシン上で動作させるサービスを起動します。 -以下のコマンドにより、Veraison を起動することができます。起動には時間がかかります。 -```sh -make -C services docker-deploy -``` - -サービスを起動した後、以下のコマンドで、サービスの状態を確認することができます。zsh を使っている場合、`source services/deployments/docker/env.bash` の代わりに `source services/deployments/docker/env.zsh` を実行してください。 -```sh -source services/deployments/docker/env.bash -veraison status -``` - -正常に、Veraison のサービスが起動した場合、以下のような出力が得られます。 -```txt - vts: running -provisioning: running -verification: running - management: running - keycloak: running -``` - -### 2. Provisioning の実行 - -以下のコマンドで、Verifier に対して、`trust anchor` と `reference value` を登録します。これらの値は Attester から送信された evidence の検証に用いられます。登録する値を変更したい場合は `provisoning/data` 以下のファイルを改変してください。 -```sh -# QEMU (default) -./provisoning/run.sh qemu -# i.MX 8M Plus -./provisoning/run.sh imx -``` - -引数を省略した場合は `qemu` が使われます。 - -登録された値は以下のコマンドで確認できます。 -```sh -veraison stores -``` - -登録が成功すると、以下のような出力が得られます。これは Verifier に登録された値を示しています。 -```txt -TRUST ANCHORS: --------------- -{ - "scheme": "PSA_IOT", - "type": "trust anchor", - "subType": "", - "attributes": { - "PSA_IOT.hw-model": "RoadRunner", - "PSA_IOT.hw-vendor": "ACME", - "PSA_IOT.iak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", - "PSA_IOT.inst-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" - } -} - -ENDORSEMENTS: -------------- -{ - "scheme": "PSA_IOT", - "type": "reference value", - "subType": "PSA_IOT.sw-component", - "attributes": { - "PSA_IOT.hw-model": "RoadRunner", - "PSA_IOT.hw-vendor": "ACME", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", - "PSA_IOT.measurement-desc": "sha-256", - "PSA_IOT.measurement-type": "PRoT", - "PSA_IOT.measurement-value": "MbgFqjT4jfR+fK1O4YyQtZUYD0nhXh7GfhM0EmR6tgc=", - "PSA_IOT.signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" - } -} -``` - -`TRUST ANCHORS` は Attester から送信された evidence の署名を検証するためのデータを示しています。Attester から送信される evidence には `impl-id` と `inst-id` が含まれており、Verifier は受信した evidence をどの `TRUST ANCHOR` で検証するかを識別するためにそれらを用います。Verifier は識別された署名鍵(公開鍵)を用いて、CBOR(COSE) 形式の evidence を検証します。 -* `iak-pub`: evidence の署名を検証するための公開鍵(本プロジェクトでは ECDSA w/ SHA256 アルゴリズムが署名に用いられます。これは生成する evidence の形式が CBOR(COSE) であり、その仕様 [RFC 8152](https://datatracker.ietf.org/doc/html/rfc8152#section-8.1) に準拠したものです。) -* `impl-id`: Attester の ID -* `inst-id`: 公開鍵の ID - -`ENDORSEMENTS` は Attester から送信された evidence の内容を検証するためのデータ(オラクル)を示しています。Attester から送信される evidence には `impl-id` と `measurment-value` が含まれており、Verifier は受信した evidence をどの `ENDORSEMENT` と比較するかを識別するために `impl-id` を用います。Verifier は識別された `ENDORSEMENT` に記録されている `measurement-value` と受信した evidence に含まれる `measurement-value` を比較して、コードハッシュ値の正しさを検証します。その他の項目やより詳細な情報は仕様 [Arm's Platform Security Architecture (PSA) Attestation Token](https://datatracker.ietf.org/doc/draft-tschofenig-rats-psa-token/) を確認してください。 -* `impl-id`: Attester の ID -* `measurement-value`: コードハッシュ値(本プロジェクトでは PTA を呼び出す TA コードの SHA256) - -### 3. Relying Party の起動 - -次に、Relying Party を実行するためのコンテナを起動し、アプリケーションを実行します。Relying Party は、Attester からのリクエストを受け、Attester と Verifier の間の通信を仲介します。また、Verifier からアテステーション結果を受信すると、それをログに出力します。 -```sh -./relying_party/container/start.sh -``` - -以下のコマンドで Relying Party のログは確認できます。 -```sh -docker logs relying-party-service -``` - -正常に起動すると、以下のような出力が得られます。 -```txt -go build -o rp main.go -./rp -2024/02/22 05:17:54 Relying party is starting... -``` - -### 4. Attester の起動 - -次に、アテステーションリクエストを送信する Attester を起動します。コンテナ上の QEMU の上で Attester を動作させる環境を準備しています。以下の 5 つの手順に従い、コンテナの起動し、 Verifier との通信プログラムを実行してください。 - -#### 4.1. コンテナの起動 - -以下のコマンドを実行すると、Docker コンテナ上に入ります。注意として、初期実行時にはイメージのビルドに時間がかかるため、コンテナが起動するのに数十分かかることがあります。 -```sh -./attester/container/start.sh -``` - -#### 4.2. normal world のターミナルを開く - -手順 4.1. でコンテナを起動したターミナルとは別のターミナルを開き、以下を実行してください。QEMU 上で実行する Attester の normal world に接続する用のターミナルが準備されます。 -```sh -./attester/container/launch_soc_term.sh normal -``` - -#### 4.3. secure world のターミナルを開く - -手順 4.1. と 4.2. で使用したターミナルとは別のターミナルを開き、以下を実行してください。QEMU 上で実行する Attester の secure world に接続する用のターミナルが準備されます。 -```sh -./attester/container/launch_soc_term.sh secure -``` - -#### 4.4. ユーザが追加した CA/TA/PTA のビルドと、QEMU の起動とログイン - -手順 4.1. で起動したターミナルで以下コマンドをを実行してください。ユーザが追加した CA/TA/PTA を再ビルドし、QEMU を起動します。コンテナイメージが `/optee/optee_os/core/pta/sub.mk` に `subdirs-y += remote_attestation` を自動で追加するため、手動編集は不要です。 -```sh -make -C ${OPTEE_DIR}/build run CFG_REMOTE_ATTESTATION_PTA=y -j -``` - -QEMU が立ち上がったら、c を入力します。 -```sh -(qemu) c -``` - -次に、normal world のターミナル(2. で起動したターミナル)上で、`test` ユーザでログインします。 -```sh -buildroot login: test -``` - -#### 4.5. プログラムの実行 - -プログラムは normal world のターミナル上で起動します。 -開発した evidence 生成プログラムを実行する場合は、以下のコマンドで実行できます。 -```sh -optee_remote_attestation -``` - -正しく実行できた場合、以下のような出力が noromal world のターミナルで得られます。 -```txt -Opened new Veraison client session at http://relying-party-service:8087/challenge-response/v1/session/ed70cc0d-d141-11ee-9588-623338313838 - -Number of media types accepted: 7 - application/vnd.parallaxsecond.key-attestation.cca - application/vnd.parallaxsecond.key-attestation.tpm - application/pem-certificate-chain - application/vnd.enacttrust.tpm-evidence - application/eat-collection; profile=http://arm.com/CCA-SSD/1.0.0 - application/psa-attestation-token - application/eat-cwt; profile=http://arm.com/psa/2.0.0 - -Nonce size: 32 bytes -Nonce: [0x60, 0x48, 0xbd, 0x24, 0x55, 0xdb, 0x8a, 0x4, 0x6e, 0xcc, 0x7, 0x20, 0x40, 0x26, 0x87, 0xd0, 0x60, 0x72, 0xd, 0x95, 0x45, 0x57, 0x92, 0xa5, 0x36, 0xf4, 0x84, 0x52, 0xd5, 0xee, 0x5d, 0xbe] - -Completed opening the session. - - -Invoke TA. -Invoked TA successfully. - - -Received evidence of CBOR (COSE) format from PTA. - -CBOR(COSE) size: 306 -CBOR(COSE): d28443a10126a058e7a71901097818687474703a2f2f61726d2e636f6d2f7073612f322e302e3019095a0119095b19300019095c582061636d652d696d706c656d656e746174696f6e2d69642d30303030303030303119095f81a3016450526f5402582031b805aa34f88df47e7cad4ee18c90b595180f49e15e1ec67e133412647ab607055820acbb11c7e4da217205523ce4ce1a245ae1a239ae3c6bfd9e7871f7e5d8bae86b0a58206048bd2455db8a046ecc0720402687d060720d95455792a536f48452d5ee5dbe190100582101ceebae7b8927a3227e5303cf5e0f1f7b34bb542ad7250ac03fbcde36ec2f15085840fd39ee2aac4f64be2a58c1eca501ec1a3a7528f73bcbe8a90e7e1efda7e2cfce793fd28137c8a966793b605981fa677824867b22e21efcd6908338c4e3083b08 - - -Supplying the generated evidence to the server. - -Received the attestation result from the server. - -Raw attestation result (JWT): eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJlYXIudmVyaWZpZXItaWQiOnsiYnVpbGQiOiJOL0EiLCJkZXZlbG9wZXIiOiJWZXJhaXNvbiBQcm9qZWN0In0sImVhdF9ub25jZSI6IllFaTlKRlhiaWdSdXpBY2dRQ2FIMEdCeURaVkZWNUtsTnZTRVV0WHVYYjQ9IiwiZWF0X3Byb2ZpbGUiOiJ0YWc6Z2l0aHViLmNvbSwyMDIzOnZlcmFpc29uL2VhciIsImlhdCI6MTcwODU3OTE1OSwic3VibW9kcyI6eyJQU0FfSU9UIjp7ImVhci5hcHByYWlzYWwtcG9saWN5LWlkIjoicG9saWN5OlBTQV9JT1QiLCJlYXIuc3RhdHVzIjoiYWZmaXJtaW5nIiwiZWFyLnRydXN0d29ydGhpbmVzcy12ZWN0b3IiOnsiY29uZmlndXJhdGlvbiI6MCwiZXhlY3V0YWJsZXMiOjIsImZpbGUtc3lzdGVtIjowLCJoYXJkd2FyZSI6MiwiaW5zdGFuY2UtaWRlbnRpdHkiOjIsInJ1bnRpbWUtb3BhcXVlIjoyLCJzb3VyY2VkLWRhdGEiOjAsInN0b3JhZ2Utb3BhcXVlIjoyfSwiZWFyLnZlcmFpc29uLmFubm90YXRlZC1ldmlkZW5jZSI6eyJlYXQtcHJvZmlsZSI6Imh0dHA6Ly9hcm0uY29tL3BzYS8yLjAuMCIsInBzYS1jbGllbnQtaWQiOjEsInBzYS1pbXBsZW1lbnRhdGlvbi1pZCI6IllXTnRaUzFwYlhCc1pXMWxiblJoZEdsdmJpMXBaQzB3TURBd01EQXdNREU9IiwicHNhLWluc3RhbmNlLWlkIjoiQWM3cnJudUpKNk1pZmxNRHoxNFBIM3MwdTFRcTF5VUt3RCs4M2pic0x4VUkiLCJwc2Etbm9uY2UiOiJZRWk5SkZYYmlnUnV6QWNnUUNhSDBHQnlEWlZGVjVLbE52U0VVdFh1WGI0PSIsInBzYS1zZWN1cml0eS1saWZlY3ljbGUiOjEyMjg4LCJwc2Etc29mdHdhcmUtY29tcG9uZW50cyI6W3sibWVhc3VyZW1lbnQtdHlwZSI6IlBSb1QiLCJtZWFzdXJlbWVudC12YWx1ZSI6Ik1iZ0ZxalQ0amZSK2ZLMU80WXlRdFpVWUQwbmhYaDdHZmhNMEVtUjZ0Z2M9Iiwic2lnbmVyLWlkIjoickxzUngrVGFJWElGVWp6a3pob2tXdUdpT2E0OGEvMmVlSEgzNWRpNjZHcz0ifV19fX19.PCUUBd6tyV2WdXuM07de3-ZFpKdoL-uEP7yeP1zNEJOpEJ9sVUDJkINI3nalh7nno2etEitbQABZxBCsy_6tKg - -Disposing client session. - -Completed sending the evidence and receiving the attestation result. -``` - -### 5. 検証の実行と結果の確認 - -もう一つターミナルを開き、以下のコマンドでrelying party のターミナルのログを確認できます。 -```sh -docker logs relying-party-service -``` - -アテステーション結果は `ear.status` の欄に記載されており、`affirming` であれば正しいアテステーション結果が得られたことを意味しています。 - -`ear.status` が `warning` で `executables not recognized` のようなログが出る場合は、古いエンドースメントが残っています。`env.bash` を source したシェルでストアをクリアし、provisioning をやり直してください(実機は `imx` を指定します)。 - -```sh -veraison clear-stores -./provisoning/run.sh qemu -``` -```txt -2024/02/22 05:19:18 Received request: POST /challenge-response/v1/newSession?nonceSize=32 -2024/02/22 05:19:18 Received response: 201 Created -2024/02/22 05:19:19 Received request: POST /challenge-response/v1/session/ed70cc0d-d141-11ee-9588-623338313838 -2024/02/22 05:19:19 Received response: 200 OK -2024/02/22 05:19:19 Attestation result: >> "/tmp/1442613949.jwt" signature successfully verified using "pkey.json" -[claims-set] -{ - "ear.verifier-id": { - "build": "N/A", - "developer": "Veraison Project" - }, - "eat_nonce": "YEi9JFXbigRuzAcgQCaH0GByDZVFV5KlNvSEUtXuXb4=", - "eat_profile": "tag:github.com,2023:veraison/ear", - "iat": 1708579159, - "submods": { - "PSA_IOT": { - "ear.appraisal-policy-id": "policy:PSA_IOT", - "ear.status": "affirming", - "ear.trustworthiness-vector": { - "configuration": 0, - "executables": 2, - "file-system": 0, - "hardware": 2, - "instance-identity": 2, - "runtime-opaque": 2, - "sourced-data": 0, - "storage-opaque": 2 - }, - "ear.veraison.annotated-evidence": { - "eat-profile": "http://arm.com/psa/2.0.0", - "psa-client-id": 1, - "psa-implementation-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", - "psa-instance-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI", - "psa-nonce": "YEi9JFXbigRuzAcgQCaH0GByDZVFV5KlNvSEUtXuXb4=", - "psa-security-lifecycle": 12288, - "psa-software-components": [ - { - "measurement-type": "PRoT", - "measurement-value": "MbgFqjT4jfR+fK1O4YyQtZUYD0nhXh7GfhM0EmR6tgc=", - "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" - } - ] - } - } - } -} -[trustworthiness vectors] -submod(PSA_IOT): -Instance Identity [affirming]: The Attesting Environment is recognized, and the associated instance of the Attester is not known to be compromised. -Configuration [none]: The Evidence received is insufficient to make a conclusion. -Executables [affirming]: Only a recognized genuine set of approved executables, scripts, files, and/or objects have been loaded during and after the boot process. -File System [none]: The Evidence received is insufficient to make a conclusion. -Hardware [affirming]: An Attester has passed its hardware and/or firmware verifications needed to demonstrate that these are genuine/supported. -Runtime Opaque [affirming]: the Attester's executing Target Environment and Attesting Environments are encrypted and within Trusted Execution Environment(s) opaque to the operating system, virtual machine manager, and peer applications. -Storage Opaque [affirming]: the Attester encrypts all secrets in persistent storage via using keys which are never visible outside an HSM or the Trusted Execution Environment hardware. -Sourced Data [none]: The Evidence received is insufficient to make a conclusion. -``` - -### 6. 異なる TA からアテステーションリクエストを送信するシナリオ - -ここまでで、リモートアテステーションが成功する一連の流れを確認しました。次に、異なる TA からアテステーションリクエストを送った際に失敗するシナリオと、新たな endorsment を登録することでアテステーションが成功されるシナリオを確認します。 - -#### 6.1. 登録されていない TA からのアテステーションリクエスト - -はじめに、録されてない TA から PTA にリクエストを送り、リモートアテステーションが失敗する流れを確認します。例えば、以下のように [`attester/remote_attestation/ta/include/remote_attestation_ta.h`](attester/remote_attestation/ta/include/remote_attestation_ta.h) の `IMPLEMENTATION_ID` を書き換えると、TA のコードハッシュと implementation ID が変わり、PTA が生成する CBOR(COSE) evidence の内容が変わります。これにより、provisioning されているデータと異なるので、アテステーションが失敗するはずです。 -```c -diff --git a/attester/remote_attestation/ta/include/remote_attestation_ta.h b/attester/remote_attestation/ta/include/remote_attestation_ta.h -index 4380753..d9cad98 100644 ---- a/attester/remote_attestation/ta/include/remote_attestation_ta.h -+++ b/attester/remote_attestation/ta/include/remote_attestation_ta.h -@@ -16,7 +16,7 @@ - #define TA_REMOTE_ATTESTATOIN_CMD_GEN_CBOR_EVIDENCE 0 - - /* Implementation ID used in PSA evidence */ --#define IMPLEMENTATION_ID "acme-implementation-id-000000001" -+#define IMPLEMENTATION_ID "acme-implementation-id-000000002" - #define IMPLEMENTATION_ID_LEN 32 - - #if defined(HOST_BUILD) -``` - -実際に、コードを書き換えた後にアテステーションリクエストを送信してみます。手順 4.4. で QEMU を起動したターミナルで `ctrl+c` をして、一度 QEMU を終了します。その後、もう一度手順 4.4 に従い、TA の再ビルド・QEMU の再起動をします。 - -その後、手順 4.5. に従い、アテステーションリクエストを送り、手順 5. に従い結果を確認すると、以下のようなアテステーション結果が得られます。`"ear.status": "contraindicated"` になっており、アテステーションに失敗していることがわかります。 -```txt -2024/02/22 05:36:19 Received request: POST /challenge-response/v1/newSession?nonceSize=32 -2024/02/22 05:36:19 Received response: 201 Created -2024/02/22 05:36:20 Received request: POST /challenge-response/v1/session/4e2f256e-d144-11ee-9588-623338313838 -2024/02/22 05:36:20 Received response: 200 OK -2024/02/22 05:36:20 Attestation result: >> "/tmp/3383640462.jwt" signature successfully verified using "pkey.json" -[claims-set] -{ - "ear.verifier-id": { - "build": "commit-b50b67d", - "developer": "Veraison Project" - }, - "eat_nonce": "J5um9vO4NYv8hYqPXUWsYuuWgW0TLV0qoZGQk3EnIUg=", - "eat_profile": "tag:github.com,2023:veraison/ear", - "iat": 1708580180, - "submods": { - "PSA_IOT": { - "ear.appraisal-policy-id": "policy:PSA_IOT", - "ear.status": "contraindicated", - "ear.trustworthiness-vector": { - "configuration": 99, - "executables": 99, - "file-system": 99, - "hardware": 99, - "instance-identity": 99, - "runtime-opaque": 99, - "sourced-data": 99, - "storage-opaque": 99 - }, - "ear.veraison.policy-claims": { - "problem": "no trust anchor for evidence" - } - } - } -} -[trustworthiness vectors] -submod(PSA_IOT): -Instance Identity [contraindicated]: Cryptographic validation of the Evidence has failed. -Configuration [contraindicated]: Cryptographic validation of the Evidence has failed. -Executables [contraindicated]: Cryptographic validation of the Evidence has failed. -File System [contraindicated]: Cryptographic validation of the Evidence has failed. -Hardware [contraindicated]: Cryptographic validation of the Evidence has failed. -Runtime Opaque [contraindicated]: Cryptographic validation of the Evidence has failed. -Storage Opaque [contraindicated]: Cryptographic validation of the Evidence has failed. -Sourced Data [contraindicated]: Cryptographic validation of the Evidence has failed. -``` - -#### 6.2. provisioning で新たな TA を登録する - -はじめに、新たな TA のコードハッシュ値を確認します。現在、PTA に evidence 生成リクエストを送ると、secure terminal にコードハッシュ値がデバッグ用に出力される実装になっています。具体的には以下のような一行があり、`gw9v98IV8ozl5nHpsMwl9W5nGGC0bzAYMPShwvff0vY=` がコードハッシュ値を base64 エンコードした値です。 -```txt -D/TC:? 0 cmd_get_cbor_evidence:82 b64_measurement_value: gw9v98IV8ozl5nHpsMwl9W5nGGC0bzAYMPShwvff0vY= -``` - -この値を provisioning で登録します。そのためには、[`provisoning/data/comid-psa-refval-qemu.json`](provisoning/data/comid-psa-refval-qemu.json) の `digests` の欄を以下のように書き換えてください(実機の場合は `provisoning/data/comid-psa-refval-imx.json` を使います)。 -また、implementation ID も `acme-implementation-id-000000002` に変更しているため、[`provisoning/data/comid-psa-refval-qemu.json`](provisoning/data/comid-psa-refval-qemu.json) と [`provisoning/data/comid-psa-ta.json`](provisoning/data/comid-psa-ta.json) の `psa.impl-id` の欄を以下のように書き換えてください。注意しとして、`psa.impl-id` の欄は implementation ID を base64 エンコードした値を登録する必要があります。例えば、`echo -n "acme-implementation-id-000000002" | base64` のようなコマンドで計算できます。 -```txt -diff --git a/provisoning/data/comid-psa-refval-qemu.json b/provisoning/data/comid-psa-refval-qemu.json -index fd7965a..db675c1 100644 ---- a/provisoning/data/comid-psa-refval-qemu.json -+++ b/provisoning/data/comid-psa-refval-qemu.json -@@ -22,7 +22,7 @@ - "class": { - "id": { - "type": "psa.impl-id", -- "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" -+ "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDI=" - }, - "vendor": "ACME", - "model": "RoadRunner" -@@ -39,7 +39,7 @@ - }, - "value": { - "digests": [ -- "sha-256;MbgFqjT4jfR+fK1O4YyQtZUYD0nhXh7GfhM0EmR6tgc=" -+ "sha-256;gw9v98IV8ozl5nHpsMwl9W5nGGC0bzAYMPShwvff0vY=" - ] - } - } -diff --git a/provisoning/data/comid-psa-ta.json b/provisoning/data/comid-psa-ta.json -index 7396dbd..9a813c3 100644 ---- a/provisoning/data/comid-psa-ta.json -+++ b/provisoning/data/comid-psa-ta.json -@@ -22,7 +22,7 @@ - "class": { - "id": { - "type": "psa.impl-id", -- "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=" -+ "value": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDI=" - }, - "vendor": "ACME", - "model": "RoadRunner" -``` - -その後、手順 2. に従い、provisioning を再実行します。その結果、以下のように二つの `TRUST ANCHORS` と `ENDORSEMENTS` が登録され、`PSA_IOT.impl-id` と `PSA_IOT.measurement-value` の部分のみが異なることを確認できます。 -```json -TRUST ANCHORS: --------------- -{ - "scheme": "PSA_IOT", - "type": "trust anchor", - "subType": "", - "attributes": { - "PSA_IOT.hw-model": "RoadRunner", - "PSA_IOT.hw-vendor": "ACME", - "PSA_IOT.iak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", - "PSA_IOT.inst-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" - } -} -{ - "scheme": "PSA_IOT", - "type": "trust anchor", - "subType": "", - "attributes": { - "PSA_IOT.hw-model": "RoadRunner", - "PSA_IOT.hw-vendor": "ACME", - "PSA_IOT.iak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDI=", - "PSA_IOT.inst-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" - } -} - -ENDORSEMENTS: -------------- -{ - "scheme": "PSA_IOT", - "type": "reference value", - "subType": "PSA_IOT.sw-component", - "attributes": { - "PSA_IOT.hw-model": "RoadRunner", - "PSA_IOT.hw-vendor": "ACME", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", - "PSA_IOT.measurement-desc": "sha-256", - "PSA_IOT.measurement-type": "PRoT", - "PSA_IOT.measurement-value": "MbgFqjT4jfR+fK1O4YyQtZUYD0nhXh7GfhM0EmR6tgc=", - "PSA_IOT.signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" - } -} -{ - "scheme": "PSA_IOT", - "type": "reference value", - "subType": "PSA_IOT.sw-component", - "attributes": { - "PSA_IOT.hw-model": "RoadRunner", - "PSA_IOT.hw-vendor": "ACME", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDI=", - "PSA_IOT.measurement-desc": "sha-256", - "PSA_IOT.measurement-type": "PRoT", - "PSA_IOT.measurement-value": "gw9v98IV8ozl5nHpsMwl9W5nGGC0bzAYMPShwvff0vY=", - "PSA_IOT.signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" - } -} -``` - -その後、手順 4.5. に従いアテステーションリクエストを送り、手順 5. に従い結果を確認すると、以下のようなアテステーション結果が得られます。`"ear.status": "affirming"` になっており、アテステーションに成功していることがわかります。 -```json -[claims-set] -{ - "ear.verifier-id": { - "build": "N/A", - "developer": "Veraison Project" - }, - "eat_nonce": "yBULiGEcBq8wtk5xwRikzPZt1GAV5n8L0nXgPY03jHo=", - "eat_profile": "tag:github.com,2023:veraison/ear", - "iat": 1708581024, - "submods": { - "PSA_IOT": { - "ear.appraisal-policy-id": "policy:PSA_IOT", - "ear.status": "affirming", - "ear.trustworthiness-vector": { - "configuration": 0, - "executables": 2, - "file-system": 0, - "hardware": 2, - "instance-identity": 2, - "runtime-opaque": 2, - "sourced-data": 0, - "storage-opaque": 2 - }, - "ear.veraison.annotated-evidence": { - "eat-profile": "http://arm.com/psa/2.0.0", - "psa-client-id": 1, - "psa-implementation-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDI=", - "psa-instance-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI", - "psa-nonce": "yBULiGEcBq8wtk5xwRikzPZt1GAV5n8L0nXgPY03jHo=", - "psa-security-lifecycle": 12288, - "psa-software-components": [ - { - "measurement-type": "PRoT", - "measurement-value": "gw9v98IV8ozl5nHpsMwl9W5nGGC0bzAYMPShwvff0vY=", - "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" - } - ] - } - } - } -} -``` - -### 7. クリーンアップ - -以下のコマンドでこのテストのために立ち上げたコンテナなどを停止することができます。 - -```sh -make -C services really-clean -docker stop relying-party-service -docker network rm veraison-net -``` - -### 8. i.MX8MP 実機でのアテステーション - -本セクションでは i.MX8MP EVK 実機上で PSA Remote Attestation を実行し、 -Veraison で検証する手順を説明します。埋め込みテスト鍵、CAAM ブラックキー新規生成、 -既存鍵の変換の 3 つのシナリオを扱います。 - -#### 8.0 i.MX8MP Yocto ビルドと SD 書き込み - -必要環境: -- Docker -- 約100GB の空き容量(初回) -- 4-8時間のビルド時間(初回) - -フルイメージのビルド(リポジトリ直下から): -```bash -cd attester/container-imx -./yocto.sh -``` - -tmpfs を使って高速化する場合: -```bash -YOCTO_DIR=/dev/shm/yocto ./yocto.sh -``` - -注意: tmpfs では一部パッケージ(例: `gdk-pixbuf-native`)のビルドが失敗する場合があります。その場合は通常のファイルシステムを使用してください。 - -部分的な再ビルド: -```bash -./yocto.sh optee-os -./yocto.sh veraison-attestation -``` - -注意: i.MX8MP は SD 先頭の `imx-boot` に埋め込まれた `tee.bin` を使用します。`./yocto.sh optee-os` は `imx-boot` の再ビルドまで実行しますが、SD 書き込み用の WIC を更新するには `./yocto.sh`(full)で再パッケージしてください。 - -出力イメージ: -``` -${YOCTO_DIR}/build/tmp/deploy/images/imx8mpevk/core-image-minimal-imx8mpevk.rootfs.wic.zst -``` - -SD カードへの書き込み: -```bash -cd ${YOCTO_DIR}/build/tmp/deploy/images/imx8mpevk/ -zstd -d core-image-minimal-imx8mpevk.rootfs.wic.zst -sudo dd if=core-image-minimal-imx8mpevk.rootfs.wic of=/dev/sdX bs=4M status=progress && sync -``` - -`/dev/sdX` は実際の SD カードデバイスに置き換えてください。 - -#### 前提条件 - -| 項目 | 詳細 | -|------|------| -| ボード | i.MX8MP EVK | -| ビルド | `core-image-minimal` (Yocto + OP-TEE + veraison-attestation PTA) | -| Veraison | Docker デプロイメント (`services/deployments/docker/`) | -| ネットワーク | デバイスと Veraison ホストが IP 到達可能 | -| SD カード | imx-boot と rootfs の両方を含む WIC イメージ | - -> **重要**: i.MX8MP は SD カード先頭の imx-boot 内の `tee.bin` を使用します。 -> rootfs 上の `/usr/lib/firmware/tee.bin` を更新しても Secure World には -> 反映されません。PTA のコード変更を反映するには **imx-boot を含む WIC イメージ全体** -> を再フラッシュする必要があります。 - -デバイス側で Veraison ホストを `/etc/hosts` に追加: -```bash -echo " relying-party-service" >> /etc/hosts -``` - -Veraison ホスト側でサービスを起動: -```bash -services/deployments/docker/veraison start -source services/deployments/docker/env.bash -``` - -#### Provisioning ヘルパー: Instance ID と PEM 公開鍵の計算 - -全シナリオ共通で `instance-id = 0x01 || SHA-256(0x04 || PubX || PubY)` です。 -CAAM 鍵を使う場合(シナリオ B, C)は、ホスト側で PubX/PubY から instance ID と -PEM 公開鍵を計算します: - -```bash -python3 -c " -import hashlib, base64 -pub_x = bytes.fromhex('') -pub_y = bytes.fromhex('') -digest = hashlib.sha256(b'\x04' + pub_x + pub_y).digest() -instance_id = b'\x01' + digest -print('instance_id (base64):', base64.b64encode(instance_id).decode()) -" -``` - -```bash -python3 -c " -from cryptography.hazmat.primitives.asymmetric import ec -from cryptography.hazmat.primitives import serialization -pub_x = bytes.fromhex('') -pub_y = bytes.fromhex('') -pub_numbers = ec.EllipticCurvePublicNumbers( - x=int.from_bytes(pub_x, 'big'), - y=int.from_bytes(pub_y, 'big'), - curve=ec.SECP256R1() -) -pub_key = pub_numbers.public_key() -pem = pub_key.public_bytes( - serialization.Encoding.PEM, - serialization.PublicFormat.SubjectPublicKeyInfo -).decode() -print(pem.strip()) -" -``` - -計算した値で `provisoning/data/comid-psa-ta.json` の `instance` と -`verification-keys` を更新してください。 - -#### 8.1 シナリオ A: 埋め込みテスト鍵 - -PTA に埋め込まれたテスト用 ECDSA P-256 鍵で evidence に署名します。 -デバイス側での鍵管理は不要です。 - -| 項目 | 値 | -|------|-----| -| PubX | `30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e` | -| PubY | `e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723` | -| Instance ID | `AZDHHoAwT5jWVWpALAWTszqArL0I5K/5xAKfbhfhA5lR` | - -**Provisioning**: -```bash -services/deployments/docker/veraison clear-stores -./provisoning/run.sh imx -``` - -デフォルトの `comid-psa-ta.json` にはテスト鍵の trust anchor が設定済みです。 - -**Attestation 実行** (デバイス側): -```bash -optee_remote_attestation -``` - -期待される結果: `"ear.status": "affirming"` - -#### 8.2 シナリオ B: CAAM ブラックキー — 新規鍵生成 - -CAAM モジュールで新しい ECDSA P-256 鍵ペアを生成します。 -秘密鍵は JDKEK で暗号化されており、プレーンテキストではメモリ上に露出しません。 - -> **注意**: ブラックキーは JDKEK (揮発性) で暗号化されています。 -> 電源サイクルで JDKEK が再生成されるため、**同一ブートセッション内でのみ使用可能**です。 - -**手順 1 — 鍵生成** (デバイス側): -```bash -optee_remote_attestation --generate-blackkey -``` - -出力例: -``` -Generating new black key... -BlackKey(hex): fbbfafca020000002000000... -PubX(hex): 3d87f38e7b34e5c0bc988becb225783daa4d14dc0031f49588fe61708c4f1f6f -PubY(hex): 15dc6990d4209e3cb1f732310a4784a535a93962b7d87274286026ec80153ce4 -FullKey(hex): 3d87f38e7b34e5c0...fbbfafca020000002000000... -Black key generation completed. -``` - -**手順 2 — Provisioning** (ホスト側): PubX/PubY から instance ID と PEM 公開鍵を -計算し(上記ヘルパー参照)、`comid-psa-ta.json` を更新後: -```bash -services/deployments/docker/veraison clear-stores -./provisoning/run.sh imx -``` - -**手順 3 — Attestation 実行** (デバイス側): FullKey をそのまま渡す: -```bash -optee_remote_attestation --key-hex -``` - -または各コンポーネントを個別に渡す: -```bash -optee_remote_attestation --key-hex --pubx-hex --puby-hex -``` - -期待される結果: `"ear.status": "affirming"` - -#### 8.3 シナリオ C: CAAM ブラックキー — 既存鍵の変換 - -既存のプレーンテキスト ECDSA P-256 秘密鍵(32 バイトの `d` 値)を -CAAM ブラックキーに変換します。OpenSSL 等で生成済みの鍵ペアがある場合に使用します。 - -**手順 1 — 鍵変換** (デバイス側): -```bash -optee_remote_attestation --convert-key <32バイト秘密鍵 hex> -``` - -出力例: -``` -Converting plain key to black key... -BlackKey(hex): fbbfafca020000002000000... -Key conversion completed. -``` - -公開鍵 (PubX/PubY) は出力されません。元の鍵ペアから既知のためです。 - -**手順 2 — Provisioning** (ホスト側): 既知の PubX/PubY から instance ID と -PEM 公開鍵を計算し(上記ヘルパー参照)、`comid-psa-ta.json` を更新後: -```bash -services/deployments/docker/veraison clear-stores -./provisoning/run.sh imx -``` - -**手順 3 — Attestation 実行** (デバイス側): -```bash -optee_remote_attestation --key-hex --pubx-hex --puby-hex -``` - -期待される結果: `"ear.status": "affirming"` - -## 謝辞 -研究は、JST、CREST、JPMJCR21M3 ([Zero Trust IoT プロジェクト](https://zt-iot.nii.ac.jp/)) の支援を受けたものです。 diff --git a/docs/secure-boot-imx8mp-j.md b/docs/secure-boot-imx8mp-j.md index ab81eef..bf2f711 100644 --- a/docs/secure-boot-imx8mp-j.md +++ b/docs/secure-boot-imx8mp-j.md @@ -176,25 +176,89 @@ Secure Boot により CAAM の鍵文脈(MPMR/BKEK)が変わるため、古 ## 10) BlackKey 使い回し不可の検証(2台) -両方の実機で **同じ SRK** を書き込みます。 +CAAM BlackKey がデバイス固有であることを検証します。同じ SRK fuse 値を持つ +2台のデバイスでも、各デバイスの JDKEK(ハードウェア固有のエントロピーから +導出)が異なるため、BlackKey は別デバイスでは使用できません。 -Device A: +両方の実機を **同じ SRK** で Close しておきます(手順 8-9)。 + +### 10.1 Device A の BlackKey を Device B で使用 + +**Device A** で BlackKey を生成: ```bash optee_remote_attestation --generate-blackkey # FullKey を控える ``` -Device B: +**Device B** で Device A の FullKey を使用: ```bash optee_remote_attestation --key-hex ``` -期待: **失敗**(`Failed to sign payload` など)。 +期待: `Failed to sign payload` — Device B の CAAM は Device A の BlackKey +blob を復号できないため、署名に失敗します。 + +### 10.2 Device B で新規 BlackKey を生成 + +```bash +optee_remote_attestation --generate-blackkey +# FullKey を控える +optee_remote_attestation --key-hex +``` + +期待: `ear.status: "contraindicated"`、`"no trust anchor for evidence"`。 + +署名は成功しますが、Device B の公開鍵(`psa-instance-id`)が Verifier に +登録されていないため、アテステーションは失敗します。 + +### 10.3 Device B を Verifier に登録して検証 + +Device B のアテステーションを成功させるには、Verifier に trust anchor を +追加登録します。`--generate-blackkey` で出力された PubX/PubY から +instance-id と PEM 公開鍵を計算し(手順 9 のヘルパー参照)、Device B 用の +provisioning JSON を作成して submit します: + +```bash +# Device B の trust anchor をビルド・登録 +veraison -- cocli comid create \ + --template provisoning/data/comid-psa-ta-deviceB.json \ + --template provisoning/data/comid-psa-refval-imx.json \ + --output-dir provisoning/data + +veraison -- cocli corim create \ + --template provisoning/data/corim-psa.json \ + --comid provisoning/data/comid-psa-refval-imx.cbor \ + --comid provisoning/data/comid-psa-ta-deviceB.cbor \ + --output provisoning/data/psa-endorsements-deviceB.cbor + +veraison -- cocli corim submit \ + --corim-file provisoning/data/psa-endorsements-deviceB.cbor \ + --api-server "https://provisioning-service:9443/endorsement-provisioning/v1/submit" \ + --media-type 'application/corim-unsigned+cbor; profile="http://arm.com/psa/iot/1"' +``` + +**Device B** で再度アテステーションを実行: + +```bash +optee_remote_attestation --key-hex +``` + +期待: `ear.status: "affirming"`。 + +### まとめ + +| テスト | 結果 | 意味 | +|--------|------|------| +| A の BlackKey を B で使用 | `Failed to sign` | BlackKey はデバイス固有(JDKEK が異なる) | +| B の新規 BlackKey(未登録) | `no trust anchor` | 鍵ペアが異なり instance-id が Verifier に未登録 | +| B の BlackKey を登録後 | `affirming` | trust anchor 追加後、アテステーション成功 | ## 注意事項 - Close は不可逆です。鍵のバックアップは必須。 - 署名済み imx‑boot は WIC の 32KB に埋め込まれます。 - 2台検証では SRK 値を必ず揃える必要があります。 +- 各デバイスは固有の CAAM 鍵ペアを生成するため、Verifier にはデバイスごとに + trust anchor を個別登録する必要があります。 diff --git a/docs/secure-boot-imx8mp.md b/docs/secure-boot-imx8mp.md index 37d75cd..677be11 100644 --- a/docs/secure-boot-imx8mp.md +++ b/docs/secure-boot-imx8mp.md @@ -177,25 +177,91 @@ the CAAM key context (MPMR/BKEK), so old BlackKeys are no longer valid. ## 10) BlackKey non-reuse test (two devices) -Use the same SRK for both devices. +This test proves that CAAM BlackKeys are device-bound. Even when two devices +share the same SRK fuse values, each device's JDKEK (derived from unique +hardware entropy) encrypts BlackKeys differently, so a BlackKey generated on +one device cannot be used on another. -Device A: +Both devices must be **closed** with the same SRK (Steps 8-9). + +### 11.1 Test A's BlackKey on Device B + +Generate a BlackKey on **Device A**: ```bash optee_remote_attestation --generate-blackkey # Save FullKey(hex) ``` -Device B: +Use Device A's FullKey on **Device B**: ```bash optee_remote_attestation --key-hex ``` -Expected: **failure** (e.g. `Failed to sign payload`), proving BlackKey is device-bound. +Expected: `Failed to sign payload` — Device B's CAAM cannot decrypt A's +BlackKey blob, so signing fails. + +### 11.2 Generate a new BlackKey on Device B + +```bash +optee_remote_attestation --generate-blackkey +# Save FullKey(hex) +optee_remote_attestation --key-hex +``` + +Expected: `ear.status: "contraindicated"` with `"no trust anchor for evidence"`. + +Signing succeeds because Device B's CAAM can use its own BlackKey, but the +Verifier rejects the evidence because Device B's public key (and therefore its +`psa-instance-id`) is not registered as a trust anchor. + +### 11.3 Register Device B and verify + +To make Device B's attestation succeed, register its trust anchor with the +Verifier. Compute the instance-id and PEM public key from the PubX/PubY +output of `--generate-blackkey` (see Step 10 for the helper scripts), then +create a provisioning JSON with Device B's values and submit it: + +```bash +# Build and submit Device B's trust anchor +veraison -- cocli comid create \ + --template provisoning/data/comid-psa-ta-deviceB.json \ + --template provisoning/data/comid-psa-refval-imx.json \ + --output-dir provisoning/data + +veraison -- cocli corim create \ + --template provisoning/data/corim-psa.json \ + --comid provisoning/data/comid-psa-refval-imx.cbor \ + --comid provisoning/data/comid-psa-ta-deviceB.cbor \ + --output provisoning/data/psa-endorsements-deviceB.cbor + +veraison -- cocli corim submit \ + --corim-file provisoning/data/psa-endorsements-deviceB.cbor \ + --api-server "https://provisioning-service:9443/endorsement-provisioning/v1/submit" \ + --media-type 'application/corim-unsigned+cbor; profile="http://arm.com/psa/iot/1"' +``` + +Run attestation again on **Device B**: + +```bash +optee_remote_attestation --key-hex +``` + +Expected: `ear.status: "affirming"`. + +### Summary + +| Test | Result | Meaning | +|------|--------|---------| +| A's BlackKey on B | `Failed to sign` | BlackKey is device-bound (JDKEK differs) | +| B's new BlackKey (unregistered) | `no trust anchor` | Key pair differs, instance-id unknown to Verifier | +| B's BlackKey after registration | `affirming` | Trust anchor added, attestation succeeds | ## Notes - Close is irreversible. Do not proceed without key backups. - The signed imx-boot is injected at 32KB in the WIC by the script. - Use the same SRK values on both devices for the non-reuse test. +- Each device generates a unique CAAM key pair; the Verifier must register + each device's trust anchor individually. diff --git a/provisoning/README-j.md b/provisoning/README-j.md index 3878d08..f338fe6 100644 --- a/provisoning/README-j.md +++ b/provisoning/README-j.md @@ -1,6 +1,3 @@ - # 日本語解説 Provisioning Provisioning は Verifier に対して、アテステーションで使うTrust AnchorとReference Valueを登録するスクリプトです。Veraison が提供するコマンドをラッパーしています。 @@ -11,22 +8,23 @@ Provisioning は Verifier に対して、アテステーションで使うTrust 以下のコマンドで、CBOR フォーマットの endorsment を生成します。 ```sh -cocli comid create --template data/comid-psa-ta.json \ +cocli comid create --template data/comid-psa-ta-qemu.json \ --template data/comid-psa-refval-qemu.json \ --output-dir data cocli corim create --template data/corim-psa.json \ - --comid data/comid-psa-refval.cbor \ - --comid data/comid-psa-ta.cbor \ + --comid data/comid-psa-refval-qemu.cbor \ + --comid data/comid-psa-ta-qemu.cbor \ --output data/psa-endorsements.cbor ``` -実機の場合は `data/comid-psa-refval-imx.json` を指定します。 +実機の場合はすべての `-qemu` サフィックスを `-imx` に置き換えてください。 以下のコマンドで、検証サーバーに対して、trust anchor と reference value を登録します。 ```sh cocli corim submit --corim-file=data/psa-endorsements.cbor \ - --api-server="http://provisioning-service:8888/endorsement-provisioning/v1/submit" \ - --media-type="'application/corim-unsigned+cbor; profile=http://arm.com/psa/iot/1'" + --api-server="https://provisioning-service:8888/endorsement-provisioning/v1/submit" \ + --media-type="'application/corim-unsigned+cbor; profile=http://arm.com/psa/iot/1'" \ + --ca-cert /tmp/veraison/certs/rootCA.crt ``` provison されたデータは以下のコマンドで確認でき、以下のような出力が得られます。 @@ -45,8 +43,8 @@ TRUST ANCHORS: "PSA_IOT.hw-model": "RoadRunner", "PSA_IOT.hw-vendor": "ACME", "PSA_IOT.iak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", - "PSA_IOT.inst-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" + "PSA_IOT.impl-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=", + "PSA_IOT.inst-id": "AZDHHoAwT5jWVWpALAWTszqArL0I5K/5xAKfbhfhA5lR" } } @@ -59,18 +57,32 @@ ENDORSEMENTS: "attributes": { "PSA_IOT.hw-model": "RoadRunner", "PSA_IOT.hw-vendor": "ACME", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", + "PSA_IOT.impl-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=", "PSA_IOT.measurement-desc": "sha-256", - "PSA_IOT.measurement-type": "PRoT", - "PSA_IOT.measurement-value": "KAnwpOcg4BXhGp/0onvYCH3rnH3wR6xHj9hOrTropX4=", + "PSA_IOT.measurement-type": "ARoT", + "PSA_IOT.measurement-value": "Qjf7I3AQkjFoBQBbhrKrYPX/toHhnmfZeingk5oE6jA=", "PSA_IOT.signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" } } ``` +`ear.status` が `warning` で `executables not recognized` のようなログが出る場合は、古いエンドースメントが残っています。`env.bash` を source したシェルでストアをクリアし、provisioning をやり直してください。 + +```sh +veraison clear-stores +./run.sh qemu +``` + +実機の場合は `imx` を指定します。 + ## より簡単な実行方法 下のコマンドを実行することで、上の手順を自動で実行することができます。 ```sh -./run.sh +# QEMU (default) +./run.sh qemu +# i.MX 8M Plus +./run.sh imx ``` + +引数を省略した場合は `qemu` が使われます。 diff --git a/provisoning/README.md b/provisoning/README.md index 696e6c7..029d39a 100644 --- a/provisoning/README.md +++ b/provisoning/README.md @@ -10,22 +10,23 @@ Provisioning is a script to register the Trust Anchor and Reference Value to the Use the following command to generate an endorsement in CBOR format. ```sh -cocli comid create --template data/comid-psa-ta.json \ +cocli comid create --template data/comid-psa-ta-qemu.json \ --template data/comid-psa-refval-qemu.json \ --output-dir data cocli corim create --template data/corim-psa.json \ - --comid data/comid-psa-refval.cbor \ - --comid data/comid-psa-ta.cbor \ + --comid data/comid-psa-refval-qemu.cbor \ + --comid data/comid-psa-ta-qemu.cbor \ --output data/psa-endorsements.cbor ``` -For i.MX 8M Plus, replace `data/comid-psa-refval-qemu.json` with `data/comid-psa-refval-imx.json`. +For i.MX 8M Plus, replace all `-qemu` suffixes with `-imx`. Use the following command to register the Trust Anchor and Reference Value with the verification server. ```sh cocli corim submit --corim-file=data/psa-endorsements.cbor \ - --api-server="http://provisioning-service:8888/endorsement-provisioning/v1/submit" \ - --media-type="'application/corim-unsigned+cbor; profile=http://arm.com/psa/iot/1'" + --api-server="https://provisioning-service:8888/endorsement-provisioning/v1/submit" \ + --media-type="'application/corim-unsigned+cbor; profile=http://arm.com/psa/iot/1'" \ + --ca-cert /tmp/veraison/certs/rootCA.crt ``` The provisioned data can be checked with the following command, and you will get output similar to the following. @@ -44,8 +45,8 @@ TRUST ANCHORS: "PSA_IOT.hw-model": "RoadRunner", "PSA_IOT.hw-vendor": "ACME", "PSA_IOT.iak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", - "PSA_IOT.inst-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" + "PSA_IOT.impl-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=", + "PSA_IOT.inst-id": "AZDHHoAwT5jWVWpALAWTszqArL0I5K/5xAKfbhfhA5lR" } } @@ -58,10 +59,10 @@ ENDORSEMENTS: "attributes": { "PSA_IOT.hw-model": "RoadRunner", "PSA_IOT.hw-vendor": "ACME", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", + "PSA_IOT.impl-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=", "PSA_IOT.measurement-desc": "sha-256", - "PSA_IOT.measurement-type": "PRoT", - "PSA_IOT.measurement-value": "KAnwpOcg4BXhGp/0onvYCH3rnH3wR6xHj9hOrTropX4=", + "PSA_IOT.measurement-type": "ARoT", + "PSA_IOT.measurement-value": "Qjf7I3AQkjFoBQBbhrKrYPX/toHhnmfZeingk5oE6jA=", "PSA_IOT.signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" } } @@ -87,98 +88,3 @@ You can automatically execute the above steps by running the following command. ``` If you omit the argument, `qemu` is used. - - - ---- ---- ---- -# 日本語解説 Provisioning - -Provisioning は Verifier に対して、アテステーションで使うTrust AnchorとReference Valueを登録するスクリプトです。Veraison が提供するコマンドをラッパーしています。 - -![](../OPTEE-RA.png) - -## 実行方法 - -以下のコマンドで、CBOR フォーマットの endorsment を生成します。 -```sh -cocli comid create --template data/comid-psa-ta.json \ - --template data/comid-psa-refval-qemu.json \ - --output-dir data -cocli corim create --template data/corim-psa.json \ - --comid data/comid-psa-refval.cbor \ - --comid data/comid-psa-ta.cbor \ - --output data/psa-endorsements.cbor -``` - -実機の場合は `data/comid-psa-refval-imx.json` を指定します。 - -以下のコマンドで、検証サーバーに対して、trust anchor と reference value を登録します。 -```sh -cocli corim submit --corim-file=data/psa-endorsements.cbor \ - --api-server="http://provisioning-service:8888/endorsement-provisioning/v1/submit" \ - --media-type="'application/corim-unsigned+cbor; profile=http://arm.com/psa/iot/1'" -``` - -provison されたデータは以下のコマンドで確認でき、以下のような出力が得られます。 -```sh -veraison stores -``` - -```txt -TRUST ANCHORS: --------------- -{ - "scheme": "PSA_IOT", - "type": "trust anchor", - "subType": "", - "attributes": { - "PSA_IOT.hw-model": "RoadRunner", - "PSA_IOT.hw-vendor": "ACME", - "PSA_IOT.iak-pub": "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMKBCTNIcKUSDii11ySs3526iDZ8A\niTo7Tu6KPAqv7D7gS2XpJFbZiItSs3m9+9Ue6GnvHw/GW2ZZaVtszggXIw==\n-----END PUBLIC KEY-----", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", - "PSA_IOT.inst-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI" - } -} - -ENDORSEMENTS: -------------- -{ - "scheme": "PSA_IOT", - "type": "reference value", - "subType": "PSA_IOT.sw-component", - "attributes": { - "PSA_IOT.hw-model": "RoadRunner", - "PSA_IOT.hw-vendor": "ACME", - "PSA_IOT.impl-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", - "PSA_IOT.measurement-desc": "sha-256", - "PSA_IOT.measurement-type": "PRoT", - "PSA_IOT.measurement-value": "KAnwpOcg4BXhGp/0onvYCH3rnH3wR6xHj9hOrTropX4=", - "PSA_IOT.signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" - } -} -``` - -`ear.status` が `warning` で `executables not recognized` のようなログが出る場合は、古いエンドースメントが残っています。`env.bash` を source したシェルでストアをクリアし、provisioning をやり直してください。 - -```sh -veraison clear-stores -./run.sh qemu -``` - -実機の場合は `imx` を指定します。 - -## より簡単な実行方法 - -下のコマンドを実行することで、上の手順を自動で実行することができます。 -```sh -# QEMU (default) -./run.sh qemu -# i.MX 8M Plus -./run.sh imx -``` - -引数を省略した場合は `qemu` が使われます。 diff --git a/relying_party/data/evidence.json b/relying_party/data/evidence.json index aea1a79..453b85f 100644 --- a/relying_party/data/evidence.json +++ b/relying_party/data/evidence.json @@ -1,15 +1,15 @@ { "eat-profile": "http://arm.com/psa/2.0.0", - "psa-client-id": 1, + "psa-client-id": 1602015901, "psa-security-lifecycle": 12288, - "psa-implementation-id": "YWNtZS1pbXBsZW1lbnRhdGlvbi1pZC0wMDAwMDAwMDE=", + "psa-implementation-id": "cWVtdS1vcHRlZS1yYS0wMDAwMDAwMDAwMDAwMDAwMDE=", "psa-software-components": [ { - "measurement-type": "PRoT", - "measurement-value": "KAnwpOcg4BXhGp/0onvYCH3rnH3wR6xHj9hOrTropX4=", + "measurement-type": "ARoT", + "measurement-value": "Qjf7I3AQkjFoBQBbhrKrYPX/toHhnmfZeingk5oE6jA=", "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" } ], - "psa-instance-id": "Ac7rrnuJJ6MiflMDz14PH3s0u1Qq1yUKwD+83jbsLxUI", + "psa-instance-id": "AZDHHoAwT5jWVWpALAWTszqArL0I5K/5xAKfbhfhA5lR", "psa-nonce": "iwnc5TjbtaYGUp4u9p8Os5K+JmQrRFL/E7W04kT9Hgo=" } From 791f4c3f4b9e99dede72d32d1bc8655c34d86fbf Mon Sep 17 00:00:00 2001 From: Yuichi Sugiyama Date: Mon, 1 Jun 2026 09:26:54 +0000 Subject: [PATCH 04/10] attester: add PRoT software component reporting OP-TEE OS version Emit a second PSA software component (measurement-type "PRoT") for the OP-TEE OS itself, alongside the existing "ARoT" component for the TA. hash.c: add get_hash_tee_memory(), a runtime SHA-256 over the core's immutable .text + .rodata (mirrors the upstream attestation PTA cmd_hash_tee_memory). The hashed range excludes relocated data (.data.rel.ro/.got live outside __rodata_start..__rodata_end), so it is reproducible across boots even with CFG_CORE_ASLR=y. cbor.{c,h}: generalize encode_evidence_to_cbor() to take an array of psa_sw_component and emit the optional version field (#4). remote_attestation.c: derive the OP-TEE OS version from core_v_str (e.g. "4.6.0") and build ARoT + PRoT components; signer-id stays the SRK hash and implementation-id is unchanged. A debug line logs the PRoT measurement in base64 for capturing the Veraison reference value. Verification stays affirming with no provisioning change: the existing ARoT reference value still matches, and the new PRoT component is ignored until a "PRoT" reference value is provisioned. --- .../remote_attestation/cbor.c | 38 ++++++---- .../remote_attestation/cbor.h | 17 +++-- .../remote_attestation/hash.c | 66 +++++++++++++++++ .../remote_attestation/hash.h | 3 + .../remote_attestation/remote_attestation.c | 71 +++++++++++++++++-- 5 files changed, 172 insertions(+), 23 deletions(-) diff --git a/attester/pta_remote_attestation/remote_attestation/cbor.c b/attester/pta_remote_attestation/remote_attestation/cbor.c index ba95a4f..8ccdf78 100644 --- a/attester/pta_remote_attestation/remote_attestation/cbor.c +++ b/attester/pta_remote_attestation/remote_attestation/cbor.c @@ -7,20 +7,16 @@ encode_evidence_to_cbor(const char *eat_profile, const int psa_client_id, const int psa_security_lifecycle, const uint8_t *psa_implementation_id, size_t psa_implementation_id_len, - const char *measurement_type, const uint8_t *signer_id, - size_t signer_id_len, const uint8_t *psa_instance_id, + const struct psa_sw_component *components, + size_t num_components, const uint8_t *psa_instance_id, size_t psa_instance_id_len, const uint8_t *psa_nonce, - size_t psa_nonce_len, const uint8_t *measurement_value, - size_t mv_len, UsefulBuf cbor_evidence_buffer) { + size_t psa_nonce_len, UsefulBuf cbor_evidence_buffer) { /* prepare usefulbufs because qcbor only accepts them */ UsefulBufC ubc_eat_profile = UsefulBuf_FromSZ(eat_profile); UsefulBufC ubc_psa_implementation_id = {psa_implementation_id, psa_implementation_id_len}; - UsefulBufC ubc_measurement_type = UsefulBuf_FromSZ(measurement_type); - UsefulBufC ubc_signer_id = {signer_id, signer_id_len}; UsefulBufC ubc_psa_instance_id = {psa_instance_id, psa_instance_id_len}; UsefulBufC ubc_psa_nonce = {psa_nonce, psa_nonce_len}; - UsefulBufC ubc_measurement_value = {measurement_value, mv_len}; QCBOREncodeContext encode_ctx; QCBOREncode_Init(&encode_ctx, cbor_evidence_buffer); @@ -44,14 +40,26 @@ encode_evidence_to_cbor(const char *eat_profile, const int psa_client_id, /* Software Components */ QCBOREncode_OpenArrayInMapN(&encode_ctx, PSA_SW_COMPONENTS); /* [ */ - QCBOREncode_OpenMap(&encode_ctx); /* { */ - QCBOREncode_AddTextToMapN(&encode_ctx, PSA_SW_COMPONENT_MEASUREMENT_TYPE, - ubc_measurement_type); - QCBOREncode_AddBytesToMapN(&encode_ctx, PSA_SW_COMPONENT_MEASUREMENT_VALUE, - ubc_measurement_value); - QCBOREncode_AddBytesToMapN(&encode_ctx, PSA_SW_COMPONENT_SIGNER_ID, - ubc_signer_id); - QCBOREncode_CloseMap(&encode_ctx); /* } */ + for (size_t i = 0; i < num_components; i++) { + const struct psa_sw_component *c = &components[i]; + UsefulBufC ubc_measurement_value = {c->measurement_value, + c->measurement_value_len}; + UsefulBufC ubc_signer_id = {c->signer_id, c->signer_id_len}; + + QCBOREncode_OpenMap(&encode_ctx); /* { */ + QCBOREncode_AddTextToMapN(&encode_ctx, + PSA_SW_COMPONENT_MEASUREMENT_TYPE, + UsefulBuf_FromSZ(c->measurement_type)); + QCBOREncode_AddBytesToMapN(&encode_ctx, + PSA_SW_COMPONENT_MEASUREMENT_VALUE, + ubc_measurement_value); + if (c->version) + QCBOREncode_AddTextToMapN(&encode_ctx, PSA_SW_COMPONENT_VERSION, + UsefulBuf_FromSZ(c->version)); + QCBOREncode_AddBytesToMapN(&encode_ctx, PSA_SW_COMPONENT_SIGNER_ID, + ubc_signer_id); + QCBOREncode_CloseMap(&encode_ctx); /* } */ + } QCBOREncode_CloseArray(&encode_ctx); /* ] */ /* Nonce */ diff --git a/attester/pta_remote_attestation/remote_attestation/cbor.h b/attester/pta_remote_attestation/remote_attestation/cbor.h index f7f0070..72ba799 100644 --- a/attester/pta_remote_attestation/remote_attestation/cbor.h +++ b/attester/pta_remote_attestation/remote_attestation/cbor.h @@ -29,16 +29,25 @@ #define COSE_ALGORITHM_ES256 -7 #define COSE_SIG_CONTEXT_STRING_SIGNATURE1 "Signature1" +/* One PSA software component (an entry in the Software Components claim). */ +struct psa_sw_component { + const char *measurement_type; /* claim 1 (text) */ + const uint8_t *measurement_value; /* claim 2 (bytes) */ + size_t measurement_value_len; + const char *version; /* claim 4 (text); NULL to omit */ + const uint8_t *signer_id; /* claim 5 (bytes) */ + size_t signer_id_len; +}; + UsefulBufC encode_evidence_to_cbor(const char *eat_profile, const int psa_client_id, const int psa_security_lifecycle, const uint8_t *psa_implementation_id, size_t psa_implementation_id_len, - const char *measurement_type, const uint8_t *signer_id, - size_t signer_id_len, const uint8_t *psa_instance_id, + const struct psa_sw_component *components, + size_t num_components, const uint8_t *psa_instance_id, size_t psa_instance_id_len, const uint8_t *psa_nonce, - size_t psa_nonce_len, const uint8_t *measurement_value, - size_t mv_len, UsefulBuf cbor_evidence_buffer); + size_t psa_nonce_len, UsefulBuf cbor_evidence_buffer); UsefulBufC generate_cose(UsefulBufC ubc_cbor_evidence, UsefulBuf buffer_for_cose, diff --git a/attester/pta_remote_attestation/remote_attestation/hash.c b/attester/pta_remote_attestation/remote_attestation/hash.c index 13582b3..a95e1d6 100644 --- a/attester/pta_remote_attestation/remote_attestation/hash.c +++ b/attester/pta_remote_attestation/remote_attestation/hash.c @@ -1,4 +1,6 @@ +#include #include +#include #include #include @@ -130,3 +132,67 @@ TEE_Result get_hash_ta_memory(uint8_t *out, size_t out_sz) ts_push_current_session(s); return res; } + +/* + * Hash the OP-TEE OS (core) immutable memory: code (.text) and read-only + * data (.rodata). This is a runtime measurement of the trusted OS and + * mirrors the official OP-TEE attestation PTA (cmd_hash_tee_memory). + * + * Note: this is a self-measurement; its trustworthiness is ultimately + * rooted in secure boot (HAB/SRK verifying the OP-TEE image at load time). + */ +TEE_Result get_hash_tee_memory(uint8_t *out, size_t out_sz) +{ + TEE_Result res = TEE_SUCCESS; + void *ctx = NULL; + + if (out_sz < TEE_SHA256_HASH_SIZE) + return TEE_ERROR_SHORT_BUFFER; + + res = crypto_hash_alloc_ctx(&ctx, TEE_ALG_SHA256); + if (res) + return res; + + res = crypto_hash_init(ctx); + if (res) + goto out; + + res = crypto_hash_update(ctx, __text_start, + __text_data_start - __text_start); + if (res) + goto out; + res = crypto_hash_update(ctx, __text_data_end, + __text_end - __text_data_end); + if (res) + goto out; + if (IS_ENABLED(CFG_WITH_PAGER)) { + res = crypto_hash_update(ctx, __text_init_start, + __text_init_end - __text_init_start); + if (res) + goto out; + res = crypto_hash_update(ctx, __text_pageable_start, + __text_pageable_end - __text_pageable_start); + if (res) + goto out; + } + res = crypto_hash_update(ctx, __rodata_start, + __rodata_end - __rodata_start); + if (res) + goto out; + if (IS_ENABLED(CFG_WITH_PAGER)) { + res = crypto_hash_update(ctx, __rodata_init_start, + __rodata_init_end - __rodata_init_start); + if (res) + goto out; + res = crypto_hash_update(ctx, __rodata_pageable_start, + __rodata_pageable_end - + __rodata_pageable_start); + if (res) + goto out; + } + + res = crypto_hash_final(ctx, out, TEE_SHA256_HASH_SIZE); +out: + crypto_hash_free_ctx(ctx); + return res; +} diff --git a/attester/pta_remote_attestation/remote_attestation/hash.h b/attester/pta_remote_attestation/remote_attestation/hash.h index 6b54add..480ccf6 100644 --- a/attester/pta_remote_attestation/remote_attestation/hash.h +++ b/attester/pta_remote_attestation/remote_attestation/hash.h @@ -5,4 +5,7 @@ TEE_Result get_hash_ta_memory(uint8_t *out, size_t out_sz); +/* Hash the OP-TEE OS (core) .text + .rodata into @out (>= 32 bytes). */ +TEE_Result get_hash_tee_memory(uint8_t *out, size_t out_sz); + #endif /* PTA_REMOTE_ATTESTATION_TA_HASH_H */ diff --git a/attester/pta_remote_attestation/remote_attestation/remote_attestation.c b/attester/pta_remote_attestation/remote_attestation/remote_attestation.c index f8dc28e..d7611ed 100644 --- a/attester/pta_remote_attestation/remote_attestation/remote_attestation.c +++ b/attester/pta_remote_attestation/remote_attestation/remote_attestation.c @@ -1,3 +1,4 @@ +#include #include #include @@ -23,6 +24,8 @@ #define EAT_PROFILE "http://arm.com/psa/2.0.0" #define MEASURMENT_TYPE "ARoT" +#define MEASUREMENT_TYPE_TEE_OS "PRoT" +#define OS_VERSION_MAX_LEN 32 #ifdef CFG_NXP_CAAM #define IMPLEMENTATION_ID "imx8mp-optee-ra-0000000000000001" #else @@ -107,7 +110,6 @@ static TEE_Result cmd_get_cbor_evidence(uint32_t param_types, TEE_Result status = TEE_SUCCESS; const char eat_profile[] = EAT_PROFILE; - const char measurement_type[] = MEASURMENT_TYPE; const uint8_t *psa_implementation_id = (const uint8_t *)IMPLEMENTATION_ID; const size_t psa_implementation_id_len = IMPLEMENTATION_ID_LEN; @@ -119,6 +121,8 @@ static TEE_Result cmd_get_cbor_evidence(uint32_t param_types, uint8_t pub_y[PUBKEY_COORD_SIZE] = {0}; uint8_t measurement_value[TEE_SHA256_HASH_SIZE] = {0}; + uint8_t tee_measurement[TEE_SHA256_HASH_SIZE] = {0}; + char os_version[OS_VERSION_MAX_LEN] = {0}; size_t b64_measurement_value_len = TEE_SHA256_HASH_SIZE * 2; char b64_measurement_value[TEE_SHA256_HASH_SIZE * 2] = {0}; @@ -216,6 +220,45 @@ static TEE_Result cmd_get_cbor_evidence(uint32_t param_types, b64_measurement_value[b64_measurement_value_len] = '\0'; DMSG("b64_measurement_value: %s", b64_measurement_value); + /* Measure the OP-TEE OS (core .text + .rodata) for the PRoT component */ + status = get_hash_tee_memory(tee_measurement, TEE_SHA256_HASH_SIZE); + if (status != TEE_SUCCESS) + return status; + + /* + * OP-TEE OS version: first whitespace-delimited token of core_v_str, + * e.g. "4.6.0" (the build banner is " () # "). + */ + { + size_t i = 0; + + while (i < sizeof(os_version) - 1 && core_v_str[i] && + core_v_str[i] != ' ') { + os_version[i] = core_v_str[i]; + i++; + } + os_version[i] = '\0'; + if (os_version[0] == '\0') + memcpy(os_version, "unknown", sizeof("unknown")); + } + DMSG("OP-TEE OS version: %s", os_version); + + /* + * For provisioning: log the PRoT (OP-TEE OS) measurement in base64 so it + * can be captured once from a device boot and registered as the Veraison + * reference value (psa.refval-id label "PRoT"). + */ + { + size_t b64_tee_len = TEE_SHA256_HASH_SIZE * 2; + char b64_tee[TEE_SHA256_HASH_SIZE * 2] = {0}; + + if (base64_encode(tee_measurement, TEE_SHA256_HASH_SIZE, b64_tee, + &b64_tee_len) == 1) { + b64_tee[b64_tee_len] = '\0'; + DMSG("PRoT (OP-TEE OS) measurement-value b64: %s", b64_tee); + } + } + /* Allocate CBOR/COSE work buffers on heap to avoid PTA stack overflow */ void *heap_cbor = malloc(512); void *heap_cose = malloc(512); @@ -227,12 +270,32 @@ static TEE_Result cmd_get_cbor_evidence(uint32_t param_types, UsefulBuf buffuer_for_cbor = {heap_cbor, 512}; UsefulBuf buffer_for_cose = {heap_cose, 512}; + /* Build the Software Components: ARoT (this TA) + PRoT (OP-TEE OS) */ + struct psa_sw_component components[] = { + { + .measurement_type = MEASURMENT_TYPE, + .measurement_value = measurement_value, + .measurement_value_len = TEE_SHA256_HASH_SIZE, + .version = NULL, + .signer_id = signer_id, + .signer_id_len = SIGNER_ID_LEN, + }, + { + .measurement_type = MEASUREMENT_TYPE_TEE_OS, + .measurement_value = tee_measurement, + .measurement_value_len = TEE_SHA256_HASH_SIZE, + .version = os_version, + .signer_id = signer_id, + .signer_id_len = SIGNER_ID_LEN, + }, + }; + /* Encode evidence to CBOR */ UsefulBufC ubc_cbor_evidence = encode_evidence_to_cbor( eat_profile, psa_client_id, psa_security_lifecycle, - psa_implementation_id, psa_implementation_id_len, measurement_type, - signer_id, SIGNER_ID_LEN, psa_instance_id, INSTANCE_ID_LEN, nonce, - nonce_sz, measurement_value, TEE_SHA256_HASH_SIZE, buffuer_for_cbor); + psa_implementation_id, psa_implementation_id_len, components, + sizeof(components) / sizeof(components[0]), psa_instance_id, + INSTANCE_ID_LEN, nonce, nonce_sz, buffuer_for_cbor); if (UsefulBuf_IsNULLC(ubc_cbor_evidence)) { DMSG("Failed to encode evidence to CBOR"); free(heap_cbor); From 2bc815fe22aadc2d13bc979487c6a697ac43eb96 Mon Sep 17 00:00:00 2001 From: Yuichi Sugiyama Date: Mon, 1 Jun 2026 09:26:54 +0000 Subject: [PATCH 05/10] attester: exclude secure-boot-out from QEMU docker build context The i.MX secure-boot output dir holds multi-hundred-MB WIC images and CST private keys owned by another user, which break and bloat the QEMU attester docker build context. It is not needed for that build. --- attester/.dockerignore | 1 + 1 file changed, 1 insertion(+) diff --git a/attester/.dockerignore b/attester/.dockerignore index b43bf86..0a446f9 100644 --- a/attester/.dockerignore +++ b/attester/.dockerignore @@ -1 +1,2 @@ README.md +container-imx/secure-boot-out/ From 030c66c539a9bc3d6682cdb42b74587b180197c2 Mon Sep 17 00:00:00 2001 From: Yuichi Sugiyama Date: Tue, 9 Jun 2026 05:30:09 +0000 Subject: [PATCH 06/10] docs: document the PRoT (OP-TEE OS version) software component Show the PRoT entry in the verification-result example (README.md / README-j.md) and explain that the OP-TEE OS is identified by the stable version field. Its measurement-value is a build-specific runtime hash (OP-TEE embeds the build timestamp in core_v_str, part of the hashed .rodata), so it is not provisioned as a reference value; the verifier ignores the PRoT component and ear.status stays affirming. OS integrity is rooted in HAB/SRK secure boot. --- README-j.md | 19 +++++++++++++++++++ README.md | 21 +++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/README-j.md b/README-j.md index 54fda77..a687919 100644 --- a/README-j.md +++ b/README-j.md @@ -297,6 +297,12 @@ Attestation result: "measurement-type": "ARoT", "measurement-value": "Qjf7I3AQkjFoBQBbhrKrYPX/toHhnmfZeingk5oE6jA=", "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" + }, + { + "measurement-type": "PRoT", + "measurement-value": "GEXvNatCVOIWXWTrDuDroAeUoynz136EUnSEp42BGhM=", + "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=", + "version": "4.6.0" } ] } @@ -315,6 +321,19 @@ Storage Opaque [affirming]: the Attester encrypts all secrets in persistent stor Sourced Data [none]: The Evidence received is insufficient to make a conclusion. ``` +> **OP-TEE OS のバージョン(`PRoT` ソフトウェアコンポーネント)。** TA を測定する +> `ARoT` コンポーネントに加え、evidence には `measurement-type` が `"PRoT"` の +> 2 つ目のソフトウェアコンポーネントが含まれ、その `version` フィールドに +> **OP-TEE OS のバージョン**(例: `"4.6.0"`)が入ります(上記参照)。 +> +> OP-TEE OS は安定した `version` フィールドで識別します。`measurement-value` は +> コアの不変領域(`.text` + `.rodata`)の実行時ハッシュですが、**参照値としては +> 登録しません**。このハッシュはビルド毎に変わるためです(OP-TEE は `core_v_str` +> にビルド日時を埋め込み、それが測定対象の `.rodata` に含まれる)。OS の完全性 +> 自体はセキュアブート(i.MX 8M Plus では HAB/SRK)が担保します。`PRoT` の参照値を +> 登録しないため、検証側はこのコンポーネントを照合対象外として無視し、 +> `ear.status` は `affirming` のままになります。 + ### 6. 異なる TA からアテステーションリクエストを送信するシナリオ ここまでで、リモートアテステーションが成功する一連の流れを確認しました。次に、異なる TA からアテステーションリクエストを送った際に失敗するシナリオと、新たな endorsment を登録することでアテステーションが成功されるシナリオを確認します。 diff --git a/README.md b/README.md index 7023418..0391431 100644 --- a/README.md +++ b/README.md @@ -341,6 +341,12 @@ Attestation result: "measurement-type": "ARoT", "measurement-value": "Qjf7I3AQkjFoBQBbhrKrYPX/toHhnmfZeingk5oE6jA=", "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=" + }, + { + "measurement-type": "PRoT", + "measurement-value": "GEXvNatCVOIWXWTrDuDroAeUoynz136EUnSEp42BGhM=", + "signer-id": "rLsRx+TaIXIFUjzkzhokWuGiOa48a/2eeHH35di66Gs=", + "version": "4.6.0" } ] } @@ -359,6 +365,21 @@ Storage Opaque [affirming]: the Attester encrypts all secrets in persistent stor Sourced Data [none]: The Evidence received is insufficient to make a conclusion. ``` +> **OP-TEE OS version (the `PRoT` software component).** In addition to the +> `ARoT` component (which measures the Trusted Application), the evidence +> includes a second software component with `measurement-type` `"PRoT"` that +> reports the **OP-TEE OS version** in its `version` field (e.g. `"4.6.0"`), as +> shown above. +> +> The OP-TEE OS is identified by the stable `version` field. Its +> `measurement-value` is a runtime hash of the immutable core (`.text` + +> `.rodata`) and is **not** registered as a reference value: that hash is +> build-specific (OP-TEE embeds the build timestamp in `core_v_str`, which is +> part of the hashed `.rodata`), so it changes on every build. OS integrity is +> rooted in secure boot (HAB/SRK on i.MX 8M Plus). Because no `PRoT` reference +> value is provisioned, the verifier ignores this component for matching and +> `ear.status` remains `affirming`. + ### 6. Scenario for Sending Attestation Requests from Different TAs From 8659bfd964ae6ac74b54b543b2c7fc97fe7cd33f Mon Sep 17 00:00:00 2001 From: Yuichi Sugiyama Date: Thu, 11 Jun 2026 00:48:52 +0000 Subject: [PATCH 07/10] provisioning: register the PRoT reference value per build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The client confirmed that the PRoT measurement-value changing on every build is acceptable, so the PRoT component is now verified by Veraison instead of being left unprovisioned: register the build's reference value and a matching build stays affirming while a different OP-TEE build (or modified code) is flagged as warning. Add provisoning/compute-prot-refval.py, the offline equivalent of the PTA's get_hash_tee_memory(): it computes the PRoT measurement-value from the tee.elf build artifact (same VA spans, same order), so the reference value can be obtained without booting the image or raising the core log level (i.MX production builds compile out all core trace). Verified on QEMU: the script output is identical to the runtime measurement reported by the PTA. Register the PRoT reference value of the current signed i.MX8MP build in comid-psa-refval-imx.json, and update the README note to describe the per-build provisioning flow. Note that Yocto optee-os builds are reproducible (SOURCE_DATE_EPOCH is set and the build counter resets on clean builds — confirmed: two cleansstate builds of identical source produce bit-identical tee.elf), so rebuilding the same source does not invalidate the registered value; QEMU container builds are not reproducible and need a fresh value per build. --- README-j.md | 29 ++++-- README.md | 32 ++++-- provisoning/compute-prot-refval.py | 115 +++++++++++++++++++++ provisoning/data/comid-psa-refval-imx.json | 14 +++ 4 files changed, 175 insertions(+), 15 deletions(-) create mode 100755 provisoning/compute-prot-refval.py diff --git a/README-j.md b/README-j.md index a687919..7245a91 100644 --- a/README-j.md +++ b/README-j.md @@ -326,13 +326,28 @@ Sourced Data [none]: The Evidence received is insufficient to make a conclusion. > 2 つ目のソフトウェアコンポーネントが含まれ、その `version` フィールドに > **OP-TEE OS のバージョン**(例: `"4.6.0"`)が入ります(上記参照)。 > -> OP-TEE OS は安定した `version` フィールドで識別します。`measurement-value` は -> コアの不変領域(`.text` + `.rodata`)の実行時ハッシュですが、**参照値としては -> 登録しません**。このハッシュはビルド毎に変わるためです(OP-TEE は `core_v_str` -> にビルド日時を埋め込み、それが測定対象の `.rodata` に含まれる)。OS の完全性 -> 自体はセキュアブート(i.MX 8M Plus では HAB/SRK)が担保します。`PRoT` の参照値を -> 登録しないため、検証側はこのコンポーネントを照合対象外として無視し、 -> `ear.status` は `affirming` のままになります。 +> `measurement-value` はコアの不変領域(`.text` + `.rodata`)の実行時ハッシュで、 +> **ビルド固有**の値です(OP-TEE は `core_v_str` にビルド日時を埋め込み、それが +> 測定対象の `.rodata` に含まれるため、OP-TEE OS を再ビルドすると変わります)。 +> そのため `PRoT` の参照値は**リリースビルドごとに登録(更新)**します。参照値は +> イメージを起動したりコアのログレベルを上げたりしなくても、ビルド成果物から +> [provisoning/compute-prot-refval.py](provisoning/compute-prot-refval.py) で +> オフライン計算できます: +> +> ```bash +> ./provisoning/compute-prot-refval.py path/to/tee.elf +> ``` +> +> 出力された `sha-256;...` ダイジェストを +> `provisoning/data/comid-psa-refval-*.json` の `PRoT` measurement に記載して +> プロビジョニングしてください。参照値を登録すると検証側は `PRoT` も他の +> コンポーネントと同様に照合します: 一致するビルドなら `ear.status` は +> `affirming` のまま、異なる OP-TEE ビルド(またはコード改変)は `warning` として +> 検出されます。参照値を登録しない場合は、このコンポーネントは照合対象外として +> 無視され、`ear.status` は他のコンポーネントだけで決まります。なお Yocto +> ビルドは再現可能(`SOURCE_DATE_EPOCH` 設定済み・クリーンビルドでビルドカウンタ +> がリセット)なので、同一ソースの再ビルドで参照値は変わりません。QEMU コンテナ +> ビルドは非再現のため、ビルドごとに値の取り直しが必要です。 ### 6. 異なる TA からアテステーションリクエストを送信するシナリオ diff --git a/README.md b/README.md index 0391431..42bd288 100644 --- a/README.md +++ b/README.md @@ -371,14 +371,30 @@ Sourced Data [none]: The Evidence received is insufficient to make a conclusion. > reports the **OP-TEE OS version** in its `version` field (e.g. `"4.6.0"`), as > shown above. > -> The OP-TEE OS is identified by the stable `version` field. Its -> `measurement-value` is a runtime hash of the immutable core (`.text` + -> `.rodata`) and is **not** registered as a reference value: that hash is -> build-specific (OP-TEE embeds the build timestamp in `core_v_str`, which is -> part of the hashed `.rodata`), so it changes on every build. OS integrity is -> rooted in secure boot (HAB/SRK on i.MX 8M Plus). Because no `PRoT` reference -> value is provisioned, the verifier ignores this component for matching and -> `ear.status` remains `affirming`. +> The `measurement-value` is a runtime hash of the immutable core (`.text` + +> `.rodata`). It is **build-specific** (OP-TEE embeds the build timestamp in +> `core_v_str`, which is part of the hashed `.rodata`), so it changes whenever +> the OP-TEE OS is rebuilt — and the `PRoT` reference value therefore has to +> be (re-)registered for every released build. Compute it offline from the +> build artifact with +> [provisoning/compute-prot-refval.py](provisoning/compute-prot-refval.py) +> (no need to boot the image or raise the core log level): +> +> ```bash +> ./provisoning/compute-prot-refval.py path/to/tee.elf +> ``` +> +> Put the printed `sha-256;...` digest into the `PRoT` measurement of +> `provisoning/data/comid-psa-refval-*.json` before provisioning. With the +> reference value registered the verifier checks the `PRoT` component like +> any other: a matching build keeps `ear.status` `affirming`, while a +> different OP-TEE build (or modified code) is flagged as `warning`. If no +> `PRoT` reference value is provisioned, the verifier ignores the component +> and `ear.status` is decided by the other components alone. Note: Yocto +> builds are reproducible (`SOURCE_DATE_EPOCH` is set and the build counter +> resets on clean builds), so rebuilding identical source does not change the +> reference value; QEMU container builds are not reproducible and need a +> fresh value per build. ### 6. Scenario for Sending Attestation Requests from Different TAs diff --git a/provisoning/compute-prot-refval.py b/provisoning/compute-prot-refval.py new file mode 100755 index 0000000..893fe1c --- /dev/null +++ b/provisoning/compute-prot-refval.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +"""Compute the PRoT reference measurement-value from a tee.elf build artifact. + +This is the offline equivalent of the remote attestation PTA's +get_hash_tee_memory(): SHA-256 over the OP-TEE core's immutable memory, +hashed in the same order as the runtime measurement: + + [__text_start, __text_data_start) + [__text_data_end, __text_end) + (pager text sections, if present) + [__rodata_start, __rodata_end) + (pager rodata sections, if present) + +Because the PRoT measurement-value is build-specific (core_v_str embeds the +build timestamp), the reference value must be recomputed and re-provisioned +for every released build. This script makes that possible without booting +the image or raising the core log level. + +Usage: + ./compute-prot-refval.py path/to/tee.elf + +Output: the base64 measurement-value to put in the comid reference value +(digests entry: "sha-256;"). + +Requires: pyelftools (pip install pyelftools) +""" +import base64 +import hashlib +import sys + +from elftools.elf.elffile import ELFFile + + +def load_symbols(elf): + syms = {} + for secname in (".symtab", ".dynsym"): + sec = elf.get_section_by_name(secname) + if sec is None: + continue + for sym in sec.iter_symbols(): + syms[sym.name] = sym["st_value"] + return syms + + +def read_va_range(elf, start, end): + """Read [start, end) virtual addresses from the ELF LOAD segments.""" + if end <= start: + return b"" + out = bytearray(end - start) + covered = 0 + for seg in elf.iter_segments(): + if seg["p_type"] != "PT_LOAD": + continue + seg_va = seg["p_vaddr"] + seg_filesz = seg["p_filesz"] + lo = max(start, seg_va) + hi = min(end, seg_va + seg_filesz) + if lo >= hi: + continue + data = seg.data() + out[lo - start:hi - start] = data[lo - seg_va:hi - seg_va] + covered += hi - lo + if covered != end - start: + raise SystemExit( + f"error: VA range 0x{start:x}..0x{end:x} not fully covered by " + f"LOAD segments ({covered}/{end - start} bytes)") + return bytes(out) + + +def main(): + if len(sys.argv) != 2: + print(__doc__, file=sys.stderr) + return 1 + path = sys.argv[1] + + with open(path, "rb") as f: + elf = ELFFile(f) + syms = load_symbols(elf) + + def addr(name): + if name not in syms: + raise SystemExit(f"error: symbol {name} not found in {path}") + return syms[name] + + # Same span order as get_hash_tee_memory() + spans = [ + (addr("__text_start"), addr("__text_data_start")), + (addr("__text_data_end"), addr("__text_end")), + ] + if "__text_init_start" in syms: # CFG_WITH_PAGER=y builds only + spans += [ + (addr("__text_init_start"), addr("__text_init_end")), + (addr("__text_pageable_start"), addr("__text_pageable_end")), + ] + spans.append((addr("__rodata_start"), addr("__rodata_end"))) + if "__rodata_init_start" in syms: # CFG_WITH_PAGER=y builds only + spans += [ + (addr("__rodata_init_start"), addr("__rodata_init_end")), + (addr("__rodata_pageable_start"), + addr("__rodata_pageable_end")), + ] + + h = hashlib.sha256() + for start, end in spans: + h.update(read_va_range(elf, start, end)) + + digest = h.digest() + print(f"PRoT measurement-value (b64): {base64.b64encode(digest).decode()}") + print(f"PRoT measurement-value (hex): {digest.hex()}") + print(f'comid digests entry: "sha-256;{base64.b64encode(digest).decode()}"') + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/provisoning/data/comid-psa-refval-imx.json b/provisoning/data/comid-psa-refval-imx.json index b1f4614..f59349d 100644 --- a/provisoning/data/comid-psa-refval-imx.json +++ b/provisoning/data/comid-psa-refval-imx.json @@ -42,6 +42,20 @@ "sha-256;v0A0kWI5jq4tGIGZf+o4ujdq/udWwLgzfrOc2XOb13A=" ] } + }, + { + "key": { + "type": "psa.refval-id", + "value": { + "label": "PRoT", + "signer-id": "427zIO3QE+zwfmqkGRPzdhocbmeEF9Bpn5Lk/mBzgf4=" + } + }, + "value": { + "digests": [ + "sha-256;UsHZbTgZfIUT3ga7FuAaKn/PnGO2WgpvZp1eM2b82oY=" + ] + } } ] } From c94c118ecfea2a41ba567b56bd10ecae70342a01 Mon Sep 17 00:00:00 2001 From: Yuichi Sugiyama Date: Thu, 11 Jun 2026 06:45:15 +0000 Subject: [PATCH 08/10] provisioning: compute the ARoT reference value offline as well MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ARoT measurement (get_hash_ta_memory) hashes the TA's read-only regions as mapped by ldelf: the ELF-header page (ldelf maps file offset 0, one page, read-only — see init_elf()) plus every read-only PT_LOAD segment zero-padded to its page-rounded memsz, hashed smallest-first (ties by content, matching the runtime cmp_regions() ASLR-stable ordering). Since TA text/rodata contain no load-base-dependent bytes (all relocations target the writable segment), this can be reproduced from the build artifact alone. Add provisoning/compute-arot-refval.py implementing exactly that; verified on QEMU that its output is identical to the runtime measurement, both from the TA ELF and from the signed .ta (the signed header is skipped automatically). The script warns if a relocation targets a read-only segment, in which case the offline value may not match the runtime one. Update comid-psa-refval-imx.json with the ARoT value computed from the current signed i.MX8MP build (replacing the stale value from an older build), so both ARoT and PRoT reference values can now be provisioned from build artifacts without a first device run, and document the script in the READMEs. --- README-j.md | 5 +- README.md | 5 +- provisoning/compute-arot-refval.py | 99 ++++++++++++++++++++++ provisoning/data/comid-psa-refval-imx.json | 2 +- 4 files changed, 108 insertions(+), 3 deletions(-) create mode 100755 provisoning/compute-arot-refval.py diff --git a/README-j.md b/README-j.md index 7245a91..ff9b3fa 100644 --- a/README-j.md +++ b/README-j.md @@ -347,7 +347,10 @@ Sourced Data [none]: The Evidence received is insufficient to make a conclusion. > 無視され、`ear.status` は他のコンポーネントだけで決まります。なお Yocto > ビルドは再現可能(`SOURCE_DATE_EPOCH` 設定済み・クリーンビルドでビルドカウンタ > がリセット)なので、同一ソースの再ビルドで参照値は変わりません。QEMU コンテナ -> ビルドは非再現のため、ビルドごとに値の取り直しが必要です。 +> ビルドは非再現のため、ビルドごとに値の取り直しが必要です。`ARoT` の参照値も +> 同様に、初回実行からの取得ではなく +> [provisoning/compute-arot-refval.py](provisoning/compute-arot-refval.py) +> (`.ta` または TA の ELF を渡す)でビルド成果物からオフライン計算できます。 ### 6. 異なる TA からアテステーションリクエストを送信するシナリオ diff --git a/README.md b/README.md index 42bd288..9fce3ab 100644 --- a/README.md +++ b/README.md @@ -394,7 +394,10 @@ Sourced Data [none]: The Evidence received is insufficient to make a conclusion. > builds are reproducible (`SOURCE_DATE_EPOCH` is set and the build counter > resets on clean builds), so rebuilding identical source does not change the > reference value; QEMU container builds are not reproducible and need a -> fresh value per build. +> fresh value per build. The `ARoT` reference value can likewise be computed +> offline from the built TA with +> [provisoning/compute-arot-refval.py](provisoning/compute-arot-refval.py) +> (pass the `.ta` or the TA ELF), instead of capturing it from a first run. ### 6. Scenario for Sending Attestation Requests from Different TAs diff --git a/provisoning/compute-arot-refval.py b/provisoning/compute-arot-refval.py new file mode 100755 index 0000000..d4b6f4e --- /dev/null +++ b/provisoning/compute-arot-refval.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 +"""Compute the ARoT reference measurement-value from a TA binary. + +This is the offline equivalent of the remote attestation PTA's +get_hash_ta_memory(): SHA-256 over the calling TA's read-only memory +regions as mapped by ldelf, which are + + - the first page of the TA ELF (ldelf maps file offset 0, 4096 bytes, + read-only: ELF header + program headers, see ldelf init_elf()), and + - every read-only PT_LOAD segment: file content zero-padded to the + page-rounded memory size. + +The regions are hashed smallest-first (ties broken by content), matching +the runtime cmp_regions() ordering, so the result is independent of TA +ASLR. Verified against the runtime measurement on QEMU. + +Accepts either the raw TA ELF (*.elf / *.stripped.elf) or the signed +*.ta file (the signed header is skipped automatically). + +Usage: + ./compute-arot-refval.py path/to/.ta + +Requires: pyelftools (pip install pyelftools) +""" +import base64 +import hashlib +import io +import sys + +from elftools.elf.elffile import ELFFile + +PAGE = 4096 + + +def elf_bytes(path): + """Return the ELF image contained in path (skip a .ta signed header).""" + data = open(path, "rb").read() + if data[:4] == b"\x7fELF": + return data + off = data.find(b"\x7fELF") + if off < 0: + raise SystemExit(f"error: no ELF image found in {path}") + return data[off:] + + +def roundup(n, align=PAGE): + return (n + align - 1) & ~(align - 1) + + +def main(): + if len(sys.argv) != 2: + print(__doc__, file=sys.stderr) + return 1 + + data = elf_bytes(sys.argv[1]) + elf = ELFFile(io.BytesIO(data)) + + # Region 1: the ELF header page mapped read-only by ldelf (file page 0) + regions = [data[:PAGE].ljust(PAGE, b"\0")] + + # Read-only PT_LOAD segments, zero-padded to the mapped (page-rounded + # memsz) size. Writable segments are not part of the measurement. + ro_ranges = [] + for seg in elf.iter_segments(): + if seg["p_type"] != "PT_LOAD" or seg["p_flags"] & 0x2: # PF_W + continue + content = data[seg["p_offset"]:seg["p_offset"] + seg["p_filesz"]] + regions.append(content.ljust(roundup(seg["p_memsz"]), b"\0")) + ro_ranges.append((seg["p_vaddr"], seg["p_vaddr"] + seg["p_memsz"])) + + # The measurement is only load-address-independent if no relocation + # targets a read-only segment; warn if one does. + for sec in elf.iter_sections(): + if not sec.name.startswith(".rela"): + continue + for rel in sec.iter_relocations(): + off = rel["r_offset"] + if any(lo <= off < hi for lo, hi in ro_ranges): + print(f"warning: relocation targets read-only segment " + f"(offset 0x{off:x}); the runtime measurement may " + f"not match this offline value", file=sys.stderr) + break + + # Hash smallest-first, ties by content (matches runtime cmp_regions()) + regions.sort(key=lambda r: (len(r), r)) + + h = hashlib.sha256() + for r in regions: + h.update(r) + + digest = h.digest() + print(f"ARoT measurement-value (b64): {base64.b64encode(digest).decode()}") + print(f"ARoT measurement-value (hex): {digest.hex()}") + print(f'comid digests entry: "sha-256;{base64.b64encode(digest).decode()}"') + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/provisoning/data/comid-psa-refval-imx.json b/provisoning/data/comid-psa-refval-imx.json index f59349d..9df1c3e 100644 --- a/provisoning/data/comid-psa-refval-imx.json +++ b/provisoning/data/comid-psa-refval-imx.json @@ -39,7 +39,7 @@ }, "value": { "digests": [ - "sha-256;v0A0kWI5jq4tGIGZf+o4ujdq/udWwLgzfrOc2XOb13A=" + "sha-256;FjIXXyuEaEG2FsLTRZjCck573aBBlnJT0sed9M9nRwA=" ] } }, From b5381ea920309e2f9af14023bd1e4343c7ba7292 Mon Sep 17 00:00:00 2001 From: Yuichi Sugiyama Date: Thu, 11 Jun 2026 12:58:27 +0000 Subject: [PATCH 09/10] docs: make offline reference-value computation the primary flow Update the new-TA registration steps (section 6.2) to recommend computing the ARoT measurement-value offline from the build artifact with provisoning/compute-arot-refval.py instead of capturing the debug output of a first run; the run-capture method remains documented as an alternative for debug builds, with a note that it is unavailable on i.MX production builds (core log level 0). Add an offline-computation section to the provisioning READMEs covering both scripts (ARoT and PRoT), when each value changes, and the pyelftools requirement. --- README-j.md | 15 ++++++++++++++- README.md | 17 ++++++++++++++++- provisoning/README-j.md | 21 +++++++++++++++++++++ provisoning/README.md | 22 ++++++++++++++++++++++ 4 files changed, 73 insertions(+), 2 deletions(-) diff --git a/README-j.md b/README-j.md index ff9b3fa..5310dcf 100644 --- a/README-j.md +++ b/README-j.md @@ -420,7 +420,20 @@ Sourced Data [contraindicated]: Cryptographic validation of the Evidence has fai #### 6.2. provisioning で新たな TA を登録する -はじめに、新たな TA のコードハッシュ値を確認します。現在、PTA に evidence 生成リクエストを送ると、secure terminal にコードハッシュ値がデバッグ用に出力される実装になっています。具体的には以下のような一行があり、`gw9v98IV8ozl5nHpsMwl9W5nGGC0bzAYMPShwvff0vY=` がコードハッシュ値を base64 エンコードした値です。 +はじめに、新たな TA のコードハッシュ値を確認します。推奨は、ビルド成果物から +[provisoning/compute-arot-refval.py](provisoning/compute-arot-refval.py) +で**オフライン計算**する方法です(新しい TA の `.ta` ファイルまたは ELF を渡します。実行は不要です): + +```bash +./provisoning/compute-arot-refval.py path/to/.ta +``` + +別の方法として、デバッグビルドでは実行時の出力からも取得できます。PTA に +evidence 生成リクエストを送ると、secure terminal にコードハッシュ値がデバッグ用に +出力されます。具体的には以下のような一行があり、`gw9v98IV8ozl5nHpsMwl9W5nGGC0bzAYMPShwvff0vY=` +がコードハッシュ値を base64 エンコードした値です。(注意: i.MX の本番ビルドは +コアログレベルが 0 のためこのデバッグ出力は得られません。実機ではオフライン計算を +使ってください。) ```txt D/TC:? 0 cmd_get_cbor_evidence:82 b64_measurement_value: gw9v98IV8ozl5nHpsMwl9W5nGGC0bzAYMPShwvff0vY= ``` diff --git a/README.md b/README.md index 9fce3ab..1b50ba8 100644 --- a/README.md +++ b/README.md @@ -470,7 +470,22 @@ Sourced Data [contraindicated]: Cryptographic validation of the Evidence has fai #### 6.2. Registering a New TA with Provisioning -First, check the code hash value of the new TA. Currently, when a request to generate evidence is sent to the PTA, the code hash value is output to the secure terminal for debugging purposes. Specifically, there is a line like the one below, where `gw9v98IV8ozl5nHpsMwl9W5nGGC0bzAYMPShwvff0vY=` is the base64 encoded value of the code hash. +First, check the code hash value of the new TA. The recommended way is to +compute it **offline from the build artifact** with +[provisoning/compute-arot-refval.py](provisoning/compute-arot-refval.py) +(pass the new TA's `.ta` file or its ELF) — no run is required: + +```bash +./provisoning/compute-arot-refval.py path/to/.ta +``` + +Alternatively, on debug builds the same value can be captured from a run: +when a request to generate evidence is sent to the PTA, the code hash value +is output to the secure terminal for debugging purposes, in a line like the +one below, where `gw9v98IV8ozl5nHpsMwl9W5nGGC0bzAYMPShwvff0vY=` is the base64 +encoded value of the code hash. (Note this debug output is unavailable on +i.MX production builds, where the core log level is 0 — use the offline +script there.) ```txt D/TC:? 0 cmd_get_cbor_evidence:82 b64_measurement_value: gw9v98IV8ozl5nHpsMwl9W5nGGC0bzAYMPShwvff0vY= diff --git a/provisoning/README-j.md b/provisoning/README-j.md index f338fe6..7a1abe5 100644 --- a/provisoning/README-j.md +++ b/provisoning/README-j.md @@ -86,3 +86,24 @@ veraison clear-stores ``` 引数を省略した場合は `qemu` が使われます。 + +## 参照値のオフライン計算 + +`data/comid-psa-refval-*.json` に登録する `measurement-value` のダイジェストは、 +ビルド成果物から直接計算できます。イメージの起動やデバッグログの取得は不要です +(i.MX の本番ビルドはコアログレベルが 0 のため、オフライン計算が唯一の取得手段です): + +```sh +# ARoT(TA の測定値): 署名済み .ta または TA の ELF を渡す +./compute-arot-refval.py path/to/.ta + +# PRoT(OP-TEE OS の測定値): コアの ELF を渡す +./compute-prot-refval.py path/to/tee.elf +``` + +それぞれ、対応する measurement に記載する `sha-256;` ダイジェストを +出力します。どちらも QEMU 上で、PTA が出力する実行時測定値と一致することを +検証済みです。PRoT の値はビルド固有(OP-TEE がビルド日時をハッシュ対象の +`.rodata` に埋め込むため)なので、リリースビルドごとに再計算・再登録して +ください。ARoT の値は TA バイナリが変わったときだけ変わります。 +`pyelftools` が必要です(`pip install pyelftools`)。 diff --git a/provisoning/README.md b/provisoning/README.md index 029d39a..0b7f802 100644 --- a/provisoning/README.md +++ b/provisoning/README.md @@ -88,3 +88,25 @@ You can automatically execute the above steps by running the following command. ``` If you omit the argument, `qemu` is used. + +## Computing the Reference Values Offline + +The `measurement-value` digests registered in `data/comid-psa-refval-*.json` +can be computed directly from the build artifacts — no need to boot the image +or capture debug logs (on i.MX production builds the core log level is 0, so +the offline computation is the only way): + +```sh +# ARoT (the TA measurement): pass the signed .ta or the TA ELF +./compute-arot-refval.py path/to/.ta + +# PRoT (the OP-TEE OS measurement): pass the core ELF +./compute-prot-refval.py path/to/tee.elf +``` + +Each prints the `sha-256;` digest to put into the corresponding +measurement entry. Both were verified on QEMU to be identical to the runtime +measurements emitted by the PTA. Note the PRoT value is build-specific +(OP-TEE embeds the build timestamp in the hashed `.rodata`), so recompute and +re-provision it for every released build; the ARoT value only changes when +the TA binary changes. Requires `pyelftools` (`pip install pyelftools`). From ac086b784b68cf5005070087ff7ca56962919e84 Mon Sep 17 00:00:00 2001 From: Yuichi Sugiyama Date: Tue, 28 Jul 2026 07:06:30 +0000 Subject: [PATCH 10/10] attester: exclude the Yocto tree from the QEMU docker build context Companion to the secure-boot-out exclusion: when YOCTO_DIR is left at its default, yocto.sh creates a real attester/container-imx/yocto directory, and the QEMU attester image builds (container/start.sh and container/export.sh use attester/ as context) would tar the entire Yocto tree into the build context. --- attester/.dockerignore | 1 + 1 file changed, 1 insertion(+) diff --git a/attester/.dockerignore b/attester/.dockerignore index 0a446f9..12c25e3 100644 --- a/attester/.dockerignore +++ b/attester/.dockerignore @@ -1,2 +1,3 @@ README.md container-imx/secure-boot-out/ +container-imx/yocto/