Beispiel #1
0
def __add_enclave_secrets(ledger_config, contract_id, client_keys, enclaveclients, provclients) :
    """Create and provision the encrypted secrets for each of the
    enclaves that will be provisioned for this contract.
    """

    secrets = {}
    encrypted_state_encryption_keys = {}
    for enclaveclient in enclaveclients:
        psecrets = []
        for provclient in provclients:
            # Get a pspk:esecret pair from the provisioning service for each enclave
            sig_payload = pcrypto.string_to_byte_array(enclaveclient.enclave_id + contract_id)
            secretinfo = provclient.get_secret(enclaveclient.enclave_id,
                                               contract_id,
                                               client_keys.verifying_key,
                                               client_keys.sign(sig_payload))
            logger.debug("pservice secretinfo: %s", secretinfo)

            # Add this pspk:esecret pair to the list
            psecrets.append(secretinfo)

        # Print all of the secret pairs generated for this particular enclave
        logger.debug('psecrets for enclave %s : %s', enclaveclient.enclave_id, psecrets)

        # Verify those secrets with the enclave
        esresponse = enclaveclient.verify_secrets(contract_id, client_keys.verifying_key, psecrets)
        logger.debug("verify_secrets response: %s", esresponse)

        # Store the ESEK mapping in a dictionary key'd by the enclave's public key (ID)
        encrypted_state_encryption_keys[enclaveclient.enclave_id] = esresponse['encrypted_state_encryption_key']

        # Add this spefiic enclave to the contract
        add_enclave_to_contract(ledger_config,
                                client_keys,
                                contract_id,
                                enclaveclient.enclave_id,
                                psecrets,
                                esresponse['encrypted_state_encryption_key'],
                                esresponse['signature'])

    return encrypted_state_encryption_keys
def compute_pdo_ccl_signature(verb, private_key, enclave_id, enclave_signature,
                              channel_id, contract_id, creator_public_key_pem,
                              contract_code_hash, message_hash,
                              contract_metadata_hash, current_state_hash,
                              previous_state_hash, dependency_list):

    k = crypto.SIG_PrivateKey(private_key)

    message_byte_array = crypto.string_to_byte_array(enclave_id)
    message_byte_array += crypto.base64_to_byte_array(enclave_signature)
    message_byte_array += crypto.string_to_byte_array(channel_id)
    message_byte_array += crypto.string_to_byte_array(contract_id)
    message_byte_array += crypto.base64_to_byte_array(contract_code_hash)
    message_byte_array += crypto.base64_to_byte_array(message_hash)

    if verb == 'initialize':
        #in ccl initialize, previous state hash and dependencies are supposed to be empty
        message_byte_array += crypto.string_to_byte_array(
            creator_public_key_pem)
        message_byte_array += crypto.base64_to_byte_array(
            contract_metadata_hash)
        message_byte_array += crypto.base64_to_byte_array(current_state_hash)
    else:
        message_byte_array += crypto.base64_to_byte_array(previous_state_hash)
        message_byte_array += crypto.base64_to_byte_array(current_state_hash)
        for d in dependency_list:
            message_byte_array += crypto.string_to_byte_array(d.contract_id)
            message_byte_array += crypto.string_to_byte_array(d.state_hash)
    signature = k.SignMessage(message_byte_array)
    encoded_signature = crypto.byte_array_to_base64(signature)
    logger.debug("signed message string: " +
                 crypto.byte_array_to_base64(message_byte_array))
    logger.debug("signed message hash: " + crypto.byte_array_to_hex(
        crypto.compute_message_hash(message_byte_array)))
    logger.debug("signature: %s", encoded_signature)
    return encoded_signature
 def hashed_identity(self):
     key_byte_array = crypto.string_to_byte_array(self.txn_public)
     hashed_txn_key = crypto.compute_message_hash(key_byte_array)
     encoded_hashed_key = crypto.byte_array_to_hex(hashed_txn_key)
     encoded_hashed_key = encoded_hashed_key.lower()
     return encoded_hashed_key
Beispiel #4
0
 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)
Beispiel #5
0
def CreateAndRegisterContract(config, contract_info, creator_keys):
    ledger_config = config.get('Sawtooth')
    contract_config = config.get('Contract')

    contract_creator_id = creator_keys.identity

    contract_name = contract_info['Name']
    source_file = contract_info['Source']
    search_path = contract_config['SourceSearchPath']
    contract_code = ContractCode.create_from_scheme_file(
        contract_name, source_file, search_path=search_path)

    # --------------------------------------------------
    logger.info('register the contract')
    # --------------------------------------------------
    pservice_urls = contract_info.get("ProvisioningServices")
    provisioning_services = list(
        map(lambda url: ProvisioningServiceClient(url), pservice_urls))
    provisioning_service_keys = list(
        map(lambda svc: svc.identity, provisioning_services))

    contract_id = register_contract(ledger_config, creator_keys, contract_code,
                                    provisioning_service_keys)
    logger.info('registered the contract as %s', contract_id)

    contract_state = ContractState.create_new_state(contract_id)
    contract = Contract(contract_code, contract_state, contract_id,
                        contract_creator_id)

    # --------------------------------------------------
    logger.info('provision enclaves')
    # --------------------------------------------------
    eservice_urls = contract_info.get("EnclaveServices")
    enclave_services = list(
        map(lambda url: GetEnclaveServiceByURL(url), eservice_urls))

    for eservice in enclave_services:
        secret_list = []
        for pservice in provisioning_services:
            message = pcrypto.string_to_byte_array(eservice.enclave_id +
                                                   contract_id)
            signature = creator_keys.sign(message)
            secret = pservice.get_secret(eservice.enclave_id, contract_id,
                                         creator_keys.verifying_key, signature)
            secret_list.append(secret)

        secretinfo = eservice.verify_secrets(contract_id, contract_creator_id,
                                             secret_list)
        encrypted_state_encryption_key = secretinfo[
            'encrypted_state_encryption_key']
        signature = secretinfo['signature']

        txnid = add_enclave_to_contract(ledger_config, creator_keys,
                                        contract_id, eservice.enclave_id,
                                        secret_list,
                                        encrypted_state_encryption_key,
                                        signature)

        contract.set_state_encryption_key(eservice.enclave_id,
                                          encrypted_state_encryption_key)

    # --------------------------------------------------
    logger.info('create the initial contract state')
    # --------------------------------------------------
    eservice = random.choice(enclave_services)
    initialize_request = contract.create_initialize_request(
        creator_keys, eservice)
    initialize_response = initialize_request.evaluate()
    if initialize_response.status is False:
        emessage = initialize_response.result
        logger.warn('initialization for contract %s failed; %s', contract_name,
                    emessage)
        raise Exception('initialization failed; {}'.format(emessage))

    contract.set_state(initialize_response.encrypted_state)

    logger.info('initial state created')

    # --------------------------------------------------
    logger.info('save the initial state in the ledger')
    # --------------------------------------------------
    txnid = initialize_response.submit_initialize_transaction(ledger_config,
                                                              wait=30)

    return contract
Beispiel #6
0
    def _secretreq(self, minfo):
        # unpack the request
        try:
            enclave_id = minfo['enclave_id']
            contract_id = minfo['contract_id']
            opk = minfo['opk']
            signature = minfo['signature']

        except KeyError as ke:
            raise Error(http.BAD_REQUEST,
                        'missing required field {0}'.format(ke))

        logger.debug('request for key for contract %s, enclave %s',
                     contract_id, enclave_id)

        # verify the signature, that is, make sure that the request was really signed by opk
        try:
            opkkey = pcrypto.SIG_PublicKey(opk)
            opkkey.VerifySignature(
                pcrypto.string_to_byte_array(enclave_id + contract_id),
                pcrypto.hex_to_byte_array(signature))
        except:
            logger.warn("Signature verification failed")
            raise Error(http.BAD_REQUEST, 'Signature Mismatch')

        # Get enclave state
        try:
            logger.debug('retrieve information for enclave %s', enclave_id)
            enclave_info = self.__registry_helper.get_enclave_info(enclave_id)
            logger.debug("enclave information retrieved: %s", enclave_info)
        except Exception as err:
            logger.error(
                'exception occurred when getting ledger information for enclave %s; %s',
                enclave_id, str(err))
            raise Exception(
                'could not retrieve enclave state; {0}'.format(err))

        # Get contract state
        try:
            logger.debug('retrieve information for contract <%s>', contract_id)
            contract_info = self.__registry_helper.get_contract_info(
                contract_id)
            logger.debug("contract_info from ledger: %s", contract_info)
        except Exception as err:
            logger.error(
                'exception occurred when getting ledger information for contract %s; %s',
                contract_id, str(err))
            raise Exception(
                'could not retrieve contract state; {0}'.format(err))

        # make sure that the signer of this request is really the owner of the contract
        try:
            # make sure that the signer of this request is really the owner of the contract
            # PdoContractInfo.pdo_contract_creator_pem_key is the VerifyingKey
            logger.debug("Contract creator's public key: %s",
                         contract_info['pdo_contract_creator_pem_key'])
            logger.debug("Expected public key: %s", opk)
            assert contract_info['pdo_contract_creator_pem_key'] == opk
        except:
            logger.error(
                'request to create secret did not come from the contract owner; %s != %s',
                contracttxn.OriginatorID, opk)
            raise Error(http.NOT_ALLOWED,
                        'operation not allowed for {0}'.format(opk))

        # make sure the provisioning service is allowed to access contract by the checking the list of allowed provisioning services
        try:
            logger.debug("Contract allowed service ids: %s",
                         contract_info['provisioning_service_ids'])
            logger.debug("Expected provisioning service id: %s", self.PSPK)
            assert self.PSPK in contract_info['provisioning_service_ids']
        except:
            logger.error(
                'This Pservice is not the list of allowed provisioning services, PSerivce ID: %s',
                self.PSPK)
            raise Error(http.NOT_ALLOWED,
                        'operation not allowed for {0}'.format(self.PSPK))

        # retrieve the sealed secret
        sealed_secret = self._GetContractSecret(contract_id)

        logger.debug("Enclave Info: %s", str(enclave_info))

        # Generate Secret for Contract Enclave, signs unsealed secret with contract enclave encryption key
        esecret = self.Enclave.generate_enclave_secret(
            self.SealedData,
            sealed_secret,
            contract_id,
            opk,
            json.dumps(enclave_info),
        )["enclave_secret"]

        logger.debug("Encrypted secret for contract %s: %s", contract_id,
                     esecret)

        # create the response
        response = dict()
        response['pspk'] = self.PSPK
        response['encrypted_secret'] = esecret

        logger.info('created secret for contract %s and enclave %s',
                    contract_id, enclave_id)
        return response
Beispiel #7
0
    def _secretreq(self, minfo):
        # unpack the request
        try:
            enclave_id = minfo['enclave_id']
            contract_id = minfo['contract_id']
            opk = minfo['opk']
            signature = minfo['signature']

        except KeyError as ke:
            raise Error(http.BAD_REQUEST,
                        'missing required field {0}'.format(ke))

        logger.debug('request for key for contract %s, enclave %s',
                     contract_id, enclave_id)

        # verify the signature, that is, make sure that the request was really signed by opk
        try:
            opkkey = pcrypto.SIG_PublicKey(opk)
            opkkey.VerifySignature(
                pcrypto.string_to_byte_array(enclave_id + contract_id),
                pcrypto.hex_to_byte_array(signature))
        except:
            logger.warn("Signature verification failed")
            raise Error(http.BAD_REQUEST, 'Signature Mismatch')

        # Get enclave state
        try:
            logger.debug('retrieve information for enclave %s', enclave_id)
            enclave_info = self.__registry_helper.get_enclave_dict(enclave_id)
            logger.debug("enclave information retrieved: %s", enclave_info)
        except BaseException as err:
            logger.warn(
                'exception occurred when getting ledger information for enclave %s; %s',
                enclave_id, str(err))
            raise Error(http.BAD_REQUEST,
                        'could not retrieve enclave state; {0}'.format(err))
        except ClientConnectException as err:
            logger.warn(
                'client exception occurred when getting ledger information for enclave %s; %s',
                enclave_id, str(err))
            raise Error(http.BAD_REQUEST,
                        'could not retrieve enclave state; {0}'.format(err))

        # Get contract state
        try:
            logger.debug('retrieve information for contract <%s>', contract_id)
            contract_info = self.__registry_helper.get_contract_dict(
                contract_id)
            logger.debug("contract_info from ledger: %s", contract_info)
        except BaseException as err:
            logger.warn(
                'exception occurred when getting ledger information for contract %s; %s',
                contract_id, str(err))
            raise Error(http.BAD_REQUEST,
                        'could not retrieve contract state; {0}'.format(err))
        except ClientConnectException as err:
            logger.warn(
                'client exception occurred when getting ledger information for contract %s; %s',
                contract_id, str(err))
            raise Error(http.BAD_REQUEST,
                        'could not retrieve contract state; {0}'.format(err))

        # make sure that the signer of this request is really the owner of the contract
        try:
            # make sure that the signer of this request is really the owner of the contract
            # PdoContractInfo.pdo_contract_creator_pem_key is the VerifyingKey
            logger.debug("Contract creator's public key: %s",
                         contract_info['pdo_contract_creator_pem_key'])
            logger.debug("Expected public key: %s", opk)
            assert contract_info['pdo_contract_creator_pem_key'] == opk
        except:
            logger.error(
                'request to create secret did not come from the contract owner; %s != %s',
                contracttxn.OriginatorID, opk)
            raise Error(http.NOT_ALLOWED,
                        'operation not allowed for {0}'.format(opk))

        # make sure the provisioning service is allowed to access contract by the checking the list of allowed provisioning services
        try:
            logger.debug("Contract allowed service ids: %s",
                         contract_info['provisioning_service_ids'])
            logger.debug("Expected provisioning service id: %s",
                         self.PSPK.Serialize())
            assert self.PSPK.Serialize(
            ) in contract_info['provisioning_service_ids']
        except:
            logger.error(
                'This Pservice is not the list of allowed provisioning services, PSerivce ID: %s',
                self.PSPK.Serialize())
            raise Error(
                http.NOT_ALLOWED,
                'operation not allowed for {0}'.format(self.PSPK.Serialize()))

        # retrieve the secret
        secret = self._GetContractSecret(contract_id)

        # create the signature
        message = secret + enclave_id + contract_id + opk
        secretsig = pcrypto.byte_array_to_hex(
            self.SigningKey.SignMessage(pcrypto.string_to_byte_array(message)))

        # pad secret to required max size
        # TODO: Eventually this requirement needs to be fixed in the crypto library itself
        required_padding = 2 * pcrypto.MAX_SIG_SIZE - len(secretsig)
        secretsig = secretsig + ('0' * required_padding)

        enclavekey = pcrypto.PKENC_PublicKey(enclave_info['encryption_key'])
        esecret = pcrypto.byte_array_to_base64(
            enclavekey.EncryptMessage(
                pcrypto.string_to_byte_array(secret + secretsig)))

        logger.debug("Encrypted secret for contract %s: %s", contract_id,
                     esecret)

        # create the response
        response = dict()
        response['pspk'] = self.PSPK.Serialize()
        response['encrypted_secret'] = esecret

        logger.info('created secret for contract %s and enclave %s',
                    contract_id, enclave_id)
        return response
 def compute_hash(self):
     return crypto.compute_message_hash(
         crypto.string_to_byte_array(self.serialize_for_hash()))