Skip to content

Commit

Permalink
[Python,CI,Docs] Support SGX extended product ID
Browse files Browse the repository at this point in the history
KSS is a new feature that introduces additional fields to identify
enclave in build time: ISVEXTPRODID and ISVFAMILYID. These fields are
defined the the developer and signed in SIGSTRUCT. Add new fields to
the manifest to add support, and support in SGX signing tool.

Add a hello world example with KSS enabled: Product ID fields are
configured in the manifest and the enclave prints them. This example
must be built with remote attestation.

At this point SGX loader is not updated and there are no sanity checks
prior to enclave load. Therefore, if an enclave with KSS is loaded on an
unsupported platform, it might crash.

Signed-off-by: Lavi, Nir <nir.lavi@intel.com>
  • Loading branch information
DL8 committed Jan 10, 2023
1 parent 1b1242f commit c98e498
Show file tree
Hide file tree
Showing 13 changed files with 227 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CI-Examples/kss-helloworld/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/kss-helloworld
/*.o
/OUTPUT
64 changes: 64 additions & 0 deletions CI-Examples/kss-helloworld/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
GRAMINEDIR ?= ../..
RA_TYPE ?= dcap

CFLAGS = -Wall -Wextra -I$(GRAMINEDIR)/pal/src/host/linux-sgx

ifeq ($(DEBUG),1)
GRAMINE_LOG_LEVEL = debug
CFLAGS += -g
else
GRAMINE_LOG_LEVEL = error
CFLAGS += -O3
endif

.PHONY: all
all: kss-helloworld.manifest.sgx kss-helloworld.sig kss-helloworld.token

kss-helloworld: kss-helloworld.o

kss-helloworld.o: kss-helloworld.c

kss-helloworld.manifest: kss-helloworld.manifest.template
gramine-manifest \
-Dlog_level=$(GRAMINE_LOG_LEVEL) \
-Dra_type=$(RA_TYPE) \
$< $@

# gramine-sgx-sign generates both a .sig file and a .manifest.sgx file. This is somewhat
# hard to express properly in Make. The simple solution would be to use
# "Rules with Grouped Targets" (`&:`), however make on Ubuntu <= 20.04 doesn't support it.
#
# Simply using a normal rule with "two targets" is equivalent to creating separate rules
# for each of the targets, and when using `make -j`, this might cause two instances
# of gramine-sgx-sign to get launched simultaneously, potentially breaking the build.
#
# As a workaround, we use a dummy intermediate target, and mark both files as depending on it, to
# get the dependency graph we want. We mark this dummy target as .INTERMEDIATE, which means
# that make will consider the source tree up-to-date even if the sgx_sign file doesn't exist,
# as long as the other dependencies check out. This is in contrast to .PHONY, which would
# be rebuilt on every invocation of make.
kss-helloworld.sig kss-helloworld.manifest.sgx: sgx_sign
@:

.INTERMEDIATE: sgx_sign
sgx_sign: kss-helloworld.manifest kss-helloworld
gramine-sgx-sign \
--manifest $< \
--output $<.sgx

kss-helloworld.token: kss-helloworld.sig
gramine-sgx-get-token \
--output $@ --sig $<

GRAMINE = gramine-sgx

.PHONY: check
check: all
$(GRAMINE) kss-helloworld

.PHONY: clean
clean:
$(RM) *.token *.sig *.manifest.sgx *.manifest kss-helloworld.o kss-helloworld OUTPUT

.PHONY: distclean
distclean: clean
24 changes: 24 additions & 0 deletions CI-Examples/kss-helloworld/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# KSS Hello World

This directory contains a Makefile and a manifest template for running a simple
"Hello World" program with KSS in Gramine. It is built with KSS support and non-zero
values for `isvextprodid` and `isvfamilyid`, which are printed by the enclave.
report.

This example is SGX-specific.

# Build

Run `make` (non-debug) or `make DEBUG=1` (debug) in the directory.

Remote attestation must be supported to run this test. Default attestation type is `dcap`.
It can be modified with the `RA_TYPE` flag in make. For example: `make RA_TYPE=epid`.

# Run

```sh
gramine-sgx ./kss-helloworld
```

Note that a platform with KSS support must be used, otherwise this example will not work.
Use `is-sgx-available` tool to determine if the platform supports KSS.
63 changes: 63 additions & 0 deletions CI-Examples/kss-helloworld/kss-helloworld.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "sgx_arch.h"

#define MAX_DIGITS (256ULL) // Should be more than enough to contain all buffers

static void blob2hex(const void* input, size_t len, char* output) {
static const char digits[] = "0123456789abcdef";
for(size_t i=0;i<len;i++) {
uint8_t byte = *((uint8_t *) input + i);
output[2*i] = digits[byte >> 4];
output[2*i+1] = digits[byte & 0xf];
}
output[2*len + 1] = 0;
}

int main(void) {
char print_buffer[MAX_DIGITS];
FILE* attestation_type_fd = NULL;
FILE* report_fd = NULL;
sgx_report_t report;

attestation_type_fd = fopen("/dev/attestation/attestation_type", "rb");
if(attestation_type_fd == NULL) {
fprintf(stderr, "Failed to open attestation type handle\n");
return 1;
}
if(fread(print_buffer, 1, sizeof(print_buffer), attestation_type_fd) < 0) {
fprintf(stderr, "Failed to read attestation type\n");
return 2;
}
// Report handles are loaded only if remote attestation is enabled
if(strcmp(print_buffer, "none") == 0) {
fprintf(stderr, "Must be built with remote attestation\n");
return 3;
}
fclose(attestation_type_fd);

// We only care about this enclave's attributes, so we omit report data and target info
report_fd = fopen("/dev/attestation/report", "rb");
if(report_fd == NULL) {
fprintf(stderr, "Failed to open report handle\n");
return 4;
}
if(fread(&report, sizeof(report), 1, report_fd) <= 0) {
fprintf(stderr, "Failed to read report\n");
return 5;
}
fclose(report_fd);

printf("isvprodid = %04x\n", report.body.isv_prod_id);
printf("isvsvn = %d\n", report.body.isv_svn);
blob2hex(report.body.isv_ext_prod_id, sizeof(report.body.isv_ext_prod_id), print_buffer);
printf("isvextprodid = %s\n", print_buffer);
blob2hex(report.body.isv_family_id, sizeof(report.body.isv_family_id), print_buffer);
printf("isvfamilyid = %s\n", print_buffer);
blob2hex(report.body.config_id.data, sizeof(report.body.config_id.data), print_buffer);
printf("configid = %s\n", print_buffer);
printf("configsvn = %d\n", report.body.config_svn);
return 0;
}
29 changes: 29 additions & 0 deletions CI-Examples/kss-helloworld/kss-helloworld.manifest.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Hello World manifest file example

loader.entrypoint = "file:{{ gramine.libos }}"
libos.entrypoint = "/kss-helloworld"
loader.log_level = "{{ log_level }}"

loader.env.LD_LIBRARY_PATH = "/lib"

fs.mounts = [
{ path = "/lib", uri = "file:{{ gramine.runtimedir() }}" },
{ path = "/kss-helloworld", uri = "file:kss-helloworld" },
]

sgx.debug = true
sgx.nonpie_binary = true

sgx.remote_attestation = "{{ ra_type }}"

sgx.kss = true
sgx.isvprodid = 5
sgx.isvsvn = 2
sgx.isvfamilyid = "0x00112233445566778899aabbccddeeff"
sgx.isvextprodid = "0xcafef00dcafef00df00dcafef00dcafe"

sgx.trusted_files = [
"file:{{ gramine.libos }}",
"file:kss-helloworld",
"file:{{ gramine.runtimedir() }}/",
]
18 changes: 18 additions & 0 deletions CI-Examples/kss-helloworld/run_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/usr/bin/env bash

set -e

if test -n "$SGX"
then
GRAMINE=gramine-sgx
else
GRAMINE=gramine-direct
fi

echo -e "\n\nRunning kss-helloworld"
$GRAMINE ./kss-helloworld > OUTPUT
grep -q 'isvprodid = 0005' OUTPUT && echo '[ Success 1/4 ]'
grep -q 'isvsvn = 2' OUTPUT && echo '[ Success 2/4 ]'
grep -q 'isvextprodid = 00112233445566778899aabbccddeeff' OUTPUT && echo '[ Success 3/4 ]'
grep -q 'isvfamilyid = cafef00dcafef00df00dcafef00dcafe' OUTPUT && echo '[ Success 4/4 ]'
rm OUTPUT
13 changes: 13 additions & 0 deletions Documentation/manifest-syntax.rst
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,19 @@ ISV Product ID and SVN
This syntax specifies the ISV Product ID and SVN to be added to the enclave
signature.

Extended ISV Product ID (KSS)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

::

sgx.kss = [true|false] (default: false)
sgx.isvextprodid = "[16-byte hex value]" (default: "0x00000000000000000000000000000000")
sgx.isvfamily = "[16-byte hex value]" (default: "0x00000000000000000000000000000000")

If ``sgx.kss = true``, this syntax specifies the extended ISV product ID and family ID to be added to the
enclave signature. The platform must support KSS to launch the enclave.
Otherwise, these two fields are ignored and remain zero.

Attribute masks for SGX sealing key derivation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
2 changes: 2 additions & 0 deletions pal/src/host/linux-sgx/enclave_framework.c
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,8 @@ static void print_report(sgx_report_t* r) {
log_debug(" attr.xfrm: %016lx", r->body.attributes.xfrm);
log_debug(" isv_prod_id: %02x", r->body.isv_prod_id);
log_debug(" isv_svn: %02x", r->body.isv_svn);
log_debug(" isv_ext_prod_id: %s", BYTES2HEX(r->body.isv_ext_prod_id));
log_debug(" isv_family_id: %s", BYTES2HEX(r->body.isv_family_id));
log_debug(" report_data: %s", BYTES2HEX(r->body.report_data.d));
log_debug(" key_id: %s", BYTES2HEX(r->key_id.id));
log_debug(" mac: %s", BYTES2HEX(r->mac));
Expand Down
1 change: 1 addition & 0 deletions pal/src/host/linux-sgx/generated_offsets.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const struct generated_offset generated_offsets[] = {
/* defines from sgx_arch.h */
DEFINE(SGX_FLAGS_DEBUG, SGX_FLAGS_DEBUG),
DEFINE(SGX_FLAGS_MODE64BIT, SGX_FLAGS_MODE64BIT),
DEFINE(SGX_FLAGS_KSS, SGX_FLAGS_KSS),
DEFINE(SGX_XFRM_LEGACY, SGX_XFRM_LEGACY),
DEFINE(SGX_XFRM_AVX, SGX_XFRM_AVX),
DEFINE(SGX_XFRM_MPX, SGX_XFRM_MPX),
Expand Down
1 change: 1 addition & 0 deletions pal/src/host/linux-sgx/sgx_arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ typedef uint8_t sgx_isvfamily_id_t[SGX_ISV_FAMILY_ID_SIZE];
#define SGX_FLAGS_MODE64BIT 0x04ULL
#define SGX_FLAGS_PROVISION_KEY 0x10ULL
#define SGX_FLAGS_LICENSE_KEY 0x20ULL
#define SGX_FLAGS_KSS 0x80ULL

/* EINIT must verify *all* SECS.ATTRIBUTES[63..0] bits (FLAGS bits) against
* SIGSTRUCT.ATTRIBUTES[63..0].
Expand Down
3 changes: 3 additions & 0 deletions python/graminelibos/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ def __init__(self, manifest_str):

sgx.setdefault('isvprodid', 0)
sgx.setdefault('isvsvn', 0)
sgx.setdefault('kss', False)
sgx.setdefault('isvextprodid', b'\x00'*16)
sgx.setdefault('isvfamilyid', b'\x00'*16)
sgx.setdefault('remote_attestation', "none")
sgx.setdefault('debug', False)
sgx.setdefault('require_avx', False)
Expand Down
4 changes: 4 additions & 0 deletions python/graminelibos/sgx_sign.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def collect_bits(manifest_sgx, options_dict):
def get_enclave_attributes(manifest_sgx):
flags_dict = {
'debug': offs.SGX_FLAGS_DEBUG,
'kss': offs.SGX_FLAGS_KSS,
}

xfrms_dict = {
Expand Down Expand Up @@ -539,6 +540,9 @@ def get_tbssigstruct(manifest_path, date, libpal=SGX_LIBPAL, verbose=False):
sig['attribute_flags'] = attribute_flags
sig['attribute_xfrms'] = attribute_xfrms
sig['misc_select'] = misc_select
if attribute_flags & offs.SGX_FLAGS_KSS:
sig['isv_ext_prod_id'] = int(manifest_sgx['isvextprodid'], 16).to_bytes(16, 'big')
sig['isv_family_id'] = int(manifest_sgx['isvfamilyid'], 16).to_bytes(16, 'big')

return sig

Expand Down
2 changes: 2 additions & 0 deletions python/graminelibos/sigstruct.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class Sigstruct:
'misc_mask': offs.SGX_MISCSELECT_MASK_CONST,
'attribute_flags_mask': offs.SGX_FLAGS_MASK_CONST,
'attribute_xfrm_mask': offs.SGX_XFRM_MASK_CONST,
'isv_ext_prod_id': b'\x00' * 16,
'isv_family_id': b'\x00' * 16,
}


Expand Down

0 comments on commit c98e498

Please sign in to comment.