Ejemplo n.º 1
0
    def __init__(self, operation, request_originator_keys, contract, **kwargs):
        if not self.__ops__[operation]:
            raise ValueError('invalid operation')

        self.operation = operation
        self.contract_id = contract.contract_id
        self.creator_id = contract.creator_id
        self.enclave_service = kwargs.get('enclave_service')
        if self.enclave_service == 'random':
            enclave_id = random.choice(list(contract.enclave_map.keys()))
            try:  #use the eservice database to get the client
                einfo = eservice_db.get_by_enclave_id(enclave_id)
                self.enclave_service = einfo.client
            except Exception as e:
                raise Exception(
                    'failed to get enclave client using database: %s', str(e))

        self.encrypted_state_encryption_key = contract.get_state_encryption_key(
            self.enclave_service.enclave_id)
        self.originator_keys = request_originator_keys
        self.make_channel_keys()
        self.session_key = crypto.SKENC_GenerateKey()
        self.contract_code = contract.contract_code
        self.contract_state = contract.contract_state
        self.message = ContractMessage(self.originator_keys, self.channel_id,
                                       **kwargs)
        self.replication_params = contract.replication_params
        self.request_number = ContractRequest.__request_number__
        ContractRequest.__request_number__ += 1
Ejemplo n.º 2
0
    def __init__(self, operation, request_originator_keys, contract, **kwargs) :
        super().__init__(request_originator_keys, contract, **kwargs)

        if not self.__ops__[operation] :
            raise ValueError('invalid operation')

        self.operation = operation
        self.contract_code = contract.contract_code
        self.contract_state = contract.contract_state
        self.message = ContractMessage(self.originator_keys, self.channel_id, **kwargs)
Ejemplo n.º 3
0
    def __init__(self, operation, request_originator_keys, enclave_service, contract, **kwargs) :
        if not self.__ops__[operation] :
            raise ValueError('invalid operation')

        self.operation = operation

        self.contract_id = contract.contract_id
        self.creator_id = contract.creator_id
        self.encrypted_state_encryption_key = contract.get_state_encryption_key(enclave_service.enclave_id)
        self.enclave_service = enclave_service
        self.originator_keys = request_originator_keys
        self.channel_keys = keys.TransactionKeys()
        self.session_key = crypto.SKENC_GenerateKey()

        self.contract_code = contract.contract_code
        self.contract_state = contract.contract_state
        self.message = ContractMessage(self.originator_keys, self.channel_keys, **kwargs)
Ejemplo n.º 4
0
class ContractRequest(object):
    __ops__ = {'initialize': True, 'update': True}

    def __init__(self, operation, request_originator_keys, enclave_service,
                 contract, **kwargs):
        if not self.__ops__[operation]:
            raise ValueError('invalid operation')

        self.operation = operation

        self.contract_id = contract.contract_id
        self.creator_id = contract.creator_id
        self.encrypted_state_encryption_key = contract.get_state_encryption_key(
            enclave_service.enclave_id)
        self.enclave_service = enclave_service
        self.originator_keys = request_originator_keys
        self.channel_keys = keys.TransactionKeys()
        self.session_key = crypto.SKENC_GenerateKey()

        self.contract_code = contract.contract_code
        self.contract_state = contract.contract_state
        self.message = ContractMessage(self.originator_keys, self.channel_keys,
                                       **kwargs)

    @property
    def enclave_keys(self):
        return self.enclave_service.enclave_keys

    def __serialize_for_encryption(self):
        result = dict()
        result['Operation'] = self.operation
        result['ContractID'] = self.contract_id
        result['CreatorID'] = self.creator_id
        result[
            'EncryptedStateEncryptionKey'] = self.encrypted_state_encryption_key

        result['ContractState'] = self.contract_state.serializeForInvokation()
        result['ContractCode'] = self.contract_code.serialize()
        result['ContractMessage'] = self.message.serialize()

        return json.dumps(result)

    def __encrypt_session_key(self):
        encrypted_key = self.enclave_keys.encrypt(self.session_key)
        return crypto.byte_array_to_base64(encrypted_key)

    # response -- base64 encode, response encrypted with session key
    def __decrypt_response(self, response):
        decoded_response = crypto.base64_to_byte_array(response)
        return crypto.SKENC_DecryptMessage(self.session_key, decoded_response)

    # enclave_service -- enclave service wrapper object
    def evaluate(self):
        encrypted_session_key = self.__encrypt_session_key()

        # Encrypt the request
        serialized_byte_array = crypto.string_to_byte_array(
            self.__serialize_for_encryption())
        encrypted_request_raw = crypto.SKENC_EncryptMessage(
            self.session_key, serialized_byte_array)
        encrypted_request = crypto.byte_array_to_base64(encrypted_request_raw)

        try:
            # Check and conditionally put the encrypted state into the block store if it is non-empty
            state_hash_b64 = self.contract_state.getStateHash(encoding='b64')
            if state_hash_b64:
                block_store_len = self.enclave_service.block_store_head(
                    state_hash_b64)
                if block_store_len <= 0:
                    # This block wasn't present in the block store of this enclave service - need to send it
                    logger.debug(
                        "Block store did not contain block '%s' - sending it",
                        state_hash_b64)

                    ret = self.enclave_service.block_store_put(
                        state_hash_b64, self.contract_state.encrypted_state)
                    if ret != True:
                        logger.exception("block_store_put failed for key %s",
                                         state_hash_b64)
                        raise

            encoded_encrypted_response = self.enclave_service.send_to_contract(
                encrypted_session_key, encrypted_request)
            if encoded_encrypted_response == None:
                logger.exception(
                    "send_to_contract failed but no exception was thrown")
                raise

            logger.debug("raw response from enclave: %s",
                         encoded_encrypted_response)
        except:
            logger.exception('contract invocation failed')
            raise

        try:
            decrypted_response = self.__decrypt_response(
                encoded_encrypted_response)
            response_string = crypto.byte_array_to_string(decrypted_response)
            response_parsed = json.loads(response_string[0:-1])

            logger.debug("parsed response: %s", response_parsed)

            contract_response = ContractResponse(self, response_parsed)
        except Exception as e:
            logger.exception('contract response is invalid: ' + str(e))
            raise

        return contract_response
Ejemplo n.º 5
0
class ContractRequest(object):
    __ops__ = {'initialize': True, 'update': True}

    def __init__(self, operation, request_originator_keys, enclave_service,
                 contract, **kwargs):
        if not self.__ops__[operation]:
            raise ValueError('invalid operation')

        self.operation = operation

        self.contract_id = contract.contract_id
        self.creator_id = contract.creator_id
        self.encrypted_state_encryption_key = contract.get_state_encryption_key(
            enclave_service.enclave_id)
        self.enclave_service = enclave_service
        self.originator_keys = request_originator_keys
        self.channel_keys = keys.TransactionKeys()
        self.session_key = crypto.SKENC_GenerateKey()

        self.contract_code = contract.contract_code
        self.contract_state = contract.contract_state
        self.message = ContractMessage(self.originator_keys, self.channel_keys,
                                       **kwargs)

    @property
    def enclave_keys(self):
        return self.enclave_service.enclave_keys

    @property
    def session_iv(self):
        return crypto.SKENC_GenerateIV(self.enclave_keys.identity)

    def __serialize_for_encryption(self):
        result = dict()
        result['Operation'] = self.operation
        result['ContractID'] = self.contract_id
        result['CreatorID'] = self.creator_id
        result[
            'EncryptedStateEncryptionKey'] = self.encrypted_state_encryption_key

        result['ContractState'] = self.contract_state.serialize()
        result['ContractCode'] = self.contract_code.serialize()
        result['ContractMessage'] = self.message.serialize()

        return json.dumps(result)

    def __encrypt_session_key(self):
        encrypted_key = self.enclave_keys.encrypt(self.session_key)
        return crypto.byte_array_to_base64(encrypted_key)

    def __encrypt_request(self):
        serialized_byte_array = crypto.string_to_byte_array(
            self.__serialize_for_encryption())
        encrypted_request = crypto.SKENC_EncryptMessage(
            self.session_key, self.session_iv, serialized_byte_array)
        return crypto.byte_array_to_base64(encrypted_request)

    # response -- base64 encode, response encrypted with session key
    def __decrypt_response(self, response):
        decoded_response = crypto.base64_to_byte_array(response)
        return crypto.SKENC_DecryptMessage(self.session_key, self.session_iv,
                                           decoded_response)

    # enclave_service -- enclave service wrapper object
    def evaluate(self):
        encrypted_session_key = self.__encrypt_session_key()
        encrypted_request = self.__encrypt_request()

        try:
            encoded_encrypted_response = self.enclave_service.send_to_contract(
                encrypted_session_key, encrypted_request)
            assert encoded_encrypted_response

            logger.debug("raw response from enclave: %s",
                         encoded_encrypted_response)
        except:
            logger.exception('contract invocation failed')
            raise

        try:
            decrypted_response = self.__decrypt_response(
                encoded_encrypted_response)
            response_string = crypto.byte_array_to_string(decrypted_response)
            response_parsed = json.loads(response_string[0:-1])

            logger.debug("parsed response: %s", response_parsed)

            contract_response = ContractResponse(self, response_parsed)
        except:
            logger.exception('contract response is invalid')
            raise

        return contract_response
Ejemplo n.º 6
0
class UpdateStateRequest(ContractRequest) :
    # -------------------------------------------------------
    def __init__(self, operation, request_originator_keys, contract, **kwargs) :
        super().__init__(request_originator_keys, contract, **kwargs)

        if not self.__ops__[operation] :
            raise ValueError('invalid operation')

        self.operation = operation
        self.contract_code = contract.contract_code
        self.contract_state = contract.contract_state
        self.message = ContractMessage(self.originator_keys, self.channel_id, **kwargs)

    # -------------------------------------------------------
    def __serialize_for_encryption(self) :
        result = dict()
        result['ContractID'] = self.contract_id
        result['CreatorID'] = self.creator_id
        result['EncryptedStateEncryptionKey'] = self.encrypted_state_encryption_key

        result['ContractCodeHash'] = self.contract_code.compute_hash(encoding='b64')
        result['ContractStateHash'] = self.contract_state.get_state_hash(encoding='b64')

        result['ContractMessage'] = self.message.serialize()

        return json.dumps(result)

    # -------------------------------------------------------
    def evaluate(self) :
        """
        evaluate the request using the enclave service
        """

        assert self.operation == 'update'

        # Encrypt the request
        serialized_byte_array = crypto.string_to_byte_array(self.__serialize_for_encryption())
        encrypted_request = bytes(crypto.SKENC_EncryptMessage(self.session_key, serialized_byte_array))
        encrypted_key = bytes(self.enclave_keys.encrypt(self.session_key))

        try :
            self.contract_state.push_state_to_eservice(self.enclave_service)
            encrypted_response = self.enclave_service.send_to_contract(encrypted_key, encrypted_request)

        except Exception as e:
            logger.warn('contract invocation failed; %s', str(e))
            raise InvocationException('contract invocation failed') from e

        try :
            decrypted_response = crypto.SKENC_DecryptMessage(self.session_key, encrypted_response)
        except Exception as e:
            logger.exception('failed to decrypt response; %s', encrypted_response)
            raise InvocationException('contract response cannot be decrypted')

        try :
            response_string = crypto.byte_array_to_string(decrypted_response)
            response_parsed = json.loads(response_string[0:-1])

            logger.debug("parsed response: %s", response_parsed)

        except Exception as e:
            logger.exception('contract response is invalid; %s', str(e))
            raise InvocationException('failed to parse contract response') from e

        # if response_parsed['Status'] is False :
        #   raise InvocationException(response_parsed['InvocationResponse'])

        try :
            if response_parsed['Status'] and response_parsed['StateChanged'] :
                contract_response = UpdateStateResponse(self, response_parsed)
            else :
                contract_response = ContractResponse(self, response_parsed)
        except Exception as e:
            logger.exception('contract response is invalid; %s', str(e))
            raise InvocationException('contract response is invalid') from e

        return contract_response
Ejemplo n.º 7
0
class ContractRequest(object) :
    __ops__ = { 'initialize' : True, 'update' : True }

    # -------------------------------------------------------
    def __init__(self, operation, request_originator_keys, enclave_service, contract, **kwargs) :
        if not self.__ops__[operation] :
            raise ValueError('invalid operation')

        self.operation = operation

        self.contract_id = contract.contract_id
        self.creator_id = contract.creator_id
        self.encrypted_state_encryption_key = contract.get_state_encryption_key(enclave_service.enclave_id)
        self.enclave_service = enclave_service
        self.originator_keys = request_originator_keys
        self.channel_keys = keys.TransactionKeys()
        self.session_key = crypto.SKENC_GenerateKey()

        self.contract_code = contract.contract_code
        self.contract_state = contract.contract_state
        self.message = ContractMessage(self.originator_keys, self.channel_keys, **kwargs)

    # -------------------------------------------------------
    @property
    def enclave_keys(self) :
        return self.enclave_service.enclave_keys

    # -------------------------------------------------------
    def __serialize_for_encryption(self) :
        result = dict()
        result['Operation'] = self.operation
        result['ContractID'] = self.contract_id
        result['CreatorID'] = self.creator_id
        result['EncryptedStateEncryptionKey'] = self.encrypted_state_encryption_key

        result['ContractState'] = self.contract_state.serialize_for_invocation()
        result['ContractCode'] = self.contract_code.serialize()
        result['ContractMessage'] = self.message.serialize()

        return json.dumps(result)

    # -------------------------------------------------------
    def __encrypt_session_key(self) :
        encrypted_key = self.enclave_keys.encrypt(self.session_key)
        return crypto.byte_array_to_base64(encrypted_key)

    # -------------------------------------------------------
    def __decrypt_response(self, response) :
        """
        decrypt the response using the session key

        :param response string: base64 encoded, encrypted with session key
        """
        decoded_response = crypto.base64_to_byte_array(response)
        return crypto.SKENC_DecryptMessage(self.session_key, decoded_response)

    # -------------------------------------------------------
    def evaluate(self) :
        """
        evaluate the request using the enclave service
        """
        encrypted_session_key = self.__encrypt_session_key()

        # Encrypt the request
        serialized_byte_array = crypto.string_to_byte_array(self.__serialize_for_encryption())
        encrypted_request_raw = crypto.SKENC_EncryptMessage(self.session_key, serialized_byte_array)
        encrypted_request = crypto.byte_array_to_base64(encrypted_request_raw)

        try :
            self.contract_state.push_state_to_eservice(self.enclave_service)

            encoded_encrypted_response = self.enclave_service.send_to_contract(encrypted_session_key, encrypted_request)
            logger.debug("raw response from enclave: %s", encoded_encrypted_response)

        except Exception as e:
            logger.warn('contract invocation failed; %s', str(e))
            raise InvocationException('contract invocation failed') from e

        try :
            decrypted_response = self.__decrypt_response(encoded_encrypted_response)
            response_string = crypto.byte_array_to_string(decrypted_response)
            response_parsed = json.loads(response_string[0:-1])

            logger.debug("parsed response: %s", response_parsed)

            contract_response = ContractResponse(self, response_parsed)
        except Exception as e:
            logger.warn('contract response is invalid; %s', str(e))
            raise InvocationException('contract response is invalid') from e

        return contract_response
Ejemplo n.º 8
0
class ContractRequest(object):
    __ops__ = {'initialize': True, 'update': True}

    # a monotonic counter used locally by the client to identify all its
    # requests. every (contract_id, statehash) pair maps to a unique
    # request_number. the converse is not true (if the request failed)
    __request_number__ = 0

    # -------------------------------------------------------
    def __init__(self, operation, request_originator_keys, contract, **kwargs):
        if not self.__ops__[operation]:
            raise ValueError('invalid operation')

        self.operation = operation
        self.contract_id = contract.contract_id
        self.creator_id = contract.creator_id
        self.enclave_service = kwargs.get('enclave_service')
        if self.enclave_service == 'random':
            enclave_id = random.choice(list(contract.enclave_map.keys()))
            try:  #use the eservice database to get the client
                einfo = eservice_db.get_by_enclave_id(enclave_id)
                self.enclave_service = einfo.client
            except Exception as e:
                raise Exception(
                    'failed to get enclave client using database: %s', str(e))

        self.encrypted_state_encryption_key = contract.get_state_encryption_key(
            self.enclave_service.enclave_id)
        self.originator_keys = request_originator_keys
        self.make_channel_keys()
        self.session_key = crypto.SKENC_GenerateKey()
        self.contract_code = contract.contract_code
        self.contract_state = contract.contract_state
        self.message = ContractMessage(self.originator_keys, self.channel_id,
                                       **kwargs)
        self.replication_params = contract.replication_params
        self.request_number = ContractRequest.__request_number__
        ContractRequest.__request_number__ += 1

    # -------------------------------------------------------
    def make_channel_keys(self, ledger_type=os.environ.get('PDO_LEDGER_TYPE')):
        if ledger_type == 'sawtooth':
            self.channel_keys = keys.TransactionKeys()
            self.channel_id = self.channel_keys.txn_public
        elif ledger_type == 'ccf':
            self.channel_keys = crypto.random_bit_string(64)  # byte array
            self.channel_id = crypto.byte_array_to_base64(
                crypto.compute_message_hash(self.channel_keys))
        else:
            raise Exception(
                "Invalid Ledger Type. Must be either sawtooth or ccf.")

    # -------------------------------------------------------
    @property
    def enclave_keys(self):
        return self.enclave_service.enclave_keys

    # -------------------------------------------------------
    def __serialize_for_encryption(self):
        result = dict()
        result['Operation'] = self.operation
        result['ContractID'] = self.contract_id
        result['CreatorID'] = self.creator_id
        result[
            'EncryptedStateEncryptionKey'] = self.encrypted_state_encryption_key

        if self.operation == 'initialize':
            result['ContractCode'] = self.contract_code.serialize()
        else:
            result['ContractCodeHash'] = self.contract_code.compute_hash(
                encoding='b64')
            result['ContractStateHash'] = self.contract_state.get_state_hash(
                encoding='b64')

        result['ContractMessage'] = self.message.serialize()

        return json.dumps(result)

    # -------------------------------------------------------
    def evaluate(self):
        """
        evaluate the request using the enclave service
        """

        # Encrypt the request
        serialized_byte_array = crypto.string_to_byte_array(
            self.__serialize_for_encryption())
        encrypted_request = bytes(
            crypto.SKENC_EncryptMessage(self.session_key,
                                        serialized_byte_array))
        encrypted_key = bytes(self.enclave_keys.encrypt(self.session_key))

        try:
            self.contract_state.push_state_to_eservice(self.enclave_service)
            encrypted_response = self.enclave_service.send_to_contract(
                encrypted_key, encrypted_request)

        except Exception as e:
            logger.warn('contract invocation failed; %s', str(e))
            raise InvocationException('contract invocation failed') from e

        try:
            decrypted_response = crypto.SKENC_DecryptMessage(
                self.session_key, encrypted_response)
        except Exception as e:
            logger.exception('failed to decrypt response; %s',
                             encrypted_response)
            raise InvocationException('contract response cannot be decrypted')

        try:
            response_string = crypto.byte_array_to_string(decrypted_response)
            response_parsed = json.loads(response_string[0:-1])

            logger.debug("parsed response: %s", response_parsed)

            contract_response = ContractResponse(self, response_parsed)
        except Exception as e:
            logger.exception('contract response is invalid; %s', str(e))
            raise InvocationException('contract response is invalid') from e

        return contract_response