def serialize(self): """ Serializes to JSON that can later be reconstituted to an EnclaveWaitTimer object Returns: A JSON string representing the serialized version of the object """ if self._serialized is None: timer_dict = { 'request_time': self.request_time, 'validator_address': self.validator_address, 'duration': self.duration, 'previous_certificate_id': self.previous_certificate_id, 'local_mean': self.local_mean } self._serialized = dict2json(timer_dict) return self._serialized
def serialize(self): """ Serializes to JSON that can later be reconstituted to an EnclaveSignupInfo object Returns: A JSON string representing the serialized version of the object. Note that the sealed signup data is not encluded in the serialized data. """ if self._serialized is None: # Note - we are not serializing the sealed signup data. Sealed # signup data is meant to be used locally on the system and not # serialized and sent to anyone else. signup_info_dict = { 'bgt_public_key': self.bgt_public_key, 'proof_data': self.proof_data, 'anti_sybil_id': self.anti_sybil_id } self._serialized = dict2json(signup_info_dict) return self._serialized
def create_wait_certificate(cls, sealed_signup_data, wait_timer, block_hash): with cls._lock: # Extract keys from the 'sealed' signup data if sealed_signup_data is None: raise ValueError('Sealed Signup Data is None') signup_data = \ json2dict( base64.b64decode(sealed_signup_data.encode()).decode()) bgt_private_key = signup_data['bgt_private_key'] bgt_public_key = signup_data['bgt_public_key'] if bgt_private_key is None or bgt_public_key is None: raise \ ValueError( 'Invalid signup data. No bgt key(s).') try: bgt_public_key = Secp256k1PublicKey.from_hex(bgt_public_key) bgt_private_key = Secp256k1PrivateKey.from_hex(bgt_private_key) except ParseError: raise \ ValueError( 'Invalid signup data. Badly formatted bgt key(s).') # Several criteria need to be met before we can create a wait # certificate: # 1. This signup data was used to sign this timer. # i.e. the key sealed / unsealed by the TEE signed this # wait timer. # 2. This timer has expired # 3. This timer has not timed out # # In a TEE implementation we would check HW counter agreement. # We can't usefully simulate a HW counter though. # i.e. wait_timer.counter_value == signup_data.counter.value # # Note - we make a concession for the genesis block (i.e., a wait # timer for which the previous certificate ID is the Null # identifier) in that we don't require the timer to have expired # and we don't worry about the timer having timed out. if wait_timer is None or \ not cls._context.verify( wait_timer.signature, wait_timer.serialize().encode(), bgt_public_key): raise \ ValueError( 'Validator is not using the current wait timer') is_not_genesis_block = \ (wait_timer.previous_certificate_id != NULL_BLOCK_IDENTIFIER) now = time.time() expire_time = \ wait_timer.request_time + \ wait_timer.duration if is_not_genesis_block and now < expire_time: raise \ ValueError( 'Cannot create wait certificate because timer has ' 'not expired') time_out_time = \ wait_timer.request_time + \ wait_timer.duration + \ TIMER_TIMEOUT_PERIOD if is_not_genesis_block and time_out_time < now: raise \ ValueError( 'Cannot create wait certificate because timer ' 'has timed out') # Create a random nonce for the certificate. For our "random" # nonce we will take the timer signature, concat that with the # current time, JSON-ize it and create a SHA-256 hash over it. # Probably not considered random by security professional # standards, but it is good enough for the simulator. random_string = \ dict2json({ 'wait_timer_signature': wait_timer.signature, 'now': datetime.datetime.utcnow().isoformat() }) nonce = hashlib.sha256(random_string.encode()).hexdigest() # First create a new enclave wait certificate using the data # provided and then sign the certificate with the BGT private key wait_certificate = \ EnclaveWaitCertificate.wait_certificate_with_wait_timer( wait_timer=wait_timer, nonce=nonce, block_hash=block_hash) wait_certificate.signature = \ cls._context.sign( wait_certificate.serialize().encode(), bgt_private_key) # In a TEE implementation we would increment the HW counter here # to prevent replay. # We can't usefully simulate a HW counter though. return wait_certificate
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 BGT # enclave to use. # Counter ID is a placeholder for a hardware counter in a TEE. bgt_private_key = Secp256k1PrivateKey.new_random() bgt_public_key = cls._context.get_public_key(bgt_private_key) counter_id = None # Simulate sealing (encrypting) the signup data. signup_data = { 'bgt_private_key': bgt_private_key.as_hex(), 'bgt_public_key': bgt_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(), bgt_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) """ sgx_quote = b'fake quote' # 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).decode( ), # 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( bgt_public_key=signup_data['bgt_public_key'], proof_data=proof_data, anti_sybil_id=cls._anti_sybil_id, sealed_signup_data=sealed_signup_data)