123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858 |
- #!/usr/bin/env python3
- import argparse
- import datetime
- import hashlib
- import os
- import shutil
- import struct
- import subprocess
- import sys
- sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
- from generated_offsets import *
- # Default / Architectural Options
- ARCHITECTURE = "amd64"
- SSAFRAMESIZE = PAGESIZE
- DEFAULT_ENCLAVE_SIZE = '256M'
- DEFAULT_THREAD_NUM = 4
- enclave_heap_min = DEFAULT_HEAP_MIN
- # Utilities
- ZERO_PAGE = bytes(PAGESIZE)
- def roundup(addr):
- remaining = addr % PAGESIZE
- if remaining:
- return addr + (PAGESIZE - remaining)
- return addr
- def rounddown(addr):
- return addr - addr % PAGESIZE
- def parse_size(s):
- scale = 1
- if s.endswith("K"):
- scale = 1024
- if s.endswith("M"):
- scale = 1024 * 1024
- if s.endswith("G"):
- scale = 1024 * 1024 * 1024
- if scale != 1:
- s = s[:-1]
- return int(s, 0) * scale
- # Reading / Writing Manifests
- def read_manifest(filename):
- manifest = dict()
- manifest_layout = []
- with open(filename, "r") as f:
- for line in f.readlines():
- if line == "":
- manifest_layout.append((None, None))
- break
- pound = line.find("#")
- if pound != -1:
- comment = line[pound:].strip()
- line = line[:pound]
- else:
- comment = None
- line = line.strip()
- equal = line.find("=")
- if equal != -1:
- key = line[:equal].strip()
- manifest[key] = line[equal + 1:].strip()
- else:
- key = None
- manifest_layout.append((key, comment))
- return (manifest, manifest_layout)
- def output_manifest(filename, manifest, manifest_layout):
- with open(filename, 'w') as f:
- written = []
- for (key, comment) in manifest_layout:
- line = ''
- if key is not None:
- line += key + ' = ' + manifest[key]
- written.append(key)
- if comment is not None:
- if line != '':
- line += ' '
- line += comment
- f.write(line)
- f.write('\n')
- f.write('\n')
- f.write("# Generated by Graphene\n")
- f.write('\n')
- for key in sorted(manifest):
- if key not in written:
- f.write("%s = %s\n" % (key, manifest[key]))
- # Loading Enclave Attributes
- def get_enclave_attributes(manifest):
- sgx_flags = {
- 'FLAG_DEBUG': struct.pack("<Q", SGX_FLAGS_DEBUG),
- 'FLAG_MODE64BIT': struct.pack("<Q", SGX_FLAGS_MODE64BIT),
- }
- sgx_xfrms = {
- 'XFRM_LEGACY': struct.pack("<Q", SGX_XFRM_LEGACY),
- 'XFRM_AVX': struct.pack("<Q", SGX_XFRM_AVX),
- 'XFRM_AVX512': struct.pack("<Q", SGX_XFRM_AVX512),
- 'XFRM_MPX': struct.pack("<Q", SGX_XFRM_MPX),
- }
- sgx_miscs = {
- 'MISC_EXINFO': struct.pack("<L", SGX_MISCSELECT_EXINFO),
- }
- default_attributes = {
- 'FLAG_DEBUG',
- 'XFRM_LEGACY',
- }
- if ARCHITECTURE == 'amd64':
- default_attributes.add('FLAG_MODE64BIT')
- manifest_options = {
- 'debug' : 'FLAG_DEBUG',
- 'require_avx' : 'XFRM_AVX',
- 'require_avx512' : 'XFRM_AVX512',
- 'enable_mpx' : 'XFRM_MPX',
- 'support_exinfo' : 'MISC_EXINFO',
- }
- attributes = default_attributes
- for opt in manifest_options:
- key = 'sgx.' + opt
- if key in manifest:
- if manifest[key] == '1':
- attributes.add(manifest_options[opt])
- else:
- attributes.discard(manifest_options[opt])
- flags_raw = struct.pack("<Q", 0)
- xfrms_raw = struct.pack("<Q", 0)
- miscs_raw = struct.pack("<L", 0)
- for attr in attributes:
- if attr in sgx_flags:
- flags_raw = bytes([a | b for a, b in
- zip(flags_raw, sgx_flags[attr])])
- if attr in sgx_xfrms:
- xfrms_raw = bytes([a | b for a, b in
- zip(xfrms_raw, sgx_xfrms[attr])])
- if attr in sgx_miscs:
- miscs_raw = bytes([a | b for a, b in
- zip(miscs_raw, sgx_miscs[attr])])
- return flags_raw, xfrms_raw, miscs_raw
- # Generate Checksums / Measurement
- def resolve_uri(uri, check_exist=True):
- orig_uri = uri
- if uri.startswith('file:'):
- target = os.path.normpath(uri[5:])
- else:
- target = os.path.normpath(uri)
- if check_exist and not os.path.exists(target):
- raise Exception(
- 'Cannot resolve ' + orig_uri + ' or the file does not exist.')
- return target
- def get_checksum(file):
- digest = hashlib.sha256()
- with open(file, 'rb') as f:
- digest.update(f.read())
- return digest.digest()
- def get_trusted_files(manifest, args):
- targets = dict()
- if 'exec' in args:
- targets['exec'] = (args['exec'], resolve_uri(args['exec']))
- if 'loader.preload' in manifest:
- i = 0
- preloads = []
- for uri in str.split(manifest['loader.preload'], ','):
- targets['preload' + str(i)] = (uri, resolve_uri(uri))
- preloads.append(uri)
- i += 1
- for (key, val) in manifest.items():
- if not key.startswith('sgx.trusted_files.'):
- continue
- key = key[len('sgx.trusted_files.'):]
- if key in targets:
- raise Exception(
- 'repeated key in manifest: sgx.trusted_files.' + key)
- targets[key] = (val, resolve_uri(val))
- for (key, val) in targets.items():
- (uri, target) = val
- checksum = get_checksum(target).hex()
- targets[key] = (uri, target, checksum)
- return targets
- def get_trusted_children(manifest):
- targets = dict()
- for (key, val) in manifest.items():
- if not key.startswith('sgx.trusted_children.'):
- continue
- key = key[len('sgx.trusted_children.'):]
- if key in targets:
- raise Exception(
- 'repeated key in manifest: sgx.trusted_children.' + key)
- target = resolve_uri(val)
- if not target.endswith('.sig'):
- target += '.sig'
- sig = open(target, 'rb').read()[
- SGX_ARCH_SIGSTRUCT_ENCLAVE_HASH:
- SGX_ARCH_SIGSTRUCT_ENCLAVE_HASH + SGX_ARCH_HASH_SIZE].hex()
- targets[key] = (val, target, sig)
- return targets
- # Populate Enclave Memory
- PAGEINFO_R = 0x1
- PAGEINFO_W = 0x2
- PAGEINFO_X = 0x4
- PAGEINFO_TCS = 0x100
- PAGEINFO_REG = 0x200
- def get_loadcmds(filename):
- loadcmds = []
- p = subprocess.Popen(['readelf', '-l', '-W', filename],
- stdout=subprocess.PIPE, stderr=subprocess.PIPE)
- while True:
- line = p.stdout.readline()
- if not line:
- break
- line = line.decode()
- stripped = line.strip()
- if not stripped.startswith('LOAD'):
- continue
- tokens = stripped.split()
- if len(tokens) < 6:
- continue
- if len(tokens) >= 7 and tokens[7] == "E":
- tokens[6] += tokens[7]
- prot = 0
- for t in tokens[6]:
- if t == "R":
- prot = prot | 4
- if t == "W":
- prot = prot | 2
- if t == "E":
- prot = prot | 1
- loadcmds.append((int(tokens[1][2:], 16), # offset
- int(tokens[2][2:], 16), # addr
- int(tokens[4][2:], 16), # filesize
- int(tokens[5][2:], 16), # memsize
- prot))
- p.wait()
- if p.returncode != 0:
- return None
- return loadcmds
- class MemoryArea:
- def __init__(self, desc, file=None, content=None, addr=None, size=None,
- flags=None, measure=True):
- self.desc = desc
- self.file = file
- self.content = content
- self.addr = addr
- self.size = size
- self.flags = flags
- self.is_binary = False
- self.measure = measure
- if file:
- loadcmds = get_loadcmds(file)
- if loadcmds:
- mapaddr = 0xffffffffffffffff
- mapaddr_end = 0
- for (_, addr_, _, memsize, _) in loadcmds:
- if rounddown(addr_) < mapaddr:
- mapaddr = rounddown(addr_)
- if roundup(addr_ + memsize) > mapaddr_end:
- mapaddr_end = roundup(addr_ + memsize)
- self.is_binary = True
- self.size = mapaddr_end - mapaddr
- if mapaddr > 0:
- self.addr = mapaddr
- else:
- self.size = os.stat(file).st_size
- if self.addr is not None:
- self.addr = rounddown(self.addr)
- if self.size is not None:
- self.size = roundup(self.size)
- def get_memory_areas(attr, args):
- areas = []
- areas.append(
- MemoryArea('ssa',
- size=attr['thread_num'] * SSAFRAMESIZE * SSAFRAMENUM,
- flags=PAGEINFO_R | PAGEINFO_W | PAGEINFO_REG))
- areas.append(MemoryArea('tcs', size=attr['thread_num'] * TCS_SIZE,
- flags=PAGEINFO_TCS))
- areas.append(MemoryArea('tls', size=attr['thread_num'] * PAGESIZE,
- flags=PAGEINFO_R | PAGEINFO_W | PAGEINFO_REG))
- for _ in range(attr['thread_num']):
- areas.append(MemoryArea('stack', size=ENCLAVE_STACK_SIZE,
- flags=PAGEINFO_R | PAGEINFO_W | PAGEINFO_REG))
- areas.append(MemoryArea('pal', file=args['libpal'], flags=PAGEINFO_REG))
- if 'exec' in args:
- areas.append(MemoryArea('exec', file=args['exec'],
- flags=PAGEINFO_W | PAGEINFO_REG))
- return areas
- def find_areas(areas, desc):
- return [area for area in areas if area.desc == desc]
- def find_area(areas, desc, allow_none=False):
- matching = find_areas(areas, desc)
- if not matching and allow_none:
- return None
- if len(matching) != 1:
- raise KeyError(
- "Could not find exactly one MemoryArea '{}'".format(desc))
- return matching[0]
- def entry_point(elf_path):
- env = os.environ
- env['LC_ALL'] = 'C'
- out = subprocess.check_output(
- ['readelf', '-l', '--', elf_path], env=env)
- for line in out.splitlines():
- line = line.decode()
- if line.startswith("Entry point "):
- return int(line[12:], 0)
- raise ValueError("Could not find entry point of elf file")
- def baseaddr():
- if enclave_heap_min == 0:
- return ENCLAVE_HIGH_ADDRESS
- return 0
- def gen_area_content(attr, areas):
- manifest_area = find_area(areas, 'manifest')
- exec_area = find_area(areas, 'exec', True)
- pal_area = find_area(areas, 'pal')
- ssa_area = find_area(areas, 'ssa')
- tcs_area = find_area(areas, 'tcs')
- tls_area = find_area(areas, 'tls')
- stacks = find_areas(areas, 'stack')
- tcs_data = bytearray(tcs_area.size)
- def set_tcs_field(t, offset, pack_fmt, value):
- struct.pack_into(pack_fmt, tcs_data, t * TCS_SIZE + offset, value)
- tls_data = bytearray(tls_area.size)
- def set_tls_field(t, offset, value):
- struct.pack_into('<Q', tls_data, t * PAGESIZE + offset, value)
- enclave_heap_max = pal_area.addr - MEMORY_GAP
- # Sanity check that we measure everything except the heap which is zeroed
- # on enclave startup.
- for area in areas:
- if (area.addr + area.size <= enclave_heap_min or
- area.addr >= enclave_heap_max or area is exec_area):
- if not area.measure:
- raise ValueError("Memory area, which is not the heap, "
- "is not measured")
- elif area.desc != 'free':
- raise ValueError("Unexpected memory area is in heap range")
- for t in range(0, attr['thread_num']):
- ssa_offset = ssa_area.addr + SSAFRAMESIZE * SSAFRAMENUM * t
- ssa = baseaddr() + ssa_offset
- set_tcs_field(t, TCS_OSSA, '<Q', ssa_offset)
- set_tcs_field(t, TCS_NSSA, '<L', SSAFRAMENUM)
- set_tcs_field(t, TCS_OENTRY, '<Q',
- pal_area.addr + entry_point(pal_area.file))
- set_tcs_field(t, TCS_OGSBASGX, '<Q', tls_area.addr + PAGESIZE * t)
- set_tcs_field(t, TCS_FSLIMIT, '<L', 0xfff)
- set_tcs_field(t, TCS_GSLIMIT, '<L', 0xfff)
- set_tls_field(t, SGX_COMMON_SELF,
- tls_area.addr + PAGESIZE * t + baseaddr())
- set_tls_field(t, SGX_ENCLAVE_SIZE, attr['enclave_size'])
- set_tls_field(t, SGX_TCS_OFFSET, tcs_area.addr + TCS_SIZE * t)
- set_tls_field(t, SGX_INITIAL_STACK_OFFSET,
- stacks[t].addr + stacks[t].size)
- set_tls_field(t, SGX_SSA, ssa)
- set_tls_field(t, SGX_GPR, ssa + SSAFRAMESIZE - SGX_GPR_SIZE)
- set_tls_field(t, SGX_MANIFEST_SIZE,
- os.stat(manifest_area.file).st_size)
- set_tls_field(t, SGX_HEAP_MIN, baseaddr() + enclave_heap_min)
- set_tls_field(t, SGX_HEAP_MAX, baseaddr() + enclave_heap_max)
- if exec_area is not None:
- set_tls_field(t, SGX_EXEC_ADDR, baseaddr() + exec_area.addr)
- set_tls_field(t, SGX_EXEC_SIZE, exec_area.size)
- tcs_area.content = tcs_data
- tls_area.content = tls_data
- def populate_memory_areas(attr, areas):
- populating = attr['enclave_size']
- for area in areas:
- if area.addr is not None:
- continue
- area.addr = populating - area.size
- if area.addr < enclave_heap_min:
- raise Exception("Enclave size is not large enough")
- if area.desc == 'exec':
- populating = area.addr
- else:
- populating = area.addr - MEMORY_GAP
- free_areas = []
- for area in areas:
- if area.addr + area.size < populating:
- addr = area.addr + area.size
- flags = PAGEINFO_R | PAGEINFO_W | PAGEINFO_X | PAGEINFO_REG
- free_areas.append(
- MemoryArea('free', addr=addr, size=populating - addr,
- flags=flags, measure=False))
- populating = area.addr
- if populating > enclave_heap_min:
- flags = PAGEINFO_R | PAGEINFO_W | PAGEINFO_X | PAGEINFO_REG
- free_areas.append(
- MemoryArea('free', addr=enclave_heap_min,
- size=populating - enclave_heap_min, flags=flags,
- measure=False))
- gen_area_content(attr, areas)
- return areas + free_areas
- def generate_measurement(attr, areas):
- def do_ecreate(digest, size):
- data = struct.pack("<8sLQ44s", b"ECREATE", SSAFRAMESIZE // PAGESIZE,
- size, b"")
- digest.update(data)
- def do_eadd(digest, offset, flags):
- data = struct.pack("<8sQQ40s", b"EADD", offset, flags, b"")
- digest.update(data)
- def do_eextend(digest, offset, content):
- if len(content) != 256:
- raise ValueError("Exactly 256 bytes expected")
- data = struct.pack("<8sQ48s", b"EEXTEND", offset, b"")
- digest.update(data)
- digest.update(content)
- def include_page(digest, offset, flags, content, measure):
- if len(content) != PAGESIZE:
- raise ValueError("Exactly one page expected")
- do_eadd(digest, offset, flags)
- if measure:
- for i in range(0, PAGESIZE, 256):
- do_eextend(digest, offset + i, content[i:i + 256])
- mrenclave = hashlib.sha256()
- do_ecreate(mrenclave, attr['enclave_size'])
- def print_area(addr, size, flags, desc, measured):
- if flags & PAGEINFO_REG:
- type_ = 'REG'
- if flags & PAGEINFO_TCS:
- type_ = 'TCS'
- prot = ['-', '-', '-']
- if flags & PAGEINFO_R:
- prot[0] = 'R'
- if flags & PAGEINFO_W:
- prot[1] = 'W'
- if flags & PAGEINFO_X:
- prot[2] = 'X'
- prot = ''.join(prot)
- desc = '(' + desc + ')'
- if measured:
- desc += ' measured'
- if size == PAGESIZE:
- print(" %016x [%s:%s] %s" % (addr, type_, prot, desc))
- else:
- print(" %016x-%016lx [%s:%s] %s" %
- (addr, addr + size, type_, prot, desc))
- def load_file(digest, f, offset, addr, filesize, memsize, desc, flags):
- f_addr = rounddown(offset)
- m_addr = rounddown(addr)
- m_size = roundup(addr + memsize) - m_addr
- print_area(m_addr, m_size, flags, desc, True)
- for pg in range(m_addr, m_addr + m_size, PAGESIZE):
- start = pg - m_addr + f_addr
- end = start + PAGESIZE
- start_zero = b""
- if start < offset:
- if offset - start >= PAGESIZE:
- start_zero = ZERO_PAGE
- else:
- start_zero = bytes(offset - start)
- end_zero = b""
- if end > offset + filesize:
- if end - offset - filesize >= PAGESIZE:
- end_zero = ZERO_PAGE
- else:
- end_zero = bytes(end - offset - filesize)
- start += len(start_zero)
- end -= len(end_zero)
- if start < end:
- f.seek(start)
- data = f.read(end - start)
- else:
- data = b""
- if len(start_zero + data + end_zero) != PAGESIZE:
- raise Exception("wrong calculation")
- include_page(digest, pg, flags, start_zero + data + end_zero, True)
- for area in areas:
- if area.file:
- with open(area.file, 'rb') as f:
- if area.is_binary:
- loadcmds = get_loadcmds(area.file)
- if loadcmds:
- mapaddr = 0xffffffffffffffff
- for (offset, addr, filesize, memsize,
- prot) in loadcmds:
- if rounddown(addr) < mapaddr:
- mapaddr = rounddown(addr)
- baseaddr_ = area.addr - mapaddr
- for (offset, addr, filesize, memsize, prot) in loadcmds:
- flags = area.flags
- if prot & 4:
- flags = flags | PAGEINFO_R
- if prot & 2:
- flags = flags | PAGEINFO_W
- if prot & 1:
- flags = flags | PAGEINFO_X
- if flags & PAGEINFO_X:
- desc = 'code'
- else:
- desc = 'data'
- load_file(mrenclave, f, offset, baseaddr_ + addr,
- filesize, memsize, desc, flags)
- else:
- load_file(mrenclave, f, 0, area.addr,
- os.stat(area.file).st_size, area.size,
- area.desc, area.flags)
- else:
- for a in range(area.addr, area.addr + area.size, PAGESIZE):
- data = ZERO_PAGE
- if area.content is not None:
- start = a - area.addr
- end = start + PAGESIZE
- data = area.content[start:end]
- include_page(mrenclave, a, area.flags, data, area.measure)
- print_area(area.addr, area.size, area.flags, area.desc,
- area.measure)
- return mrenclave.digest()
- def generate_sigstruct(attr, args, mrenclave):
- """Generate Sigstruct."""
- today = datetime.date.today()
- # field format: (offset, type, value)
- fields = {
- 'header': (SGX_ARCH_SIGSTRUCT_HEADER,
- "<4L", 0x00000006, 0x000000e1, 0x00010000, 0x00000000),
- 'vendor': (SGX_ARCH_SIGSTRUCT_VENDOR, "<L", 0x00000000),
- 'date': (SGX_ARCH_SIGSTRUCT_DATE,
- "<HBB", today.year, today.month, today.day),
- 'header2': (SGX_ARCH_SIGSTRUCT_HEADER2,
- "<4L", 0x00000101, 0x00000060, 0x00000060, 0x00000001),
- 'swdefined': (SGX_ARCH_SIGSTRUCT_SWDEFINED, "<L", 0x00000000),
- 'miscs': (SGX_ARCH_SIGSTRUCT_MISCSELECT, "4s", attr['miscs']),
- 'miscmask': (SGX_ARCH_SIGSTRUCT_MISCSELECT_MASK, "4s", attr['miscs']),
- 'attrs': (SGX_ARCH_SIGSTRUCT_ATTRIBUTES,
- "8s8s", attr['flags'], attr['xfrms']),
- 'attrmask': (SGX_ARCH_SIGSTRUCT_ATTRIBUTES_MASK,
- "8s8s", attr['flags'], attr['xfrms']),
- 'mrenclave': (SGX_ARCH_SIGSTRUCT_ENCLAVE_HASH, "32s", mrenclave),
- 'isvprodid': (SGX_ARCH_SIGSTRUCT_ISVPRODID, "<H", attr['isvprodid']),
- 'isvsvn': (SGX_ARCH_SIGSTRUCT_ISVSVN, "<H", attr['isvsvn']),
- }
- sign_buffer = bytearray(128 + 128)
- for field in fields.values():
- if field[0] >= SGX_ARCH_SIGSTRUCT_MISCSELECT:
- struct.pack_into(field[1], sign_buffer,
- field[0] - SGX_ARCH_SIGSTRUCT_MISCSELECT + 128,
- *field[2:])
- else:
- struct.pack_into(field[1], sign_buffer, field[0], *field[2:])
- p = subprocess.Popen(
- ['openssl', 'rsa', '-modulus', '-in', args['key'], '-noout'],
- stdout=subprocess.PIPE)
- modulus_out = p.communicate()[0]
- modulus = bytes.fromhex(modulus_out[8:8+SGX_ARCH_KEY_SIZE*2].decode())
- modulus = bytes(reversed(modulus))
- p = subprocess.Popen(
- ['openssl', 'sha256', '-binary', '-sign', args['key']],
- stdin=subprocess.PIPE, stdout=subprocess.PIPE)
- signature = p.communicate(sign_buffer)[0]
- signature = signature[::-1]
- modulus_int = int.from_bytes(modulus, byteorder='little')
- signature_int = int.from_bytes(signature, byteorder='little')
- tmp1 = signature_int * signature_int
- q1_int = tmp1 // modulus_int
- tmp2 = tmp1 % modulus_int
- q2_int = tmp2 * signature_int // modulus_int
- q1 = q1_int.to_bytes(384, byteorder='little')
- q2 = q2_int.to_bytes(384, byteorder='little')
- fields.update({
- 'modulus': (SGX_ARCH_SIGSTRUCT_MODULUS, "384s", modulus),
- 'exponent': (SGX_ARCH_SIGSTRUCT_EXPONENT, "<L", 3),
- 'signature': (SGX_ARCH_SIGSTRUCT_SIGNATURE, "384s", signature),
- 'q1': (SGX_ARCH_SIGSTRUCT_Q1, "384s", q1),
- 'q2': (SGX_ARCH_SIGSTRUCT_Q2, "384s", q2),
- })
- buffer = bytearray(SGX_ARCH_SIGSTRUCT_SIZE)
- for field in fields.values():
- struct.pack_into(field[1], buffer, field[0], *field[2:])
- return buffer
- # Main Program
- argparser = argparse.ArgumentParser()
- argparser.add_argument('--output', '-output', metavar='OUTPUT',
- type=str, required=True,
- help='Output .manifest.sgx file '
- '(manifest augmented with autogenerated fields)')
- argparser.add_argument('--libpal', '-libpal', metavar='LIBPAL',
- type=str, required=True,
- help='Input libpal file '
- '(required as part of the enclave measurement)')
- argparser.add_argument('--key', '-key', metavar='KEY',
- type=str, required=True,
- help='specify signing key(.pem) file')
- argparser.add_argument('--manifest', '-manifest', metavar='MANIFEST',
- type=str, required=True,
- help='Input .manifest file '
- '(user-prepared manifest template)')
- argparser.add_argument('--exec', '-exec', metavar='EXEC',
- type=str, required=False,
- help='Input executable file '
- '(required as part of the enclave measurement)')
- def parse_args(args):
- args = argparser.parse_args(args)
- args_dict = {
- 'output': args.output,
- 'libpal': args.libpal,
- 'key': args.key,
- 'manifest': args.manifest,
- }
- if args.exec is not None:
- args_dict['exec'] = args.exec
- return args_dict
- def main(args=None):
- args = parse_args(args)
- (manifest, manifest_layout) = read_manifest(args['manifest'])
- if 'exec' not in args:
- if 'loader.exec' in manifest:
- exec_url = manifest['loader.exec']
- if exec_url[:5] != 'file:':
- print("executable must be a local file", file=sys.stderr)
- return -1
- args['exec'] = os.path.join(os.path.dirname(args['manifest']),
- exec_url[5:])
- args['root'] = os.path.dirname(os.path.abspath(args['output']))
- if 'sgx.sigfile' in manifest:
- args['sigfile'] = resolve_uri(manifest['sgx.sigfile'], False)
- else:
- sigfile = args['output']
- for ext in ['.manifest.sgx', '.manifest']:
- if sigfile.endswith(ext):
- sigfile = sigfile[:-len(ext)]
- break
- args['sigfile'] = sigfile + '.sig'
- manifest['sgx.sigfile'] = 'file:' + os.path.basename(args['sigfile'])
- # Get attributes from manifest
- attr = dict()
- parse_int = lambda s: int(s, 0)
- for key, default, parse in [
- ('enclave_size', DEFAULT_ENCLAVE_SIZE, parse_size),
- ('thread_num', str(DEFAULT_THREAD_NUM), parse_int),
- ('isvprodid', '0', parse_int),
- ('isvsvn', '0', parse_int),
- ]:
- attr[key] = parse(manifest.setdefault('sgx.' + key, default))
- (attr['flags'], attr['xfrms'], attr['miscs']) = get_enclave_attributes(
- manifest)
- print("Attributes:")
- print(" size: %d" % attr['enclave_size'])
- print(" threadnum: %d" % attr['thread_num'])
- print(" isvprodid: %d" % attr['isvprodid'])
- print(" isvsvn: %d" % attr['isvsvn'])
- print(" flags: %016x" % int.from_bytes(attr['flags'],
- byteorder='big'))
- print(" xfrms: %016x" % int.from_bytes(attr['xfrms'],
- byteorder='big'))
- print(" miscs: %08x" % int.from_bytes(attr['miscs'],
- byteorder='big'))
- # Check client info for remote attestation (if sgx.ra_client.spid is provided)
- print("Attestation:")
- if 'sgx.ra_client_spid' in manifest and manifest['sgx.ra_client_spid']:
- print(" spid: " + manifest['sgx.ra_client_spid'])
- if 'sgx.ra_client_key' in manifest and manifest['sgx.ra_client_key']:
- print(" key: " + manifest['sgx.ra_client_key'])
- else:
- print(" *** sgx.ra_client_key not specified ***")
- return -1
- if 'sgx.ra_client_linkable' in manifest:
- print(" linkable: " + manifest['sgx.ra_client_linkable'])
- else:
- print(" linkable: 0")
- else:
- print(" *** Client info is not specified. Graphene will not perform"
- " remote attestation before execution. Please provide"
- " sgx.ra_client_spid and sgx.ra_client_key in the manifest. ***")
- # Get trusted checksums and measurements
- print("Trusted files:")
- for key, val in get_trusted_files(manifest, args).items():
- (uri, _, checksum) = val
- print(" %s %s" % (checksum, uri))
- manifest['sgx.trusted_checksum.' + key] = checksum
- print("Trusted children:")
- for key, val in get_trusted_children(manifest).items():
- (uri, _, mrenclave) = val
- print(" %s %s" % (mrenclave, uri))
- manifest['sgx.trusted_mrenclave.' + key] = mrenclave
- # Try populate memory areas
- memory_areas = get_memory_areas(attr, args)
- if any([a.addr is not None for a in memory_areas]):
- manifest['sgx.static_address'] = '1'
- else:
- global enclave_heap_min
- enclave_heap_min = 0
- # Add manifest at the top
- shutil.copy2(args['manifest'], args['output'])
- output_manifest(args['output'], manifest, manifest_layout)
- memory_areas = [
- MemoryArea('manifest', file=args['output'],
- flags=PAGEINFO_R | PAGEINFO_REG)
- ] + memory_areas
- memory_areas = populate_memory_areas(attr, memory_areas)
- print("Memory:")
- # Generate measurement
- mrenclave = generate_measurement(attr, memory_areas)
- print("Measurement:")
- print(" %s" % mrenclave.hex())
- # Generate sigstruct
- open(args['sigfile'], 'wb').write(
- generate_sigstruct(attr, args, mrenclave))
- return 0
- if __name__ == "__main__":
- sys.exit(main())
|