def _generate_batch(self, payload): payload_encoded = payload.encode('utf-8') hasher = hashlib.sha512() hasher.update(payload_encoded) header = TransactionHeader() header.batcher_pubkey = self.public_key # txn.dependencies not yet header.family_name = 'test' header.family_version = '1' header.nonce = _generate_id(16) header.payload_encoding = "text" header.payload_sha512 = hasher.hexdigest().encode() header.signer_pubkey = self.public_key txn = Transaction() header_bytes = header.SerializeToString() txn.header = header_bytes txn.header_signature = signing.sign(header_bytes, self.signing_key) txn.payload = payload_encoded batch_header = BatchHeader() batch_header.signer_pubkey = self.public_key batch_header.transaction_ids.extend([txn.header_signature]) batch = Batch() header_bytes = batch_header.SerializeToString() batch.header = header_bytes batch.header_signature = signing.sign(header_bytes, self.signing_key) batch.transactions.extend([txn]) return batch
def _create_config_txn(pubkey, signing_key, setting_key_value): """Creates an individual sawtooth_config transaction for the given key and value. """ setting_key = setting_key_value[0] setting_value = setting_key_value[1] nonce = str(datetime.datetime.utcnow().timestamp()) proposal = ConfigProposal(setting=setting_key, value=setting_value, nonce=nonce) payload = ConfigPayload(data=proposal.SerializeToString(), action=ConfigPayload.PROPOSE).SerializeToString() header = TransactionHeader( signer_pubkey=pubkey, family_name='sawtooth_config', family_version='1.0', inputs=_config_inputs(setting_key), outputs=_config_outputs(setting_key), dependencies=[], payload_encoding='application/protobuf', payload_sha512=hashlib.sha512(payload).hexdigest(), batcher_pubkey=pubkey).SerializeToString() signature = signing.sign(header, signing_key) return Transaction(header=header, header_signature=signature, payload=payload)
def _do_config_set(args): """Executes the 'set' subcommand. Given a key file, and a series of key/value pairs, it generates batches of sawtooth_config transactions in a BatchList instance, and stores it in a file. """ settings = [s.split('=', 1) for s in args.setting] with open(args.key, 'r') as key_file: wif_key = key_file.read().strip() signing_key = signing.encode_privkey( signing.decode_privkey(wif_key, 'wif'), 'hex') pubkey = signing.encode_pubkey(signing.generate_pubkey(signing_key), 'hex') txns = [ _create_config_txn(pubkey, signing_key, setting) for setting in settings ] txn_ids = [txn.header_signature for txn in txns] batch_header = BatchHeader(signer_pubkey=pubkey, transaction_ids=txn_ids).SerializeToString() batch = Batch(header=batch_header, header_signature=signing.sign(batch_header, signing_key), transactions=txns) batch_list = BatchList(batches=[batch]).SerializeToString() try: with open(args.output, 'wb') as batch_file: batch_file.write(batch_list) except: raise CliException('Unable to write to {}'.format(args.output))
def _create_batches(self, batch_count, txn_count, valid_batch=True, valid_txn=True, valid_batcher=True): batch_list = [] for i in range(batch_count): txn_list = self._create_transactions(txn_count, valid_txn, valid_batcher) txn_sig_list = [txn.header_signature for txn in txn_list] batch_header = BatchHeader(signer_pubkey=self.public_key) batch_header.transaction_ids.extend(txn_sig_list) header_bytes = batch_header.SerializeToString() if valid_batch: signature = signing.sign( header_bytes, self.private_key) else: signature = "bad_signature" batch = Batch(header=header_bytes, transactions=txn_list, header_signature=signature) batch_list.append(batch) return batch_list
def test_deserialized_wait_timer(self): wait_timer = \ EnclaveWaitTimer( validator_address='1600 Pennsylvania Avenue NW', duration=3.14159, previous_certificate_id='Bond. James Bond.', local_mean=2.71828) serialized = wait_timer.serialize() signing_key = self._create_random_key() wait_timer.signature = \ signing.sign(serialized, signing_key) copy_wait_timer = \ EnclaveWaitTimer.wait_timer_from_serialized( serialized, wait_timer.signature) self.assertEqual(wait_timer.validator_address, copy_wait_timer.validator_address) self.assertAlmostEqual(wait_timer.request_time, copy_wait_timer.request_time) self.assertAlmostEqual(wait_timer.duration, copy_wait_timer.duration) self.assertEqual(wait_timer.previous_certificate_id, copy_wait_timer.previous_certificate_id) self.assertAlmostEqual(wait_timer.local_mean, copy_wait_timer.local_mean) self.assertEqual(wait_timer.signature, copy_wait_timer.signature) self.assertEqual(serialized, copy_wait_timer.serialize())
def _create_blocks(self, block_count, batch_count, valid_block=True, valid_batch=True): block_list = [] for i in range(block_count): batch_list = self._create_batches( batch_count, 2, valid_batch=valid_batch) batch_ids = [batch.header_signature for batch in batch_list] block_header = BlockHeader(signer_pubkey=self.public_key, batch_ids=batch_ids) header_bytes = block_header.SerializeToString() if valid_block: signature = signing.sign( header_bytes, self.private_key) else: signature = "bad_signature" block = Block(header=header_bytes, batches=batch_list, header_signature=signature) block_list.append(block) return block_list
def _create_blocks(self, block_count, batch_count, valid_block=True, valid_batch=True): block_list = [] for i in range(block_count): batch_list = self._create_batches(batch_count, 2, valid_batch=valid_batch) batch_ids = [batch.header_signature for batch in batch_list] block_header = BlockHeader(signer_pubkey=self.public_key, batch_ids=batch_ids) header_bytes = block_header.SerializeToString() if valid_block: signature = signing.sign(header_bytes, self.private_key) else: signature = "bad_signature" block = Block(header=header_bytes, batches=batch_list, header_signature=signature) block_list.append(block) return block_list
def _create_config_txn(pubkey, signing_key, setting_key_value): """Creates an individual sawtooth_config transaction for the given key and value. """ setting_key = setting_key_value[0] setting_value = setting_key_value[1] nonce = str(datetime.datetime.utcnow().timestamp()) proposal = ConfigProposal( setting=setting_key, value=setting_value, nonce=nonce) payload = ConfigPayload(data=proposal.SerializeToString(), action=ConfigPayload.PROPOSE).SerializeToString() header = TransactionHeader( signer_pubkey=pubkey, family_name='sawtooth_config', family_version='1.0', inputs=_config_inputs(setting_key), outputs=_config_outputs(setting_key), dependencies=[], payload_encoding='application/protobuf', payload_sha512=hashlib.sha512(payload).hexdigest(), batcher_pubkey=pubkey ).SerializeToString() signature = signing.sign(header, signing_key) return Transaction( header=header, header_signature=signature, payload=payload)
def _do_config_set(args): """Executes the 'set' subcommand. Given a key file, and a series of key/value pairs, it generates batches of sawtooth_config transactions in a BatchList instance, and stores it in a file. """ settings = [s.split('=', 1) for s in args.setting] with open(args.key, 'r') as key_file: wif_key = key_file.read().strip() signing_key = signing.encode_privkey( signing.decode_privkey(wif_key, 'wif'), 'hex') pubkey = signing.encode_pubkey( signing.generate_pubkey(signing_key), 'hex') txns = [_create_config_txn(pubkey, signing_key, setting) for setting in settings] txn_ids = [txn.header_signature for txn in txns] batch_header = BatchHeader(signer_pubkey=pubkey, transaction_ids=txn_ids).SerializeToString() batch = Batch( header=batch_header, header_signature=signing.sign(batch_header, signing_key), transactions=txns ) batch_list = BatchList(batches=[batch]).SerializeToString() try: with open(args.output, 'wb') as batch_file: batch_file.write(batch_list) except: raise CliException('Unable to write to {}'.format(args.output))
def _create_batches(self, batch_count, txn_count, valid_batch=True, valid_txn=True, valid_batcher=True): batch_list = [] for i in range(batch_count): txn_list = self._create_transactions(txn_count, valid_txn, valid_batcher) txn_sig_list = [txn.header_signature for txn in txn_list] batch_header = BatchHeader(signer_pubkey=self.public_key) batch_header.transaction_ids.extend(txn_sig_list) header_bytes = batch_header.SerializeToString() if valid_batch: signature = signing.sign(header_bytes, self.private_key) else: signature = "bad_signature" batch = Batch(header=header_bytes, transactions=txn_list, header_signature=signature) batch_list.append(batch) return batch_list
def _send_xo_txn(self, name, action, space=""): # Serialization is just a delimited utf-8 encoded string payload = ",".join([name, action, str(space)]).encode() # Construct the address address = self._get_address(name) header = TransactionHeader( signer_pubkey=self._public_key, family_name="xo", family_version="1.0", inputs=[address], outputs=[address], dependencies=[], payload_encoding="csv-utf8", payload_sha512=_sha512(payload), batcher_pubkey=self._public_key).SerializeToString() signature = signing.sign(header, self._private_key) transaction = Transaction(header=header, payload=payload, header_signature=signature) batch_list = self._create_batch_list([transaction]) result = self._send_request("batches", batch_list.SerializeToString(), 'application/octet-stream') return result
def create_wait_timer(cls, validator_address, previous_certificate_id, local_mean, minimum_wait_time): with cls._lock: # If we don't have a PoET private key, then the enclave has not # been properly initialized (either by calling create_signup_info # or unseal_signup_data) if cls._poet_private_key is None: raise \ ValueError( 'Enclave must be initialized before attempting to ' 'create a wait timer') # Create some value from the cert ID. We are just going to use # the seal key to sign the cert ID. We will then use the # low-order 64 bits to change that to a number [0, 1] tag = \ base64.b64decode( signing.sign( previous_certificate_id, cls._seal_private_key)) tagd = float(struct.unpack('Q', tag[-8:])[0]) / (2**64 - 1) # Now compute the duration with a minimum wait time guaranteed duration = minimum_wait_time - local_mean * math.log(tagd) # Create and sign the wait timer wait_timer = \ EnclaveWaitTimer( validator_address=validator_address, duration=duration, previous_certificate_id=previous_certificate_id, local_mean=local_mean) wait_timer.signature = \ signing.sign( wait_timer.serialize(), cls._poet_private_key) # Keep track of the active wait timer cls._active_wait_timer = wait_timer return wait_timer
def _generate_genesis_block(self): genesis_header = BlockHeader(previous_block_id=NULL_BLOCK_IDENTIFIER, signer_pubkey=self.public_key, block_num=0) block = BlockBuilder(genesis_header) block.add_batches([self._generate_batch("Genesis")]) header_bytes = block.block_header.SerializeToString() signature = signing.sign(header_bytes, self.signing_key) block.set_signature(signature) return BlockWrapper(block.build_block())
def _create_batch_list(self, transactions): transaction_signatures = [t.header_signature for t in transactions] header = BatchHeader( signer_pubkey=self._public_key, transaction_ids=transaction_signatures).SerializeToString() signature = signing.sign(header, self._private_key) batch = Batch(header=header, transactions=transactions, header_signature=signature) return BatchList(batches=[batch])
def test_deserialized_wait_certificate(self): wait_timer = \ EnclaveWaitTimer( validator_address='1600 Pennsylvania Avenue NW', duration=3.14159, previous_certificate_id='Smart, Maxwell Smart', local_mean=2.71828) wait_certificate = \ EnclaveWaitCertificate.wait_certificate_with_wait_timer( wait_timer=wait_timer, nonce='Eeny, meeny, miny, moe.', block_digest='Indigestion. Pepto Bismol.') serialized = wait_certificate.serialize() signing_key = self._create_random_key() wait_certificate.signature = \ signing.sign(serialized, signing_key) copy_wait_certificate = \ EnclaveWaitCertificate.wait_certificate_from_serialized( serialized, wait_certificate.signature) self.assertAlmostEqual( wait_certificate.request_time, copy_wait_certificate.request_time) self.assertAlmostEqual( wait_certificate.duration, copy_wait_certificate.duration) self.assertEqual( wait_certificate.previous_certificate_id, copy_wait_certificate.previous_certificate_id) self.assertAlmostEqual( wait_certificate.local_mean, copy_wait_certificate.local_mean) self.assertEqual( wait_certificate.validator_address, copy_wait_certificate.validator_address) self.assertEqual( wait_certificate.nonce, copy_wait_certificate.nonce) self.assertEqual( wait_certificate.block_digest, copy_wait_certificate.block_digest) self.assertEqual( wait_certificate.signature, copy_wait_certificate.signature) self.assertEqual(serialized, copy_wait_certificate.serialize())
def _sign_message_with_transaction(transaction, message_type, key): """ Signs a transaction message or transaction :param transaction (dict): :param key (str): A signing key returns message, txnid (tuple): The first 16 characters of a sha256 hexdigest. """ transaction['Nonce'] = time.time() pub = signing.encode_pubkey(signing.generate_pubkey(key), "hex") transaction["PublicKey"] = pub sig = signing.sign(_dict2cbor(transaction), key) transaction['Signature'] = sig txnid = hashlib.sha256(transaction['Signature'].encode()).hexdigest()[:16] message = { 'Transaction': transaction, '__TYPE__': message_type, '__NONCE__': time.time(), } cbor_serialized_message = _dict2cbor(message) signature = signing.sign(cbor_serialized_message, key) message['__SIGNATURE__'] = signature return message, txnid
def sign_object(self, signingkey): """Generates a string signature for the object using the signing key. Args: signingkey (str): hex encoded private key """ self._originator_id = None serialized = self.serialize(signable=True) self.Signature = signing.sign(bytes(serialized), signingkey) self._recover_verifying_address() self._identifier = hashlib.sha256( self.Signature.encode()).hexdigest()
def _sign_message_with_transaction(transaction, message_type, key): """ Signs a transaction message or transaction :param transaction (dict): :param key (str): A signing key returns message, txnid (tuple): The first 16 characters of a sha256 hexdigest. """ transaction['Nonce'] = time.time() pub = signing.encode_pubkey(signing.generate_pubkey(key), "hex") transaction["PublicKey"] = pub sig = signing.sign(_dict2cbor(transaction), key) transaction['Signature'] = sig txnid = hashlib.sha256(transaction['Signature'].encode()).hexdigest()[:16] message = { 'Transaction': transaction, '__TYPE__': message_type, '__NONCE__': time.time(), } cbor_serialized_message = _dict2cbor(message) signature = signing.sign(cbor_serialized_message, key) message['__SIGNATURE__'] = signature return message, txnid
def _sign_block(self, block): """ The block should be complete and the final signature from the publishing validator (this validator) needs to be added. """ public_key = signing.encode_pubkey( signing.generate_pubkey(self._identity_priv_key), "hex") block.block_header.signer_pubkey = public_key block_header = block.block_header header_bytes = block_header.SerializeToString() signature = signing.sign( header_bytes, self._identity_priv_key) block.set_signature(signature) return block
def test_invalid_verfication_report(self): """ Test that a transaction whose verication report is invalid returns an invalid transaction. """ signup_info = self.factory.create_signup_info(self.factory.pubkey_hash, "000") # Verifcation Report is None proof_data = signup_info.proof_data signup_info.proof_data = json.dumps({}) self._test_bad_signup_info(signup_info) # ------------------------------------------------------ # No verification signature proof_data_dict = json.loads(proof_data) del proof_data_dict["signature"] signup_info.proof_data = json.dumps(proof_data_dict) self._test_bad_signup_info(signup_info) # ------------------------------------------------------ # Bad verification signature proof_data_dict["signature"] = "bads" signup_info.proof_data = json.dumps(proof_data_dict) self._test_bad_signup_info(signup_info) # ------------------------------------------------------ # No Nonce verification_report = \ json.loads(proof_data_dict["verification_report"]) verification_report["nonce"] = None proof_data_dict = { 'verification_report': json.dumps(verification_report), 'signature': signing.sign(json.dumps(verification_report), self._report_private_key) } signup_info.proof_data = json.dumps(proof_data_dict) self._test_bad_signup_info(signup_info)
def _create_transactions(self, count, valid=True, valid_batcher=True): txn_list = [] for i in range(count): payload = {'Verb': 'set', 'Name': 'name' + str(random.randint(0, 100)), 'Value': random.randint(0, 100)} intkey_prefix = \ hashlib.sha512('intkey'.encode('utf-8')).hexdigest()[0:6] addr = intkey_prefix + \ hashlib.sha512(payload["Name"].encode('utf-8')).hexdigest() payload_encode = hashlib.sha512(cbor.dumps(payload)).hexdigest() header = TransactionHeader( signer_pubkey=self.public_key, family_name='intkey', family_version='1.0', inputs=[addr], outputs=[addr], dependencies=[], payload_encoding="application/cbor", payload_sha512=payload_encode) if valid_batcher: header.batcher_pubkey = self.public_key else: header.batcher_pubkey = "bad_batcher" header_bytes = header.SerializeToString() if valid: signature = signing.sign( header_bytes, self.private_key) else: signature = "bad_signature" transaction = Transaction( header=header_bytes, payload=cbor.dumps(payload), header_signature=signature) txn_list.append(transaction) return txn_list
def _sign_block(block): """ The block should be complete and the final signature from the publishing validator (this validator) needs to be added. """ temp_key = signing.generate_privkey() public_key = signing.encode_pubkey( signing.generate_pubkey(temp_key), "hex") block.block_header.signer_pubkey = public_key block_header = block.block_header header_bytes = block_header.SerializeToString() signature = signing.sign( header_bytes, temp_key) block.set_signature(signature) return block
def _create_transactions(self, count, valid=True, valid_batcher=True): txn_list = [] for i in range(count): payload = { 'Verb': 'set', 'Name': 'name' + str(random.randint(0, 100)), 'Value': random.randint(0, 100) } intkey_prefix = \ hashlib.sha512('intkey'.encode('utf-8')).hexdigest()[0:6] addr = intkey_prefix + \ hashlib.sha512(payload["Name"].encode('utf-8')).hexdigest() payload_encode = hashlib.sha512(cbor.dumps(payload)).hexdigest() header = TransactionHeader(signer_pubkey=self.public_key, family_name='intkey', family_version='1.0', inputs=[addr], outputs=[addr], dependencies=[], payload_encoding="application/cbor", payload_sha512=payload_encode) if valid_batcher: header.batcher_pubkey = self.public_key else: header.batcher_pubkey = "bad_batcher" header_bytes = header.SerializeToString() if valid: signature = signing.sign(header_bytes, self.private_key) else: signature = "bad_signature" transaction = Transaction(header=header_bytes, payload=cbor.dumps(payload), header_signature=signature) txn_list.append(transaction) return txn_list
def test_is_valid_pub_key(self): pubkey = signing.generate_pubkey("5KQ4iQQGgbQX9MmfiPUwwHBL1R" "GPa86NwFbqrWoodjuzruqFVDd") pub = signing.encode_pubkey(pubkey, "hex") minfo = {'Nonce': 100, 'PublicKey': pub, 'TransactionType': '/Transaction', 'Dependencies': []} sig = signing.sign( signed_object.dict2cbor(minfo), "5KQ4iQQGgbQX9MmfiPUwwHBL1RGPa86NwFbqrWoodjuzruqFVDd" ) # Create valid transaction minfo["Signature"] = sig temp = Transaction(minfo) self.assertTrue(temp.is_valid("unused")) # Change transaction after it was signed minfo["Nonce"] = time.time() temp = Transaction(minfo) self.assertFalse(temp.is_valid("unused"))
def test_deserialized_wait_certificate(self): wait_timer = \ EnclaveWaitTimer( validator_address='1600 Pennsylvania Avenue NW', duration=3.14159, previous_certificate_id='Smart, Maxwell Smart', local_mean=2.71828) wait_certificate = \ EnclaveWaitCertificate.wait_certificate_with_wait_timer( wait_timer=wait_timer, nonce='Eeny, meeny, miny, moe.', block_digest='Indigestion. Pepto Bismol.') serialized = wait_certificate.serialize() signing_key = self._create_random_key() wait_certificate.signature = \ signing.sign(serialized, signing_key) copy_wait_certificate = \ EnclaveWaitCertificate.wait_certificate_from_serialized( serialized, wait_certificate.signature) self.assertAlmostEqual(wait_certificate.request_time, copy_wait_certificate.request_time) self.assertAlmostEqual(wait_certificate.duration, copy_wait_certificate.duration) self.assertEqual(wait_certificate.previous_certificate_id, copy_wait_certificate.previous_certificate_id) self.assertAlmostEqual(wait_certificate.local_mean, copy_wait_certificate.local_mean) self.assertEqual(wait_certificate.validator_address, copy_wait_certificate.validator_address) self.assertEqual(wait_certificate.nonce, copy_wait_certificate.nonce) self.assertEqual(wait_certificate.block_digest, copy_wait_certificate.block_digest) self.assertEqual(wait_certificate.signature, copy_wait_certificate.signature) self.assertEqual(serialized, copy_wait_certificate.serialize())
def test_is_valid_pub_key(self): pubkey = signing.generate_pubkey("5KQ4iQQGgbQX9MmfiPUwwHBL1R" "GPa86NwFbqrWoodjuzruqFVDd") pub = signing.encode_pubkey(pubkey, "hex") minfo = { 'Nonce': 100, 'PublicKey': pub, 'TransactionType': '/Transaction', 'Dependencies': [] } sig = signing.sign( signed_object.dict2cbor(minfo), "5KQ4iQQGgbQX9MmfiPUwwHBL1RGPa86NwFbqrWoodjuzruqFVDd") # Create valid transaction minfo["Signature"] = sig temp = Transaction(minfo) self.assertTrue(temp.is_valid("unused")) # Change transaction after it was signed minfo["Nonce"] = time.time() temp = Transaction(minfo) self.assertFalse(temp.is_valid("unused"))
def test_deserialized_wait_timer(self): wait_timer = \ EnclaveWaitTimer( validator_address='1600 Pennsylvania Avenue NW', duration=3.14159, previous_certificate_id='Bond. James Bond.', local_mean=2.71828) serialized = wait_timer.serialize() signing_key = self._create_random_key() wait_timer.signature = \ signing.sign(serialized, signing_key) copy_wait_timer = \ EnclaveWaitTimer.wait_timer_from_serialized( serialized, wait_timer.signature) self.assertEqual( wait_timer.validator_address, copy_wait_timer.validator_address) self.assertAlmostEqual( wait_timer.request_time, copy_wait_timer.request_time) self.assertAlmostEqual( wait_timer.duration, copy_wait_timer.duration) self.assertEqual( wait_timer.previous_certificate_id, copy_wait_timer.previous_certificate_id) self.assertAlmostEqual( wait_timer.local_mean, copy_wait_timer.local_mean) self.assertEqual( wait_timer.signature, copy_wait_timer.signature) self.assertEqual(serialized, copy_wait_timer.serialize())
def create_signup_info(self, originator_public_key_hash, most_recent_wait_certificate_id): # First we need to create a public/private key pair for the PoET # enclave to use. _poet_private_key = \ "1f70fa2518077ad18483f48e77882d11983b537fa5f7cf158684d2c670fe4f1f" _poet_public_key = \ signing.generate_pubkey(_poet_private_key) # currently not used # _active_wait_timer = None _report_private_key = \ signing.encode_privkey( signing.decode_privkey( '5Jz5Kaiy3kCiHE537uXcQnJuiNJshf2bZZn43CrALMGoCd3zRuo', 'wif'), 'hex') # We are going to fake out the sealing the signup data. signup_data = { 'poet_public_key': signing.encode_pubkey(_poet_public_key, 'hex'), 'poet_private_key': signing.encode_privkey(_poet_private_key, 'hex') } # Create a fake report report_data = '{0}{1}'.format( originator_public_key_hash.upper(), signing.encode_pubkey(_poet_public_key, 'hex').upper()) quote = { 'report_body': hashlib.sha256(json.dumps(report_data).encode()).hexdigest() } # Fake our "proof" data. verification_report = { 'id': base64.b64encode( bytes( hashlib.sha256(b'2017-02-16T15:21:24.437048').hexdigest(). encode())).decode(), 'isvEnclaveQuoteStatus': 'OK', 'isvEnclaveQuoteBody': base64.b64encode(json.dumps(quote).encode()).decode(), 'pseManifestStatus': 'OK', 'pseManifestHash': base64.b64encode( hashlib.sha256( bytes( b'Do you believe in ' b'manifest destiny?')).hexdigest().encode()).decode(), 'nonce': most_recent_wait_certificate_id } proof_data_dict = { 'verification_report': json.dumps(verification_report), 'signature': signing.sign(json.dumps(verification_report), _report_private_key) } proof_data = json.dumps(proof_data_dict) return \ SignUpInfo( poet_public_key=signup_data['poet_public_key'], proof_data=proof_data, anti_sybil_id=originator_public_key_hash)
def test_invalid_pse_manifest(self): """ Test that a transaction whose pse_manifast 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 pseManifestStatus verification_report = \ json.loads(proof_data_dict["verification_report"]) pse_status = verification_report['pseManifestStatus'] verification_report['pseManifestStatus'] = None proof_data_dict = { 'verification_report': json.dumps(verification_report), 'signature': signing.sign(json.dumps(verification_report), self._report_private_key) } signup_info.proof_data = json.dumps(proof_data_dict) self._test_bad_signup_info(signup_info) # ------------------------------------------------------ # Bad pseManifestStatus verification_report = \ json.loads(proof_data_dict["verification_report"]) verification_report['pseManifestStatus'] = "bad" proof_data_dict = { 'verification_report': json.dumps(verification_report), 'signature': signing.sign(json.dumps(verification_report), self._report_private_key) } signup_info.proof_data = json.dumps(proof_data_dict) self._test_bad_signup_info(signup_info) # ------------------------------------------------------ # No pseManifestHash verification_report = \ json.loads(proof_data_dict["verification_report"]) verification_report['pseManifestStatus'] = pse_status verification_report['pseManifestHash'] = None proof_data_dict = { 'verification_report': json.dumps(verification_report), 'signature': signing.sign(json.dumps(verification_report), self._report_private_key) } signup_info.proof_data = json.dumps(proof_data_dict) self._test_bad_signup_info(signup_info) # ------------------------------------------------------ # Bad pseManifestHash verification_report = \ json.loads(proof_data_dict["verification_report"]) verification_report['pseManifestHash'] = "Bad" proof_data_dict = { 'verification_report': json.dumps(verification_report), 'signature': signing.sign(json.dumps(verification_report), self._report_private_key) } signup_info.proof_data = json.dumps(proof_data_dict) self._test_bad_signup_info(signup_info)
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 the sealing the signup data. signup_data = { 'poet_public_key': signing.encode_pubkey(cls._poet_public_key, 'hex'), 'poet_private_key': signing.encode_privkey(cls._poet_private_key, 'hex') } sealed_signup_data = \ base64.b64encode(bytes(dict2json(signup_data).encode())) # Create a fake report report_data = '{0}{1}'.format( originator_public_key_hash.upper(), signing.encode_pubkey(cls._poet_public_key, 'hex').upper()) quote = { 'report_body': hashlib.sha256(dict2json(report_data).encode()).hexdigest() } # Fake our "proof" data. verification_report = { 'id': base64.b64encode( bytes( hashlib.sha256(datetime.datetime.now().isoformat( ).encode()).hexdigest().encode())).decode(), 'isvEnclaveQuoteStatus': 'OK', 'isvEnclaveQuoteBody': base64.b64encode(dict2json(quote).encode()).decode(), 'pseManifestStatus': 'OK', 'pseManifestHash': base64.b64encode( hashlib.sha256( bytes(b'Do you believe in ' b'manifest destiny?')).hexdigest().encode()). decode(), 'nonce': most_recent_wait_certificate_id } proof_data_dict = { 'verification_report': dict2json(verification_report), 'signature': signing.sign(dict2json(verification_report), cls._report_private_key) } 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 create_wait_certificate(cls, wait_timer, block_digest): with cls._lock: # If we don't have a PoET private key, then the enclave has not # been properly initialized (either by calling create_signup_info # or unseal_signup_data) if cls._poet_private_key is None: raise \ ValueError( 'Enclave must be initialized before attempting to ' 'create a wait certificate') # Several criteria need to be met before we can create a wait # certificate: # 1. We have an active timer # 2. The caller's wait timer is the active wait timer. We are not # going to rely the objects, being the same, but will compute # a signature over the object and verify that the signatures # are the same. # 3. The active timer has expired # 4. The active timer has not timed out # # 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 cls._active_wait_timer is None: raise \ ValueError( 'There is not a current enclave active wait timer') if wait_timer is None or \ cls._active_wait_timer.signature != \ signing.sign( wait_timer.serialize(), cls._poet_private_key): raise \ ValueError( 'Validator is not using the current wait timer') is_not_genesis_block = \ (cls._active_wait_timer.previous_certificate_id != NullIdentifier) now = time.time() expire_time = \ cls._active_wait_timer.request_time + \ cls._active_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 = \ cls._active_wait_timer.request_time + \ cls._active_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': cls._active_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 PoET private key wait_certificate = \ EnclaveWaitCertificate.wait_certificate_with_wait_timer( wait_timer=cls._active_wait_timer, nonce=nonce, block_digest=block_digest) wait_certificate.signature = \ signing.sign( wait_certificate.serialize(), cls._poet_private_key) # Now that we have created the certificate, we no longer have an # active timer cls._active_wait_timer = None return wait_certificate
def create_wait_certificate(cls, wait_timer, block_digest): with cls._lock: # If we don't have a PoET private key, then the enclave has not # been properly initialized (either by calling create_signup_info # or unseal_signup_data) if cls._poet_private_key is None: raise \ ValueError( 'Enclave must be initialized before attempting to ' 'create a wait certificate') # Several criteria need to be met before we can create a wait # certificate: # 1. We have an active timer # 2. The caller's wait timer is the active wait timer. We are not # going to rely the objects, being the same, but will compute # a signature over the object and verify that the signatures # are the same. # 3. The active timer has expired # 4. The active timer has not timed out # # 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 cls._active_wait_timer is None: raise \ ValueError( 'There is not a current enclave active wait timer') if wait_timer is None or \ cls._active_wait_timer.signature != \ signing.sign( wait_timer.serialize(), cls._poet_private_key): raise \ ValueError( 'Validator is not using the current wait timer') is_not_genesis_block = \ (cls._active_wait_timer.previous_certificate_id != NULL_BLOCK_IDENTIFIER) now = time.time() expire_time = \ cls._active_wait_timer.request_time + \ cls._active_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 = \ cls._active_wait_timer.request_time + \ cls._active_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': cls._active_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 PoET private key wait_certificate = \ EnclaveWaitCertificate.wait_certificate_with_wait_timer( wait_timer=cls._active_wait_timer, nonce=nonce, block_digest=block_digest) wait_certificate.signature = \ signing.sign( wait_certificate.serialize(), cls._poet_private_key) # Now that we have created the certificate, we no longer have an # active timer cls._active_wait_timer = None return wait_certificate
def test_invalid_envalve_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 proof_data_dict = { 'verification_report': json.dumps(verification_report), 'signature': signing.sign(json.dumps(verification_report), self._report_private_key) } signup_info.proof_data = json.dumps(proof_data_dict) self._test_bad_signup_info(signup_info) # ------------------------------------------------------ # No isvEnclaveQuoteStatus verification_report = \ json.loads(proof_data_dict["verification_report"]) verification_report["isvEnclaveQuoteStatus"] = "Bad" proof_data_dict = { 'verification_report': json.dumps(verification_report), 'signature': signing.sign(json.dumps(verification_report), self._report_private_key) } signup_info.proof_data = json.dumps(proof_data_dict) 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 proof_data_dict = { 'verification_report': json.dumps(verification_report), 'signature': signing.sign(json.dumps(verification_report), self._report_private_key) } signup_info.proof_data = json.dumps(proof_data_dict) self._test_bad_signup_info(signup_info) # ------------------------------------------------------ # No report body in isvEnclaveQuoteBody verification_report = \ json.loads(proof_data_dict["verification_report"]) quote = {"test": "none"} verification_report['isvEnclaveQuoteBody'] = \ base64.b64encode( json.dumps(quote).encode()).decode() proof_data_dict = { 'verification_report': json.dumps(verification_report), 'signature': signing.sign(json.dumps(verification_report), self._report_private_key) } signup_info.proof_data = json.dumps(proof_data_dict) self._test_bad_signup_info(signup_info) # ------------------------------------------------------ # Bad isvEnclaveQuoteBody verification_report = \ json.loads(proof_data_dict["verification_report"]) quote = {"report_body": "none"} verification_report['isvEnclaveQuoteBody'] = \ base64.b64encode( json.dumps(quote).encode()).decode() proof_data_dict = { 'verification_report': json.dumps(verification_report), 'signature': signing.sign(json.dumps(verification_report), self._report_private_key) } signup_info.proof_data = json.dumps(proof_data_dict) self._test_bad_signup_info(signup_info)
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 the sealing the signup data. signup_data = { 'poet_public_key': signing.encode_pubkey(cls._poet_public_key, 'hex'), 'poet_private_key': signing.encode_privkey( cls._poet_private_key, 'hex') } sealed_signup_data = \ base64.b64encode(bytes(dict2json(signup_data).encode())) # Create a fake report report_data = '{0}{1}'.format( originator_public_key_hash.upper(), signing.encode_pubkey( cls._poet_public_key, 'hex').upper() ) quote = { 'report_body': hashlib.sha256( dict2json(report_data).encode()).hexdigest() } # Fake our "proof" data. verification_report = { 'id': base64.b64encode( bytes(hashlib.sha256( datetime.datetime.now().isoformat().encode()) .hexdigest().encode())).decode(), 'isvEnclaveQuoteStatus': 'OK', 'isvEnclaveQuoteBody': base64.b64encode( dict2json(quote).encode()).decode(), 'pseManifestStatus': 'OK', 'pseManifestHash': base64.b64encode( hashlib.sha256( bytes(b'Do you believe in ' b'manifest destiny?')).hexdigest() .encode()).decode(), 'nonce': most_recent_wait_certificate_id } proof_data_dict = { 'verification_report': dict2json(verification_report), 'signature': signing.sign( dict2json(verification_report), cls._report_private_key) } 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)