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
예제 #2
0
    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)