DRM_enclave.edl
DRM_enclave.edl import sgx_tae_service.edl
and add six trusted functions.
enclave {
from "sgx_tae_service.edl" import *;
trusted {
/* define ECALLs here. */
public uint32_t create_sealed_policy([out, size=sealed_log_size]
uint8_t* sealed_log, uint32_t sealed_log_size );
public uint32_t perform_sealed_policy([in, size=sealed_log_size]
const uint8_t* sealed_log, uint32_t sealed_log_size);
public uint32_t update_sealed_policy([in,out, size=sealed_log_size]
uint8_t* sealed_log, uint32_t sealed_log_size);
public uint32_t delete_sealed_policy([in, size=sealed_log_size]
const uint8_t* sealed_log, uint32_t sealed_log_size);
public uint32_t create_time_based_policy([out, size=sealed_log_size]
uint8_t* sealed_log, uint32_t sealed_log_size );
public uint32_t perform_time_based_policy([in, size=sealed_log_size]
const uint8_t* sealed_log, uint32_t sealed_log_size );
};
};
sgx_tae_service.edl
enclave{
from "sgx_tstdc.edl" import *;
untrusted {
sgx_status_t create_session_ocall([out] uint32_t* sid,
[size = dh_msg1_size, out] uint8_t* dh_msg1,
uint32_t dh_msg1_size,
uint32_t timeout);
sgx_status_t exchange_report_ocall(uint32_t sid,
[size = dh_msg2_size, in] uint8_t* dh_msg2, uint32_t dh_msg2_size,
[size = dh_msg3_size, out] uint8_t* dh_msg3, uint32_t dh_msg3_size,
uint32_t timeout);
sgx_status_t close_session_ocall(uint32_t sid, uint32_t timeout);
sgx_status_t invoke_service_ocall([size = pse_message_req_size, in] uint8_t* pse_message_req,
uint32_t pse_message_req_size,
[size = pse_message_resp_size, out] uint8_t* pse_message_resp, uint32_t pse_message_resp_size,
uint32_t timeout);
};
};
sgx_tstdc.edl
sgx_tstdc.edl defines 5 untrusted functions. cdecl调用约定是C标准的默认方式,OCALLs的函数调用约定.
enclave {
untrusted {
[cdecl] void sgx_oc_cpuidex([out] int cpuinfo[4], int leaf, int subleaf);
/* Go outside and wait on my untrusted event */
[cdecl] int sgx_thread_wait_untrusted_event_ocall([user_check] const void *self);
/* Wake a thread waiting on its untrusted event */
[cdecl] int sgx_thread_set_untrusted_event_ocall([user_check] const void *waiter);
/* Wake a thread waiting on its untrusted event, and wait on my untrusted event */
[cdecl] int sgx_thread_setwait_untrusted_events_ocall([user_check] const void *waiter, [user_check] const void *self);
/* Wake multiple threads waiting on their untrusted events */
[cdecl] int sgx_thread_set_multiple_untrusted_events_ocall([in, count = total] const void **waiters, size_t total);
};
};
DRM_app.cpp
DRM_app.cpp calls 5 functions start with test_
.
#define _T(x) x
int main(int argc, char* argv[])
{
(void)argc; /* unused parameter */
(void)argv; /* unused parameter */
/* normal operation */
test_replay_protected_drm_operation();
/* trigger update limitation */
test_replay_protected_drm_update_limitation();
/* replay attack */
test_replay_protected_drm_replay_attack_protection();
/* normal operation */
test_time_based_policy_operation();
/* trigger expiration */
test_time_based_policy_expiration();
printf("Enter a character before exit ...\n");
getchar();
return 0;
}
test_replay_protected_drm_operation
The function test_replay_protected_drm_operation introduces ReplayProtectedDRM.
uint32_t test_replay_protected_drm_operation()
{
cout<<endl<<"\tReplay Protected DRM operation:"<<endl;
uint32_t result = 0;
ReplayProtectedDRM DRM;
result = DRM.init();
if(result)
{
cerr<<"Initialization the DRM failed."<<endl;
return result;
}
else
cout<<"Successfully initialized the DRM."<<endl;
do{
result = DRM.perform_function();
if(result)
{
cerr<<"Performing the DRM functions failed."<<endl;
break;
}
else
cout<<"Successfully performed the DRM functions."<<endl;
result = DRM.update_secret();
if(result)
{
cerr<<"Updating the DRM secret failed."<<endl;
break;
}
else
cout<<"Successfully updated the DRM secret."<<endl;
result = DRM.perform_function();
if(result)
{
cerr<<"Performing the DRM functions failed."<<endl;
break;
}
else
cout<<"Successfully performed the DRM functions."<<endl;
}while(0);
if(DRM.delete_secret())
{
cerr<<"Deleting the DRM secret failed."<<endl;
return result;
}
else
cout<<"Successfully deleted the DRM secret."<<endl;
return result;
}
The constructor of ReplayProtectedDRM
.
ReplayProtectedDRM::ReplayProtectedDRM(): enclave_id(0)
{
sgx_status_t sgx_ret = SGX_ERROR_UNEXPECTED;
sgx_ret = sgx_create_enclave(ENCLAVE_NAME, SGX_DEBUG_FLAG,
NULL, NULL, &enclave_id, NULL);
if (sgx_ret)
{
cerr<<"cannot create enclave, error code = 0x"<< hex<< sgx_ret <<endl;
}
}
At first, it calls result = DRM.init();
#define SEALED_REPLAY_PROTECTED_PAY_LOAD_SIZE 620
static const uint32_t sealed_activity_log_length = SEALED_REPLAY_PROTECTED_PAY_LOAD_SIZE;
uint8_t sealed_activity_log[sealed_activity_log_length];
uint32_t ReplayProtectedDRM:: init()
{
return init(sealed_activity_log);
}
init(uint8_t* stored_sealed_activity_log)
uint32_t ReplayProtectedDRM:: init(uint8_t* stored_sealed_activity_log)
{
sgx_status_t sgx_ret = SGX_ERROR_UNEXPECTED;
sgx_ps_cap_t ps_cap;
memset(&ps_cap, 0, sizeof(sgx_ps_cap_t));
sgx_ret = sgx_get_ps_cap(&ps_cap);
if (sgx_ret)
{
cerr<<"cannot get platform service capability, error code = 0x"<< hex
<< sgx_ret <<endl;
return sgx_ret;
}
if (!SGX_IS_MONOTONIC_COUNTER_AVAILABLE(ps_cap))
{
cerr<<"monotonic counter is not supported"<<endl;
return SGX_ERROR_SERVICE_UNAVAILABLE;
}
uint32_t enclave_ret = 0;
sgx_ret = create_sealed_policy(enclave_id, &enclave_ret,
(uint8_t *)stored_sealed_activity_log, sealed_activity_log_length);
if (sgx_ret)
{
cerr<<"call create_sealed_policy fail, error code = 0x"<< hex<< sgx_ret
<<endl;
return sgx_ret;
}
if (enclave_ret)
{
cerr<<"cannot create_sealed_policy, function return fail, error code ="
"0x"<< hex<< enclave_ret <<endl;
return enclave_ret;
}
return 0;
}
call sgx_get_ps_cap from sgx_uae_service.h
/**
* Get the platform service capabilities
*
* @param sgx_ps_cap Platform capabilities reported by AESM.
* @return if OK, return SGX_SUCCESS
*/
sgx_status_t SGXAPI sgx_get_ps_cap(sgx_ps_cap_t* p_sgx_ps_cap);
create_sealed_policy defines in DRM_enclave.edl, implemented in DRM_enclave.cpp
uint32_t create_sealed_policy(uint8_t* sealed_log, uint32_t sealed_log_size )
{
uint32_t ret = 0;
int busy_retry_times = 2;
replay_protected_pay_load data2seal;
memset(&data2seal, 0, sizeof(data2seal));
uint32_t size = sgx_calc_sealed_data_size(0,
sizeof(replay_protected_pay_load));
if(sealed_log_size != size)
return SGX_ERROR_INVALID_PARAMETER;
do{
ret = sgx_create_pse_session();
}while (ret == SGX_ERROR_BUSY && busy_retry_times--);
if (ret != SGX_SUCCESS)
return ret;
do
{
ret = sgx_create_monotonic_counter(&data2seal.mc,&data2seal.mc_value);
if(ret != SGX_SUCCESS)
{
switch(ret)
{
case SGX_ERROR_SERVICE_UNAVAILABLE:
/* Architecture Enclave Service Manager is not installed or not
working properly.*/
break;
case SGX_ERROR_SERVICE_TIMEOUT:
/* retry the operation later*/
break;
case SGX_ERROR_BUSY:
/* retry the operation later*/
break;
case SGX_ERROR_MC_OVER_QUOTA:
/* SGX Platform Service enforces a quota scheme on the Monotonic
Counters a SGX app can maintain. the enclave has reached the
quota.*/
break;
case SGX_ERROR_MC_USED_UP:
/* the Monotonic Counter has been used up and cannot create
Monotonic Counter anymore.*/
break;
default:
/*other errors*/
break;
}
break;
}
/* secret should be provisioned into enclave after the enclave attests to
the secret owner.
For example, the server that delivers the encrypted DRM content.
In this sample code, a random number is used to represent the secret */
ret = sgx_read_rand(data2seal.secret, REPLAY_PROTECTED_SECRET_SIZE);
if(ret != SGX_SUCCESS)
break;
data2seal.log.release_version = 0;
/* the secret can be updated for 5 times */
data2seal.log.max_release_version =
REPLAY_PROTECTED_PAY_LOAD_MAX_RELEASE_VERSION;
/*sealing the plaintext to ciphertext. The ciphertext can be delivered
outside of enclave.*/
ret = sgx_seal_data(0, NULL,sizeof(data2seal),(uint8_t*)&data2seal,
sealed_log_size, (sgx_sealed_data_t*)sealed_log);
} while (0);
/* remember to clear secret data after been used by memset_s */
memset_s(&data2seal, sizeof(replay_protected_pay_load), 0,
sizeof(replay_protected_pay_load));
sgx_close_pse_session();
return ret;
}