def test_sgx_measurement(self): sgx_measurement = sgx_structs.SgxMeasurement() # Test with None and invalid types with self.assertRaises(TypeError): sgx_measurement.parse_from_bytes(None) with self.assertRaises(TypeError): sgx_measurement.parse_from_bytes([]) with self.assertRaises(TypeError): sgx_measurement.parse_from_bytes({}) with self.assertRaises(TypeError): sgx_measurement.parse_from_bytes(1) with self.assertRaises(TypeError): sgx_measurement.parse_from_bytes(1.0) with self.assertRaises(TypeError): sgx_measurement.parse_from_bytes('') # Test an empty string, a string that is one too short, and a string # that is one too long with self.assertRaises(ValueError): sgx_measurement.parse_from_bytes(b'') with self.assertRaises(ValueError): sgx_measurement.parse_from_bytes( b'\x00' * (sgx_structs.SgxMeasurement.STRUCT_SIZE - 1)) with self.assertRaises(ValueError): sgx_measurement.parse_from_bytes( b'\x00' * (sgx_structs.SgxMeasurement.STRUCT_SIZE + 1)) # Verify sgx_measurement unpacks properly measurement = \ TestSgxStructs.create_random_buffer( sgx_structs.SgxMeasurement.STRUCT_SIZE) sgx_measurement.parse_from_bytes(measurement) self.assertTrue(sgx_measurement.m == measurement) # Reset the object using the field values and verify that we # get expected serialized buffer sgx_measurement = sgx_structs.SgxMeasurement(m=measurement) self.assertEqual(measurement, sgx_measurement.serialize_to_bytes())
def create_signup_info(self, originator_public_key_hash, nonce, pse_manifest_status='OK'): # currently not used # _active_wait_timer = None # We are going to fake out the sealing the signup data. signup_data = { 'poet_public_key': self.poet_public_key.as_hex(), 'poet_private_key': self._poet_private_key.as_hex() } # Build up a fake SGX quote containing: # 1. The basename # 2. The report body that contains: # a. The enclave measurement # b. The report data SHA256(SHA256(OPK)|PPK) sgx_basename = \ sgx_structs.SgxBasename(name=self.__VALID_BASENAME__) sgx_measurement = \ sgx_structs.SgxMeasurement( m=self.__VALID_ENCLAVE_MEASUREMENT__) hash_input = \ '{0}{1}'.format( originator_public_key_hash.upper(), self.poet_public_key.as_hex().upper()).encode() report_data = hashlib.sha256(hash_input).digest() sgx_report_data = sgx_structs.SgxReportData(d=report_data) sgx_report_body = \ sgx_structs.SgxReportBody( mr_enclave=sgx_measurement, report_data=sgx_report_data) sgx_quote = \ sgx_structs.SgxQuote( basename=sgx_basename, report_body=sgx_report_body) # Create a fake PSE manifest. A base64 encoding of the # originator public key hash should suffice. pse_manifest = \ base64.b64encode(originator_public_key_hash.encode()) timestamp = '2017-02-16T15:21:24.437048' # Fake our "proof" data. verification_report = OrderedDict([ ('epidPseudonym', originator_public_key_hash), ('id', base64.b64encode( hashlib.sha256( timestamp.encode()).hexdigest().encode()).decode()), ('isvEnclaveQuoteStatus', 'OK'), ('isvEnclaveQuoteBody', base64.b64encode(sgx_quote.serialize_to_bytes()).decode()), ('pseManifestStatus', pse_manifest_status), ('pseManifestHash', hashlib.sha256(base64.b64decode(pse_manifest)).hexdigest()), ('nonce', nonce), ('timestamp', timestamp) ]) proof_data = \ self.create_proof_data( verification_report=verification_report, evidence_payload={ 'pse_manifest': pse_manifest.decode() }) return \ SignUpInfo( poet_public_key=signup_data['poet_public_key'], proof_data=proof_data, anti_sybil_id=originator_public_key_hash, nonce=nonce)
def create_signup_info(cls, originator_public_key_hash, nonce): with cls._lock: # First we need to create a public/private key pair for the PoET # enclave to use. # Counter ID is a placeholder for a hardware counter in a TEE. poet_private_key = Secp256k1PrivateKey.new_random() poet_public_key = \ cls._context.get_public_key(poet_private_key) counter_id = None # Simulate sealing (encrypting) the signup data. signup_data = { 'poet_private_key': poet_private_key.as_hex(), 'poet_public_key': poet_public_key.as_hex(), 'counter_id': counter_id } sealed_signup_data = \ base64.b64encode( dict2json(signup_data).encode()).decode('utf-8') # Build up a fake SGX quote containing: # 1. The basename # 2. The report body that contains: # a. The enclave measurement # b. The report data SHA256(SHA256(OPK)|PPK) sgx_basename = \ sgx_structs.SgxBasename(name=cls.__VALID_BASENAME__) sgx_measurement = \ sgx_structs.SgxMeasurement( m=cls.__VALID_ENCLAVE_MEASUREMENT__) hash_input = \ '{0}{1}'.format( originator_public_key_hash.upper(), poet_public_key.as_hex().upper()).encode() report_data = hashlib.sha256(hash_input).digest() sgx_report_data = sgx_structs.SgxReportData(d=report_data) sgx_report_body = \ sgx_structs.SgxReportBody( mr_enclave=sgx_measurement, report_data=sgx_report_data) sgx_quote = \ sgx_structs.SgxQuote( basename=sgx_basename, report_body=sgx_report_body) # Create a fake PSE manifest. A base64 encoding of the # originator public key hash should suffice. pse_manifest = \ base64.b64encode(originator_public_key_hash.encode()) timestamp = datetime.datetime.now().isoformat() # Fake our "proof" data. verification_report = { 'epidPseudonym': cls._anti_sybil_id, 'id': base64.b64encode( hashlib.sha256( timestamp.encode()).hexdigest().encode()).decode(), 'isvEnclaveQuoteStatus': 'OK', 'isvEnclaveQuoteBody': base64.b64encode(sgx_quote.serialize_to_bytes()).decode(), 'pseManifestStatus': 'OK', 'pseManifestHash': hashlib.sha256(base64.b64decode(pse_manifest)).hexdigest(), 'nonce': nonce, 'timestamp': timestamp } # Serialize the verification report, sign it, and then put # in the proof data verification_report_json = dict2json(verification_report) signature = \ cls._report_private_key.sign( verification_report_json.encode(), padding.PKCS1v15(), hashes.SHA256()) proof_data_dict = { 'evidence_payload': { 'pse_manifest': pse_manifest.decode() }, 'verification_report': verification_report_json, 'signature': base64.b64encode(signature).decode() } proof_data = dict2json(proof_data_dict) return \ EnclaveSignupInfo( poet_public_key=signup_data['poet_public_key'], proof_data=proof_data, anti_sybil_id=cls._anti_sybil_id, sealed_signup_data=sealed_signup_data)
def test_sgx_quote(self): sgx_quote = sgx_structs.SgxQuote() # Test with None and invalid types with self.assertRaises(TypeError): sgx_quote.parse_from_bytes(None) with self.assertRaises(TypeError): sgx_quote.parse_from_bytes([]) with self.assertRaises(TypeError): sgx_quote.parse_from_bytes({}) with self.assertRaises(TypeError): sgx_quote.parse_from_bytes(1) with self.assertRaises(TypeError): sgx_quote.parse_from_bytes(1.0) with self.assertRaises(TypeError): sgx_quote.parse_from_bytes('') # Test an empty string and a buffer one too small with self.assertRaises(ValueError): sgx_quote.parse_from_bytes(b'') with self.assertRaises(ValueError): sgx_quote.parse_from_bytes( b'\x00' * (sgx_structs.SgxQuote.FIXED_STRUCT_SIZE - 1)) # typedef uint8_t sgx_epid_group_id_t[4]; # typedef uint16_t sgx_isv_svn_t; # uint16_t version; /* 0 */ # uint16_t sign_type; /* 2 */ # sgx_epid_group_id_t epid_group_id; /* 4 */ # sgx_isv_svn_t qe_svn; /* 8 */ # sgx_isv_svn_t pce_svn; /* 10 */ # uint32_t extended_epid_group_id; /* 12 */ # sgx_basename_t basename; /* 16 */ # sgx_report_body_t report_body; /* 48 */ # uint32_t signature_len; /* 432 */ # uint8_t signature[]; /* 436 */ # Verify sgx_quote unpacks properly version = 0x0102 sign_type = 0x0304 epid_group_id = TestSgxStructs.create_random_buffer(4) qe_svn = 0x0506 pce_svn = 0x0708 extended_epid_group_id = 0x090a0b0c basename = \ TestSgxStructs.create_random_buffer( sgx_structs.SgxBasename.STRUCT_SIZE) svn = \ TestSgxStructs.create_random_buffer( sgx_structs.SgxCpuSvn.STRUCT_SIZE) misc_select = 0x0d0e0f10 reserved1 = b'\x00' * 28 flags = 0x1112131415161718 xfrm = 0x191a1b1c1d1e1f20 mr_enclave = \ TestSgxStructs.create_random_buffer( sgx_structs.SgxMeasurement.STRUCT_SIZE) reserved2 = b'\x00' * 32 mr_signer = \ TestSgxStructs.create_random_buffer( sgx_structs.SgxMeasurement.STRUCT_SIZE) reserved3 = b'\x00' * 96 isv_prod_id = 0x2122 isv_svn = 0x2324 reserved4 = b'\x00' * 60 report_data = \ TestSgxStructs.create_random_buffer( sgx_structs.SgxReportData.STRUCT_SIZE) report_body = \ struct.pack( '<{}sL{}sQQ{}s{}s{}s{}sHH{}s{}s'.format( len(svn), len(reserved1), len(mr_enclave), len(reserved2), len(mr_signer), len(reserved3), len(reserved4), len(report_data) ), svn, misc_select, reserved1, flags, xfrm, mr_enclave, reserved2, mr_signer, reserved3, isv_prod_id, isv_svn, reserved4, report_data) quote = \ struct.pack( '<HH{}sHHL{}s{}s'.format( len(epid_group_id), len(basename), len(report_body)), version, sign_type, epid_group_id, qe_svn, pce_svn, extended_epid_group_id, basename, report_body) sgx_quote.parse_from_bytes(quote) self.assertTrue(sgx_quote.version == version) self.assertTrue(sgx_quote.sign_type == sign_type) self.assertTrue(sgx_quote.epid_group_id == epid_group_id) self.assertTrue(sgx_quote.qe_svn == qe_svn) self.assertTrue(sgx_quote.pce_svn == pce_svn) self.assertTrue(sgx_quote.basename.name == basename) self.assertTrue(sgx_quote.report_body.cpu_svn.svn == svn) self.assertTrue(sgx_quote.report_body.misc_select == misc_select) self.assertTrue(sgx_quote.report_body.attributes.flags == flags) self.assertTrue(sgx_quote.report_body.attributes.xfrm == xfrm) self.assertTrue(sgx_quote.report_body.mr_enclave.m == mr_enclave) self.assertTrue(sgx_quote.report_body.mr_signer.m == mr_signer) self.assertTrue(sgx_quote.report_body.isv_prod_id == isv_prod_id) self.assertTrue(sgx_quote.report_body.isv_svn == isv_svn) self.assertTrue(sgx_quote.report_body.report_data.d == report_data) # Add a few bytes so that the signature length is partial. Should # fail. bad_quote = quote[:] for _ in range(3): bad_quote += TestSgxStructs.create_random_buffer(1) with self.assertRaises(ValueError): sgx_quote.parse_from_bytes(bad_quote) # Add a non-zero signature length, but don't add a signature. Should # fail. bad_quote = struct.pack('<{}sL'.format(len(quote)), quote, 4) with self.assertRaises(ValueError): sgx_quote.parse_from_bytes(bad_quote) # Add a signature that is too short short_signature = TestSgxStructs.create_random_buffer(31) bad_quote = \ struct.pack( '<{}sL{}s'.format( len(quote), len(short_signature)), quote, len(short_signature) + 1, short_signature) with self.assertRaises(ValueError): sgx_quote.parse_from_bytes(bad_quote) # Add a signature length of zero without a signature and verify unsigned_quote = struct.pack('<{}sL'.format(len(quote)), quote, 0) sgx_quote.parse_from_bytes(unsigned_quote) self.assertTrue(sgx_quote.version == version) self.assertTrue(sgx_quote.sign_type == sign_type) self.assertTrue(sgx_quote.epid_group_id == epid_group_id) self.assertTrue(sgx_quote.qe_svn == qe_svn) self.assertTrue(sgx_quote.pce_svn == pce_svn) self.assertTrue(sgx_quote.basename.name == basename) self.assertTrue(sgx_quote.report_body.cpu_svn.svn == svn) self.assertTrue(sgx_quote.report_body.misc_select == misc_select) self.assertTrue(sgx_quote.report_body.attributes.flags == flags) self.assertTrue(sgx_quote.report_body.attributes.xfrm == xfrm) self.assertTrue(sgx_quote.report_body.mr_enclave.m == mr_enclave) self.assertTrue(sgx_quote.report_body.mr_signer.m == mr_signer) self.assertTrue(sgx_quote.report_body.isv_prod_id == isv_prod_id) self.assertTrue(sgx_quote.report_body.isv_svn == isv_svn) self.assertTrue(sgx_quote.report_body.report_data.d == report_data) self.assertTrue(sgx_quote.signature_len == 0) # Add a good signature and verify signature = TestSgxStructs.create_random_buffer(32) signed_quote = \ struct.pack( '<{}sL{}s'.format( len(quote), len(signature)), quote, len(signature), signature) sgx_quote.parse_from_bytes(signed_quote) self.assertTrue(sgx_quote.version == version) self.assertTrue(sgx_quote.sign_type == sign_type) self.assertTrue(sgx_quote.epid_group_id == epid_group_id) self.assertTrue(sgx_quote.qe_svn == qe_svn) self.assertTrue(sgx_quote.pce_svn == pce_svn) self.assertTrue(sgx_quote.basename.name == basename) self.assertTrue(sgx_quote.report_body.cpu_svn.svn == svn) self.assertTrue(sgx_quote.report_body.misc_select == misc_select) self.assertTrue(sgx_quote.report_body.attributes.flags == flags) self.assertTrue(sgx_quote.report_body.attributes.xfrm == xfrm) self.assertTrue(sgx_quote.report_body.mr_enclave.m == mr_enclave) self.assertTrue(sgx_quote.report_body.mr_signer.m == mr_signer) self.assertTrue(sgx_quote.report_body.isv_prod_id == isv_prod_id) self.assertTrue(sgx_quote.report_body.isv_svn == isv_svn) self.assertTrue(sgx_quote.report_body.report_data.d == report_data) self.assertTrue(sgx_quote.signature_len == len(signature)) self.assertTrue(sgx_quote.signature == signature) # Reset the object using the field values and verify that we # get expected serialized buffer sgx_basename = sgx_structs.SgxBasename(name=basename) sgx_cpu_svn = sgx_structs.SgxCpuSvn(svn=svn) sgx_attributes = sgx_structs.SgxAttributes(flags=flags, xfrm=xfrm) sgx_measurement_mr_enclave = sgx_structs.SgxMeasurement(m=mr_enclave) sgx_measurement_mr_signer = sgx_structs.SgxMeasurement(m=mr_signer) sgx_report_data = sgx_structs.SgxReportData(d=report_data) sgx_report_body = \ sgx_structs.SgxReportBody( cpu_svn=sgx_cpu_svn, misc_select=misc_select, attributes=sgx_attributes, mr_enclave=sgx_measurement_mr_enclave, mr_signer=sgx_measurement_mr_signer, isv_prod_id=isv_prod_id, isv_svn=isv_svn, report_data=sgx_report_data) sgx_quote = sgx_structs.SgxQuote( version=version, sign_type=sign_type, epid_group_id=epid_group_id, qe_svn=qe_svn, pce_svn=pce_svn, extended_epid_group_id=extended_epid_group_id, basename=sgx_basename, report_body=sgx_report_body) self.assertEqual(quote, sgx_quote.serialize_to_bytes()[:len(quote)]) # Verify that zero signature serializes successfully zero_sign_quote = struct.pack('<{}sL'.format(len(quote)), quote, 0) self.assertEqual(zero_sign_quote, sgx_quote.serialize_to_bytes()) # Verify that non-zero signature serializes successfully non_zero_sign_quote = \ struct.pack( '<{}sL{}s'.format( len(quote), len(signature)), quote, len(signature), signature) sgx_quote.signature_len = len(signature) sgx_quote.signature = signature self.assertEqual(non_zero_sign_quote, sgx_quote.serialize_to_bytes())
def test_sgx_report(self): sgx_report = sgx_structs.SgxReport() # Test with None and invalid types with self.assertRaises(TypeError): sgx_report.parse_from_bytes(None) with self.assertRaises(TypeError): sgx_report.parse_from_bytes([]) with self.assertRaises(TypeError): sgx_report.parse_from_bytes({}) with self.assertRaises(TypeError): sgx_report.parse_from_bytes(1) with self.assertRaises(TypeError): sgx_report.parse_from_bytes(1.0) with self.assertRaises(TypeError): sgx_report.parse_from_bytes('') # Test an empty string, a string that is one too short, and a string # that is one too long with self.assertRaises(ValueError): sgx_report.parse_from_bytes(b'') with self.assertRaises(ValueError): sgx_report.parse_from_bytes( b'\x00' * (sgx_structs.SgxReport.STRUCT_SIZE - 1)) with self.assertRaises(ValueError): sgx_report.parse_from_bytes( b'\x00' * (sgx_structs.SgxReport.STRUCT_SIZE + 1)) # Simply verify that buffer of correct size unpacks without error sgx_report.parse_from_bytes( TestSgxStructs.create_random_buffer( sgx_structs.SgxReport.STRUCT_SIZE)) # The report body is laid out as follows: # # sgx_report_body_t body; /* 0 */ # sgx_key_id_t key_id; /* 384 */ # sgx_mac_t mac; /* 416 */ # Verify sgx_report unpacks properly svn = \ TestSgxStructs.create_random_buffer( sgx_structs.SgxCpuSvn.STRUCT_SIZE) misc_select = 0x00010203 reserved1 = b'\x00' * 28 flags = 0x0405060708090a0b xfrm = 0x0c0d0e0f10111213 mr_enclave = \ TestSgxStructs.create_random_buffer( sgx_structs.SgxMeasurement.STRUCT_SIZE) reserved2 = b'\x00' * 32 mr_signer = \ TestSgxStructs.create_random_buffer( sgx_structs.SgxMeasurement.STRUCT_SIZE) reserved3 = b'\x00' * 96 isv_prod_id = 0x1415 isv_svn = 0x1617 reserved4 = b'\x00' * 60 report_data = \ TestSgxStructs.create_random_buffer( sgx_structs.SgxReportData.STRUCT_SIZE) report_body = \ struct.pack( '<{}sL{}sQQ{}s{}s{}s{}sHH{}s{}s'.format( len(svn), len(reserved1), len(mr_enclave), len(reserved2), len(mr_signer), len(reserved3), len(reserved4), len(report_data) ), svn, misc_select, reserved1, flags, xfrm, mr_enclave, reserved2, mr_signer, reserved3, isv_prod_id, isv_svn, reserved4, report_data) key_id = \ TestSgxStructs.create_random_buffer( sgx_structs.SgxKeyId.STRUCT_SIZE) mac = TestSgxStructs.create_random_buffer(16) report = \ struct.pack( '<{}s{}s{}s'.format( len(report_body), len(key_id), len(mac)), report_body, key_id, mac) sgx_report.parse_from_bytes(report) self.assertTrue(sgx_report.body.cpu_svn.svn == svn) self.assertTrue(sgx_report.body.misc_select == misc_select) self.assertTrue(sgx_report.body.attributes.flags == flags) self.assertTrue(sgx_report.body.attributes.xfrm == xfrm) self.assertTrue(sgx_report.body.mr_enclave.m == mr_enclave) self.assertTrue(sgx_report.body.mr_signer.m == mr_signer) self.assertTrue(sgx_report.body.isv_prod_id == isv_prod_id) self.assertTrue(sgx_report.body.isv_svn == isv_svn) self.assertTrue(sgx_report.body.report_data.d == report_data) self.assertTrue(sgx_report.key_id.id == key_id) self.assertTrue(sgx_report.mac == mac) # Reset the object using the field values and verify that we # get expected serialized buffer sgx_cpu_svn = sgx_structs.SgxCpuSvn(svn=svn) sgx_attributes = sgx_structs.SgxAttributes(flags=flags, xfrm=xfrm) sgx_measurement_mr_enclave = sgx_structs.SgxMeasurement(m=mr_enclave) sgx_measurement_mr_signer = sgx_structs.SgxMeasurement(m=mr_signer) sgx_report_data = sgx_structs.SgxReportData(d=report_data) sgx_report_body = \ sgx_structs.SgxReportBody( cpu_svn=sgx_cpu_svn, misc_select=misc_select, attributes=sgx_attributes, mr_enclave=sgx_measurement_mr_enclave, mr_signer=sgx_measurement_mr_signer, isv_prod_id=isv_prod_id, isv_svn=isv_svn, report_data=sgx_report_data) sgx_key_id = sgx_structs.SgxKeyId(identifier=key_id) sgx_report = \ sgx_structs.SgxReport( body=sgx_report_body, key_id=sgx_key_id, mac=mac) self.assertEqual(report, sgx_report.serialize_to_bytes())