Esempio n. 1
0
/*
 * An internal function used to verify EPID Blob, get EPID Group Cert
 * and get EPID context, at the same time, you can check whether EPID blob has
 * been resealed.
 *
 * @param p_blob[in, out] Pointer to EPID Blob.
 * @param p_is_resealed[out] Whether the EPID Blob has been resealed.
 * @param create_context[in] Flag indicates create EPID context or not.
 * @param plaintext_epid_data[out] Used to get the plaintext part of epid blob
 * @param pp_epid_context[out] Used to get the pointer of the EPID context.
 * @param p_cpusvn[out] Return the raw CPUSVN.
 * @return ae_error_t AE_SUCCESS or other error cases.
 */
static ae_error_t verify_blob_internal(
    uint8_t *p_blob,
    uint32_t blob_size,
    uint8_t *p_is_resealed,
    uint32_t create_context,
    se_plaintext_epid_data_sdk_t& plaintext_epid_data,
    MemberCtx **pp_epid_context,
    sgx_cpu_svn_t *p_cpusvn)
{
    ae_error_t ret = QE_UNEXPECTED_ERROR;
    sgx_status_t se_ret = SGX_SUCCESS;
    uint8_t resealed = FALSE;
    se_secret_epid_data_sdk_t secret_epid_data;
    se_plaintext_epid_data_sik_t plaintext_old_format;
    uint32_t plaintext_length;
    int is_old_format = 0;
    uint32_t decryptedtext_length = sizeof(secret_epid_data);
    sgx_sealed_data_t *p_epid_blob = (sgx_sealed_data_t *)p_blob;
    uint8_t local_epid_blob[sizeof(*p_epid_blob)
                            + sizeof(secret_epid_data)
                            + sizeof(plaintext_epid_data)]
                            = {0};
    MemberCtx *p_ctx = NULL;

    do {
        // We will use plaintext_old_format as buffer to hold the output of sgx_unseal_data.
        // It can be se_plaintext_epid_data_sik_t or se_plaintext_epid_data_sdk_t.
        // We use the static assert to reassure plaintext_old_format is big enough.
        // If someone changed the definition of these 2 structures and break current assumption,
        // it will report error in compile time.
        se_static_assert(sizeof(plaintext_old_format) >= sizeof(plaintext_epid_data));

        if (sgx_get_encrypt_txt_len(p_epid_blob) != sizeof(se_secret_epid_data_sdk_t) &&
            sgx_get_encrypt_txt_len(p_epid_blob) != sizeof(se_secret_epid_data_sik_t)) {
            return QE_EPIDBLOB_ERROR;
        }
        plaintext_length = sgx_get_add_mac_txt_len(p_epid_blob);
        if (plaintext_length != sizeof(se_plaintext_epid_data_sik_t) &&
            plaintext_length != sizeof(se_plaintext_epid_data_sdk_t))
        {
            return QE_EPIDBLOB_ERROR;
        }

        memset(&secret_epid_data, 0, sizeof(secret_epid_data));
        memset(&plaintext_epid_data, 0, sizeof(plaintext_epid_data));
        memset(&plaintext_old_format, 0, sizeof(plaintext_old_format));

        se_ret = sgx_unseal_data(p_epid_blob,
            (uint8_t *)&plaintext_old_format, // The unsealed plaintext can be old or new format, the buffer is defined as old format because it is bigger
            &plaintext_length,
            (uint8_t *)&secret_epid_data,
            &decryptedtext_length);
        BREAK_IF_TRUE(SGX_SUCCESS != se_ret, ret, QE_EPIDBLOB_ERROR);

        //QE will support both epid blob with/without member precomputation
        //If the epid blob without member precomputation is used, QE will generate member precomputation and reseal epid blob
        //blob_type and key_version are always first two fields of plaintext in both format
        BREAK_IF_TRUE((plaintext_old_format.seal_blob_type != PVE_SEAL_EPID_KEY_BLOB)
            || (plaintext_old_format.epid_key_version != EPID_KEY_BLOB_VERSION_SDK&&
                plaintext_old_format.epid_key_version != EPID_KEY_BLOB_VERSION_SIK),
            ret, QE_EPIDBLOB_ERROR);

        // Only 2 combinations are legitimate for the tuple epid_key_version|decryptedtext_length|plaintext_length:
        // EPID_KEY_BLOB_VERSION_SIK|sizeof(se_secret_epid_data_sik_t)|sizeof(se_plaintext_epid_data_sik_t)
        // EPID_KEY_BLOB_VERSION_SDK|sizeof(se_secret_epid_data_sdk_t)|sizeof(se_plaintext_epid_data_sdk_t)
        BREAK_IF_TRUE((plaintext_old_format.epid_key_version == EPID_KEY_BLOB_VERSION_SIK &&
            (decryptedtext_length != sizeof(se_secret_epid_data_sik_t) || plaintext_length != sizeof(se_plaintext_epid_data_sik_t))) ||
            (plaintext_old_format.epid_key_version == EPID_KEY_BLOB_VERSION_SDK &&
            (decryptedtext_length != sizeof(se_secret_epid_data_sdk_t) || plaintext_length != sizeof(se_plaintext_epid_data_sdk_t))),
            ret, QE_EPIDBLOB_ERROR);

        // If the input epid blob is in sik format, we will upgrade it to sdk version
        if (plaintext_old_format.epid_key_version == EPID_KEY_BLOB_VERSION_SIK) {
            plaintext_epid_data.seal_blob_type = PVE_SEAL_EPID_KEY_BLOB;
            plaintext_epid_data.epid_key_version = EPID_KEY_BLOB_VERSION_SDK;
            memcpy(&plaintext_epid_data.equiv_cpu_svn, &plaintext_old_format.equiv_cpu_svn, sizeof(plaintext_old_format.equiv_cpu_svn));
            memcpy(&plaintext_epid_data.equiv_pve_isv_svn, &plaintext_old_format.equiv_pve_isv_svn, sizeof(plaintext_old_format.equiv_pve_isv_svn));
            memcpy(&plaintext_epid_data.epid_group_cert, &plaintext_old_format.epid_group_cert, sizeof(plaintext_old_format.epid_group_cert));
            memcpy(&plaintext_epid_data.qsdk_exp, &plaintext_old_format.qsdk_exp, sizeof(plaintext_old_format.qsdk_exp));
            memcpy(&plaintext_epid_data.qsdk_mod, &plaintext_old_format.qsdk_mod, sizeof(plaintext_old_format.qsdk_mod));
            memcpy(&plaintext_epid_data.epid_sk, &plaintext_old_format.epid_sk, sizeof(plaintext_old_format.epid_sk));
            plaintext_epid_data.xeid = plaintext_old_format.xeid;
            memset(&secret_epid_data.member_precomp_data, 0, sizeof(secret_epid_data.member_precomp_data));
            is_old_format = 1;
            //PrivKey of secret_epid_data are both in offset 0 so that we need not move it
        }
        else {//SDK version format
            memcpy(&plaintext_epid_data, &plaintext_old_format, sizeof(plaintext_epid_data));
        }

        /* Create report to get current cpu_svn and isv_svn. */
        sgx_report_t report;
        memset(&report, 0, sizeof(report));
        se_ret = sgx_create_report(NULL, NULL, &report);
        BREAK_IF_TRUE(SGX_SUCCESS != se_ret, ret, QE_UNEXPECTED_ERROR);

        /* Get the random function pointer. */
        BitSupplier rand_func = epid_random_func;

        /* Create EPID member context if required. PvE is responsible for verifying
        the Cert signature before storing them in the EPID blob. */
        if (create_context || is_old_format)
        {
            EpidStatus epid_ret = kEpidNoErr;
            epid_ret = epid_member_create(rand_func, NULL, NULL, &p_ctx);
            BREAK_IF_TRUE(kEpidNoErr != epid_ret, ret, QE_UNEXPECTED_ERROR);

            epid_ret = EpidProvisionKey(p_ctx,
                &(plaintext_epid_data.epid_group_cert),
                (PrivKey*)&(secret_epid_data.epid_private_key),
                is_old_format ? NULL : &secret_epid_data.member_precomp_data);
            BREAK_IF_TRUE(kEpidNoErr != epid_ret, ret, QE_UNEXPECTED_ERROR);

            // start member
            epid_ret = EpidMemberStartup(p_ctx);
            BREAK_IF_TRUE(kEpidNoErr != epid_ret, ret, QE_UNEXPECTED_ERROR);

            if (is_old_format)
            {
                epid_ret = EpidMemberWritePrecomp(p_ctx, &secret_epid_data.member_precomp_data);
                BREAK_IF_TRUE(kEpidNoErr != epid_ret, ret, QE_UNEXPECTED_ERROR);
            }
        }

        /* Update the Key Blob using the SEAL Key for the current TCB if the TCB is
           upgraded after the Key Blob is generated. Here memcmp cpu_svns might be
           different even though they're actually same, but for defense in depth we
           will keep this comparison here. And we will also upgrade old format EPID
           blob to new format here. */
        if ((memcmp(&report.body.cpu_svn, &p_epid_blob->key_request.cpu_svn,
            sizeof(report.body.cpu_svn)))
            || (report.body.isv_svn != p_epid_blob->key_request.isv_svn)
            || plaintext_old_format.epid_key_version == EPID_KEY_BLOB_VERSION_SIK)
        {
            se_ret = sgx_seal_data(sizeof(plaintext_epid_data),
                (uint8_t *)&plaintext_epid_data,
                sizeof(secret_epid_data),
                (uint8_t *)&secret_epid_data,
                SGX_TRUSTED_EPID_BLOB_SIZE_SDK,
                (sgx_sealed_data_t *)local_epid_blob);
            BREAK_IF_TRUE(SGX_SUCCESS != se_ret, ret, QE_UNEXPECTED_ERROR);

            memcpy(p_epid_blob, local_epid_blob, blob_size);
            resealed = TRUE;
        }
        *p_is_resealed = resealed;
        memcpy(p_cpusvn, &report.body.cpu_svn, sizeof(*p_cpusvn));
        ret = AE_SUCCESS;
    }
    while (false);

    // Clear the output buffer to make sure nothing leaks.
    memset_s(&secret_epid_data, sizeof(secret_epid_data), 0,
        sizeof(secret_epid_data));
    if (AE_SUCCESS != ret) {
        if (p_ctx)
            epid_member_delete(&p_ctx);
    }
    else if (!create_context) {
        if (p_ctx)
            epid_member_delete(&p_ctx);
    }
    else {
        *pp_epid_context = p_ctx;
    }

    return ret;
}
Esempio n. 2
0
extern "C" sgx_status_t sgx_ra_proc_msg2_trusted(
    sgx_ra_context_t context,
    const sgx_ra_msg2_t *p_msg2,            //(g_b||spid||quote_type|| KDF_ID ||sign_gb_ga||cmac||sig_rl_size||sig_rl)
    const sgx_target_info_t *p_qe_target,
    sgx_report_t *p_report,
    sgx_quote_nonce_t* p_nonce)
{
    sgx_status_t se_ret = SGX_ERROR_UNEXPECTED;
    //p_msg2[in] p_qe_target[in] p_report[out] p_nonce[out] in EDL file
    if(vector_size(&g_ra_db) <= context
       || !p_msg2
       || !p_qe_target
       || !p_report
       || !p_nonce)
        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;

    sgx_ec256_private_t a;
    memset(&a, 0, sizeof(a));
    // Create gb_ga
    sgx_ec256_public_t gb_ga[2];
    sgx_ec256_public_t sp_pubkey;
    sgx_ec_key_128bit_t smkey = {0};
    sgx_ec_key_128bit_t skey = {0};
    sgx_ec_key_128bit_t mkey = {0};
    sgx_ec_key_128bit_t vkey = {0};
    sgx_ra_derive_secret_keys_t ra_key_cb = NULL;

    memset(&gb_ga[0], 0, sizeof(gb_ga));
    sgx_spin_lock(&item->item_lock);
    //sgx_ra_get_ga must have been called
    if (item->state != ra_get_gaed)
    {
        sgx_spin_unlock(&item->item_lock);
        return SGX_ERROR_INVALID_STATE;
    }
    memcpy(&a, &item->a, sizeof(a));
    memcpy(&gb_ga[1], &item->g_a, sizeof(gb_ga[1]));
    memcpy(&sp_pubkey, &item->sp_pubkey, sizeof(sp_pubkey));
    ra_key_cb = DEC_KDF_POINTER(item->derive_key_cb);
    sgx_spin_unlock(&item->item_lock);
    memcpy(&gb_ga[0], &p_msg2->g_b, sizeof(gb_ga[0]));

    sgx_ecc_state_handle_t ecc_state = NULL;

    // ecc_state need to be freed when exit.
    se_ret = sgx_ecc256_open_context(&ecc_state);
    if (SGX_SUCCESS != se_ret)
    {
        if(SGX_ERROR_OUT_OF_MEMORY != se_ret)
            se_ret = SGX_ERROR_UNEXPECTED;
        return se_ret;
    }

    sgx_ec256_dh_shared_t dh_key;
    memset(&dh_key, 0, sizeof(dh_key));
    sgx_ec256_public_t* p_msg2_g_b = const_cast<sgx_ec256_public_t*>(&p_msg2->g_b);
    se_ret = sgx_ecc256_compute_shared_dhkey(&a,
        (sgx_ec256_public_t*)p_msg2_g_b,
        &dh_key, ecc_state);
    if(SGX_SUCCESS != se_ret)
    {
        if (SGX_ERROR_OUT_OF_MEMORY != se_ret)
            se_ret = SGX_ERROR_UNEXPECTED;
        sgx_ecc256_close_context(ecc_state);
        return se_ret;
    }
    // Verify signature of gb_ga
    uint8_t result;
    sgx_ec256_signature_t* p_msg2_sign_gb_ga = const_cast<sgx_ec256_signature_t*>(&p_msg2->sign_gb_ga);
    se_ret = sgx_ecdsa_verify((uint8_t *)&gb_ga, sizeof(gb_ga),
        &sp_pubkey,
        p_msg2_sign_gb_ga,
        &result, ecc_state);
    if(SGX_SUCCESS != se_ret)
    {
        if (SGX_ERROR_OUT_OF_MEMORY != se_ret)
            se_ret = SGX_ERROR_UNEXPECTED;
        sgx_ecc256_close_context(ecc_state);
        return se_ret;
    }
    if(SGX_EC_VALID != result)
    {
        sgx_ecc256_close_context(ecc_state);
        return SGX_ERROR_INVALID_SIGNATURE;
    }

    do
    {
        if(NULL != ra_key_cb)
        {
            se_ret = ra_key_cb(&dh_key,
                               p_msg2->kdf_id,
                               &smkey,
                               &skey,
                               &mkey,
                               &vkey);
            if (SGX_SUCCESS != se_ret)
            {
                if(SGX_ERROR_OUT_OF_MEMORY != se_ret &&
                    SGX_ERROR_INVALID_PARAMETER != se_ret &&
                    SGX_ERROR_KDF_MISMATCH != se_ret)
                    se_ret = SGX_ERROR_UNEXPECTED;
                break;
            }
        }
        else if (p_msg2->kdf_id == 0x0001)
        {
            se_ret = derive_key(&dh_key, "SMK", (uint32_t)(sizeof("SMK") -1), &smkey);
            if (SGX_SUCCESS != se_ret)
            {
                if(SGX_ERROR_OUT_OF_MEMORY != se_ret)
                    se_ret = SGX_ERROR_UNEXPECTED;
                break;
            }
            se_ret = derive_key(&dh_key, "SK", (uint32_t)(sizeof("SK") -1), &skey);
            if (SGX_SUCCESS != se_ret)
            {
                if(SGX_ERROR_OUT_OF_MEMORY != se_ret)
                    se_ret = SGX_ERROR_UNEXPECTED;
                break;
            }

            se_ret = derive_key(&dh_key, "MK", (uint32_t)(sizeof("MK") -1), &mkey);
            if (SGX_SUCCESS != se_ret)
            {
                if(SGX_ERROR_OUT_OF_MEMORY != se_ret)
                    se_ret = SGX_ERROR_UNEXPECTED;
                break;
            }

            se_ret = derive_key(&dh_key, "VK", (uint32_t)(sizeof("VK") -1), &vkey);
            if (SGX_SUCCESS != se_ret)
            {
                if(SGX_ERROR_OUT_OF_MEMORY != se_ret)
                    se_ret = SGX_ERROR_UNEXPECTED;
                break;
            }
        }
        else
        {
            se_ret = SGX_ERROR_KDF_MISMATCH;
            break;
        }

        sgx_cmac_128bit_tag_t mac;
        uint32_t maced_size = offsetof(sgx_ra_msg2_t, mac);

        se_ret = sgx_rijndael128_cmac_msg(&smkey, (const uint8_t *)p_msg2, maced_size, &mac);
        if (SGX_SUCCESS != se_ret)
        {
            if(SGX_ERROR_OUT_OF_MEMORY != se_ret)
                se_ret = SGX_ERROR_UNEXPECTED;
            break;
        }
        //Check mac
        if(0 == consttime_memequal(mac, p_msg2->mac, sizeof(mac)))
        {
            se_ret = SGX_ERROR_MAC_MISMATCH;
            break;
        }

        //create a nonce
        se_ret =sgx_read_rand((uint8_t*)p_nonce, sizeof(sgx_quote_nonce_t));
        if (SGX_SUCCESS != se_ret)
        {
            if(SGX_ERROR_OUT_OF_MEMORY != se_ret)
                se_ret = SGX_ERROR_UNEXPECTED;
            break;
        }

        sgx_spin_lock(&item->item_lock);
        //sgx_ra_get_ga must have been called
        if (item->state != ra_get_gaed)
        {
            se_ret = SGX_ERROR_INVALID_STATE;
            sgx_spin_unlock(&item->item_lock);
            break;
        }
        memcpy(&item->g_b, &p_msg2->g_b, sizeof(item->g_b));
        memcpy(&item->smk_key, smkey, sizeof(item->smk_key));
        memcpy(&item->sk_key, skey, sizeof(item->sk_key));
        memcpy(&item->mk_key, mkey, sizeof(item->mk_key));
        memcpy(&item->vk_key, vkey, sizeof(item->vk_key));
        memcpy(&item->qe_target, p_qe_target, sizeof(sgx_target_info_t));
        memcpy(&item->quote_nonce, p_nonce, sizeof(sgx_quote_nonce_t));
        sgx_report_data_t report_data = {{0}};
        se_static_assert(sizeof(sgx_report_data_t)>=sizeof(sgx_sha256_hash_t));
        // H = SHA256(ga || gb || VK_CMAC)
        uint32_t sha256ed_size = offsetof(ra_db_item_t, sp_pubkey);
        //report_data is 512bits, H is 256bits. The H is in the lower 256 bits of report data while the higher 256 bits are all zeros.
        se_ret = sgx_sha256_msg((uint8_t *)&item->g_a, sha256ed_size,
                                (sgx_sha256_hash_t *)&report_data);
        if(SGX_SUCCESS != se_ret)
        {
            if (SGX_ERROR_OUT_OF_MEMORY != se_ret)
                se_ret = SGX_ERROR_UNEXPECTED;
            sgx_spin_unlock(&item->item_lock);
            break;
        }
        //REPORTDATA = H
        se_ret = sgx_create_report(p_qe_target, &report_data, p_report);
        if (SGX_SUCCESS != se_ret)
        {
            if(SGX_ERROR_OUT_OF_MEMORY != se_ret)
                se_ret = SGX_ERROR_UNEXPECTED;
            sgx_spin_unlock(&item->item_lock);
            break;
        }
        item->state = ra_proc_msg2ed;
        sgx_spin_unlock(&item->item_lock);
    }while(0);
    memset_s(&dh_key, sizeof(dh_key), 0, sizeof(dh_key));
    sgx_ecc256_close_context(ecc_state);
    memset_s(&a, sizeof(sgx_ec256_private_t),0, sizeof(sgx_ec256_private_t));
    memset_s(smkey, sizeof(sgx_ec_key_128bit_t),0, sizeof(sgx_ec_key_128bit_t));
    memset_s(skey, sizeof(sgx_ec_key_128bit_t),0, sizeof(sgx_ec_key_128bit_t));
    memset_s(mkey, sizeof(sgx_ec_key_128bit_t),0, sizeof(sgx_ec_key_128bit_t));
    memset_s(vkey, sizeof(sgx_ec_key_128bit_t),0, sizeof(sgx_ec_key_128bit_t));
    return se_ret;
}
Esempio n. 3
0
/*
 * An internal function used to sign the EPID signature on the quote body.
 * Prefix "emp_" means it is a pointer points memory outside enclave.
 *
 * For quote with SIG-RL
 * |--------------------------------------------------------------------|
 * |sgx_quote_t|wrap_key_t|iv|payload_size|basic_sig|rl_ver|n2|nrp..|mac|
 * |--------------------------------------------------------------------|
 * For quote without SIG-RL
 * |--------------------------------------------------------------|
 * |sgx_quote_t|wrap_key_t|iv|payload_size|basic_sig|rl_ver|n2|mac|
 * |--------------------------------------------------------------|
 *
 * @param p_epid_context[in] Pointer to the EPID context.
 * @param plaintext[in] Reference to the plain text part of EPID blob.
 * @param p_basename[in] The pointer to basename.
 * @param emp_sig_rl_entries[in] The pointer to SIG-RL entries.
 * @param p_sig_rl_header[in] The header of SIG-RL, within EPC.
 * @param p_sig_rl_signature[in] The ecdsa signature of SIG-RL, within EPC.
 * @param p_enclave_report[in] The input isv report.
 * @param p_nonce[in] The input nonce.
 * @param p_qe_report[out] The output buffer for qe_report.
 * @param emp_quote[out] The output buffer for quote.
 * @param p_quote_body[in] The quote body in EPC.
 * @param sign_size[in] size of the signature.
 * @return ae_error_t AE_SUCCESS for success, otherwise for errors.
 */
static ae_error_t qe_epid_sign(
    MemberCtx *p_epid_context,
    const se_plaintext_epid_data_sdk_t& plaintext,
    const sgx_basename_t *p_basename,
    const SigRlEntry *emp_sig_rl_entries,
    se_sig_rl_t *p_sig_rl_header,
    sgx_ec256_signature_t *p_sig_rl_signature,
    const sgx_report_t *p_enclave_report,
    const sgx_quote_nonce_t *p_nonce,
    sgx_report_t *p_qe_report,
    uint8_t *emp_quote,
    const sgx_quote_t *p_quote_body,
    uint32_t sign_size)
{
    ae_error_t ret = AE_SUCCESS;
    sgx_status_t se_ret = SGX_SUCCESS;
    EpidStatus epid_ret = kEpidNoErr;

    se_wrap_key_t wrap_key;
    BasicSignature basic_sig;
    BasicSignature encrypted_basic_sig;
    uint8_t aes_iv[QUOTE_IV_SIZE] = {0};
    uint8_t aes_key[QE_AES_KEY_SIZE] = {0};
    uint8_t aes_tag[SGX_SEAL_TAG_SIZE] = {0};
    sgx_report_data_t qe_report_data = {{0}};
    sgx_target_info_t report_target;
    sgx_ec256_public_t ec_pub_key; // little endian
    se_ae_ecdsa_hash_t sig_rl_hash = {{0}};
    uint8_t ecc_result = SGX_EC_INVALID_SIGNATURE;

    sgx_sha_state_handle_t sha_context = NULL;
    sgx_sha_state_handle_t sha_quote_context = NULL;
    sgx_aes_state_handle_t aes_gcm_state = NULL;
    void *pub_key = NULL;
    size_t pub_key_size = 0;
    uint8_t* pub_key_buffer = NULL;
    sgx_ecc_state_handle_t ecc_handle = NULL;

    memset(&wrap_key, 0, sizeof(wrap_key));
    memset(&basic_sig, 0, sizeof(basic_sig));
    memset(&encrypted_basic_sig, 0, sizeof(encrypted_basic_sig));
    memset(&report_target, 0, sizeof(report_target));
    memset(&ec_pub_key, 0, sizeof(ec_pub_key));

    se_encrypted_sign_t *emp_p = (se_encrypted_sign_t *)
                                (((sgx_quote_t *)emp_quote)->signature);

    uint8_t* emp_nr = NULL;
    uint32_t match = FALSE;

    /* Sign the quote body and get the basic signature*/
    epid_ret = EpidSignBasic(p_epid_context,
               (uint8_t *)const_cast<sgx_quote_t *>(p_quote_body),
               (uint32_t)QE_QUOTE_BODY_SIZE,
               (uint8_t *)const_cast<sgx_basename_t *>(p_basename),
               sizeof(*p_basename),
               &basic_sig,
               NULL); //Random basename, can be NULL if basename is provided
    if(kEpidNoErr != epid_ret)
    {
        ret = QE_UNEXPECTED_ERROR;
        goto CLEANUP;
    }

    /* Prepare the context for SHA256 of quote. */
    if(p_qe_report)
    {
        se_ret = sgx_sha256_init(&sha_quote_context);
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }

        // Update hash for nonce.
        se_ret = sgx_sha256_update((uint8_t *)const_cast<sgx_quote_nonce_t *>(p_nonce),
                                   sizeof(*p_nonce),
                                   sha_quote_context);
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }
        // Update hash for the first part of quote.
        se_ret = sgx_sha256_update((uint8_t *)const_cast<sgx_quote_t *>(p_quote_body),
                                   sizeof(*p_quote_body),
                                   sha_quote_context);
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }
    }

    /* Prepare the context for SHA256 and start calculate the hash of header
     * of SIG-RL. */
    if(emp_sig_rl_entries)
    {
        se_ret = sgx_sha256_init(&sha_context);
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }

        /* Calculate the hash of SIG-RL header. */
        se_ret = sgx_sha256_update((uint8_t *)p_sig_rl_header,
                                   (uint32_t)(sizeof(se_sig_rl_t) - sizeof(SigRlEntry)),
                                   sha_context);
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }
    }

    // Start encrypt the signature.

    /* Get the random wrap key */
    se_ret = sgx_read_rand(aes_key, sizeof(aes_key));
    if(SGX_SUCCESS != se_ret)
    {
        ret = QE_UNEXPECTED_ERROR;
        goto CLEANUP;
    }

    /* Copy the hash of wrap key into output buffer. */
    se_static_assert(sizeof(wrap_key.key_hash) == sizeof(sgx_sha256_hash_t));
    se_ret = sgx_sha256_msg(aes_key, sizeof(aes_key),
                            (sgx_sha256_hash_t *)wrap_key.key_hash);
    if(SGX_SUCCESS != se_ret)
    {
        ret = QE_UNEXPECTED_ERROR;
        goto CLEANUP;
    }

    /* Start encrypt the wrap key by RSA algorithm. */
    se_ret = sgx_create_rsa_pub1_key(sizeof(g_qsdk_pub_key_n),
                                 sizeof(g_qsdk_pub_key_e),
                                 (const unsigned char *)g_qsdk_pub_key_n,
                                 (const unsigned char *)g_qsdk_pub_key_e,
                                 &pub_key);
    if(se_ret != SGX_SUCCESS)
    {
        ret = QE_UNEXPECTED_ERROR;
        goto CLEANUP;
    }

    /* Get output buffer size */
    se_ret = sgx_rsa_pub_encrypt_sha256(pub_key, NULL, &pub_key_size, aes_key, sizeof(aes_key));
    if(SGX_SUCCESS != se_ret)
    {
        ret = QE_UNEXPECTED_ERROR;
        goto CLEANUP;
    }

    se_ret = sgx_rsa_pub_encrypt_sha256(pub_key, wrap_key.encrypted_key, &pub_key_size, aes_key, sizeof(aes_key));
    if(SGX_SUCCESS != se_ret)
    {
        ret = QE_UNEXPECTED_ERROR;
        goto CLEANUP;
    }

    /* Create the random AES IV. */
    se_ret = sgx_read_rand(aes_iv, sizeof(aes_iv));
    if(SGX_SUCCESS != se_ret)
    {
        ret = QE_UNEXPECTED_ERROR;
        goto CLEANUP;
    }

    /* Copy the wrap_key_t into output buffer. */
    memcpy(&emp_p->wrap_key, &wrap_key, sizeof(wrap_key));
    /* Copy the AES IV into output buffer. */
    memcpy(&emp_p->iv, aes_iv, sizeof(aes_iv));
    /* Copy the AES Blob payload size into output buffer. */
    memcpy(&emp_p->payload_size, &sign_size, sizeof(sign_size));


    se_ret = sgx_aes_gcm128_enc_init(
        aes_key,
        aes_iv, //input initial vector. randomly generated value and encryption of different msg should use different iv
        sizeof(aes_iv),   //length of initial vector, usually IV_SIZE
        NULL,//AAD of AES-GCM, it could be NULL
        0,  //length of bytes of AAD
        &aes_gcm_state);
    if(SGX_SUCCESS != se_ret)
    {
        ret = QE_UNEXPECTED_ERROR;
        goto CLEANUP;
    }
    memset_s(aes_key, sizeof(aes_key), 0, sizeof(aes_key));

    /* Encrypt the basic signature. */
    se_ret = sgx_aes_gcm128_enc_update(
        (uint8_t *)&basic_sig,   //start address to data before/after encryption
        sizeof(basic_sig),
        (uint8_t *)&encrypted_basic_sig, //length of data
        aes_gcm_state); //pointer to a state

    if(SGX_SUCCESS != se_ret)
    {
        ret = QE_UNEXPECTED_ERROR;
        goto CLEANUP;
    }

    /* Copy the encrypted basic signature into output buffer. */
    memcpy(&emp_p->basic_sign, &encrypted_basic_sig,
           sizeof(encrypted_basic_sig));

    if(p_qe_report)
    {
        se_ret = sgx_sha256_update((uint8_t *)&wrap_key,
                                   sizeof(wrap_key),
                                   sha_quote_context);
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }
        se_ret = sgx_sha256_update(aes_iv,
                                   sizeof(aes_iv),
                                   sha_quote_context);
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }
        se_ret = sgx_sha256_update((uint8_t *)&sign_size,
                                   sizeof(sign_size),
                                   sha_quote_context);
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }
        se_ret = sgx_sha256_update((uint8_t *)&encrypted_basic_sig,
                                   sizeof(encrypted_basic_sig),
                                   sha_quote_context);
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }
    }

    /* Start process the SIG-RL. */
    if(emp_sig_rl_entries)
    {
        unsigned int entry_count = 0;
        unsigned int i = 0;
        RLver_t encrypted_rl_ver = {{0}};
        RLCount encrypted_n2 = {{0}};
        entry_count = lv_ntohl(p_sig_rl_header->sig_rl.n2);//entry count for big endian to little endian

        // Continue encrypt the output
        se_ret = sgx_aes_gcm128_enc_update(
            (uint8_t *)&(p_sig_rl_header->sig_rl.version),   //start address to data before/after encryption
            sizeof(p_sig_rl_header->sig_rl.version),
            (uint8_t *)&encrypted_rl_ver, //length of data
            aes_gcm_state); //pointer to a state
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }

        se_ret = sgx_aes_gcm128_enc_update(
            (uint8_t *)&(p_sig_rl_header->sig_rl.n2),   //start address to data before/after encryption
            sizeof(p_sig_rl_header->sig_rl.n2),
            (uint8_t *)&encrypted_n2, //length of data
            aes_gcm_state); //pointer to a state
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }

        memcpy(&(emp_p->rl_ver), &encrypted_rl_ver,
               sizeof(encrypted_rl_ver));
        memcpy(&(emp_p->rl_num), &encrypted_n2,
               sizeof(encrypted_n2));
        if(p_qe_report)
        {
            se_ret = sgx_sha256_update((uint8_t *)&encrypted_rl_ver,
                                       sizeof(encrypted_rl_ver),
                                       sha_quote_context);
            if(SGX_SUCCESS != se_ret)
            {
                ret = QE_UNEXPECTED_ERROR;
                goto CLEANUP;
            }
            se_ret = sgx_sha256_update((uint8_t *)&encrypted_n2,
                                       sizeof(encrypted_n2),
                                       sha_quote_context);
            if(SGX_SUCCESS != se_ret)
            {
                ret = QE_UNEXPECTED_ERROR;
                goto CLEANUP;
            }
        }

        /* Start process the SIG-RL entries one by one. */
        emp_nr = emp_p->nrp_mac;
        for (i = 0; i < entry_count; i++, emp_nr += sizeof(NrProof))
        {
            /* Generate non-revoke prove one by one. */
            SigRlEntry entry;
            NrProof temp_nr;
            NrProof encrypted_temp_nr;
            memcpy(&entry, emp_sig_rl_entries + i, sizeof(entry));
            memset_s(&temp_nr, sizeof(temp_nr), 0, sizeof(temp_nr));
            memset_s(&encrypted_temp_nr, sizeof(encrypted_temp_nr), 0, sizeof(encrypted_temp_nr));
            epid_ret = EpidNrProve(p_epid_context,
                (uint8_t *)const_cast<sgx_quote_t *>(p_quote_body),
                (uint32_t)QE_QUOTE_BODY_SIZE,
                (uint8_t *)const_cast<sgx_basename_t *>(p_basename), // basename is required, otherwise it will return kEpidBadArgErr
                sizeof(*p_basename),
                &basic_sig, // Basic signature with 'b' and 'k' in it
                &entry, //Single entry in SigRl composed of 'b' and 'k'
                &temp_nr); // The generated non-revoked proof
            if(kEpidNoErr != epid_ret)
            {
                if(kEpidSigRevokedInSigRl == epid_ret)
                    match = TRUE;
                else
                {
                    ret = QE_UNEXPECTED_ERROR;
                    goto CLEANUP;
                }
            }

            /* Update the hash of SIG-RL */
            se_ret = sgx_sha256_update((uint8_t *)&entry,
                                       sizeof(entry), sha_context);
            if(SGX_SUCCESS != se_ret)
            {
                ret = QE_UNEXPECTED_ERROR;
                goto CLEANUP;
            }

            se_ret = sgx_aes_gcm128_enc_update(
                (uint8_t *)&temp_nr,   //start address to data before/after encryption
                sizeof(encrypted_temp_nr),
                (uint8_t *)&encrypted_temp_nr, //length of data
                aes_gcm_state); //pointer to a state
            if(SGX_SUCCESS != se_ret)
            {
                ret = QE_UNEXPECTED_ERROR;
                goto CLEANUP;
            }

            memcpy(emp_nr, &encrypted_temp_nr, sizeof(encrypted_temp_nr));

            if(p_qe_report)
            {
                se_ret = sgx_sha256_update((uint8_t *)&encrypted_temp_nr,
                                           sizeof(encrypted_temp_nr),
                                           sha_quote_context);
                if(SGX_SUCCESS != se_ret)
                {
                    ret = QE_UNEXPECTED_ERROR;
                    goto CLEANUP;
                }
            }
        }

        /* Get the final hash of the whole SIG-RL. */
        se_ret =  sgx_sha256_get_hash(sha_context,
                                      (sgx_sha256_hash_t *)&sig_rl_hash.hash);
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }

        /* Verify the integrity of SIG-RL by check ECDSA signature. */
        se_static_assert(sizeof(ec_pub_key) == sizeof(plaintext.epid_sk));
        // Both plaintext.epid_sk and ec_pub_key are little endian
        memcpy(&ec_pub_key, plaintext.epid_sk, sizeof(ec_pub_key));

        se_ret = sgx_ecc256_open_context(&ecc_handle);
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }

        // sgx_ecdsa_verify_hash will take ec_pub_key as little endian
        se_ret = sgx_ecdsa_verify_hash((uint8_t*)&(sig_rl_hash.hash),
                            (const sgx_ec256_public_t *)&ec_pub_key,
                            p_sig_rl_signature,
                            &ecc_result,
                            ecc_handle);
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }
        else if(SGX_EC_VALID != ecc_result)
        {
            ret = QE_SIGRL_ERROR;
            goto CLEANUP;
        }
        else if(match)
        {
            ret = QE_REVOKED_ERROR;
            goto CLEANUP;
        }
    }
    else
    {
        se_static_assert(sizeof(emp_p->rl_ver) == sizeof(RLver_t));
        se_static_assert(sizeof(emp_p->rl_num) == sizeof(RLCount));
        uint8_t temp_buf[sizeof(RLver_t) + sizeof(RLCount)] = {0};
        uint8_t encrypted_temp_buf[sizeof(temp_buf)] = {0};

        se_ret = sgx_aes_gcm128_enc_update(
            (uint8_t *)&temp_buf,   //start address to data before/after encryption
            sizeof(encrypted_temp_buf),
            (uint8_t *)&encrypted_temp_buf, //length of data
            aes_gcm_state); //pointer to a state
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }
        /* This will copy both encrypted rl_ver and encrypted rl_num into
           Output buffer. */
        memcpy(&emp_p->rl_ver, &encrypted_temp_buf,
               sizeof(encrypted_temp_buf));

        if(p_qe_report)
        {
            se_ret = sgx_sha256_update((uint8_t *)&encrypted_temp_buf,
                                       sizeof(encrypted_temp_buf),
                                       sha_quote_context);
            if(SGX_SUCCESS != se_ret)
            {
                ret = QE_UNEXPECTED_ERROR;
                goto CLEANUP;
            }
        }
    }

    se_ret = sgx_aes_gcm128_enc_get_mac(aes_tag, aes_gcm_state);
    if(SGX_SUCCESS != se_ret)
    {
        ret = QE_UNEXPECTED_ERROR;
        goto CLEANUP;
    }

    memcpy((uint8_t *)&(emp_p->basic_sign) + sign_size, &aes_tag,
           sizeof(aes_tag));

    if(p_qe_report)
    {
        se_ret = sgx_sha256_update(aes_tag, sizeof(aes_tag),
                                   sha_quote_context);
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }
        se_ret =  sgx_sha256_get_hash(sha_quote_context,
                                      (sgx_sha256_hash_t *)&qe_report_data);
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_UNEXPECTED_ERROR;
            goto CLEANUP;
        }
        memcpy(&(report_target.attributes),
               &(((const sgx_report_t *)p_enclave_report)->body.attributes),
               sizeof(report_target.attributes));
        memcpy(&(report_target.mr_enclave),
               &(((const sgx_report_t *)p_enclave_report)->body.mr_enclave),
               sizeof(report_target.mr_enclave));
        memcpy(&(report_target.misc_select),
            &(((const sgx_report_t *)p_enclave_report)->body.misc_select),
            sizeof(report_target.misc_select));
        se_ret = sgx_create_report(&report_target, &qe_report_data, p_qe_report);
        if(SGX_SUCCESS != se_ret)
        {
            ret = QE_PARAMETER_ERROR;
            goto CLEANUP;
        }
    }

CLEANUP:
    memset_s(aes_key, sizeof(aes_key), 0, sizeof(aes_key));
    sgx_sha256_close(sha_context);
    sgx_sha256_close(sha_quote_context);
    if (aes_gcm_state)
        sgx_aes_gcm_close(aes_gcm_state);
    if (pub_key)
        sgx_free_rsa_key(pub_key, SGX_RSA_PUBLIC_KEY, sizeof(plaintext.qsdk_mod), sizeof(plaintext.qsdk_exp));
    if (pub_key_buffer)
        free(pub_key_buffer);
    if (ecc_handle)
        sgx_ecc256_close_context(ecc_handle);

    return ret;
}
Esempio n. 4
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;
}
Esempio n. 5
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;
}
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);

}
Esempio n. 7
0
//Function to create data for ProvMsg3 generation 
// The sigrl of ProvMsg2 will processed in this function in piece-meal method
//@msg2_blob_input: structure to hold decoded data of ProvMsg2
//@performance_rekey_used[in]: 1 if performance rekey used or 0 if not
//@msg3_parm: structure to hold most information to generate ProvMsg3
//@msg3_output: structure to hold output data to create ProvMsg3
//@emp_epid_sig: output buffer to external memory for variable length EpidSignature
//@epid_sig_buffer_size: size in bytes of buffer emp_epid_sig
//@return PVEC_SUCCESS on success and error code if failed
pve_status_t gen_prov_msg3_data(const proc_prov_msg2_blob_input_t *msg2_blob_input,
                                prov_msg3_parm_t& msg3_parm,
                                uint8_t performance_rekey_used,
                                gen_prov_msg3_output_t *msg3_output,
                                external_memory_byte_t *emp_epid_sig, 
                                uint32_t epid_sig_buffer_size)
{
    pve_status_t ret = PVEC_SUCCESS;
    sgx_status_t sgx_status = SGX_ERROR_UNEXPECTED;
    uint8_t temp_buf[JOIN_PROOF_TLV_TOTAL_SIZE];
    uint8_t *data_to_encrypt = NULL;
    uint8_t  size_to_encrypt = 0;
    uint8_t  pwk2_tlv_buffer[PWK2_TLV_TOTAL_SIZE];
    sgx_key_128bit_t *pwk2=reinterpret_cast<sgx_key_128bit_t *>(pwk2_tlv_buffer+PWK2_TLV_HEADER_SIZE);
    uint8_t report_data_payload[MAC_SIZE + HARD_CODED_JOIN_PROOF_WITH_ESCROW_TLV_SIZE + NONCE_2_SIZE + PEK_MOD_SIZE];
    uint8_t* pdata = &report_data_payload[0];
    sgx_report_data_t report_data = { 0 };
    uint8_t aad[sizeof(GroupId)+sizeof(device_id_t)+CHALLENGE_NONCE_SIZE];
    void *pub_key = NULL;
    const signed_pek_t& pek = msg2_blob_input->pek;
    uint32_t le_e;
    int i;
    size_t output_len = 0;
    uint8_t le_n[sizeof(pek.n)];
    static_assert(sizeof(pek.n)==384, "pek.n should be 384 bytes");
    device_id_t *device_id_in_aad= (device_id_t *)(aad+sizeof(GroupId));
    join_proof_with_escrow_t* join_proof_with_escrow=reinterpret_cast<join_proof_with_escrow_t *>(temp_buf+JOIN_PROOF_TLV_HEADER_SIZE);
    se_static_assert(sizeof(join_proof_with_escrow_t)+JOIN_PROOF_TLV_HEADER_SIZE==JOIN_PROOF_TLV_TOTAL_SIZE); /*unmatched hardcoded size*/
    se_static_assert(sizeof(sgx_key_128bit_t)==PWK2_TLV_TOTAL_SIZE-PWK2_TLV_HEADER_SIZE); /*unmatched PWK2 size*/
    memset(temp_buf, 0 ,sizeof(temp_buf));
    memset(aad, 0, sizeof(aad));
    memset(pwk2, 0, sizeof(sgx_key_128bit_t));
    memcpy(pwk2_tlv_buffer, PWK2_TLV_HEADER, PWK2_TLV_HEADER_SIZE);
    msg3_output->is_join_proof_generated=false;
    msg3_output->is_epid_sig_generated=false;

    if ((msg2_blob_input->pce_target_info.attributes.flags & SGX_FLAGS_PROVISION_KEY) != SGX_FLAGS_PROVISION_KEY ||
        (msg2_blob_input->pce_target_info.attributes.flags & SGX_FLAGS_DEBUG) != 0){
        //PCE must have access to provisioning key
        //Can't be debug PCE
        ret = PVEC_PARAMETER_ERROR;
        goto ret_point;
    }

    if(!performance_rekey_used){
        //the temp_buf used for join_proof_with_escrow tlv
        memcpy(temp_buf, JOIN_PROOF_TLV_HEADER, JOIN_PROOF_TLV_HEADER_SIZE);//first copy in tlv header
        ret = random_stack_advance(gen_msg3_join_proof_escrow_data, msg2_blob_input, *join_proof_with_escrow);//generate the tlv payload
        if( PVEC_SUCCESS != ret )
            goto ret_point;
        msg3_output->is_join_proof_generated = true;
        data_to_encrypt = temp_buf;
        size_to_encrypt = JOIN_PROOF_TLV_TOTAL_SIZE;
    }
    //now encrypt field1
    ret = se_read_rand_error_to_pve_error(sgx_read_rand(msg3_output->field1_iv, IV_SIZE));//randomly generate IV
    if( PVEC_SUCCESS != ret)
        goto ret_point;
    memcpy(aad, &msg2_blob_input->group_cert.key.gid,sizeof(GroupId));//start to prepare AAD
    memcpy(&device_id_in_aad->fmsp, &msg2_blob_input->equiv_pi.fmsp, sizeof(fmsp_t));
    memcpy(&device_id_in_aad->psvn.cpu_svn, &msg2_blob_input->equiv_pi.cpu_svn, sizeof(sgx_cpu_svn_t));
    memcpy(&device_id_in_aad->psvn.isv_svn, &msg2_blob_input->equiv_pi.pve_svn, sizeof(sgx_isv_svn_t));
    memset(&device_id_in_aad->ppid, 0, sizeof(device_id_in_aad->ppid));
    ret = pve_rng_generate(NONCE_2_SIZE*8, msg3_output->n2);
    if(PVEC_SUCCESS !=ret){
        goto ret_point;
    }
    ret = random_stack_advance(get_pwk2, &device_id_in_aad->psvn, msg3_output->n2, pwk2);
    if( PVEC_SUCCESS != ret )
        goto ret_point;

    memcpy(aad+sizeof(GroupId)+sizeof(device_id_t), msg2_blob_input->challenge_nonce, CHALLENGE_NONCE_SIZE);
    se_static_assert(sizeof(sgx_aes_gcm_128bit_key_t)==SK_SIZE); /*sizeof sgx_aes_gcm_128bit_key_t should be same as TCB size*/
    se_static_assert(sizeof(sgx_aes_gcm_128bit_tag_t)==MAC_SIZE); /*sizeof sgx_aes_gcm_128bit_tag_t should be same as MAC_SIZE*/
    sgx_status = sgx_rijndael128GCM_encrypt(reinterpret_cast<const sgx_aes_gcm_128bit_key_t *>(pwk2),
        data_to_encrypt, size_to_encrypt, msg3_output->field1_data,
        msg3_output->field1_iv, IV_SIZE, aad, static_cast<uint32_t>(sizeof(GroupId)+sizeof(device_id_t)+CHALLENGE_NONCE_SIZE),
        reinterpret_cast<sgx_aes_gcm_128bit_tag_t *>(msg3_output->field1_mac));//encrypt field1
    if(SGX_SUCCESS != sgx_status){
        ret = sgx_error_to_pve_error(sgx_status);
        goto ret_point;
    }
    if( msg2_blob_input->is_previous_pi_provided ){
        //preparing the encryption state of ProvMsg3 and encrypt inplace of msg3_inside enclave (field1_0 and field1_1)
        //The function will randomly set the iv value too
        ret = proc_msg3_state_init(&msg3_parm, pwk2);
        if( PVEC_SUCCESS!=ret )
            goto ret_point; 
        //Now start piece-meal generation of EPIDsign 
        ret = gen_msg3_signature(msg2_blob_input, &msg3_parm, emp_epid_sig, epid_sig_buffer_size);
        if( PVEC_SUCCESS!=ret )
            goto ret_point;
        msg3_output->is_epid_sig_generated = true;
        msg3_output->epid_sig_output_size = epid_sig_buffer_size;
        memcpy(msg3_output->epid_sig_iv, msg3_parm.iv, IV_SIZE);
        //generate MAC in EPC
        ret = sgx_error_to_pve_error(sgx_aes_gcm128_enc_get_mac(msg3_output->epid_sig_mac, (sgx_aes_state_handle_t*)msg3_parm.p_msg3_state));
        if (PVEC_SUCCESS != ret)
            goto ret_point;
    }

    le_e = lv_ntohl(pek.e);
    se_static_assert(sizeof(pek.n)==sizeof(le_n));  /*unmatched size of pek.n*/
    //endian swap
    for(i=0;i<(int)(sizeof(pek.n)/sizeof(pek.n[0]));i++){
        le_n[i]=pek.n[sizeof(pek.n)/sizeof(pek.n[0])-i-1];
    }

    sgx_status = sgx_create_rsa_pub_key(sizeof(pek.n), sizeof(pek.e),
        reinterpret_cast<const unsigned char *>(le_n), reinterpret_cast<const unsigned char *>(&le_e), &pub_key);
    if (SGX_SUCCESS != sgx_status) {
        ret = sgx_error_to_pve_error(sgx_status);
        goto ret_point;
    }

    sgx_status = sgx_rsa_pub_encrypt_sha256(pub_key, NULL, &output_len, reinterpret_cast<const unsigned char*>(pwk2_tlv_buffer),
        PWK2_TLV_TOTAL_SIZE);
    if (SGX_SUCCESS != sgx_status) {
        ret = sgx_error_to_pve_error(sgx_status);
        goto ret_point;
    }
    sgx_status = sgx_rsa_pub_encrypt_sha256(pub_key, msg3_output->encrypted_pwk2, &output_len, reinterpret_cast<const unsigned char*>(pwk2_tlv_buffer),
        PWK2_TLV_TOTAL_SIZE);
    if (SGX_SUCCESS != sgx_status) {
        ret = sgx_error_to_pve_error(sgx_status);
        goto ret_point;
    }

    // X = (NT)MAC_PWK2(... (NT)E_PWK2((T)(JoinP, f)) ...) | (NT)E_PWK2((T)(JoinP, f)) | (NT)PWK2N | (NT)E_PEK((T)PWK2)
    // REPORT.ReportData == SHA256[X] 
    memcpy(pdata, msg3_output->field1_mac, MAC_SIZE);
    pdata += MAC_SIZE;
    if (!performance_rekey_used){
        memcpy(pdata, msg3_output->field1_data, HARD_CODED_JOIN_PROOF_WITH_ESCROW_TLV_SIZE);
        pdata += HARD_CODED_JOIN_PROOF_WITH_ESCROW_TLV_SIZE;
    }
    memcpy(pdata, msg3_output->n2, NONCE_2_SIZE);
    pdata += NONCE_2_SIZE;
    memcpy(pdata, msg3_output->encrypted_pwk2, PEK_MOD_SIZE);
    pdata += PEK_MOD_SIZE;
    se_static_assert(sizeof(report_data) >= sizeof(sgx_sha256_hash_t)); /*report data is no large enough*/
    sgx_status = sgx_sha256_msg(report_data_payload, (uint32_t)(pdata - &report_data_payload[0]), reinterpret_cast<sgx_sha256_hash_t *>(&report_data));
    if (SGX_SUCCESS != sgx_status){
        ret = sgx_error_to_pve_error(sgx_status);
        goto ret_point;
    }
    sgx_status = sgx_create_report(&msg2_blob_input->pce_target_info, &report_data, &msg3_output->pwk2_report);
    if (SGX_SUCCESS != sgx_status){
        ret = sgx_error_to_pve_error(sgx_status);
        goto ret_point;
    }

ret_point:
    (void)memset_s(aad, sizeof(aad), 0, sizeof(aad));
    (void)memset_s(temp_buf, sizeof(temp_buf), 0, sizeof(temp_buf));
    (void)memset_s(pwk2_tlv_buffer, sizeof(pwk2_tlv_buffer),0,sizeof(pwk2_tlv_buffer));
    if(pub_key){
        sgx_free_rsa_key(pub_key, SGX_RSA_PUBLIC_KEY, sizeof(pek.n), sizeof(pek.e));
    }

    return ret;
}
Esempio n. 8
0
/*
 * Internal function used to init white list. It will check the content of the
 * cert chain, and verify the signature of input cert chains. If no problem,
 * it will cache the input white list into EPC.
 *
 * @param p_wl_cert_chain[in] Pointer to the white list cert chain.
 * @param entry_number[in] The entry number within the white list.
 * @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(
    const wl_cert_chain_t *p_wl_cert_chain,
    uint32_t entry_number,
    uint32_t wl_cert_chain_size)
{
    sgx_status_t sgx_ret = SGX_SUCCESS;
    uint32_t ret = AE_SUCCESS;
    uint32_t new_wl_version = 0;
    uint8_t verify_result = 0;
    int valid = 0;
    const uint8_t *buf = NULL;
    uint32_t buf_size = 0;
    sgx_prod_id_t wl_prod_id = 0;
    sgx_ecc_state_handle_t ecc_handle = NULL;
    wl_cert_t *p_wl_cert_cache = (wl_cert_t *)g_wl_cert_buf;
    sgx_report_t report;
    sgx_ec256_signature_t wl_signature;
    sgx_ec256_public_t wl_pubkey;


    // Check fields of provider cert
    // Format version should be 1 (big endian)
    if(p_wl_cert_chain->wl_provider_cert.version != WL_PROVIDER_CERT_VERSION)
    {
        ret = LE_INVALID_PARAMETER;
        goto CLEANUP;
    }
    // For Enclave Signing Key White List Cert, must be 0
    if(p_wl_cert_chain->wl_provider_cert.cert_type != WL_PROVIDER_CERT_TYPE)
    {
        ret = LE_INVALID_PARAMETER;
        goto CLEANUP;
    }
    // only one White List Provider is approved:
    // WLProviderID: ISecG = 0
    if(p_wl_cert_chain->wl_provider_cert.provider_id != WL_PROVIDER_CERT_PROVIDER_ID)
    {
        ret = LE_INVALID_PARAMETER;
        goto CLEANUP;
    }
    // only one WLRootID is valid: WLRootID-iKGF-Key-0 = 0
    if(p_wl_cert_chain->wl_provider_cert.root_id != WL_PROVIDER_CERT_ROOT_ID)
    {
        ret = LE_INVALID_PARAMETER;
        goto CLEANUP;
    }

    // Check fields of wl cert
    // only valid version is 1
    if(p_wl_cert_chain->wl_cert.version != WL_CERT_VERSION)
    {
        ret = LE_INVALID_PARAMETER;
        goto CLEANUP;
    }
    // For Enclave Signing Key White List Cert, must be 1
    if(p_wl_cert_chain->wl_cert.cert_type != WL_CERT_TYPE)
    {
        ret = LE_INVALID_PARAMETER;
        goto CLEANUP;
    }
    // only one White List Provider is approved:
    // WLProviderID: ISecG = 0
    if(p_wl_cert_chain->wl_cert.provider_id != WL_CERT_PROVIDER_ID)
    {
        ret = LE_INVALID_PARAMETER;
        goto CLEANUP;
    }

    // If cache exists
    new_wl_version = p_wl_cert_chain->wl_cert.wl_version;
    new_wl_version = _ntohl(new_wl_version);
    if(p_wl_cert_cache->version != 0)
    {
        // the logic will be needed to support more than
        // one providers in the future.
        //if(p_wl_cert_chain->wl_cert.provider_id
        //   != p_wl_cert_cache->provider_id)
        //{
        //    ret = LE_INVALID_PARAMETER;
        //    goto CLEANUP;
        //}
        if(new_wl_version < p_wl_cert_cache->wl_version)
        {
            ret = LE_INVALID_PARAMETER;
            goto CLEANUP;
        }
    }

    sgx_ret = sgx_ecc256_open_context(&ecc_handle);
    if (SGX_SUCCESS != sgx_ret)
    {
        ret = LE_UNEXPECTED_ERROR;
        goto CLEANUP;
    }

    memset(&wl_signature, 0, sizeof(wl_signature));
    // Convert the signature of provider cert into little endian
    memcpy(&wl_signature,
           &(p_wl_cert_chain->wl_provider_cert.signature),
           sizeof(wl_signature));
    SWAP_ENDIAN_8X32B(wl_signature.x);
    SWAP_ENDIAN_8X32B(wl_signature.y);

    // Verify the wl provider cert
    buf = (const uint8_t *)&(p_wl_cert_chain->wl_provider_cert);
    buf_size = static_cast<uint32_t>(sizeof(p_wl_cert_chain->wl_provider_cert)
               - sizeof(p_wl_cert_chain->wl_provider_cert.signature));
    sgx_ret = sgx_ecdsa_verify(buf, buf_size,
                               &g_wl_root_pubkey,
                               &wl_signature,
                               &verify_result,
                               ecc_handle);
    if (SGX_SUCCESS != sgx_ret)
    {
        ret = LE_UNEXPECTED_ERROR;
        goto CLEANUP;
    }
    if(SGX_EC_VALID != verify_result)
    {
        ret = LE_INVALID_PARAMETER;
        goto CLEANUP;
    }

    // Convert the signature of wl cert into little endian
    buf = (const uint8_t *)p_wl_cert_chain + wl_cert_chain_size
          - sizeof(wl_signature);
    memcpy(&wl_signature, buf, sizeof(wl_signature));
    SWAP_ENDIAN_8X32B(wl_signature.x);
    SWAP_ENDIAN_8X32B(wl_signature.y);

    // Convert the pubkey into little endian
    memset(&wl_pubkey, 0, sizeof(wl_pubkey));
    memcpy(&wl_pubkey,
           &(p_wl_cert_chain->wl_provider_cert.pub_key),
           sizeof(wl_pubkey));
    reverse_byte_array(wl_pubkey.gx, sizeof(wl_pubkey.gx));
    reverse_byte_array(wl_pubkey.gy, sizeof(wl_pubkey.gy));

    // Check whether the pubkey is valid first.
    sgx_ret = sgx_ecc256_check_point(&wl_pubkey, ecc_handle, &valid);
    if(SGX_SUCCESS != sgx_ret)
    {
        ret = LE_UNEXPECTED_ERROR;
        goto CLEANUP;
    }
    if(!valid)
    {
        ret = LE_INVALID_PARAMETER;
        goto CLEANUP;
    }

    // Verify the wl_cert
    buf = (const uint8_t *)&(p_wl_cert_chain->wl_cert);
    buf_size = wl_cert_chain_size - static_cast<uint32_t>(sizeof(wl_provider_cert_t) + sizeof(sgx_ec256_signature_t));
    sgx_ret = sgx_ecdsa_verify(buf, buf_size,
                               &wl_pubkey,
                               &wl_signature,
                               &verify_result,
                               ecc_handle);
    if (SGX_SUCCESS != sgx_ret)
    {
        ret = LE_UNEXPECTED_ERROR;
        goto CLEANUP;
    }
    if(SGX_EC_VALID != verify_result)
    {
        ret = LE_INVALID_PARAMETER;
        goto CLEANUP;
    }

    memset(&report, 0, sizeof(report));
    // Create report to get current mrsigner.
    sgx_ret = sgx_create_report(NULL, NULL, &report);
    if(SGX_SUCCESS != sgx_ret)
    {
        ret = LE_UNEXPECTED_ERROR;
        goto CLEANUP;
    }

    // Convert the big endian prod id to little endian.
    wl_prod_id = p_wl_cert_chain->wl_cert.le_prod_id;
    wl_prod_id = _ntohs(wl_prod_id);
    if(report.body.isv_prod_id != wl_prod_id)
    {
        ret = LE_INVALID_PARAMETER;
        goto CLEANUP;
    }

    // Cache the wl cert
    memset(g_wl_cert_buf, 0, sizeof(g_wl_cert_buf));
    memcpy(g_wl_cert_buf, &(p_wl_cert_chain->wl_cert), buf_size);
    // Change entry_number and wl_version to little endian, so we don't need to
    // convert them next time.
    p_wl_cert_cache->entry_number = entry_number;
    p_wl_cert_cache->wl_version = new_wl_version;

CLEANUP:
    if(ecc_handle != NULL)
    {
        sgx_ecc256_close_context(ecc_handle);
    }
    return ret;

}
Esempio n. 9
0
ae_error_t le_generate_launch_token(
    const sgx_measurement_t* mrenclave,
    const sgx_measurement_t* mrsigner,
    const sgx_attributes_t* se_attributes,
    token_t* lictoken)
{
    uint32_t i = 0;
    bool is_production = false;
    sgx_status_t sgx_ret = SGX_ERROR_UNEXPECTED;
    ae_error_t ae_ret = AE_FAILURE;
    wl_cert_t *p_wl_cert_cache = (wl_cert_t *)g_wl_cert_buf;
    sgx_measurement_t empty_mrsigner;
    sgx_report_t report;

    // se_attributes must have no reserved bit set.
    // urts(finally EINIT instruction)rejects EINIT Token with SGX_FLAGS_INITTED
    // set. So LE doesn't need to check it here.
    if((se_attributes->flags) & SGX_FLAGS_RESERVED)
    {
        return LE_INVALID_ATTRIBUTE;
    }

    memset(&report, 0, sizeof(report));
    // Create report to get current cpu_svn and isv_svn.
    sgx_ret = sgx_create_report(NULL, NULL, &report);
    if(SGX_SUCCESS != sgx_ret)
    {
        return LE_UNEXPECTED_ERROR;
    }
    
    for(i = 0; i < (sizeof(g_le_mrsigner) / sizeof(g_le_mrsigner[0])); i++)
    {
        if(0 == memcmp(&(g_le_mrsigner[i]), &(report.body.mr_signer),
                       sizeof(g_le_mrsigner[0])))
        {
            is_production = true;
            break;
        }
    }

    if(true == is_production)
    {
        // Only Provision Enclave is allowed to be EINITed with the privilege
        // to access the PROVISIONKEY, which is signed with fixed signing key
        if((se_attributes->flags & SGX_FLAGS_PROVISION_KEY))
        {
            for(i = 0; i < (sizeof(G_SERVICE_ENCLAVE_MRSIGNER) / sizeof(G_SERVICE_ENCLAVE_MRSIGNER[0]));
                i++)
            {
                if(0 == memcmp(&G_SERVICE_ENCLAVE_MRSIGNER[i], mrsigner,
                               sizeof(G_SERVICE_ENCLAVE_MRSIGNER[0])))
                {
                    break;
                }
            }
            if(i == sizeof(G_SERVICE_ENCLAVE_MRSIGNER) / sizeof(G_SERVICE_ENCLAVE_MRSIGNER[0]))
            {
                return LE_INVALID_ATTRIBUTE;
            }
        }
    }

    // on "production" system, enclaves to be launched in "non-enclave-debug"
    // mode are subjected to Enclave Signing Key White Listing control.
    if(((se_attributes->flags & SGX_FLAGS_DEBUG) == 0)
        && (true == is_production))
    {
        // Check whether the wl is initialized
        if(p_wl_cert_cache->version == 0)
        {
            return LE_WHITELIST_UNINITIALIZED_ERROR;
        }

        // Create an empty mrsigner
        memset(&empty_mrsigner, 0, sizeof(empty_mrsigner));
        // Check if p_wl_cert_cache->mr_signer_list[0] is empty.
        // If mr_signer_list[0] = 0, a "wild card" white list cert is in-use,
        // meant to allow any enclave to launch.
        if(0 != memcmp(&(p_wl_cert_cache->mr_signer_list[0]), &empty_mrsigner,
                       sizeof(p_wl_cert_cache->mr_signer_list[0])))
        {
            for(i = 0; i < p_wl_cert_cache->entry_number; i++)
            {
                if(0 == memcmp(&(p_wl_cert_cache->mr_signer_list[i]),
                               mrsigner,
                               sizeof(p_wl_cert_cache->mr_signer_list[i])))
                {
                    break;
                }
            }
            if(i == p_wl_cert_cache->entry_number)
            {
                return LE_INVALID_PRIVILEGE_ERROR;
            }
        }
    }


    //initial EINIT Token and set 0 for all reserved area
    memset(lictoken, 0, sizeof(*lictoken));

    //set the EINIT Token valid
    lictoken->body.valid = 1;

    //set EINIT Token mrenclave
    memcpy(&lictoken->body.mr_enclave, mrenclave,
           sizeof(lictoken->body.mr_enclave));

    //set EINIT Token mrsigner
    memcpy(&lictoken->body.mr_signer, mrsigner,
           sizeof(lictoken->body.mr_signer));

    //set EINIT Token attributes
    memcpy(&lictoken->body.attributes, se_attributes,
           sizeof(lictoken->body.attributes));

    //set EINIT Token with platform information from ereport of LE
    memcpy(&lictoken->cpu_svn_le, &report.body.cpu_svn, sizeof(sgx_cpu_svn_t));
    lictoken->isv_svn_le = report.body.isv_svn;
    lictoken->isv_prod_id_le = report.body.isv_prod_id;

    //will mask attributes in le_calc_lic_token
    memcpy(&lictoken->attributes_le, &report.body.attributes,
           sizeof(lictoken->attributes_le));

    //will mask misc_select_le in le_calc_lic_token
    lictoken->masked_misc_select_le = report.body.misc_select;

    //calculate EINIT Token
    ae_ret = le_calc_lic_token(lictoken);
    //if failure, clear EINIT Token
    if (ae_ret != AE_SUCCESS)
    {
        memset_s(lictoken,sizeof(*lictoken), 0, sizeof(*lictoken));
    }
    return ae_ret;

}