Files
intel-linux-sgx/SampleCode/RemoteAttestation/isv_app/isv_app.cpp
T
Li, Xun c505e6129a Linux 2.6 Open Source Gold Release
Added support for Reproducible Enclave Build using Docker file.
Added support for Intel AVX-512 instructions and Intel SHA Extensions New Instructions (SHA-NI) in trusted libraries.
Support both EPID and ECDSA based quote for quoting related interfaces in sgx_uae_service library.
Updated key exchange library to support both EPID and ECDSA based remote attestation.
Support new interface to check platform information blob from remote attestation response message.
Fixed bugs.

Signed-off-by: Li, Xun <xun.li@intel.com>
2019-07-05 14:12:24 +08:00

733 lines
30 KiB
C++

/*
* Copyright (C) 2011-2019 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.
*
*/
// This sample is confined to the communication between a SGX client platform
// and an ISV Application Server.
#include <stdio.h>
#include <limits.h>
#include <unistd.h>
// Needed for definition of remote attestation messages.
#include "remote_attestation_result.h"
#include "isv_enclave_u.h"
// Needed to call untrusted key exchange library APIs, i.e. sgx_ra_proc_msg2.
#include "sgx_ukey_exchange.h"
// Needed to get service provider's information, in your real project, you will
// need to talk to real server.
#include "network_ra.h"
// Needed to create enclave and do ecall.
#include "sgx_urts.h"
// Needed to query extended epid group id.
#include "sgx_uae_service.h"
#include "service_provider.h"
#ifndef SAFE_FREE
#define SAFE_FREE(ptr) {if (NULL != (ptr)) {free(ptr); (ptr) = NULL;}}
#endif
// In addition to generating and sending messages, this application
// can use pre-generated messages to verify the generation of
// messages and the information flow.
#include "sample_messages.h"
#define ENCLAVE_PATH "isv_enclave.signed.so"
uint8_t* msg1_samples[] = { msg1_sample1, msg1_sample2 };
uint8_t* msg2_samples[] = { msg2_sample1, msg2_sample2 };
uint8_t* msg3_samples[] = { msg3_sample1, msg3_sample2 };
uint8_t* attestation_msg_samples[] =
{ attestation_msg_sample1, attestation_msg_sample2};
// Some utility functions to output some of the data structures passed between
// the ISV app and the remote attestation service provider.
void PRINT_BYTE_ARRAY(
FILE *file, void *mem, uint32_t len)
{
if(!mem || !len)
{
fprintf(file, "\n( null )\n");
return;
}
uint8_t *array = (uint8_t *)mem;
fprintf(file, "%u bytes:\n{\n", len);
uint32_t i = 0;
for(i = 0; i < len - 1; i++)
{
fprintf(file, "0x%x, ", array[i]);
if(i % 8 == 7) fprintf(file, "\n");
}
fprintf(file, "0x%x ", array[i]);
fprintf(file, "\n}\n");
}
void PRINT_ATTESTATION_SERVICE_RESPONSE(
FILE *file,
ra_samp_response_header_t *response)
{
if(!response)
{
fprintf(file, "\t\n( null )\n");
return;
}
fprintf(file, "RESPONSE TYPE: 0x%x\n", response->type);
fprintf(file, "RESPONSE STATUS: 0x%x 0x%x\n", response->status[0],
response->status[1]);
fprintf(file, "RESPONSE BODY SIZE: %u\n", response->size);
if(response->type == TYPE_RA_MSG2)
{
sgx_ra_msg2_t* p_msg2_body = (sgx_ra_msg2_t*)(response->body);
fprintf(file, "MSG2 gb - ");
PRINT_BYTE_ARRAY(file, &(p_msg2_body->g_b), sizeof(p_msg2_body->g_b));
fprintf(file, "MSG2 spid - ");
PRINT_BYTE_ARRAY(file, &(p_msg2_body->spid), sizeof(p_msg2_body->spid));
fprintf(file, "MSG2 quote_type : %hx\n", p_msg2_body->quote_type);
fprintf(file, "MSG2 kdf_id : %hx\n", p_msg2_body->kdf_id);
fprintf(file, "MSG2 sign_gb_ga - ");
PRINT_BYTE_ARRAY(file, &(p_msg2_body->sign_gb_ga),
sizeof(p_msg2_body->sign_gb_ga));
fprintf(file, "MSG2 mac - ");
PRINT_BYTE_ARRAY(file, &(p_msg2_body->mac), sizeof(p_msg2_body->mac));
fprintf(file, "MSG2 sig_rl - ");
PRINT_BYTE_ARRAY(file, &(p_msg2_body->sig_rl),
p_msg2_body->sig_rl_size);
}
else if(response->type == TYPE_RA_ATT_RESULT)
{
sample_ra_att_result_msg_t *p_att_result =
(sample_ra_att_result_msg_t *)(response->body);
fprintf(file, "ATTESTATION RESULT MSG platform_info_blob - ");
PRINT_BYTE_ARRAY(file, &(p_att_result->platform_info_blob),
sizeof(p_att_result->platform_info_blob));
fprintf(file, "ATTESTATION RESULT MSG mac - ");
PRINT_BYTE_ARRAY(file, &(p_att_result->mac), sizeof(p_att_result->mac));
fprintf(file, "ATTESTATION RESULT MSG secret.payload_tag - %u bytes\n",
p_att_result->secret.payload_size);
fprintf(file, "ATTESTATION RESULT MSG secret.payload - ");
PRINT_BYTE_ARRAY(file, p_att_result->secret.payload,
p_att_result->secret.payload_size);
}
else
{
fprintf(file, "\nERROR in printing out the response. "
"Response of type not supported %d\n", response->type);
}
}
// This sample code doesn't have any recovery/retry mechanisms for the remote
// attestation. Since the enclave can be lost due S3 transitions, apps
// susceptible to S3 transitions should have logic to restart attestation in
// these scenarios.
#define _T(x) x
int main(int argc, char* argv[])
{
int ret = 0;
ra_samp_request_header_t *p_msg0_full = NULL;
ra_samp_response_header_t *p_msg0_resp_full = NULL;
ra_samp_request_header_t *p_msg1_full = NULL;
ra_samp_response_header_t *p_msg2_full = NULL;
sgx_ra_msg3_t *p_msg3 = NULL;
ra_samp_response_header_t* p_att_result_msg_full = NULL;
sgx_enclave_id_t enclave_id = 0;
int enclave_lost_retry_time = 1;
int busy_retry_time = 4;
sgx_ra_context_t context = INT_MAX;
sgx_status_t status = SGX_SUCCESS;
ra_samp_request_header_t* p_msg3_full = NULL;
sgx_att_key_id_t selected_key_id = {0};
int32_t verify_index = -1;
int32_t verification_samples = sizeof(msg1_samples)/sizeof(msg1_samples[0]);
FILE* OUTPUT = stdout;
#define VERIFICATION_INDEX_IS_VALID() (verify_index > 0 && \
verify_index <= verification_samples)
#define GET_VERIFICATION_ARRAY_INDEX() (verify_index-1)
if(argc > 1)
{
verify_index = atoi(argv[1]);
if( VERIFICATION_INDEX_IS_VALID())
{
fprintf(OUTPUT, "\nVerifying precomputed attestation messages "
"using precomputed values# %d\n", verify_index);
}
else
{
fprintf(OUTPUT, "\nValid invocations are:\n");
fprintf(OUTPUT, "\n\tisv_app\n");
fprintf(OUTPUT, "\n\tisv_app <verification index>\n");
fprintf(OUTPUT, "\nValid indices are [1 - %d]\n",
verification_samples);
fprintf(OUTPUT, "\nUsing a verification index uses precomputed "
"messages to assist debugging the remote attestation "
"service provider.\n");
return -1;
}
}
int i = 2; // We will do it twice, the first time is ECDSA quoting, the second one is EPID quoting
do
{
// Preparation for remote attestation by configuring extended epid group id.
{
uint32_t extended_epid_group_id = 0;
ret = sgx_get_extended_epid_group_id(&extended_epid_group_id);
if (SGX_SUCCESS != ret)
{
ret = -1;
fprintf(OUTPUT, "\nError, call sgx_get_extended_epid_group_id fail [%s].",
__FUNCTION__);
return ret;
}
fprintf(OUTPUT, "\nCall sgx_get_extended_epid_group_id success.");
p_msg0_full = (ra_samp_request_header_t*)
malloc(sizeof(ra_samp_request_header_t)
+sizeof(uint32_t));
if (NULL == p_msg0_full)
{
ret = -1;
goto CLEANUP;
}
p_msg0_full->type = TYPE_RA_MSG0;
p_msg0_full->size = sizeof(uint32_t);
*(uint32_t*)((uint8_t*)p_msg0_full + sizeof(ra_samp_request_header_t)) = extended_epid_group_id;
{
fprintf(OUTPUT, "\nMSG0 body generated -\n");
PRINT_BYTE_ARRAY(OUTPUT, p_msg0_full->body, p_msg0_full->size);
}
// The ISV application sends msg0 to the SP.
// The ISV decides whether to support this extended epid group id.
fprintf(OUTPUT, "\nSending msg0 to remote attestation service provider.\n");
ret = ra_network_send_receive("http://SampleServiceProvider.intel.com/",
p_msg0_full,
&p_msg0_resp_full);
if (ret != 0)
{
fprintf(OUTPUT, "\nError, ra_network_send_receive for msg0 failed "
"[%s].", __FUNCTION__);
goto CLEANUP;
}
fprintf(OUTPUT, "\nSent MSG0 to remote attestation service.\n");
ret = sgx_select_att_key_id(p_msg0_resp_full->body, p_msg0_resp_full->size, &selected_key_id);
if(SGX_SUCCESS != ret)
{
ret = -1;
fprintf(OUTPUT, "\nError, call sgx_select_att_key_id fail [%s].",
__FUNCTION__);
goto CLEANUP;
}
fprintf(OUTPUT, "\nCall sgx_select_att_key_id success.");
}
// Remote attestation will be initiated the ISV server challenges the ISV
// app or if the ISV app detects it doesn't have the credentials
// (shared secret) from a previous attestation required for secure
// communication with the server.
{
// ISV application creates the ISV enclave.
do
{
ret = sgx_create_enclave(_T(ENCLAVE_PATH),
SGX_DEBUG_FLAG,
NULL,
NULL,
&enclave_id, NULL);
if(SGX_SUCCESS != ret)
{
ret = -1;
fprintf(OUTPUT, "\nError, call sgx_create_enclave fail [%s].",
__FUNCTION__);
goto CLEANUP;
}
fprintf(OUTPUT, "\nCall sgx_create_enclave success.");
ret = enclave_init_ra(enclave_id,
&status,
false,
&context);
//Ideally, this check would be around the full attestation flow.
} while (SGX_ERROR_ENCLAVE_LOST == ret && enclave_lost_retry_time--);
if(SGX_SUCCESS != ret || status)
{
ret = -1;
fprintf(OUTPUT, "\nError, call enclave_init_ra fail [%s].",
__FUNCTION__);
goto CLEANUP;
}
fprintf(OUTPUT, "\nCall enclave_init_ra success.");
// isv application call uke sgx_ra_get_msg1
p_msg1_full = (ra_samp_request_header_t*)
malloc(sizeof(ra_samp_request_header_t)
+ sizeof(sgx_ra_msg1_t));
if(NULL == p_msg1_full)
{
ret = -1;
goto CLEANUP;
}
p_msg1_full->type = TYPE_RA_MSG1;
p_msg1_full->size = sizeof(sgx_ra_msg1_t);
do
{
ret = sgx_ra_get_msg1_ex(&selected_key_id, context, enclave_id, sgx_ra_get_ga,
(sgx_ra_msg1_t*)((uint8_t*)p_msg1_full
+ sizeof(ra_samp_request_header_t)));
sleep(3); // Wait 3s between retries
} while (SGX_ERROR_BUSY == ret && busy_retry_time--);
if(SGX_SUCCESS != ret)
{
ret = -1;
fprintf(OUTPUT, "\nError, call sgx_ra_get_msg1_ex fail [%s].",
__FUNCTION__);
goto CLEANUP;
}
else
{
fprintf(OUTPUT, "\nCall sgx_ra_get_msg1_ex success.\n");
fprintf(OUTPUT, "\nMSG1 body generated -\n");
PRINT_BYTE_ARRAY(OUTPUT, p_msg1_full->body, p_msg1_full->size);
}
if(VERIFICATION_INDEX_IS_VALID())
{
memcpy_s(p_msg1_full->body, p_msg1_full->size,
msg1_samples[GET_VERIFICATION_ARRAY_INDEX()],
p_msg1_full->size);
fprintf(OUTPUT, "\nInstead of using the recently generated MSG1, "
"we will use the following precomputed MSG1 -\n");
PRINT_BYTE_ARRAY(OUTPUT, p_msg1_full->body, p_msg1_full->size);
}
// The ISV application sends msg1 to the SP to get msg2,
// msg2 needs to be freed when no longer needed.
// The ISV decides whether to use linkable or unlinkable signatures.
fprintf(OUTPUT, "\nSending msg1 to remote attestation service provider."
"Expecting msg2 back.\n");
ret = ra_network_send_receive("http://SampleServiceProvider.intel.com/",
p_msg1_full,
&p_msg2_full);
if(ret != 0 || !p_msg2_full)
{
fprintf(OUTPUT, "\nError, ra_network_send_receive for msg1 failed "
"[%s].", __FUNCTION__);
if(VERIFICATION_INDEX_IS_VALID())
{
fprintf(OUTPUT, "\nBecause we are in verification mode we will "
"ignore this error.\n");
fprintf(OUTPUT, "\nInstead, we will pretend we received the "
"following MSG2 - \n");
SAFE_FREE(p_msg2_full);
ra_samp_response_header_t* precomputed_msg2 =
(ra_samp_response_header_t*)msg2_samples[
GET_VERIFICATION_ARRAY_INDEX()];
const size_t msg2_full_size = sizeof(ra_samp_response_header_t)
+ precomputed_msg2->size;
p_msg2_full =
(ra_samp_response_header_t*)malloc(msg2_full_size);
if(NULL == p_msg2_full)
{
ret = -1;
goto CLEANUP;
}
memcpy_s(p_msg2_full, msg2_full_size, precomputed_msg2,
msg2_full_size);
PRINT_BYTE_ARRAY(OUTPUT, p_msg2_full,
(uint32_t)sizeof(ra_samp_response_header_t)
+ p_msg2_full->size);
}
else
{
goto CLEANUP;
}
}
else
{
// Successfully sent msg1 and received a msg2 back.
// Time now to check msg2.
if(TYPE_RA_MSG2 != p_msg2_full->type)
{
fprintf(OUTPUT, "\nError, didn't get MSG2 in response to MSG1. "
"[%s].", __FUNCTION__);
if(VERIFICATION_INDEX_IS_VALID())
{
fprintf(OUTPUT, "\nBecause we are in verification mode we "
"will ignore this error.");
}
else
{
goto CLEANUP;
}
}
fprintf(OUTPUT, "\nSent MSG1 to remote attestation service "
"provider. Received the following MSG2:\n");
PRINT_BYTE_ARRAY(OUTPUT, p_msg2_full,
(uint32_t)sizeof(ra_samp_response_header_t)
+ p_msg2_full->size);
fprintf(OUTPUT, "\nA more descriptive representation of MSG2:\n");
PRINT_ATTESTATION_SERVICE_RESPONSE(OUTPUT, p_msg2_full);
if( VERIFICATION_INDEX_IS_VALID() )
{
// The response should match the precomputed MSG2:
ra_samp_response_header_t* precomputed_msg2 =
(ra_samp_response_header_t *)
msg2_samples[GET_VERIFICATION_ARRAY_INDEX()];
if(MSG2_BODY_SIZE !=
sizeof(ra_samp_response_header_t) + p_msg2_full->size ||
memcmp( precomputed_msg2, p_msg2_full,
sizeof(ra_samp_response_header_t) + p_msg2_full->size))
{
fprintf(OUTPUT, "\nVerification ERROR. Our precomputed "
"value for MSG2 does NOT match.\n");
fprintf(OUTPUT, "\nPrecomputed value for MSG2:\n");
PRINT_BYTE_ARRAY(OUTPUT, precomputed_msg2,
(uint32_t)sizeof(ra_samp_response_header_t)
+ precomputed_msg2->size);
fprintf(OUTPUT, "\nA more descriptive representation "
"of precomputed value for MSG2:\n");
PRINT_ATTESTATION_SERVICE_RESPONSE(OUTPUT,
precomputed_msg2);
}
else
{
fprintf(OUTPUT, "\nVerification COMPLETE. Remote "
"attestation service provider generated a "
"matching MSG2.\n");
}
}
}
sgx_ra_msg2_t* p_msg2_body = (sgx_ra_msg2_t*)((uint8_t*)p_msg2_full
+ sizeof(ra_samp_response_header_t));
uint32_t msg3_size = 0;
if( VERIFICATION_INDEX_IS_VALID())
{
// We cannot generate a valid MSG3 using the precomputed messages
// we have been using. We will use the precomputed msg3 instead.
msg3_size = MSG3_BODY_SIZE;
p_msg3 = (sgx_ra_msg3_t*)malloc(msg3_size);
if(NULL == p_msg3)
{
ret = -1;
goto CLEANUP;
}
memcpy_s(p_msg3, msg3_size,
msg3_samples[GET_VERIFICATION_ARRAY_INDEX()], msg3_size);
fprintf(OUTPUT, "\nBecause MSG1 was a precomputed value, the MSG3 "
"we use will also be. PRECOMPUTED MSG3 - \n");
}
else
{
busy_retry_time = 2;
// The ISV app now calls uKE sgx_ra_proc_msg2,
// The ISV app is responsible for freeing the returned p_msg3!!
do
{
ret = sgx_ra_proc_msg2_ex(&selected_key_id,
context,
enclave_id,
sgx_ra_proc_msg2_trusted,
sgx_ra_get_msg3_trusted,
p_msg2_body,
p_msg2_full->size,
&p_msg3,
&msg3_size);
} while (SGX_ERROR_BUSY == ret && busy_retry_time--);
if(!p_msg3)
{
fprintf(OUTPUT, "\nError, call sgx_ra_proc_msg2_ex fail. "
"p_msg3 = 0x%p [%s].", p_msg3, __FUNCTION__);
ret = -1;
goto CLEANUP;
}
if(SGX_SUCCESS != (sgx_status_t)ret)
{
fprintf(OUTPUT, "\nError, call sgx_ra_proc_msg2_ex fail. "
"ret = 0x%08x [%s].", ret, __FUNCTION__);
ret = -1;
goto CLEANUP;
}
else
{
fprintf(OUTPUT, "\nCall sgx_ra_proc_msg2_ex success.\n");
fprintf(OUTPUT, "\nMSG3 - \n");
}
}
PRINT_BYTE_ARRAY(OUTPUT, p_msg3, msg3_size);
p_msg3_full = (ra_samp_request_header_t*)malloc(
sizeof(ra_samp_request_header_t) + msg3_size);
if(NULL == p_msg3_full)
{
ret = -1;
goto CLEANUP;
}
p_msg3_full->type = TYPE_RA_MSG3;
p_msg3_full->size = msg3_size;
if(memcpy_s(p_msg3_full->body, msg3_size, p_msg3, msg3_size))
{
fprintf(OUTPUT,"\nError: INTERNAL ERROR - memcpy failed in [%s].",
__FUNCTION__);
ret = -1;
goto CLEANUP;
}
// The ISV application sends msg3 to the SP to get the attestation
// result message, attestation result message needs to be freed when
// no longer needed. The ISV service provider decides whether to use
// linkable or unlinkable signatures. The format of the attestation
// result is up to the service provider. This format is used for
// demonstration. Note that the attestation result message makes use
// of both the MK for the MAC and the SK for the secret. These keys are
// established from the SIGMA secure channel binding.
ret = ra_network_send_receive("http://SampleServiceProvider.intel.com/",
p_msg3_full,
&p_att_result_msg_full);
if(ret || !p_att_result_msg_full)
{
ret = -1;
fprintf(OUTPUT, "\nError, sending msg3 failed [%s].", __FUNCTION__);
goto CLEANUP;
}
sample_ra_att_result_msg_t * p_att_result_msg_body =
(sample_ra_att_result_msg_t *)((uint8_t*)p_att_result_msg_full
+ sizeof(ra_samp_response_header_t));
if(TYPE_RA_ATT_RESULT != p_att_result_msg_full->type)
{
ret = -1;
fprintf(OUTPUT, "\nError. Sent MSG3 successfully, but the message "
"received was NOT of type att_msg_result. Type = "
"%d. [%s].", p_att_result_msg_full->type,
__FUNCTION__);
goto CLEANUP;
}
else
{
fprintf(OUTPUT, "\nSent MSG3 successfully. Received an attestation "
"result message back\n.");
if( VERIFICATION_INDEX_IS_VALID() )
{
if(ATTESTATION_MSG_BODY_SIZE != p_att_result_msg_full->size ||
memcmp(p_att_result_msg_full->body,
attestation_msg_samples[GET_VERIFICATION_ARRAY_INDEX()],
p_att_result_msg_full->size) )
{
fprintf(OUTPUT, "\nSent MSG3 successfully. Received an "
"attestation result message back that did "
"NOT match the expected value.\n");
fprintf(OUTPUT, "\nEXPECTED ATTESTATION RESULT -");
PRINT_BYTE_ARRAY(OUTPUT,
attestation_msg_samples[GET_VERIFICATION_ARRAY_INDEX()],
ATTESTATION_MSG_BODY_SIZE);
}
}
}
fprintf(OUTPUT, "\nATTESTATION RESULT RECEIVED - ");
PRINT_BYTE_ARRAY(OUTPUT, p_att_result_msg_full->body,
p_att_result_msg_full->size);
if( VERIFICATION_INDEX_IS_VALID() )
{
fprintf(OUTPUT, "\nBecause we used precomputed values for the "
"messages, the attestation result message will "
"not pass further verification tests, so we will "
"skip them.\n");
goto CLEANUP;
}
// Check the MAC using MK on the attestation result message.
// The format of the attestation result message is ISV specific.
// This is a simple form for demonstration. In a real product,
// the ISV may want to communicate more information.
ret = verify_att_result_mac(enclave_id,
&status,
context,
(uint8_t*)&p_att_result_msg_body->platform_info_blob,
sizeof(ias_platform_info_blob_t),
(uint8_t*)&p_att_result_msg_body->mac,
sizeof(sgx_mac_t));
if((SGX_SUCCESS != ret) ||
(SGX_SUCCESS != status))
{
ret = -1;
fprintf(OUTPUT, "\nError: INTEGRITY FAILED - attestation result "
"message MK based cmac failed in [%s].",
__FUNCTION__);
goto CLEANUP;
}
bool attestation_passed = true;
// Check the attestation result for pass or fail.
// Whether attestation passes or fails is a decision made by the ISV Server.
// When the ISV server decides to trust the enclave, then it will return success.
// When the ISV server decided to not trust the enclave, then it will return failure.
if(0 != p_att_result_msg_full->status[0]
|| 0 != p_att_result_msg_full->status[1])
{
fprintf(OUTPUT, "\nError, attestation result message MK based cmac "
"failed in [%s].", __FUNCTION__);
attestation_passed = false;
}
// The attestation result message should contain a field for the Platform
// Info Blob (PIB). The PIB is returned by attestation server in the attestation report.
// It is not returned in all cases, but when it is, the ISV app
// should pass it to the blob analysis API called sgx_report_attestation_status()
// along with the trust decision from the ISV server.
// The ISV application will take action based on the update_info.
// returned in update_info by the API.
// This call is stubbed out for the sample.
//
// sgx_update_info_bit_t update_info;
// ret = sgx_report_attestation_status(
// &p_att_result_msg_body->platform_info_blob,
// attestation_passed ? 0 : 1, &update_info);
// Get the shared secret sent by the server using SK (if attestation
// passed)
if(attestation_passed)
{
ret = put_secret_data(enclave_id,
&status,
context,
p_att_result_msg_body->secret.payload,
p_att_result_msg_body->secret.payload_size,
p_att_result_msg_body->secret.payload_tag);
if((SGX_SUCCESS != ret) || (SGX_SUCCESS != status))
{
fprintf(OUTPUT, "\nError, attestation result message secret "
"using SK based AESGCM failed in [%s]. ret = "
"0x%0x. status = 0x%0x", __FUNCTION__, ret,
status);
goto CLEANUP;
}
}
fprintf(OUTPUT, "\nSecret successfully received from server.");
fprintf(OUTPUT, "\nRemote attestation success!");
}
CLEANUP:
// Clean-up
// Need to close the RA key state.
if(INT_MAX != context)
{
int ret_save = ret;
ret = enclave_ra_close(enclave_id, &status, context);
if(SGX_SUCCESS != ret || status)
{
ret = -1;
fprintf(OUTPUT, "\nError, call enclave_ra_close fail [%s].",
__FUNCTION__);
}
else
{
// enclave_ra_close was successful, let's restore the value that
// led us to this point in the code.
ret = ret_save;
}
fprintf(OUTPUT, "\nCall enclave_ra_close success.");
}
sgx_destroy_enclave(enclave_id);
ra_free_network_response_buffer(p_msg0_resp_full);
ra_free_network_response_buffer(p_msg2_full);
ra_free_network_response_buffer(p_att_result_msg_full);
// p_msg3 is malloc'd by the untrusted KE library. App needs to free.
SAFE_FREE(p_msg3);
SAFE_FREE(p_msg3_full);
SAFE_FREE(p_msg1_full);
SAFE_FREE(p_msg0_full);
}while(--i);
printf("\nEnter a character before exit ...\n");
getchar();
return ret;
}