pal-sgx-sign 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  1. #!/usr/bin/env python
  2. import os
  3. import sys
  4. import re
  5. import datetime
  6. import struct
  7. import subprocess
  8. import hashlib
  9. import binascii
  10. import shutil
  11. """ Default / Architectural Options """
  12. ARCHITECTURE = "amd64"
  13. PAGESIZE = 4096
  14. MEMORY_GAP = PAGESIZE
  15. TCSSIZE = PAGESIZE
  16. SSAFRAMESIZE = PAGESIZE
  17. SSAFRAMENUM = 2
  18. ENCLAVE_STACK_SIZE = PAGESIZE * 16
  19. DEFAULT_ENCLAVE_SIZE = '256M'
  20. DEFAULT_THREAD_NUM = 4
  21. ENCLAVE_HEAP_MIN = 0x10000
  22. """ Utilities """
  23. def roundup(addr):
  24. remaining = addr % PAGESIZE
  25. if remaining:
  26. return addr + (PAGESIZE - remaining)
  27. else:
  28. return addr
  29. def rounddown(addr):
  30. return addr - addr % PAGESIZE
  31. def roundup_data(data):
  32. return data + '\0' * (roundup(len(data)) - len(data))
  33. def int_to_bytes(i):
  34. b = ""
  35. l = 0
  36. while i > 0:
  37. b = b + chr(i % 256)
  38. i = i // 256
  39. l = l + 1
  40. return b
  41. def bytes_to_int(b):
  42. i = 0
  43. for c in b:
  44. i = i * 256 + ord(c)
  45. return i
  46. def parse_int(s):
  47. if len(s) > 2 and s.startswith("0x"):
  48. return int(s[2:], 16)
  49. if len(s) > 1 and s.startswith("0"):
  50. return int(s[1:], 8)
  51. return int(s)
  52. def parse_size(s):
  53. scale = 1
  54. if s.endswith("K"):
  55. scale = 1024
  56. if s.endswith("M"):
  57. scale = 1024 * 1024
  58. if s.endswith("G"):
  59. scale = 1024 * 1024 * 1024
  60. if scale != 1:
  61. s = s[:-1]
  62. return parse_int(s) * scale
  63. """ Reading / Writing Manifests """
  64. def read_manifest(filename):
  65. manifest = dict()
  66. manifest_layout = []
  67. with open(filename, "r") as f:
  68. for line in f.readlines():
  69. if line == "":
  70. manifest_layout.append((None, None))
  71. break
  72. pound = line.find("#")
  73. if pound != -1:
  74. comment = line[pound:].strip()
  75. line = line[:pound]
  76. else:
  77. comment = None
  78. line = line.strip()
  79. equal = line.find("=")
  80. if equal != -1:
  81. key = line[:equal].strip()
  82. manifest[key] = line[equal + 1:].strip()
  83. else:
  84. key = None
  85. manifest_layout.append((key, comment))
  86. return (manifest, manifest_layout)
  87. def output_manifest(filename, manifest, manifest_layout):
  88. with open(filename, 'w') as f:
  89. written = []
  90. for (key, comment) in manifest_layout:
  91. line = ''
  92. if key is not None:
  93. line += key + ' = ' + manifest[key]
  94. written.append(key)
  95. if comment is not None:
  96. if line != '':
  97. line += ' '
  98. line += comment
  99. print >>f, line
  100. print >>f
  101. print >>f, "# Generated by Graphene"
  102. print >>f
  103. for key in sorted(manifest.keys()):
  104. if key not in written:
  105. print >>f, key, '=', manifest[key]
  106. """ Loading Enclave Attributes """
  107. def get_enclave_attributes(manifest):
  108. sgx_flags = {
  109. 'FLAG_DEBUG' : struct.pack("<Q", 0x02),
  110. 'FLAG_MODE64BIT' : struct.pack("<Q", 0x04),
  111. }
  112. sgx_xfrms = {
  113. 'XFRM_LEGACY' : struct.pack("<Q", 0x03),
  114. 'XFRM_AVX' : struct.pack("<Q", 0x06),
  115. 'XFRM_AVX3' : struct.pack("<Q", 0xe6),
  116. 'XFRM_MPX' : struct.pack("<Q", 0x18),
  117. }
  118. sgx_miscs = {
  119. 'MISC_EXINFO' : struct.pack("<L", 0x01),
  120. }
  121. default_attributes = [
  122. 'FLAG_DEBUG',
  123. 'XFRM_LEGACY',
  124. 'XFRM_AVX',
  125. ]
  126. if ARCHITECTURE == 'amd64':
  127. default_attributes.append('FLAG_MODE64BIT')
  128. manifest_options = {
  129. 'debug' : 'FLAG_DEBUG',
  130. 'enable_avx3' : 'XFRM_AVX3',
  131. 'enable_mpx' : 'XFRM_MPX',
  132. 'support_exinfo' : 'MISC_EXINFO',
  133. }
  134. attributes = default_attributes
  135. for opt in manifest_options.keys():
  136. key = 'sgx.' + opt
  137. if key in manifest:
  138. if manifest[key] == '1':
  139. attributes.append(manifest_options[opt])
  140. else:
  141. if manifest_options[opt] in attributes:
  142. attributes.pop(manifest_options[opt])
  143. if manifest.get('sgx.disable_avx') == '1':
  144. attributes.remove('XFRM_AVX')
  145. flags_raw = struct.pack("<Q", 0)
  146. xfrms_raw = struct.pack("<Q", 0)
  147. miscs_raw = struct.pack("<L", 0)
  148. for attr in attributes:
  149. if attr in sgx_flags:
  150. flags_raw = ''.join([chr(ord(a)|ord(b)) for a, b in zip(flags_raw, sgx_flags[attr])])
  151. if attr in sgx_xfrms:
  152. xfrms_raw = ''.join([chr(ord(a)|ord(b)) for a, b in zip(xfrms_raw, sgx_xfrms[attr])])
  153. if attr in sgx_miscs:
  154. miscs_raw = ''.join([chr(ord(a)|ord(b)) for a, b in zip(miscs_raw, sgx_miscs[attr])])
  155. return flags_raw, xfrms_raw, miscs_raw
  156. """ Generate Checksums / Measurement """
  157. def resolve_uri(uri, check_exist=True):
  158. orig_uri = uri
  159. if uri.startswith('file:'):
  160. target = os.path.normpath(uri[5:])
  161. else:
  162. target = os.path.normpath(uri)
  163. if check_exist and not os.path.exists(target):
  164. raise Exception('Cannot resolve ' + orig_uri + ' or the file does not exist.')
  165. return target
  166. builtin_checksum_dictionary = dict([
  167. ('libaprutil-1.so.0', '070ef5ce5bd2246b1422ee2629bf45520e0001b827355770fba695b3fa0875bd'),
  168. ('libprotobuf.so.9', 'abd8b868f0f06584c30edbee90e27e2f8546ffe5bbe938922f62c5821b243925'),
  169. ('php.ini', '64db864cdad432bf5ddd10147b862fcccbaeaa9f1946572e51fd29a40419d7a1'),
  170. ('libxml2.so.2', '7e4720faceaf360a182168cfa338bfd5756d794888ad6db022ffbddae5356536'),
  171. ('libstdc++.so.6', '62affc63ba79e6718ab4c4388ca85a73e9476eb5abe4b9af4ae26b79859d8a5f'),
  172. ('libgcc_s.so.1', 'c77f8044b4f8ae7166e5b0968204a4624529bfc4f42f29180ba62eccbb8ce8b5'),
  173. ('libphpcpp.so.2.0', '17fd518d703dc89e173aa7ac0da41aa9fa2c0c2aee53a347d018d86b0b9f2b7b'),
  174. ('localattestation_decryption.so', '6075d7bf84028a0ed356ce82b65d2c20687ac3ddf0b1f0ff377a4dde0fbff345'),
  175. ('ld-linux-x86-64.so.2', 'f4ca46938370886e67167be1918f9ee1542eb633e4baf802788ba3234b038bd1'),
  176. ('libnss_compat.so.2', '2264d94307147f686cd245da2e0a4be26d954cf49d4c67eb00e2351b727022e4'),
  177. ('libpthread.so.0', '08d37ac3e370c040d544ccc7c22b75856f00ba343396dcdf06b5894dca236965'),
  178. ('libpcre.so.3', '47e4aa7dbcc325bf87b9117d3e4d216a874ee547920068538f79d6a9aa2f8197'),
  179. ('libsysdb.so', '79719b196987aa45ebe03afcaaa4d20435bd18522f2879ccc8e05b95aac57fc4'),
  180. ('libc.so.6', 'a56b9bc1616be611cf6b0d198119a032dba5e0ab330f0bb45b6c507de9da1b11'),
  181. ('libexpat.so.1', 'c8a3bea5b20cef75b00fe195e6d5671916a1925b769e5506442fdc95292a11b9'),
  182. ('libnsl.so.1', 'ea9b08f38db8fa5767e8984643cbd418e9feb7c48795a216c9a610e3a06e7f2e'),
  183. ('libresolv.so.2', '975e49f2c5a49c5dc982f7f16c515f14d874454f4bea41839625785533e7a893'),
  184. ('libicudata.so.55', '7c08e87ad676f17e83e7966d7784bf00ca8a8801bb50f059d75f14a8724dd9c5'),
  185. ('libicuuc.so.55', '7f8317190f6bc783135b00f4058e21a67ece3b26f01c7fffec8fbd5dadcc4063'),
  186. ('libcrypt.so.1', '3fe988797911e25cb62afce73d416552d553f719233e41e7fec555e0bf1df8df'),
  187. ('libm.so.6', '7f5a011231b01dac0e42feaab47e86fdc98db636933502bd71cb0f71a8f860fa'),
  188. ('httpd', 'dd14c4876f1a42d91bf0607004df3bd7242ca7cd9f8436e1ae513ad7e923cf8e'),
  189. ('libdl.so.2', '3f35b33bf03edae233e453b16663c1955c6552e8226f37d4a67b5e55f5f19f12'),
  190. ('libnss_files.so.2', 'aa7f8780fa4d02b82d31e0e99d33fb809d440440d42eb8b2a9ef7b3675c37fc6'),
  191. ('liblzma.so.5', '0f59a1a9e0a369c403fa7fc3a5aa6fc92d3087bd9f9b9eb07da712f549553bbf'),
  192. ('libz.so.1', 'a04cab74df9c7f96f82b34286bda5d4ee810feaac92dd2e8bcfe931d9c8baef4'),
  193. ('libnss_nis.so.2', 'da420502ac3bfb7df0a52c5f5d282d030b069f420c354cb8c0b97be678bc0d16'),
  194. ('libapr-1.so.0', 'ed490fbee479638995c92abd0bb5129a4fde56a1d61982b087bc66383ac74b89'),
  195. ('libnss_dns.so.2', '95166d8666e6902b734354a66ebb9d9f69c20b04d912534cefcab47cec6e569b'),
  196. ('libuuid.so.1', 'd2427063179b81342bbd5179cdf6907928df78c24595c91cabd0624b853f45ae')
  197. ]);
  198. def get_checksum(file): #Just need filename.
  199. key = file.split('/')[-1]
  200. if key in builtin_checksum_dictionary:
  201. return builtin_checksum_dictionary[key];
  202. raise Exception('Builtin dictionary doesnt know what this file is. Plz wait for a new version of the verifier.')
  203. def get_trusted_files(manifest, args):
  204. targets = dict()
  205. if 'exec' in args:
  206. targets['exec'] = (args['exec'], resolve_uri(args['exec']))
  207. if 'loader.preload' in manifest:
  208. i = 0
  209. preloads = []
  210. for uri in str.split(manifest['loader.preload'], ','):
  211. targets['preload' + str(i)] = (uri, resolve_uri(uri))
  212. preloads.append(uri)
  213. i += 1
  214. for (key, val) in manifest.items():
  215. if not key.startswith('sgx.trusted_files.'):
  216. continue
  217. key = key[len('sgx.trusted_files.'):]
  218. if key in targets:
  219. raise Exception('repeated key in manifest: sgx.trusted_files.' + key)
  220. targets[key] = (val, resolve_uri(val))
  221. for (key, val) in targets.items():
  222. (uri, target) = val
  223. checksum = get_checksum(target) #.encode('hex')
  224. targets[key] = (uri, target, checksum)
  225. return targets
  226. def get_trusted_children(manifest, args):
  227. targets = dict()
  228. for (key, val) in manifest.items():
  229. if not key.startswith('sgx.trusted_children.'):
  230. continue
  231. key = key[len('sgx.trusted_children.'):]
  232. if key in targets:
  233. raise Exception('repeated key in manifest: sgx.trusted_children.' + key)
  234. target = resolve_uri(val)
  235. sig = open(target, 'rb').read()[960:992].encode('hex')
  236. targets[key] = (val, target, sig)
  237. return targets
  238. """ Populate Enclave Memory """
  239. PAGEINFO_R = 0x1
  240. PAGEINFO_W = 0x2
  241. PAGEINFO_X = 0x4
  242. PAGEINFO_TCS = 0x100
  243. PAGEINFO_REG = 0x200
  244. def get_loadcmds(filename):
  245. loadcmds = []
  246. p = subprocess.Popen(['readelf', '-l', '-W', filename],
  247. stdout=subprocess.PIPE,
  248. stderr=subprocess.PIPE)
  249. while True:
  250. line = p.stdout.readline()
  251. if line == '':
  252. break
  253. stripped = line.strip()
  254. if not stripped.startswith('LOAD'):
  255. continue
  256. tokens = stripped.split()
  257. if len(tokens) < 6:
  258. continue
  259. if len(tokens) >= 7 and tokens[7] == "E":
  260. tokens[6] += tokens[7]
  261. prot = 0
  262. for t in tokens[6]:
  263. if t == "R":
  264. prot = prot | 4
  265. if t == "W":
  266. prot = prot | 2
  267. if t == "E":
  268. prot = prot | 1
  269. loadcmds.append((int(tokens[1][2:], 16), # offset
  270. int(tokens[2][2:], 16), # addr
  271. int(tokens[4][2:], 16), # filesize
  272. int(tokens[5][2:], 16), # memsize
  273. prot))
  274. p.wait()
  275. if p.returncode != 0:
  276. return None
  277. return loadcmds
  278. class MemoryArea:
  279. def __init__(self, desc, file=None, addr=None, size=None, flags=None):
  280. self.desc = desc
  281. self.file = file
  282. self.addr = addr
  283. self.size = size
  284. self.flags = flags
  285. self.is_binary = False
  286. if file:
  287. loadcmds = get_loadcmds(file)
  288. if loadcmds:
  289. mapaddr = 0xffffffffffffffff
  290. mapaddr_end = 0
  291. for (offset, addr, filesize, memsize, prot) in loadcmds:
  292. if rounddown(addr) < mapaddr:
  293. mapaddr = rounddown(addr)
  294. if roundup(addr + memsize) > mapaddr_end:
  295. mapaddr_end = roundup(addr + memsize)
  296. self.is_binary = True
  297. self.size = mapaddr_end - mapaddr
  298. if mapaddr > 0:
  299. self.addr = mapaddr
  300. else:
  301. self.size = os.stat(file).st_size
  302. if self.addr is not None:
  303. self.addr = rounddown(self.addr)
  304. if self.size is not None:
  305. self.size = roundup(self.size)
  306. def get_memory_areas(manifest, attr, args):
  307. areas = []
  308. areas.append(MemoryArea('ssa', size=attr['thread_num'] * SSAFRAMESIZE * SSAFRAMENUM,
  309. flags=PAGEINFO_R|PAGEINFO_W|PAGEINFO_REG))
  310. areas.append(MemoryArea('tcs', size=attr['thread_num'] * TCSSIZE,
  311. flags=PAGEINFO_TCS))
  312. areas.append(MemoryArea('tls', size=attr['thread_num'] * PAGESIZE,
  313. flags=PAGEINFO_R|PAGEINFO_W|PAGEINFO_REG))
  314. for t in range(attr['thread_num']):
  315. areas.append(MemoryArea('stack', size=ENCLAVE_STACK_SIZE,
  316. flags=PAGEINFO_R|PAGEINFO_W|PAGEINFO_REG))
  317. areas.append(MemoryArea('pal', file=args['libpal'], flags=PAGEINFO_REG))
  318. if 'exec' in args:
  319. areas.append(MemoryArea('exec', file=args['exec'],
  320. flags=PAGEINFO_W|PAGEINFO_REG))
  321. return areas
  322. def populate_memory_areas(manifest, attr, areas):
  323. populating = attr['enclave_size']
  324. for area in areas:
  325. if area.addr is not None:
  326. continue
  327. area.addr = populating - area.size
  328. if area.addr < ENCLAVE_HEAP_MIN:
  329. raise Exception("Enclave size is not large enough")
  330. if area.desc == 'exec':
  331. populating = area.addr;
  332. else:
  333. populating = area.addr - MEMORY_GAP
  334. free_areas = []
  335. for area in areas:
  336. if area.addr + area.size < populating:
  337. addr = area.addr + area.size
  338. free_areas.append(MemoryArea('free', addr=addr, size=populating - addr,
  339. flags=PAGEINFO_R|PAGEINFO_W|PAGEINFO_X|PAGEINFO_REG))
  340. populating = area.addr
  341. if populating > ENCLAVE_HEAP_MIN:
  342. free_areas.append(MemoryArea('free', addr=ENCLAVE_HEAP_MIN,
  343. size=populating - ENCLAVE_HEAP_MIN,
  344. flags=PAGEINFO_R|PAGEINFO_W|PAGEINFO_X|PAGEINFO_REG))
  345. return areas + free_areas
  346. def generate_measurement(attr, areas):
  347. def do_ecreate(digest, size):
  348. data = struct.pack("<8sLQ44s", "ECREATE", SSAFRAMESIZE / PAGESIZE, size, "")
  349. digest.update(data)
  350. def do_eadd(digest, offset, flags):
  351. data = struct.pack("<8sQQ40s", "EADD", offset, flags, "")
  352. digest.update(data)
  353. def do_eextend(digest, offset):
  354. data = struct.pack("<8sQ48s", "EEXTEND", offset, "")
  355. digest.update(data)
  356. class mrenclave_digest:
  357. def __init__(self):
  358. self.digest = hashlib.sha256()
  359. def update(self, payload):
  360. for er in range(0, len(payload), 64):
  361. self.digest.update(payload[er:er+64])
  362. def finalize(self):
  363. return self.digest.digest()
  364. mrenclave = mrenclave_digest()
  365. do_ecreate(mrenclave, attr['enclave_size'])
  366. def print_area(addr, size, flags, desc, measured):
  367. if flags & PAGEINFO_REG:
  368. type = 'REG'
  369. if flags & PAGEINFO_TCS:
  370. type = 'TCS'
  371. prot = ['-', '-', '-']
  372. if flags & PAGEINFO_R:
  373. prot[0] = 'R'
  374. if flags & PAGEINFO_W:
  375. prot[1] = 'W'
  376. if flags & PAGEINFO_X:
  377. prot[2] = 'X'
  378. prot = ''.join(prot)
  379. desc = '(' + desc + ')'
  380. if measured:
  381. desc += ' measured'
  382. if size == PAGESIZE:
  383. print >>sys.stderr, " %016x [%s:%s] %s" % (addr, type, prot, desc)
  384. else:
  385. print >>sys.stderr, " %016x-%016lx [%s:%s] %s" % (addr, addr + size, type, prot, desc)
  386. def load_file(digest, f, offset, addr, filesize, memsize, desc, flags):
  387. f_addr = rounddown(offset)
  388. m_addr = rounddown(addr)
  389. f_size = roundup(offset + filesize) - f_addr
  390. m_size = roundup(addr + memsize) - m_addr
  391. print_area(m_addr, f_size, flags, desc, True)
  392. if f_size < m_size:
  393. print_area(m_addr + f_size, m_size - f_size, flags, "bss", False)
  394. for pg in range(m_addr, m_addr + m_size, PAGESIZE):
  395. do_eadd(digest, pg, flags)
  396. if (pg >= m_addr + f_size):
  397. continue
  398. for er in range(pg, pg + PAGESIZE, 256):
  399. do_eextend(digest, er)
  400. start = er - m_addr + f_addr
  401. end = start + 256
  402. start_zero = ""
  403. if start < offset:
  404. if offset - start >= 256:
  405. start_zero = chr(0) * 256
  406. else:
  407. start_zero = chr(0) * (offset - start)
  408. end_zero = ""
  409. if end > offset + filesize:
  410. if end - offset - filesize >= 256:
  411. end_zero = chr(0) * 256
  412. else:
  413. end_zero = chr(0) * (end - offset - filesize)
  414. start += len(start_zero)
  415. end -= len(end_zero)
  416. if start < end:
  417. f.seek(start)
  418. data = f.read(end - start)
  419. else:
  420. data = ""
  421. if len(start_zero + data + end_zero) != 256:
  422. raise Exception("wrong calculation")
  423. digest.update(start_zero + data + end_zero)
  424. for area in areas:
  425. if area.file:
  426. with open(area.file, 'rb') as f:
  427. if area.is_binary:
  428. loadcmds = get_loadcmds(area.file)
  429. if loadcmds:
  430. mapaddr = 0xffffffffffffffff
  431. for (offset, addr, filesize, memsize, prot) in loadcmds:
  432. if rounddown(addr) < mapaddr:
  433. mapaddr = rounddown(addr)
  434. baseaddr = area.addr - mapaddr
  435. for (offset, addr, filesize, memsize, prot) in loadcmds:
  436. flags = area.flags
  437. if prot & 4:
  438. flags = flags | PAGEINFO_R
  439. if prot & 2:
  440. flags = flags | PAGEINFO_W
  441. if prot & 1:
  442. flags = flags | PAGEINFO_X
  443. if flags & PAGEINFO_X:
  444. desc = 'code'
  445. else:
  446. desc = 'data'
  447. load_file(mrenclave, f, offset, baseaddr + addr,
  448. filesize, memsize, desc, flags)
  449. else:
  450. load_file(mrenclave, f, 0, area.addr,
  451. os.stat(area.file).st_size, area.size,
  452. area.desc, area.flags)
  453. else:
  454. for a in range(area.addr, area.addr + area.size, PAGESIZE):
  455. do_eadd(mrenclave, a, area.flags)
  456. print_area(area.addr, area.size, area.flags, area.desc, False)
  457. return mrenclave.finalize()
  458. """ Generate Sigstruct """
  459. def generate_sigstruct(attr, args, mrenclave):
  460. today = datetime.date.today()
  461. # field format: (offset, type, value)
  462. fields = dict()
  463. fields['header'] = ( 0, "<4L", 0x00000006, 0x000000e1, 0x00010000, 0x00000000)
  464. fields['vendor'] = ( 16, "<L", 0x00000000)
  465. fields['date'] = ( 20, "<HBB", today.year, today.month, today.day)
  466. fields['header2'] = ( 24, "<4L", 0x00000101, 0x00000060, 0x00000060, 0x00000001)
  467. fields['swdefined'] = ( 40, "<L", 0x00000000)
  468. fields['miscs'] = ( 900, "4s", attr['miscs'])
  469. fields['miscmask'] = ( 904, "4s", attr['miscs'])
  470. fields['attrs'] = ( 928, "8s8s", attr['flags'], attr['xfrms'])
  471. fields['attrmask'] = ( 944, "8s8s", attr['flags'], attr['xfrms'])
  472. fields['mrencalve'] = ( 960, "32s", mrenclave)
  473. fields['isvprodid'] = (1024, "<H", attr['isvprodid'])
  474. fields['isvsvn'] = (1026, "<H", attr['isvsvn'])
  475. sign_buffer = bytearray(128 + 128)
  476. for key, field in fields.items():
  477. if field[0] >= 900:
  478. struct.pack_into(field[1], sign_buffer, field[0] - 900 + 128, *field[2:])
  479. else:
  480. struct.pack_into(field[1], sign_buffer, field[0], *field[2:])
  481. #TODO: Got to work on this part now - take in a key
  482. p = subprocess.Popen(['openssl', 'rsa', '-modulus', '-in', args['key'], '-noout'], stdout=subprocess.PIPE)
  483. modulus_out = p.communicate()[0]
  484. modulus = modulus_out[8:8+384*2].lower().decode('hex')
  485. modulus = modulus[::-1]
  486. #TODO: Sign the manifest. Prolly do this in C code?
  487. p = subprocess.Popen(['openssl', 'sha256', '-binary', '-sign', args['key']],
  488. stdin=subprocess.PIPE, stdout=subprocess.PIPE)
  489. signature = p.communicate(sign_buffer)[0]
  490. signature = signature[::-1]
  491. def bytes_to_int(bytes):
  492. i = 0
  493. q = 1
  494. for digit in bytes:
  495. if ord(digit) != 0:
  496. i = i + ord(digit) * q
  497. q = q * 256
  498. return i
  499. def int_to_bytes(i):
  500. b = ""
  501. l = 0
  502. while i > 0:
  503. b = b + chr(i % 256)
  504. i = i // 256
  505. l = l + 1
  506. return b
  507. modulus_int = bytes_to_int(modulus)
  508. signature_int = bytes_to_int(signature)
  509. tmp1 = signature_int * signature_int
  510. q1_int = tmp1 // modulus_int
  511. tmp2 = tmp1 % modulus_int
  512. q2_int = tmp2 * signature_int // modulus_int
  513. q1 = int_to_bytes(q1_int)
  514. q2 = int_to_bytes(q2_int)
  515. fields['modulus'] = ( 128, "384s", modulus)
  516. fields['exponent'] = ( 512, "<L", 3)
  517. fields['signature'] = ( 516, "384s", signature)
  518. fields['q1'] = (1040, "384s", q1)
  519. fields['q2'] = (1424, "384s", q2)
  520. buffer = bytearray(1808)
  521. for key, field in fields.items():
  522. struct.pack_into(field[1], buffer, field[0], *field[2:])
  523. return buffer
  524. """ Main Program """
  525. options = {
  526. # Option name : (Required Value)
  527. 'output': (True, 'output'),
  528. 'libpal': (True, 'libpal path'),
  529. 'key': (True, 'signing key'),
  530. 'manifest': (True, 'manifest'),
  531. 'exec': (False, 'executable'),
  532. }
  533. def usage():
  534. usage_message = 'USAGE: ' + sys.argv[0] + ' -help|-h'
  535. for opt, optval in options.items():
  536. if not optval[0]:
  537. usage_message += '['
  538. usage_message += '|-' + opt
  539. if optval[1]:
  540. usage_message += ' <' + optval[1] + '>'
  541. if not optval[0]:
  542. usage_message += ']'
  543. print >> sys.stderr, usage_message
  544. os._exit(-1)
  545. def parse_args():
  546. args = dict()
  547. for opt, optval in options.items():
  548. if not optval[1]:
  549. args[opt] = False
  550. i = 1
  551. while i < len(sys.argv):
  552. got = sys.argv[i]
  553. if got == '-help' or got == '-h':
  554. usage()
  555. invalid = True
  556. for opt, optval in options.items():
  557. if got != '-' + opt:
  558. continue
  559. if optval[1] is not None:
  560. i += 1
  561. if i == len(sys.argv):
  562. print >>sys.stderr, "Option %s needs a value." % (opt)
  563. usage()
  564. args[opt] = sys.argv[i]
  565. else:
  566. args[opt] = True
  567. invalid = False
  568. break
  569. if invalid:
  570. print >>sys.stderr, "Unknown option: %s." % (got[1:])
  571. usage()
  572. i += 1
  573. for opt, optval in options.items():
  574. if optval[0] and opt not in args:
  575. print >>sys.stderr, "Must specify %s <%s>." % (opt, optval[1])
  576. usage()
  577. return args
  578. if __name__ == "__main__":
  579. # Parse arguments
  580. args = parse_args()
  581. (manifest, manifest_layout) = read_manifest(args['manifest'])
  582. if 'exec' not in args:
  583. if 'loader.exec' in manifest:
  584. exec_url = manifest['loader.exec']
  585. if exec_url[:5] != 'file:':
  586. print "executable must be a local file"
  587. os._exit(-1)
  588. args['exec'] = os.path.join(os.path.dirname(args['manifest']), exec_url[5:])
  589. args['root'] = os.path.dirname(os.path.abspath(args['output']))
  590. if 'sgx.sigfile' in manifest:
  591. args['sigfile'] = resolve_uri(manifest['sgx.sigfile'], False)
  592. else:
  593. sigfile = args['output']
  594. for ext in ['.manifest.sgx', '.manifest']:
  595. if sigfile.endswith(ext):
  596. sigfile = sigfile[:-len(ext)]
  597. break
  598. args['sigfile'] = sigfile + '.sig'
  599. manifest['sgx.sigfile'] = 'file:' + os.path.basename(args['sigfile'])
  600. # Get attributes from manifest
  601. attr = dict()
  602. for key, default, parse in [
  603. ('enclave_size', DEFAULT_ENCLAVE_SIZE, parse_size),
  604. ('thread_num', str(DEFAULT_THREAD_NUM), parse_int),
  605. ('isvprodid', '0', parse_int),
  606. ('isvsvn', '0', parse_int),
  607. ]:
  608. if 'sgx.' + key not in manifest:
  609. manifest['sgx.' + key] = default
  610. attr[key] = parse(manifest['sgx.' + key])
  611. (attr['flags'], attr['xfrms'], attr['miscs']) = get_enclave_attributes(manifest)
  612. print >>sys.stderr, "Attributes:"
  613. print >>sys.stderr, " size: %d" % (attr['enclave_size'])
  614. print >>sys.stderr, " threadnum: %d" % (attr['thread_num'])
  615. print >>sys.stderr, " isvprodid: %d" % (attr['isvprodid'])
  616. print >>sys.stderr, " isvsvn: %d" % (attr['isvsvn'])
  617. print >>sys.stderr, " flags: %016x" % (bytes_to_int(attr['flags']))
  618. print >>sys.stderr, " xfrms: %016x" % (bytes_to_int(attr['xfrms']))
  619. print >>sys.stderr, " miscs: %08x" % (bytes_to_int(attr['miscs']))
  620. # Get trusted checksums and measurements
  621. #Fixed this to make it run without computing hashes.
  622. print >>sys.stderr, "Trusted files:"
  623. for key, val in get_trusted_files(manifest, args).items():
  624. (uri, target, checksum) = val
  625. print >>sys.stderr, " ('%s', '%s')," % (target.split('/')[-1], checksum) #(checksum, uri)
  626. manifest['sgx.trusted_checksum.' + key] = checksum
  627. print >>sys.stderr, "Trusted children:"
  628. for key, val in get_trusted_children(manifest, args).items():
  629. (uri, target, mrenclave) = val
  630. print >>sys.stderr, " %s %s" % (mrenclave, uri)
  631. manifest['sgx.trusted_mrenclave.' + key] = mrenclave
  632. #TODO: Uses readelf for .sgx manifest file, output file and libpal.
  633. #Try to hard-code results for libpal, exec in GET_LOADCMDS (called by the constructor of MemoryAreas).
  634. # Try populate memory areas
  635. memory_areas = get_memory_areas(manifest, attr, args)
  636. if len([a for a in memory_areas if a.addr is not None]) > 0:
  637. manifest['sgx.static_address'] = '1'
  638. else:
  639. ENCLAVE_HEAP_MIN = 0
  640. # Add manifest at the top
  641. shutil.copy2(args['manifest'], args['output'])
  642. output_manifest(args['output'], manifest, manifest_layout)
  643. memory_areas = [
  644. MemoryArea('manifest', file=args['output'],
  645. flags=PAGEINFO_R|PAGEINFO_REG)
  646. ] + memory_areas
  647. memory_areas = populate_memory_areas(manifest, attr, memory_areas)
  648. print >>sys.stderr, "Memory:"
  649. # Generate measurement
  650. #TODO:This should also tap into the hard-coded readelf results.
  651. mrenclave = generate_measurement(attr, memory_areas)
  652. print >>sys.stderr, "Measurement:"
  653. print >>sys.stderr, " " + mrenclave.encode('hex')
  654. #TODO:This should also be removed - prolly just return the sigstruct to the main verifier enclave.
  655. # Generate sigstruct
  656. open(args['sigfile'], 'wb').write(generate_sigstruct(attr, args, mrenclave))