Browse Source

Implements most of libsgx_capable for Linux (previously only available in the Windows SDK) (#107)

* Adds libsgx_capable, which is currently only available in the Windows
version of the Intel SGX SDK. The Linux implementation of this library
adds the following functions:

  sgx_status_t sgx_is_capable (int *sgx_capable);
  sgx_status_t sgx_cap_get_status (sgx_device_status_t *sgx_device_status);
  sgx_status_t sgx_cap_enable_device (sgx_device_status_t *sgx_device_status);

And adds the following error code (also from the Windows version of the
Intel SGX SDK):

  SGX_ERROR_NO_PRIVILEGE

Generates both a static and dynamic build of libsgx_capable. This is
incorporated into the SDK package, not the PSW package, since software
installers need to check for Intel SGX capability on systems where the PSW
may not already be installed. This means that installers will either have
to statically link, or distribute the .so with their installation package.

----------------------

Developer Certificate of Origin
Version 1.1

Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
660 York Street, Suite 102,
San Francisco, CA 94110 USA

Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.

Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.

Signed-off-by: John P Mechalas <john.p.mechalas@intel.com>
John Mechalas 6 years ago
parent
commit
6f0e20cfd9

+ 90 - 0
common/inc/sgx_capable.h

@@ -0,0 +1,90 @@
+/*
+* Copyright 2011-2017 Intel Corporation
+* 
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 
+* 1. Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+* 
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* 
+* 3. Neither the name of the copyright holder nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+* 
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#pragma once
+
+#ifndef _SGX_CAPABLE_H_
+#define _SGX_CAPABLE_H_
+
+#include "sgx_error.h"
+#include "sgx_defs.h"
+
+#if defined(_MSC_VER)
+#include <Windows.h>
+#endif
+
+typedef enum _sgx_device_status_t {
+    SGX_ENABLED,
+    SGX_DISABLED_REBOOT_REQUIRED, /* A reboot is required to finish enabling SGX */
+    SGX_DISABLED_LEGACY_OS, /* SGX is disabled and a Software Control Interface is not available to enable it */
+    SGX_DISABLED, /* SGX is not enabled on this platform. More details are unavailable. */
+    SGX_DISABLED_SCI_AVAILABLE, /* SGX is disabled, but a Software Control Interface is available to enable it */
+    SGX_DISABLED_MANUAL_ENABLE, /* SGX is disabled, but can be enabled manually in the BIOS setup */
+    SGX_DISABLED_HYPERV_ENABLED, /* Detected an unsupported version of Windows* 10 with Hyper-V enabled */
+    SGX_DISABLED_UNSUPPORTED_CPU, /* SGX is not supported by this CPU */
+} sgx_device_status_t;
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Function to check if the client platform is SGX enabled.
+ *
+ * @param sgx_capable[out] The SGX capable status of the client platform.
+ *          1 - Platform is SGX enabled or the Software Control Interface is available to configure SGX
+ *          0 - SGX not available
+ * @return If the function succeeds, return SGX_SUCCESS, any other value indicates an error.
+ */
+sgx_status_t sgx_is_capable(int* sgx_capable);
+
+/*
+ * Function used to enable SGX device through EFI.
+ *
+ * @param sgx_device_status[out] The status of SGX device.
+ * @return If the function succeeds, return SGX_SUCCESS, any other value indicates an error.
+ */
+sgx_status_t sgx_cap_enable_device(sgx_device_status_t* sgx_device_status);
+
+/*
+* Function used to query SGX device status.
+*
+* @param sgx_device_status[out] The status of SGX device. 
+* @return If the function succeeds, return SGX_SUCCESS, any other value indicates an error.
+*/
+sgx_status_t SGXAPI sgx_cap_get_status(sgx_device_status_t* sgx_device_status);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
+

+ 3 - 0
common/inc/sgx_error.h

@@ -87,6 +87,9 @@ typedef enum _status_t
     SGX_ERROR_MC_OVER_QUOTA             = SGX_MK_ERROR(0x400f),   /* Monotonic counters exceeds quota limitation */
     SGX_ERROR_KDF_MISMATCH              = SGX_MK_ERROR(0x4011),   /* Key derivation function doesn't match during key exchange */
     SGX_ERROR_UNRECOGNIZED_PLATFORM     = SGX_MK_ERROR(0x4012),   /* EPID Provisioning failed due to platform not recognized by backend server*/
+
+    SGX_ERROR_NO_PRIVILEGE              = SGX_MK_ERROR(0x5002),   /* Not enough privilege to perform the operation */
+
     
     /* SGX errors are only used in the file API when there is no appropriate EXXX (EINVAL, EIO etc.) error code */
     SGX_ERROR_FILE_BAD_STATUS               = SGX_MK_ERROR(0x7001),	/* The file is in bad status, run sgx_clearerr to try and fix it */

+ 1 - 0
linux/installer/common/sdk/BOMs/sdk_base.txt

@@ -1,6 +1,7 @@
 DeliveryName	InstallName	FileCheckSum	FileFeature	FileOwner
 <deliverydir>/build/linux/libsample_libcrypto.so	<installdir>/package/SampleCode/RemoteAttestation/sample_libcrypto/libsample_libcrypto.so	0	main	STP
 <deliverydir>/common/inc/sgx_attributes.h	<installdir>/package/include/./sgx_attributes.h	0	main	STP
+<deliverydir>/common/inc/sgx_capable.h	<installdir>/package/include/./sgx_capable.h	0	main	STP
 <deliverydir>/common/inc/sgx_cpuid.h	<installdir>/package/include/./sgx_cpuid.h	0	main	STP
 <deliverydir>/common/inc/sgx_defs.h	<installdir>/package/include/./sgx_defs.h	0	main	STP
 <deliverydir>/common/inc/sgx_dh.h	<installdir>/package/include/./sgx_dh.h	0	main	STP

+ 2 - 0
linux/installer/common/sdk/BOMs/sdk_x64.txt

@@ -19,6 +19,8 @@ DeliveryName	InstallName	FileCheckSum	FileFeature	FileOwner
 <deliverydir>/build/linux/libsgx_uae_service_deploy.so	<installdir>/package/lib64/libsgx_uae_service.so	0	main	STP
 <deliverydir>/build/linux/libsgx_uae_service_sim.so	<installdir>/package/lib64/libsgx_uae_service_sim.so	0	main	STP
 <deliverydir>/build/linux/libsgx_ukey_exchange.a	<installdir>/package/lib64/libsgx_ukey_exchange.a	0	main	STP
+<deliverydir>/build/linux/libsgx_capable.a	<installdir>/package/lib64/libsgx_capable.a	0	main	STP
+<deliverydir>/build/linux/libsgx_capable.so	<installdir>/package/lib64/libsgx_capable.so	0	main	STP
 <deliverydir>/build/linux/libsgx_uprotected_fs.a	<installdir>/package/lib64/libsgx_uprotected_fs.a	0	main	STP
 <deliverydir>/build/linux/libsgx_tprotected_fs.a	<installdir>/package/lib64/libsgx_tprotected_fs.a	0	main	STP
 <deliverydir>/build/linux/libsgx_urts_deploy.so	<installdir>/package/lib64/libsgx_urts.so	0	main	STP

+ 11 - 1
sdk/Makefile.opt_lib

@@ -47,6 +47,8 @@
 #        - uprotected_fs: libsgx_uprotected_fs.a
 #        - sample_crypto: libsample_crypto.so (for sample code use)
 #        - ptrace:        libsgx_ptrace.so, gdb-sgx-plugin
+#  - Standalone, untrusted libraries
+#        - libcapable:    libsgx_capable.a libsgx_capable.so
 #  - Tools
 #        - signtool:      sgx_sign
 #        - edger8r:       sgx_edger8r
@@ -77,7 +79,7 @@ all: $(CHECK_OPT)
 	$(MAKE) components
 
 .PHONY: components
-components: tstdc tstdcxx tcxx tservice trts tcrypto tkey_exchange ukey_exchange tprotected_fs uprotected_fs ptrace sample_crypto simulation signtool edger8r tsetjmp tcmalloc
+components: tstdc tstdcxx tcxx tservice trts tcrypto tkey_exchange ukey_exchange tprotected_fs uprotected_fs ptrace sample_crypto libcapable simulation signtool edger8r tsetjmp tcmalloc
 
 # ---------------------------------------------------
 #  tstdc
@@ -237,6 +239,13 @@ ptrace:
 sample_crypto:
 	$(MAKE) -C sample_libcrypto
 
+# ---------------------------------------------------
+#  standalone, untrusted libraries
+# ---------------------------------------------------
+.PHONY: libcapable
+libcapable:
+	$(MAKE) -C libcapable/linux/
+
 # ---------------------------------------------------
 #  simualtion libraries and tools
 # ---------------------------------------------------
@@ -279,6 +288,7 @@ clean:
 	$(MAKE) -C protected_fs/sgx_uprotected_fs/     clean
 	$(MAKE) -C debugger_interface/linux/           clean
 	$(MAKE) -C sample_libcrypto/                   clean
+	$(MAKE) -C libcapable/linux/                   clean
 	$(MAKE) -C simulation/                         clean
 	$(MAKE) -C sign_tool/SignTool                  clean
 	$(MAKE) -C edger8r/linux                       clean

+ 12 - 1
sdk/Makefile.source

@@ -47,6 +47,8 @@
 #        - uprotected_fs: libsgx_uprotected_fs.a
 #        - ptrace:        libsgx_ptrace.so, gdb-sgx-plugin
 #        - sample_crypto: libsample_crypto.so (for sample code use)
+#  - Standalone, untrusted libraries
+#        - libcapable:    libsgx_capable.a libsgx_capable.so
 #  - Tools
 #        - signtool:      sgx_sign
 #        - edger8r:       sgx_edger8r
@@ -61,7 +63,7 @@ LIBTCXX    := $(BUILD_DIR)/libsgx_tcxx.a
 LIBTSE     := $(BUILD_DIR)/libsgx_tservice.a
 
 .PHONY: all
-all: tstdc tstdcxx tcxx tservice trts tcrypto tkey_exchange ukey_exchange tprotected_fs uprotected_fs ptrace sample_crypto simulation signtool edger8r tsetjmp tcmalloc
+all: tstdc tstdcxx tcxx tservice trts tcrypto tkey_exchange ukey_exchange tprotected_fs uprotected_fs ptrace sample_crypto libcapable simulation signtool edger8r tsetjmp tcmalloc
 
 # ---------------------------------------------------
 #  tstdc
@@ -218,6 +220,14 @@ ptrace:
 sample_crypto:
 	$(MAKE) -C sample_libcrypto
 
+# ---------------------------------------------------
+#  standalone, untrusted libraries
+# ---------------------------------------------------
+
+.PHONY: libcapable
+libcapable:
+	$(MAKE) -C libcapable/linux/
+
 # ---------------------------------------------------
 #  simualtion libraries and tools
 # ---------------------------------------------------
@@ -261,6 +271,7 @@ clean:
 	$(MAKE) -C protected_fs/sgx_uprotected_fs/     clean
 	$(MAKE) -C debugger_interface/linux/           clean
 	$(MAKE) -C sample_libcrypto/                   clean
+	$(MAKE) -C libcapable/linux/                   clean
 	$(MAKE) -C simulation/                         clean
 	$(MAKE) -C sign_tool/SignTool                  clean
 	$(MAKE) -C edger8r/linux                       clean

+ 71 - 0
sdk/libcapable/linux/Makefile

@@ -0,0 +1,71 @@
+#
+# Copyright (C) 2011-2017 Intel Corporation. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#   * Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+#   * Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in
+#     the documentation and/or other materials provided with the
+#     distribution.
+#   * Neither the name of Intel Corporation nor the names of its
+#     contributors may be used to endorse or promote products derived
+#     from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#
+
+include ../../../buildenv.mk
+
+CXXFLAGS += -fPIC -Werror -g
+CXXFLAGS += $(ADDED_INC)
+
+CFLAGS += -fPIC -Werror -g
+CFLAGS += $(ADDED_INC)
+
+INC += -I$(COMMON_DIR)/inc                \
+       -I$(COMMON_DIR)/inc/internal       \
+       -I$(COMMON_DIR)/inc/internal/linux 
+
+LIB += -L$(BUILD_DIR)
+
+LIBCAPABLE := libsgx_capable.so
+LIBCAPABLE_STATIC := libsgx_capable.a
+
+OBJ := sgx_capable.o
+
+.PHONY: all
+all: $(LIBCAPABLE) $(LIBCAPABLE_STATIC) | $(BUILD_DIR)
+	@$(CP) $(LIBCAPABLE)          $|
+	@$(CP) $(LIBCAPABLE_STATIC)   $|
+
+$(LIBCAPABLE): $(OBJ) 
+	$(CXX) $(CXXFLAGS) -shared -Wl,-soname=$@ $(LIB) -o $@  $(OBJ) $(LDFLAGS)
+
+$(LIBCAPABLE_STATIC): $(OBJ) 
+	$(AR) r $@ $?
+
+%.o: %.cpp
+	$(CXX) -c $(CXXFLAGS) $(INC) $< -o $@
+
+$(BUILD_DIR):
+	@$(MKDIR) $@
+
+.PHONY: clean
+clean::
+	@$(RM) *.o $(LIBCAPABLE) $(BUILD_DIR)/$(LIBCAPABLE)
+	@$(RM) $(LIBCAPABLE_STATIC) $(BUILD_DIR)/$(LIBCAPABLE_STATIC)

+ 362 - 0
sdk/libcapable/linux/sgx_capable.cpp

@@ -0,0 +1,362 @@
+/*
+* Copyright 2011-2017 Intel Corporation
+* 
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 
+* 1. Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+* 
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* 
+* 3. Neither the name of the copyright holder nor the names of its
+* contributors may be used to endorse or promote products derived from
+* this software without specific prior written permission.
+* 
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sgx_uae_service.h>
+#include <sgx_capable.h>
+
+/* __cpuid(unsinged int info[4], unsigned int leaf, unsigned int subleaf); */
+/* Because gcc's __get_cpuid() intrinsic is difficult to work with */
+#define __cpuid(x,y,z) asm volatile("cpuid":"=a"(x[0]),"=b"(x[1]),"=c"(x[2]),"=d"(x[3]):"a"(y),"c"(z))
+
+#define EFIFS_PATH		"/sys/firmware/efi/"
+#define EFIVARS_PATH 	EFIFS_PATH"efivars/"
+#define EFIVAR_EPCBIOS	EFIVARS_PATH"EPCBIOS-c60aa7f6-e8d6-4956-8ba1-fe26298f5e87"
+#define EFIVAR_EPCSW	EFIVARS_PATH"EPCSW-d69a279b-58eb-45d1-a148-771bb9eb5251"
+
+static int _is_sgx_available();
+static int _is_cpu_supported();
+
+sgx_status_t sgx_is_capable (int *sgx_capable)
+{
+	struct stat sb;
+
+	if ( sgx_capable == NULL ) return SGX_ERROR_INVALID_PARAMETER;
+
+	if ( ! _is_cpu_supported() ) {
+		*sgx_capable= 0;
+		return SGX_SUCCESS;
+	}
+
+	if ( _is_sgx_available() ) {
+		*sgx_capable= 1;
+		return SGX_SUCCESS;
+	}
+
+	/* Check to see if the Software Control Interface is available */
+
+	if ( stat(EFIVAR_EPCBIOS, &sb) == -1 ) {
+		if ( errno == EACCES ) return SGX_ERROR_NO_PRIVILEGE;
+		*sgx_capable = 0;
+		return SGX_SUCCESS;
+	}
+
+	*sgx_capable= 1;
+	return SGX_SUCCESS;
+}
+
+sgx_status_t sgx_cap_get_status (sgx_device_status_t *sgx_device_status)
+{
+	struct stat sb;
+	int has_efifs= 0;
+
+	if ( sgx_device_status == NULL ) return SGX_ERROR_INVALID_PARAMETER;
+
+	if ( ! _is_cpu_supported() ) {
+		*sgx_device_status= SGX_DISABLED_UNSUPPORTED_CPU;
+		return SGX_SUCCESS;
+	}
+
+	if ( _is_sgx_available() ) {
+		*sgx_device_status= SGX_ENABLED;
+		return SGX_SUCCESS;
+	}
+
+	/*
+	 * Intel SGX is supported, but not enabled. Figure out what
+	 * it will take to enable it.
+	 */
+
+	/* Were we booted in UEFI mode? */
+
+	if ( stat(EFIFS_PATH, &sb) == 0 ) {
+		has_efifs= 1;
+
+		if ( stat(EFIVARS_PATH, &sb) == -1 )
+		{
+			/* We have /sys/firmware/efi but not efivars */
+
+			switch (errno) {
+			case EACCES:
+				return SGX_ERROR_NO_PRIVILEGE;
+			case ENOENT:
+			case ENOTDIR:
+				break;
+			default:
+				return SGX_ERROR_UNEXPECTED;
+			}
+		}
+	} else {
+		switch (errno) {
+		case EACCES:
+			return SGX_ERROR_NO_PRIVILEGE;
+		case ENOENT:
+		case ENOTDIR:
+			break;
+		default:
+			return SGX_ERROR_UNEXPECTED;
+		}
+	} 
+
+	if ( ! has_efifs ) {
+		/*
+		 * We don't have /sys/firmware/efi mounted. It could have been
+		 * unmounted by the user, or we might not have UEFI support in
+		 * the OS. If /boot/efi exists, then we are probably capable of
+		 * UEFI and should report SGX_DISABLED. Otherwise report
+		 * SGX_DISABLED_LEGACY_OS.
+		 */
+
+		if ( stat("/boot/efi", &sb) == 0 ) *sgx_device_status= SGX_DISABLED;
+		else {
+			switch(errno) {
+			case ENOENT:
+			case ENOTDIR:
+				*sgx_device_status= SGX_DISABLED_LEGACY_OS;
+				break;
+			default:
+				/* 
+				 * We don't have enough information to figure this out
+				 * so report SGX_DISABLED.
+				 */
+				*sgx_device_status= SGX_DISABLED;
+			}
+
+		} 
+
+		return SGX_SUCCESS;
+	}
+
+	/*
+	 * We have access to efivars. Now examine the EFI variable for the
+	 * Software Control Interface.
+	 */
+
+	if ( stat(EFIVAR_EPCBIOS, &sb) == -1 ) {
+		if ( errno == EACCES ) return SGX_ERROR_NO_PRIVILEGE;
+
+		/* No SCI is present so we can't do a s/w enabled */
+
+		*sgx_device_status= SGX_DISABLED_MANUAL_ENABLE;
+		return SGX_SUCCESS;
+	}
+
+	/*
+	 * Check to see if the software enable has already been
+	 * performed. If so, then we will be enabled on the next
+	 * reboot.
+	 */
+
+	if ( stat(EFIVAR_EPCSW, &sb) == -1 ) {
+		if ( errno == EACCES ) return SGX_ERROR_NO_PRIVILEGE;
+
+		/* The software enable hasn't been attempted yet. */
+
+		*sgx_device_status= SGX_DISABLED_SCI_AVAILABLE;
+		return SGX_SUCCESS;
+	}
+
+	/* Software enable has occurred. Need a reboot. */
+
+	*sgx_device_status= SGX_DISABLED_REBOOT_REQUIRED;
+
+	return SGX_SUCCESS;
+}
+
+/* Determine if the CPU supports Intel SGX */
+
+static int _is_cpu_supported()
+{
+	unsigned int info[4];
+	unsigned int *ebx, *ecx, *edx;
+
+	ebx= &info[1];
+	ecx= &info[2];
+	edx= &info[3];
+
+	/* Is this an Intel CPU? */
+
+	__cpuid (info, 0x00, 0);
+	if ( *ebx != 0x756e6547 || *ecx != 0x6c65746e || *edx != 0x49656e69 )
+		return 0;
+
+	/* Does the CPU support Intel SGX? */
+
+	__cpuid (info, 0x07, 0);
+
+	return ( *ebx & (0x1<<2) );
+}
+
+/* Are SGX instructions available for use? */
+
+static int _is_sgx_available ()
+{
+	unsigned int info[4];
+	unsigned int *eax, *ebx, *ecx, *edx;
+	unsigned int subleaf= 2;
+	unsigned int flag;
+
+	eax= &info[0];
+	ebx= &info[1];
+	ecx= &info[2];
+	edx= &info[3];
+
+	/* Are Intel SGX instructions available for use? */
+
+	__cpuid(info, 0x12, 0);
+
+	flag= *eax&0x3;
+	if ( flag == 0 ) return 0;
+
+	/* Do we have non-zero, max enclave sizes? */
+
+	if ( (*edx & 0xFFFF) == 0 ) return 0;
+
+	/*
+	 * Enumerate the subleafs for the EPC. At least one must be a valid
+	 * subleaf that describes a page. 
+	 */
+
+	while (1) {
+		__cpuid(info, 0x12, subleaf);
+
+		/* 
+		 * Is this an invalid subleaf? If we've hit an invalid subleaf
+		 * before finding a valid subleaf with a non-zero page size,
+		 * then we have no EPC memory allocated, and thus no Intel SGX
+		 * capability.
+		 */
+
+		if ( ! (*eax & 0x1) ) return 0;
+
+		/*
+		 * Is there a non-zero size for this EPC subleaf? If so, we
+		 * have memory allocated to the EPC for Intel SGX, and are
+		 * enabled.
+		 */
+
+		if (
+			(*eax&0xFFFFF000 || *ebx&0xFFFFF) &&
+			(*ecx&0xFFFFF000 || *edx&0xFFFFF)
+		) return 1;
+
+		++subleaf;
+	}
+
+	/* We'll never get here, but we need to keep the compiler happy */
+
+	return 0;
+}
+
+sgx_status_t sgx_cap_enable_device (sgx_device_status_t *sgx_device_status)
+{
+	sgx_status_t status;
+	struct epcbios_stuct {
+		uint32_t attrs;
+		uint32_t sprmbins;
+		uint32_t maxepcsz;
+		/* There's more, but this is all we need */
+	} epcbios;
+	struct epcsw_struct {
+		uint32_t attrs;
+		uint32_t maxepcsz;
+	} epcsw;
+	FILE *fefivar;
+
+	if ( sgx_device_status == NULL ) return SGX_ERROR_INVALID_PARAMETER;
+
+	status= sgx_cap_get_status(sgx_device_status);
+	if ( status != SGX_SUCCESS ) return status;
+
+	/*
+	 * If we get back anything other than SGX_DISABLED_SCI_AVAILABLE
+	 * then return, because there is nothing to do.
+	 */
+
+	if ( *sgx_device_status != SGX_DISABLED_SCI_AVAILABLE )
+		return SGX_SUCCESS;
+
+	/* Attempt the software enable */
+
+	/* First, read the EPCBIOS EFI variable to get the max EPC size */
+
+	fefivar= fopen(EFIVAR_EPCBIOS, "r");
+	if ( fefivar == NULL ) {
+		if ( errno == EACCES ) return SGX_ERROR_NO_PRIVILEGE;
+
+		return SGX_ERROR_UNEXPECTED;
+	}
+
+	/*
+	 * The first 4 bytes are the EFI variable attributes. Data starts
+	 * at offset 0x4, and the value we want is a UINT32 at offset 0x8.
+	 */
+
+	if ( fread(&epcbios, sizeof(epcbios), 1, fefivar) != 1 ) {
+		fclose(fefivar);
+		return SGX_ERROR_UNEXPECTED;
+	}
+
+	fclose(fefivar);
+
+	/*
+	 * Now create the EPCSW EFI variable. The variable data is a 
+	 * single UINT32 specifying the requested EPC size.
+	 */
+
+	epcsw.attrs= epcbios.attrs;
+	epcsw.maxepcsz= epcbios.maxepcsz;
+
+	fefivar= fopen(EFIVAR_EPCSW, "w");
+	if ( fefivar == NULL ) {
+		if ( errno == EACCES ) return SGX_ERROR_NO_PRIVILEGE;
+
+		return SGX_ERROR_UNEXPECTED;
+	}
+
+	/* Write out the EPCSW structure */
+
+	if ( fwrite(&epcsw, sizeof(epcsw), 1, fefivar) != 1 ) {
+		unlink(EFIVAR_EPCSW);
+		fclose(fefivar);
+		return SGX_ERROR_UNEXPECTED;
+	}
+
+	fclose(fefivar);
+
+	*sgx_device_status= SGX_DISABLED_REBOOT_REQUIRED;
+
+	return SGX_SUCCESS;
+}