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 _verify_signup_info(self, signup_info, originator_public_key_hash, val_reg_payload, context): # Verify the attestation verification report signature proof_data_dict = json.loads(signup_info.proof_data) verification_report = proof_data_dict.get('verification_report') if verification_report is None: raise ValueError('Verification report is missing from proof data') signature = proof_data_dict.get('signature') if signature is None: raise ValueError('Signature is missing from proof data') # Try to get the report key from the configuration setting. If it # is not there or we cannot parse it, fail verification. try: report_public_key_pem = \ _get_config_setting( context=context, key='sawtooth.poet.report_public_key_pem') report_public_key = \ serialization.load_pem_public_key( report_public_key_pem.encode(), backend=backends.default_backend()) except KeyError: raise \ ValueError( 'Report public key configuration setting ' '(sawtooth.poet.report_public_key_pem) not found.') except (TypeError, ValueError) as error: raise ValueError('Failed to parse public key: {}'.format(error)) # Retrieve the valid enclave measurement values, converting the comma- # delimited list. If it is not there, or fails to parse correctly, # fail verification. try: valid_measurements = \ _get_config_setting( context=context, key='sawtooth.poet.valid_enclave_measurements') valid_enclave_mesaurements = \ [bytes.fromhex(m) for m in valid_measurements.split(',')] except KeyError: raise \ ValueError( 'Valid enclave measurements configuration setting ' '(sawtooth.poet.valid_enclave_measurements) not found.') except ValueError as error: raise \ ValueError( 'Failed to parse enclave measurement: {}'.format( valid_measurements)) # Retrieve the valid enclave basename value. If it is not there, or # fails to parse correctly, fail verification. try: valid_basenames = \ _get_config_setting( context=context, key='sawtooth.poet.valid_enclave_basenames') valid_enclave_basenames = \ [bytes.fromhex(b) for b in valid_basenames.split(',')] except KeyError: raise \ ValueError( 'Valid enclave basenames configuration setting ' '(sawtooth.poet.valid_enclave_basenames) not found.') except ValueError: raise \ ValueError( 'Failed to parse enclave basename: {}'.format( valid_basenames)) try: report_public_key.verify(base64.b64decode(signature.encode()), verification_report.encode(), padding.PKCS1v15(), hashes.SHA256()) except InvalidSignature: raise ValueError('Verification report signature is invalid') verification_report_dict = json.loads(verification_report) # Verify that the verification report contains an ID field if 'id' not in verification_report_dict: raise ValueError('Verification report does not contain an ID') # Verify that the verification report contains an EPID pseudonym and # that it matches the anti-Sybil ID epid_pseudonym = verification_report_dict.get('epidPseudonym') if epid_pseudonym is None: raise \ ValueError( 'Verification report does not contain an EPID pseudonym') if epid_pseudonym != signup_info.anti_sybil_id: raise \ ValueError( 'The anti-Sybil ID in the verification report [{0}] does ' 'not match the one contained in the signup information ' '[{1}]'.format( epid_pseudonym, signup_info.anti_sybil_id)) # Verify that the verification report contains a PSE manifest status # and it is OK pse_manifest_status = \ verification_report_dict.get('pseManifestStatus') if pse_manifest_status is None: raise \ ValueError( 'Verification report does not contain a PSE manifest ' 'status') if pse_manifest_status.upper() != 'OK': if pse_manifest_status.upper() == 'OUT_OF_DATE': LOGGER.warning( 'Peer has out of date (but not revoked)' ' hardware, pseManifestStatus: %s', pse_manifest_status) else: raise \ ValueError( 'PSE manifest status is {} (i.e., not OK)'.format( pse_manifest_status)) # Verify that the verification report contains a PSE manifest hash pse_manifest_hash = \ verification_report_dict.get('pseManifestHash') if pse_manifest_hash is None: raise \ ValueError( 'Verification report does not contain a PSE manifest ' 'hash') # Verify that the proof data contains evidence payload evidence_payload = proof_data_dict.get('evidence_payload') if evidence_payload is None: raise ValueError('Evidence payload is missing from proof data') # Verify that the evidence payload contains a PSE manifest and then # use it to make sure that the PSE manifest hash is what we expect pse_manifest = evidence_payload.get('pse_manifest') if pse_manifest is None: raise ValueError('Evidence payload does not include PSE manifest') expected_pse_manifest_hash = \ hashlib.sha256( base64.b64decode(pse_manifest.encode())).hexdigest() if pse_manifest_hash.upper() != expected_pse_manifest_hash.upper(): raise \ ValueError( 'PSE manifest hash {0} does not match {1}'.format( pse_manifest_hash, expected_pse_manifest_hash)) # Verify that the verification report contains an enclave quote and # that its status is OK enclave_quote_status = \ verification_report_dict.get('isvEnclaveQuoteStatus') if enclave_quote_status is None: raise \ ValueError( 'Verification report does not contain an enclave quote ' 'status') if enclave_quote_status.upper() != 'OK': if enclave_quote_status.upper() == 'GROUP_OUT_OF_DATE': LOGGER.warning( 'Peer has out of date (but not revoked)' ' hardware, isvEnclaveQuoteStatus: %s', str(enclave_quote_status)) else: raise \ ValueError( 'Enclave quote status is {} (i.e., not OK)'.format( enclave_quote_status)) # Verify that the verification report contains an enclave quote enclave_quote = verification_report_dict.get('isvEnclaveQuoteBody') if enclave_quote is None: raise \ ValueError( 'Verification report does not contain an enclave quote') # The ISV enclave quote body is base 64 encoded, so decode it and then # create an SGX quote structure from it so we can inspect sgx_quote = sgx_structs.SgxQuote() sgx_quote.parse_from_bytes(base64.b64decode(enclave_quote)) # The report body should be SHA256(SHA256(OPK)|PPK) # # NOTE - since the code that created the report data is in the enclave # code, this code needs to be kept in sync with it. Any changes to how # the report data is created, needs to be reflected in how we re-create # the report data for verification. hash_input = \ '{0}{1}'.format( originator_public_key_hash.upper(), signup_info.poet_public_key.upper()).encode() hash_value = hashlib.sha256(hash_input).digest() expected_report_data = \ hash_value + \ (b'\x00' * (sgx_structs.SgxReportData.STRUCT_SIZE - len(hash_value))) if sgx_quote.report_body.report_data.d != expected_report_data: raise \ ValueError( 'AVR report data [{0}] not equal to [{1}]'.format( sgx_quote.report_body.report_data.d.hex(), expected_report_data.hex())) # Verify that the enclave measurement is in the list of valid # enclave measurements. if sgx_quote.report_body.mr_enclave.m not in \ valid_enclave_mesaurements: raise \ ValueError( 'AVR enclave measurement [{}] not in list of valid ' 'enclave measurements [{}]'.format( sgx_quote.report_body.mr_enclave.m.hex(), valid_measurements)) # Verify that the enclave basename is in the list of valid # enclave basenames if sgx_quote.basename.name not in valid_enclave_basenames: raise \ ValueError( 'AVR enclave basename [{}] not in list of valid ' 'enclave basenames [{}]'.format( sgx_quote.basename.name.hex(), valid_basenames)) # Verify that the nonce in the verification report matches the nonce # in the transaction payload submitted nonce = verification_report_dict.get('nonce', '') if nonce != val_reg_payload.signup_info.nonce: raise \ ValueError( 'AVR nonce [{0}] does not match signup info nonce ' '[{1}]'.format( nonce, val_reg_payload.signup_info.nonce))
def test_invalid_enclave_body(self): """ Test that a transaction whose enclave_body is invalid returns an invalid transaction. """ signup_info = self.factory.create_signup_info( self.factory.pubkey_hash, "000") proof_data = signup_info.proof_data proof_data_dict = json.loads(proof_data) # ------------------------------------------------------ # No isvEnclaveQuoteStatus verification_report = \ json.loads(proof_data_dict["verification_report"]) enclave_status = verification_report["isvEnclaveQuoteStatus"] verification_report["isvEnclaveQuoteStatus"] = None signup_info.proof_data = \ self.factory.create_proof_data( verification_report=verification_report, evidence_payload=proof_data_dict.get('evidence_payload')) self._test_bad_signup_info(signup_info) # ------------------------------------------------------ # Bad isvEnclaveQuoteStatus verification_report = \ json.loads(proof_data_dict["verification_report"]) verification_report["isvEnclaveQuoteStatus"] = "Bad" signup_info.proof_data = \ self.factory.create_proof_data( verification_report=verification_report, evidence_payload=proof_data_dict.get('evidence_payload')) self._test_bad_signup_info(signup_info) # ------------------------------------------------------ # No isvEnclaveQuoteBody verification_report = \ json.loads(proof_data_dict["verification_report"]) verification_report["isvEnclaveQuoteStatus"] = enclave_status verification_report['isvEnclaveQuoteBody'] = None signup_info.proof_data = \ self.factory.create_proof_data( verification_report=verification_report, evidence_payload=proof_data_dict.get('evidence_payload')) self._test_bad_signup_info(signup_info) # ------------------------------------------------------ # Malformed isvEnclaveQuoteBody (decode the enclave quote, chop off # the last byte, and re-encode) verification_report = \ json.loads(proof_data_dict["verification_report"]) verification_report['isvEnclaveQuoteBody'] = \ base64.b64encode( base64.b64decode( verification_report['isvEnclaveQuoteBody'].encode())[1:])\ .decode() signup_info.proof_data = \ self.factory.create_proof_data( verification_report=verification_report, evidence_payload=proof_data_dict.get('evidence_payload')) self._test_bad_signup_info(signup_info) # ------------------------------------------------------ # Invalid basename verification_report = \ json.loads(proof_data_dict["verification_report"]) sgx_quote = sgx_structs.SgxQuote() sgx_quote.parse_from_bytes( base64.b64decode( verification_report['isvEnclaveQuoteBody'].encode())) sgx_quote.basename.name = \ b'\xCC' * sgx_structs.SgxBasename.STRUCT_SIZE verification_report['isvEnclaveQuoteBody'] = \ base64.b64encode(sgx_quote.serialize_to_bytes()).decode() signup_info.proof_data = \ self.factory.create_proof_data( verification_report=verification_report, evidence_payload=proof_data_dict.get('evidence_payload')) self._test_bad_signup_info(signup_info) # ------------------------------------------------------ # Report data is not valid (bad OPK hash) verification_report = \ json.loads(proof_data_dict["verification_report"]) sgx_quote = sgx_structs.SgxQuote() sgx_quote.parse_from_bytes( base64.b64decode( verification_report['isvEnclaveQuoteBody'].encode())) hash_input = \ '{0}{1}'.format( 'Not a valid OPK Hash', self.factory.poet_public_key).upper().encode() sgx_quote.report_body.report_data.d = \ hashlib.sha256(hash_input).digest() verification_report['isvEnclaveQuoteBody'] = \ base64.b64encode(sgx_quote.serialize_to_bytes()).decode() signup_info.proof_data = \ self.factory.create_proof_data( verification_report=verification_report, evidence_payload=proof_data_dict.get('evidence_payload')) self._test_bad_signup_info(signup_info) # ------------------------------------------------------ # Report data is not valid (bad PPK) verification_report = \ json.loads(proof_data_dict["verification_report"]) sgx_quote = sgx_structs.SgxQuote() sgx_quote.parse_from_bytes( base64.b64decode( verification_report['isvEnclaveQuoteBody'].encode())) hash_input = \ '{0}{1}'.format( self.factory.pubkey_hash, "Not a valid PPK").encode() sgx_quote.report_body.report_data.d = \ hashlib.sha256(hash_input).digest() verification_report['isvEnclaveQuoteBody'] = \ base64.b64encode(sgx_quote.serialize_to_bytes()).decode() signup_info.proof_data = \ self.factory.create_proof_data( verification_report=verification_report, evidence_payload=proof_data_dict.get('evidence_payload')) self._test_bad_signup_info(signup_info) # ------------------------------------------------------ # Invalid enclave measurement verification_report = \ json.loads(proof_data_dict["verification_report"]) sgx_quote = sgx_structs.SgxQuote() sgx_quote.parse_from_bytes( base64.b64decode( verification_report['isvEnclaveQuoteBody'].encode())) sgx_quote.report_body.mr_enclave.m = \ b'\xCC' * sgx_structs.SgxMeasurement.STRUCT_SIZE verification_report['isvEnclaveQuoteBody'] = \ base64.b64encode(sgx_quote.serialize_to_bytes()).decode() signup_info.proof_data = \ self.factory.create_proof_data( verification_report=verification_report, evidence_payload=proof_data_dict.get('evidence_payload')) self._test_bad_signup_info(signup_info)
def verify_signup_info(self, signup_info, originator_public_key_hash, most_recent_wait_certificate_id): # Verify the attestation verification report signature proof_data_dict = json.loads(signup_info.proof_data) verification_report = proof_data_dict.get('verification_report') if verification_report is None: raise ValueError('Verification report is missing from proof data') signature = proof_data_dict.get('signature') if signature is None: raise ValueError('Signature is missing from proof data') try: self._report_public_key.verify( base64.b64decode(signature.encode()), verification_report.encode(), padding.PKCS1v15(), hashes.SHA256()) except InvalidSignature: raise ValueError('Verification report signature is invalid') verification_report_dict = json.loads(verification_report) # Verify that the verification report contains an ID field if 'id' not in verification_report_dict: raise ValueError('Verification report does not contain an ID') # Verify that the verification report contains an EPID pseudonym and # that it matches the anti-Sybil ID epid_pseudonym = verification_report_dict.get('epidPseudonym') if epid_pseudonym is None: raise \ ValueError( 'Verification report does not contain an EPID pseudonym') if epid_pseudonym != signup_info.anti_sybil_id: raise \ ValueError( 'The anti-Sybil ID in the verification report [{0}] does ' 'not match the one contained in the signup information ' '[{1}]'.format( epid_pseudonym, signup_info.anti_sybil_id)) # Verify that the verification report contains a PSE manifest status # and it is OK pse_manifest_status = \ verification_report_dict.get('pseManifestStatus') if pse_manifest_status is None: raise \ ValueError( 'Verification report does not contain a PSE manifest ' 'status') if pse_manifest_status.upper() != 'OK': raise \ ValueError( 'PSE manifest status is {} (i.e., not OK)'.format( pse_manifest_status)) # Verify that the verification report contains a PSE manifest hash pse_manifest_hash = \ verification_report_dict.get('pseManifestHash') if pse_manifest_hash is None: raise \ ValueError( 'Verification report does not contain a PSE manifest ' 'hash') # Verify that the proof data contains evidence payload evidence_payload = proof_data_dict.get('evidence_payload') if evidence_payload is None: raise ValueError('Evidence payload is missing from proof data') # Verify that the evidence payload contains a PSE manifest and then # use it to make sure that the PSE manifest hash is what we expect pse_manifest = evidence_payload.get('pse_manifest') if pse_manifest is None: raise ValueError('Evidence payload does not include PSE manifest') expected_pse_manifest_hash = \ base64.b64encode( hashlib.sha256( pse_manifest.encode()).hexdigest().encode()).decode() if pse_manifest_hash.upper() != expected_pse_manifest_hash.upper(): raise \ ValueError( 'PSE manifest hash {0} does not match {1}'.format( pse_manifest_hash, expected_pse_manifest_hash)) # Verify that the verification report contains an enclave quote and # that its status is OK enclave_quote_status = \ verification_report_dict.get('isvEnclaveQuoteStatus') if enclave_quote_status is None: raise \ ValueError( 'Verification report does not contain an enclave quote ' 'status') if enclave_quote_status.upper() != 'OK': raise \ ValueError( 'Enclave quote status is {} (i.e., not OK)'.format( enclave_quote_status)) # Verify that the verification report contains an enclave quote enclave_quote = verification_report_dict.get('isvEnclaveQuoteBody') if enclave_quote is None: raise \ ValueError( 'Verification report does not contain an enclave quote') # The ISV enclave quote body is base 64 encoded, so decode it and then # create an SGX quote structure from it so we can inspect sgx_quote = sgx_structs.SgxQuote() sgx_quote.parse_from_bytes(base64.b64decode(enclave_quote)) # The report body should be SHA256(SHA256(OPK)|PPK) # # NOTE - since the code that created the report data is in the enclave # code, this code needs to be kept in sync with it. Any changes to how # the report data is created, needs to be reflected in how we re-create # the report data for verification. hash_input = \ '{0}{1}'.format( originator_public_key_hash.upper(), signup_info.poet_public_key.upper().upper()).encode() hash_value = hashlib.sha256(hash_input).digest() expected_report_data = \ hash_value + \ (b'\x00' * (sgx_structs.SgxReportData.STRUCT_SIZE - len(hash_value))) if sgx_quote.report_body.report_data.d != expected_report_data: raise \ ValueError( 'AVR report data [{0}] not equal to [{1}]'.format( sgx_quote.report_body.report_data.d.hex(), expected_report_data.hex())) # Compare the enclave measurement against the expected valid enclave # measurement. # # NOTE - this is only a temporary check. Instead of checking against # a predefined enclave measurement value, we should be configured with # a set of one or more enclave measurement values that we will # consider as valid. if sgx_quote.report_body.mr_enclave.m != \ self.__VALID_ENCLAVE_MEASUREMENT__: raise \ ValueError( 'AVR enclave measurement [{0}] not equal to [{1}]'.format( sgx_quote.report_body.mr_enclave.m.hex(), self.__VALID_ENCLAVE_MEASUREMENT__.hex())) # Compare the enclave basename in the verification report against the # expected enclave basename. # # NOTE - this is only a temporary check. Instead of checking against # a predefined enclave basenme value, we should be configured with a # set of one or more enclave basenames that we will consider as valid. if sgx_quote.basename.name != self.__VALID_BASENAME__: raise \ ValueError( 'AVR enclave basename [{0}] not equal to [{1}]'.format( sgx_quote.basename.name.hex(), self.__VALID_BASENAME__.hex())) # Verify that the wait certificate ID in the verification report # matches the provided wait certificate ID. The wait certificate ID # is stored in the nonce field. nonce = verification_report_dict.get('nonce') if nonce is None: raise \ ValueError( 'Verification report does not have a nonce')
def create_signup_info(cls, originator_public_key_hash, most_recent_wait_certificate_id): with cls._lock: # First we need to create a public/private key pair for the PoET # enclave to use. cls._poet_private_key = signing.generate_privkey() cls._poet_public_key = \ signing.generate_pubkey(cls._poet_private_key) cls._active_wait_timer = None # We are going to fake out sealing the signup data. Note that # the signing module uses strings for both private (WIF encoded) # and public (hex encoded) key canonical formats. Therefore, we # don't have to encode before putting in the signup data. This # also means that on the flip side (unsealing signup data and # verifying signatures using public keys), we don't have to decode # before using. signup_data = { 'poet_public_key': cls._poet_public_key, 'poet_private_key': cls._poet_private_key } sealed_signup_data = \ base64.b64encode(bytes(dict2json(signup_data).encode())) # 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(), cls._poet_public_key.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': 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': 'OK', 'pseManifestHash': base64.b64encode( hashlib.sha256( pse_manifest).hexdigest().encode()).decode(), 'nonce': most_recent_wait_certificate_id, '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=originator_public_key_hash, sealed_signup_data=sealed_signup_data)
def do_sgx_quote(): sgx_quote = sgx_structs.SgxQuote() # 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 = create_random_buffer(4) qe_svn = 0x0506 pce_svn = 0x0708 extended_epid_group_id = 0x090a0b0c basename = \ create_random_buffer( sgx_structs.SgxBasename.STRUCT_SIZE) svn = \ create_random_buffer( sgx_structs.SgxCpuSvn.STRUCT_SIZE) misc_select = 0x0d0e0f10 reserved1 = b'\x00' * 28 flags = 0x1112131415161718 xfrm = 0x191a1b1c1d1e1f20 mr_enclave = \ create_random_buffer( sgx_structs.SgxMeasurement.STRUCT_SIZE) reserved2 = b'\x00' * 32 mr_signer = \ 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 = \ 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) # Add a few bytes so that the signature length is partial. Should # fail. bad_quote = quote[:] for _ in range(3): bad_quote += create_random_buffer(1) with pytest.raises(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 pytest.raises(ValueError): sgx_quote.parse_from_bytes(bad_quote) # Add a signature that is too short short_signature = create_random_buffer(31) bad_quote = \ struct.pack( '<{}sL{}s'.format( len(quote), len(short_signature)), quote, len(short_signature) + 1, short_signature) with pytest.raises(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) # Add a good signature and verify signature = 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) # 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) assert 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) assert 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 assert non_zero_sign_quote == sgx_quote.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, 'poet_private_key': self._poet_private_key } # 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.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)