Files
lzha101 26c458905b Update copyright. (#708)
Signed-off-by: Zhang Lili <lili.z.zhang@intel.com>
2021-05-18 10:52:48 +08:00

868 lines
32 KiB
C++

/*
* Copyright (C) 2011-2021 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 <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <time.h>
#include <string.h>
#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
}
};
const uint8_t g_ecdsa_p256_att_key_id_list[] = {
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x8c, 0x4f,
0x57, 0x75, 0xd7, 0x96, 0x50, 0x3e, 0x96, 0x13,
0x7f, 0x77, 0xc6, 0x8a, 0x82, 0x9a, 0x00, 0x56,
0xac, 0x8d, 0xed, 0x70, 0x14, 0x0b, 0x08, 0x1b,
0x09, 0x44, 0x90, 0xc5, 0x7b, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
const uint8_t g_epid_unlinkable_att_key_id_list[] = {
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0xec, 0x15,
0xb1, 0x07, 0x87, 0xd2, 0xf8, 0x46, 0x67, 0xce,
0xb0, 0xb5, 0x98, 0xff, 0xc4, 0x4a, 0x1f, 0x1c,
0xb8, 0x0f, 0x67, 0x0a, 0xae, 0x5d, 0xf9, 0xe8,
0xfa, 0x9f, 0x63, 0x76, 0xe1, 0xf8, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
// 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 bool g_return_ecdsa_att_key_id = true;
static int g_sp_credentials = 0;
static int g_authentication_token = 0;
uint8_t g_secret[] = {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,
ra_samp_response_header_t **pp_msg0_resp)
{
int ret = -1;
uint32_t msg0_resp_size = 0;
ra_samp_response_header_t* p_msg0_resp_full = NULL;
if (!p_msg0 ||
!pp_msg0_resp ||
(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;
goto CLEANUP;
}
g_is_sp_registered = true;
break;
}
}
}
// Return ECDSA attestation key id first
if (g_return_ecdsa_att_key_id)
{
msg0_resp_size = (uint32_t)sizeof(g_ecdsa_p256_att_key_id_list);
// Next time we will return EPID attestation key id
}
else // Return EPID attestation key id
{
msg0_resp_size = (uint32_t)sizeof(g_epid_unlinkable_att_key_id_list);
}
p_msg0_resp_full = (ra_samp_response_header_t*)malloc(msg0_resp_size
+ sizeof(ra_samp_response_header_t));
if(!p_msg0_resp_full)
{
fprintf(stderr, "\nError, out of memory in [%s].", __FUNCTION__);
ret = SP_INTERNAL_ERROR;
}
else
{
memset(p_msg0_resp_full, 0, msg0_resp_size + sizeof(ra_samp_response_header_t));
if (g_return_ecdsa_att_key_id)
{
memcpy_s(p_msg0_resp_full->body, msg0_resp_size,
g_ecdsa_p256_att_key_id_list, msg0_resp_size);
g_return_ecdsa_att_key_id = false;
}
else // Return EPID attestation key id
{
memcpy_s(p_msg0_resp_full->body, msg0_resp_size,
g_epid_unlinkable_att_key_id_list, msg0_resp_size);
}
p_msg0_resp_full->type = TYPE_RA_MSG0;
p_msg0_resp_full->size = msg0_resp_size;
// The simulated message0 always passes. This would need to be set
// accordingly in a real service provider implementation.
p_msg0_resp_full->status[0] = 0;
p_msg0_resp_full->status[1] = 0;
ret = SP_OK;
}
CLEANUP:
if(ret)
{
*pp_msg0_resp = NULL;
SAFE_FREE(p_msg0_resp_full);
}
else
{
// Freed by the network simulator in ra_free_network_response_buffer
*pp_msg0_resp = p_msg0_resp_full;
}
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 attestation 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.
//! Refer to the attestation server API for more information on how to communicate to
//! the real attestation server.
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 ECDH 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 ECDH 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 ECDH 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 = (uint32_t)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;
const 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 - (uint32_t)sizeof(sample_mac_t);
p_msg3_cmaced = reinterpret_cast<const uint8_t*>(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 = (const 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,
&(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.
//! Please refer to the attestation server API for more details on this interface.
ias_att_report_t attestation_report;
memset(&attestation_report, 0, sizeof(attestation_report));
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\tAttestation 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; i<sizeof(p_quote->basename.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;i<sizeof(sample_measurement_t);i++)
{
fprintf(OUTPUT, "%02x",p_quote->report_body.mr_enclave[i]);
//fprintf(stderr, "%02x",p_quote->report_body.mr_enclave.m[i]);
}
fprintf(OUTPUT, "\n\tmr_signer: ");
for(i=0;i<sizeof(sample_measurement_t);i++)
{
fprintf(OUTPUT, "%02x",p_quote->report_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 = sizeof(g_secret);
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;
}