def test_private_key_sawtooth_random(self):
     """Generates two private keys using Sawtooth Signing's
     Secp256k1PrivateKey class, and make sure they don't match;
     and thus are hopefully random and non-deterministic"""
     key1 = Secp256k1PrivateKey.new_random()
     key2 = Secp256k1PrivateKey.new_random()
     self.assertNotEqual(key1.as_hex(), key2.as_hex())
     self.assertNotEqual(key1.as_bytes(), key2.as_bytes())
 def test_private_key_sawtooth(self):
     """Generates a random private key using Sawtooth Signing's
     Secp256k1PrivateKey class, and make sure it passes sanity checks"""
     self.assertTrue(callable(Secp256k1PrivateKey.new_random))
     private_key = Secp256k1PrivateKey.new_random()
     self.assertIsPrivateKeySecp256k1(private_key)
     return private_key
async def create_new_user(request):
    required_fields = ['name', 'password']
    utils.validate_fields(required_fields, request.json)

    # Generate keys
    private_key = Secp256k1PrivateKey.new_random()
    txn_key = Key(private_key.as_hex())
    encrypted_private_key = utils.encrypt_private_key(
        request.app.config.AES_KEY, txn_key.public_key, private_key.as_bytes())

    # Build create user transaction
    batch_list = create_user(txn_key, request.app.config.BATCHER_KEY_PAIR,
                             request.json.get('name'), txn_key.public_key,
                             request.json.get('metadata'),
                             request.json.get('manager'))

    # Submit transaction and wait for complete
    await utils.send(request.app.config.VAL_CONN, batch_list[0],
                     request.app.config.TIMEOUT)

    # Save new user in auth table
    hashed_password = hashlib.sha256(
        request.json.get('password').encode('utf-8')).hexdigest()

    auth_entry = {
        'user_id': txn_key.public_key,
        'hashed_password': hashed_password,
        'encrypted_private_key': encrypted_private_key,
        'email': request.json.get('email')
    }
    await auth_query.create_auth_entry(request.app.config.DB_CONN, auth_entry)

    # Send back success response
    return create_user_response(request, txn_key.public_key)
Beispiel #4
0
 def test_key_class_given_private_key(self):
     """Test initializing the key class with a given private key"""
     private_key = Secp256k1PrivateKey.new_random()
     txn_key = Key(private_key.as_hex())
     self.assertEqual(len(txn_key.private_key), PRIVATE_KEY_LENGTH * 2)
     self.assertTrue(PRIVATE_KEY_PATTERN.match(txn_key.private_key))
     self.assertEqual(txn_key.private_key, private_key.as_hex())
     self.assertEqual(len(txn_key.public_key), PUBLIC_KEY_LENGTH * 2)
     self.assertTrue(PUBLIC_KEY_PATTERN.match(txn_key.public_key))
Beispiel #5
0
 def test_public_key_sawtooth(self):
     """Derive a public key from a random private key using Sawtooth Signing
     and make sure it passes sanity checks"""
     context = sawtooth_signing.create_context(ELLIPTIC_CURVE_ALGORITHM)
     private_key = Secp256k1PrivateKey.new_random()
     public_key = context.get_public_key(private_key)
     self.assertIsPublicKeySecp256k1(public_key)
     self.assertIsKeyPairSecp256k1(public_key, private_key)
     return public_key, private_key
Beispiel #6
0
    def __init__(self, loop, connection,timeout=DEFAULT_TIMEOUT, metrics_registry=None):

        super().__init__(loop,connection,timeout,metrics_registry)
        # BGX init
        self._context = create_context('secp256k1') 
        self._private_key = Secp256k1PrivateKey.new_random()
        self._public_key = self._context.get_public_key(self._private_key)
        self._crypto_factory = CryptoFactory(self._context)
        self._signer = self._crypto_factory.new_signer(self._private_key)
        LOGGER.debug('BgxRouteHandler: _signer PUBLIC_KEY=%s',self._public_key.as_hex()[:8])
Beispiel #7
0
 def __init__(self):
     self._context = create_context('secp256k1') 
     LOGGER.debug('_do_set: context')
     self._private_key = Secp256k1PrivateKey.new_random()
     LOGGER.debug('_do_set: context private_key=%s',self._private_key.as_hex())
     self._public_key = self._context.get_public_key(self._private_key)
     crypto_factory = CryptoFactory(self._context)
     self._signer = crypto_factory.new_signer(self._private_key)
     #self._signer = CryptoFactory(self._context).new_signer(self.private_key)
     LOGGER.debug('_do_set: public_key=%s  ',self._public_key.as_hex())
     LOGGER.info('BgtTransactionHandler init DONE')
Beispiel #8
0
    def generate_key_pair():
        """
        Generate public and private key pair.

        Returns:
            Generated key pair in bytes.
        """
        private_key_obj = Secp256k1PrivateKey.new_random()
        public_key_obj = Secp256k1PublicKey(
            private_key_obj.secp256k1_private_key.pubkey)

        return private_key_obj.as_bytes(), public_key_obj.as_bytes()
    def __init__(self, loop, connection,timeout=DEFAULT_TIMEOUT, metrics_registry=None):

        super().__init__(loop,connection,timeout,metrics_registry)
        # Dashboard init
        self._context = create_context('secp256k1') 
        self._private_key = Secp256k1PrivateKey.new_random()
        self._public_key = self._context.get_public_key(self._private_key)
        self._crypto_factory = CryptoFactory(self._context)
        self._signer = self._crypto_factory.new_signer(self._private_key)
        self._public_key_id = self._public_key.as_hex()
        LOGGER.debug('DashboardRouteHandler: _signer PUBLIC_KEY=%s',self._public_key_id[:8])
        self._network = {}
        try:
            with open('./network.json') as file:
                self._network = json.load(file)
        except Exception as err:
            LOGGER.debug('DashboardRouteHandler: err=%s',err)
Beispiel #10
0
    def __init__(self, private_key=None, public_key=None):
        """
        Key() -- generates a new key
        Key(private_key:str) -- Uses the private key passed
        """
        self._context = create_context(ELLIPTIC_CURVE_ALGORITHM)

        if private_key is None and public_key is None:
            private_key = Secp256k1PrivateKey.new_random()
        if isinstance(private_key, str):
            private_key = Secp256k1PrivateKey.from_hex(private_key)
        if isinstance(public_key, str):
            public_key = Secp256k1PublicKey.from_hex(public_key)
        if public_key is None and private_key is not None:
            public_key = self._context.get_public_key(private_key)

        self._public_key = public_key
        self._private_key = private_key
Beispiel #11
0
async def create_new_user(request):
    required_fields = ["name", "username", "password"]
    utils.validate_fields(required_fields, request.json)

    # Generate keys
    private_key = Secp256k1PrivateKey.new_random()
    txn_key = Key(private_key.as_hex())
    encrypted_private_key = encrypt_private_key(
        request.app.config.AES_KEY, txn_key.public_key, private_key.as_bytes()
    )

    # Build create user transaction
    batch_list = create_user(
        txn_key,
        request.app.config.BATCHER_KEY_PAIR,
        request.json.get("name"),
        request.json.get("username"),
        txn_key.public_key,
        request.json.get("metadata"),
        request.json.get("manager"),
    )

    # Submit transaction and wait for complete
    await utils.send(
        request.app.config.VAL_CONN, batch_list[0], request.app.config.TIMEOUT
    )

    # Save new user in auth table
    hashed_password = hashlib.sha256(
        request.json.get("password").encode("utf-8")
    ).hexdigest()

    auth_entry = {
        "user_id": txn_key.public_key,
        "hashed_password": hashed_password,
        "encrypted_private_key": encrypted_private_key,
        "user_name": request.json.get("username"),
        "email": request.json.get("email"),
    }
    await auth_query.create_auth_entry(request.app.config.DB_CONN, auth_entry)

    # Send back success response
    return create_user_response(request, txn_key.public_key)
Beispiel #12
0
def create_random_private_key():
    return Secp256k1PrivateKey.new_random()
    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_key_class_public_key(self):
     private_key = Secp256k1PrivateKey.new_random()
     txn_key = Key(private_key.as_hex())
     self.assertEqual(len(txn_key.public_key), PUBLIC_KEY_LENGTH * 2)
     self.assertTrue(PUBLIC_KEY_PATTERN.match(txn_key.public_key))
Beispiel #15
0
    def create_user_transaction(self, name, username, metadata):
        txn_private_key = Secp256k1PrivateKey.new_random()
        batch_private_key = Secp256k1PrivateKey.new_random()

        txn_key = Key(txn_private_key.as_hex())
        batch_key = Key(batch_private_key.as_hex())

        batchlist, sig = create_user(
            txn_key, batch_key, name, username, txn_key.public_key, metadata
        )

        self.assertEqual(type(sig), str)
        self.assertEqual(type(batchlist), batch_pb2.BatchList)

        self.assertEqual(len(sig), SIGNATURE_LENGTH)
        self.assertTrue(SIGNATURE_PATTERN.match(sig))

        batch_count = 0
        for batch in batchlist.batches:
            batch_count += 1
            self.assertEqual(type(batch), batch_pb2.Batch)
            self.assertEqual(type(batch.header_signature), str)
            self.assertEqual(len(batch.header_signature), SIGNATURE_LENGTH)
            self.assertTrue(SIGNATURE_PATTERN.match(batch.header_signature))

            trans_count = 0
            for transaction in batch.transactions:
                trans_count += 1
                self.assertEqual(type(transaction.header), bytes)
                self.assertEqual(type(transaction.header_signature), str)
                self.assertEqual(type(transaction.payload), bytes)

                self.assertEqual(len(transaction.header_signature), SIGNATURE_LENGTH)
                self.assertTrue(SIGNATURE_PATTERN.match(transaction.header_signature))

                header = transaction_pb2.TransactionHeader()
                header.ParseFromString(transaction.header)

                self.assertEqual(type(header), transaction_pb2.TransactionHeader)
                self.assertEqual(header.family_name, addresser.FAMILY_NAME)
                self.assertEqual(header.family_version, addresser.FAMILY_VERSION)
                self.assertEqual(header.batcher_public_key, batch_key.public_key)
                self.assertEqual(header.signer_public_key, txn_key.public_key)

                self.assertEqual(len(header.payload_sha512), SIGNATURE_LENGTH)
                self.assertTrue(SIGNATURE_PATTERN.match(header.payload_sha512))

                input_count = 0
                for address in header.inputs:
                    input_count += 1
                    self.assertEqual(type(address), str)
                    self.assertEqual(len(address), addresser.ADDRESS_LENGTH)
                    self.assertEqual(
                        addresser.address_is(address), addresser.AddressSpace.USER
                    )

                self.assertEqual(input_count, 1)

                output_count = 0
                for address in header.outputs:
                    output_count += 1
                    self.assertEqual(type(address), str)
                    self.assertEqual(len(address), addresser.ADDRESS_LENGTH)
                    self.assertEqual(
                        addresser.address_is(address), addresser.AddressSpace.USER
                    )

                self.assertEqual(output_count, 1)

                payload = rbac_payload_pb2.RBACPayload()
                payload.ParseFromString(transaction.payload)

                self.assertEqual(type(payload), rbac_payload_pb2.RBACPayload)
                self.assertEqual(
                    payload.message_type, rbac_payload_pb2.RBACPayload.CREATE_USER
                )
                self.assertEqual(type(payload.content), bytes)

                user = user_transaction_pb2.CreateUser()
                user.ParseFromString(payload.content)

                self.assertEqual(type(user), user_transaction_pb2.CreateUser)
                self.assertEqual(user.name, name)
                self.assertEqual(user.user_name, username)
                self.assertEqual(type(user.user_id), str)
                self.assertEqual(user.user_id, txn_key.public_key)

            self.assertEqual(trans_count, 1)

        self.assertEqual(batch_count, 1)
def _create_random_key():
    return Secp256k1PrivateKey.new_random()
    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 _create_random_key(cls):
     return Secp256k1PrivateKey.new_random()
import sys
import time
import logging
from uuid import uuid4
from urllib.request import urlopen
from urllib.error import HTTPError
from urllib.error import URLError
import sawtooth_signing
from sawtooth_signing.secp256k1 import Secp256k1PrivateKey
from rbac.transaction_creation.common import Key

LOGGER = logging.getLogger(__name__)
LOGGER.level = logging.DEBUG
LOGGER.addHandler(logging.StreamHandler(sys.stdout))

BATCHER_PRIVATE_KEY = Secp256k1PrivateKey.new_random().as_hex()
BATCHER_KEY = Key(BATCHER_PRIVATE_KEY)


class IntegrationTestHelper:
    """ A singleton test helper ensuring the Docker containers
    are up and available to be tested against."""

    class __impl:

        __available = False

        def wait_for_containers(self):
            self.__check_containers()

        def __check_containers(self):
    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 PBFT
            # enclave to use.
            # Counter ID is a placeholder for a hardware counter in a TEE.
            pbft_private_key = Secp256k1PrivateKey.new_random()
            pbft_public_key = cls._context.get_public_key(pbft_private_key)
            counter_id = None

            # Simulate sealing (encrypting) the signup data.
            signup_data = {
                'pbft_private_key': pbft_private_key.as_hex(),
                'pbft_public_key': pbft_public_key.as_hex(),
                'counter_id': counter_id
            }
            sealed_signup_data = base64.b64encode(
                dict2json(signup_data).encode()).decode('utf-8')
            """
            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(
                pbft_public_key=signup_data['pbft_public_key'],
                proof_data=proof_data,
                anti_sybil_id=cls._anti_sybil_id,
                sealed_signup_data=sealed_signup_data)
class _PoetEnclaveSimulator:
    # A lock to protect threaded access
    _lock = threading.Lock()

    # The private key we generate to sign the certificate ID when creating
    # the random wait timeout value
    _context = create_context('secp256k1')
    _seal_private_key = Secp256k1PrivateKey.new_random()

    # The basename and enclave measurement values we will put into and verify
    # are in the enclave quote in the attestation verification report.
    __VALID_BASENAME__ = \
        bytes.fromhex(
            'b785c58b77152cbe7fd55ee3851c4990'
            '00000000000000000000000000000000')
    __VALID_ENCLAVE_MEASUREMENT__ = \
        bytes.fromhex(
            'c99f21955e38dbb03d2ca838d3af6e43'
            'ef438926ed02db4cc729380c8c7a174e')

    # We use the report private key PEM to create the private key used to
    # sign attestation verification reports.  On the flip side, the report
    # public key PEM is used to create the public key used to verify the
    # signature on the attestation verification reports.
    __REPORT_PRIVATE_KEY_PEM__ = \
        '-----BEGIN PRIVATE KEY-----\n' \
        'MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCsy/NmLwZP6Uj0\n' \
        'p5mIiefgK8VOK7KJ34g3h0/X6aFOd/Ff4j+e23wtQpkxsjVHWLM5SjElGhfpVDhL\n' \
        '1WAMsQI9bpCWR4sjV6p7gOJhv34nkA2Grj5eSHCAJRQXCl+pJ9dYIeKaNoaxkdtq\n' \
        '+Xme//ohtkkv/ZjMTfsjMl0RLXokJ+YhSuTpNSovRaCtZfLB5MihVJuV3Qzb2ROh\n' \
        'KQxcuyPy9tBtOIrBWJaFiXOLRxAijs+ICyzrqUBbRfoAztkljIBx9KNItHiC4zPv\n' \
        'o6DxpGSO2yMQSSrs13PkfyGWVZSgenEYOouEz07X+H5B29PPuW5mCl4nkoH3a9gv\n' \
        'rI6VLEx9AgMBAAECggEAImfFge4RCq4/eX85gcc7pRXyBjuLJAqe+7d0fWAmXxJg\n' \
        'vB+3XTEEi5p8GDoMg7U0kk6kdGe6pRnAz9CffEduU78FCPcbzCCzcD3cVWwkeUok\n' \
        'd1GQV4OC6vD3DBNjsrGdHg45KU18CjUphCZCQhdjvXynG+gZmWxZecuYXkg4zqPT\n' \
        'LwOkcdWBPhJ9CbjtiYOtKDZbhcbdfnb2fkxmvnAoz1OWNfVFXh+x7651FrmL2Pga\n' \
        'xGz5XoxFYYT6DWW1fL6GNuVrd97wkcYUcjazMgunuUMC+6XFxqK+BoqnxeaxnsSt\n' \
        'G2r0sdVaCyK1sU41ftbEQsc5oYeQ3v5frGZL+BgrYQKBgQDgZnjqnVI/B+9iarx1\n' \
        'MjAFyhurcKvFvlBtGKUg9Q62V6wI4VZvPnzA2zEaR1J0cZPB1lCcMsFACpuQF2Mr\n' \
        '3VDyJbnpSG9q05POBtfLjGQdXKtGb8cfXY2SwjzLH/tvxHm3SP+RxvLICQcLX2/y\n' \
        'GTJ+mY9C6Hs6jIVLOnMWkRWamQKBgQDFITE3Qs3Y0ZwkKfGQMKuqJLRw29Tyzw0n\n' \
        'XKaVmO/pEzYcXZMPBrFhGvdmNcJLo2fcsmGZnmit8RP4ChwHUlD11dH1Ffqw9FWc\n' \
        '387i0chlE5FhQPirSM8sWFVmjt2sxC4qFWJoAD/COQtKHgEaVKVc4sH/yRostL1C\n' \
        'r+7aWuqzhQKBgQDcuC5LJr8VPGrbtPz1kY3mw+r/cG2krRNSm6Egj6oO9KFEgtCP\n' \
        'zzjKQU9E985EtsqNKI5VdR7cLRLiYf6r0J6j7zO0IAlnXADP768miUqYDuRw/dUw\n' \
        'JsbwCZneefDI+Mp325d1/egjla2WJCNqUBp4p/Zf62f6KOmbGzzEf6RuUQKBgG2y\n' \
        'E8YRiaTOt5m0MXUwcEZk2Hg5DF31c/dkalqy2UYU57aPJ8djzQ8hR2x8G9ulWaWJ\n' \
        'KiCm8s9gaOFNFt3II785NfWxPmh7/qwmKuUzIdWFNxAsbHQ8NvURTqyccaSzIpFO\n' \
        'hw0inlhBEBQ1cB2r3r06fgQNb2BTT0Itzrd5gkNVAoGBAJcMgeKdBMukT8dKxb4R\n' \
        '1PgQtFlR3COu2+B00pDyUpROFhHYLw/KlUv5TKrH1k3+E0KM+winVUIcZHlmFyuy\n' \
        'Ilquaova1YSFXP5cpD+PKtxRV76Qlqt6o+aPywm81licdOAXotT4JyJhrgz9ISnn\n' \
        'J13KkHoAZ9qd0rX7s37czb3O\n' \
        '-----END PRIVATE KEY-----'

    _report_private_key = \
        serialization.load_pem_private_key(
            __REPORT_PRIVATE_KEY_PEM__.encode(),
            password=None,
            backend=backends.default_backend())

    # The anti-sybil ID for this particular validator.  This will get set when
    # the enclave is initialized
    _anti_sybil_id = None

    MINIMUM_WAIT_TIME = 1.0

    @classmethod
    def initialize(cls, config_dir, data_dir):
        # See if our configuration file exists.  If so, then we are going to
        # see if there is a configuration value for the validator ID.  If so,
        # then we'll use that when constructing the simulated anti-Sybil ID.
        # Otherwise, we are going to fall back on trying to create one that is
        # unique.
        validator_id = datetime.datetime.now().isoformat()

        config_file = os.path.join(config_dir, 'poet_enclave_simulator.toml')
        if os.path.exists(config_file):
            LOGGER.info(
                'Loading PoET enclave simulator config from : %s',
                config_file)

            try:
                with open(config_file) as fd:
                    toml_config = toml.loads(fd.read())
            except IOError as e:
                LOGGER.info(
                    'Error loading PoET enclave simulator configuration: %s',
                    e)
                LOGGER.info('Continuing with default configuration')

            invalid_keys = set(toml_config.keys()).difference(['validator_id'])
            if invalid_keys:
                LOGGER.warning(
                    'Ignoring invalid keys in PoET enclave simulator config: '
                    '%s',
                    ', '.join(sorted(list(invalid_keys))))

            validator_id = toml_config.get('validator_id', validator_id)

        LOGGER.debug(
            'PoET enclave simulator creating anti-Sybil ID from: %s',
            validator_id)

        # Create an anti-Sybil ID that is unique for this validator
        cls._anti_sybil_id = hashlib.sha256(validator_id.encode()).hexdigest()

    @classmethod
    def shutdown(cls):
        pass

    @classmethod
    def get_enclave_measurement(cls):
        return cls.__VALID_ENCLAVE_MEASUREMENT__.hex()

    @classmethod
    def get_enclave_basename(cls):
        return cls.__VALID_BASENAME__.hex()

    @classmethod
    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)

    @classmethod
    def deserialize_signup_info(cls, serialized_signup_info):
        return \
            EnclaveSignupInfo.signup_info_from_serialized(
                serialized_signup_info=serialized_signup_info)

    @classmethod
    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.encode()).decode())
        return signup_data.get('poet_public_key')

    @classmethod
    def release_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
        """
        # This is a standin method to release enclave resources associated
        # with this signup. This is not currently relevant to the simulator
        # but it must match the interface with the HW enclave.
        pass

    @classmethod
    def create_wait_timer(cls,
                          sealed_signup_data,
                          validator_address,
                          previous_certificate_id,
                          local_mean):
        with cls._lock:
            # Extract keys from the 'sealed' signup data
            signup_data = \
                json2dict(
                    base64.b64decode(sealed_signup_data.encode()).decode())
            poet_private_key = signup_data['poet_private_key']

            if poet_private_key is None:
                raise \
                    ValueError(
                        'Invalid signup data. No poet private key.')

            try:
                poet_private_key = Secp256k1PrivateKey.from_hex(
                    poet_private_key)
            except ParseError:
                raise \
                    ValueError(
                        'Invalid signup data. Badly formatted poet key(s).')

            # In a TEE implementation we would increment the HW counter here.
            # We can't usefully simulate a HW counter though.

            # 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(
                    cls._context.sign(
                        previous_certificate_id.encode(),
                        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 = \
                _PoetEnclaveSimulator.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 = \
                cls._context.sign(
                    wait_timer.serialize().encode(),
                    poet_private_key)

            return wait_timer

    @classmethod
    def deserialize_wait_timer(cls, serialized_timer, signature):
        return \
            EnclaveWaitTimer.wait_timer_from_serialized(
                serialized_timer=serialized_timer,
                signature=signature)

    @classmethod
    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())
            poet_private_key = signup_data['poet_private_key']
            poet_public_key = signup_data['poet_public_key']

            if poet_private_key is None or poet_public_key is None:
                raise \
                    ValueError(
                        'Invalid signup data. No poet key(s).')

            try:
                poet_public_key = Secp256k1PublicKey.from_hex(poet_public_key)
                poet_private_key = Secp256k1PrivateKey.from_hex(
                    poet_private_key)
            except ParseError:
                raise \
                    ValueError(
                        'Invalid signup data. Badly formatted poet 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(),
                        poet_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 PoET 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(),
                    poet_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

    @classmethod
    def deserialize_wait_certificate(cls, serialized_certificate, signature):
        return \
            EnclaveWaitCertificate.wait_certificate_from_serialized(
                serialized_certificate=serialized_certificate,
                signature=signature)

    @classmethod
    def verify_wait_certificate(cls, certificate, poet_public_key):
        # Since the signing module uses a hex-encoded string as the canonical
        # format for public keys and we should be handed a public key that was
        # part of signup information created by us, don't bother decoding
        # the public key.
        try:
            poet_public_key = Secp256k1PublicKey.from_hex(poet_public_key)
        except ParseError:
            raise \
                ValueError(
                    'Invalid signup data. Badly formatted poet key(s).')

        if not \
            cls._context.verify(
                certificate.signature,
                certificate.serialize().encode(),
                poet_public_key):
            raise ValueError('Wait certificate signature does not match')
Beispiel #22
0
def create_user():
    private_key = Secp256k1PrivateKey.new_random().as_hex()
    # public_key = CryptoFactory(create_context('secp256k1')).new_signer(private_key)
    return private_key