diff --git a/attestation/samples/README.en.md b/attestation/samples/README.en.md index 930bee1dcb32328c2c5a99704da62f4bfbff19d9..6de1ed1242ca6c9abfb8c97eeb881e1a89491be3 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,15 +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: @@ -65,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: @@ -77,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 @@ -115,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/build.sh b/attestation/samples/build.sh old mode 100644 new mode 100755 diff --git a/attestation/samples/include/token_validate.h b/attestation/samples/include/token_validate.h index 955558ca58c9ed86d951d678a61449be98d64108..de5d91df809c2ae190f313edb53c5c2e7c0afb19 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 9e43ea924c8a388cc5f599779b240e0e7b433f74..d45df037bcb39daf3287df8ebe26be4032161d96 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) */ @@ -178,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; } @@ -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) { @@ -723,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"); @@ -743,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 fd35c6d64c9957252e42e54f3cd586daecf07512..3c37a82ad363195eb1d223aeac3d71f09bc0b948 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 306acb098792df0cde8439062ec0e3e7c87c65ee..f8856b6efe3b6eca5a81dfb7def5d60786a7b198 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); - 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); + 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; } - - 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,66 @@ 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 +534,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 +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) { - 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 +556,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); @@ -553,7 +570,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; @@ -569,55 +585,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"); - 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); + 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_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; @@ -660,6 +638,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_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]; + 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_aik_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_aik_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_aik_pubkey_hash: Failed to calculate the hash value\n"); + return false; + } + + /* platform_instance_id = {0x01,hash(aik_pub_key)} */ + if (platform_instance_id.len < 1 + pubkey_hash_len) { + 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_aik_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) @@ -788,7 +892,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; @@ -803,58 +906,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); @@ -865,8 +917,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); @@ -880,14 +933,16 @@ 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, 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(); @@ -902,16 +957,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"); @@ -931,31 +976,55 @@ 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); } - index += 1; } + 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 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(aik_pub_key)} */ - 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"); + if (plat_cose.ptr != NULL && plat_cose.len > 0) { + 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); + } + } + else { /* - /* In mixed scenarios, we don't fail the verification just because - /* the keys don't match - the individual signature verifications - /* are more important + /* Verify cvm pubkey relationship with AIK + /* 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. */ - printf("Allowing verification to proceed despite key mismatch\n"); + 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 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 + /* are more important + */ + printf("Allowing verification to proceed despite key mismatch\n"); + } } index += 1; @@ -990,37 +1059,39 @@ 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. 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 << 1))) { + if (!(ret_bits & (1 << 0))) { printf("Critical: CVM token signature verification failed\n"); critical_verifications_passed = false; } + if (!(ret_bits & (1 << 2))) { + printf("Critical: Platform token signature verification failed\n"); + critical_verifications_passed = false; + } + if (!(ret_bits & (1 << 3))) { + printf("Critical: Challenge binding 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 */