lkml.org 
[lkml]   [2020]   [Mar]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v28 14/22] selftests/x86: Add a selftest for SGX
    Date
    Add a selftest for SGX. It is a trivial test where a simple enclave
    copies one 64-bit word of memory between two memory locations given to
    the enclave as arguments. Use ENCLS[EENTER] to invoke the enclave.

    Cc: linux-sgx@vger.kernel.org
    Cc: linux-kselftest@vger.kernel.org
    Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
    ---
    tools/testing/selftests/x86/sgx/.gitignore | 3 +
    tools/testing/selftests/x86/sgx/Makefile | 48 ++
    tools/testing/selftests/x86/sgx/defines.h | 17 +
    tools/testing/selftests/x86/sgx/encl.c | 20 +
    tools/testing/selftests/x86/sgx/encl.lds | 34 ++
    .../selftests/x86/sgx/encl_bootstrap.S | 94 ++++
    tools/testing/selftests/x86/sgx/main.c | 247 +++++++++
    tools/testing/selftests/x86/sgx/sgx_call.S | 23 +
    tools/testing/selftests/x86/sgx/sgx_call.h | 11 +
    tools/testing/selftests/x86/sgx/sgxsign.c | 493 ++++++++++++++++++
    .../testing/selftests/x86/sgx/signing_key.pem | 39 ++
    11 files changed, 1029 insertions(+)
    create mode 100644 tools/testing/selftests/x86/sgx/.gitignore
    create mode 100644 tools/testing/selftests/x86/sgx/Makefile
    create mode 100644 tools/testing/selftests/x86/sgx/defines.h
    create mode 100644 tools/testing/selftests/x86/sgx/encl.c
    create mode 100644 tools/testing/selftests/x86/sgx/encl.lds
    create mode 100644 tools/testing/selftests/x86/sgx/encl_bootstrap.S
    create mode 100644 tools/testing/selftests/x86/sgx/main.c
    create mode 100644 tools/testing/selftests/x86/sgx/sgx_call.S
    create mode 100644 tools/testing/selftests/x86/sgx/sgx_call.h
    create mode 100644 tools/testing/selftests/x86/sgx/sgxsign.c
    create mode 100644 tools/testing/selftests/x86/sgx/signing_key.pem

    diff --git a/tools/testing/selftests/x86/sgx/.gitignore b/tools/testing/selftests/x86/sgx/.gitignore
    new file mode 100644
    index 000000000000..98eb2d439606
    --- /dev/null
    +++ b/tools/testing/selftests/x86/sgx/.gitignore
    @@ -0,0 +1,3 @@
    +encl.ss
    +sgxsign
    +test_sgx
    diff --git a/tools/testing/selftests/x86/sgx/Makefile b/tools/testing/selftests/x86/sgx/Makefile
    new file mode 100644
    index 000000000000..f838700029e2
    --- /dev/null
    +++ b/tools/testing/selftests/x86/sgx/Makefile
    @@ -0,0 +1,48 @@
    +top_srcdir = ../../../../..
    +
    +include ../../lib.mk
    +
    +ifndef OBJCOPY
    +OBJCOPY := $(CROSS_COMPILE)objcopy
    +endif
    +
    +INCLUDES := -I$(top_srcdir)/tools/include
    +HOST_CFLAGS := -Wall -Werror -g $(INCLUDES) -fPIC -z noexecstack
    +ENCL_CFLAGS := -Wall -Werror -static -nostdlib -nostartfiles -fPIC \
    + -fno-stack-protector -mrdrnd $(INCLUDES)
    +
    +TEST_CUSTOM_PROGS := $(OUTPUT)/test_sgx $(OUTPUT)/encl.bin $(OUTPUT)/encl.ss
    +
    +all: $(TEST_CUSTOM_PROGS)
    +
    +$(OUTPUT)/test_sgx: $(OUTPUT)/main.o $(OUTPUT)/sgx_call.o
    + $(CC) $(HOST_CFLAGS) -o $@ $^
    +
    +$(OUTPUT)/main.o: main.c
    + $(CC) $(HOST_CFLAGS) -c $< -o $@
    +
    +$(OUTPUT)/sgx_call.o: sgx_call.S
    + $(CC) $(HOST_CFLAGS) -c $< -o $@
    +
    +$(OUTPUT)/encl.bin: $(OUTPUT)/encl.elf $(OUTPUT)/sgxsign
    + $(OBJCOPY) -O binary $< $@
    +
    +$(OUTPUT)/encl.elf: encl.lds encl.c encl_bootstrap.S
    + $(CC) $(ENCL_CFLAGS) -T $^ -o $@
    +
    +$(OUTPUT)/encl.ss: $(OUTPUT)/encl.bin
    + $(OUTPUT)/sgxsign signing_key.pem $(OUTPUT)/encl.bin $(OUTPUT)/encl.ss
    +
    +$(OUTPUT)/sgxsign: sgxsign.c
    + $(CC) $(INCLUDES) -o $@ $< -lcrypto
    +
    +EXTRA_CLEAN := \
    + $(OUTPUT)/encl.bin \
    + $(OUTPUT)/encl.elf \
    + $(OUTPUT)/encl.ss \
    + $(OUTPUT)/sgx_call.o \
    + $(OUTPUT)/sgxsign \
    + $(OUTPUT)/test_sgx \
    + $(OUTPUT)/test_sgx.o \
    +
    +.PHONY: clean
    diff --git a/tools/testing/selftests/x86/sgx/defines.h b/tools/testing/selftests/x86/sgx/defines.h
    new file mode 100644
    index 000000000000..87264f85cb9f
    --- /dev/null
    +++ b/tools/testing/selftests/x86/sgx/defines.h
    @@ -0,0 +1,17 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +/*
    + * Copyright(c) 2016-19 Intel Corporation.
    + */
    +
    +#ifndef DEFINES_H
    +#define DEFINES_H
    +
    +#include <stdint.h>
    +
    +#define __aligned(x) __attribute__((__aligned__(x)))
    +#define __packed __attribute__((packed))
    +
    +#include "../../../../../arch/x86/kernel/cpu/sgx/arch.h"
    +#include "../../../../../arch/x86/include/uapi/asm/sgx.h"
    +
    +#endif /* DEFINES_H */
    diff --git a/tools/testing/selftests/x86/sgx/encl.c b/tools/testing/selftests/x86/sgx/encl.c
    new file mode 100644
    index 000000000000..ede915399742
    --- /dev/null
    +++ b/tools/testing/selftests/x86/sgx/encl.c
    @@ -0,0 +1,20 @@
    +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
    +// Copyright(c) 2016-18 Intel Corporation.
    +
    +#include <stddef.h>
    +#include "defines.h"
    +
    +static void *memcpy(void *dest, const void *src, size_t n)
    +{
    + size_t i;
    +
    + for (i = 0; i < n; i++)
    + ((char *)dest)[i] = ((char *)src)[i];
    +
    + return dest;
    +}
    +
    +void encl_body(void *rdi, void *rsi)
    +{
    + memcpy(rsi, rdi, 8);
    +}
    diff --git a/tools/testing/selftests/x86/sgx/encl.lds b/tools/testing/selftests/x86/sgx/encl.lds
    new file mode 100644
    index 000000000000..9a56d3064104
    --- /dev/null
    +++ b/tools/testing/selftests/x86/sgx/encl.lds
    @@ -0,0 +1,34 @@
    +OUTPUT_FORMAT(elf64-x86-64)
    +
    +SECTIONS
    +{
    + . = 0;
    + .tcs : {
    + *(.tcs*)
    + }
    +
    + . = ALIGN(4096);
    + .text : {
    + *(.text*)
    + *(.rodata*)
    + }
    +
    + . = ALIGN(4096);
    + .data : {
    + *(.data*)
    + }
    +
    + /DISCARD/ : {
    + *(.data*)
    + *(.comment*)
    + *(.note*)
    + *(.debug*)
    + *(.eh_frame*)
    + }
    +}
    +
    +ASSERT(!DEFINED(.altinstructions), "ALTERNATIVES are not supported in enclaves")
    +ASSERT(!DEFINED(.altinstr_replacement), "ALTERNATIVES are not supported in enclaves")
    +ASSERT(!DEFINED(.discard.retpoline_safe), "RETPOLINE ALTERNATIVES are not supported in enclaves")
    +ASSERT(!DEFINED(.discard.nospec), "RETPOLINE ALTERNATIVES are not supported in enclaves")
    +ASSERT(!DEFINED(.got.plt), "Libcalls are not supported in enclaves")
    diff --git a/tools/testing/selftests/x86/sgx/encl_bootstrap.S b/tools/testing/selftests/x86/sgx/encl_bootstrap.S
    new file mode 100644
    index 000000000000..d07f970ccdf9
    --- /dev/null
    +++ b/tools/testing/selftests/x86/sgx/encl_bootstrap.S
    @@ -0,0 +1,94 @@
    +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
    +/*
    + * Copyright(c) 2016-18 Intel Corporation.
    + */
    +
    + .macro ENCLU
    + .byte 0x0f, 0x01, 0xd7
    + .endm
    +
    + .section ".tcs", "a"
    + .balign 4096
    +
    + .fill 1, 8, 0 # STATE (set by CPU)
    + .fill 1, 8, 0 # FLAGS
    + .quad encl_ssa # OSSA
    + .fill 1, 4, 0 # CSSA (set by CPU)
    + .fill 1, 4, 1 # NSSA
    + .quad encl_entry # OENTRY
    + .fill 1, 8, 0 # AEP (set by EENTER and ERESUME)
    + .fill 1, 8, 0 # OFSBASE
    + .fill 1, 8, 0 # OGSBASE
    + .fill 1, 4, 0xFFFFFFFF # FSLIMIT
    + .fill 1, 4, 0xFFFFFFFF # GSLIMIT
    + .fill 4024, 1, 0 # Reserved
    +
    + .text
    +
    +encl_entry:
    + # RBX contains the base address for TCS, which is also the first address
    + # inside the enclave. By adding the value of le_stack_end to it, we get
    + # the absolute address for the stack.
    + lea (encl_stack)(%rbx), %rax
    + xchg %rsp, %rax
    + push %rax
    +
    + push %rcx # push the address after EENTER
    + push %rbx # push the enclave base address
    +
    + call encl_body
    +
    + pop %rbx # pop the enclave base address
    +
    + # Restore XSAVE registers to a synthetic state.
    + mov $0xFFFFFFFF, %rax
    + mov $0xFFFFFFFF, %rdx
    + lea (xsave_area)(%rbx), %rdi
    + fxrstor (%rdi)
    +
    + # Clear GPRs.
    + xor %rcx, %rcx
    + xor %rdx, %rdx
    + xor %rdi, %rdi
    + xor %rsi, %rsi
    + xor %r8, %r8
    + xor %r9, %r9
    + xor %r10, %r10
    + xor %r11, %r11
    + xor %r12, %r12
    + xor %r13, %r13
    + xor %r14, %r14
    + xor %r15, %r15
    +
    + # Reset status flags.
    + add %rdx, %rdx # OF = SF = AF = CF = 0; ZF = PF = 1
    +
    + # Prepare EEXIT target by popping the address of the instruction after
    + # EENTER to RBX.
    + pop %rbx
    +
    + # Restore the caller stack.
    + pop %rax
    + mov %rax, %rsp
    +
    + # EEXIT
    + mov $4, %rax
    + enclu
    +
    + .section ".data", "aw"
    +
    +encl_ssa:
    + .space 4096
    +
    +xsave_area:
    + .fill 1, 4, 0x037F # FCW
    + .fill 5, 4, 0
    + .fill 1, 4, 0x1F80 # MXCSR
    + .fill 1, 4, 0xFFFF # MXCSR_MASK
    + .fill 123, 4, 0
    + .fill 1, 4, 0x80000000 # XCOMP_BV[63] = 1, compaction mode
    + .fill 12, 4, 0
    +
    + .balign 4096
    + .space 8192
    +encl_stack:
    diff --git a/tools/testing/selftests/x86/sgx/main.c b/tools/testing/selftests/x86/sgx/main.c
    new file mode 100644
    index 000000000000..48ed5fdfb3cb
    --- /dev/null
    +++ b/tools/testing/selftests/x86/sgx/main.c
    @@ -0,0 +1,247 @@
    +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
    +// Copyright(c) 2016-18 Intel Corporation.
    +
    +#include <elf.h>
    +#include <errno.h>
    +#include <fcntl.h>
    +#include <stdbool.h>
    +#include <stdio.h>
    +#include <stdint.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <unistd.h>
    +#include <sys/ioctl.h>
    +#include <sys/mman.h>
    +#include <sys/stat.h>
    +#include <sys/time.h>
    +#include <sys/types.h>
    +#include "defines.h"
    +#include "sgx_call.h"
    +
    +#define PAGE_SIZE 4096
    +
    +static const uint64_t MAGIC = 0x1122334455667788ULL;
    +
    +static bool encl_create(int dev_fd, unsigned long bin_size,
    + struct sgx_secs *secs)
    +{
    + struct sgx_enclave_create ioc;
    + void *area;
    + int rc;
    +
    + memset(secs, 0, sizeof(*secs));
    + secs->ssa_frame_size = 1;
    + secs->attributes = SGX_ATTR_MODE64BIT;
    + secs->xfrm = 3;
    +
    + for (secs->size = 4096; secs->size < bin_size; )
    + secs->size <<= 1;
    +
    + area = mmap(NULL, secs->size * 2, PROT_NONE, MAP_SHARED, dev_fd, 0);
    + if (area == MAP_FAILED) {
    + perror("mmap");
    + return false;
    + }
    +
    + secs->base = ((uint64_t)area + secs->size - 1) & ~(secs->size - 1);
    +
    + munmap(area, secs->base - (uint64_t)area);
    + munmap((void *)(secs->base + secs->size),
    + (uint64_t)area + secs->size - secs->base);
    +
    + ioc.src = (unsigned long)secs;
    + rc = ioctl(dev_fd, SGX_IOC_ENCLAVE_CREATE, &ioc);
    + if (rc) {
    + fprintf(stderr, "ECREATE failed rc=%d, err=%d.\n", rc, errno);
    + munmap((void *)secs->base, secs->size);
    + return false;
    + }
    +
    + return true;
    +}
    +
    +static bool encl_add_pages(int dev_fd, unsigned long offset, void *data,
    + unsigned long length, uint64_t flags)
    +{
    + struct sgx_enclave_add_pages ioc;
    + struct sgx_secinfo secinfo;
    + int rc;
    +
    + memset(&secinfo, 0, sizeof(secinfo));
    + secinfo.flags = flags;
    +
    + ioc.src = (uint64_t)data;
    + ioc.offset = offset;
    + ioc.length = length;
    + ioc.secinfo = (unsigned long)&secinfo;
    + ioc.flags = SGX_PAGE_MEASURE;
    +
    + rc = ioctl(dev_fd, SGX_IOC_ENCLAVE_ADD_PAGES, &ioc);
    + if (rc) {
    + fprintf(stderr, "EADD failed rc=%d.\n", rc);
    + return false;
    + }
    +
    + if (ioc.count != ioc.length) {
    + fprintf(stderr, "Partially processed, update the test.\n");
    + return false;
    + }
    +
    + return true;
    +}
    +
    +#define SGX_REG_PAGE_FLAGS \
    + (SGX_SECINFO_REG | SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_X)
    +
    +static bool encl_build(struct sgx_secs *secs, void *bin,
    + unsigned long bin_size, struct sgx_sigstruct *sigstruct)
    +{
    + struct sgx_enclave_init ioc;
    + void *addr;
    + int dev_fd;
    + int rc;
    +
    + dev_fd = open("/dev/sgx/enclave", O_RDWR);
    + if (dev_fd < 0) {
    + fprintf(stderr, "Unable to open /dev/sgx\n");
    + return false;
    + }
    +
    + if (!encl_create(dev_fd, bin_size, secs))
    + goto out_dev_fd;
    +
    + if (!encl_add_pages(dev_fd, 0, bin, PAGE_SIZE, SGX_SECINFO_TCS))
    + goto out_dev_fd;
    +
    + if (!encl_add_pages(dev_fd, PAGE_SIZE, bin + PAGE_SIZE,
    + bin_size - PAGE_SIZE, SGX_REG_PAGE_FLAGS))
    + goto out_dev_fd;
    +
    + ioc.sigstruct = (uint64_t)sigstruct;
    + rc = ioctl(dev_fd, SGX_IOC_ENCLAVE_INIT, &ioc);
    + if (rc) {
    + printf("EINIT failed rc=%d\n", rc);
    + goto out_map;
    + }
    +
    + addr = mmap((void *)secs->base, PAGE_SIZE, PROT_READ | PROT_WRITE,
    + MAP_SHARED | MAP_FIXED, dev_fd, 0);
    + if (addr == MAP_FAILED) {
    + fprintf(stderr, "mmap() failed on TCS, errno=%d.\n", errno);
    + return false;
    + }
    +
    + addr = mmap((void *)(secs->base + PAGE_SIZE), bin_size - PAGE_SIZE,
    + PROT_READ | PROT_WRITE | PROT_EXEC,
    + MAP_SHARED | MAP_FIXED, dev_fd, 0);
    + if (addr == MAP_FAILED) {
    + fprintf(stderr, "mmap() failed, errno=%d.\n", errno);
    + return false;
    + }
    +
    + close(dev_fd);
    + return true;
    +out_map:
    + munmap((void *)secs->base, secs->size);
    +out_dev_fd:
    + close(dev_fd);
    + return false;
    +}
    +
    +bool get_file_size(const char *path, off_t *bin_size)
    +{
    + struct stat sb;
    + int ret;
    +
    + ret = stat(path, &sb);
    + if (ret) {
    + perror("stat");
    + return false;
    + }
    +
    + if (!sb.st_size || sb.st_size & 0xfff) {
    + fprintf(stderr, "Invalid blob size %lu\n", sb.st_size);
    + return false;
    + }
    +
    + *bin_size = sb.st_size;
    + return true;
    +}
    +
    +bool encl_data_map(const char *path, void **bin, off_t *bin_size)
    +{
    + int fd;
    +
    + fd = open(path, O_RDONLY);
    + if (fd == -1) {
    + fprintf(stderr, "open() %s failed, errno=%d.\n", path, errno);
    + return false;
    + }
    +
    + if (!get_file_size(path, bin_size))
    + goto err_out;
    +
    + *bin = mmap(NULL, *bin_size, PROT_READ, MAP_PRIVATE, fd, 0);
    + if (*bin == MAP_FAILED) {
    + fprintf(stderr, "mmap() %s failed, errno=%d.\n", path, errno);
    + goto err_out;
    + }
    +
    + close(fd);
    + return true;
    +
    +err_out:
    + close(fd);
    + return false;
    +}
    +
    +bool load_sigstruct(const char *path, void *sigstruct)
    +{
    + int fd;
    +
    + fd = open(path, O_RDONLY);
    + if (fd == -1) {
    + fprintf(stderr, "open() %s failed, errno=%d.\n", path, errno);
    + return false;
    + }
    +
    + if (read(fd, sigstruct, sizeof(struct sgx_sigstruct)) !=
    + sizeof(struct sgx_sigstruct)) {
    + fprintf(stderr, "read() %s failed, errno=%d.\n", path, errno);
    + close(fd);
    + return false;
    + }
    +
    + close(fd);
    + return true;
    +}
    +
    +int main(int argc, char *argv[], char *envp[])
    +{
    + struct sgx_sigstruct sigstruct;
    + struct sgx_secs secs;
    + uint64_t result = 0;
    + off_t bin_size;
    + void *bin;
    +
    + if (!encl_data_map("encl.bin", &bin, &bin_size))
    + exit(1);
    +
    + if (!load_sigstruct("encl.ss", &sigstruct))
    + exit(1);
    +
    + if (!encl_build(&secs, bin, bin_size, &sigstruct))
    + exit(1);
    +
    + printf("Input: 0x%lx\n", MAGIC);
    +
    + sgx_call_eenter((void *)&MAGIC, &result, (void *)secs.base);
    + if (result != MAGIC) {
    + fprintf(stderr, "0x%lx != 0x%lx\n", result, MAGIC);
    + exit(1);
    + }
    +
    + printf("Output: 0x%lx\n", result);
    +
    + exit(0);
    +}
    diff --git a/tools/testing/selftests/x86/sgx/sgx_call.S b/tools/testing/selftests/x86/sgx/sgx_call.S
    new file mode 100644
    index 000000000000..ca4c7893f9d9
    --- /dev/null
    +++ b/tools/testing/selftests/x86/sgx/sgx_call.S
    @@ -0,0 +1,23 @@
    +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
    +/**
    +* Copyright(c) 2016-18 Intel Corporation.
    +*/
    +
    + .text
    +
    + .macro ENCLU
    + .byte 0x0f, 0x01, 0xd7
    + .endm
    +
    + .text
    +
    + .global sgx_call_eenter
    +sgx_call_eenter:
    + push %rbx
    + mov $0x02, %rax
    + mov %rdx, %rbx
    + lea sgx_async_exit(%rip), %rcx
    +sgx_async_exit:
    + ENCLU
    + pop %rbx
    + ret
    diff --git a/tools/testing/selftests/x86/sgx/sgx_call.h b/tools/testing/selftests/x86/sgx/sgx_call.h
    new file mode 100644
    index 000000000000..bf72068ada23
    --- /dev/null
    +++ b/tools/testing/selftests/x86/sgx/sgx_call.h
    @@ -0,0 +1,11 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +/*
    + * Copyright(c) 2016-19 Intel Corporation.
    + */
    +
    +#ifndef SGX_CALL_H
    +#define SGX_CALL_H
    +
    +void sgx_call_eenter(void *rdi, void *rsi, void *entry);
    +
    +#endif /* SGX_CALL_H */
    diff --git a/tools/testing/selftests/x86/sgx/sgxsign.c b/tools/testing/selftests/x86/sgx/sgxsign.c
    new file mode 100644
    index 000000000000..3d9007af40c9
    --- /dev/null
    +++ b/tools/testing/selftests/x86/sgx/sgxsign.c
    @@ -0,0 +1,493 @@
    +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
    +// Copyright(c) 2016-18 Intel Corporation.
    +
    +#define _GNU_SOURCE
    +#include <getopt.h>
    +#include <stdbool.h>
    +#include <stdint.h>
    +#include <stdio.h>
    +#include <stdlib.h>
    +#include <string.h>
    +#include <sys/stat.h>
    +#include <sys/types.h>
    +#include <unistd.h>
    +#include <openssl/err.h>
    +#include <openssl/pem.h>
    +#include "defines.h"
    +
    +struct sgx_sigstruct_payload {
    + struct sgx_sigstruct_header header;
    + struct sgx_sigstruct_body body;
    +};
    +
    +static bool check_crypto_errors(void)
    +{
    + int err;
    + bool had_errors = false;
    + const char *filename;
    + int line;
    + char str[256];
    +
    + for ( ; ; ) {
    + if (ERR_peek_error() == 0)
    + break;
    +
    + had_errors = true;
    + err = ERR_get_error_line(&filename, &line);
    + ERR_error_string_n(err, str, sizeof(str));
    + fprintf(stderr, "crypto: %s: %s:%d\n", str, filename, line);
    + }
    +
    + return had_errors;
    +}
    +
    +static void exit_usage(const char *program)
    +{
    + fprintf(stderr,
    + "Usage: %s/sign-le <key> <enclave> <sigstruct>\n", program);
    + exit(1);
    +}
    +
    +static inline const BIGNUM *get_modulus(RSA *key)
    +{
    +#if OPENSSL_VERSION_NUMBER < 0x10100000L
    + return key->n;
    +#else
    + const BIGNUM *n;
    +
    + RSA_get0_key(key, &n, NULL, NULL);
    + return n;
    +#endif
    +}
    +
    +static RSA *load_sign_key(const char *path)
    +{
    + FILE *f;
    + RSA *key;
    +
    + f = fopen(path, "rb");
    + if (!f) {
    + fprintf(stderr, "Unable to open %s\n", path);
    + return NULL;
    + }
    + key = RSA_new();
    + if (!PEM_read_RSAPrivateKey(f, &key, NULL, NULL))
    + return NULL;
    + fclose(f);
    +
    + if (BN_num_bytes(get_modulus(key)) != SGX_MODULUS_SIZE) {
    + fprintf(stderr, "Invalid key size %d\n",
    + BN_num_bytes(get_modulus(key)));
    + RSA_free(key);
    + return NULL;
    + }
    +
    + return key;
    +}
    +
    +static void reverse_bytes(void *data, int length)
    +{
    + int i = 0;
    + int j = length - 1;
    + uint8_t temp;
    + uint8_t *ptr = data;
    +
    + while (i < j) {
    + temp = ptr[i];
    + ptr[i] = ptr[j];
    + ptr[j] = temp;
    + i++;
    + j--;
    + }
    +}
    +
    +enum mrtags {
    + MRECREATE = 0x0045544145524345,
    + MREADD = 0x0000000044444145,
    + MREEXTEND = 0x00444E4554584545,
    +};
    +
    +static bool mrenclave_update(EVP_MD_CTX *ctx, const void *data)
    +{
    + if (!EVP_DigestUpdate(ctx, data, 64)) {
    + fprintf(stderr, "digest update failed\n");
    + return false;
    + }
    +
    + return true;
    +}
    +
    +static bool mrenclave_commit(EVP_MD_CTX *ctx, uint8_t *mrenclave)
    +{
    + unsigned int size;
    +
    + if (!EVP_DigestFinal_ex(ctx, (unsigned char *)mrenclave, &size)) {
    + fprintf(stderr, "digest commit failed\n");
    + return false;
    + }
    +
    + if (size != 32) {
    + fprintf(stderr, "invalid digest size = %u\n", size);
    + return false;
    + }
    +
    + return true;
    +}
    +
    +struct mrecreate {
    + uint64_t tag;
    + uint32_t ssaframesize;
    + uint64_t size;
    + uint8_t reserved[44];
    +} __attribute__((__packed__));
    +
    +
    +static bool mrenclave_ecreate(EVP_MD_CTX *ctx, uint64_t blob_size)
    +{
    + struct mrecreate mrecreate;
    + uint64_t encl_size;
    +
    + for (encl_size = 0x1000; encl_size < blob_size; )
    + encl_size <<= 1;
    +
    + memset(&mrecreate, 0, sizeof(mrecreate));
    + mrecreate.tag = MRECREATE;
    + mrecreate.ssaframesize = 1;
    + mrecreate.size = encl_size;
    +
    + if (!EVP_DigestInit_ex(ctx, EVP_sha256(), NULL))
    + return false;
    +
    + return mrenclave_update(ctx, &mrecreate);
    +}
    +
    +struct mreadd {
    + uint64_t tag;
    + uint64_t offset;
    + uint64_t flags; /* SECINFO flags */
    + uint8_t reserved[40];
    +} __attribute__((__packed__));
    +
    +static bool mrenclave_eadd(EVP_MD_CTX *ctx, uint64_t offset, uint64_t flags)
    +{
    + struct mreadd mreadd;
    +
    + memset(&mreadd, 0, sizeof(mreadd));
    + mreadd.tag = MREADD;
    + mreadd.offset = offset;
    + mreadd.flags = flags;
    +
    + return mrenclave_update(ctx, &mreadd);
    +}
    +
    +struct mreextend {
    + uint64_t tag;
    + uint64_t offset;
    + uint8_t reserved[48];
    +} __attribute__((__packed__));
    +
    +static bool mrenclave_eextend(EVP_MD_CTX *ctx, uint64_t offset, uint8_t *data)
    +{
    + struct mreextend mreextend;
    + int i;
    +
    + for (i = 0; i < 0x1000; i += 0x100) {
    + memset(&mreextend, 0, sizeof(mreextend));
    + mreextend.tag = MREEXTEND;
    + mreextend.offset = offset + i;
    +
    + if (!mrenclave_update(ctx, &mreextend))
    + return false;
    +
    + if (!mrenclave_update(ctx, &data[i + 0x00]))
    + return false;
    +
    + if (!mrenclave_update(ctx, &data[i + 0x40]))
    + return false;
    +
    + if (!mrenclave_update(ctx, &data[i + 0x80]))
    + return false;
    +
    + if (!mrenclave_update(ctx, &data[i + 0xC0]))
    + return false;
    + }
    +
    + return true;
    +}
    +
    +/**
    + * measure_encl - measure enclave
    + * @path: path to the enclave
    + * @mrenclave: measurement
    + *
    + * Calculates MRENCLAVE. Assumes that the very first page is a TCS page and
    + * following pages are regular pages. Does not measure the contents of the
    + * enclave as the signing tool is used at the moment only for the launch
    + * enclave, which is pass-through (everything gets a token).
    + */
    +static bool measure_encl(const char *path, uint8_t *mrenclave)
    +{
    + FILE *file;
    + struct stat sb;
    + EVP_MD_CTX *ctx;
    + uint64_t flags;
    + uint64_t offset;
    + uint8_t data[0x1000];
    + int rc;
    +
    + ctx = EVP_MD_CTX_create();
    + if (!ctx)
    + return false;
    +
    + file = fopen(path, "rb");
    + if (!file) {
    + perror("fopen");
    + EVP_MD_CTX_destroy(ctx);
    + return false;
    + }
    +
    + rc = stat(path, &sb);
    + if (rc) {
    + perror("stat");
    + goto out;
    + }
    +
    + if (!sb.st_size || sb.st_size & 0xfff) {
    + fprintf(stderr, "Invalid blob size %lu\n", sb.st_size);
    + goto out;
    + }
    +
    + if (!mrenclave_ecreate(ctx, sb.st_size))
    + goto out;
    +
    + for (offset = 0; offset < sb.st_size; offset += 0x1000) {
    + if (!offset)
    + flags = SGX_SECINFO_TCS;
    + else
    + flags = SGX_SECINFO_REG | SGX_SECINFO_R |
    + SGX_SECINFO_W | SGX_SECINFO_X;
    +
    + if (!mrenclave_eadd(ctx, offset, flags))
    + goto out;
    +
    + rc = fread(data, 1, 0x1000, file);
    + if (!rc)
    + break;
    + if (rc < 0x1000)
    + goto out;
    +
    + if (!mrenclave_eextend(ctx, offset, data))
    + goto out;
    + }
    +
    + if (!mrenclave_commit(ctx, mrenclave))
    + goto out;
    +
    + fclose(file);
    + EVP_MD_CTX_destroy(ctx);
    + return true;
    +out:
    + fclose(file);
    + EVP_MD_CTX_destroy(ctx);
    + return false;
    +}
    +
    +/**
    + * sign_encl - sign enclave
    + * @sigstruct: pointer to SIGSTRUCT
    + * @key: 3072-bit RSA key
    + * @signature: byte array for the signature
    + *
    + * Calculates EMSA-PKCSv1.5 signature for the given SIGSTRUCT. The result is
    + * stored in big-endian format so that it can be further passed to OpenSSL
    + * libcrypto functions.
    + */
    +static bool sign_encl(const struct sgx_sigstruct *sigstruct, RSA *key,
    + uint8_t *signature)
    +{
    + struct sgx_sigstruct_payload payload;
    + unsigned int siglen;
    + uint8_t digest[SHA256_DIGEST_LENGTH];
    + bool ret;
    +
    + memcpy(&payload.header, &sigstruct->header, sizeof(sigstruct->header));
    + memcpy(&payload.body, &sigstruct->body, sizeof(sigstruct->body));
    +
    + SHA256((unsigned char *)&payload, sizeof(payload), digest);
    +
    + ret = RSA_sign(NID_sha256, digest, SHA256_DIGEST_LENGTH, signature,
    + &siglen, key);
    +
    + return ret;
    +}
    +
    +struct q1q2_ctx {
    + BN_CTX *bn_ctx;
    + BIGNUM *m;
    + BIGNUM *s;
    + BIGNUM *q1;
    + BIGNUM *qr;
    + BIGNUM *q2;
    +};
    +
    +static void free_q1q2_ctx(struct q1q2_ctx *ctx)
    +{
    + BN_CTX_free(ctx->bn_ctx);
    + BN_free(ctx->m);
    + BN_free(ctx->s);
    + BN_free(ctx->q1);
    + BN_free(ctx->qr);
    + BN_free(ctx->q2);
    +}
    +
    +static bool alloc_q1q2_ctx(const uint8_t *s, const uint8_t *m,
    + struct q1q2_ctx *ctx)
    +{
    + ctx->bn_ctx = BN_CTX_new();
    + ctx->s = BN_bin2bn(s, SGX_MODULUS_SIZE, NULL);
    + ctx->m = BN_bin2bn(m, SGX_MODULUS_SIZE, NULL);
    + ctx->q1 = BN_new();
    + ctx->qr = BN_new();
    + ctx->q2 = BN_new();
    +
    + if (!ctx->bn_ctx || !ctx->s || !ctx->m || !ctx->q1 || !ctx->qr ||
    + !ctx->q2) {
    + free_q1q2_ctx(ctx);
    + return false;
    + }
    +
    + return true;
    +}
    +
    +static bool calc_q1q2(const uint8_t *s, const uint8_t *m, uint8_t *q1,
    + uint8_t *q2)
    +{
    + struct q1q2_ctx ctx;
    +
    + if (!alloc_q1q2_ctx(s, m, &ctx)) {
    + fprintf(stderr, "Not enough memory for Q1Q2 calculation\n");
    + return false;
    + }
    +
    + if (!BN_mul(ctx.q1, ctx.s, ctx.s, ctx.bn_ctx))
    + goto out;
    +
    + if (!BN_div(ctx.q1, ctx.qr, ctx.q1, ctx.m, ctx.bn_ctx))
    + goto out;
    +
    + if (BN_num_bytes(ctx.q1) > SGX_MODULUS_SIZE) {
    + fprintf(stderr, "Too large Q1 %d bytes\n",
    + BN_num_bytes(ctx.q1));
    + goto out;
    + }
    +
    + if (!BN_mul(ctx.q2, ctx.s, ctx.qr, ctx.bn_ctx))
    + goto out;
    +
    + if (!BN_div(ctx.q2, NULL, ctx.q2, ctx.m, ctx.bn_ctx))
    + goto out;
    +
    + if (BN_num_bytes(ctx.q2) > SGX_MODULUS_SIZE) {
    + fprintf(stderr, "Too large Q2 %d bytes\n",
    + BN_num_bytes(ctx.q2));
    + goto out;
    + }
    +
    + BN_bn2bin(ctx.q1, q1);
    + BN_bn2bin(ctx.q2, q2);
    +
    + free_q1q2_ctx(&ctx);
    + return true;
    +out:
    + free_q1q2_ctx(&ctx);
    + return false;
    +}
    +
    +static bool save_sigstruct(const struct sgx_sigstruct *sigstruct,
    + const char *path)
    +{
    + FILE *f = fopen(path, "wb");
    +
    + if (!f) {
    + fprintf(stderr, "Unable to open %s\n", path);
    + return false;
    + }
    +
    + fwrite(sigstruct, sizeof(*sigstruct), 1, f);
    + fclose(f);
    + return true;
    +}
    +
    +int main(int argc, char **argv)
    +{
    + uint64_t header1[2] = {0x000000E100000006, 0x0000000000010000};
    + uint64_t header2[2] = {0x0000006000000101, 0x0000000100000060};
    + struct sgx_sigstruct ss;
    + const char *program;
    + int opt;
    + RSA *sign_key;
    +
    + memset(&ss, 0, sizeof(ss));
    + ss.header.header1[0] = header1[0];
    + ss.header.header1[1] = header1[1];
    + ss.header.header2[0] = header2[0];
    + ss.header.header2[1] = header2[1];
    + ss.exponent = 3;
    +
    +#ifndef CONFIG_EINITTOKENKEY
    + ss.body.attributes = SGX_ATTR_MODE64BIT;
    +#else
    + ss.body.attributes = SGX_ATTR_MODE64BIT | SGX_ATTR_EINITTOKENKEY;
    +#endif
    + ss.body.xfrm = 3,
    +
    + program = argv[0];
    +
    + do {
    + opt = getopt(argc, argv, "");
    + switch (opt) {
    + case -1:
    + break;
    + default:
    + exit_usage(program);
    + }
    + } while (opt != -1);
    +
    + argc -= optind;
    + argv += optind;
    +
    + if (argc < 3)
    + exit_usage(program);
    +
    + /* sanity check only */
    + if (check_crypto_errors())
    + exit(1);
    +
    + sign_key = load_sign_key(argv[0]);
    + if (!sign_key)
    + goto out;
    +
    + BN_bn2bin(get_modulus(sign_key), ss.modulus);
    +
    + if (!measure_encl(argv[1], ss.body.mrenclave))
    + goto out;
    +
    + if (!sign_encl(&ss, sign_key, ss.signature))
    + goto out;
    +
    + if (!calc_q1q2(ss.signature, ss.modulus, ss.q1, ss.q2))
    + goto out;
    +
    + /* convert to little endian */
    + reverse_bytes(ss.signature, SGX_MODULUS_SIZE);
    + reverse_bytes(ss.modulus, SGX_MODULUS_SIZE);
    + reverse_bytes(ss.q1, SGX_MODULUS_SIZE);
    + reverse_bytes(ss.q2, SGX_MODULUS_SIZE);
    +
    + if (!save_sigstruct(&ss, argv[2]))
    + goto out;
    + exit(0);
    +out:
    + check_crypto_errors();
    + exit(1);
    +}
    diff --git a/tools/testing/selftests/x86/sgx/signing_key.pem b/tools/testing/selftests/x86/sgx/signing_key.pem
    new file mode 100644
    index 000000000000..d76f21f19187
    --- /dev/null
    +++ b/tools/testing/selftests/x86/sgx/signing_key.pem
    @@ -0,0 +1,39 @@
    +-----BEGIN RSA PRIVATE KEY-----
    +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
    +-----END RSA PRIVATE KEY-----
    --
    2.25.0
    \
     
     \ /
      Last update: 2020-03-04 00:39    [W:2.679 / U:0.132 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site