From bcab3a0e0fa2fea7dbaa4dc49828f2958013d982 Mon Sep 17 00:00:00 2001 From: chenguanyuan Date: Thu, 31 Jul 2025 16:38:52 +0800 Subject: [PATCH 01/12] attestation verify iak cert pubkey relationship with platform instance_id --- attestation/samples/include/token_validate.h | 4 +- attestation/samples/src/client.c | 8 +- attestation/samples/src/token_validate.c | 148 +++++++++++++++++-- 3 files changed, 143 insertions(+), 17 deletions(-) diff --git a/attestation/samples/include/token_validate.h b/attestation/samples/include/token_validate.h index 955558c..de5d91d 100644 --- a/attestation/samples/include/token_validate.h +++ b/attestation/samples/include/token_validate.h @@ -78,6 +78,8 @@ bool verify_cca_token_signatures(cert_info_t *cert_info, qbuf_t cvm_cose, qbuf_t cvm_pub_key, qbuf_t plat_challenge, - qbuf_t cvm_pub_key_algo); + qbuf_t cvm_pub_key_algo, + qbuf_t platform_pub_key_algo, + qbuf_t platform_instance_id); #endif /* TOKEN_VALIDATE_H */ diff --git a/attestation/samples/src/client.c b/attestation/samples/src/client.c index 9e43ea9..2605c3d 100644 --- a/attestation/samples/src/client.c +++ b/attestation/samples/src/client.c @@ -168,7 +168,9 @@ int verify_token(unsigned char *token, size_t token_len) cca_token.cvm_cose, cca_token.cvm_token.pub_key, cca_token.platform_token.challenge, - cca_token.cvm_token.pub_key_hash_algo_id); + cca_token.cvm_token.pub_key_hash_algo_id, + cca_token.platform_token.hash_algo_id, + cca_token.platform_token.instance_id); /* * Verify sw-components in Platform token (following rust-ccatoken logic) */ @@ -201,7 +203,9 @@ int verify_token(unsigned char *token, size_t token_len) cca_token.cvm_cose, cca_token.cvm_token.pub_key, empty_buf, /* platform challenge */ - cca_token.cvm_token.pub_key_hash_algo_id); + cca_token.cvm_token.pub_key_hash_algo_id, + empty_buf, /* platform_pub_key_algo */ + empty_buf /* platform_instance_id */); printf("Using legacy CVM-only token verification mode\n"); if (verify_platform_components) { diff --git a/attestation/samples/src/token_validate.c b/attestation/samples/src/token_validate.c index 306acb0..29ff016 100644 --- a/attestation/samples/src/token_validate.c +++ b/attestation/samples/src/token_validate.c @@ -660,6 +660,132 @@ done: return ret; } +static bool get_ecckey_from_x509(X509 *x509_cert, unsigned char **pubkey_bin, size_t *pubkey_len) +{ + EVP_PKEY *pkey = X509_get_pubkey(x509_cert); + if (!pkey) { + printf("get_ecckey_from_x509: get_pub_key_from_cert Unable to decode the public key from x509_cert\n"); + return false; + } + + if (EVP_PKEY_id(pkey) != EVP_PKEY_EC) { + EVP_PKEY_free(pkey); + return false; // 非 ECC 公钥 + } + + // 获取 EC_KEY 结构 + EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(pkey); + if (!ec_key) { + EVP_PKEY_free(pkey); + return false; + } + + // 获取公钥点 + const EC_POINT *point = EC_KEY_get0_public_key(ec_key); + const EC_GROUP *group = EC_KEY_get0_group(ec_key); + + // 获取公钥的压缩或非压缩格式 + *pubkey_len = EC_POINT_point2oct(group, point, + EC_KEY_get_conv_form(ec_key), + NULL, 0, NULL); + if (*pubkey_len == 0) { + EC_KEY_free(ec_key); + EVP_PKEY_free(pkey); + return false; + } + + *pubkey_bin = (unsigned char *)malloc(*pubkey_len); + if (*pubkey_bin == NULL) { + EC_KEY_free(ec_key); + EVP_PKEY_free(pkey); + return false; + } + + if (EC_POINT_point2oct(group, point, + EC_KEY_get_conv_form(ec_key), + *pubkey_bin, *pubkey_len, NULL) == 0) { + EC_KEY_free(ec_key); + EVP_PKEY_free(pkey); + return false; + } + + EC_KEY_free(ec_key); + EVP_PKEY_free(pkey); + + return true; +} + +bool verify_iak_pubkey_hash(X509 *x509_cert, qbuf_t platform_pub_key_algo, qbuf_t platform_instance_id) +{ + char algo[10]; + uint8_t pubkey_hash[512]; + unsigned int pubkey_hash_len; + uint8_t calculated_pubkey_hash[512]; + size_t pubkey_len; + unsigned char *pubkey_bin; + + /* Get the ECC public key from the certificate, pubkey_bin for ECC is 0x04 || X || Y */ + if (!get_ecckey_from_x509(x509_cert, &pubkey_bin, &pubkey_len)) { + printf("verify_iak_pubkey_hash: failed to get ECC key from certificate\n"); + free(pubkey_bin); + return false; + } + + /* todo: + cert ECC key format is 0x04 || X || Y + HSM generate instance id hash used 8byte aliand X||Y:(6byte 0x00 + 66byte ECC(X)) +(6byte 0x00 + 66byte ECC(Y) + need convert cert ECC key to HSM generate instance id hash format*/ + int pubkey_buffer_size = pubkey_len - 1; + unsigned char *pubkey_buffer = pubkey_bin + 1; + + int ecc_x_len = pubkey_buffer_size/2; + int final_ecc_x_len = (ecc_x_len + 7) & ~7; + int final_ecc_x_pad_len = final_ecc_x_len - ecc_x_len; + int final_pubkey_buffer_size = final_ecc_x_len * 2; + + unsigned char *final_pubkey_buffer = (unsigned char *)malloc(final_pubkey_buffer_size); + (void)memset(final_pubkey_buffer, 0, final_ecc_x_pad_len); + memcpy(final_pubkey_buffer + final_ecc_x_pad_len, pubkey_buffer, ecc_x_len); + (void)memset(final_pubkey_buffer + final_ecc_x_len, 0, final_ecc_x_pad_len); + memcpy(final_pubkey_buffer + final_ecc_x_len + final_ecc_x_pad_len, pubkey_buffer + ecc_x_len, ecc_x_len); + + /* Get the hash algorithm from platform_pub_key_algo */ + if (strncmp("sha-256", platform_pub_key_algo.ptr, platform_pub_key_algo.len) == 0) { + memcpy(algo, "sha256", sizeof("sha256")); + } else if (strncmp("sha-384", platform_pub_key_algo.ptr, platform_pub_key_algo.len) == 0) { + memcpy(algo, "sha384", sizeof("sha384")); + } else if (strncmp("sha-512", platform_pub_key_algo.ptr, platform_pub_key_algo.len) == 0) { + memcpy(algo, "sha512", sizeof("sha512")); + } else { + printf("verify_iak_pubkey_hash: Unsupported sha algorithm."); + return false; + } + + //todo, hsm use sha256 only now + memcpy(algo, "sha256", sizeof("sha256")); + + if (!digest_sha(final_pubkey_buffer, final_pubkey_buffer_size, algo, calculated_pubkey_hash, &pubkey_hash_len)) { + printf("verify_iak_pubkey_hash: Failed to calculate the hash value\n"); + return false; + } + + /* platform_instance_id = {0x01,hash(iak_pub_key)} */ + if (platform_instance_id.len < 1 + pubkey_hash_len) { + printf("verify_iak_pubkey_hash: Invalid instance_id length"); + return false; + } + memcpy(pubkey_hash, platform_instance_id.ptr + 1, pubkey_hash_len); + + if (memcmp(pubkey_hash, calculated_pubkey_hash, pubkey_hash_len)) { + printf("verify_iak_pubkey_hash: unmatched pubkey hash value with platform instance id. \n"); + return false; + } + + free(pubkey_bin); + free(final_pubkey_buffer); + return true; +} + /* /* Helper function: Convert DER format ECDSA signature to COSE format (r||s) /* For P-521: DER format (~139 bytes) → COSE format (132 bytes) @@ -887,7 +1013,9 @@ bool verify_cca_token_signatures(cert_info_t *cert_info, qbuf_t cvm_cose, qbuf_t cvm_pub_key, qbuf_t plat_challenge, - qbuf_t cvm_pub_key_algo) + qbuf_t cvm_pub_key_algo, + qbuf_t platform_pub_key_algo, + qbuf_t platform_instance_id) { X509 *x509_root = X509_new(); X509 *x509_sub = X509_new(); @@ -940,22 +1068,14 @@ bool verify_cca_token_signatures(cert_info_t *cert_info, } /* - /* Verify cvm pubkey relationship with AIK - /* Note: In transitional scenarios where CPAK (ECC) signs platform token - /* and RAK (also ECC) signs CVM token, these keys may be different. - /* We allow this scenario but log it appropriately. + /* Verify Platform instance_id relationship with AIK + /* Note: platform_instance_id = {0x01,hash(iak_pub_key)} */ - ret = verify_cvm_pubkey(cvm_pub_key, x509_aik); - printf("Verifying cvm pubkey relationship with aik pubkey: %s \n", + ret = verify_iak_pubkey_hash(x509_aik, platform_pub_key_algo, platform_instance_id); + printf("Verifying platform_instance_id relationship with aik pubkey: %s \n", ret ? "Success" : "Failed"); if (ret == false) { - printf("Note: This may be expected in CPAK/RAK mixed scenarios\n"); - /* - /* In mixed scenarios, we don't fail the verification just because - /* the keys don't match - the individual signature verifications - /* are more important - */ - printf("Allowing verification to proceed despite key mismatch\n"); + ret_bits &= ~(1 << index); } index += 1; -- Gitee From ed21fda60d5d77a4abbd75a3d05f52ec8dd174f0 Mon Sep 17 00:00:00 2001 From: chenguanyuan Date: Tue, 5 Aug 2025 23:08:38 +0800 Subject: [PATCH 02/12] modify readme, remove old task, upgrate critical ret bits --- attestation/samples/README.en.md | 1 + attestation/samples/build.sh | 0 attestation/samples/src/token_validate.c | 147 ++++------------------- 3 files changed, 23 insertions(+), 125 deletions(-) mode change 100644 => 100755 attestation/samples/build.sh diff --git a/attestation/samples/README.en.md b/attestation/samples/README.en.md index 930bee1..ab478d0 100644 --- a/attestation/samples/README.en.md +++ b/attestation/samples/README.en.md @@ -53,6 +53,7 @@ Options: -f, --firmware Enable firmware verification with JSON reference file -e, --eventlog Dump event log -k, --fdekey Enable Full Disk Encryption with rootfs key file + -P, --platform Enable platform SW-components verification with JSON reference file -h, --help Print Help (this message) and exit ``` diff --git a/attestation/samples/build.sh b/attestation/samples/build.sh old mode 100644 new mode 100755 diff --git a/attestation/samples/src/token_validate.c b/attestation/samples/src/token_validate.c index 29ff016..4e9e04e 100644 --- a/attestation/samples/src/token_validate.c +++ b/attestation/samples/src/token_validate.c @@ -553,113 +553,6 @@ bool verify_plat_cose_sign(qbuf_t signed_cose, X509 *x509_aik) return true; } - -static bool verify_cvm_pubkey(qbuf_t pub_key, X509 *x509_aik) -{ - bool ret = false; - EVP_PKEY *aik_pkey = NULL; - EVP_PKEY *cvm_pkey = NULL; - const unsigned char *pub_key_ptr = pub_key.ptr; - - aik_pkey = X509_get_pubkey(x509_aik); - if (!aik_pkey) { - printf("Failed to extract pub-key from aik_cert\n"); - goto done; - } - - cvm_pkey = d2i_PUBKEY(NULL, &pub_key_ptr, pub_key.len); - if (cvm_pkey == NULL) { - if (pub_key.len == 133 && ((unsigned char*)pub_key.ptr)[0] == 0x04) { - EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp521r1); - if (!group) { - printf("Failed to create P-521 curve for CVM key\n"); - goto done; - } - - EC_POINT *point = EC_POINT_new(group); - if (!point) { - printf("Failed to create EC point for CVM key\n"); - EC_GROUP_free(group); - goto done; - } - - if (EC_POINT_oct2point(group, point, pub_key.ptr, pub_key.len, NULL) != 1) { - printf("Failed to convert CVM raw data to EC point\n"); - EC_POINT_free(point); - EC_GROUP_free(group); - goto done; - } - - EC_KEY *ec_key = EC_KEY_new(); - if (!ec_key || - EC_KEY_set_group(ec_key, group) != 1 || - EC_KEY_set_public_key(ec_key, point) != 1) { - printf("Failed to create EC_KEY for CVM key\n"); - if (ec_key) { - EC_KEY_free(ec_key); - } - EC_POINT_free(point); - EC_GROUP_free(group); - goto done; - } - - cvm_pkey = EVP_PKEY_new(); - if (!cvm_pkey || EVP_PKEY_set1_EC_KEY(cvm_pkey, ec_key) != 1) { - printf("Failed to create EVP_PKEY from CVM EC_KEY\n"); - if (cvm_pkey) { - EVP_PKEY_free(cvm_pkey); - } - EC_KEY_free(ec_key); - EC_POINT_free(point); - EC_GROUP_free(group); - goto done; - } - - EC_KEY_free(ec_key); - EC_POINT_free(point); - EC_GROUP_free(group); - } else { - printf("Failed to load CVM pubkey in any supported format\n"); - goto done; - } - } - - /* - /* Compare the two public keys - /* Note: For different key types (RSA vs ECC), this will return 0 (not equal) - /* which is expected behavior when transitioning between key types - */ - int key_compare_result = EVP_PKEY_cmp(aik_pkey, cvm_pkey); - if (key_compare_result == 1) { - ret = true; - } else if (key_compare_result == 0) { - /* - /* Keys don't match - this could be expected if we're transitioning - /* from RSA AIK to ECC RAK keys. In this case, we should verify - /* that the CVM key is valid and properly formed. - */ - if (EVP_PKEY_base_id(cvm_pkey) == EVP_PKEY_EC) { - EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(cvm_pkey); - if (ec_key) { - const EC_GROUP *group = EC_KEY_get0_group(ec_key); - if (group && EC_GROUP_get_curve_name(group) == NID_secp521r1) { - ret = true; - } - EC_KEY_free(ec_key); - } - } - } - -done: - if (aik_pkey) { - EVP_PKEY_free(aik_pkey); - } - if (cvm_pkey) { - EVP_PKEY_free(cvm_pkey); - } - return ret; -} - static bool get_ecckey_from_x509(X509 *x509_cert, unsigned char **pubkey_bin, size_t *pubkey_len) { EVP_PKEY *pkey = X509_get_pubkey(x509_cert); @@ -1037,8 +930,8 @@ bool verify_cca_token_signatures(cert_info_t *cert_info, if (ret == false) { ret_bits &= ~(1 << index); } - index += 1; } + index += 1; ret = verify_cvm_cose_sign(cvm_cose, cvm_pub_key); printf("Verifying if cVM token signature is signed by RAK: %s \n", @@ -1064,18 +957,20 @@ bool verify_cca_token_signatures(cert_info_t *cert_info, if (ret == false) { ret_bits &= ~(1 << index); } - index += 1; } + index += 1; /* /* Verify Platform instance_id relationship with AIK /* Note: platform_instance_id = {0x01,hash(iak_pub_key)} */ - ret = verify_iak_pubkey_hash(x509_aik, platform_pub_key_algo, platform_instance_id); - printf("Verifying platform_instance_id relationship with aik pubkey: %s \n", - ret ? "Success" : "Failed"); - if (ret == false) { - ret_bits &= ~(1 << index); + if (plat_cose.ptr != NULL && plat_cose.len > 0) { + ret = verify_iak_pubkey_hash(x509_aik, platform_pub_key_algo, platform_instance_id); + printf("Verifying platform_instance_id relationship with aik pubkey: %s \n", + ret ? "Success" : "Failed"); + if (ret == false) { + ret_bits &= ~(1 << index); + } } index += 1; @@ -1122,25 +1017,27 @@ bool verify_cca_token_signatures(cert_info_t *cert_info, /* 1. CVM token signature verification (RAK signs CVM token) /* 2. Platform token signature verification (CPAK signs platform token) /* 3. Challenge binding (RAK public key hash matches platform challenge) - /* 4. Certificate chain validation - THIS IS CRITICAL FOR SECURITY + /* 4. Platform instance id binding (AIK public key hash matches platform instance id) + /* 5. Certificate chain validation - THIS IS CRITICAL FOR SECURITY */ bool critical_verifications_passed = true; - if (plat_cose.ptr != NULL && plat_cose.len > 0) { - if (!(ret_bits & (1 << 0))) { - printf("Critical: Challenge binding failed\n"); - critical_verifications_passed = false; - } - if (!(ret_bits & (1 << 3))) { - printf("Critical: Platform token signature verification failed\n"); - critical_verifications_passed = false; - } + if (!(ret_bits & (1 << 0))) { + printf("Critical: Challenge binding failed\n"); + critical_verifications_passed = false; } - if (!(ret_bits & (1 << 1))) { printf("Critical: CVM token signature verification failed\n"); critical_verifications_passed = false; } + if (!(ret_bits & (1 << 3))) { + printf("Critical: Platform token signature verification failed\n"); + critical_verifications_passed = false; + } + if (!(ret_bits & (1 << 4))) { + printf("Critical: Instance_id binding failed\n"); + critical_verifications_passed = false; + } /* SECURITY FIX: Certificate chain validation is CRITICAL and must pass */ if (!(ret_bits & (1 << (index - 1)))) { /* Certificate chain validation bit */ -- Gitee From f6bb30965fb91cc312eb58d5d084482c9fd5f676 Mon Sep 17 00:00:00 2001 From: chenguanyuan Date: Tue, 5 Aug 2025 07:24:30 +0000 Subject: [PATCH 03/12] update attestation/samples/README.en.md. Signed-off-by: chenguanyuan --- attestation/samples/README.en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/attestation/samples/README.en.md b/attestation/samples/README.en.md index ab478d0..72dba73 100644 --- a/attestation/samples/README.en.md +++ b/attestation/samples/README.en.md @@ -53,7 +53,7 @@ Options: -f, --firmware Enable firmware verification with JSON reference file -e, --eventlog Dump event log -k, --fdekey Enable Full Disk Encryption with rootfs key file - -P, --platform Enable platform SW-components verification with JSON reference file + -P, --platform Enable platform SW-components verification with JSON reference file -h, --help Print Help (this message) and exit ``` -- Gitee From 8c7fccbf74352f7daa1cbca56a1a09b50606a9ac Mon Sep 17 00:00:00 2001 From: chenguanyuan Date: Tue, 5 Aug 2025 07:26:01 +0000 Subject: [PATCH 04/12] update attestation/samples/README.en.md. Signed-off-by: chenguanyuan --- attestation/samples/README.en.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/attestation/samples/README.en.md b/attestation/samples/README.en.md index 72dba73..5ba63a2 100644 --- a/attestation/samples/README.en.md +++ b/attestation/samples/README.en.md @@ -53,7 +53,7 @@ Options: -f, --firmware Enable firmware verification with JSON reference file -e, --eventlog Dump event log -k, --fdekey Enable Full Disk Encryption with rootfs key file - -P, --platform Enable platform SW-components verification with JSON reference file + -P, --platform Enable platform SW-components verification with JSON reference file -h, --help Print Help (this message) and exit ``` -- Gitee From ad7092ddfcf759018eb60ec2f12c419069fa52b1 Mon Sep 17 00:00:00 2001 From: chenguanyuan Date: Wed, 6 Aug 2025 03:45:29 +0800 Subject: [PATCH 05/12] update printf format --- attestation/samples/src/token_validate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/attestation/samples/src/token_validate.c b/attestation/samples/src/token_validate.c index 4e9e04e..95367b7 100644 --- a/attestation/samples/src/token_validate.c +++ b/attestation/samples/src/token_validate.c @@ -966,7 +966,7 @@ bool verify_cca_token_signatures(cert_info_t *cert_info, */ if (plat_cose.ptr != NULL && plat_cose.len > 0) { ret = verify_iak_pubkey_hash(x509_aik, platform_pub_key_algo, platform_instance_id); - printf("Verifying platform_instance_id relationship with aik pubkey: %s \n", + printf("Verifying if platform token instance_id matches with IAK Pubkey Hash: %s \n", ret ? "Success" : "Failed"); if (ret == false) { ret_bits &= ~(1 << index); -- Gitee From 9059a1e72a388d034690602bb7f6215edd39a0e6 Mon Sep 17 00:00:00 2001 From: chenguanyuan Date: Thu, 7 Aug 2025 18:40:24 +0800 Subject: [PATCH 06/12] revert verify_cvm_pubkey task for cvm token only scene --- attestation/samples/src/token_validate.c | 126 +++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/attestation/samples/src/token_validate.c b/attestation/samples/src/token_validate.c index 95367b7..c757433 100644 --- a/attestation/samples/src/token_validate.c +++ b/attestation/samples/src/token_validate.c @@ -553,6 +553,112 @@ bool verify_plat_cose_sign(qbuf_t signed_cose, X509 *x509_aik) return true; } +static bool verify_cvm_pubkey(qbuf_t pub_key, X509 *x509_aik) +{ + bool ret = false; + EVP_PKEY *aik_pkey = NULL; + EVP_PKEY *cvm_pkey = NULL; + const unsigned char *pub_key_ptr = pub_key.ptr; + + aik_pkey = X509_get_pubkey(x509_aik); + if (!aik_pkey) { + printf("Failed to extract pub-key from aik_cert\n"); + goto done; + } + + cvm_pkey = d2i_PUBKEY(NULL, &pub_key_ptr, pub_key.len); + if (cvm_pkey == NULL) { + if (pub_key.len == 133 && ((unsigned char*)pub_key.ptr)[0] == 0x04) { + EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp521r1); + if (!group) { + printf("Failed to create P-521 curve for CVM key\n"); + goto done; + } + + EC_POINT *point = EC_POINT_new(group); + if (!point) { + printf("Failed to create EC point for CVM key\n"); + EC_GROUP_free(group); + goto done; + } + + if (EC_POINT_oct2point(group, point, pub_key.ptr, pub_key.len, NULL) != 1) { + printf("Failed to convert CVM raw data to EC point\n"); + EC_POINT_free(point); + EC_GROUP_free(group); + goto done; + } + + EC_KEY *ec_key = EC_KEY_new(); + if (!ec_key || + EC_KEY_set_group(ec_key, group) != 1 || + EC_KEY_set_public_key(ec_key, point) != 1) { + printf("Failed to create EC_KEY for CVM key\n"); + if (ec_key) { + EC_KEY_free(ec_key); + } + EC_POINT_free(point); + EC_GROUP_free(group); + goto done; + } + + cvm_pkey = EVP_PKEY_new(); + if (!cvm_pkey || EVP_PKEY_set1_EC_KEY(cvm_pkey, ec_key) != 1) { + printf("Failed to create EVP_PKEY from CVM EC_KEY\n"); + if (cvm_pkey) { + EVP_PKEY_free(cvm_pkey); + } + EC_KEY_free(ec_key); + EC_POINT_free(point); + EC_GROUP_free(group); + goto done; + } + + EC_KEY_free(ec_key); + EC_POINT_free(point); + EC_GROUP_free(group); + } else { + printf("Failed to load CVM pubkey in any supported format\n"); + goto done; + } + } + + /* + /* Compare the two public keys + /* Note: For different key types (RSA vs ECC), this will return 0 (not equal) + /* which is expected behavior when transitioning between key types + */ + int key_compare_result = EVP_PKEY_cmp(aik_pkey, cvm_pkey); + if (key_compare_result == 1) { + ret = true; + } else if (key_compare_result == 0) { + /* + /* Keys don't match - this could be expected if we're transitioning + /* from RSA AIK to ECC RAK keys. In this case, we should verify + /* that the CVM key is valid and properly formed. + */ + if (EVP_PKEY_base_id(cvm_pkey) == EVP_PKEY_EC) { + EC_KEY *ec_key = EVP_PKEY_get1_EC_KEY(cvm_pkey); + if (ec_key) { + const EC_GROUP *group = EC_KEY_get0_group(ec_key); + if (group && EC_GROUP_get_curve_name(group) == NID_secp521r1) { + ret = true; + } + EC_KEY_free(ec_key); + } + } + } + +done: + if (aik_pkey) { + EVP_PKEY_free(aik_pkey); + } + if (cvm_pkey) { + EVP_PKEY_free(cvm_pkey); + } + return ret; +} + static bool get_ecckey_from_x509(X509 *x509_cert, unsigned char **pubkey_bin, size_t *pubkey_len) { EVP_PKEY *pkey = X509_get_pubkey(x509_cert); @@ -972,6 +1078,26 @@ bool verify_cca_token_signatures(cert_info_t *cert_info, ret_bits &= ~(1 << index); } } + else { + /* + /* Verify cvm pubkey relationship with AIK + /* Note: In transitional scenarios where CPAK (ECC) signs platform token + /* and RAK (also ECC) signs CVM token, these keys may be different. + /* We allow this scenario but log it appropriately. + */ + ret = verify_cvm_pubkey(cvm_pub_key, x509_aik); + printf("Verifying cvm pubkey relationship with aik pubkey: %s \n", + ret ? "Success" : "Failed"); + if (ret == false) { + printf("Note: This may be expected in CPAK/RAK mixed scenarios\n"); + /* + /* In mixed scenarios, we don't fail the verification just because + /* the keys don't match - the individual signature verifications + /* are more important + */ + printf("Allowing verification to proceed despite key mismatch\n"); + } + } index += 1; if (!file_exists(cert_info->cert_path_prefix, -- Gitee From abbbf3eebc424bc971042b76bee05bf3ada83579 Mon Sep 17 00:00:00 2001 From: chenguanyuan Date: Thu, 7 Aug 2025 23:45:33 +0800 Subject: [PATCH 07/12] code optimize, package rawkey convert to evp_pkey task, package sign_cose der2cose task, add comment --- attestation/samples/src/client.c | 6 +- attestation/samples/src/server.c | 2 + attestation/samples/src/token_validate.c | 344 +++++++++-------------- 3 files changed, 141 insertions(+), 211 deletions(-) diff --git a/attestation/samples/src/client.c b/attestation/samples/src/client.c index 2605c3d..d45df03 100644 --- a/attestation/samples/src/client.c +++ b/attestation/samples/src/client.c @@ -180,9 +180,9 @@ int verify_token(unsigned char *token, size_t token_len) /* Execute sw-components verification */ bool sw_verify_result = verify_platform_sw_components(&cca_token.platform_token, &ref_values); if (sw_verify_result) { - printf("Platform SW-Components verification PASSED\n"); + printf("Platform SW-Components verification Success\n"); } else { - printf("Platform SW-Components verification FAILED\n"); + printf("Platform SW-Components verification Failed\n"); ret = false; } @@ -727,6 +727,7 @@ int main(int argc, char *argv[]) } } + /* create and conect to server by IP and port */ sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { printf("socket creation failed...\n"); @@ -747,6 +748,7 @@ int main(int argc, char *argv[]) printf("connected to the server..\n"); } + /* Handle the connection */ ret = handle_connect(sockfd); close(sockfd); diff --git a/attestation/samples/src/server.c b/attestation/samples/src/server.c index fd35c6d..3c37a82 100644 --- a/attestation/samples/src/server.c +++ b/attestation/samples/src/server.c @@ -205,6 +205,7 @@ int main(int argc, char *argv[]) return 1; } + /* create a socket and wait for client connect */ sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { printf("socket creation failed...\n"); @@ -241,6 +242,7 @@ int main(int argc, char *argv[]) printf("server accept the client...\n"); } + /* Handle the connection */ ret = handle_connect(connfd, ctx); close(sockfd); diff --git a/attestation/samples/src/token_validate.c b/attestation/samples/src/token_validate.c index c757433..fa43bba 100644 --- a/attestation/samples/src/token_validate.c +++ b/attestation/samples/src/token_validate.c @@ -225,7 +225,59 @@ cleanup: return ret; } -/* +static bool ecc521_pubkey_raw2evp_pkey(struct q_useful_buf_c pub_key, EVP_PKEY **pkey) +{ + EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp521r1); + if (!group) { + printf("Failed to create P-521 curve\n"); + return false; + } + + EC_POINT *point = EC_POINT_new(group); + if (!point) { + printf("Failed to create EC point\n"); + EC_GROUP_free(group); + return false; + } + + if (EC_POINT_oct2point(group, point, pub_key.ptr, pub_key.len, NULL) != 1) { + printf("Failed to convert raw data to EC point\n"); + EC_POINT_free(point); + EC_GROUP_free(group); + return false; + } + + EC_KEY *ec_key = EC_KEY_new(); + if (!ec_key || + EC_KEY_set_group(ec_key, group) != 1 || + EC_KEY_set_public_key(ec_key, point) != 1) { + printf("Failed to create EC_KEY\n"); + if (ec_key) { + EC_KEY_free(ec_key); + } + EC_POINT_free(point); + EC_GROUP_free(group); + return false; + } + + *pkey = EVP_PKEY_new(); + if (!*pkey || EVP_PKEY_set1_EC_KEY(*pkey, ec_key) != 1) { + printf("Failed to create EVP_PKEY from EC_KEY\n"); + if (*pkey) { + EVP_PKEY_free(*pkey); + } + EC_KEY_free(ec_key); + EC_POINT_free(point); + EC_GROUP_free(group); + return false; + } + + EC_KEY_free(ec_key); + EC_POINT_free(point); + EC_GROUP_free(group); + return true; +} + /* Enhanced initialization for signing key to support both RSA and ECC */ static enum t_cose_err_t @@ -243,59 +295,13 @@ init_signing_key(struct t_cose_key *key_pair, /* For P-521: 1 byte (0x04) + 66 bytes (x) + 66 bytes (y) = 133 bytes */ if (pub_key.len == 133 && ((unsigned char*)pub_key.ptr)[0] == 0x04) { - EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp521r1); - if (!group) { - printf("Failed to create P-521 curve\n"); - ret = T_COSE_ERR_FAIL; - goto done; - } - - EC_POINT *point = EC_POINT_new(group); - if (!point) { - printf("Failed to create EC point\n"); - EC_GROUP_free(group); + printf("init_signing_key: load pubkey in raw ECC public key format\n"); + ret = ecc521_pubkey_raw2evp_pkey(pub_key,&pkey); + if (!ret) { + printf("Failed to transfer ECC public key to EVP_PKEY\n"); ret = T_COSE_ERR_FAIL; goto done; } - - if (EC_POINT_oct2point(group, point, pub_key.ptr, pub_key.len, NULL) != 1) { - printf("Failed to convert raw data to EC point\n"); - EC_POINT_free(point); - EC_GROUP_free(group); - ret = T_COSE_ERR_FAIL; - goto done; - } - - EC_KEY *ec_key = EC_KEY_new(); - if (!ec_key || - EC_KEY_set_group(ec_key, group) != 1 || - EC_KEY_set_public_key(ec_key, point) != 1) { - printf("Failed to create EC_KEY\n"); - if (ec_key) { - EC_KEY_free(ec_key); - } - EC_POINT_free(point); - EC_GROUP_free(group); - ret = T_COSE_ERR_FAIL; - goto done; - } - - pkey = EVP_PKEY_new(); - if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, ec_key) != 1) { - printf("Failed to create EVP_PKEY from EC_KEY\n"); - if (pkey) { - EVP_PKEY_free(pkey); - } - EC_KEY_free(ec_key); - EC_POINT_free(point); - EC_GROUP_free(group); - ret = T_COSE_ERR_FAIL; - goto done; - } - - EC_KEY_free(ec_key); - EC_POINT_free(point); - EC_GROUP_free(group); } else { printf("Failed to load pubkey in any supported format\n"); ret = T_COSE_ERR_FAIL; @@ -308,6 +314,9 @@ init_signing_key(struct t_cose_key *key_pair, ret = T_COSE_SUCCESS; done: + if (ret != T_COSE_SUCCESS && pkey) { + EVP_PKEY_free(pkey); // 确保失败时释放 + } return ret; } @@ -454,6 +463,64 @@ bool verify_pubkhash_challenge(qbuf_t pub_key, qbuf_t challenge, qbuf_t algorith return true; } +static void ecc521_cose_signature_convert_der2cose_if_needed(qbuf_t signed_cose,qbuf_t *final_signed_cose, EVP_PKEY *pkey) +{ + unsigned char *converted_cose_data = NULL; + size_t converted_cose_len = 0; + + QCBORDecodeContext decode_context; + QCBORItem item; + QCBORDecode_Init(&decode_context, signed_cose, QCBOR_DECODE_MODE_NORMAL); + + QCBORDecode_VGetNext(&decode_context, &item); + if (item.uDataType == QCBOR_TYPE_ARRAY && item.val.uCount == 4) { + QCBORDecode_VGetNext(&decode_context, &item); + QCBORDecode_VGetNext(&decode_context, &item); + QCBORDecode_VGetNext(&decode_context, &item); + QCBORDecode_VGetNext(&decode_context, &item); + + if (item.uDataType == QCBOR_TYPE_BYTE_STRING) { + const unsigned char *signature_data = item.val.string.ptr; + size_t signature_len = item.val.string.len; + + if (signature_is_der_format(signature_data, signature_len)) { + printf("Signature is in DER format.\n"); + int curve_nid = get_curve_nid_from_key(pkey); + if (curve_nid > 0) { + int field_size = (curve_nid == NID_secp521r1) ? 66 : + (curve_nid == NID_secp384r1) ? 48 : 32; + unsigned char *cose_signature = malloc(field_size * 2); + size_t cose_sig_len = field_size * 2; + + if (ecdsa_signature_der_to_cose(signature_data, signature_len, + cose_signature, &cose_sig_len, curve_nid)) { + converted_cose_len = signed_cose.len - signature_len + cose_sig_len; + converted_cose_data = malloc(converted_cose_len); + + if (converted_cose_data) { + size_t prefix_len = (unsigned char*)signature_data - (unsigned char*)signed_cose.ptr; + memcpy(converted_cose_data, signed_cose.ptr, prefix_len); + + converted_cose_data[prefix_len - 1] = cose_sig_len; + memcpy(converted_cose_data + prefix_len, cose_signature, cose_sig_len); + + size_t remaining_len = signed_cose.len - prefix_len - signature_len; + if (remaining_len > 0) { + memcpy(converted_cose_data + prefix_len + cose_sig_len, + (unsigned char*)signature_data + signature_len, remaining_len); + } + + final_signed_cose->ptr = converted_cose_data; + final_signed_cose->len = converted_cose_len; + } + } + + free(cose_signature); + } + } + } + } +} /* /* Enhanced platform COSE signature verification with DER-to-COSE conversion support /* Same DER format conversion capability as CVM token verification @@ -465,9 +532,6 @@ bool verify_plat_cose_sign(qbuf_t signed_cose, X509 *x509_aik) struct t_cose_key key_pair; struct t_cose_sign1_verify_ctx verify_ctx; EVP_PKEY *pkey; - bool conversion_performed = false; - unsigned char *converted_cose_data = NULL; - size_t converted_cose_len = 0; qbuf_t final_signed_cose = signed_cose; pkey = X509_get_pubkey(x509_aik); @@ -482,58 +546,7 @@ bool verify_plat_cose_sign(qbuf_t signed_cose, X509 *x509_aik) key_pair.crypto_lib = T_COSE_CRYPTO_LIB_OPENSSL; if (key_type == EVP_PKEY_EC) { - QCBORDecodeContext decode_context; - QCBORItem item; - QCBORDecode_Init(&decode_context, signed_cose, QCBOR_DECODE_MODE_NORMAL); - - QCBORDecode_VGetNext(&decode_context, &item); - if (item.uDataType == QCBOR_TYPE_ARRAY && item.val.uCount == 4) { - QCBORDecode_VGetNext(&decode_context, &item); - QCBORDecode_VGetNext(&decode_context, &item); - QCBORDecode_VGetNext(&decode_context, &item); - QCBORDecode_VGetNext(&decode_context, &item); - - if (item.uDataType == QCBOR_TYPE_BYTE_STRING) { - const unsigned char *signature_data = item.val.string.ptr; - size_t signature_len = item.val.string.len; - - if (signature_is_der_format(signature_data, signature_len)) { - int curve_nid = get_curve_nid_from_key(pkey); - if (curve_nid > 0) { - int field_size = (curve_nid == NID_secp521r1) ? 66 : - (curve_nid == NID_secp384r1) ? 48 : 32; - unsigned char *cose_signature = malloc(field_size * 2); - size_t cose_sig_len = field_size * 2; - - if (ecdsa_signature_der_to_cose(signature_data, signature_len, - cose_signature, &cose_sig_len, curve_nid)) { - converted_cose_len = signed_cose.len - signature_len + cose_sig_len; - converted_cose_data = malloc(converted_cose_len); - - if (converted_cose_data) { - size_t prefix_len = (unsigned char*)signature_data - (unsigned char*)signed_cose.ptr; - memcpy(converted_cose_data, signed_cose.ptr, prefix_len); - - converted_cose_data[prefix_len - 1] = cose_sig_len; - memcpy(converted_cose_data + prefix_len, cose_signature, cose_sig_len); - - size_t remaining_len = signed_cose.len - prefix_len - signature_len; - if (remaining_len > 0) { - memcpy(converted_cose_data + prefix_len + cose_sig_len, - (unsigned char*)signature_data + signature_len, remaining_len); - } - - final_signed_cose.ptr = converted_cose_data; - final_signed_cose.len = converted_cose_len; - conversion_performed = true; - } - } - - free(cose_signature); - } - } - } - } + ecc521_cose_signature_convert_der2cose_if_needed(signed_cose,&final_signed_cose,pkey); } t_cose_sign1_verify_init(&verify_ctx, 0); @@ -541,9 +554,11 @@ bool verify_plat_cose_sign(qbuf_t signed_cose, X509 *x509_aik) ret = t_cose_sign1_verify(&verify_ctx, final_signed_cose, &payload, NULL); - if (converted_cose_data) { - free(converted_cose_data); + /** Free the converted COSE if it was converted */ + if (final_signed_cose.ptr && final_signed_cose.ptr != signed_cose.ptr) { + free(final_signed_cose.ptr); } + free_signing_key(key_pair); if (ret != T_COSE_SUCCESS) { printf("Platform token signature verification failed with t_cose error: %d\n", ret); @@ -568,55 +583,17 @@ static bool verify_cvm_pubkey(qbuf_t pub_key, X509 *x509_aik) cvm_pkey = d2i_PUBKEY(NULL, &pub_key_ptr, pub_key.len); if (cvm_pkey == NULL) { + /* + /* If DER format fails, try raw ECC public key format + /* For P-521: 1 byte (0x04) + 66 bytes (x) + 66 bytes (y) = 133 bytes + */ if (pub_key.len == 133 && ((unsigned char*)pub_key.ptr)[0] == 0x04) { - EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp521r1); - if (!group) { - printf("Failed to create P-521 curve for CVM key\n"); + printf("verify_cvm_pubkey: load pubkey in raw ECC public key format\n"); + ret = ecc521_pubkey_raw2evp_pkey(pub_key,&cvm_pkey); + if (!ret) { + printf("Failed to transfer ECC public key to EVP_PKEY\n"); goto done; } - - EC_POINT *point = EC_POINT_new(group); - if (!point) { - printf("Failed to create EC point for CVM key\n"); - EC_GROUP_free(group); - goto done; - } - - if (EC_POINT_oct2point(group, point, pub_key.ptr, pub_key.len, NULL) != 1) { - printf("Failed to convert CVM raw data to EC point\n"); - EC_POINT_free(point); - EC_GROUP_free(group); - goto done; - } - - EC_KEY *ec_key = EC_KEY_new(); - if (!ec_key || - EC_KEY_set_group(ec_key, group) != 1 || - EC_KEY_set_public_key(ec_key, point) != 1) { - printf("Failed to create EC_KEY for CVM key\n"); - if (ec_key) { - EC_KEY_free(ec_key); - } - EC_POINT_free(point); - EC_GROUP_free(group); - goto done; - } - - cvm_pkey = EVP_PKEY_new(); - if (!cvm_pkey || EVP_PKEY_set1_EC_KEY(cvm_pkey, ec_key) != 1) { - printf("Failed to create EVP_PKEY from CVM EC_KEY\n"); - if (cvm_pkey) { - EVP_PKEY_free(cvm_pkey); - } - EC_KEY_free(ec_key); - EC_POINT_free(point); - EC_GROUP_free(group); - goto done; - } - - EC_KEY_free(ec_key); - EC_POINT_free(point); - EC_GROUP_free(group); } else { printf("Failed to load CVM pubkey in any supported format\n"); goto done; @@ -913,7 +890,6 @@ bool verify_cvm_cose_sign(qbuf_t signed_cose, qbuf_t pub_key) enum t_cose_err_t ret; struct t_cose_key key_pair; struct t_cose_sign1_verify_ctx verify_ctx; - bool conversion_performed = false; unsigned char *converted_cose_data = NULL; size_t converted_cose_len = 0; qbuf_t final_signed_cose = signed_cose; @@ -928,58 +904,7 @@ bool verify_cvm_cose_sign(qbuf_t signed_cose, qbuf_t pub_key) int key_type = EVP_PKEY_base_id(verification_key); if (key_type == EVP_PKEY_EC) { - QCBORDecodeContext decode_context; - QCBORItem item; - QCBORDecode_Init(&decode_context, signed_cose, QCBOR_DECODE_MODE_NORMAL); - - QCBORDecode_VGetNext(&decode_context, &item); - if (item.uDataType == QCBOR_TYPE_ARRAY && item.val.uCount == 4) { - QCBORDecode_VGetNext(&decode_context, &item); - QCBORDecode_VGetNext(&decode_context, &item); - QCBORDecode_VGetNext(&decode_context, &item); - QCBORDecode_VGetNext(&decode_context, &item); - - if (item.uDataType == QCBOR_TYPE_BYTE_STRING) { - const unsigned char *signature_data = item.val.string.ptr; - size_t signature_len = item.val.string.len; - - if (signature_is_der_format(signature_data, signature_len)) { - int curve_nid = get_curve_nid_from_key(verification_key); - if (curve_nid > 0) { - int field_size = (curve_nid == NID_secp521r1) ? 66 : - (curve_nid == NID_secp384r1) ? 48 : 32; - unsigned char *cose_signature = malloc(field_size * 2); - size_t cose_sig_len = field_size * 2; - - if (ecdsa_signature_der_to_cose(signature_data, signature_len, - cose_signature, &cose_sig_len, curve_nid)) { - converted_cose_len = signed_cose.len - signature_len + cose_sig_len; - converted_cose_data = malloc(converted_cose_len); - - if (converted_cose_data) { - size_t prefix_len = (unsigned char*)signature_data - (unsigned char*)signed_cose.ptr; - memcpy(converted_cose_data, signed_cose.ptr, prefix_len); - - converted_cose_data[prefix_len - 1] = cose_sig_len; - memcpy(converted_cose_data + prefix_len, cose_signature, cose_sig_len); - - size_t remaining_len = signed_cose.len - prefix_len - signature_len; - if (remaining_len > 0) { - memcpy(converted_cose_data + prefix_len + cose_sig_len, - (unsigned char*)signature_data + signature_len, remaining_len); - } - - final_signed_cose.ptr = converted_cose_data; - final_signed_cose.len = converted_cose_len; - conversion_performed = true; - } - } - - free(cose_signature); - } - } - } - } + ecc521_cose_signature_convert_der2cose_if_needed(signed_cose, &final_signed_cose, verification_key); } t_cose_sign1_verify_init(&verify_ctx, 0); @@ -990,8 +915,9 @@ bool verify_cvm_cose_sign(qbuf_t signed_cose, qbuf_t pub_key) &payload, NULL); - if (converted_cose_data) { - free(converted_cose_data); + /** Free the converted COSE if it was converted */ + if (final_signed_cose.ptr && final_signed_cose.ptr != signed_cose.ptr) { + free(final_signed_cose.ptr); } free_signing_key(key_pair); -- Gitee From bac67f43a41180de513ed252473c91021bfcfb36 Mon Sep 17 00:00:00 2001 From: chenguanyuan Date: Tue, 12 Aug 2025 23:56:40 +0800 Subject: [PATCH 08/12] update readme, modify cvm-only or platform+cvm scene token verify flow --- attestation/samples/README.en.md | 197 +++++++++++++++++++++-- attestation/samples/src/token_validate.c | 28 ++-- 2 files changed, 194 insertions(+), 31 deletions(-) diff --git a/attestation/samples/README.en.md b/attestation/samples/README.en.md index 5ba63a2..a4a5b74 100644 --- a/attestation/samples/README.en.md +++ b/attestation/samples/README.en.md @@ -35,8 +35,8 @@ The server supports parameters as below. $ ./server -h Usage: server [options] Options: - -i, --ip Listening IP address - -p, --port Listening tcp port + -i, --ip Listening IP address, By default, it is the local loopback address. + -p, --port Listening tcp port, By default, it is 7220. -k, --fdekey Enable Full Disk Encryption with rootfs key file -h, --help Print Help (this message) and exit @@ -47,16 +47,18 @@ The client supports parameters as below. ```shell Usage: client [options] Options: - -i, --ip Listening IP address - -p, --port Listening tcp port + -i, --ip Listening IP address, By default, it is the local loopback address. + -p, --port Listening tcp port, By default, it is 7220. -m, --measurement Initial measurement for cVM - -f, --firmware Enable firmware verification with JSON reference file - -e, --eventlog Dump event log + -f, --firmware Dump ACPI table & Event Log and Enable firmware verification with JSON reference file + -e, --eventlog Dump ACPI table & Event Log and print -k, --fdekey Enable Full Disk Encryption with rootfs key file -P, --platform Enable platform SW-components verification with JSON reference file -h, --help Print Help (this message) and exit ``` +Note: The parameter `-f` and `-e` can not used together. + Example Commands - Run attestation samples for direct kernel boot: @@ -66,10 +68,80 @@ Example Commands ``` ```shell -./client -i 127.0.0.1 -p 12345 -m 38d644db0aeddedbf9e11a50dd56fb2d0c663f664d63ad62762490da41562108 +./client -i 127.0.0.1 -p 12345 -m 38d644db0aeddedbf9e11a50dd56fb2d0c663f664d63ad62762490da41562108 -P sw-compnents.json ``` -Note: The parameter following `-m` is the reference value for the CVM initial measurement, calculated by the [gen_rim_ref](https://gitee.com/openeuler/virtCCA_sdk/tree/master/attestation/rim_ref) tool. +Note: + +1. The parameter following `-m` is the reference value for the CVM initial measurement, calculated by the [gen_rim_ref](https://gitee.com/openeuler/virtCCA_sdk/tree/master/attestation/rim_ref) tool. +2. The parameter following `-P` is A JSON file that verifies the sofeware components within the platform_token, included in the BIOS release package. + +``` +{ + "header": { + "timestamp": "2025-01-14", + "copyright": "Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.", + "version": "2.0", + "description": "Platform reference values for CCA token verification" + }, + "hostBios": [ + { + "biosVersion": "21.21.0", + "biosVendor": "Huawei Corp.", + "pcrs": [ + { + "pcrIndex": "0", + "description": "BIOS", + "sha256": "fa4caa9e3c17efbf3aa9d40a5316dd31cae54cdbee74bb1df666e0ce8d5c82e2" + }, + { + "pcrIndex": "0", + "description": "BIOS", + "sm3": "6c9bbf28432f525519aadfc1d635e96980e66b1d7aa5b67cbdb0acb6ab014fd2" + } + ], + "measure_value": [ + { + "firware_name": "ipu", + "measurement": "1d018904e20291089280073eb1abcbedbff9334f916ba725daa8474d524ee1c0", + "firware_version": "21.21.0", + "hash_algorithm": "sha256" + }, + { + "firware_name": "imu", + "measurement": "a7311708162e6336cf765527345953e54fb18d7ee0960ca34465404e21ebf288", + "firware_version": "21.21.0", + "hash_algorithm": "sha256" + }, + { + "firware_name": "imf_ap", + "measurement": "4de464130279547206a15ee2f7ecc1357daecf5e24091fc0a08dab28e0c4bf2f", + "firware_version": "21.21.0", + "hash_algorithm": "sha256" + }, + { + "firware_name": "tf_bl2", + "measurement": "b32c4018835b6c637f7841526adf2b6f2c5589f38872f11a9acd3a07bb30e96c", + "firware_version": "21.21.0", + "hash_algorithm": "sha256" + }, + { + "firware_name": "uefi", + "measurement": "afe614b7be8ad6e0aceb9c0a2d3d2ebfa13bfb0bafd72f8522c3674945b62b17", + "firware_version": "21.21.0", + "hash_algorithm": "sha256" + }, + { + "firware_name": "tee", + "measurement": "11d4282bc1f587d0c3af913b785de72b1daafdd24f41f7795484afcaf7e78ed8", + "firware_version": "1.4", + "hash_algorithm": "sha256" + } + ] + } + ] +} +``` - Run attestation samples for grub boot: @@ -78,11 +150,26 @@ Note: The parameter following `-m` is the reference value for the CVM initial me ``` ```shell -./client -i 127.0.0.1 -p 12345 -m 38d644db0aeddedbf9e11a50dd56fb2d0c663f664d63ad62762490da41562108 -f image_reference_measurement.json +./client -i 127.0.0.1 -p 12345 -m 38d644db0aeddedbf9e11a50dd56fb2d0c663f664d63ad62762490da41562108 -P sw-compnents.json -f image_reference_measurement.json ``` The JSON file following `-f` includes golden measurements of the CVM image, such as grub binary, grub configuration, kernels and corresponding initramfs images. This file is generated by the [cvm-image-rewriter](https://gitee.com/openeuler/virtCCA_sdk/tree/master/cvm-image-rewriter) tool. +``` +{ + "grub": "87276d2d4f3d17714e120d5b68694873880043e5abe7747fb4a47b5f6f38ca7a", + "grub.cfg": "1aaeda68126809b20f88f6ed6fac2ec720ddf4ae4ea99b2d2ba6fafc18d79971", + "kernels": [ + { + "version": "6.6.0-98.0.0.103.oe2403sp2.aarch64", + "kernel": "e14bd37fd6d957b48d3ddde9be14c6d977f74127a6c6e4846c6b2a9f4fe48b41", + "initramfs": "fc7269847648cdab5323a4213a6d7b9a47512851beae8106a81b3e507e6dfc79" + } + ], + "hash_alg": "sha-256" +} +``` + ## Workflow ### Interaction between Client & Server @@ -116,14 +203,90 @@ sequenceDiagram The detailed process for "Verify Device Certificate and Attestation Token" is shown as follows. Please refer to `verify_token` in client.c to see code details. +```mermaid +flowchart + A[Parse CCA Token] + A --> B[Verify CCA Token Signatures] + B -- Platfom+CVM --> C[Load & Parse SW-Component file] + C --> D[Verify Platform SW-Component Measurements] + B -- CVM-only --> E + D --> E[Check CVM Challenge and RIM] + E -- Direct Kernel Boot --> F[Pass Verification] + E -- Grub Boot --> G[Parse & Replay Event Log] + G --> H[Compare Token REMs with Replayed REMs] + H --> I[Extract & Verify Firmware States] + I --> F +``` + +### Parse CCA Token + +CCA Token Format is shown as follows. + +``` +CCA attestation token { // Tag:399 + CVM token { // 44241 + COSE_SIGN1 envelop { // 18 + Protected headers + Unprotected headers + CVM token claim map { // Payload + challege // 10 + rpv // 44235 + rem[4] // 44238 + cvm_hash_algo_id // 44239 + pub_key // 44237 + pub_key_hash_algo_id // 44240 + } + Signature(RAK) + } + } + CCA platform token { // 44234 + COSE_SIGN1 envelop { // 18 + Protected headers + Unprotected headers + Platform token claim map { // Payload + profile // 265 + challenge // 10 + inplementation_id // 2396 + instance_id // 256 + config // 2401 + lifecycle // 2395 + sw_components { //2399 + sw_component { + type + measurement + version + signer_id + hash_algo_id + } + } + verification_service //2400 + hash_algo_id //2402 + } + Signature(IAK) + } + } +} +``` + +1. CCA Token format use CBOR(Concise Binary Object Representation). +2. COSE_Sign1 envelop item use array type, contains 4 arrays; +3. In CVM Token claim, rem[4] item use array type, contain 4 data arrays; +4. In Platform Token claim, sw_components item use array type, contains variable arrays, depends on software component numbers. +5. Others item all use map type. + + + +### Verify CCA Token Signatures + +The detailed process for "Verify CCA Token Signatures" is shown as follows. + ```mermaid flowchart TD - A[Verify Certificate Chain] - A --> B[Verify Token Signature] - B --> C[Check Challenge and RIM] - C -- Direct Kernel Boot --> D[Pass Verification] - C -- Grub Boot --> E[Parse & Replay Event Log] - E --> F[Compare Token REMs with Replayed REMs] - F --> G[Extract & Verify Firmware States] - G --> D + A[Verify CVM Token Signature] + A -- Platfom+CVM --> B[Verify Platform Token Signature] + A -- CVM-only --> C[Verify CVM Pubkey Match IAK] + B --> D[Verify CVM Pubkhash Match Platform Challenge] + D --> E[Verify IAK Pubkhash Match Platform Instance ID] + E --> F[Verify Certificate Chain: ROOT → SUB → IAK] + C --> F ``` diff --git a/attestation/samples/src/token_validate.c b/attestation/samples/src/token_validate.c index fa43bba..b4e37ca 100644 --- a/attestation/samples/src/token_validate.c +++ b/attestation/samples/src/token_validate.c @@ -955,16 +955,6 @@ bool verify_cca_token_signatures(cert_info_t *cert_info, goto free; } - if (plat_cose.ptr != NULL && plat_cose.len > 0) { - ret = verify_pubkhash_challenge(cvm_pub_key, plat_challenge, cvm_pub_key_algo); - printf("Verifying if cVM token RAK matches platform token challenge: %s \n", - ret ? "Success" : "Failed"); - if (ret == false) { - ret_bits &= ~(1 << index); - } - } - index += 1; - ret = verify_cvm_cose_sign(cvm_cose, cvm_pub_key); printf("Verifying if cVM token signature is signed by RAK: %s \n", ret ? "Success" : "Failed"); @@ -992,6 +982,16 @@ bool verify_cca_token_signatures(cert_info_t *cert_info, } index += 1; + if (plat_cose.ptr != NULL && plat_cose.len > 0) { + ret = verify_pubkhash_challenge(cvm_pub_key, plat_challenge, cvm_pub_key_algo); + printf("Verifying if cVM token RAK matches platform token challenge: %s \n", + ret ? "Success" : "Failed"); + if (ret == false) { + ret_bits &= ~(1 << index); + } + } + index += 1; + /* /* Verify Platform instance_id relationship with AIK /* Note: platform_instance_id = {0x01,hash(iak_pub_key)} @@ -1075,15 +1075,15 @@ bool verify_cca_token_signatures(cert_info_t *cert_info, bool critical_verifications_passed = true; if (!(ret_bits & (1 << 0))) { - printf("Critical: Challenge binding failed\n"); + printf("Critical: CVM token signature verification failed\n"); critical_verifications_passed = false; } - if (!(ret_bits & (1 << 1))) { - printf("Critical: CVM token signature verification failed\n"); + if (!(ret_bits & (1 << 2))) { + printf("Critical: Platform token signature verification failed\n"); critical_verifications_passed = false; } if (!(ret_bits & (1 << 3))) { - printf("Critical: Platform token signature verification failed\n"); + printf("Critical: Challenge binding failed\n"); critical_verifications_passed = false; } if (!(ret_bits & (1 << 4))) { -- Gitee From 7ed4d6771142c527812fb40f4b04a4edfe436c8e Mon Sep 17 00:00:00 2001 From: chenguanyuan Date: Wed, 13 Aug 2025 23:57:53 +0800 Subject: [PATCH 09/12] merge cpak/aik/iak to aik name --- attestation/samples/src/token_validate.c | 34 ++++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/attestation/samples/src/token_validate.c b/attestation/samples/src/token_validate.c index b4e37ca..a5fd015 100644 --- a/attestation/samples/src/token_validate.c +++ b/attestation/samples/src/token_validate.c @@ -691,7 +691,7 @@ static bool get_ecckey_from_x509(X509 *x509_cert, unsigned char **pubkey_bin, si return true; } -bool verify_iak_pubkey_hash(X509 *x509_cert, qbuf_t platform_pub_key_algo, qbuf_t platform_instance_id) +bool verify_aik_pubkey_hash(X509 *x509_cert, qbuf_t platform_pub_key_algo, qbuf_t platform_instance_id) { char algo[10]; uint8_t pubkey_hash[512]; @@ -702,7 +702,7 @@ bool verify_iak_pubkey_hash(X509 *x509_cert, qbuf_t platform_pub_key_algo, qbuf_ /* Get the ECC public key from the certificate, pubkey_bin for ECC is 0x04 || X || Y */ if (!get_ecckey_from_x509(x509_cert, &pubkey_bin, &pubkey_len)) { - printf("verify_iak_pubkey_hash: failed to get ECC key from certificate\n"); + printf("verify_aik_pubkey_hash: failed to get ECC key from certificate\n"); free(pubkey_bin); return false; } @@ -733,7 +733,7 @@ bool verify_iak_pubkey_hash(X509 *x509_cert, qbuf_t platform_pub_key_algo, qbuf_ } else if (strncmp("sha-512", platform_pub_key_algo.ptr, platform_pub_key_algo.len) == 0) { memcpy(algo, "sha512", sizeof("sha512")); } else { - printf("verify_iak_pubkey_hash: Unsupported sha algorithm."); + printf("verify_aik_pubkey_hash: Unsupported sha algorithm."); return false; } @@ -741,19 +741,19 @@ bool verify_iak_pubkey_hash(X509 *x509_cert, qbuf_t platform_pub_key_algo, qbuf_ memcpy(algo, "sha256", sizeof("sha256")); if (!digest_sha(final_pubkey_buffer, final_pubkey_buffer_size, algo, calculated_pubkey_hash, &pubkey_hash_len)) { - printf("verify_iak_pubkey_hash: Failed to calculate the hash value\n"); + printf("verify_aik_pubkey_hash: Failed to calculate the hash value\n"); return false; } - /* platform_instance_id = {0x01,hash(iak_pub_key)} */ + /* platform_instance_id = {0x01,hash(aik_pub_key)} */ if (platform_instance_id.len < 1 + pubkey_hash_len) { - printf("verify_iak_pubkey_hash: Invalid instance_id length"); + printf("verify_aik_pubkey_hash: Invalid instance_id length"); return false; } memcpy(pubkey_hash, platform_instance_id.ptr + 1, pubkey_hash_len); if (memcmp(pubkey_hash, calculated_pubkey_hash, pubkey_hash_len)) { - printf("verify_iak_pubkey_hash: unmatched pubkey hash value with platform instance id. \n"); + printf("verify_aik_pubkey_hash: unmatched pubkey hash value with platform instance id. \n"); return false; } @@ -931,7 +931,7 @@ bool verify_cvm_cose_sign(qbuf_t signed_cose, qbuf_t pub_key) /* /* Complete CCA token signature verification with platform token support -/* Enhanced to support ECC CPAK certificates and RAK keys +/* Enhanced to support ECC AIK certificates and RAK keys */ bool verify_cca_token_signatures(cert_info_t *cert_info, qbuf_t plat_cose, @@ -974,7 +974,7 @@ bool verify_cca_token_signatures(cert_info_t *cert_info, if (plat_cose.ptr != NULL && plat_cose.len > 0) { ret = verify_plat_cose_sign(plat_cose, x509_aik); - printf("Verifying if platform token signature is signed by IAK: %s \n", + printf("Verifying if platform token signature is signed by AIK: %s \n", ret ? "Success" : "Failed"); if (ret == false) { ret_bits &= ~(1 << index); @@ -994,11 +994,11 @@ bool verify_cca_token_signatures(cert_info_t *cert_info, /* /* Verify Platform instance_id relationship with AIK - /* Note: platform_instance_id = {0x01,hash(iak_pub_key)} + /* Note: platform_instance_id = {0x01,hash(aik_pub_key)} */ if (plat_cose.ptr != NULL && plat_cose.len > 0) { - ret = verify_iak_pubkey_hash(x509_aik, platform_pub_key_algo, platform_instance_id); - printf("Verifying if platform token instance_id matches with IAK Pubkey Hash: %s \n", + ret = verify_aik_pubkey_hash(x509_aik, platform_pub_key_algo, platform_instance_id); + printf("Verifying if platform token instance_id matches with AIK Pubkey Hash: %s \n", ret ? "Success" : "Failed"); if (ret == false) { ret_bits &= ~(1 << index); @@ -1007,7 +1007,7 @@ bool verify_cca_token_signatures(cert_info_t *cert_info, else { /* /* Verify cvm pubkey relationship with AIK - /* Note: In transitional scenarios where CPAK (ECC) signs platform token + /* Note: In transitional scenarios where AIK (ECC) signs platform token /* and RAK (also ECC) signs CVM token, these keys may be different. /* We allow this scenario but log it appropriately. */ @@ -1015,7 +1015,7 @@ bool verify_cca_token_signatures(cert_info_t *cert_info, printf("Verifying cvm pubkey relationship with aik pubkey: %s \n", ret ? "Success" : "Failed"); if (ret == false) { - printf("Note: This may be expected in CPAK/RAK mixed scenarios\n"); + printf("Note: This may be expected in AIK/RAK mixed scenarios\n"); /* /* In mixed scenarios, we don't fail the verification just because /* the keys don't match - the individual signature verifications @@ -1057,17 +1057,17 @@ bool verify_cca_token_signatures(cert_info_t *cert_info, index += 1; ret = validate_aik_cert_chain(x509_aik, x509_sub, x509_root); - printf("Verifying IAK certificate chain: %s \n", + printf("Verifying AIK certificate chain: %s \n", ret ? "Success" : "Failed"); if (ret == false) { ret_bits &= ~(1 << index); } /* - /* In mixed CPAK/RAK scenarios, we consider the verification successful + /* In mixed AIK/RAK scenarios, we consider the verification successful /* if the critical components pass: /* 1. CVM token signature verification (RAK signs CVM token) - /* 2. Platform token signature verification (CPAK signs platform token) + /* 2. Platform token signature verification (AIK signs platform token) /* 3. Challenge binding (RAK public key hash matches platform challenge) /* 4. Platform instance id binding (AIK public key hash matches platform instance id) /* 5. Certificate chain validation - THIS IS CRITICAL FOR SECURITY -- Gitee From 9e4809039e2b87b24e794a4dda32bda1b1f219b8 Mon Sep 17 00:00:00 2001 From: chenguanyuan Date: Wed, 13 Aug 2025 08:17:39 +0000 Subject: [PATCH 10/12] update attestation/samples/README.en.md. Signed-off-by: chenguanyuan --- attestation/samples/README.en.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/attestation/samples/README.en.md b/attestation/samples/README.en.md index a4a5b74..6de1ed1 100644 --- a/attestation/samples/README.en.md +++ b/attestation/samples/README.en.md @@ -233,7 +233,7 @@ CCA attestation token { // Tag:399 rpv // 44235 rem[4] // 44238 cvm_hash_algo_id // 44239 - pub_key // 44237 + pub_key // 44237 pub_key_hash_algo_id // 44240 } Signature(RAK) @@ -248,7 +248,7 @@ CCA attestation token { // Tag:399 challenge // 10 inplementation_id // 2396 instance_id // 256 - config // 2401 + config // 2401 lifecycle // 2395 sw_components { //2399 sw_component { -- Gitee From 7fc0edf758c6110ab3e5614efb82c0e074ea68dd Mon Sep 17 00:00:00 2001 From: chenguanyuan Date: Thu, 14 Aug 2025 18:40:07 +0800 Subject: [PATCH 11/12] fix openeuler-ci-bot check_code fail --- attestation/samples/src/token_validate.c | 38 +++++++++++++----------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/attestation/samples/src/token_validate.c b/attestation/samples/src/token_validate.c index a5fd015..f8856b6 100644 --- a/attestation/samples/src/token_validate.c +++ b/attestation/samples/src/token_validate.c @@ -296,7 +296,7 @@ init_signing_key(struct t_cose_key *key_pair, */ if (pub_key.len == 133 && ((unsigned char*)pub_key.ptr)[0] == 0x04) { printf("init_signing_key: load pubkey in raw ECC public key format\n"); - ret = ecc521_pubkey_raw2evp_pkey(pub_key,&pkey); + ret = ecc521_pubkey_raw2evp_pkey(pub_key, &pkey); if (!ret) { printf("Failed to transfer ECC public key to EVP_PKEY\n"); ret = T_COSE_ERR_FAIL; @@ -463,7 +463,9 @@ bool verify_pubkhash_challenge(qbuf_t pub_key, qbuf_t challenge, qbuf_t algorith return true; } -static void ecc521_cose_signature_convert_der2cose_if_needed(qbuf_t signed_cose,qbuf_t *final_signed_cose, EVP_PKEY *pkey) +static void ecc521_cose_signature_convert_der2cose_if_needed(qbuf_t signed_cose, + qbuf_t *final_signed_cose, + EVP_PKEY *pkey) { unsigned char *converted_cose_data = NULL; size_t converted_cose_len = 0; @@ -507,7 +509,7 @@ static void ecc521_cose_signature_convert_der2cose_if_needed(qbuf_t signed_cose, size_t remaining_len = signed_cose.len - prefix_len - signature_len; if (remaining_len > 0) { memcpy(converted_cose_data + prefix_len + cose_sig_len, - (unsigned char*)signature_data + signature_len, remaining_len); + (unsigned char*)signature_data + signature_len, remaining_len); } final_signed_cose->ptr = converted_cose_data; @@ -546,7 +548,7 @@ bool verify_plat_cose_sign(qbuf_t signed_cose, X509 *x509_aik) key_pair.crypto_lib = T_COSE_CRYPTO_LIB_OPENSSL; if (key_type == EVP_PKEY_EC) { - ecc521_cose_signature_convert_der2cose_if_needed(signed_cose,&final_signed_cose,pkey); + ecc521_cose_signature_convert_der2cose_if_needed(signed_cose, &final_signed_cose, pkey); } t_cose_sign1_verify_init(&verify_ctx, 0); @@ -589,7 +591,7 @@ static bool verify_cvm_pubkey(qbuf_t pub_key, X509 *x509_aik) */ if (pub_key.len == 133 && ((unsigned char*)pub_key.ptr)[0] == 0x04) { printf("verify_cvm_pubkey: load pubkey in raw ECC public key format\n"); - ret = ecc521_pubkey_raw2evp_pkey(pub_key,&cvm_pkey); + ret = ecc521_pubkey_raw2evp_pkey(pub_key, &cvm_pkey); if (!ret) { printf("Failed to transfer ECC public key to EVP_PKEY\n"); goto done; @@ -661,9 +663,9 @@ static bool get_ecckey_from_x509(X509 *x509_cert, unsigned char **pubkey_bin, si const EC_GROUP *group = EC_KEY_get0_group(ec_key); // 获取公钥的压缩或非压缩格式 - *pubkey_len = EC_POINT_point2oct(group, point, - EC_KEY_get_conv_form(ec_key), - NULL, 0, NULL); + *pubkey_len = EC_POINT_point2oct(group, point, + EC_KEY_get_conv_form(ec_key), + NULL, 0, NULL); if (*pubkey_len == 0) { EC_KEY_free(ec_key); EVP_PKEY_free(pkey); @@ -677,9 +679,9 @@ static bool get_ecckey_from_x509(X509 *x509_cert, unsigned char **pubkey_bin, si return false; } - if (EC_POINT_point2oct(group, point, - EC_KEY_get_conv_form(ec_key), - *pubkey_bin, *pubkey_len, NULL) == 0) { + if (EC_POINT_point2oct(group, point, + EC_KEY_get_conv_form(ec_key), + *pubkey_bin, *pubkey_len, NULL) == 0) { EC_KEY_free(ec_key); EVP_PKEY_free(pkey); return false; @@ -707,17 +709,17 @@ bool verify_aik_pubkey_hash(X509 *x509_cert, qbuf_t platform_pub_key_algo, qbuf_ return false; } - /* todo: - cert ECC key format is 0x04 || X || Y + /* todo: + cert ECC key format is 0x04 || X || Y HSM generate instance id hash used 8byte aliand X||Y:(6byte 0x00 + 66byte ECC(X)) +(6byte 0x00 + 66byte ECC(Y) - need convert cert ECC key to HSM generate instance id hash format*/ + need convert cert ECC key to HSM generate instance id hash format */ int pubkey_buffer_size = pubkey_len - 1; - unsigned char *pubkey_buffer = pubkey_bin + 1; + unsigned char *pubkey_buffer = pubkey_bin + 1; - int ecc_x_len = pubkey_buffer_size/2; + int ecc_x_len = pubkey_buffer_size / 2; int final_ecc_x_len = (ecc_x_len + 7) & ~7; int final_ecc_x_pad_len = final_ecc_x_len - ecc_x_len; - int final_pubkey_buffer_size = final_ecc_x_len * 2; + int final_pubkey_buffer_size = final_ecc_x_len * 2; unsigned char *final_pubkey_buffer = (unsigned char *)malloc(final_pubkey_buffer_size); (void)memset(final_pubkey_buffer, 0, final_ecc_x_pad_len); @@ -737,7 +739,7 @@ bool verify_aik_pubkey_hash(X509 *x509_cert, qbuf_t platform_pub_key_algo, qbuf_ return false; } - //todo, hsm use sha256 only now + // todo, hsm use sha256 only now memcpy(algo, "sha256", sizeof("sha256")); if (!digest_sha(final_pubkey_buffer, final_pubkey_buffer_size, algo, calculated_pubkey_hash, &pubkey_hash_len)) { -- Gitee From be2057c24c3b91c55f477b849d9990078a2f8e27 Mon Sep 17 00:00:00 2001 From: chenguanyuan Date: Thu, 14 Aug 2025 19:04:13 +0800 Subject: [PATCH 12/12] fix openeuler-ci-bot check_code fail --- attestation/samples/src/token_validate.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/attestation/samples/src/token_validate.c b/attestation/samples/src/token_validate.c index f8856b6..bc0d2c4 100644 --- a/attestation/samples/src/token_validate.c +++ b/attestation/samples/src/token_validate.c @@ -1005,8 +1005,7 @@ bool verify_cca_token_signatures(cert_info_t *cert_info, if (ret == false) { ret_bits &= ~(1 << index); } - } - else { + } else { /* /* Verify cvm pubkey relationship with AIK /* Note: In transitional scenarios where AIK (ECC) signs platform token -- Gitee