SDK_PFImplementations

April 9, 2021 at 11:03 am
Analysis Artifact SGX

The implementations are in https://github.com/intel/linux-sgx/tree/master/sdk/protected_fs/sgx_tprotected_fs.

High Level Organization

Protected files are objects in SGX SDK's implementation. The opened PFs contains important fields like key, report and file pointer received from the OS. Data in the file is maintained as Merkle Hash Tree Nodes, and each node contains node number and encrypted/decrypted data in its struct. Besides, metadata is also stored in a meta node, which includes MAC, key, file id and version info about CPU/ISV/PF. The encryption scheme is rijndael 128 GCM (AES 128 GCM) algorithm. To ensure PF operations are atomic, it also recruits mutex mechanism.

All the internal interfaces in the enclave relies on the untrusted code to perform file operations by OS. Those interfaces are in https://github.com/intel/linux-sgx/tree/master/sdk/protected_fs/sgx_uprotected_fs, and are of less interest.

Encryption

sgx_status_t sgx_rijndael128GCM_encrypt(const sgx_aes_gcm_128bit_key_t *p_key, const uint8_t *p_src, uint32_t src_len,  uint8_t *p_dst, const uint8_t *p_iv, uint32_t iv_len, const uint8_t *p_aad, uint32_t aad_len,  sgx_aes_gcm_128bit_tag_t *p_out_mac)

Decryption

sgx_status_t sgx_rijndael128GCM_decrypt(const sgx_aes_gcm_128bit_key_t *p_key, const uint8_t *p_src, uint32_t src_len, uint8_t *p_dst, const uint8_t *p_iv, uint32_t iv_len, const uint8_t *p_aad, uint32_t aad_len, const sgx_aes_gcm_128bit_tag_t *p_in_mac)

See also:

SDK_PF_New (protected_fs_file::protected_fs_file)

SDK_ProtectedFileClass

SGX_PF_Class

Internal APIs

Open

  1. new protected_fs_file (SDK_PF_New)
  2. if no error, return handle
static SGX_FILE* sgx_fopen_internal(const char* filename, const char* mode, const sgx_key_128bit_t *auto_key, const sgx_key_128bit_t *kdk_key)
{
    protected_fs_file* file = NULL;

    if (filename == NULL || mode == NULL)
    {
        errno = EINVAL;
        return NULL;
    }

    try {
        file = new protected_fs_file(filename, mode, auto_key, kdk_key);
    }
    catch (std::bad_alloc& e) {
        (void)e; // remove warning
        errno = ENOMEM;
        return NULL;
    }

    if (file->get_error() != SGX_FILE_STATUS_OK)
    {
        errno = file->get_error();
        delete file;
        file = NULL;
    }

    return (SGX_FILE*)file;
}

Write

size_t sgx_fwrite(const void* ptr, size_t size, size_t count, SGX_FILE* stream)
{
    if (ptr == NULL || stream == NULL || size == 0 || count == 0)
        return 0;

    protected_fs_file* file = (protected_fs_file*)stream;

    return file->write(ptr, size, count);
}

Write in PF Class

Close

int32_t sgx_fclose(SGX_FILE* stream)
{
    return sgx_fclose_internal(stream, NULL, false);
}

static int32_t sgx_fclose_internal(SGX_FILE* stream, sgx_key_128bit_t *key, bool import)
{
    int32_t retval = 0;

    if (stream == NULL)
        return EOF;

    protected_fs_file* file = (protected_fs_file*)stream;

    if (file->pre_close(key, import) == false)
        retval = 1;

    delete file;

    return retval;
}

Close in PF Class

Flush

Flush performs the actual encryption and write.

Flush in PF