/* * Copyright (C) 2011-2017 Intel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Intel Corporation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "service_provider.h" #include "sample_libcrypto.h" #include "ecp.h" #include #include #include #include #include #include "ias_ra.h" #ifndef SAFE_FREE #define SAFE_FREE(ptr) {if (NULL != (ptr)) {free(ptr); (ptr) = NULL;}} #endif // This is supported extended epid group of SP. SP can support more than one // extended epid group with different extended epid group id and credentials. static const sample_extended_epid_group g_extended_epid_groups[] = { { 0, ias_enroll, ias_get_sigrl, ias_verify_attestation_evidence } }; // This is the private EC key of SP, the corresponding public EC key is // hard coded in isv_enclave. It is based on NIST P-256 curve. static const sample_ec256_private_t g_sp_priv_key = { { 0x90, 0xe7, 0x6c, 0xbb, 0x2d, 0x52, 0xa1, 0xce, 0x3b, 0x66, 0xde, 0x11, 0x43, 0x9c, 0x87, 0xec, 0x1f, 0x86, 0x6a, 0x3b, 0x65, 0xb6, 0xae, 0xea, 0xad, 0x57, 0x34, 0x53, 0xd1, 0x03, 0x8c, 0x01 } }; // This is the public EC key of SP, this key is hard coded in isv_enclave. // It is based on NIST P-256 curve. Not used in the SP code. static const sample_ec_pub_t g_sp_pub_key = { { 0x72, 0x12, 0x8a, 0x7a, 0x17, 0x52, 0x6e, 0xbf, 0x85, 0xd0, 0x3a, 0x62, 0x37, 0x30, 0xae, 0xad, 0x3e, 0x3d, 0xaa, 0xee, 0x9c, 0x60, 0x73, 0x1d, 0xb0, 0x5b, 0xe8, 0x62, 0x1c, 0x4b, 0xeb, 0x38 }, { 0xd4, 0x81, 0x40, 0xd9, 0x50, 0xe2, 0x57, 0x7b, 0x26, 0xee, 0xb7, 0x41, 0xe7, 0xc6, 0x14, 0xe2, 0x24, 0xb7, 0xbd, 0xc9, 0x03, 0xf2, 0x9a, 0x28, 0xa8, 0x3c, 0xc8, 0x10, 0x11, 0x14, 0x5e, 0x06 } }; // This is a context data structure used on SP side typedef struct _sp_db_item_t { sample_ec_pub_t g_a; sample_ec_pub_t g_b; sample_ec_key_128bit_t vk_key;// Shared secret key for the REPORT_DATA sample_ec_key_128bit_t mk_key;// Shared secret key for generating MAC's sample_ec_key_128bit_t sk_key;// Shared secret key for encryption sample_ec_key_128bit_t smk_key;// Used only for SIGMA protocol sample_ec_priv_t b; sample_ps_sec_prop_desc_t ps_sec_prop; }sp_db_item_t; static sp_db_item_t g_sp_db; static const sample_extended_epid_group* g_sp_extended_epid_group_id= NULL; static bool g_is_sp_registered = false; static int g_sp_credentials = 0; static int g_authentication_token = 0; uint8_t g_secret[8] = {0,1,2,3,4,5,6,7}; sample_spid_t g_spid; // Verify message 0 then configure extended epid group. int sp_ra_proc_msg0_req(const sample_ra_msg0_t *p_msg0, uint32_t msg0_size) { int ret = -1; if (!p_msg0 || (msg0_size != sizeof(sample_ra_msg0_t))) { return -1; } uint32_t extended_epid_group_id = p_msg0->extended_epid_group_id; // Check to see if we have registered with the attestation server yet? if (!g_is_sp_registered || (g_sp_extended_epid_group_id != NULL && g_sp_extended_epid_group_id->extended_epid_group_id != extended_epid_group_id)) { // Check to see if the extended_epid_group_id is supported? ret = SP_UNSUPPORTED_EXTENDED_EPID_GROUP; for (size_t i = 0; i < sizeof(g_extended_epid_groups) / sizeof(sample_extended_epid_group); i++) { if (g_extended_epid_groups[i].extended_epid_group_id == extended_epid_group_id) { g_sp_extended_epid_group_id = &(g_extended_epid_groups[i]); // In the product, the SP will establish a mutually // authenticated SSL channel. During the enrollment process, the ISV // registers it exchanges TLS certs with attestation server and obtains an SPID and // Report Key from the attestation server. // For a product attestation server, enrollment is an offline process. See the 'on-boarding' // documentation to get the information required. The enrollment process is // simulated by a call in this sample. ret = g_sp_extended_epid_group_id->enroll(g_sp_credentials, &g_spid, &g_authentication_token); if (0 != ret) { ret = SP_IAS_FAILED; break; } g_is_sp_registered = true; ret = SP_OK; break; } } } else { ret = SP_OK; } return ret; } // Verify message 1 then generate and return message 2 to isv. int sp_ra_proc_msg1_req(const sample_ra_msg1_t *p_msg1, uint32_t msg1_size, ra_samp_response_header_t **pp_msg2) { int ret = 0; ra_samp_response_header_t* p_msg2_full = NULL; sample_ra_msg2_t *p_msg2 = NULL; sample_ecc_state_handle_t ecc_state = NULL; sample_status_t sample_ret = SAMPLE_SUCCESS; bool derive_ret = false; if(!p_msg1 || !pp_msg2 || (msg1_size != sizeof(sample_ra_msg1_t))) { return -1; } // Check to see if we have registered? if (!g_is_sp_registered) { return SP_UNSUPPORTED_EXTENDED_EPID_GROUP; } do { // Get the sig_rl from attestation server using GID. // GID is Base-16 encoded of EPID GID in little-endian format. // In the product, the SP and attesation server uses an established channel for // communication. uint8_t* sig_rl; uint32_t sig_rl_size = 0; // The product interface uses a REST based message to get the SigRL. ret = g_sp_extended_epid_group_id->get_sigrl(p_msg1->gid, &sig_rl_size, &sig_rl); if(0 != ret) { fprintf(stderr, "\nError, ias_get_sigrl [%s].", __FUNCTION__); ret = SP_IAS_FAILED; break; } // Need to save the client's public ECCDH key to local storage if (memcpy_s(&g_sp_db.g_a, sizeof(g_sp_db.g_a), &p_msg1->g_a, sizeof(p_msg1->g_a))) { fprintf(stderr, "\nError, cannot do memcpy in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } // Generate the Service providers ECCDH key pair. sample_ret = sample_ecc256_open_context(&ecc_state); if(SAMPLE_SUCCESS != sample_ret) { fprintf(stderr, "\nError, cannot get ECC context in [%s].", __FUNCTION__); ret = -1; break; } sample_ec256_public_t pub_key = {{0},{0}}; sample_ec256_private_t priv_key = {{0}}; sample_ret = sample_ecc256_create_key_pair(&priv_key, &pub_key, ecc_state); if(SAMPLE_SUCCESS != sample_ret) { fprintf(stderr, "\nError, cannot generate key pair in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } // Need to save the SP ECCDH key pair to local storage. if(memcpy_s(&g_sp_db.b, sizeof(g_sp_db.b), &priv_key,sizeof(priv_key)) || memcpy_s(&g_sp_db.g_b, sizeof(g_sp_db.g_b), &pub_key,sizeof(pub_key))) { fprintf(stderr, "\nError, cannot do memcpy in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } // Generate the client/SP shared secret sample_ec_dh_shared_t dh_key = {{0}}; sample_ret = sample_ecc256_compute_shared_dhkey(&priv_key, (sample_ec256_public_t *)&p_msg1->g_a, (sample_ec256_dh_shared_t *)&dh_key, ecc_state); if(SAMPLE_SUCCESS != sample_ret) { fprintf(stderr, "\nError, compute share key fail in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } #ifdef SUPPLIED_KEY_DERIVATION // smk is only needed for msg2 generation. derive_ret = derive_key(&dh_key, SAMPLE_DERIVE_KEY_SMK_SK, &g_sp_db.smk_key, &g_sp_db.sk_key); if(derive_ret != true) { fprintf(stderr, "\nError, derive key fail in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } // The rest of the keys are the shared secrets for future communication. derive_ret = derive_key(&dh_key, SAMPLE_DERIVE_KEY_MK_VK, &g_sp_db.mk_key, &g_sp_db.vk_key); if(derive_ret != true) { fprintf(stderr, "\nError, derive key fail in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } #else // smk is only needed for msg2 generation. derive_ret = derive_key(&dh_key, SAMPLE_DERIVE_KEY_SMK, &g_sp_db.smk_key); if(derive_ret != true) { fprintf(stderr, "\nError, derive key fail in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } // The rest of the keys are the shared secrets for future communication. derive_ret = derive_key(&dh_key, SAMPLE_DERIVE_KEY_MK, &g_sp_db.mk_key); if(derive_ret != true) { fprintf(stderr, "\nError, derive key fail in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } derive_ret = derive_key(&dh_key, SAMPLE_DERIVE_KEY_SK, &g_sp_db.sk_key); if(derive_ret != true) { fprintf(stderr, "\nError, derive key fail in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } derive_ret = derive_key(&dh_key, SAMPLE_DERIVE_KEY_VK, &g_sp_db.vk_key); if(derive_ret != true) { fprintf(stderr, "\nError, derive key fail in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } #endif uint32_t msg2_size = sizeof(sample_ra_msg2_t) + sig_rl_size; p_msg2_full = (ra_samp_response_header_t*)malloc(msg2_size + sizeof(ra_samp_response_header_t)); if(!p_msg2_full) { fprintf(stderr, "\nError, out of memory in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } memset(p_msg2_full, 0, msg2_size + sizeof(ra_samp_response_header_t)); p_msg2_full->type = TYPE_RA_MSG2; p_msg2_full->size = msg2_size; // The simulated message2 always passes. This would need to be set // accordingly in a real service provider implementation. p_msg2_full->status[0] = 0; p_msg2_full->status[1] = 0; p_msg2 = (sample_ra_msg2_t *)p_msg2_full->body; // Assemble MSG2 if(memcpy_s(&p_msg2->g_b, sizeof(p_msg2->g_b), &g_sp_db.g_b, sizeof(g_sp_db.g_b)) || memcpy_s(&p_msg2->spid, sizeof(sample_spid_t), &g_spid, sizeof(g_spid))) { fprintf(stderr,"\nError, memcpy failed in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } // The service provider is responsible for selecting the proper EPID // signature type and to understand the implications of the choice! p_msg2->quote_type = SAMPLE_QUOTE_LINKABLE_SIGNATURE; #ifdef SUPPLIED_KEY_DERIVATION //isv defined key derivation function id #define ISV_KDF_ID 2 p_msg2->kdf_id = ISV_KDF_ID; #else p_msg2->kdf_id = SAMPLE_AES_CMAC_KDF_ID; #endif // Create gb_ga sample_ec_pub_t gb_ga[2]; if(memcpy_s(&gb_ga[0], sizeof(gb_ga[0]), &g_sp_db.g_b, sizeof(g_sp_db.g_b)) || memcpy_s(&gb_ga[1], sizeof(gb_ga[1]), &g_sp_db.g_a, sizeof(g_sp_db.g_a))) { fprintf(stderr,"\nError, memcpy failed in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } // Sign gb_ga sample_ret = sample_ecdsa_sign((uint8_t *)&gb_ga, sizeof(gb_ga), (sample_ec256_private_t *)&g_sp_priv_key, (sample_ec256_signature_t *)&p_msg2->sign_gb_ga, ecc_state); if(SAMPLE_SUCCESS != sample_ret) { fprintf(stderr, "\nError, sign ga_gb fail in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } // Generate the CMACsmk for gb||SPID||TYPE||KDF_ID||Sigsp(gb,ga) uint8_t mac[SAMPLE_EC_MAC_SIZE] = {0}; uint32_t cmac_size = offsetof(sample_ra_msg2_t, mac); sample_ret = sample_rijndael128_cmac_msg(&g_sp_db.smk_key, (uint8_t *)&p_msg2->g_b, cmac_size, &mac); if(SAMPLE_SUCCESS != sample_ret) { fprintf(stderr, "\nError, cmac fail in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } if(memcpy_s(&p_msg2->mac, sizeof(p_msg2->mac), mac, sizeof(mac))) { fprintf(stderr,"\nError, memcpy failed in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } if(memcpy_s(&p_msg2->sig_rl[0], sig_rl_size, sig_rl, sig_rl_size)) { fprintf(stderr,"\nError, memcpy failed in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } p_msg2->sig_rl_size = sig_rl_size; }while(0); if(ret) { *pp_msg2 = NULL; SAFE_FREE(p_msg2_full); } else { // Freed by the network simulator in ra_free_network_response_buffer *pp_msg2 = p_msg2_full; } if(ecc_state) { sample_ecc256_close_context(ecc_state); } return ret; } // Process remote attestation message 3 int sp_ra_proc_msg3_req(const sample_ra_msg3_t *p_msg3, uint32_t msg3_size, ra_samp_response_header_t **pp_att_result_msg) { int ret = 0; sample_status_t sample_ret = SAMPLE_SUCCESS; const uint8_t *p_msg3_cmaced = NULL; sample_quote_t *p_quote = NULL; sample_sha_state_handle_t sha_handle = NULL; sample_report_data_t report_data = {0}; sample_ra_att_result_msg_t *p_att_result_msg = NULL; ra_samp_response_header_t* p_att_result_msg_full = NULL; uint32_t i; if((!p_msg3) || (msg3_size < sizeof(sample_ra_msg3_t)) || (!pp_att_result_msg)) { return SP_INTERNAL_ERROR; } // Check to see if we have registered? if (!g_is_sp_registered) { return SP_UNSUPPORTED_EXTENDED_EPID_GROUP; } do { // Compare g_a in message 3 with local g_a. ret = memcmp(&g_sp_db.g_a, &p_msg3->g_a, sizeof(sample_ec_pub_t)); if(ret) { fprintf(stderr, "\nError, g_a is not same [%s].", __FUNCTION__); ret = SP_PROTOCOL_ERROR; break; } //Make sure that msg3_size is bigger than sample_mac_t. uint32_t mac_size = msg3_size - sizeof(sample_mac_t); p_msg3_cmaced = reinterpret_cast(p_msg3); p_msg3_cmaced += sizeof(sample_mac_t); // Verify the message mac using SMK sample_cmac_128bit_tag_t mac = {0}; sample_ret = sample_rijndael128_cmac_msg(&g_sp_db.smk_key, p_msg3_cmaced, mac_size, &mac); if(SAMPLE_SUCCESS != sample_ret) { fprintf(stderr, "\nError, cmac fail in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } // In real implementation, should use a time safe version of memcmp here, // in order to avoid side channel attack. ret = memcmp(&p_msg3->mac, mac, sizeof(mac)); if(ret) { fprintf(stderr, "\nError, verify cmac fail [%s].", __FUNCTION__); ret = SP_INTEGRITY_FAILED; break; } if(memcpy_s(&g_sp_db.ps_sec_prop, sizeof(g_sp_db.ps_sec_prop), &p_msg3->ps_sec_prop, sizeof(p_msg3->ps_sec_prop))) { fprintf(stderr,"\nError, memcpy failed in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } p_quote = (sample_quote_t *)p_msg3->quote; // Check the quote version if needed. Only check the Quote.version field if the enclave // identity fields have changed or the size of the quote has changed. The version may // change without affecting the legacy fields or size of the quote structure. //if(p_quote->version < ACCEPTED_QUOTE_VERSION) //{ // fprintf(stderr,"\nError, quote version is too old.", __FUNCTION__); // ret = SP_QUOTE_VERSION_ERROR; // break; //} // Verify the report_data in the Quote matches the expected value. // The first 32 bytes of report_data are SHA256 HASH of {ga|gb|vk}. // The second 32 bytes of report_data are set to zero. sample_ret = sample_sha256_init(&sha_handle); if(sample_ret != SAMPLE_SUCCESS) { fprintf(stderr,"\nError, init hash failed in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } sample_ret = sample_sha256_update((uint8_t *)&(g_sp_db.g_a), sizeof(g_sp_db.g_a), sha_handle); if(sample_ret != SAMPLE_SUCCESS) { fprintf(stderr,"\nError, udpate hash failed in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } sample_ret = sample_sha256_update((uint8_t *)&(g_sp_db.g_b), sizeof(g_sp_db.g_b), sha_handle); if(sample_ret != SAMPLE_SUCCESS) { fprintf(stderr,"\nError, udpate hash failed in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } sample_ret = sample_sha256_update((uint8_t *)&(g_sp_db.vk_key), sizeof(g_sp_db.vk_key), sha_handle); if(sample_ret != SAMPLE_SUCCESS) { fprintf(stderr,"\nError, udpate hash failed in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } sample_ret = sample_sha256_get_hash(sha_handle, (sample_sha256_hash_t *)&report_data); if(sample_ret != SAMPLE_SUCCESS) { fprintf(stderr,"\nError, Get hash failed in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } ret = memcmp((uint8_t *)&report_data, (uint8_t *)&(p_quote->report_body.report_data), sizeof(report_data)); if(ret) { fprintf(stderr, "\nError, verify hash fail [%s].", __FUNCTION__); ret = SP_INTEGRITY_FAILED; break; } // Verify Enclave policy (an attestation server may provide an API for this if we // registered an Enclave policy) // Verify quote with attestation server. // In the product, an attestation server could use a REST message and JSON formatting to request // attestation Quote verification. The sample only simulates this interface. ias_att_report_t attestation_report = {0}; ret = g_sp_extended_epid_group_id->verify_attestation_evidence(p_quote, NULL, &attestation_report); if(0 != ret) { ret = SP_IAS_FAILED; break; } FILE* OUTPUT = stdout; fprintf(OUTPUT, "\n\n\tAtestation Report:"); fprintf(OUTPUT, "\n\tid: 0x%0x.", attestation_report.id); fprintf(OUTPUT, "\n\tstatus: %d.", attestation_report.status); fprintf(OUTPUT, "\n\trevocation_reason: %u.", attestation_report.revocation_reason); // attestation_report.info_blob; fprintf(OUTPUT, "\n\tpse_status: %d.", attestation_report.pse_status); // Note: This sample always assumes the PIB is sent by attestation server. In the product // implementation, the attestation server could only send the PIB for certain attestation // report statuses. A product SP implementation needs to handle cases // where the PIB is zero length. // Respond the client with the results of the attestation. uint32_t att_result_msg_size = sizeof(sample_ra_att_result_msg_t); p_att_result_msg_full = (ra_samp_response_header_t*)malloc(att_result_msg_size + sizeof(ra_samp_response_header_t) + sizeof(g_secret)); if(!p_att_result_msg_full) { fprintf(stderr, "\nError, out of memory in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } memset(p_att_result_msg_full, 0, att_result_msg_size + sizeof(ra_samp_response_header_t) + sizeof(g_secret)); p_att_result_msg_full->type = TYPE_RA_ATT_RESULT; p_att_result_msg_full->size = att_result_msg_size; if(IAS_QUOTE_OK != attestation_report.status) { p_att_result_msg_full->status[0] = 0xFF; } if(IAS_PSE_OK != attestation_report.pse_status) { p_att_result_msg_full->status[1] = 0xFF; } p_att_result_msg = (sample_ra_att_result_msg_t *)p_att_result_msg_full->body; // In a product implementation of attestation server, the HTTP response header itself could have // an RK based signature that the service provider needs to check here. // The platform_info_blob signature will be verified by the client // when sent. No need to have the Service Provider to check it. The SP // should pass it down to the application for further analysis. fprintf(OUTPUT, "\n\n\tEnclave Report:"); fprintf(OUTPUT, "\n\tSignature Type: 0x%x", p_quote->sign_type); fprintf(OUTPUT, "\n\tSignature Basename: "); for(i=0; ibasename.name) && p_quote->basename.name[i]; i++) { fprintf(OUTPUT, "%c", p_quote->basename.name[i]); } #ifdef __x86_64__ fprintf(OUTPUT, "\n\tattributes.flags: 0x%0lx", p_quote->report_body.attributes.flags); fprintf(OUTPUT, "\n\tattributes.xfrm: 0x%0lx", p_quote->report_body.attributes.xfrm); #else fprintf(OUTPUT, "\n\tattributes.flags: 0x%0llx", p_quote->report_body.attributes.flags); fprintf(OUTPUT, "\n\tattributes.xfrm: 0x%0llx", p_quote->report_body.attributes.xfrm); #endif fprintf(OUTPUT, "\n\tmr_enclave: "); for(i=0;ireport_body.mr_enclave[i]); //fprintf(stderr, "%02x",p_quote->report_body.mr_enclave.m[i]); } fprintf(OUTPUT, "\n\tmr_signer: "); for(i=0;ireport_body.mr_signer[i]); //fprintf(stderr, "%02x",p_quote->report_body.mr_signer.m[i]); } fprintf(OUTPUT, "\n\tisv_prod_id: 0x%0x", p_quote->report_body.isv_prod_id); fprintf(OUTPUT, "\n\tisv_svn: 0x%0x",p_quote->report_body.isv_svn); fprintf(OUTPUT, "\n"); // A product service provider needs to verify that its enclave properties // match what is expected. The SP needs to check these values before // trusting the enclave. For the sample, we always pass the policy check. // Attestation server only verifies the quote structure and signature. It does not // check the identity of the enclave. bool isv_policy_passed = true; // Assemble Attestation Result Message // Note, this is a structure copy. We don't copy the policy reports // right now. p_att_result_msg->platform_info_blob = attestation_report.info_blob; // Generate mac based on the mk key. mac_size = sizeof(ias_platform_info_blob_t); sample_ret = sample_rijndael128_cmac_msg(&g_sp_db.mk_key, (const uint8_t*)&p_att_result_msg->platform_info_blob, mac_size, &p_att_result_msg->mac); if(SAMPLE_SUCCESS != sample_ret) { fprintf(stderr, "\nError, cmac fail in [%s].", __FUNCTION__); ret = SP_INTERNAL_ERROR; break; } // Generate shared secret and encrypt it with SK, if attestation passed. uint8_t aes_gcm_iv[SAMPLE_SP_IV_SIZE] = {0}; p_att_result_msg->secret.payload_size = 8; if((IAS_QUOTE_OK == attestation_report.status) && (IAS_PSE_OK == attestation_report.pse_status) && (isv_policy_passed == true)) { ret = sample_rijndael128GCM_encrypt(&g_sp_db.sk_key, &g_secret[0], p_att_result_msg->secret.payload_size, p_att_result_msg->secret.payload, &aes_gcm_iv[0], SAMPLE_SP_IV_SIZE, NULL, 0, &p_att_result_msg->secret.payload_tag); } }while(0); if(ret) { *pp_att_result_msg = NULL; SAFE_FREE(p_att_result_msg_full); } else { // Freed by the network simulator in ra_free_network_response_buffer *pp_att_result_msg = p_att_result_msg_full; } return ret; }