Esempio n. 1
0
inline std::vector<uint8_t> udg::crypto::seal_data(const uint8_t* data,
        uint32_t len) {

	uint32_t out_size = sgx_calc_sealed_data_size(0, len);

	std::vector<uint8_t> out;
	out.resize(out_size);

	auto res = sgx_seal_data(0, nullptr, len, data, out_size, (sgx_sealed_data_t*)(&out[0]));

	if (res != SGX_SUCCESS) {
		throw udg::crypto::data_integrity_exception();
	}

	return out;

}
Esempio n. 2
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;
}