Example #1
0
/*
 * External function used to verify EPID Blob and check whether QE has
 * been updated.
 *
 * @param p_blob[in, out] Pointer to EPID Blob.
 * @param blob_size[in] The size of EPID Blob, in bytes.
 * @param p_is_resealed[out] Whether the EPID Blob is resealed within this function call.
 * @param p_cpusvn[out] Return the raw CPUSVN.
 * @return uint32_t AE_SUCCESS or other error cases.
 */
uint32_t verify_blob(
    uint8_t *p_blob,
    uint32_t blob_size,
    uint8_t *p_is_resealed,
    sgx_cpu_svn_t *p_cpusvn)
{
    se_plaintext_epid_data_sdk_t plain_text;

    /* Actually, some cases here will be checked with code generated by
       edger8r. Here we just want to defend in depth. */
    if(NULL == p_blob || NULL == p_is_resealed || NULL == p_cpusvn)
        return QE_PARAMETER_ERROR;

    if(SGX_TRUSTED_EPID_BLOB_SIZE_SDK != blob_size)
        return QE_PARAMETER_ERROR;

	//
	// if we mispredict here and blob_size is too
	// small, we might overflow
	//
	sgx_lfence();

    if(!sgx_is_within_enclave(p_blob, blob_size))
        return QE_PARAMETER_ERROR;

    return random_stack_advance(verify_blob_internal, p_blob, blob_size,
                                p_is_resealed, FALSE, plain_text, (MemberCtx**) NULL, p_cpusvn);
}
Example #2
0
// TKE interface for isv enclaves
sgx_status_t sgx_ra_get_keys(
    sgx_ra_context_t context,
    sgx_ra_key_type_t type,
    sgx_ra_key_128_t *p_key)
{
    if(vector_size(&g_ra_db) <= context || !p_key)
        return SGX_ERROR_INVALID_PARAMETER;
    ra_db_item_t* item = NULL;
    if(0 != vector_get(&g_ra_db, context, reinterpret_cast<void**>(&item)) || item == NULL )
        return SGX_ERROR_INVALID_PARAMETER;

    if(!sgx_is_within_enclave(p_key, sizeof(sgx_ra_key_128_t)))
        return SGX_ERROR_INVALID_PARAMETER;

    sgx_status_t ret = SGX_SUCCESS;
    sgx_spin_lock(&item->item_lock);
    //sgx_ra_proc_msg2_trusted fill the keys, so keys are available after it's called.
    if (item->state != ra_proc_msg2ed)
        ret = SGX_ERROR_INVALID_STATE;
    else if(SGX_RA_KEY_MK == type)
        memcpy(p_key, item->mk_key, sizeof(sgx_ra_key_128_t));
    else if(SGX_RA_KEY_SK == type)
        memcpy(p_key, item->sk_key, sizeof(sgx_ra_key_128_t));
    else
        ret = SGX_ERROR_INVALID_PARAMETER;
    sgx_spin_unlock(&item->item_lock);
    return ret;
}
Example #3
0
sgx_status_t sgx_read_rand(unsigned char *rand, size_t length_in_bytes)
{
    // check parameters
    //
    // rand can be within or outside the enclave
    if(!rand || !length_in_bytes)
    {
        return SGX_ERROR_INVALID_PARAMETER;
    }
    if(!sgx_is_within_enclave(rand, length_in_bytes) && !sgx_is_outside_enclave(rand, length_in_bytes))
    {
        return SGX_ERROR_INVALID_PARAMETER;
    }
    // loop to rdrand
    uint32_t rand_num = 0;
    while(length_in_bytes > 0)
    {
        sgx_status_t status = __do_get_rand32(&rand_num);
        if(status != SGX_SUCCESS)
        {
            return status;
        }

        size_t size = (length_in_bytes < sizeof(rand_num)) ? length_in_bytes : sizeof(rand_num);
        memcpy(rand, &rand_num, size);

        rand += size;
        length_in_bytes -= size;
    }
    memset_s(&rand_num, sizeof(rand_num), 0, sizeof(rand_num));
    return SGX_SUCCESS;
}
Example #4
0
/* ecall_pointer_out:
 *   the buffer of val is copied to the untrusted side.
 */
void ecall_pointer_out(int *val)
{
    if (sgx_is_within_enclave(val, sizeof(int)) != 1)
        abort();
    assert(*val == 0);
    *val = 1234;
}
Example #5
0
SGX_WEAK void* SGXAPI operator new[] (size_t dwBytes, void* ptr) throw()
{
	if( !sgx_is_within_enclave(ptr, dwBytes) ){
		//compiler will check the pointer before call object construct, so it is OK to return NULL here
		return NULL;
	}
	return ptr;
}
Example #6
0
// sgx_register_exception_handler()
//      register a custom exception handler
// Parameter
//      is_first_handler - the order in which the handler should be called.
// if the parameter is nonzero, the handler is the first handler to be called.
// if the parameter is zero, the handler is the last handler to be called.
//      exception_handler - a pointer to the handler to be called.
// Return Value
//      handler - success
//         NULL - fail
void *sgx_register_exception_handler(int is_first_handler, sgx_exception_handler_t exception_handler)
{
    // initialize g_veh_cookie for the first time sgx_register_exception_handler is called.
    if(unlikely(g_veh_cookie == 0))
    {
        uintptr_t rand = 0;
        do
        {
            if(SGX_SUCCESS != sgx_read_rand((unsigned char *)&rand, sizeof(rand)))
            {
                return NULL;
            }
        } while(rand == 0);

        sgx_spin_lock(&g_handler_lock);
        if(g_veh_cookie == 0)
        {
            g_veh_cookie = rand;
        }
        sgx_spin_unlock(&g_handler_lock);
    }
    if(!sgx_is_within_enclave((const void*)exception_handler, 0))
    {
        return NULL;
    }
    handler_node_t *node = (handler_node_t *)malloc(sizeof(handler_node_t));
    if(!node)
    {
        return NULL;
    }
    node->callback = ENC_VEH_POINTER(exception_handler);

    // write lock
    sgx_spin_lock(&g_handler_lock);

    if((g_first_node == NULL) || is_first_handler)
    {
        node->next = g_first_node;
        g_first_node = node;
    }
    else
    {
        handler_node_t *tmp = g_first_node;
        while(tmp->next != NULL)
        {
            tmp = tmp->next;
        }
        node->next = NULL;
        tmp->next = node;
    }
    // write unlock
    sgx_spin_unlock(&g_handler_lock);

    return node;
}
Example #7
0
sgx_status_t sgx_verify_report(const sgx_report_t *report)
{
    sgx_mac_t mac;
    sgx_key_request_t key_request;
    sgx_key_128bit_t key;
    sgx_status_t err = SGX_ERROR_UNEXPECTED;
    //check parameter
    if(!report||!sgx_is_within_enclave(report, sizeof(*report)))
    {
        return SGX_ERROR_INVALID_PARAMETER;
    }

    memset(&mac, 0, sizeof(sgx_mac_t));
    memset(&key_request, 0, sizeof(sgx_key_request_t));
    memset(&key, 0, sizeof(sgx_key_128bit_t));

    //prepare the key_request
    key_request.key_name = SGX_KEYSELECT_REPORT;
    memcpy_s(&key_request.key_id, sizeof(key_request.key_id), &report->key_id, sizeof(report->key_id));

    //get the report key
    // Since the key_request is not an input parameter by caller,
    // we suppose sgx_get_key would never return the following error code:
    //      SGX_ERROR_INVALID_PARAMETER
    //      SGX_ERROR_INVALID_ATTRIBUTE
    //      SGX_ERROR_INVALID_CPUSVN
    //      SGX_ERROR_INVALID_ISVSVN
    //      SGX_ERROR_INVALID_KEYNAME
    err = sgx_get_key(&key_request, &key);
    if(err != SGX_SUCCESS)
    {
        return err; // err must be SGX_ERROR_OUT_OF_MEMORY or SGX_ERROR_UNEXPECTED
    }
    //get the report mac
    err = sgx_rijndael128_cmac_msg((sgx_cmac_128bit_key_t*)&key, (const uint8_t *)(&report->body), sizeof(sgx_report_body_t), &mac);
    memset_s (&key, sizeof(sgx_key_128bit_t), 0, sizeof(sgx_key_128bit_t));
    if (SGX_SUCCESS != err)
    {
        if(err != SGX_ERROR_OUT_OF_MEMORY)
            err = SGX_ERROR_UNEXPECTED;
        return err;
    }
    if(consttime_memequal(mac, report->mac, sizeof(sgx_mac_t)) == 0)
    {
        return SGX_ERROR_MAC_MISMATCH;
    }
    else
    {
        return SGX_SUCCESS;
    }
}
Example #8
0
/*
 * External function used to init white list. It will check whether the input
 * buffer is correctly copied into EPC, and check the size of the buffer.
 *
 * @param wl_cert_chain[in] Pointer to the white list cert chain.
 * @param wl_cert_chain_size[in] The size of white list cert chain, in bytes.
 * @return uint32_t AE_SUCCESS for success, otherwise for errors.
 */
uint32_t le_init_white_list_wrapper(
    const uint8_t *wl_cert_chain,
    uint32_t wl_cert_chain_size)
{
    const wl_cert_chain_t *p_wl_cert_chain = NULL;
    uint32_t entry_number = 0;
    uint32_t temp_size = 0;

    if(wl_cert_chain == NULL)
    {
        return LE_INVALID_PARAMETER;
    }
    if(!sgx_is_within_enclave(wl_cert_chain, wl_cert_chain_size))
        return LE_INVALID_PARAMETER;
    p_wl_cert_chain = (const wl_cert_chain_t *)wl_cert_chain;
    // First compare wl_cert_chain_size with the minimal size of cert chain.
    // It should have at least one entry of mrsigner.
    if(wl_cert_chain_size < sizeof(wl_cert_chain_t)
                            + sizeof(sgx_measurement_t)
                            + sizeof(sgx_ec256_signature_t))
    {
        return LE_INVALID_PARAMETER;
    }
    entry_number = p_wl_cert_chain->wl_cert.entry_number;
    entry_number = _ntohl(entry_number);
    // limits max MRSIGNER entry number in
    // WL Cert to be <= 512
    if(entry_number > LE_MAX_MRSIGNER_NUMBER)
    {
        return LE_INVALID_PARAMETER;
    }
    temp_size =  static_cast<uint32_t>(sizeof(wl_cert_chain_t)
                 + sizeof(sgx_ec256_signature_t)
                 + (sizeof(sgx_measurement_t) * entry_number));
    if(wl_cert_chain_size != temp_size)
    {
        return LE_INVALID_PARAMETER;
    }
    return le_init_white_list(p_wl_cert_chain, entry_number, wl_cert_chain_size);
}
Example #9
0
// TKE interface for isv enclaves
sgx_status_t sgx_ra_init_ex(
    const sgx_ec256_public_t *p_pub_key,
    int b_pse,
    sgx_ra_derive_secret_keys_t derive_key_cb,
    sgx_ra_context_t *p_context)
{
    int valid = 0;
    sgx_status_t ret = SGX_SUCCESS;
    sgx_ecc_state_handle_t ecc_state = NULL;

    // initialize g_kdf_cookie for the first time sgx_ra_init_ex is called.
    if (unlikely(g_kdf_cookie == 0))
    {
        uintptr_t rand = 0;
        do
        {
            if (SGX_SUCCESS != sgx_read_rand((unsigned char *)&rand, sizeof(rand)))
            {
                return SGX_ERROR_UNEXPECTED;
            }
        } while (rand == 0);

        sgx_spin_lock(&g_ra_db_lock);
        if (g_kdf_cookie == 0)
        {
            g_kdf_cookie = rand;
            memset_s(&rand, sizeof(rand), 0, sizeof(rand));
        }
        sgx_spin_unlock(&g_ra_db_lock);
    }

    if(!p_pub_key || !p_context)
        return SGX_ERROR_INVALID_PARAMETER;

    if(!sgx_is_within_enclave(p_pub_key, sizeof(sgx_ec256_public_t)))
        return SGX_ERROR_INVALID_PARAMETER;

    //derive_key_cb can be NULL
    if (NULL != derive_key_cb &&
        !sgx_is_within_enclave((const void*)derive_key_cb, 0))
    {
        return SGX_ERROR_INVALID_PARAMETER;
    }

    ret = sgx_ecc256_open_context(&ecc_state);
    if(SGX_SUCCESS != ret)
    {
        if(SGX_ERROR_OUT_OF_MEMORY != ret)
            ret = SGX_ERROR_UNEXPECTED;
        return ret;
    }

    ret = sgx_ecc256_check_point((const sgx_ec256_public_t *)p_pub_key,
                                 ecc_state, &valid);
    if(SGX_SUCCESS != ret)
    {
        if(SGX_ERROR_OUT_OF_MEMORY != ret)
            ret = SGX_ERROR_UNEXPECTED;
        sgx_ecc256_close_context(ecc_state);
        return ret;
    }
    if(!valid)
    {
        sgx_ecc256_close_context(ecc_state);
        return SGX_ERROR_INVALID_PARAMETER;
    }
    sgx_ecc256_close_context(ecc_state);

    //add new item to g_ra_db
    ra_db_item_t* new_item = (ra_db_item_t*)malloc(sizeof(ra_db_item_t));
    if (!new_item)
    {
        return SGX_ERROR_OUT_OF_MEMORY;
    }
    memset(new_item,0, sizeof(ra_db_item_t));
    memcpy(&new_item->sp_pubkey, p_pub_key, sizeof(new_item->sp_pubkey));
    if(b_pse)
    {
        //sgx_create_pse_session() must have been called
        ret = sgx_get_ps_sec_prop(&new_item->ps_sec_prop);
        if (ret!=SGX_SUCCESS)
        {
            SAFE_FREE(new_item);
            return ret;
        }
    }

    new_item->derive_key_cb = ENC_KDF_POINTER(derive_key_cb);
    new_item->state = ra_inited;

    //find first empty slot in g_ra_db
    int first_empty = -1;
    ra_db_item_t* item = NULL;
    sgx_spin_lock(&g_ra_db_lock);
    uint32_t size = vector_size(&g_ra_db);
    for (uint32_t i = 0; i < size; i++)
    {
        if(0 != vector_get(&g_ra_db, i, reinterpret_cast<void**>(&item)))
        {
            sgx_spin_unlock(&g_ra_db_lock);
            SAFE_FREE(new_item);
            return SGX_ERROR_UNEXPECTED;
        }
        if(item == NULL)
        {
            first_empty = i;
            break;
        }
    }
    //if there is a empty slot, use it
    if (first_empty >= 0)
    {
        errno_t vret = vector_set(&g_ra_db, first_empty, new_item);
        UNUSED(vret);
        assert(vret == 0);
        *p_context = first_empty;
    }
    //if there are no empty slots, add a new item to g_ra_db
    else
    {
        if(size >= INT32_MAX)
        {
            //overflow
            sgx_spin_unlock(&g_ra_db_lock);
            SAFE_FREE(new_item);
            return SGX_ERROR_OUT_OF_MEMORY;
        }
        if(0 != vector_push_back(&g_ra_db, new_item))
        {
            sgx_spin_unlock(&g_ra_db_lock);
            SAFE_FREE(new_item);
            return SGX_ERROR_OUT_OF_MEMORY;
        }
        *p_context = size;
    }
    sgx_spin_unlock(&g_ra_db_lock);
    return SGX_SUCCESS;
}
Example #10
0
/*
 * External function used to get quote. Prefix "emp_" means it is a pointer
 * points memory outside enclave.
 *
 * @param p_blob[in, out] Pointer to the EPID Blob.
 * @param blob_size[in] The size of EPID Blob, in bytes.
 * @param p_enclave_report[in] The application enclave's report.
 * @param quote_type[in] The type of quote, random based or name based.
 * @param p_spid[in] Pointer to SPID.
 * @param p_nonce[in] Pointer to nonce.
 * @param emp_sig_rl[in] Pointer to SIG-RL.
 * @param sig_rl_size[in] The size of SIG-RL, in bytes.
 * @param p_qe_report[out] Pointer to QE report, which reportdata is
 *                         sha256(nonce || quote)
 * @param emp_quote[out] Pointer to the output buffer for quote.
 * @param quote_size[in] The size of emp_quote, in bytes.
 * @param pce_isvsvn[in] The ISVSVN of PCE.
 * @return ae_error_t AE_SUCCESS for success, otherwise for errors.
 */
uint32_t get_quote(
    uint8_t *p_blob,
    uint32_t blob_size,
    const sgx_report_t *p_enclave_report,
    sgx_quote_sign_type_t quote_type,
    const sgx_spid_t *p_spid,
    const sgx_quote_nonce_t *p_nonce,
    const uint8_t *emp_sig_rl,
    uint32_t sig_rl_size,
    sgx_report_t *p_qe_report,
    uint8_t *emp_quote,
    uint32_t quote_size,
    sgx_isv_svn_t pce_isvsvn)
{
    ae_error_t ret = AE_SUCCESS;
    EpidStatus epid_ret = kEpidNoErr;
    MemberCtx *p_epid_context = NULL;
    sgx_quote_t quote_body;
    uint8_t is_resealed = 0;
    sgx_basename_t basename = {{0}};
    uint64_t sign_size = 0;
    sgx_status_t se_ret = SGX_SUCCESS;
    sgx_report_t qe_report;
    uint64_t required_buffer_size = 0;
    se_sig_rl_t sig_rl_header;
    se_plaintext_epid_data_sdk_t plaintext;
    sgx_ec256_signature_t ec_signature;
    sgx_cpu_svn_t cpusvn;

    memset(&quote_body, 0, sizeof(quote_body));
    memset(&sig_rl_header, 0, sizeof(sig_rl_header));
    memset(&plaintext, 0, sizeof(plaintext));
    memset(&ec_signature, 0, sizeof(ec_signature));
    memset(&cpusvn, 0, sizeof(cpusvn));


    /* Actually, some cases here will be checked with code generated by
       edger8r. Here we just want to defend in depth. */
    if((NULL == p_blob)
       || (NULL == p_enclave_report)
       || (NULL == p_spid)
       || (NULL == emp_quote)
       || (!quote_size)
       || ((NULL != emp_sig_rl) && (sig_rl_size < sizeof(se_sig_rl_t)
                                                  + 2 * SE_ECDSA_SIGN_SIZE))

		//
		// this size check could mispredict and cause us to
		// overflow, but we have an lfence below
		// that's safe to use for this case
		//

       || ((NULL == emp_sig_rl) && (sig_rl_size != 0)))
        return QE_PARAMETER_ERROR;
    if(SGX_TRUSTED_EPID_BLOB_SIZE_SDK != blob_size)
        return QE_PARAMETER_ERROR;

	//
	// this could mispredict and cause us to
	// overflow, but we have an lfence below
	// that's safe to use for this case
	//

    if(SGX_LINKABLE_SIGNATURE != quote_type
       && SGX_UNLINKABLE_SIGNATURE != quote_type)
        return QE_PARAMETER_ERROR;
    if(!p_nonce && p_qe_report)
        return QE_PARAMETER_ERROR;
    if(p_nonce && !p_qe_report)
        return QE_PARAMETER_ERROR;

    /* To reduce the memory footprint of QE, we should leave sig_rl and
       quote buffer outside enclave. */
    if(!sgx_is_outside_enclave(emp_sig_rl, sig_rl_size))
        return QE_PARAMETER_ERROR;

    //
    // for user_check SigRL input
    // based on quote_size input parameter
    //
    sgx_lfence();

    if(!sgx_is_outside_enclave(emp_quote, quote_size))
        return QE_PARAMETER_ERROR;

    /* Check whether p_blob is copied into EPC. If we want to reduce the
       memory usage, maybe we can leave the p_blob outside EPC. */
    if(!sgx_is_within_enclave(p_blob, blob_size))
        return QE_PARAMETER_ERROR;
    if(!sgx_is_within_enclave(p_enclave_report, sizeof(*p_enclave_report)))
        return QE_PARAMETER_ERROR;
    if(!sgx_is_within_enclave(p_spid, sizeof(*p_spid)))
        return QE_PARAMETER_ERROR;
    /* If the code reach here, if p_nonce is NULL, then p_qe_report will be
       NULL also. So we only check p_nonce here.*/
    if(p_nonce)
    {
        /* Actually Edger8r will alloc the buffer within EPC, this is just kind
           of defense in depth. */
        if(!sgx_is_within_enclave(p_nonce, sizeof(*p_nonce)))
            return QE_PARAMETER_ERROR;
        if(!sgx_is_within_enclave(p_qe_report, sizeof(*p_qe_report)))
            return QE_PARAMETER_ERROR;
    }

    /* Verify the input report. */
    if(SGX_SUCCESS != sgx_verify_report(p_enclave_report))
        return QE_PARAMETER_ERROR;

    /* Verify EPID p_blob and create the context */
    ret = random_stack_advance(verify_blob_internal, p_blob,
        blob_size,
        &is_resealed,
        TRUE,
        plaintext,
        &p_epid_context,
        &cpusvn);
    if(AE_SUCCESS != ret)
        goto CLEANUP;

    /* If SIG-RL is provided, we should check its size. */
    if(emp_sig_rl)
    {
        uint64_t temp_size = 0;
        uint64_t n2 = 0;

        memcpy(&sig_rl_header, emp_sig_rl, sizeof(sig_rl_header));
        if(sig_rl_header.protocol_version != SE_EPID_SIG_RL_VERSION)
        {
            ret = QE_PARAMETER_ERROR;
            goto CLEANUP;
        }

        if(sig_rl_header.epid_identifier != SE_EPID_SIG_RL_ID)
        {
            ret = QE_PARAMETER_ERROR;
            goto CLEANUP;
        }

        if(memcmp(&sig_rl_header.sig_rl.gid, &plaintext.epid_group_cert.gid,
                   sizeof(sig_rl_header.sig_rl.gid)))
        {
            ret = QE_PARAMETER_ERROR;
            goto CLEANUP;
        }
        temp_size = se_get_sig_rl_size(&sig_rl_header);
        if(temp_size != sig_rl_size)
        {
            ret = QE_PARAMETER_ERROR;
            goto CLEANUP;
        }

        se_static_assert(sizeof(ec_signature.x) == SE_ECDSA_SIGN_SIZE);
        se_static_assert(sizeof(ec_signature.y) == SE_ECDSA_SIGN_SIZE);
        memcpy(ec_signature.x,
               emp_sig_rl + sig_rl_size - (SE_ECDSA_SIGN_SIZE * 2),
               sizeof(ec_signature.x));
        SWAP_ENDIAN_32B(ec_signature.x);
        memcpy(ec_signature.y,
               emp_sig_rl + sig_rl_size - (SE_ECDSA_SIGN_SIZE * 1),
               sizeof(ec_signature.y));
        SWAP_ENDIAN_32B(ec_signature.y);

        n2 = SWAP_4BYTES(sig_rl_header.sig_rl.n2);
        temp_size = sizeof(EpidSignature) - sizeof(NrProof)
                    + n2 * sizeof(NrProof);
        if(temp_size > UINT32_MAX)
        {
            ret = QE_PARAMETER_ERROR;
            goto CLEANUP;
        }
        sign_size = temp_size;
    }
    else
    {
        sign_size = sizeof(BasicSignature)
                    + sizeof(uint32_t) // rl_ver
                    + sizeof(uint32_t); // rl_num
    }

    /* Verify sizeof basename is large enough and it should always be true*/
    se_static_assert(sizeof(basename) > sizeof(*p_spid));
    /* Because basename has already been zeroed,
       so we don't need to concatenating with 0s.*/
    memcpy(&basename, p_spid, sizeof(*p_spid));
    if(SGX_UNLINKABLE_SIGNATURE == quote_type)
    {
        uint8_t *p = (uint8_t *)&basename + sizeof(*p_spid);
        se_ret = sgx_read_rand(p, sizeof(basename) - sizeof(*p_spid));
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }
    }

    epid_ret = EpidRegisterBasename(p_epid_context, (uint8_t *)&basename,
        sizeof(basename));
    if(kEpidNoErr != epid_ret)
    {
        ret = QE_UNEXPECTED_ERROR;
        goto CLEANUP;
    }

    required_buffer_size = SE_QUOTE_LENGTH_WITHOUT_SIG + sign_size;

    /* We should make sure the buffer size is big enough. */
    if(quote_size < required_buffer_size)
    {
        ret = QE_PARAMETER_ERROR;
        goto CLEANUP;
    }

    //
    // for user_check SigRL input
    // based on n2 field in SigRL
    //
    sgx_lfence();

    /* Copy the data in the report into quote body. */
    memset(emp_quote, 0, quote_size);
    quote_body.version = QE_QUOTE_VERSION;
    quote_body.sign_type = (uint16_t)quote_type;
    quote_body.pce_svn = pce_isvsvn; // Both are little endian
    quote_body.xeid = plaintext.xeid; // Both are little endian
    se_static_assert(sizeof(plaintext.epid_group_cert.gid) == sizeof(OctStr32));
    se_static_assert(sizeof(quote_body.epid_group_id) == sizeof(uint32_t));
    ((uint8_t *)(&quote_body.epid_group_id))[0] = plaintext.epid_group_cert.gid.data[3];
    ((uint8_t *)(&quote_body.epid_group_id))[1] = plaintext.epid_group_cert.gid.data[2];
    ((uint8_t *)(&quote_body.epid_group_id))[2] = plaintext.epid_group_cert.gid.data[1];
    ((uint8_t *)(&quote_body.epid_group_id))[3] = plaintext.epid_group_cert.gid.data[0];
    memcpy(&quote_body.basename, &basename, sizeof(quote_body.basename));

    // Get the QE's report.
    se_ret = sgx_create_report(NULL, NULL, &qe_report);
    if(SGX_SUCCESS != se_ret)
    {
        ret = QE_PARAMETER_ERROR;
        goto CLEANUP;
    }

    // Copy QE's security version in to Quote body.
    quote_body.qe_svn = qe_report.body.isv_svn;

    // Copy the incoming report into Quote body.
    memcpy(&quote_body.report_body, &(p_enclave_report->body),
           sizeof(quote_body.report_body));
    /* Because required_buffer_size is larger than signature_len, so if we
       get here, then no integer overflow will ocur. */
    quote_body.signature_len = (uint32_t)(sizeof(se_wrap_key_t)
                               + QUOTE_IV_SIZE
                               + sizeof(uint32_t)
                               + sign_size
                               + sizeof(sgx_mac_t));

    /* Make the signature. */
    ret = qe_epid_sign(p_epid_context,
                       plaintext,
                       &basename,
                       emp_sig_rl ? ((const se_sig_rl_t *)emp_sig_rl)->sig_rl.bk
                                    : NULL,
                       &sig_rl_header,
                       &ec_signature,
                       p_enclave_report,
                       p_nonce,
                       p_qe_report,
                       emp_quote,
                       &quote_body,
                       (uint32_t)sign_size);
    if(AE_SUCCESS != ret)
    {
        // Only need to clean the buffer after the fixed length part.
        memset_s(emp_quote + sizeof(sgx_quote_t), quote_size - sizeof(sgx_quote_t),
                 0, quote_size - sizeof(sgx_quote_t));
        goto CLEANUP;
    }

    memcpy(emp_quote, &quote_body, sizeof(sgx_quote_t));

CLEANUP:
    if(p_epid_context)
		epid_member_delete(&p_epid_context);
    return ret;
}
Example #11
0
extern "C" sgx_status_t sgx_mac_aadata_ex(const uint16_t key_policy,
                                            const sgx_attributes_t attribute_mask,
                                            const sgx_misc_select_t misc_mask,
                                            const uint32_t additional_MACtext_length,
                                            const uint8_t *p_additional_MACtext,
                                            const uint32_t sealed_data_size,
                                            sgx_sealed_data_t *p_sealed_data)
{
    sgx_status_t err = SGX_ERROR_UNEXPECTED;
    sgx_report_t report;
    sgx_key_id_t keyID;
    sgx_key_request_t tmp_key_request;
    uint8_t payload_iv[SGX_SEAL_IV_SIZE];
    memset(&payload_iv, 0, sizeof(payload_iv));

    uint32_t sealedDataSize = sgx_calc_sealed_data_size(additional_MACtext_length, 0);
    // Check for overflow
    if (sealedDataSize == UINT32_MAX)
    {
        return SGX_ERROR_INVALID_PARAMETER;
    }

    //
    // Check parameters
    //
    // check key_request->key_policy reserved bits are not set and one of policy bits are set
    if ((key_policy & ~(SGX_KEYPOLICY_MRENCLAVE | SGX_KEYPOLICY_MRSIGNER)) ||
        ((key_policy & (SGX_KEYPOLICY_MRENCLAVE | SGX_KEYPOLICY_MRSIGNER)) == 0))
    {
        return SGX_ERROR_INVALID_PARAMETER;
    }
    if ((attribute_mask.flags & 0x3) != 0x3)
    {
        return SGX_ERROR_INVALID_PARAMETER;
    }
    // The AAD must be provided
    if ((additional_MACtext_length == 0) || (p_additional_MACtext == NULL))
    {
        return SGX_ERROR_INVALID_PARAMETER;
    }
    // Ensure AAD does not cross enclave boundary
    if (!(sgx_is_within_enclave(p_additional_MACtext, additional_MACtext_length) ||
        sgx_is_outside_enclave(p_additional_MACtext, additional_MACtext_length)))
    {
        return SGX_ERROR_INVALID_PARAMETER;
    }
    // Ensure sealed data blob is within an enclave during the sealing process
    if ((p_sealed_data == NULL) || (!sgx_is_within_enclave(p_sealed_data, sealed_data_size)))
    {
        return SGX_ERROR_INVALID_PARAMETER;
    }
    if (sealedDataSize != sealed_data_size)
    {
        return SGX_ERROR_INVALID_PARAMETER;
    }
    memset(&report, 0, sizeof(sgx_report_t));
    memset(p_sealed_data, 0, sealedDataSize);
    memset(&keyID, 0, sizeof(sgx_key_id_t));
    memset(&tmp_key_request, 0, sizeof(sgx_key_request_t));

    // Get the report to obtain isv_svn and cpu_svn
    err = sgx_create_report(NULL, NULL, &report);
    if (err != SGX_SUCCESS)
    {
        goto clear_return;
    }

    // Get a random number to populate the key_id of the key_request
    err = sgx_read_rand(reinterpret_cast<uint8_t *>(&keyID), sizeof(sgx_key_id_t));
    if (err != SGX_SUCCESS)
    {
        goto clear_return;
    }

    memcpy(&(tmp_key_request.cpu_svn), &(report.body.cpu_svn), sizeof(sgx_cpu_svn_t));
    memcpy(&(tmp_key_request.isv_svn), &(report.body.isv_svn), sizeof(sgx_isv_svn_t));
    tmp_key_request.key_name = SGX_KEYSELECT_SEAL;
    tmp_key_request.key_policy = key_policy;
    tmp_key_request.attribute_mask.flags = attribute_mask.flags;
    tmp_key_request.attribute_mask.xfrm = attribute_mask.xfrm;
    memcpy(&(tmp_key_request.key_id), &keyID, sizeof(sgx_key_id_t));
    tmp_key_request.misc_mask = misc_mask;

    err = sgx_seal_data_iv(additional_MACtext_length, p_additional_MACtext,
        0, NULL, payload_iv, &tmp_key_request, p_sealed_data);

    if (err == SGX_SUCCESS)
    {
        // Copy data from the temporary key request buffer to the sealed data blob
        memcpy(&(p_sealed_data->key_request), &tmp_key_request, sizeof(sgx_key_request_t));
    }

clear_return:
    // Clear temp state
    memset_s(&report, sizeof(sgx_report_t), 0, sizeof(sgx_report_t));
    memset_s(&keyID, sizeof(sgx_key_id_t), 0, sizeof(sgx_key_id_t));
    return err;
}
Example #12
0
extern "C" sgx_status_t sgx_unmac_aadata(const sgx_sealed_data_t *p_sealed_data,
                                        uint8_t *p_additional_MACtext,
                                        uint32_t *p_additional_MACtext_length)
{
    sgx_status_t err = SGX_ERROR_UNEXPECTED;
    // Ensure the the sgx_sealed_data_t members are all inside enclave before using them.
    if ((p_sealed_data == NULL) || (!sgx_is_within_enclave(p_sealed_data, sizeof(sgx_sealed_data_t))))
    {
        return SGX_ERROR_INVALID_PARAMETER;
    }

    // If using this API, the sealed blob must have no encrypted data. 
    // So the encryt_text_length must be 0.
    uint32_t encrypt_text_length = sgx_get_encrypt_txt_len(p_sealed_data);
    if (encrypt_text_length != 0)
    {
        return SGX_ERROR_MAC_MISMATCH; // Return error indicating the blob is corrupted
    }

    // The sealed blob must have AAD. So the add_text_length must not be 0.
    uint32_t add_text_length = sgx_get_add_mac_txt_len(p_sealed_data);
    if (add_text_length == UINT32_MAX || add_text_length == 0)
    {
        return SGX_ERROR_MAC_MISMATCH; // Return error indicating the blob is corrupted
    }
    uint32_t sealedDataSize = sgx_calc_sealed_data_size(add_text_length, encrypt_text_length);
    if (sealedDataSize == UINT32_MAX)
    {
        return SGX_ERROR_MAC_MISMATCH; // Return error indicating the blob is corrupted
    }

    //
    // Check parameters
    //
    // Ensure sealed data blob is within an enclave during the sealing process
    if (!sgx_is_within_enclave(p_sealed_data, sealedDataSize))
    {
        return SGX_ERROR_INVALID_PARAMETER;
    }
    if (p_additional_MACtext == NULL || p_additional_MACtext_length == NULL)
    {
        return SGX_ERROR_INVALID_PARAMETER;
    }

    // Ensure AAD does not cross enclave boundary
    if (!(sgx_is_within_enclave(p_additional_MACtext, add_text_length) || 
        sgx_is_outside_enclave(p_additional_MACtext, add_text_length)))
    {
        return SGX_ERROR_INVALID_PARAMETER;
    }

    uint32_t additional_MACtext_length = *p_additional_MACtext_length;
    if (additional_MACtext_length < add_text_length) {
        return SGX_ERROR_INVALID_PARAMETER;
    }

    err = sgx_unseal_data_helper(p_sealed_data, p_additional_MACtext, add_text_length,
        NULL, encrypt_text_length);
    if (err == SGX_SUCCESS)
    {
        *p_additional_MACtext_length = add_text_length;
    }
    return err;
}
ae_error_t prepare_for_certificate_provisioning
(
    /*in */ UINT64  nonce64,
    /*in */ const sgx_target_info_t*     pTargetInfo,
    /*in */ UINT16  nMax_CSR_pse,
    /*out*/ UINT8*  pCSR_pse,
    /*out*/ UINT16* pnLen_CSR_pse,
    /*out*/ sgx_report_t*          pREPORT,
    /*i/o*/ pairing_blob_t* pPairingBlob
)
{
    // Flow:  1) Check pointers for buffer data sizes
    //        2) If buffers are too small, return and tell caller size required
    //        3) Validate pointers and ensure buffers are within the enclave
    //        4) Generate a new private/public ECDSA key pair
    //        5) Request signed CSR template
    //        6) Calculate HASH_pse of (CSR_pse || nonce64)
    //        7) Generate REPORT with HASH_pse as the REPORTDATA, targeting QE
    //        8) Copy private key and public key into unsealed_pairing buffer
    //        9) Seal pairing blob
    //       10) Return Sealed pairing blob, generated CSR, REPORT, and status

    ae_error_t status = AE_FAILURE;

    pairing_data_t pairingData;
    EcDsaPrivKey privateKey;
    EcDsaPubKey publicKey;
    uint8_t     temp_instance_id[16];

    SignCSR CSR;

    size_t nMaxSizeCSR = CSR.GetMaxSize();
    sgx_ecc_state_handle_t csr_ecc_handle = NULL;

    memset(&pairingData, 0, sizeof(pairingData));

    /////////////////////////////////////////////////////////////////

    do
    {
        //*********************************************************************
        // Validate pointers and sizes
        //*********************************************************************
        BREAK_IF_TRUE((NULL == pPairingBlob),
            status, PSE_PR_BAD_POINTER_ERROR);

        // save SW_INSTANCE_ID
        memcpy(temp_instance_id, pPairingBlob->plaintext.pse_instance_id, sizeof(temp_instance_id));

        {

            BREAK_IF_TRUE((NULL == pTargetInfo),
                status, PSE_PR_BAD_POINTER_ERROR);

            BREAK_IF_TRUE((NULL == pREPORT),
                status, PSE_PR_BAD_POINTER_ERROR);

            BREAK_IF_TRUE((NULL == pCSR_pse || NULL == pnLen_CSR_pse),
                status, PSE_PR_BAD_POINTER_ERROR);

            BREAK_IF_TRUE((nMax_CSR_pse < nMaxSizeCSR),
                status, PSE_PR_PARAMETER_ERROR);

            BREAK_IF_FALSE(sgx_is_within_enclave(pCSR_pse, nMaxSizeCSR), status, PSE_PR_BAD_POINTER_ERROR);

            //*********************************************************************
            // Generate a new ECDSA Key Pair
            //*********************************************************************
            
            sgx_status_t sgx_status = sgx_ecc256_open_context(&csr_ecc_handle);
            BREAK_IF_TRUE((SGX_ERROR_OUT_OF_MEMORY == sgx_status), status, PSE_PR_INSUFFICIENT_MEMORY_ERROR);
            BREAK_IF_TRUE((SGX_SUCCESS != sgx_status), status, PSE_PR_KEY_PAIR_GENERATION_ERROR);

            sgx_status = sgx_ecc256_create_key_pair((sgx_ec256_private_t *)privateKey, (sgx_ec256_public_t*)publicKey, csr_ecc_handle);
            BREAK_IF_TRUE((SGX_SUCCESS != sgx_status), status, PSE_PR_KEY_PAIR_GENERATION_ERROR);

            *pnLen_CSR_pse = (uint16_t)nMaxSizeCSR;

            //*********************************************************************
            // Get a signed Certificate Signing Request from the template
            //*********************************************************************
            status = CSR.GetSignedTemplate(&privateKey, &publicKey, csr_ecc_handle,  pCSR_pse, pnLen_CSR_pse);
            BREAK_IF_FAILED(status);

            //*********************************************************************
            // Calculate HASH_pse of (CSR_pse || nonce64)
            //*********************************************************************
            PrepareHashSHA256 hash;
            SHA256_HASH computedHash;
            status = hash.Update(pCSR_pse, *pnLen_CSR_pse);
            BREAK_IF_FAILED(status);
            status = hash.Update(&nonce64, sizeof(nonce64));
            BREAK_IF_FAILED(status);
            status = hash.Finalize(&computedHash);
            BREAK_IF_FAILED(status);

            //*********************************************************************
            // Generate a REPORT with HASH_pse
            //*********************************************************************
            sgx_report_data_t report_data = {{0}};
            memcpy(&report_data, &computedHash, sizeof(computedHash));
            if (SGX_SUCCESS != sgx_create_report(const_cast<sgx_target_info_t*>(pTargetInfo), 
                &report_data, (sgx_report_t*)pREPORT))
            {
                status = PSE_PR_CREATE_REPORT_ERROR;
                break;
            }

            //*********************************************************************
            // Try to unseal the pairing data
            //*********************************************************************
            status = UnsealPairingBlob(pPairingBlob, &pairingData);
            if (AE_FAILED(status))
                memset_s(&pairingData, sizeof(pairingData), 0, sizeof(pairingData));

            //*********************************************************************
            // Seal ECDSA Verifier Private Key into blob
            //*********************************************************************

            memcpy(pairingData.secret_data.VerifierPrivateKey, &privateKey, sizeof(EcDsaPrivKey));
        
        } // "Public" PSE Cert

        // Set pairingData.plaintext.pse_instance_id using saved temp_instance_id
        memcpy(pairingData.plaintext.pse_instance_id, temp_instance_id, sizeof(pairingData.plaintext.pse_instance_id));

        status = SealPairingBlob(&pairingData, pPairingBlob);
        BREAK_IF_FAILED(status);

        //*********************************************************************
        // WE PASSED ALL BARRIERS TO SUCCESS
        //*********************************************************************

        status = AE_SUCCESS;

//        OutputOctets("::tPrepareForCertificateProvisioning:: New CSR generated", NULL, 0);

    } while (false);

    // Defense-in-depth: clear the data on stack that contains enclave secret.
    memset_s(&pairingData, sizeof(pairingData), 0, sizeof(pairingData));
    memset_s(&privateKey, sizeof(privateKey), 0, sizeof(privateKey));

    if (csr_ecc_handle != NULL) sgx_ecc256_close_context(csr_ecc_handle);

    return map_error_for_return(status);

}
Example #14
0
void ecall_pointer_in(int *val)
{
    if (sgx_is_within_enclave(val, sizeof(int)) != 1)
        abort();
    *val = 1234;
}
Example #15
0
sgx_status_t sgx_get_key(const sgx_key_request_t *key_request, sgx_key_128bit_t *key)
{
    sgx_status_t err = SGX_ERROR_UNEXPECTED;
    void *buffer = NULL;
    size_t size = 0, buf_ptr = 0;
    sgx_key_request_t *tmp_key_request = NULL;
    sgx_key_128bit_t *tmp_key = NULL;
    egetkey_status_t egetkey_status = EGETKEY_SUCCESS;
    int i = 0;
    const sgx_report_t *report = NULL;
    // check parameters
    //
    // key_request must be within the enclave
    if(!key_request || !sgx_is_within_enclave(key_request, sizeof(*key_request)))
    {
        err = SGX_ERROR_INVALID_PARAMETER;
        goto CLEANUP;
    }

    if (key_request->reserved1 != 0)
    {
        err = SGX_ERROR_INVALID_PARAMETER;
        goto CLEANUP;
    }

    for (i=0; i<SGX_KEY_REQUEST_RESERVED2_BYTES; ++i)
    {
        if (key_request->reserved2[i] != 0)
        {
            err = SGX_ERROR_INVALID_PARAMETER;
            goto CLEANUP;
        }
    }

    // key must be within the enclave
    if(!key || !sgx_is_within_enclave(key, sizeof(*key)))
    {
        err = SGX_ERROR_INVALID_PARAMETER;
        goto CLEANUP;
    }
    // check key_request->key_policy reserved bits
    if(key_request->key_policy & ~(SGX_KEYPOLICY_MRENCLAVE | SGX_KEYPOLICY_MRSIGNER | (KEY_POLICY_KSS)))
    {
        err = SGX_ERROR_INVALID_PARAMETER;
        goto CLEANUP;
    }

    // check if KSS flag is disabled but KSS related policy or config_svn is set
    report = sgx_self_report();
    if (!(report->body.attributes.flags & SGX_FLAGS_KSS) &&
        ((key_request->key_policy & KEY_POLICY_KSS) || key_request->config_svn > 0))
    {
        err = SGX_ERROR_INVALID_PARAMETER;
        goto CLEANUP;
    }

    // allocate memory
    // 
    // To minimize the effort of memory management, the two elements allocation 
    // are combined in a single malloc. The calculation for the required size has
    // an assumption, that
    // the elements should be allocated in descending order of the alignment size. 
    //
    // If the alignment requirements are changed, the allocation order needs to
    // change accordingly.
    //
    // Current allocation order is:
    //     key_request -> key
    //
    // key_request: 512-byte aligned, 512-byte length
    // key:          16-byte aligned,  16-byte length
    size = ROUND_TO(sizeof(*key_request), KEY_REQUEST_ALIGN_SIZE) + ROUND_TO(sizeof(*key), KEY_ALIGN_SIZE);
    size += MAX(KEY_REQUEST_ALIGN_SIZE, KEY_ALIGN_SIZE) - 1;

    buffer = malloc(size);
    if(buffer == NULL)
    {
        err = SGX_ERROR_OUT_OF_MEMORY;
        goto CLEANUP;
    }
    memset(buffer, 0, size);
    buf_ptr = reinterpret_cast<size_t>(buffer);

    buf_ptr = ROUND_TO(buf_ptr, KEY_REQUEST_ALIGN_SIZE);
    tmp_key_request = reinterpret_cast<sgx_key_request_t *>(buf_ptr);
    buf_ptr += sizeof(*tmp_key_request);

    buf_ptr = ROUND_TO(buf_ptr, KEY_ALIGN_SIZE);
    tmp_key = reinterpret_cast<sgx_key_128bit_t *>(buf_ptr);

    // Copy data from user buffer to the aligned memory
    memcpy_s(tmp_key_request, sizeof(*tmp_key_request), key_request, sizeof(*key_request));

    // Do EGETKEY
    egetkey_status = (egetkey_status_t) do_egetkey(tmp_key_request, tmp_key);
    switch(egetkey_status)
    {
    case EGETKEY_SUCCESS:
        err = SGX_SUCCESS;
        break;
    case  EGETKEY_INVALID_ATTRIBUTE:
        err =  SGX_ERROR_INVALID_ATTRIBUTE;
        break;
    case EGETKEY_INVALID_CPUSVN:
        err =  SGX_ERROR_INVALID_CPUSVN;
        break;
    case EGETKEY_INVALID_ISVSVN:
        err = SGX_ERROR_INVALID_ISVSVN;
        break;
    case EGETKEY_INVALID_KEYNAME:
        err = SGX_ERROR_INVALID_KEYNAME;
        break;
    default:
        err = SGX_ERROR_UNEXPECTED;
        break;
    }


CLEANUP:
    if((SGX_SUCCESS != err) && (NULL != key))
    {
        // The key buffer should be filled with random number.
        // If sgx_read_rand returns failure, let the key buffer untouched
        sgx_read_rand(reinterpret_cast<uint8_t *>(key), sizeof(*key));
    }
    else if(NULL != key)
    {
        // Copy data to the user buffer
        memcpy_s(key, sizeof(*key), tmp_key, sizeof(*tmp_key));
    }

    // cleanup
    if(buffer)
    {
        memset_s(buffer, size, 0, size);
        free(buffer);
    }

    return err;
}