def unseal_signup_data(cls, sealed_signup_data): """ Args: sealed_signup_data: Sealed signup data that was returned previously in a EnclaveSignupInfo object from a call to create_signup_info Returns: A string The hex encoded PoET public key that was extracted from the sealed data """ # Reverse the process we used in creating "sealed" signup info. # Specifically, we will do a base 64 decode, which gives us JSON # we can convert back to a dictionary we can use to get the # data we need signup_data = \ json2dict(base64.b64decode(sealed_signup_data).decode()) # Since the signing module uses strings for both private (WIF encoded) # and public (hex encoded) key canonical formats, we don't have to # decode. with cls._lock: cls._poet_public_key = str(signup_data.get('poet_public_key')) cls._poet_private_key = str(signup_data.get('poet_private_key')) cls._active_wait_timer = None return signup_data.get('poet_public_key')
def wait_certificate_from_serialized(cls, serialized_certificate, signature): """ Takes wait certificate that has been serialized to JSON and reconstitutes into an EnclaveWaitCertificate object. Args: serialized_certificate (str): JSON serialized wait certificate signature (str): Signature over serialized certificate Returns: An EnclaveWaitCertificate object """ deserialized_certificate = json2dict(serialized_certificate) certificate = \ EnclaveWaitCertificate( duration=float(deserialized_certificate.get('duration')), previous_certificate_id=str( deserialized_certificate.get('previous_certificate_id')), local_mean=float(deserialized_certificate.get('local_mean')), request_time=float( deserialized_certificate.get('request_time')), validator_address=str( deserialized_certificate.get('validator_address')), nonce=str(deserialized_certificate.get('nonce')), block_hash=str(deserialized_certificate.get( 'block_hash')), signature=signature, serialized_certificate=serialized_certificate) return certificate
def unseal_signup_data(cls, sealed_signup_data): """ Args: sealed_signup_data: Sealed signup data that was returned previously in a EnclaveSignupInfo object from a call to create_signup_info Returns: A string The hex encoded PoET public key that was extracted from the sealed data """ # Reverse the process we used in creating "sealed" signup info. # Specifically, we will do a base 32 decode, which gives us json # we can convert back to a dictionary we can use to get the # data we need signup_data = \ json2dict(base64.b64decode(sealed_signup_data).decode()) with cls._lock: cls._poet_public_key = \ signing.decode_pubkey( signup_data.get('poet_public_key'), 'hex') cls._poet_private_key = \ signing.decode_privkey( signup_data.get('poet_private_key'), 'hex') cls._active_wait_timer = None return signup_data.get('poet_public_key')
def wait_timer_from_serialized(cls, serialized_timer, signature): """ Takes wait timer that has been serialized to JSON and reconstitutes into an EnclaveWaitTimer object. Args: serialized_timer (str): JSON serialized wait timer signature (str): Signature over serialized timer Returns: An EnclaveWaitTimer object """ deserialized_timer = json2dict(serialized_timer) timer = \ EnclaveWaitTimer( validator_address=str(deserialized_timer.get( 'validator_address')), duration=float(deserialized_timer.get( 'duration')), previous_certificate_id=str(deserialized_timer.get( 'previous_certificate_id')), local_mean=float(deserialized_timer.get( 'local_mean')), signature=signature, serialized_timer=serialized_timer) timer.request_time = float(deserialized_timer.get('request_time')) return timer
def signup_info_from_serialized(cls, serialized_signup_info): """ Takes signup information that has been serialized to JSON and reconstitutes into an EnclaveSignupInfo object. Args: serialized_signup_info: JSON serialized signup info Returns: An EnclaveSignupInfo object with sealed signup info data stripped out as serialized signup info doesn't contain it. """ deserialized_signup_info = json2dict(serialized_signup_info) # Note - serialized signup info shouldn't have sealed signup # data. signup_info = \ EnclaveSignupInfo( poet_public_key=deserialized_signup_info.get( 'poet_public_key'), proof_data=deserialized_signup_info.get( 'proof_data'), anti_sybil_id=deserialized_signup_info.get( 'anti_sybil_id'), serialized_signup_info=serialized_signup_info) return signup_info
def verify_signup_info(cls, signup_info, originator_public_key_hash, most_recent_wait_certificate_id): # Verify the attestation verification report signature proof_data_dict = json2dict(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') if not signing.verify( verification_report, signature, cls._report_public_key): raise ValueError('Verification report signature is invalid') verification_report_dict = json2dict(verification_report) # 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 != '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 # and it is the value we expect 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') expected_pse_manifest_hash = \ base64.b64encode( hashlib.sha256( bytes(b'Do you believe in ' b'manifest destiny?')).hexdigest() .encode()).decode() if pse_manifest_hash != expected_pse_manifest_hash: 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 != 'OK': raise \ ValueError( 'Enclave quote status is {} (i.e., not OK)'.format( enclave_quote_status)) enclave_quote = verification_report_dict.get('isvEnclaveQuoteBody') if enclave_quote is None: raise \ ValueError( 'Verification report does not contain an enclave quote') # Verify that the enclave quote contains a report body with the value # we expect (i.e., SHA256(SHA256(OPK)|PPK) report_data = '{0}{1}'.format( originator_public_key_hash.upper(), signup_info.poet_public_key.upper() ) expected_report_body = hashlib.sha256( dict2json(report_data).encode()).hexdigest() enclave_quote_dict = \ json2dict(base64.b64decode(enclave_quote).decode()) report_body = enclave_quote_dict.get('report_body') if report_body is None: raise ValueError('Enclave quote does not contain a report body') if report_body != expected_report_body: raise \ ValueError( 'Enclave quote report body {0} does not match {1}'.format( report_body, expected_report_body)) # 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 verify_signup_info(cls, signup_info, originator_public_key_hash, most_recent_wait_certificate_id): # Verify the attestation verification report signature proof_data_dict = json2dict(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: cls._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 = json2dict(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 status # and the 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') # Verify that the enclave quote contains a report body with the value # we expect (i.e., SHA256(SHA256(OPK)|PPK) report_data = '{0}{1}'.format(originator_public_key_hash.upper(), signup_info.poet_public_key.upper()) expected_report_body = hashlib.sha256( dict2json(report_data).encode()).hexdigest() enclave_quote_dict = \ json2dict(base64.b64decode(enclave_quote).decode()) report_body = enclave_quote_dict.get('report_body') if report_body is None: raise ValueError('Enclave quote does not contain a report body') if report_body.upper() != expected_report_body.upper(): raise \ ValueError( 'Enclave quote report body {0} does not match {1}'.format( report_body, expected_report_body)) # 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')