diff --git a/README-j.md b/README-j.md index 5310dcf..984527b 100644 --- a/README-j.md +++ b/README-j.md @@ -807,5 +807,17 @@ optee_remote_attestation --key-hex --pubx-hex --puby-h 期待される結果: `"ear.status": "affirming"` +## 性能計測ログ (RA_PERF) + +アテステーション処理全体の時間と主要イベント(メモリハッシュ、CBOR/COSE +エンコード、ECDSA/CAAM 署名、ブラックキー処理)ごとの所要時間を、機械可読な +ログ(`RA_PERF||||key=`)として出力でき +ます。ファームウェア側は `CFG_REMOTE_ATTESTATION_PERF=y` でコンパイルし、 +クライアント側は実行時に `optee_remote_attestation --perf`(データ収集用に +`--loop N` / `--no-server` も利用可)で有効化します。ログポイント一覧、 +QEMU/i.MX での有効化手順、CAAM ブラックキー使用有無の比較を含む推奨計測 +プロトコルは [docs/performance-measurement-j.md](docs/performance-measurement-j.md) +を参照してください。 + ## 謝辞 研究は、JST、CREST、JPMJCR21M3 ([Zero Trust IoT プロジェクト](https://zt-iot.nii.ac.jp/)) の支援を受けたものです。 diff --git a/README.md b/README.md index 1b50ba8..e09becf 100644 --- a/README.md +++ b/README.md @@ -868,6 +868,18 @@ optee_remote_attestation --key-hex --pubx-hex --puby-h Expected result: `"ear.status": "affirming"` +## Performance Measurement Logging (RA_PERF) + +The attestation stack can emit machine-parsable timing logs +(`RA_PERF||||key=`) covering the total +attestation time and each major event (memory hashing, CBOR/COSE encoding, +ECDSA/CAAM signing, black-key processing). The firmware side is compiled in +with `CFG_REMOTE_ATTESTATION_PERF=y`; the client side is enabled at runtime +with `optee_remote_attestation --perf` (plus `--loop N` / `--no-server` for +data collection). See [docs/performance-measurement.md](docs/performance-measurement.md) +for the log-point list, how to enable it on QEMU/i.MX, and the recommended +measurement protocol including the CAAM black-key on/off comparison. + ## Acknowlegement This work was supported by JST, CREST Grant Number JPMJCR21M3 ([ZeroTrust IoT Project](https://zt-iot.nii.ac.jp/en/)), Japan. 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 29669de..c423be9 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 @@ -8,6 +8,16 @@ PTA_EXTERNAL_SRC ?= "/attester/pta_remote_attestation" # Enable the custom remote_attestation PTA EXTRA_OEMAKE:append = " CFG_REMOTE_ATTESTATION_PTA=y" +# Performance measurement logging. Enable from local.conf with: +# CFG_REMOTE_ATTESTATION_PERF:pn-optee-os = "y" +# CFG_REMOTE_ATTESTATION_PERF:pn-veraison-attestation = "y" +# CFG_TEE_CORE_LOG_LEVEL must be raised together with the flag because +# meta-freescale's optee-os-common-fslc-imx.inc forces it to 0 (all core +# trace compiled out, RA_PERF lines included); this append is parsed after +# the .inc, so the later assignment wins on the make command line. +CFG_REMOTE_ATTESTATION_PERF ?= "n" +EXTRA_OEMAKE:append = "${@' CFG_REMOTE_ATTESTATION_PERF=y CFG_TEE_CORE_LOG_LEVEL=2' if d.getVar('CFG_REMOTE_ATTESTATION_PERF') == 'y' else ''}" + # Copy PTA source to OP-TEE OS source tree before compile do_configure:append() { # Create PTA directory in OP-TEE OS source @@ -32,6 +42,8 @@ do_configure:append() { cp ${PTA_SRC}/hash.h ${S}/core/pta/remote_attestation/ cp ${PTA_SRC}/sign.c ${S}/core/pta/remote_attestation/ cp ${PTA_SRC}/sign.h ${S}/core/pta/remote_attestation/ + cp ${PTA_SRC}/perf.c ${S}/core/pta/remote_attestation/ + cp ${PTA_SRC}/perf.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/ diff --git a/attester/container-imx/meta-veraison-attestation/recipes-security/veraison-attestation/veraison-attestation_1.0.bb b/attester/container-imx/meta-veraison-attestation/recipes-security/veraison-attestation/veraison-attestation_1.0.bb index dcbe7e3..a6bb25c 100644 --- a/attester/container-imx/meta-veraison-attestation/recipes-security/veraison-attestation/veraison-attestation_1.0.bb +++ b/attester/container-imx/meta-veraison-attestation/recipes-security/veraison-attestation/veraison-attestation_1.0.bb @@ -22,6 +22,10 @@ S = "${WORKDIR}/src" TA_DEV_KIT_DIR = "${STAGING_INCDIR}/optee/export-user_ta" TEEC_EXPORT = "${STAGING_DIR_HOST}${prefix}" +# Performance measurement logging in the TA (set "y" in local.conf, together +# with the optee-os flag; see optee-os_%.imx.bbappend) +CFG_REMOTE_ATTESTATION_PERF ?= "n" + # Rust configuration - rust-apiclient FFI library CARGO_SRC_DIR = "${S}/host/rust-ffi/coserv-rs" CARGO_MANIFEST_PATH = "${S}/host/rust-ffi/coserv-rs/Cargo.toml" @@ -95,7 +99,8 @@ do_compile() { oe_runmake V=1 \ TA_DEV_KIT_DIR=${TA_DEV_KIT_DIR} \ CROSS_COMPILE=${HOST_PREFIX} \ - LIBGCC_LOCATE_CFLAGS="--sysroot=${STAGING_DIR_HOST}" + LIBGCC_LOCATE_CFLAGS="--sysroot=${STAGING_DIR_HOST}" \ + CFG_REMOTE_ATTESTATION_PERF=${CFG_REMOTE_ATTESTATION_PERF} # Build host application cd ${S}/host diff --git a/attester/pta_remote_attestation/remote_attestation/perf.c b/attester/pta_remote_attestation/remote_attestation/perf.c new file mode 100644 index 0000000..5c87fac --- /dev/null +++ b/attester/pta_remote_attestation/remote_attestation/perf.c @@ -0,0 +1,66 @@ +#include "perf.h" + +#include +#include + +#define RA_PERF_MAX_EVENTS 16 + +struct ra_perf_event { + const char *event; + const char *keymode; + uint64_t ticks; +}; + +/* + * Simple per-command event buffer. Measurement runs are expected to be + * sequential (one attestation client at a time); concurrent PTA invocations + * would interleave their events. + */ +static struct ra_perf_event ra_perf_events[RA_PERF_MAX_EVENTS]; +static size_t ra_perf_num_events; + +void ra_perf_reset(void) +{ + ra_perf_num_events = 0; +} + +void ra_perf_record(const char *event, uint64_t start_ticks, + uint64_t end_ticks, const char *keymode) +{ + struct ra_perf_event *e = NULL; + + if (ra_perf_num_events >= RA_PERF_MAX_EVENTS) + return; + + e = &ra_perf_events[ra_perf_num_events++]; + e->event = event; + e->keymode = keymode; + e->ticks = end_ticks - start_ticks; +} + +void ra_perf_flush(void) +{ + uint32_t freq = read_cntfrq(); + uint64_t flush_start = ra_perf_now(); + size_t i = 0; + + /* Report the counter frequency once so tick math can be verified */ + IMSG("RA_PERF|pta|cntfrq|%" PRIu32 "|key=-", freq); + + for (i = 0; i < ra_perf_num_events; i++) { + struct ra_perf_event *e = &ra_perf_events[i]; + uint64_t us = e->ticks * 1000000ULL / freq; + + IMSG("RA_PERF|pta|%s|%" PRIu64 "|key=%s", e->event, us, e->keymode); + } + ra_perf_num_events = 0; + + /* + * Console writes are synchronous, so this flush is visible in the + * brackets measured by the layers above (TA pta_invoke, host + * evidence_get). Report its own cost so it can be subtracted; only + * the final line below remains unaccounted for. + */ + IMSG("RA_PERF|pta|perf_flush|%" PRIu64 "|key=-", + (ra_perf_now() - flush_start) * 1000000ULL / freq); +} diff --git a/attester/pta_remote_attestation/remote_attestation/perf.h b/attester/pta_remote_attestation/remote_attestation/perf.h new file mode 100644 index 0000000..228f7a7 --- /dev/null +++ b/attester/pta_remote_attestation/remote_attestation/perf.h @@ -0,0 +1,74 @@ +/* + * Performance measurement logging for the remote attestation PTA. + * + * Enabled with CFG_REMOTE_ATTESTATION_PERF=y. Durations are taken from the + * ARM generic timer (CNTPCT via barrier_read_counter_timer()) and reported + * in microseconds as: + * + * RA_PERF|pta|||key= + * + * Events are buffered with ra_perf_record() and emitted in one batch by + * ra_perf_flush(). Buffering matters: the secure console UART is synchronous + * and slow, so printing between two measured operations would inflate the + * later measurements. + */ +#ifndef PTA_REMOTE_ATTESTATION_PERF_H +#define PTA_REMOTE_ATTESTATION_PERF_H + +#ifdef CFG_REMOTE_ATTESTATION_PERF + +#include +#include +#include + +static inline uint64_t ra_perf_now(void) +{ + return barrier_read_counter_timer(); +} + +/* + * Key-path label used to split measurement runs in the logs: + * embedded = no external key, embedded test key + * plain = external plain private key (32 bytes) + * black = external serialized CAAM black key (> 32 bytes) + * Note: on i.MX with CFG_NXP_CAAM_ECC_DRV all three paths sign on CAAM + * hardware; "black" additionally pays blob decapsulation + CCM key import. + */ +static inline const char *ra_perf_keymode(const uint8_t *key, size_t key_len) +{ + if (!key || !key_len) + return "embedded"; + return key_len > 32 ? "black" : "plain"; +} + +void ra_perf_reset(void); +void ra_perf_record(const char *event, uint64_t start_ticks, + uint64_t end_ticks, const char *keymode); +void ra_perf_flush(void); + +#define RA_PERF_DECL(v) uint64_t v = 0 +#define RA_PERF_RESET() ra_perf_reset() +#define RA_PERF_START(v) ((v) = ra_perf_now()) +#define RA_PERF_STOP(v, event, keymode) \ + ra_perf_record((event), (v), ra_perf_now(), (keymode)) +#define RA_PERF_FLUSH() ra_perf_flush() + +#else /* CFG_REMOTE_ATTESTATION_PERF */ + +#define RA_PERF_DECL(v) +#define RA_PERF_RESET() \ + do { \ + } while (0) +#define RA_PERF_START(v) \ + do { \ + } while (0) +#define RA_PERF_STOP(v, event, keymode) \ + do { \ + } while (0) +#define RA_PERF_FLUSH() \ + do { \ + } while (0) + +#endif /* CFG_REMOTE_ATTESTATION_PERF */ + +#endif /* PTA_REMOTE_ATTESTATION_PERF_H */ diff --git a/attester/pta_remote_attestation/remote_attestation/remote_attestation.c b/attester/pta_remote_attestation/remote_attestation/remote_attestation.c index d7611ed..78d8831 100644 --- a/attester/pta_remote_attestation/remote_attestation/remote_attestation.c +++ b/attester/pta_remote_attestation/remote_attestation/remote_attestation.c @@ -5,11 +5,16 @@ #include "base64.h" #include "cbor.h" #include "hash.h" +#include "perf.h" #include "sign.h" #include #include #include +/* Perf-log key-path label, valid inside cmd_get_cbor_evidence() */ +#define RA_PERF_KM \ + ra_perf_keymode(serialized_black_key, serialized_black_key_len) + #ifdef CFG_NXP_CAAM #include #include @@ -99,6 +104,12 @@ static int32_t derive_client_id(const uint8_t *ta_uuid, size_t uuid_len) { static TEE_Result cmd_get_cbor_evidence(uint32_t param_types, TEE_Param params[TEE_NUM_PARAMS]) { + RA_PERF_DECL(t_cmd); + RA_PERF_DECL(t); + + RA_PERF_RESET(); + RA_PERF_START(t_cmd); + 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; @@ -152,27 +163,6 @@ 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) @@ -182,6 +172,9 @@ static TEE_Result cmd_get_cbor_evidence(uint32_t param_types, * instance_id = 0x01 || SHA-256(0x04 || PubX || PubY) * * When absent, the embedded test key's public coordinates are used. + * + * Parsed before any measured operation so the perf logs can label + * every event with the key path (RA_PERF_KM). */ if (TEE_PARAM_TYPE_GET(param_types, 3) == TEE_PARAM_TYPE_MEMREF_INPUT) { const uint8_t *p3 = params[3].memref.buffer; @@ -201,15 +194,45 @@ static TEE_Result cmd_get_cbor_evidence(uint32_t param_types, return status; } + /* Populate signer-id and lifecycle from platform fuses or fallback */ +#ifdef CFG_NXP_CAAM + RA_PERF_START(t); + status = ocotp_read_srk_hash(signer_id); + if (status != TEE_SUCCESS) + return status; + RA_PERF_STOP(t, "ocotp_srk", RA_PERF_KM); + + { + uint32_t lifecycle_val = 0; + + RA_PERF_START(t); + status = ocotp_get_lifecycle(&lifecycle_val); + if (status != TEE_SUCCESS) + return status; + RA_PERF_STOP(t, "ocotp_lifecycle", RA_PERF_KM); + 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 + /* Compute PSA instance-id from public key */ + RA_PERF_START(t); status = compute_instance_id(pub_x, pub_y, psa_instance_id); if (status != TEE_SUCCESS) return status; + RA_PERF_STOP(t, "instance_id", RA_PERF_KM); /* Calculate measurement hash of memory */ + RA_PERF_START(t); status = get_hash_ta_memory(measurement_value, TEE_SHA256_HASH_SIZE); if (status != TEE_SUCCESS) return status; + RA_PERF_STOP(t, "hash_ta", RA_PERF_KM); /* For debug print */ if (base64_encode(measurement_value, TEE_SHA256_HASH_SIZE, @@ -221,9 +244,11 @@ static TEE_Result cmd_get_cbor_evidence(uint32_t param_types, DMSG("b64_measurement_value: %s", b64_measurement_value); /* Measure the OP-TEE OS (core .text + .rodata) for the PRoT component */ + RA_PERF_START(t); status = get_hash_tee_memory(tee_measurement, TEE_SHA256_HASH_SIZE); if (status != TEE_SUCCESS) return status; + RA_PERF_STOP(t, "hash_tee", RA_PERF_KM); /* * OP-TEE OS version: first whitespace-delimited token of core_v_str, @@ -291,6 +316,7 @@ static TEE_Result cmd_get_cbor_evidence(uint32_t param_types, }; /* Encode evidence to CBOR */ + RA_PERF_START(t); UsefulBufC ubc_cbor_evidence = encode_evidence_to_cbor( eat_profile, psa_client_id, psa_security_lifecycle, psa_implementation_id, psa_implementation_id_len, components, @@ -302,8 +328,10 @@ static TEE_Result cmd_get_cbor_evidence(uint32_t param_types, free(heap_cose); return TEE_ERROR_GENERIC; } + RA_PERF_STOP(t, "cbor_encode", RA_PERF_KM); /* Sign the CBOR and generate a COSE evidence */ + RA_PERF_START(t); UsefulBufC cose_evidence = generate_cose(ubc_cbor_evidence, buffer_for_cose, serialized_black_key, serialized_black_key_len); @@ -313,6 +341,7 @@ static TEE_Result cmd_get_cbor_evidence(uint32_t param_types, free(heap_cose); return TEE_ERROR_GENERIC; } + RA_PERF_STOP(t, "cose_sign1", RA_PERF_KM); /* Copy COSE evidence for return buffer */ memcpy(output_buffer, cose_evidence.ptr, cose_evidence.len); @@ -320,6 +349,14 @@ static TEE_Result cmd_get_cbor_evidence(uint32_t param_types, free(heap_cbor); free(heap_cose); + + /* + * All timestamps are taken before any RA_PERF line is printed: the + * (slow, synchronous) console writes happen only in the flush below. + */ + RA_PERF_STOP(t_cmd, "cmd_total", RA_PERF_KM); + RA_PERF_FLUSH(); + return TEE_SUCCESS; } @@ -341,18 +378,24 @@ static TEE_Result cmd_generate_keypair(uint32_t param_types, size_t d_len, x_len, y_len; const size_t sec_size = 32; /* P-256 */ + RA_PERF_DECL(t); + if (param_types != exp_pt) return TEE_ERROR_BAD_PARAMETERS; + RA_PERF_RESET(); + res = crypto_acipher_alloc_ecc_keypair(&key, TEE_TYPE_ECDSA_KEYPAIR, sec_size * 8); if (res != TEE_SUCCESS) return res; key.curve = TEE_ECC_CURVE_NIST_P256; + RA_PERF_START(t); res = crypto_acipher_gen_ecc_key(&key, sec_size * 8); if (res != TEE_SUCCESS) goto out_free; + RA_PERF_STOP(t, "keypair_generate", "-"); d_len = crypto_bignum_num_bytes(key.d); x_len = crypto_bignum_num_bytes(key.x); @@ -389,6 +432,7 @@ static TEE_Result cmd_generate_keypair(uint32_t param_types, crypto_bignum_free(&key.d); crypto_bignum_free(&key.x); crypto_bignum_free(&key.y); + RA_PERF_FLUSH(); return res; } @@ -408,12 +452,18 @@ static TEE_Result cmd_convert_to_blackkey(uint32_t param_types, size_t need_size = 0; const size_t sec_size = 32; /* P-256 */ + RA_PERF_DECL(t_cmd); + RA_PERF_DECL(t); + if (param_types != exp_pt) return TEE_ERROR_BAD_PARAMETERS; if (!plain_d || plain_d_size != sec_size) return TEE_ERROR_BAD_PARAMETERS; + RA_PERF_RESET(); + RA_PERF_START(t_cmd); + caam_key.key_type = CAAM_KEY_PLAIN_TEXT; caam_key.sec_size = plain_d_size; caam_key.is_blob = false; @@ -424,11 +474,13 @@ static TEE_Result cmd_convert_to_blackkey(uint32_t param_types, memcpy(caam_key.buf.data, plain_d, plain_d_size); + RA_PERF_START(t); caam_res = caam_key_black_encapsulation(&caam_key, CAAM_KEY_BLACK_CCM); if (caam_res != CAAM_NO_ERROR) { res = caam_to_tee_status(caam_res); goto out; } + RA_PERF_STOP(t, "blackkey_encap", "-"); caam_res = caam_key_serialized_size(&caam_key, &need_size); if (caam_res != CAAM_NO_ERROR) { @@ -454,6 +506,8 @@ static TEE_Result cmd_convert_to_blackkey(uint32_t param_types, out: caam_key_free(&caam_key); + RA_PERF_STOP(t_cmd, "convert_total", "-"); + RA_PERF_FLUSH(); return res; } #endif /* CFG_NXP_CAAM */ diff --git a/attester/pta_remote_attestation/remote_attestation/sign.c b/attester/pta_remote_attestation/remote_attestation/sign.c index 98c2416..ade2d0f 100644 --- a/attester/pta_remote_attestation/remote_attestation/sign.c +++ b/attester/pta_remote_attestation/remote_attestation/sign.c @@ -1,3 +1,4 @@ +#include "perf.h" #include "sign.h" #include #include @@ -45,7 +46,6 @@ The key information has been extracted using the command: static TEE_Result hash_sha256(const uint8_t *msg, size_t msg_len, uint8_t *hash); static void free_keypair(struct ecc_keypair *keypair); -static void free_pubkey(struct ecc_public_key *pk); TEE_Result sign_ecdsa_sha256(const uint8_t *msg, size_t msg_len, uint8_t *sig, size_t *sig_len, @@ -54,10 +54,11 @@ TEE_Result sign_ecdsa_sha256(const uint8_t *msg, size_t msg_len, uint8_t *sig, TEE_Result res = TEE_SUCCESS; uint8_t hash_msg[TEE_SHA256_HASH_SIZE]; struct ecc_keypair *key = NULL; - struct ecc_public_key *pubkey = NULL; const uint8_t private_key[] = {PRIVATE_KEY}; - const uint8_t public_key_x[] = {PUBLIC_KEY_X}; - const uint8_t public_key_y[] = {PUBLIC_KEY_Y}; + + RA_PERF_DECL(t); + + RA_PERF_START(t); /* Allocate the key pair */ key = calloc(1, sizeof(*key)); @@ -86,59 +87,31 @@ TEE_Result sign_ecdsa_sha256(const uint8_t *msg, size_t msg_len, uint8_t *sig, if (res != TEE_SUCCESS) { goto free_key; } - - /* Allocate a public key storage for verification */ - pubkey = calloc(1, sizeof(*pubkey)); - if (pubkey == NULL) { - res = TEE_ERROR_OUT_OF_MEMORY; - goto free_key; - } - - res = crypto_acipher_alloc_ecc_public_key(pubkey, TEE_TYPE_ECDSA_PUBLIC_KEY, - KEY_SIZE_BIT); - if (res != TEE_SUCCESS) { - goto free_pubkey; - } - pubkey->curve = TEE_ECC_CURVE_NIST_P256; - - /* Copy the public key */ - res = crypto_bignum_bin2bn(public_key_x, KEY_SIZE, pubkey->x); - if (res != TEE_SUCCESS) { - goto free_pubkey; - } - res = crypto_bignum_bin2bn(public_key_y, KEY_SIZE, pubkey->y); - if (res != TEE_SUCCESS) { - goto free_pubkey; - } } + RA_PERF_STOP(t, "sign_key_setup", + ra_perf_keymode(serialized_black_key, + serialized_black_key_len)); + /* Hash the msg */ + RA_PERF_START(t); res = hash_sha256(msg, msg_len, hash_msg); if (res != TEE_SUCCESS) - goto free_pubkey; + goto free_key; + RA_PERF_STOP(t, "sign_tbs_hash", + ra_perf_keymode(serialized_black_key, + serialized_black_key_len)); /* Sign the hashed msg by the key pair */ + RA_PERF_START(t); res = crypto_acipher_ecc_sign(TEE_ALG_ECDSA_SHA256, key, hash_msg, TEE_SHA256_HASH_SIZE, sig, sig_len); if (res != TEE_SUCCESS) - goto free_pubkey; - - /* Verify the signature if we have the public key */ - if (pubkey) { - res = crypto_acipher_ecc_verify(TEE_ALG_ECDSA_SHA256, pubkey, hash_msg, - TEE_SHA256_HASH_SIZE, sig, *sig_len); - if (res == TEE_SUCCESS) { - DMSG("Success to verify"); - } else { - DMSG("Failed to verify"); - } - /* Reset res to success even if verify fails - we still signed */ - res = TEE_SUCCESS; - } + goto free_key; + RA_PERF_STOP(t, "sign_ecdsa", + ra_perf_keymode(serialized_black_key, + serialized_black_key_len)); -free_pubkey: - if (pubkey) - free_pubkey(pubkey); free_key: if (key) free_keypair(key); @@ -182,19 +155,6 @@ static void free_keypair(struct ecc_keypair *keypair) { free(keypair); } -static void free_pubkey(struct ecc_public_key *pk) { - if (!pk) - return; - - if (pk->x) - crypto_bignum_free(&pk->x); - if (pk->y) - crypto_bignum_free(&pk->y); - - memset(pk, 0, sizeof(*pk)); - free(pk); -} - /* * Compute PSA instance-id per: * PSA Attestation Token: draft-tschofenig-rats-psa-token, Section 4.2.1 diff --git a/attester/pta_remote_attestation/remote_attestation/sub.mk b/attester/pta_remote_attestation/remote_attestation/sub.mk index 21093d7..a1f7589 100644 --- a/attester/pta_remote_attestation/remote_attestation/sub.mk +++ b/attester/pta_remote_attestation/remote_attestation/sub.mk @@ -3,12 +3,13 @@ srcs-$(CFG_REMOTE_ATTESTATION_PTA) += base64.c srcs-$(CFG_REMOTE_ATTESTATION_PTA) += cbor.c srcs-$(CFG_REMOTE_ATTESTATION_PTA) += hash.c srcs-$(CFG_REMOTE_ATTESTATION_PTA) += sign.c +srcs-$(CFG_REMOTE_ATTESTATION_PERF) += perf.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 +incdirs-$(CFG_NXP_CAAM) += ../../drivers/crypto/caam/include cflags-$(CFG_REMOTE_ATTESTATION_PTA) += -Wno-declaration-after-statement cflags-$(CFG_REMOTE_ATTESTATION_PTA) += -Wno-redundant-decls diff --git a/attester/remote_attestation/host/client.c b/attester/remote_attestation/host/client.c index 5791551..941e4f3 100644 --- a/attester/remote_attestation/host/client.c +++ b/attester/remote_attestation/host/client.c @@ -3,6 +3,7 @@ #include #include "client.h" +#include "perf.h" int find_psa_media_type_index(const ChallengeResponseSession *session) { for (int i = 0; i < session->accept_type_count; i++) { @@ -22,6 +23,7 @@ ChallengeResponseSession *open_session() { "%s/challenge-response/v1/newSession", base_url); /* Now run the challenge response session, using the discovered endpoint */ + uint64_t t0 = ra_perf_now_us(); VeraisonResult status = open_challenge_response_session( new_session_endpoint, 32, /* Nonce size */ NULL, &session); @@ -30,6 +32,7 @@ ChallengeResponseSession *open_session() { printf("Failed to allocate Veraison client session.\n"); goto cleanup; } + ra_perf_log("veraison_new_session", ra_perf_now_us() - t0); printf("\nOpened new Veraison client session at %s\n", session->session_url); @@ -73,6 +76,7 @@ VeraisonResult post_evidence(ChallengeResponseSession *session, printf("Supplying the generated evidence to the server.\n"); /* Supply our evidence. */ + uint64_t t0 = ra_perf_now_us(); VeraisonResult status = challenge_response( session, evidence_len, evidence, session->accept_type_list[find_psa_media_type_index(session)]); @@ -81,6 +85,7 @@ VeraisonResult post_evidence(ChallengeResponseSession *session, printf("Failed to supply evidence to server.\n"); goto cleanup; } + ra_perf_log("veraison_post_evidence", ra_perf_now_us() - t0); printf("\nReceived the attestation result from the server.\n"); // And, finally, display the server's response, which will be a JWT diff --git a/attester/remote_attestation/host/main.c b/attester/remote_attestation/host/main.c index edc648b..3961822 100644 --- a/attester/remote_attestation/host/main.c +++ b/attester/remote_attestation/host/main.c @@ -1,8 +1,10 @@ #include +#include #include #include #include #include +#include /* OP-TEE TEE client API (built by optee_client) */ #include @@ -11,6 +13,35 @@ #include #include "client.h" +#include "perf.h" + +/* Performance measurement logging (see perf.h) */ +int ra_perf_enabled = 0; +const char *ra_perf_keymode = "-"; + +uint64_t ra_perf_now_us(void) { + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + return (uint64_t)ts.tv_sec * 1000000ULL + (uint64_t)ts.tv_nsec / 1000; +} + +void ra_perf_log(const char *event, uint64_t duration_us) { + if (ra_perf_enabled) + printf("RA_PERF|host|%s|%" PRIu64 "|key=%s\n", event, duration_us, + ra_perf_keymode); +} + +static int get_random_nonce(uint8_t *nonce, size_t sz) { + FILE *f = fopen("/dev/urandom", "rb"); + size_t n = 0; + + if (!f) + return -1; + n = fread(nonce, 1, sz, f); + fclose(f); + return n == sz ? 0 : -1; +} void print_binary_in_hex(uint8_t *buf, size_t sz) { int i = 0; @@ -59,6 +90,9 @@ static void print_usage(const char *prog) { printf(" --key-hex HEX Use key blob in hex for signing\n"); printf(" --pubx-hex HEX Public key X coordinate (32 bytes hex)\n"); printf(" --puby-hex HEX Public key Y coordinate (32 bytes hex)\n"); + printf(" --perf Print RA_PERF timing logs (or RA_PERF=1)\n"); + printf(" --loop N Repeat the attestation N times\n"); + printf(" --no-server Skip the verifier; use a local random nonce\n"); printf("\n"); printf("When using --key-hex with a CAAM black key, also supply --pubx-hex\n"); printf("and --puby-hex so the PTA can compute the correct PSA instance-id.\n"); @@ -85,13 +119,26 @@ int main(int argc, char *argv[]) { size_t host_pub_y_len = 0; bool mode_generate = false; bool mode_convert = false; + bool no_server = false; + long loop_count = 1; + + { + const char *env_perf = getenv("RA_PERF"); + + if (env_perf && strcmp(env_perf, "0") != 0) + ra_perf_enabled = 1; + } if (argc > 1 && strcmp(argv[1], "--generate-blackkey") == 0) { - if (argc != 2) - errx(1, "--generate-blackkey takes no arguments"); + if (argc == 3 && strcmp(argv[2], "--perf") == 0) + ra_perf_enabled = 1; + else if (argc != 2) + errx(1, "--generate-blackkey takes no arguments (except --perf)"); mode_generate = true; } else if (argc > 1 && strcmp(argv[1], "--convert-key") == 0) { - if (argc != 3) + if (argc == 4 && strcmp(argv[3], "--perf") == 0) + ra_perf_enabled = 1; + else if (argc != 3) errx(1, "--convert-key requires a hex key argument"); mode_convert = true; } @@ -132,6 +179,17 @@ int main(int argc, char *argv[]) { errx(1, "--puby-hex must be exactly 32 bytes"); has_puby = true; i++; + } else if (strcmp(argv[i], "--perf") == 0) { + ra_perf_enabled = 1; + } else if (strcmp(argv[i], "--loop") == 0) { + if (i + 1 >= argc) + errx(1, "Missing value for --loop"); + loop_count = strtol(argv[i + 1], NULL, 10); + if (loop_count < 1) + errx(1, "Invalid --loop value"); + i++; + } else if (strcmp(argv[i], "--no-server") == 0) { + no_server = true; } else { errx(1, "Unknown argument: %s", argv[i]); } @@ -143,16 +201,22 @@ int main(int argc, char *argv[]) { errx(1, "--pubx-hex and --puby-hex must be specified together"); } + uint64_t t0 = 0; + /* Initialize a context connecting us to the TEE */ + t0 = ra_perf_now_us(); res = TEEC_InitializeContext(NULL, &ctx); if (res != TEEC_SUCCESS) errx(1, "TEEC_InitializeContext failed with code 0x%x", res); + ra_perf_log("teec_init", ra_perf_now_us() - t0); + t0 = ra_perf_now_us(); res = TEEC_OpenSession(&ctx, &sess, &ta_uuid, TEEC_LOGIN_PUBLIC, NULL, NULL, &err_origin); if (res != TEEC_SUCCESS) errx(1, "TEEC_Opensession failed with code 0x%x origin 0x%x", res, err_origin); + ra_perf_log("teec_open_session", ra_perf_now_us() - t0); /* Convert plain key to black key */ if (mode_convert) { @@ -178,12 +242,14 @@ int main(int argc, char *argv[]) { op_c.params[1].tmpref.size = sizeof(black_key); printf("\nConverting plain key to black key...\n"); + t0 = ra_perf_now_us(); res = TEEC_InvokeCommand(&sess, TA_REMOTE_ATTESTATION_CMD_CONVERT_TO_BLACKKEY, &op_c, &err_origin); if (res != TEEC_SUCCESS) { free(plain_key); errx(1, "Convert key failed 0x%x origin 0x%x", res, err_origin); } + ra_perf_log("blackkey_convert", ra_perf_now_us() - t0); printf("BlackKey(hex): "); print_binary_in_hex(black_key, op_c.params[1].tmpref.size); @@ -209,6 +275,7 @@ int main(int argc, char *argv[]) { op_p.params[2].tmpref.buffer = pub_y; op_p.params[2].tmpref.size = sizeof(pub_y); printf("\nGenerating new black key...\n"); + t0 = ra_perf_now_us(); res = TEEC_InvokeCommand(&sess, TA_REMOTE_ATTESTATION_CMD_GENERATE_BLACKKEY, &op_p, &err_origin); if (res != TEEC_ERROR_SHORT_BUFFER && res != TEEC_SUCCESS) @@ -226,6 +293,8 @@ int main(int argc, char *argv[]) { free(blob); errx(1, "Generate black key (fetch) failed 0x%x origin 0x%x", res, err_origin); } + /* Includes both invocations (size probe + fetch = two keygens) */ + ra_perf_log("blackkey_generate", ra_perf_now_us() - t0); printf("BlackKey(hex): "); print_binary_in_hex(blob, op_p.params[0].tmpref.size); @@ -253,13 +322,6 @@ int main(int argc, char *argv[]) { return 0; } - /* Connect to the server and establish a session */ - ChallengeResponseSession *session = open_session(); - if (session == NULL) { - printf("Failed to open session.\n"); - return 1; - } - /* Optional: pass private key from host (SW 'd' or CAAM black key) */ /* @@ -292,53 +354,93 @@ int main(int argc, char *argv[]) { } } - /* Request TA to issue evidence based on a given nonce */ - /* The buffer allocated here must be large enough to hold the CBOR evidece - */ - uint8_t cbor_evidence[1024] = {0}; - TEEC_Operation op = {0}; - - if (packed_key_param && packed_key_param_len > 0) { - /* 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_NONE); - } else { - /* Params: nonce(in), output(out) */ - op.paramTypes = TEEC_PARAM_TYPES( - TEEC_MEMREF_TEMP_INPUT, TEEC_MEMREF_TEMP_OUTPUT, - 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 packed key: PubX(32) || PubY(32) || key_blob(N) */ - if (packed_key_param && packed_key_param_len > 0) { - op.params[2].tmpref.buffer = packed_key_param; - op.params[2].tmpref.size = packed_key_param_len; - } - - printf("\nInvoke TA.\n"); - res = TEEC_InvokeCommand(&sess, TA_REMOTE_ATTESTATOIN_CMD_GEN_CBOR_EVIDENCE, - &op, &err_origin); - if (res != TEEC_SUCCESS) - errx(1, "TEEC_InvokeCommand failed with code 0x%x origin 0x%x", res, - err_origin); - - printf("Invoked TA successfully.\n\n\n"); - - /* Receive CBOR(COSE) evidence from PTA */ - printf("Received evidence of CBOR (COSE) format from PTA.\n\n"); + /* Key-path label for the RA_PERF log lines */ + if (packed_key_param && packed_key_param_len > 0) + ra_perf_keymode = packed_key_param_len > 96 ? "black" : "plain"; + else + ra_perf_keymode = "embedded"; + + for (long iter = 0; iter < loop_count; iter++) { + ChallengeResponseSession *session = NULL; + uint8_t local_nonce[32] = {0}; + const uint8_t *nonce = NULL; + size_t nonce_sz = 0; + uint64_t t_total = ra_perf_now_us(); + + if (no_server) { + /* No verifier round trip: attest against a local random nonce */ + if (get_random_nonce(local_nonce, sizeof(local_nonce)) != 0) + errx(1, "Failed to generate a local nonce"); + nonce = local_nonce; + nonce_sz = sizeof(local_nonce); + } else { + /* Connect to the server and establish a session */ + session = open_session(); + if (session == NULL) { + printf("Failed to open session.\n"); + return 1; + } + nonce = (const uint8_t *)session->nonce; + nonce_sz = session->nonce_size; + } - printf("CBOR(COSE) size: %ld\n", op.params[1].tmpref.size); - printf("CBOR(COSE): "); - print_binary_in_hex(op.params[1].tmpref.buffer, op.params[1].tmpref.size); - printf("\n\n"); + /* Request TA to issue evidence based on a given nonce */ + /* The buffer allocated here must be large enough to hold the CBOR + * evidece */ + uint8_t cbor_evidence[1024] = {0}; + TEEC_Operation op = {0}; + + if (packed_key_param && packed_key_param_len > 0) { + /* 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_NONE); + } else { + /* Params: nonce(in), output(out) */ + op.paramTypes = TEEC_PARAM_TYPES( + TEEC_MEMREF_TEMP_INPUT, TEEC_MEMREF_TEMP_OUTPUT, + TEEC_NONE, TEEC_NONE); + } + op.params[0].tmpref.buffer = (uint8_t *)nonce; + op.params[0].tmpref.size = nonce_sz; + op.params[1].tmpref.buffer = cbor_evidence; + op.params[1].tmpref.size = sizeof(cbor_evidence); + /* param[2] is packed key: PubX(32) || PubY(32) || key_blob(N) */ + if (packed_key_param && packed_key_param_len > 0) { + op.params[2].tmpref.buffer = packed_key_param; + op.params[2].tmpref.size = packed_key_param_len; + } - /* Send the generated evidence to the session just established */ - post_evidence(session, op.params[1].tmpref.buffer, - op.params[1].tmpref.size); + printf("\nInvoke TA.\n"); + t0 = ra_perf_now_us(); + res = TEEC_InvokeCommand(&sess, + TA_REMOTE_ATTESTATOIN_CMD_GEN_CBOR_EVIDENCE, + &op, &err_origin); + if (res != TEEC_SUCCESS) + errx(1, "TEEC_InvokeCommand failed with code 0x%x origin 0x%x", + res, err_origin); + ra_perf_log("evidence_get", ra_perf_now_us() - t0); + + printf("Invoked TA successfully.\n\n\n"); + + /* Receive CBOR(COSE) evidence from PTA */ + printf("Received evidence of CBOR (COSE) format from PTA.\n\n"); + + t0 = ra_perf_now_us(); + printf("CBOR(COSE) size: %ld\n", op.params[1].tmpref.size); + printf("CBOR(COSE): "); + print_binary_in_hex(op.params[1].tmpref.buffer, + op.params[1].tmpref.size); + printf("\n\n"); + ra_perf_log("print_evidence", ra_perf_now_us() - t0); + + /* Send the generated evidence to the session just established */ + if (!no_server) + post_evidence(session, op.params[1].tmpref.buffer, + op.params[1].tmpref.size); + + ra_perf_log("total", ra_perf_now_us() - t_total); + } if (packed_key_param && packed_key_param != host_key) free(packed_key_param); diff --git a/attester/remote_attestation/host/perf.h b/attester/remote_attestation/host/perf.h new file mode 100644 index 0000000..8a79f27 --- /dev/null +++ b/attester/remote_attestation/host/perf.h @@ -0,0 +1,21 @@ +/* + * Performance measurement logging for the attestation host client. + * + * Enabled at runtime with --perf or the RA_PERF=1 environment variable. + * Durations come from clock_gettime(CLOCK_MONOTONIC) and are printed to + * stdout as: + * + * RA_PERF|host|||key= + */ +#ifndef HOST_RA_PERF_H +#define HOST_RA_PERF_H + +#include + +extern int ra_perf_enabled; +extern const char *ra_perf_keymode; + +uint64_t ra_perf_now_us(void); +void ra_perf_log(const char *event, uint64_t duration_us); + +#endif /* HOST_RA_PERF_H */ diff --git a/attester/remote_attestation/ta/remote_attestation_ta.c b/attester/remote_attestation/ta/remote_attestation_ta.c index 7885240..548434b 100755 --- a/attester/remote_attestation/ta/remote_attestation_ta.c +++ b/attester/remote_attestation/ta/remote_attestation_ta.c @@ -1,12 +1,36 @@ #include #include +#include #include #include #include #include +#ifdef CFG_REMOTE_ATTESTATION_PERF +/* + * Performance measurement logging (CFG_REMOTE_ATTESTATION_PERF=y). + * User TAs have no access to a high-resolution counter, so TA-level + * durations come from TEE_GetSystemTime and are accurate to ~1 ms only. + * Reported in microseconds for consistency with the PTA/host log lines: + * RA_PERF|ta|||key= + */ +static uint64_t ra_perf_now_us(void) { + TEE_Time t = {}; + + TEE_GetSystemTime(&t); + return ((uint64_t)t.seconds * 1000 + t.millis) * 1000; +} + +/* packed_key_len is the params[2] size: PubX(32) || PubY(32) || blob(N) */ +static const char *ra_perf_keymode(size_t packed_key_len) { + if (packed_key_len == 0) + return "embedded"; + return packed_key_len > 96 ? "black" : "plain"; +} +#endif + TEE_Result call_pta_for_cbor_evidence(uint32_t param_types, TEE_Param params[4]) { TEE_TASessionHandle sess = TEE_HANDLE_NULL; @@ -19,6 +43,16 @@ TEE_Result call_pta_for_cbor_evidence(uint32_t param_types, size_t nonce_len = 0; size_t out_len = 0; +#ifdef CFG_REMOTE_ATTESTATION_PERF + uint64_t perf_cmd_start = ra_perf_now_us(); + uint64_t perf_invoke_start = 0; + uint64_t perf_invoke_us = 0; + const char *perf_keymode = "embedded"; + + if (TEE_PARAM_TYPE_GET(param_types, 2) == TEE_PARAM_TYPE_MEMREF_INPUT) + perf_keymode = ra_perf_keymode(params[2].memref.size); +#endif + res = TEE_OpenTASession(&att_uuid, TEE_TIMEOUT_INFINITE, 0, NULL, &sess, &ret_orig); if (res != TEE_SUCCESS) { @@ -119,9 +153,15 @@ TEE_Result call_pta_for_cbor_evidence(uint32_t param_types, TEE_PARAM_TYPE_NONE); } +#ifdef CFG_REMOTE_ATTESTATION_PERF + perf_invoke_start = ra_perf_now_us(); +#endif res = TEE_InvokeTACommand(sess, TEE_TIMEOUT_INFINITE, PTA_REMOTE_ATTESTATION_GET_CBOR_EVIDENCE, pta_param_types, pta_params, &ret_orig); +#ifdef CFG_REMOTE_ATTESTATION_PERF + perf_invoke_us = ra_perf_now_us() - perf_invoke_start; +#endif if (res != TEE_SUCCESS) { EMSG("TEE_InvokeTACommand failed\n"); goto cleanup_return; @@ -142,6 +182,17 @@ TEE_Result call_pta_for_cbor_evidence(uint32_t param_types, if (nonce_buf) TEE_Free(nonce_buf); TEE_CloseTASession(sess); +#ifdef CFG_REMOTE_ATTESTATION_PERF + /* Durations measured before printing; ~1 ms resolution (see above) */ + if (perf_invoke_us) { + uint64_t perf_cmd_us = ra_perf_now_us() - perf_cmd_start; + + IMSG("RA_PERF|ta|pta_invoke|%" PRIu64 "|key=%s", perf_invoke_us, + perf_keymode); + IMSG("RA_PERF|ta|cmd_total|%" PRIu64 "|key=%s", perf_cmd_us, + perf_keymode); + } +#endif return res; } diff --git a/attester/remote_attestation/ta/sub.mk b/attester/remote_attestation/ta/sub.mk index 3cf5671..6662dd8 100644 --- a/attester/remote_attestation/ta/sub.mk +++ b/attester/remote_attestation/ta/sub.mk @@ -1,2 +1,5 @@ global-incdirs-y += include srcs-y += remote_attestation_ta.c + +# Performance measurement logging (pass CFG_REMOTE_ATTESTATION_PERF=y) +cflags-$(CFG_REMOTE_ATTESTATION_PERF) += -DCFG_REMOTE_ATTESTATION_PERF=1 diff --git a/docs/performance-measurement-j.md b/docs/performance-measurement-j.md new file mode 100644 index 0000000..77a5ece --- /dev/null +++ b/docs/performance-measurement-j.md @@ -0,0 +1,216 @@ +# 性能計測ログ (`RA_PERF`) + +リモートアテステーション全体の処理時間と、主要イベント(ハッシュ計算、 +CBOR/COSE エンコード、CAAM 署名、ブラックキー処理など)ごとの所要時間を +ログとして出力し、性能評価データを収集できます。 + +英語版は [performance-measurement.md](performance-measurement.md) を参照 +してください。 + +## ログフォーマット + +計測 1 件につき 1 行を出力します: + +``` +RA_PERF||||key= +``` + +| フィールド | 意味 | +| ------------- | -------------------------------------------------------------------------- | +| `layer` | `host`(Linux クライアント)、`ta`(ユーザ TA)、`pta`(OP-TEE コア内の PTA) | +| `event` | 後述のログポイント一覧を参照 | +| `duration_us` | 所要時間(マイクロ秒、整数) | +| `keymode` | 実行時の鍵パス: `embedded`(組込みテストキー)/ `plain`(外部平文鍵)/ `black`(CAAM ブラックキー)/ `-`(非該当) | + +クロックソースと出力先: + +| Layer | クロック | 分解能 | 出力先 | +| ------ | ------------------------------------------------ | ------- | ---------------------------------------- | +| `host` | `clock_gettime(CLOCK_MONOTONIC)` | 約 1 µs | `optee_remote_attestation` の標準出力 | +| `ta` | `TEE_GetSystemTime` | 約 1 ms | セキュアコンソール(`I/TA:` プレフィクス)| +| `pta` | ARM ジェネリックタイマ(`CNTPCT`、周波数 `CNTFRQ`)| µs 未満 | セキュアコンソール(`I/TC:` プレフィクス)| + +QEMU ではセキュアコンソールは `serial1.log`(`make check` 時)または +soc_term ウィンドウ、i.MX 8M Plus EVK ではデバッグ UART です。`dmesg` は +使用しません。PTA は実行ごとに擬似イベント `cntfrq` でカウンタ周波数を +1 回出力するので、tick→µs 換算の検証に使えます(i.MX8MP: 8 MHz、QEMU +virt: 約 62.5 MHz)。 + +## ログポイント一覧 + +### `host`(標準出力) + +| イベント | 計測対象 | +| ------------------------ | -------------------------------------------------------------------- | +| `teec_init` | `TEEC_InitializeContext`(`/dev/tee0` オープン) | +| `teec_open_session` | `TEEC_OpenSession` — 毎回 TA のロード/認証を含む | +| `veraison_new_session` | relying party への HTTP ラウンドトリップ(`newSession`、nonce 受領) | +| `evidence_get` | `TEEC_InvokeCommand` — REE から見た secure 側エビデンス生成の全体 | +| `print_evidence` | エビデンスの 16 進ダンプ出力(`total` から差し引けるように計測) | +| `veraison_post_evidence` | HTTP ラウンドトリップ: エビデンス POST → アテステーション結果(EAR JWT)| +| `total` | アテステーション 1 回分全体(セッション開始 → 結果受領) | +| `blackkey_generate` | `--generate-blackkey` 全体(PTA 呼び出し 2 回: サイズ確認 + 取得) | +| `blackkey_convert` | `--convert-key` の呼び出し | + +### `ta`(セキュアコンソール、分解能約 1 ms) + +| イベント | 計測対象 | +| ------------ | ----------------------------------------------- | +| `pta_invoke` | `TEE_InvokeTACommand` による PTA 呼び出し往復 | +| `cmd_total` | TA コマンド全体(パラメータ準備・コピーバック含む)| + +### `pta`(セキュアコンソール、µs 分解能) + +| イベント | 計測対象 | +| ------------------ | ----------------------------------------------------------------------------- | +| `cntfrq` | (擬似イベント)ジェネリックタイマ周波数 [Hz]。時間ではない | +| `ocotp_srk` | signer-id 用 OCOTP SRK ハッシュのヒューズ読み出し(i.MX のみ) | +| `ocotp_lifecycle` | OCOTP ライフサイクル読み出し(i.MX のみ。内部で SRK ワードを再読する) | +| `instance_id` | PSA instance-id の導出(公開鍵の SHA-256) | +| `hash_ta` | ARoT 計測値: 呼び出し元 TA の読み取り専用メモリの SHA-256 | +| `hash_tee` | PRoT 計測値: OP-TEE コア `.text` + `.rodata` の SHA-256 | +| `cbor_encode` | PSA クレームの QCBOR エンコード | +| `sign_key_setup` | 署名鍵の確保とインポート(ブラックキー blob または組込み鍵) | +| `sign_tbs_hash` | COSE 署名対象(TBS)の SHA-256 | +| `sign_ecdsa` | `crypto_acipher_ecc_sign` — **ブラックキー比較用ブラケット**(後述) | +| `cose_sign1` | COSE_Sign1 生成全体(上記 `sign_*` 3 イベントを含む) | +| `cmd_total` | `GET_CBOR_EVIDENCE` PTA コマンド全体 | +| `perf_flush` | バッファした RA_PERF 行の出力自体のコスト(注意事項参照) | +| `keypair_generate` | `crypto_acipher_gen_ecc_key`(i.MX では CAAM 鍵生成)。`--generate-blackkey` 1 回につき 2 回記録(サイズ確認 + 取得) | +| `blackkey_encap` | `--convert-key` 内の `caam_key_black_encapsulation`(CCM) | +| `convert_total` | `CONVERT_TO_BLACKKEY` PTA コマンド全体 | + +## ログの有効化 + +ファームウェア側の計測コードは `CFG_REMOTE_ATTESTATION_PERF=y` のときだけ +コンパイルされます。デフォルト(リリースビルド)には影響しません。 + +**QEMU**(attester コンテナ内): + +```bash +make check CFG_REMOTE_ATTESTATION_PTA=y CFG_REMOTE_ATTESTATION_PERF=y +``` + +**i.MX 8M Plus(Yocto)** — `local.conf` に追加: + +``` +CFG_REMOTE_ATTESTATION_PERF:pn-optee-os = "y" +CFG_REMOTE_ATTESTATION_PERF:pn-veraison-attestation = "y" +``` + +その後 `optee-os` を cleansstate から再ビルドし、`veraison-attestation`、 +イメージのビルド、再署名を行ってください。注意: NXP の +`optee-os-common-fslc-imx.inc` は `CFG_TEE_CORE_LOG_LEVEL=0`(コアのトレース +を全てコンパイル時に除去)を強制するため、本リポジトリの bbappend は perf +フラグと同時にコアログレベルを 2 へ自動的に引き上げます — これがないと +`pta` の行は UART に一切出力されません。 + +**ホストクライアント** — ファームウェアフラグとは独立したランタイム指定: + +```bash +optee_remote_attestation --perf # または RA_PERF=1 optee_remote_attestation +``` + +データ収集向けの追加オプション: + +| オプション | 用途 | +| ------------- | ------------------------------------------------------------------------ | +| `--loop N` | アテステーション全体を N 回繰り返す(反復ごとに `total` 行を出力) | +| `--no-server` | 検証器との通信を省略しローカル乱数 nonce でアテステーションを実行 — relying party に到達できない環境や、ネットワーク変動と切り離して TEE 側だけを測りたい場合に有効 | + +## 推奨計測プロトコル + +1. 環境を固定して記録する: ボード(i.MX8MPEVK)、ビルド設定、`cntfrq` 行、 + ソフトウェアのバージョン、N。sub-ms のイベント(署名・ハッシュ)は DVFS で + ぶれるので、**CPU ガバナを固定し実クロックを記録**する: + + ```bash + for g in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do + echo performance > "$g" 2>/dev/null + done + cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor + cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq + ``` + + 固定できない場合も、`scaling_governor` と `scaling_cur_freq` を読み取って + 記録すれば、後で DVFS による変動幅を論文で明示できる。 +2. 設定ごとに 30 回以上繰り返し、初回(コールドキャッシュ・初回 TA ロード) + は除外する: + +```bash +# 検証器あり(エンドツーエンド): +optee_remote_attestation --perf --loop 31 | tee host-embedded.log + +# TEE 側のみ(ネットワークなし): +optee_remote_attestation --perf --no-server --loop 31 | tee host-offline.log + +# CAAM ブラックキー(i.MX のみ): 1 回生成してから計測 +optee_remote_attestation --generate-blackkey --perf # blackkey_generate を記録 +optee_remote_attestation --perf --loop 31 --key-hex | tee host-black.log +``` + +3. `pta`/`ta` の行はセキュアコンソール(UART / `serial1.log`)から回収する。 +4. 集計(イベント × 鍵パスごとの平均/最小/最大): + +```bash +grep -h -o 'RA_PERF|.*' serial1.log host-*.log | awk -F'|' ' + { split($5, k, "="); id = $2 "|" $3 "|" k[2]; + n[id]++; s[id] += $4; + if (min[id] == "" || $4 < min[id]) min[id] = $4; + if ($4 > max[id]) max[id] = $4 } + END { for (i in n) printf "%-44s n=%-3d mean=%10.1f min=%8d max=%8d\n", + i, n[i], s[i]/n[i], min[i], max[i] }' | sort +``` + +この one-liner は**全イテレーションを集計**するため、`n` には手順 2 で除外 +すべき初回(コールド)実行が含まれる。出力は「未トリム(n=N)」として扱うか、 +集計前に各 `layer|event|keymode` の先頭 1 件を落とすこと(生ログはイテレーション +順を保持しているので `tail -n +2` 相当でトリム可)。なお `teec_init` / +`teec_open_session` はループ前に 1 回だけ計測されるので、各イテレーションの +集計には元々含まれない。 + +## CAAM 署名のブラックキー使用有無の比較 + +ブラックキーの使用有無は、同一の i.MX ビルド上での**ランタイム**の選択です: + +* **ブラックキーあり**: `--key-hex ` を指定(FullKey = + `PubX(32) || PubY(32) || シリアライズ済み CAAM ブラックキー blob`。 + `--generate-blackkey` または `--convert-key` で取得)。ログは `key=black`。 +* **ブラックキーなし**: 鍵引数を指定しない — 組込みテストキーを使用。 + ログは `key=embedded`。 + +比較には `pta|sign_ecdsa` イベント**のみ**を使ってください: + +* `CFG_NXP_CAAM_ECC_DRV=y` の i.MX では**どちらのパスも** CAAM ハードウェア + で ECDSA 署名を実行します。ブラックキーパスはそれに加えて鍵 blob の + デカプセル化とエンジン内 CCM 鍵インポートのコストを払うため、この差分が + まさに比較で分離したい量になります。(QEMU 実行はソフトウェア署名のみの + 第 3 のデータ点になります。) +* ブラックキー差分の評価に `cose_sign1` や `cmd_total` を使わないでください。 + +> **セキュリティに関する注意。** ブラックキーを使わない場合、署名鍵は +> OP-TEE 内で平文として扱われ(組込みテストキーの場合はバイナリにも含まれ)、 +> CAAM による鍵保護は働きません。セキュアブートを起点とした鍵保護の保証が +> 成り立たないため、ブラックキーなしの数値は性能比較のためだけのものであり、 +> 本番構成で使用してはいけません。 + +## 数値解釈上の注意 + +* PTA のタイムスタンプはすべて RA_PERF 行の出力**前**に取得され、PTA + コマンドの最後に一括出力されます。コンソール書き込みは同期的なので、 + この出力コストは上位レイヤのブラケット(`ta|pta_invoke`、 + `host|evidence_get`、`host|total`)には**含まれます**。出力コスト自体は + `pta|perf_flush` として報告されるため、レイヤ間の対応を取るときは差し引いて + ください(最後の `perf_flush` 行 1 行分だけは計上されません)。 +* 純粋なエビデンス生成時間には `pta|cmd_total` を使ってください。 + `host|evidence_get − ta|cmd_total` ≈ REE↔TEE 遷移 + libteec のオーバヘッド、 + `ta|pta_invoke − pta|cmd_total − pta|perf_flush` ≈ secure 側ディスパッチの + オーバヘッドです。 +* `host|total` はクライアントの冗長な表示を含みます。コンソールダンプ分は + `print_evidence` として計測しているので差し引けます。 +* `ta` レイヤの分解能は約 1 ms です(`TEE_GetSystemTime`。ユーザ TA は + サイクルカウンタへ直接アクセスできません)。 +* `hash_ta` は SHA-256 だけでなく、TA の読み取り専用リージョンの + `qsort`(`memcmp` 比較。ASLR に対して順序を安定化)を含みます。 +* `ocotp_lifecycle` は `ocotp_srk` が読んだ SRK ヒューズワードを内部で + 再読します。この重複は意図的にそのまま計測しています。 diff --git a/docs/performance-measurement.md b/docs/performance-measurement.md new file mode 100644 index 0000000..f9d77c7 --- /dev/null +++ b/docs/performance-measurement.md @@ -0,0 +1,217 @@ +# Performance Measurement Logging (`RA_PERF`) + +This repository can emit timing logs for the whole remote attestation flow so +that the total processing time and the duration of each major event (hash +computation, CBOR/COSE encoding, CAAM signing, black-key processing, …) can be +collected for performance evaluation. + +The Japanese version of this document is +[performance-measurement-j.md](performance-measurement-j.md). + +## Log format + +Every measurement is a single line: + +``` +RA_PERF||||key= +``` + +| Field | Meaning | +| ------------- | ---------------------------------------------------------------------------------------- | +| `layer` | `host` (Linux client), `ta` (user TA), `pta` (PTA inside the OP-TEE core) | +| `event` | See the log point tables below | +| `duration_us` | Duration in microseconds (integer) | +| `keymode` | Key path of the run: `embedded` (built-in test key), `plain` (external plain key), `black` (CAAM black key), `-` (not applicable) | + +Clock sources and where the lines appear: + +| Layer | Clock | Resolution | Output | +| ------ | ---------------------------------------------- | ---------- | ----------------------------------------------- | +| `host` | `clock_gettime(CLOCK_MONOTONIC)` | ~1 µs | stdout of `optee_remote_attestation` | +| `ta` | `TEE_GetSystemTime` | ~1 ms | secure console (`I/TA:` prefix) | +| `pta` | ARM generic timer (`CNTPCT`), frequency `CNTFRQ` | sub-µs | secure console (`I/TC:` prefix) | + +On QEMU the secure console is `serial1.log` (with `make check`) or the +soc_term window; on the i.MX 8M Plus EVK it is the debug UART. `dmesg` is not +involved. The PTA reports the counter frequency once per run as the +`cntfrq` pseudo-event so the tick-to-µs conversion can be verified +(i.MX8MP: 8 MHz, QEMU virt: ~62.5 MHz). + +## Log points + +### `host` (stdout) + +| Event | Measures | +| ----------------------- | --------------------------------------------------------------------- | +| `teec_init` | `TEEC_InitializeContext` (open `/dev/tee0`) | +| `teec_open_session` | `TEEC_OpenSession` — includes TA load/authentication on every run | +| `veraison_new_session` | HTTP round trip to the relying party (`newSession`, nonce receipt) | +| `evidence_get` | `TEEC_InvokeCommand` — entire secure-side evidence generation as seen from the REE | +| `print_evidence` | Console hex dump of the evidence (so it can be subtracted from `total`)| +| `veraison_post_evidence`| HTTP round trip: evidence POST → attestation result (EAR JWT) | +| `total` | One whole attestation transaction (session open → result received) | +| `blackkey_generate` | `--generate-blackkey` total (two PTA invocations: size probe + fetch) | +| `blackkey_convert` | `--convert-key` invocation | + +### `ta` (secure console, ~1 ms resolution) + +| Event | Measures | +| ------------ | ---------------------------------------------------- | +| `pta_invoke` | `TEE_InvokeTACommand` round trip into the PTA | +| `cmd_total` | Whole TA command incl. parameter staging and copy-back | + +### `pta` (secure console, µs resolution) + +| Event | Measures | +| ------------------ | ---------------------------------------------------------------------------- | +| `cntfrq` | (pseudo-event) generic timer frequency in Hz, not a duration | +| `ocotp_srk` | OCOTP SRK-hash fuse read for signer-id (i.MX only) | +| `ocotp_lifecycle` | OCOTP lifecycle read (i.MX only; re-reads the SRK words internally) | +| `instance_id` | PSA instance-id derivation (SHA-256 of the public key) | +| `hash_ta` | ARoT measurement: SHA-256 over the calling TA's read-only memory | +| `hash_tee` | PRoT measurement: SHA-256 over the OP-TEE core `.text` + `.rodata` | +| `cbor_encode` | QCBOR encoding of the PSA claims | +| `sign_key_setup` | Signing key allocation and import (black-key blob or embedded key) | +| `sign_tbs_hash` | SHA-256 of the COSE to-be-signed structure | +| `sign_ecdsa` | `crypto_acipher_ecc_sign` — **the black-key comparison bracket** (see below) | +| `cose_sign1` | Whole COSE_Sign1 generation (includes the three `sign_*` events) | +| `cmd_total` | Whole `GET_CBOR_EVIDENCE` PTA command | +| `perf_flush` | Cost of printing the buffered RA_PERF lines themselves (see Caveats) | +| `keypair_generate` | `crypto_acipher_gen_ecc_key` (CAAM keygen on i.MX); logged twice per `--generate-blackkey` (size probe + fetch) | +| `blackkey_encap` | `caam_key_black_encapsulation` (CCM) in `--convert-key` | +| `convert_total` | Whole `CONVERT_TO_BLACKKEY` PTA command | + +## Enabling the logs + +The firmware-side instrumentation is compiled in only with +`CFG_REMOTE_ATTESTATION_PERF=y`; release builds are unaffected by default. + +**QEMU** (inside the attester container): + +```bash +make check CFG_REMOTE_ATTESTATION_PTA=y CFG_REMOTE_ATTESTATION_PERF=y +``` + +**i.MX 8M Plus (Yocto)** — add to `local.conf` (or pass through your build +wrapper): + +``` +CFG_REMOTE_ATTESTATION_PERF:pn-optee-os = "y" +CFG_REMOTE_ATTESTATION_PERF:pn-veraison-attestation = "y" +``` + +then rebuild `optee-os` (cleansstate), `veraison-attestation`, the image, and +re-sign. Note: NXP's `optee-os-common-fslc-imx.inc` forces +`CFG_TEE_CORE_LOG_LEVEL=0` (all core trace compiled out), so the bbappend in +this repository automatically raises the core log level to 2 together with the +perf flag — without it no `pta` line would ever reach the UART. + +**Host client** — runtime opt-in, independent of the firmware flag: + +```bash +optee_remote_attestation --perf # or RA_PERF=1 optee_remote_attestation +``` + +Additional client options for data collection: + +| Option | Purpose | +| ------------- | ------------------------------------------------------------------------ | +| `--loop N` | Repeat the whole attestation N times (per-iteration `total` lines) | +| `--no-server` | Skip the verifier round trips and attest a local random nonce — useful on devices that cannot reach a relying party, and for isolating TEE-side numbers from network jitter | + +## Recommended measurement protocol + +1. Fix the environment and record it: board (i.MX8MPEVK), build config, + `cntfrq` line, software versions, N. Pin the CPU governor and record the + actual frequency — the sub-ms events (signing, hashing) swing with DVFS: + + ```bash + for g in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do + echo performance > "$g" 2>/dev/null + done + cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor + cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq + ``` + + If pinning is not possible, at least read and record `scaling_governor` + and `scaling_cur_freq` so the DVFS-induced variance can be bounded. +2. Collect ≥ 30 iterations per configuration and discard the first iteration + (cold caches, first TA load): + +```bash +# with verifier (end-to-end): +optee_remote_attestation --perf --loop 31 | tee host-embedded.log + +# TEE-side only (no network): +optee_remote_attestation --perf --no-server --loop 31 | tee host-offline.log + +# CAAM black key (i.MX only): generate once, then measure +optee_remote_attestation --generate-blackkey --perf # records blackkey_generate +optee_remote_attestation --perf --loop 31 --key-hex | tee host-black.log +``` + +3. Capture the secure console (UART/`serial1.log`) for the `pta`/`ta` lines. +4. Aggregate (mean/min/max per event and key path): + +```bash +grep -h -o 'RA_PERF|.*' serial1.log host-*.log | awk -F'|' ' + { split($5, k, "="); id = $2 "|" $3 "|" k[2]; + n[id]++; s[id] += $4; + if (min[id] == "" || $4 < min[id]) min[id] = $4; + if ($4 > max[id]) max[id] = $4 } + END { for (i in n) printf "%-44s n=%-3d mean=%10.1f min=%8d max=%8d\n", + i, n[i], s[i]/n[i], min[i], max[i] }' | sort +``` + +This one-liner aggregates **all** iterations, so its `n` includes the cold +first iteration that step 2 says to discard. Either treat its output as +"untrimmed (n=N)" or drop the first occurrence per `layer|event|keymode` +before aggregating (the raw log preserves iteration order, so `tail -n +2` +per event works). Note `teec_init`/`teec_open_session` are measured once +before the loop, so they are already outside the per-iteration aggregates. + +## Comparing CAAM signing with and without the black key + +The black-key usage is a **runtime** choice on a single i.MX build: + +* **with black key**: pass `--key-hex ` (FullKey = + `PubX(32) || PubY(32) || serialized CAAM black-key blob`, produced by + `--generate-blackkey` or `--convert-key`). Log lines carry `key=black`. +* **without black key**: pass no key arguments — the embedded test key is + used. Log lines carry `key=embedded`. + +Compare the `pta|sign_ecdsa` event only: + +* On i.MX with `CFG_NXP_CAAM_ECC_DRV=y` **both** paths execute the ECDSA sign + on the CAAM hardware; the black-key path additionally pays the key-blob + decapsulation and in-engine CCM key import, which is exactly the delta the + comparison isolates. (A QEMU run provides a third, software-only datapoint.) +* Do not use `cose_sign1` or `cmd_total` for the black-key delta. + +> **Security note.** Running without the black key means the signing key is +> handled as plaintext inside OP-TEE (and, for the embedded test key, is part +> of the binary). It is **not** protected by the CAAM and the +> secure-boot-rooted key-protection guarantee does not hold. The +> non-black-key numbers are for performance comparison only and must not be +> used in a production configuration. + +## Caveats for interpreting the numbers + +* All PTA timestamps are taken **before** any RA_PERF line is printed; the + lines are flushed in one batch at the end of the PTA command. Console + writes are synchronous, so this flush *is* visible in the brackets of the + layers above (`ta|pta_invoke`, `host|evidence_get`, `host|total`). The + flush reports its own cost as `pta|perf_flush` — subtract it when relating + layers (only the final `perf_flush` line itself remains unaccounted). +* Use `pta|cmd_total` as the pure evidence-generation time; + `host|evidence_get − ta|cmd_total` ≈ REE↔TEE transition + libteec overhead, + `ta|pta_invoke − pta|cmd_total − pta|perf_flush` ≈ secure-world dispatch + overhead. +* `host|total` includes all verbose client prints; `print_evidence` is + measured so the console dump can be subtracted. +* The `ta` layer has only ~1 ms resolution (`TEE_GetSystemTime`); user TAs + have no direct access to the cycle counter. +* `hash_ta` includes a `qsort` with `memcmp` of the TA's read-only regions + (ASLR-stable ordering), not just the SHA-256 itself. +* `ocotp_lifecycle` internally re-reads the SRK fuse words already read by + `ocotp_srk`; the duplication is intentionally measured as-is. diff --git a/provisoning/README-j.md b/provisoning/README-j.md index 7a1abe5..1ed9f7b 100644 --- a/provisoning/README-j.md +++ b/provisoning/README-j.md @@ -83,9 +83,15 @@ veraison clear-stores ./run.sh qemu # i.MX 8M Plus ./run.sh imx +# i.MX 8M Plus のビルド別バリアント(CAAM vs CPU 署名比較用、 +# docs/performance-measurement-j.md 参照) +./run.sh imx-caam +./run.sh imx-cpu ``` -引数を省略した場合は `qemu` が使われます。 +引数を省略した場合は `qemu` が使われます。環境名は +`data/comid-psa-refval-.json` / `data/comid-psa-ta-.json` の +ファイルペアに対応します。 ## 参照値のオフライン計算 diff --git a/provisoning/README.md b/provisoning/README.md index 0b7f802..5fe72bf 100644 --- a/provisoning/README.md +++ b/provisoning/README.md @@ -85,9 +85,14 @@ You can automatically execute the above steps by running the following command. ./run.sh qemu # i.MX 8M Plus ./run.sh imx +# i.MX 8M Plus per-build variants (CAAM vs CPU signing comparison, +# see docs/performance-measurement.md) +./run.sh imx-caam +./run.sh imx-cpu ``` -If you omit the argument, `qemu` is used. +If you omit the argument, `qemu` is used. Each environment name maps to a +`data/comid-psa-refval-.json` / `data/comid-psa-ta-.json` pair. ## Computing the Reference Values Offline diff --git a/provisoning/data/comid-psa-refval-imx-caam.json b/provisoning/data/comid-psa-refval-imx-caam.json new file mode 100644 index 0000000..4950e77 --- /dev/null +++ b/provisoning/data/comid-psa-refval-imx-caam.json @@ -0,0 +1,64 @@ +{ + "lang": "en-GB", + "tag-identity": { + "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B18", + "version": 0 + }, + "entities": [ + { + "name": "ACME Ltd.", + "regid": "https://acme.example", + "roles": [ + "tagCreator", + "creator", + "maintainer" + ] + } + ], + "triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "psa.impl-id", + "value": "aW14OG1wLW9wdGVlLXJhLTAwMDAwMDAwMDAwMDAwMDE=" + }, + "vendor": "ACME", + "model": "RoadRunner" + } + }, + "measurements": [ + { + "key": { + "type": "psa.refval-id", + "value": { + "label": "ARoT", + "signer-id": "427zIO3QE+zwfmqkGRPzdhocbmeEF9Bpn5Lk/mBzgf4=" + } + }, + "value": { + "digests": [ + "sha-256;FjIXXyuEaEG2FsLTRZjCck573aBBlnJT0sed9M9nRwA=" + ] + } + }, + { + "key": { + "type": "psa.refval-id", + "value": { + "label": "PRoT", + "signer-id": "427zIO3QE+zwfmqkGRPzdhocbmeEF9Bpn5Lk/mBzgf4=" + } + }, + "value": { + "digests": [ + "sha-256;gwmn34vboH/hXniANvQYJ4imFpvOmILM7iPgtNen/YI=" + ] + } + } + ] + } + ] + } +} \ No newline at end of file diff --git a/provisoning/data/comid-psa-refval-imx-cpu.json b/provisoning/data/comid-psa-refval-imx-cpu.json new file mode 100644 index 0000000..215faf0 --- /dev/null +++ b/provisoning/data/comid-psa-refval-imx-cpu.json @@ -0,0 +1,64 @@ +{ + "lang": "en-GB", + "tag-identity": { + "id": "43BBE37F-2E61-4B33-AED3-53CFF1428B17", + "version": 0 + }, + "entities": [ + { + "name": "ACME Ltd.", + "regid": "https://acme.example", + "roles": [ + "tagCreator", + "creator", + "maintainer" + ] + } + ], + "triples": { + "reference-values": [ + { + "environment": { + "class": { + "id": { + "type": "psa.impl-id", + "value": "aW14OG1wLW9wdGVlLXJhLTAwMDAwMDAwMDAwMDAwMDE=" + }, + "vendor": "ACME", + "model": "RoadRunner" + } + }, + "measurements": [ + { + "key": { + "type": "psa.refval-id", + "value": { + "label": "ARoT", + "signer-id": "427zIO3QE+zwfmqkGRPzdhocbmeEF9Bpn5Lk/mBzgf4=" + } + }, + "value": { + "digests": [ + "sha-256;FjIXXyuEaEG2FsLTRZjCck573aBBlnJT0sed9M9nRwA=" + ] + } + }, + { + "key": { + "type": "psa.refval-id", + "value": { + "label": "PRoT", + "signer-id": "427zIO3QE+zwfmqkGRPzdhocbmeEF9Bpn5Lk/mBzgf4=" + } + }, + "value": { + "digests": [ + "sha-256;E3zh/dMCQdC5VTamh+ipGFfNAeXfQrwOi13izZVxQqE=" + ] + } + } + ] + } + ] + } +} \ No newline at end of file diff --git a/provisoning/data/comid-psa-ta-imx-caam.json b/provisoning/data/comid-psa-ta-imx-caam.json new file mode 100644 index 0000000..8aadb39 --- /dev/null +++ b/provisoning/data/comid-psa-ta-imx-caam.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": "aW14OG1wLW9wdGVlLXJhLTAwMDAwMDAwMDAwMDAwMDE=" + }, + "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/data/comid-psa-ta-imx-cpu.json b/provisoning/data/comid-psa-ta-imx-cpu.json new file mode 100644 index 0000000..8aadb39 --- /dev/null +++ b/provisoning/data/comid-psa-ta-imx-cpu.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": "aW14OG1wLW9wdGVlLXJhLTAwMDAwMDAwMDAwMDAwMDE=" + }, + "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 6a4f78b..1394f50 100755 --- a/provisoning/run.sh +++ b/provisoning/run.sh @@ -6,13 +6,15 @@ VERAISON=${THIS_DIR}/../services/deployments/docker/veraison source ${THIS_DIR}/../services/deployments/docker/env.bash -# Select environment: qemu (default) or imx +# Select environment: qemu (default), imx, or a per-build variant such as +# imx-caam / imx-cpu (any name with a data/comid-psa-{refval,ta}-.json pair) 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" ]] || [[ ! -f "$TA_FILE" ]]; then - echo "Error: Unknown environment '$ENV'. Use 'qemu' or 'imx'." + echo "Error: Unknown environment '$ENV'. Available:" + ls "${THIS_DIR}"/data/comid-psa-refval-*.json | sed 's/.*comid-psa-refval-\(.*\)\.json/ \1/' exit 1 fi