On Tue, Mar 3, 2020 at 6:39 PM Jarkko Sakkinen jarkko.sakkinen@linux.intel.com wrote:
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), %raxxchg %rsp, %raxpush %raxpush %rcx # push the address after EENTERpush %rbx # push the enclave base addresscall encl_bodypop %rbx # pop the enclave base address# Restore XSAVE registers to a synthetic state.mov $0xFFFFFFFF, %raxmov $0xFFFFFFFF, %rdxlea (xsave_area)(%rbx), %rdifxrstor (%rdi)# Clear GPRs.xor %rcx, %rcxxor %rdx, %rdxxor %rdi, %rdixor %rsi, %rsixor %r8, %r8xor %r9, %r9xor %r10, %r10xor %r11, %r11xor %r12, %r12xor %r13, %r13xor %r14, %r14xor %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 %raxmov %rax, %rsp# EEXITmov $4, %raxenclu.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
I find this much more readable:
xsave_area: # Legacy .fill 1, 4, 0x037F # FCW .fill 5, 4, 0 .fill 1, 4, 0x1F80 # MXCSR .fill 1, 4, 0xFFFF # MXCSR_MASK .fill 60, 8, 0
# Header .fill 1, 8, 0 # XSTATE_BV .fill 1, 8, 1 << 63 # XCOMP_BV (compaction mode) .fill 6, 8, 0
Also, since people are likely to copy this code for their own enclaves, it would be helpful to document which flags are set in FCW and MXCSR.
.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 %rbxmov $0x02, %raxmov %rdx, %rbxlea sgx_async_exit(%rip), %rcx+sgx_async_exit:
ENCLUpop %rbxretdiff --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;elseflags = 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