From 174504be5921098e29b8376743883e1f6bc15ecd Mon Sep 17 00:00:00 2001 From: wangxiaozhe Date: Tue, 16 Jun 2020 19:56:52 +0800 Subject: [PATCH] rune/libenclave: Refresh skeleton example This new implementation inspires the design of https://github.com/jsakkine-intel/linux-sgx/tree/next/tools/testing/selftests/x86/sgx, which is a real enclave runtime. Signed-off-by: jack.wxz --- rune/Makefile | 4 +- .../internal/runtime/pal/skeleton/Makefile | 57 ++ .../internal/runtime/pal/skeleton/README.md | 3 + .../internal/runtime/pal/skeleton/arch.h | 372 +++++++++++++ .../internal/runtime/pal/skeleton/defines.h | 17 + .../internal/runtime/pal/skeleton/encl.c | 20 + .../internal/runtime/pal/skeleton/encl.lds | 34 ++ .../runtime/pal/skeleton/encl_bootstrap.S | 94 ++++ .../runtime/pal/skeleton/liberpal-skeleton.c | 327 +++++++++--- .../internal/runtime/pal/skeleton/pal.h | 5 + .../internal/runtime/pal/skeleton/sgx.h | 125 +++++ .../internal/runtime/pal/skeleton/sgx_call.S | 35 ++ .../internal/runtime/pal/skeleton/sgx_call.h | 11 + .../internal/runtime/pal/skeleton/sgxsign.c | 495 ++++++++++++++++++ 14 files changed, 1525 insertions(+), 74 deletions(-) create mode 100644 rune/libenclave/internal/runtime/pal/skeleton/Makefile create mode 100644 rune/libenclave/internal/runtime/pal/skeleton/arch.h create mode 100644 rune/libenclave/internal/runtime/pal/skeleton/defines.h create mode 100644 rune/libenclave/internal/runtime/pal/skeleton/encl.c create mode 100644 rune/libenclave/internal/runtime/pal/skeleton/encl.lds create mode 100644 rune/libenclave/internal/runtime/pal/skeleton/encl_bootstrap.S create mode 100644 rune/libenclave/internal/runtime/pal/skeleton/pal.h create mode 100644 rune/libenclave/internal/runtime/pal/skeleton/sgx.h create mode 100644 rune/libenclave/internal/runtime/pal/skeleton/sgx_call.S create mode 100644 rune/libenclave/internal/runtime/pal/skeleton/sgx_call.h create mode 100644 rune/libenclave/internal/runtime/pal/skeleton/sgxsign.c diff --git a/rune/Makefile b/rune/Makefile index 4c80b5d..2bbb12d 100644 --- a/rune/Makefile +++ b/rune/Makefile @@ -44,7 +44,7 @@ recvtty: skeleton: libenclave/internal/runtime/pal/skeleton/liberpal-skeleton.so libenclave/internal/runtime/pal/skeleton/liberpal-skeleton.so: - gcc -fPIC -shared -Wall -Wno-unused-const-variable -Ilibenclave/pal -o $@ libenclave/internal/runtime/pal/skeleton/liberpal-skeleton.c + make -C libenclave/internal/runtime/pal/skeleton static: $(GO_BUILD_STATIC) -o rune . @@ -125,7 +125,7 @@ clean: rm -rf release rm -rf man/man8 rm -f libenclave/proto/*.pb.go - rm -f libenclave/internal/runtime/pal/skeleton/liberpal-skeleton.so + make -C libenclave/internal/runtime/pal/skeleton clean validate: script/validate-gofmt diff --git a/rune/libenclave/internal/runtime/pal/skeleton/Makefile b/rune/libenclave/internal/runtime/pal/skeleton/Makefile new file mode 100644 index 0000000..6f5f2df --- /dev/null +++ b/rune/libenclave/internal/runtime/pal/skeleton/Makefile @@ -0,0 +1,57 @@ +ifndef OBJCOPY +OBJCOPY := $(CROSS_COMPILE)objcopy +endif + +OUTPUT ?= ./ +HOST_CFLAGS := -Wall -Werror -g -fPIC -z noexecstack \ + -Wno-unused-const-variable +ENCL_CFLAGS := -Wall -Werror -static -nostdlib -nostartfiles -fPIC \ + -fno-stack-protector -mrdrnd +HOST_LDFLAGS := -fPIC -shared + +TEST_CUSTOM_PROGS := $(OUTPUT)/encl.bin $(OUTPUT)/encl.ss $(OUTPUT)/liberpal-skeleton.so $(OUTPUT)/signing_key.pem $(OUTPUT)/encl.token + +all: $(TEST_CUSTOM_PROGS) + +$(OUTPUT)/liberpal-skeleton.so: $(OUTPUT)/sgx_call.o $(OUTPUT)/liberpal-skeleton.o + $(CC) $(HOST_LDFLAGS) -o $@ $^ + +$(OUTPUT)/liberpal-skeleton.o: liberpal-skeleton.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)/signing_key.pem: + openssl genrsa -3 -out $@ 3072 + +$(OUTPUT)/encl.ss: $(OUTPUT)/encl.bin $(OUTPUT)/signing_key.pem + $(OUTPUT)/sgxsign signing_key.pem $(OUTPUT)/encl.bin $(OUTPUT)/encl.ss + +$(OUTPUT)/encl.token: $(OUTPUT)/encl.ss + runectl gen-token --signature encl.ss --token $@ + +$(OUTPUT)/sgxsign: sgxsign.c + $(CC) -I../include -o $@ $< -lcrypto + +EXTRA_CLEAN := \ + $(OUTPUT)/encl.bin \ + $(OUTPUT)/encl.elf \ + $(OUTPUT)/encl.ss \ + $(OUTPUT)/sgx_call.o \ + $(OUTPUT)/sgxsign \ + $(OUTPUT)/liberpal-skeleton.o \ + $(OUTPUT)/liberpal-skeleton.so \ + $(OUTPUT)/signing_key.pem \ + $(OUTPUT)/encl.token + +clean: + rm -f ${EXTRA_CLEAN} + +.PHONY: clean all diff --git a/rune/libenclave/internal/runtime/pal/skeleton/README.md b/rune/libenclave/internal/runtime/pal/skeleton/README.md index b897d96..0cb4ef5 100644 --- a/rune/libenclave/internal/runtime/pal/skeleton/README.md +++ b/rune/libenclave/internal/runtime/pal/skeleton/README.md @@ -1,6 +1,9 @@ The files in this directory are used to implement a skeleton enclave runtime, in order to help to write your own enclave runtime. +# Install runectl +Refer to this document:[runectl](https://github.com/alibaba/inclavare-containers/tree/master/runectl) + # Build liberpal-skeleton.so ```shell cd "$GOPATH/src/github.com/alibaba/inclavare-containers/rune" diff --git a/rune/libenclave/internal/runtime/pal/skeleton/arch.h b/rune/libenclave/internal/runtime/pal/skeleton/arch.h new file mode 100644 index 0000000..d43acc1 --- /dev/null +++ b/rune/libenclave/internal/runtime/pal/skeleton/arch.h @@ -0,0 +1,372 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */ +/** + * Copyright(c) 2016-18 Intel Corporation. + * + * Contains data structures defined by the SGX architecture. Data structures + * defined by the Linux software stack should not be placed here. + * + * Inspired by https://github.com/jsakkine-intel/linux-sgx/tree/next/tools/testing/selftests/x86/sgx + */ +#ifndef _ASM_X86_SGX_ARCH_H +#define _ASM_X86_SGX_ARCH_H + +#include + +#define SGX_CPUID 0x12 +#define SGX_CPUID_FIRST_VARIABLE_SUB_LEAF 2 + +#ifndef BIT +#define BIT(nr) (1UL << (nr)) +#endif + +/** + * enum sgx_return_code - The return code type for ENCLS, ENCLU and ENCLV + * %SGX_NOT_TRACKED: Previous ETRACK's shootdown sequence has not + * been completed yet. + * %SGX_INVALID_EINITTOKEN: EINITTOKEN is invalid and enclave signer's + * public key does not match IA32_SGXLEPUBKEYHASH. + * %SGX_UNMASKED_EVENT: An unmasked event, e.g. INTR, was received + */ +enum sgx_return_code { + SGX_NOT_TRACKED = 11, + SGX_INVALID_EINITTOKEN = 16, + SGX_UNMASKED_EVENT = 128, +}; + +/** + * enum sgx_sub_leaf_types - SGX CPUID variable sub-leaf types + * %SGX_CPUID_SUB_LEAF_INVALID: Indicates this sub-leaf is invalid. + * %SGX_CPUID_SUB_LEAF_EPC_SECTION: Sub-leaf enumerates an EPC section. + */ +enum sgx_sub_leaf_types { + SGX_CPUID_SUB_LEAF_INVALID = 0x0, + SGX_CPUID_SUB_LEAF_EPC_SECTION = 0x1, +}; + +#define SGX_CPUID_SUB_LEAF_TYPE_MASK GENMASK(3, 0) + +#define SGX_MODULUS_SIZE 384 + +/** + * enum sgx_miscselect - additional information to an SSA frame + * %SGX_MISC_EXINFO: Report #PF or #GP to the SSA frame. + * + * Save State Area (SSA) is a stack inside the enclave used to store processor + * state when an exception or interrupt occurs. This enum defines additional + * information stored to an SSA frame. + */ +enum sgx_miscselect { + SGX_MISC_EXINFO = BIT(0), +}; + +#define SGX_MISC_RESERVED_MASK GENMASK_ULL(63, 1) + +#define SGX_SSA_GPRS_SIZE 184 +#define SGX_SSA_MISC_EXINFO_SIZE 16 + +/** + * enum sgx_attributes - the attributes field in &struct sgx_secs + * %SGX_ATTR_INIT: Enclave can be entered (is initialized). + * %SGX_ATTR_DEBUG: Allow ENCLS(EDBGRD) and ENCLS(EDBGWR). + * %SGX_ATTR_MODE64BIT: Tell that this a 64-bit enclave. + * %SGX_ATTR_PROVISIONKEY: Allow to use provisioning keys for remote + * attestation. + * %SGX_ATTR_KSS: Allow to use key separation and sharing (KSS). + * %SGX_ATTR_EINITTOKENKEY: Allow to use token signing key that is used to + * sign cryptographic tokens that can be passed to + * EINIT as an authorization to run an enclave. + */ +enum sgx_attribute { + SGX_ATTR_INIT = BIT(0), + SGX_ATTR_DEBUG = BIT(1), + SGX_ATTR_MODE64BIT = BIT(2), + SGX_ATTR_PROVISIONKEY = BIT(4), + SGX_ATTR_EINITTOKENKEY = BIT(5), + SGX_ATTR_KSS = BIT(7), +}; + +#define SGX_ATTR_RESERVED_MASK (BIT_ULL(3) | BIT_ULL(6) | GENMASK_ULL(63, 8)) +#define SGX_ATTR_ALLOWED_MASK (SGX_ATTR_DEBUG | SGX_ATTR_MODE64BIT | \ + SGX_ATTR_KSS) + +/** + * struct sgx_secs - SGX Enclave Control Structure (SECS) + * @size: size of the address space + * @base: base address of the address space + * @ssa_frame_size: size of an SSA frame + * @miscselect: additional information stored to an SSA frame + * @attributes: attributes for enclave + * @xfrm: XSave-Feature Request Mask (subset of XCR0) + * @mrenclave: SHA256-hash of the enclave contents + * @mrsigner: SHA256-hash of the public key used to sign the SIGSTRUCT + * @config_id: a user-defined value that is used in key derivation + * @isv_prod_id: a user-defined value that is used in key derivation + * @isv_svn: a user-defined value that is used in key derivation + * @config_svn: a user-defined value that is used in key derivation + * + * SGX Enclave Control Structure (SECS) is a special enclave page that is not + * visible in the address space. In fact, this structure defines the address + * range and other global attributes for the enclave and it is the first EPC + * page created for any enclave. It is moved from a temporary buffer to an EPC + * by the means of ENCLS(ECREATE) leaf. + */ +struct sgx_secs { + uint64_t size; + uint64_t base; + uint32_t ssa_frame_size; + uint32_t miscselect; + uint8_t reserved1[24]; + uint64_t attributes; + uint64_t xfrm; + uint32_t mrenclave[8]; + uint8_t reserved2[32]; + uint32_t mrsigner[8]; + uint8_t reserved3[32]; + uint32_t config_id[16]; + uint16_t isv_prod_id; + uint16_t isv_svn; + uint16_t config_svn; + uint8_t reserved4[3834]; +} __packed; + +/** + * enum sgx_tcs_flags - execution flags for TCS + * %SGX_TCS_DBGOPTIN: If enabled allows single-stepping and breakpoints + * inside an enclave. It is cleared by EADD but can + * be set later with EDBGWR. + */ +enum sgx_tcs_flags { + SGX_TCS_DBGOPTIN = 0x01, +}; + +#define SGX_TCS_RESERVED_MASK GENMASK_ULL(63, 1) +#define SGX_TCS_RESERVED_SIZE 4024 + +/** + * struct sgx_tcs - Thread Control Structure (TCS) + * @state: used to mark an entered TCS + * @flags: execution flags (cleared by EADD) + * @ssa_offset: SSA stack offset relative to the enclave base + * @ssa_index: the current SSA frame index (cleard by EADD) + * @nr_ssa_frames: the number of frame in the SSA stack + * @entry_offset: entry point offset relative to the enclave base + * @exit_addr: address outside the enclave to exit on an exception or + * interrupt + * @fs_offset: offset relative to the enclave base to become FS + * segment inside the enclave + * @gs_offset: offset relative to the enclave base to become GS + * segment inside the enclave + * @fs_limit: size to become a new FS-limit (only 32-bit enclaves) + * @gs_limit: size to become a new GS-limit (only 32-bit enclaves) + * + * Thread Control Structure (TCS) is an enclave page visible in its address + * space that defines an entry point inside the enclave. A thread enters inside + * an enclave by supplying address of TCS to ENCLU(EENTER). A TCS can be entered + * by only one thread at a time. + */ +struct sgx_tcs { + uint64_t state; + uint64_t flags; + uint64_t ssa_offset; + uint32_t ssa_index; + uint32_t nr_ssa_frames; + uint64_t entry_offset; + uint64_t exit_addr; + uint64_t fs_offset; + uint64_t gs_offset; + uint32_t fs_limit; + uint32_t gs_limit; + uint8_t reserved[SGX_TCS_RESERVED_SIZE]; +} __packed; + +/** + * struct sgx_pageinfo - an enclave page descriptor + * @addr: address of the enclave page + * @contents: pointer to the page contents + * @metadata: pointer either to a SECINFO or PCMD instance + * @secs: address of the SECS page + */ +struct sgx_pageinfo { + uint64_t addr; + uint64_t contents; + uint64_t metadata; + uint64_t secs; +} __packed __aligned(32); + + +/** + * enum sgx_page_type - bits in the SECINFO flags defining the page type + * %SGX_PAGE_TYPE_SECS: a SECS page + * %SGX_PAGE_TYPE_TCS: a TCS page + * %SGX_PAGE_TYPE_REG: a regular page + * %SGX_PAGE_TYPE_VA: a VA page + * %SGX_PAGE_TYPE_TRIM: a page in trimmed state + */ +enum sgx_page_type { + SGX_PAGE_TYPE_SECS, + SGX_PAGE_TYPE_TCS, + SGX_PAGE_TYPE_REG, + SGX_PAGE_TYPE_VA, + SGX_PAGE_TYPE_TRIM, +}; + +#define SGX_NR_PAGE_TYPES 5 +#define SGX_PAGE_TYPE_MASK GENMASK(7, 0) + +/** + * enum sgx_secinfo_flags - the flags field in &struct sgx_secinfo + * %SGX_SECINFO_R: allow read + * %SGX_SECINFO_W: allow write + * %SGX_SECINFO_X: allow execution + * %SGX_SECINFO_SECS: a SECS page + * %SGX_SECINFO_TCS: a TCS page + * %SGX_SECINFO_REG: a regular page + * %SGX_SECINFO_VA: a VA page + * %SGX_SECINFO_TRIM: a page in trimmed state + */ +enum sgx_secinfo_flags { + SGX_SECINFO_R = BIT(0), + SGX_SECINFO_W = BIT(1), + SGX_SECINFO_X = BIT(2), + SGX_SECINFO_SECS = (SGX_PAGE_TYPE_SECS << 8), + SGX_SECINFO_TCS = (SGX_PAGE_TYPE_TCS << 8), + SGX_SECINFO_REG = (SGX_PAGE_TYPE_REG << 8), + SGX_SECINFO_VA = (SGX_PAGE_TYPE_VA << 8), + SGX_SECINFO_TRIM = (SGX_PAGE_TYPE_TRIM << 8), +}; + +#define SGX_SECINFO_PERMISSION_MASK GENMASK_ULL(2, 0) +#define SGX_SECINFO_PAGE_TYPE_MASK (SGX_PAGE_TYPE_MASK << 8) +#define SGX_SECINFO_RESERVED_MASK ~(SGX_SECINFO_PERMISSION_MASK | \ + SGX_SECINFO_PAGE_TYPE_MASK) + +/** + * struct sgx_secinfo - describes attributes of an EPC page + * @flags: permissions and type + * + * Used together with ENCLS leaves that add or modify an EPC page to an + * enclave to define page permissions and type. + */ +struct sgx_secinfo { + uint64_t flags; + uint8_t reserved[56]; +} __packed __aligned(64); + +#define SGX_PCMD_RESERVED_SIZE 40 + +/** + * struct sgx_pcmd - Paging Crypto Metadata (PCMD) + * @enclave_id: enclave identifier + * @mac: MAC over PCMD, page contents and isvsvn + * + * PCMD is stored for every swapped page to the regular memory. When ELDU loads + * the page back it recalculates the MAC by using a isvsvn number stored in a + * VA page. Together these two structures bring integrity and rollback + * protection. + */ +struct sgx_pcmd { + struct sgx_secinfo secinfo; + uint64_t enclave_id; + uint8_t reserved[SGX_PCMD_RESERVED_SIZE]; + uint8_t mac[16]; +} __packed __aligned(128); + +#define SGX_SIGSTRUCT_RESERVED1_SIZE 84 +#define SGX_SIGSTRUCT_RESERVED2_SIZE 20 +#define SGX_SIGSTRUCT_RESERVED3_SIZE 32 +#define SGX_SIGSTRUCT_RESERVED4_SIZE 12 + +/** + * struct sgx_sigstruct_header - defines author of the enclave + * @header1: constant byte string + * @vendor: must be either 0x0000 or 0x8086 + * @date: YYYYMMDD in BCD + * @header2: costant byte string + * @swdefined: software defined value + */ +struct sgx_sigstruct_header { + uint64_t header1[2]; + uint32_t vendor; + uint32_t date; + uint64_t header2[2]; + uint32_t swdefined; + uint8_t reserved1[84]; +} __packed; + +/** + * struct sgx_sigstruct_body - defines contents of the enclave + * @miscselect: additional information stored to an SSA frame + * @misc_mask: required miscselect in SECS + * @attributes: attributes for enclave + * @xfrm: XSave-Feature Request Mask (subset of XCR0) + * @attributes_mask: required attributes in SECS + * @xfrm_mask: required XFRM in SECS + * @mrenclave: SHA256-hash of the enclave contents + * @isvprodid: a user-defined value that is used in key derivation + * @isvsvn: a user-defined value that is used in key derivation + */ +struct sgx_sigstruct_body { + uint32_t miscselect; + uint32_t misc_mask; + uint8_t reserved2[20]; + uint64_t attributes; + uint64_t xfrm; + uint64_t attributes_mask; + uint64_t xfrm_mask; + uint8_t mrenclave[32]; + uint8_t reserved3[32]; + uint16_t isvprodid; + uint16_t isvsvn; +} __packed; + +/** + * struct sgx_sigstruct - an enclave signature + * @header: defines author of the enclave + * @modulus: the modulus of the public key + * @exponent: the exponent of the public key + * @signature: the signature calculated over the fields except modulus, + * @body: defines contents of the enclave + * @q1: a value used in RSA signature verification + * @q2: a value used in RSA signature verification + * + * Header and body are the parts that are actual signed. The remaining fields + * define the signature of the enclave. + */ +struct sgx_sigstruct { + struct sgx_sigstruct_header header; + uint8_t modulus[SGX_MODULUS_SIZE]; + uint32_t exponent; + uint8_t signature[SGX_MODULUS_SIZE]; + struct sgx_sigstruct_body body; + uint8_t reserved4[12]; + uint8_t q1[SGX_MODULUS_SIZE]; + uint8_t q2[SGX_MODULUS_SIZE]; +} __packed; + +struct sgx_einittoken_payload { + uint32_t valid; + uint32_t reserved1[11]; + uint64_t attributes; + uint64_t xfrm; + uint8_t mrenclave[32]; + uint8_t reserved2[32]; + uint8_t mrsigner[32]; + uint8_t reserved3[32]; +}; + +struct sgx_einittoken { + struct sgx_einittoken_payload payload; + uint8_t cpusvnle[16]; + uint16_t isvprodidle; + uint16_t isvsvnle; + uint8_t reserved2[24]; + uint32_t maskedmiscselectle; + uint64_t maskedattributesle; + uint64_t maskedxfrmle; + uint8_t keyid[32]; + uint8_t mac[16]; +}; + +#define SGX_LAUNCH_TOKEN_SIZE 304 + +#endif /* _ASM_X86_SGX_ARCH_H */ diff --git a/rune/libenclave/internal/runtime/pal/skeleton/defines.h b/rune/libenclave/internal/runtime/pal/skeleton/defines.h new file mode 100644 index 0000000..6591cdc --- /dev/null +++ b/rune/libenclave/internal/runtime/pal/skeleton/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 + +#define __aligned(x) __attribute__((__aligned__(x))) +#define __packed __attribute__((packed)) + +#include "arch.h" +#include "sgx.h" + +#endif /* DEFINES_H */ diff --git a/rune/libenclave/internal/runtime/pal/skeleton/encl.c b/rune/libenclave/internal/runtime/pal/skeleton/encl.c new file mode 100644 index 0000000..ede9153 --- /dev/null +++ b/rune/libenclave/internal/runtime/pal/skeleton/encl.c @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-18 Intel Corporation. + +#include +#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/rune/libenclave/internal/runtime/pal/skeleton/encl.lds b/rune/libenclave/internal/runtime/pal/skeleton/encl.lds new file mode 100644 index 0000000..9a56d30 --- /dev/null +++ b/rune/libenclave/internal/runtime/pal/skeleton/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/rune/libenclave/internal/runtime/pal/skeleton/encl_bootstrap.S b/rune/libenclave/internal/runtime/pal/skeleton/encl_bootstrap.S new file mode 100644 index 0000000..d07f970 --- /dev/null +++ b/rune/libenclave/internal/runtime/pal/skeleton/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/rune/libenclave/internal/runtime/pal/skeleton/liberpal-skeleton.c b/rune/libenclave/internal/runtime/pal/skeleton/liberpal-skeleton.c index a77b9b2..bd52708 100644 --- a/rune/libenclave/internal/runtime/pal/skeleton/liberpal-skeleton.c +++ b/rune/libenclave/internal/runtime/pal/skeleton/liberpal-skeleton.c @@ -1,16 +1,31 @@ -#include -#include +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-18 Intel Corporation. + +#include #include -#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "defines.h" +#include "sgx_call.h" -#define BUFF_LEN 1024 -#define DEBUG_ARGS "debug" +#define PAGE_SIZE 4096 -static const unsigned int skeleton_pal_version = 1; +#define SGX_REG_PAGE_FLAGS \ + (SGX_SECINFO_REG | SGX_SECINFO_R | SGX_SECINFO_W | SGX_SECINFO_X) -static bool initialized = false; -static bool debug = false; +#define IMAGE "encl.bin" +#define SIGSTRUCT "encl.ss" +#define TOKEN "encl.token" struct pal_attr_t { const char *args; @@ -21,82 +36,252 @@ struct pal_stdio_fds { int stdin, stdout, stderr; }; -int skeleton_pal_init(struct pal_attr_t *attr) +static const unsigned int skeleton_pal_version = 1; + +static const uint64_t MAGIC = 0x1122334455667788ULL; +static struct sgx_secs secs; +static bool initialized = false; + +static bool encl_create(int dev_fd, unsigned long bin_size, + struct sgx_secs *secs) { - if (!attr->args) - return -ENOENT; + struct sgx_enclave_create ioc; + void *area; + int rc; + + memset(secs, 0, sizeof(*secs)); + secs->ssa_frame_size = 1; + secs->attributes = SGX_ATTR_MODE64BIT | SGX_ATTR_DEBUG; + secs->xfrm = 7; - char *args = (char *)attr->args; - while ((args = strtok(args, " "))) { - if (!strcmp(args, DEBUG_ARGS)) - debug = true; - args = NULL; + for (secs->size = PAGE_SIZE; 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; } - initialized = true; + 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); - return 0; + if (mprotect((void *)secs->base, secs->size, PROT_READ | PROT_WRITE | PROT_EXEC)) { + perror("mprotect"); + return false; + } + + 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; } -int skeleton_pal_exec(char *path, char *argv[], struct pal_stdio_fds *stdio, - int *exit_code) +static bool encl_add_pages(int dev_fd, unsigned long addr, void *data, + unsigned long length, uint64_t flags) { - if (!path || access(path, F_OK) != 0) - return -ENOENT; - - if (access(path, R_OK) != 0) - return -EACCES; + struct sgx_enclave_add_page ioc; + struct sgx_secinfo secinfo; + int rc; - if (!stdio) - return -EINVAL; + memset(&secinfo, 0, sizeof(secinfo)); + secinfo.flags = flags; - if (!exit_code) - return -EINVAL; + ioc.src = (uint64_t)data; + ioc.addr = addr; + ioc.secinfo = (unsigned long)&secinfo; + ioc.mrmask = (__u16)-1; - if (!initialized) { - fprintf(stderr, "enclave runtime skeleton uninitialized yet!\n"); - return -EINVAL; - } - - int i; - - if (debug) { - for (i = 0; argv[i]; ++i) - printf("argv[%d] = %s\n", i, argv[i]); - } - - for (i = 0; i < 60; ++i) { - sleep(1); - if (stdio->stdout < 0 && debug) { - printf("pal_exec running %d seconds\n", i + 1); - } else { - char buf[BUFF_LEN]; - - ssize_t len; - if (debug) - len = snprintf(buf, BUFF_LEN, "pal_exec running %d seconds, " - "outputting to fd %d\n", i + 1, stdio->stdout); - else - len = snprintf(buf, BUFF_LEN, "%d", i + 1); - - ssize_t bytes = 0; - while (bytes < len) { - ssize_t n = write(stdio->stdout, &buf[bytes], len - bytes); - if (n < 0) { - if (errno == EAGAIN || errno == EINTR) - continue; - - fprintf(stderr, "write failed\n"); - return -1; - } else if (n == 0) { - fprintf(stderr, "stdout is EOF\n"); - return -1; - } else - bytes += n; - } + uint64_t added_size = 0; + while (added_size < length) { + rc = ioctl(dev_fd, SGX_IOC_ENCLAVE_ADD_PAGE, &ioc); + if (rc) { + fprintf(stderr, "EADD failed rc=%d.\n", rc); + return false; } + + ioc.addr += PAGE_SIZE; + ioc.src += PAGE_SIZE; + added_size += PAGE_SIZE; + } + + return true; +} + +static bool encl_build(struct sgx_secs *secs, void *bin, unsigned long bin_size, + struct sgx_sigstruct *sigstruct,struct sgx_einittoken *token) +{ + struct sgx_enclave_init ioc; + int dev_fd; + int rc; + + dev_fd = open("/dev/isgx", 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, secs->base + 0, bin, PAGE_SIZE, SGX_SECINFO_TCS)) + goto out_dev_fd; + + if (!encl_add_pages(dev_fd, secs->base + PAGE_SIZE, bin + PAGE_SIZE, + bin_size - PAGE_SIZE, SGX_REG_PAGE_FLAGS)) + goto out_dev_fd; + + ioc.addr = secs->base; + ioc.sigstruct = (uint64_t)sigstruct; + ioc.einittoken = (uint64_t)token; + rc = ioctl(dev_fd, SGX_IOC_ENCLAVE_INIT, &ioc); + if (rc) { + printf("EINIT failed rc=%d\n", rc); + goto out_map; + } + + 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; +} + +bool load_token(const char *path, void *token) +{ + 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, token, sizeof(struct sgx_einittoken)) != + sizeof(struct sgx_einittoken)) { + fprintf(stderr, "read() %s failed, errno=%d.\n", path, errno); + close(fd); + return false; + } + + close(fd); + return true; +} + +int skeleton_pal_init(struct pal_attr_t *attr) +{ + struct sgx_sigstruct sigstruct; + struct sgx_einittoken token; + off_t bin_size; + void *bin; + + if (!encl_data_map(IMAGE, &bin, &bin_size)) + return ENOENT; + + if (!load_sigstruct(SIGSTRUCT, &sigstruct)) + return ENOENT; + + if (!load_token(TOKEN, &token)) + return ENOENT; + + if (!encl_build(&secs, bin, bin_size, &sigstruct, &token)) + return EINVAL; + + initialized = true; + return 0; +} + +int skeleton_pal_exec(char *path, char *argv[], struct pal_stdio_fds *stdio, + int *exit_code) +{ + uint64_t result = 0; + + sgx_call_eenter((void *)&MAGIC, &result, (void *)secs.base); + + if (result != MAGIC) { + fprintf(stderr, "0x%lx != 0x%lx\n", result, MAGIC); + return -1; + } + + fprintf(stderr, "copy MAGIC with enclave sucess.\n"); + *exit_code = 0; return 0; } @@ -106,7 +291,5 @@ int skeleton_pal_destroy(void) fprintf(stderr, "enclave runtime skeleton uninitialized yet!\n"); return -1; } - - printf("enclave runtime skeleton exits\n"); return 0; } diff --git a/rune/libenclave/internal/runtime/pal/skeleton/pal.h b/rune/libenclave/internal/runtime/pal/skeleton/pal.h new file mode 100644 index 0000000..53d52d4 --- /dev/null +++ b/rune/libenclave/internal/runtime/pal/skeleton/pal.h @@ -0,0 +1,5 @@ +int pal_skeleton_init(char *instance_path); +int pal_skeleton_exec(char *path, char *argv[], int *exit_value, + int stdin_fd, int stdout_fd, int stderr_fd); +int pal_skeleton_kill(int sig, int pid); +int pal_skeleton_destroy(); diff --git a/rune/libenclave/internal/runtime/pal/skeleton/sgx.h b/rune/libenclave/internal/runtime/pal/skeleton/sgx.h new file mode 100644 index 0000000..ce16e44 --- /dev/null +++ b/rune/libenclave/internal/runtime/pal/skeleton/sgx.h @@ -0,0 +1,125 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) WITH Linux-syscall-note */ +/* + * Copyright(c) 2016-19 Intel Corporation. + */ +#ifndef _UAPI_ASM_X86_SGX_H +#define _UAPI_ASM_X86_SGX_H + +#include +#include + +/** + * enum sgx_epage_flags - page control flags + * %SGX_PAGE_MEASURE: Measure the page contents with a sequence of + * ENCLS[EEXTEND] operations. + */ +enum sgx_page_flags { + SGX_PAGE_MEASURE = 0x01, +}; + +#define SGX_MAGIC 0xA4 + +#define SGX_IOC_ENCLAVE_CREATE \ + _IOW(SGX_MAGIC, 0x00, struct sgx_enclave_create) +#define SGX_IOC_ENCLAVE_ADD_PAGES \ + _IOWR(SGX_MAGIC, 0x01, struct sgx_enclave_add_pages) +#define SGX_IOC_ENCLAVE_INIT \ + _IOW(SGX_MAGIC, 0x02, struct sgx_enclave_init) +#define SGX_IOC_ENCLAVE_SET_ATTRIBUTE \ + _IOW(SGX_MAGIC, 0x03, struct sgx_enclave_set_attribute) +#define SGX_IOC_ENCLAVE_ADD_PAGE \ + _IOW(SGX_MAGIC, 0x01, struct sgx_enclave_add_page) + +/** + * struct sgx_enclave_create - parameter structure for the + * %SGX_IOC_ENCLAVE_CREATE ioctl + * @src: address for the SECS page data + */ +struct sgx_enclave_create { + __u64 src; +}; + +/** + * struct sgx_enclave_add_pages - parameter structure for the + * %SGX_IOC_ENCLAVE_ADD_PAGE ioctl + * @src: start address for the page data + * @offset: starting page offset + * @length: length of the data (multiple of the page size) + * @secinfo: address for the SECINFO data + * @flags: page control flags + * @count: number of bytes added (multiple of the page size) + */ +struct sgx_enclave_add_pages { + __u64 src; + __u64 offset; + __u64 length; + __u64 secinfo; + __u64 flags; + __u64 count; +}; + +struct sgx_enclave_add_page { + __u64 addr; + __u64 src; + __u64 secinfo; + __u16 mrmask; +} __attribute__((__packed__)); + +/** + * struct sgx_enclave_init - parameter structure for the + * %SGX_IOC_ENCLAVE_INIT ioctl + * @sigstruct: address for the SIGSTRUCT data + */ +struct sgx_enclave_init { + __u64 addr; + __u64 sigstruct; + __u64 einittoken; +} __attribute__((__packed__)); + +/** + * struct sgx_enclave_set_attribute - parameter structure for the + * %SGX_IOC_ENCLAVE_SET_ATTRIBUTE ioctl + * @attribute_fd: file handle of the attribute file in the securityfs + */ +struct sgx_enclave_set_attribute { + __u64 attribute_fd; +}; + +/** + * struct sgx_enclave_exception - structure to report exceptions encountered in + * __vdso_sgx_enter_enclave() + * + * @leaf: ENCLU leaf from \%eax at time of exception + * @trapnr: exception trap number, a.k.a. fault vector + * @error_code: exception error code + * @address: exception address, e.g. CR2 on a #PF + * @reserved: reserved for future use + */ +struct sgx_enclave_exception { + __u32 leaf; + __u16 trapnr; + __u16 error_code; + __u64 address; + __u64 reserved[2]; +}; + +/** + * typedef sgx_enclave_exit_handler_t - Exit handler function accepted by + * __vdso_sgx_enter_enclave() + * + * @rdi: RDI at the time of enclave exit + * @rsi: RSI at the time of enclave exit + * @rdx: RDX at the time of enclave exit + * @ursp: RSP at the time of enclave exit (untrusted stack) + * @r8: R8 at the time of enclave exit + * @r9: R9 at the time of enclave exit + * @tcs: Thread Control Structure used to enter enclave + * @ret: 0 on success (EEXIT), -EFAULT on an exception + * @e: Pointer to struct sgx_enclave_exception (as provided by caller) + */ +typedef int (*sgx_enclave_exit_handler_t)(long rdi, long rsi, long rdx, + long ursp, long r8, long r9, + void *tcs, int ret, + struct sgx_enclave_exception *e); + +#endif /* _UAPI_ASM_X86_SGX_H */ diff --git a/rune/libenclave/internal/runtime/pal/skeleton/sgx_call.S b/rune/libenclave/internal/runtime/pal/skeleton/sgx_call.S new file mode 100644 index 0000000..e29f643 --- /dev/null +++ b/rune/libenclave/internal/runtime/pal/skeleton/sgx_call.S @@ -0,0 +1,35 @@ +/* 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 + push %rdi + push %rsi + push %r12 + push %r13 + push %r14 + push %r15 + mov $0x02, %rax + mov %rdx, %rbx + lea sgx_async_exit(%rip), %rcx +sgx_async_exit: + ENCLU + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rsi + pop %rdi + pop %rbx + ret diff --git a/rune/libenclave/internal/runtime/pal/skeleton/sgx_call.h b/rune/libenclave/internal/runtime/pal/skeleton/sgx_call.h new file mode 100644 index 0000000..bf72068 --- /dev/null +++ b/rune/libenclave/internal/runtime/pal/skeleton/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/rune/libenclave/internal/runtime/pal/skeleton/sgxsign.c b/rune/libenclave/internal/runtime/pal/skeleton/sgxsign.c new file mode 100644 index 0000000..6440541 --- /dev/null +++ b/rune/libenclave/internal/runtime/pal/skeleton/sgxsign.c @@ -0,0 +1,495 @@ +// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) +// Copyright(c) 2016-18 Intel Corporation. + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 \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.attributes |= SGX_ATTR_DEBUG; + ss.body.xfrm = 7; + ss.body.attributes_mask = ss.body.attributes; + + 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); +} -- GitLab