class JRPCWorkerRegistryImpl(WorkerRegistry):
    """
    This class is to read the worker registry to get the more details
    of worker.
    """
    def __init__(self, config):
        self.__uri_client = HttpJrpcClient(config["tcf"]["json_rpc_uri"])

    def worker_retrieve(self, worker_id, id=None):
        """
        Retrieve the worker identified by worker ID.

        Parameters:
        worker_id Worker ID value derived from the worker's DID
        id        Optional Optional JSON RPC request ID

        Returns:
        JRPC response containing:
        organization ID, application ID, worker status,
        and worker details.
        """

        json_rpc_request = {
            "jsonrpc": "2.0",
            "method": "WorkerRetrieve",
            "id": id,
            "params": {
                "workerId": worker_id
            }
        }
        response = self.__uri_client._postmsg(json.dumps(json_rpc_request))
        return response

    def worker_lookup(self,
                      worker_type=None,
                      organization_id=None,
                      application_type_id=None,
                      id=None):
        """
        Worker lookup based on worker type, organization ID,
        and application ID.
        All fields are optional and, if present, condition should match for
        all fields. If none are passed it should return all workers.

        Parameters:
        worker_type         Optional characteristic of Workers for which you
                            may wish to search. Currently defined types are:
                            * "TEE-SGX": an Intel SGX Trusted Execution
                              Environment
                            * "MPC": Multi-Party Compute
                            * "ZK": Zero-Knowledge
        organization_id     Optional parameter representing the
                            organization that hosts the Worker,
                            e.g. a bank in the consortium or
                            anonymous entity
        application_type_id Optional application type that has to be supported
                            by the worker
        id                  Optional Optional JSON RPC request ID


        Returns:
        JRPC response containing number of workers,
        lookup tag, and list of worker IDs.
        """
        json_rpc_request = {
            "jsonrpc": "2.0",
            "method": "WorkerLookUp",
            "id": id,
            "params": {}
        }

        if worker_type is not None:
            json_rpc_request["params"]["workerType"] = worker_type.value

        if organization_id is not None:
            json_rpc_request["params"]["organizationId"] = organization_id

        if application_type_id is not None:
            json_rpc_request["params"]["applicationTypeId"] = \
                application_type_id

        response = self.__uri_client._postmsg(json.dumps(json_rpc_request))
        return response

    def worker_lookup_next(self,
                           lookup_tag,
                           worker_type=None,
                           organization_id=None,
                           application_type_id=None,
                           id=None):
        """
        Retrieve subsequent Worker lookup results based on worker type,
        organization ID, and application ID.
        Similar to workerLookUp with additional parameter lookup_tag.

        Parameters:
        lookup_tag          Used to lookup subsequent results after calling
                            worker_lookup
        worker_type         Optional characteristic of Workers for which you
                            may wish to search. Currently defined types are:
                            * "TEE-SGX": an Intel SGX Trusted Execution
                              Environment
                            * "MPC": Multi-Party Compute
                            * "ZK": Zero-Knowledge
        organization_id     Optional parameter representing the
                            organization that hosts the Worker,
                            e.g. a bank in the consortium or
                            anonymous entity
        application_type_id Optional application type that has to be supported
                            by the worker
        id                  Optional Optional JSON RPC request ID

        Returns:
        JRPC response containing number of workers,
        lookup tag, and list of worker IDs.
        """

        json_rpc_request = {
            "jsonrpc": "2.0",
            "method": "WorkerLookUpNext",
            "id": id,
            "params": {
                "lookUpTag": lookup_tag
            }
        }

        if worker_type is not None:
            json_rpc_request["params"]["workerType"] = worker_type.value

        if organization_id is not None:
            json_rpc_request["params"]["organizationId"] = organization_id

        if application_type_id is not None:
            json_rpc_request["params"]["applicationTypeId"] = \
                application_type_id

        response = self.__uri_client._postmsg(json.dumps(json_rpc_request))
        return response

    def worker_register(self,
                        worker_id,
                        worker_type,
                        org_id,
                        application_type_ids,
                        details,
                        id=None):
        """
        Adds worker details to registry

        Parameters:
        worker_id            Worker ID value derived from the worker's DID
        worker_type          Type of Worker. Currently defined types are:
                             * "TEE-SGX": an Intel SGX Trusted Execution
                               Environment
                             * "MPC": Multi-Party Compute
                             * "ZK": Zero-Knowledge
        org_id               Organization that hosts the Worker,
                             e.g. a bank in the consortium or
                             anonymous entity
        application_type_ids Application types supported by the worker
        id                   Optional JSON RPC request ID

        Returns:
        JRPC response with worker registry status.
        """
        json_rpc_request = {
            "jsonrpc": "2.0",
            "method": "WorkerRegister",
            "id": id,
            "params": {
                "workerId": worker_id,
                "workerType": worker_type.value,
                "organizationId": org_id,
                "applicationTypeId": application_type_ids,
                "details": details
            }
        }
        response = self.__uri_client._postmsg(json.dumps(json_rpc_request))
        return response

    def worker_update(self, worker_id, details, id=None):
        """
        Update worker with new information.

        Parameters:
        worker_id Worker ID value derived from the worker's DID
        details   Detailed information about the worker in
                  JSON RPC format as defined in
        id        Optional JSON RPC request ID

        Returns:
        JRPC response with update status.
        """
        json_rpc_request = {
            "jsonrpc": "2.0",
            "method": "WorkerUpdate",
            "id": id,
            "params": {
                "workerId": worker_id,
                "details": details
            }
        }
        response = self.__uri_client._postmsg(json.dumps(json_rpc_request))
        return response

    def worker_set_status(self, worker_id, status, id=None):
        """
        Set the worker status to active, offline,
        decommissioned, or compromised state.

        Parameters:
        worker_id  Worker ID value derived from the worker's DID
        status     Worker status value to set
        id         Optional JSON RPC request ID

        Returns:
        JRPC response with status.
        """
        json_rpc_request = {
            "jsonrpc": "2.0",
            "method": "WorkerSetStatus",
            "id": id,
            "params": {
                "workerId": worker_id,
                "status": status.value
            }
        }
        response = self.__uri_client._postmsg(json.dumps(json_rpc_request))
        return response
Esempio n. 2
0
class WPERequester():
    """
    JRPC requester acting on behalf of WorkOrderProcessorEnclaveManager
    """
    def __init__(self, config):
        """
        Constructor for WPERequester. Initialize the HTTP jrpc client.
        Parameters :
            @param config - dict of config read
        """
        self._uri_client = HttpJrpcClient(
            config["KMEListener"]["kme_listener_url"])
        self._conn_retries = config["KMEListener"]["connection_retry"]
        worker_id = config.get("WorkerConfig")["worker_id"]
        # Calculate sha256 of worker id to get 32 bytes. The TC spec proxy
        # model contracts expect byte32. Then take a hexdigest for hex str.
        worker_id = hashlib.sha256(worker_id.encode("UTF-8")).hexdigest()
        if config.get("KvStorage") is None:
            logger.error("Kv Storage path is missing")
            sys.exit(-1)
        try:
            kv_helper = connector.open(config['KvStorage']['remote_url'])
        except Exception as err:
            logger.error("Failed to open KV storage interface; " +
                         "exiting Intel SGX Enclave manager: {}".format(err))
            sys.exit(-1)
        worker_kv_delegate = WorkerKVDelegate(kv_helper)
        self._worker = worker_kv_delegate.get_worker_by_id(worker_id)
        jrpc_methods = {}
        jrpc_methods["kme-uid"] = "GetUniqueVerificationKey"
        jrpc_methods["kme-reg"] = "RegisterWorkOrderProcessor"
        jrpc_methods["kme-preprocess"] = "PreProcessWorkOrder"
        # Map too hold workload-id to JRPC method mapping
        self._jrpc_methods = jrpc_methods

    def get_unique_verification_key(self, verification_key_nonce):
        """
        Request wrapper to get a unique id from the KME

        Parameters :
            @param verification_key_nonce - Random nonce generated by this WPE
        Returns :
            @returns result - Result received from the KME which includes the
                              public verification key which is supposed to be
                              included in REPORTDATA by the WPE. None, in case
                              of failure.
        """
        workload_id = "kme-uid"
        in_data = [verification_key_nonce]

        # Create session key and iv to sign work order request
        session_key = crypto_utils.generate_key()
        session_iv = crypto_utils.generate_iv()

        wo_req = self._construct_wo_req(in_data, workload_id,
                                        self._worker.encryption_key,
                                        session_key, session_iv)

        response = self._post_and_get_result(wo_req)

        if "result" in response:
            wo_response_json = response["result"]
            if self._verify_res_signature(wo_response_json,
                                          self._worker.verification_key,
                                          wo_req["params"]["requesterNonce"]):
                decrypted_res = crypto_utils.decrypted_response(
                    wo_response_json, session_key, session_iv)
                # Response contains an array of results. In this case, the
                # array has single element and the data field is of interest.
                # The data contains result,verification_key and
                # verification_key_signature delimited by ' '.
                # @TODO : Update to use multiple out_data fields.
                return decrypted_res[0]['data']
            return None
        else:
            logger.error(
                "Could not get a unique id from the KME : {}".format(response))
            return None

    def register_wo_processor(self, unique_verification_id, encryption_key,
                              proof_data, mr_enclave):
        """
        Request to register this WPE with the KME

        Parameters :
            @param unique_verification_id - Unique verifying key received from
            KME.
            @param encryption_key - encryption key of WPE
            @param proof_data - The IAS attestation report/DCAP quote
            @param mr_enclave - MRENCLAVE for this WPE
        Returns :
            @returns status - The status of the registration.
                              True, for success. None, in case of errors.
        """
        workload_id = "kme-reg"
        registration_params = {
            "unique_id": unique_verification_id,
            "proof_data": proof_data,
            "wpe_encryption_key": encryption_key,
            "mr_enclave": mr_enclave
        }
        in_data = [json.dumps(registration_params)]

        # Create session key and iv to sign work order request
        session_key = crypto_utils.generate_key()
        session_iv = crypto_utils.generate_iv()

        wo_req = self._construct_wo_req(in_data, workload_id,
                                        self._worker.encryption_key,
                                        session_key, session_iv)

        response = self._post_and_get_result(wo_req)

        if "result" in response:
            wo_response_json = response["result"]
            if "error" not in wo_response_json and self._verify_res_signature(
                    wo_response_json, self._worker.verification_key,
                    wo_req["params"]["requesterNonce"]):
                decrypted_res = crypto_utils.decrypted_response(
                    wo_response_json, session_key, session_iv)
                # Response contains an array of results. In this case, the
                # array has single element and the data field is of interest.
                # It is integer with status of registration.
                return decrypted_res[0]['data']
            return None
        else:
            logger.error(
                "Could not register this WPE with the KME : {}".format(
                    response))
            return None

    def preprocess_work_order(self, wo_request, encryption_key):
        """
        Request to preprocess a work order

        Parameters :
            @param wo_request - The original work order request as str
            @param encryption_key - WPE's public encryption key
        Returns :
            @returns result - Result from KME that includes the workorder
                              key info. error response, in case of failure.
        """
        workload_id = "kme-preprocess"
        in_data = [wo_request, encryption_key]

        # Create session key and iv to sign work order request
        session_key = crypto_utils.generate_key()
        session_iv = crypto_utils.generate_iv()

        wo_req = self._construct_wo_req(in_data, workload_id,
                                        self._worker.encryption_key,
                                        session_key, session_iv)

        response = self._post_and_get_result(wo_req)

        if "result" in response:
            wo_response_json = response["result"]
            if self._verify_res_signature(wo_response_json,
                                          self._worker.verification_key,
                                          wo_req["params"]["requesterNonce"]):
                decrypted_res = crypto_utils.decrypted_response(
                    wo_response_json, session_key, session_iv)
                # Response contains an array of results. In this case, the
                # array has single element and the data field is of interest.
                return decrypted_res[0]['data']
            return None
        else:
            logger.error(
                "Could not preprocess work order at KME : {}".format(response))
            return response

    def _construct_wo_req(self, in_data, workload_id, encryption_key,
                          session_key, session_iv):
        """
        Construct the parameters for a standard work order request

        Parameters :
            @param in_data - List of data to be passed to workload processor
            @param workload_id - Id of the target workload
            @encryption_key - Worker encryption key
            @session_key - Session key to be embedded in request
            @session_iv - Session key iv for encryption algorithm
        Returns :
            @returns A json request prepared using parameters passed
        """
        # Create work order
        # Convert workloadId to hex
        workload_id_hex = workload_id.encode("UTF-8").hex()
        work_order_id = secrets.token_hex(32)
        requester_id = secrets.token_hex(32)
        requester_nonce = secrets.token_hex(16)
        # worker id is not known here. Hence passing a random string
        worker_id = secrets.token_hex(32)
        # Create work order params
        wo_params = WorkOrderParams(work_order_id,
                                    worker_id,
                                    workload_id_hex,
                                    requester_id,
                                    session_key,
                                    session_iv,
                                    requester_nonce,
                                    result_uri=" ",
                                    notify_uri=" ",
                                    worker_encryption_key=encryption_key,
                                    data_encryption_algorithm="AES-GCM-256")
        for value in in_data:
            wo_params.add_in_data(value)

        # Encrypt work order request hash
        wo_params.add_encrypted_request_hash()

        return {
            "jsonrpc": "2.0",
            "id": random.randint(0, 100000),
            "params": json.loads(wo_params.to_string()),
            "method": self._jrpc_methods[workload_id]
        }

    def _verify_res_signature(self, work_order_res, worker_verification_key,
                              requester_nonce):
        """
        Verify work order result signature

        Parameters :
            @param work_order_res - Result from work order response
            @param worker_verification_key - Worker verification key
            @param requester_nonce - requester generated nonce in work
            order request
        Returns :
            @returns True - If verification succeeds
                    False - If verification fails
        """
        sig_obj = signature.ClientSignature()
        status = sig_obj.verify_signature(work_order_res,
                                          worker_verification_key,
                                          requester_nonce)
        if status == SignatureStatus.PASSED:
            logger.info("Signature verification successful")
        else:
            logger.error("Signature verification failed")
            return False
        return True

    def _post_and_get_result(self, json_rpc_request):
        """
        Helper method to serialize and send JRPC request and get response
        from the KME.

        Parameters :
            @param json_rpc_request - JSON containing RPC request
        Returns :
            @returns response - Response received from the KME
        """
        json_request_str = json.dumps(json_rpc_request)
        logger.info("Request to KME listener %s", json_request_str)
        try:
            # Attempt to post request could fail if KME yet to be ready to
            # receive requests. Hence pass in the number of retries(>1)
            # to post a request.
            response = self._uri_client._postmsg(json_request_str,
                                                 self._conn_retries)
        except Exception as err:
            logger.error("Exception occured in communication with KME")
            raise err
        logger.info("Response from KME %s", response)

        return response
Esempio n. 3
0
def local_main(config):
    if not input_json_str and not input_json_dir:
        LOGGER.error("JSON input file is not provided")
        exit(1)

    if not output_json_file_name:
        LOGGER.error("JSON output file is not provided")
        exit(1)

    if not server_uri:
        LOGGER.error("Server URI is not provided")
        exit(1)

    LOGGER.info("Execute work order")
    uri_client = HttpJrpcClient(server_uri)
    response = None
    wo_id = None
    if input_json_dir:
        directory = os.fsencode(input_json_dir)
        files = os.listdir(directory)

        for file in sorted(files):
            LOGGER.info("---------------- Input file name: %s -------------\n",
                        file.decode("utf-8"))
            input_json_str1 = futils.read_json_file(
                (directory.decode("utf-8") + file.decode("utf-8")))
            # -----------------------------------------------------------------

            # If Client request is WorkOrderSubmit, a requester payload's
            # signature with the requester private signing key is generated.
            if "WorkOrderSubmit" in input_json_str1:
                # Update workOrderId , workerId and workloadId
                input_json_obj = json.loads(input_json_str1)
                wo_id = hex(random.randint(1, 2**64 - 1))
                input_json_obj["params"]["workOrderId"] = wo_id
                input_json_obj["params"]["workerId"] = worker_obj.worker_id
                # Convert workloadId to a hex string and update the request
                workload_id = input_json_obj["params"]["workloadId"]
                workload_id_hex = workload_id.encode("UTF-8").hex()
                input_json_obj["params"]["workloadId"] = workload_id_hex
                input_json_str1 = json.dumps(input_json_obj)

                # Generate session iv an encrypted session key
                session_iv = enclave_helper.generate_iv()
                session_key = enclave_helper.generate_key()
                encrypted_session_key = enclave_helper.generate_encrypted_key(
                    session_key, worker_obj.encryption_key)

                input_json_str1, status = sig_obj.generate_client_signature(
                    input_json_str1, worker_obj, private_key, session_key,
                    session_iv, encrypted_session_key)
                if status != SignatureStatus.PASSED:
                    LOGGER.info("Generate signature failed\n")
                    exit(1)
                if input_json_str1 is None:
                    continue
            # -----------------------------------------------------------------

            # Update the worker ID
            if response:
                if "workerId" in input_json_str1:
                    # Retrieve the worker id from the "WorkerRetrieve"
                    # response and update the worker id information for
                    # further json requests.
                    if "result" in response and \
                            "ids" in response["result"].keys():
                        input_json_final = json.loads(input_json_str1)
                        worker_id = response["result"]["ids"][0]
                        input_json_final["params"]["workerId"] = worker_id
                        input_json_str1 = json.dumps(input_json_final)
                        LOGGER.info(
                            "********** Worker details Updated with "
                            "Worker ID*********\n%s\n", input_json_str1)

            # -----------------------------------------------------------------
            if "WorkOrderGetResult" in input_json_str1 or \
                    "WorkOrderReceiptRetrieve":
                input_json_obj = json.loads(input_json_str1)
                input_json_obj["params"]["workOrderId"] = wo_id
                input_json_str1 = json.dumps(input_json_obj)

            LOGGER.info("*********Request Json********* \n%s\n",
                        input_json_str1)
            response = uri_client._postmsg(input_json_str1)
            LOGGER.info("**********Received Response*********\n%s\n", response)

            # -----------------------------------------------------------------

            # Worker details are loaded into Worker_Obj
            if "WorkerRetrieve" in input_json_str1 and "result" in response:
                worker_obj.load_worker(response["result"]["details"])
            # -----------------------------------------------------------------

            # Poll for "WorkOrderGetResult" and break when you get the result
            while ("WorkOrderGetResult" in input_json_str1
                   and "result" not in response):
                if response["error"]["code"] != WorkOrderStatus.PENDING:
                    break
                response = uri_client._postmsg(input_json_str1)
                LOGGER.info("Received Response: %s, \n \n ", response)
                time.sleep(3)

            # -----------------------------------------------------------------

            # Verify the signature
            if "WorkOrderGetResult" in input_json_str1:
                if "error" in response:
                    # Response has error, hence skip Signature verification
                    LOGGER.info("Work order response has error; "
                                "skipping signature verification")
                    continue
                sig_bool = sig_obj.verify_signature(
                    response['result'], worker_obj.verification_key)
                try:
                    if sig_bool > 0:
                        LOGGER.info("Signature Verified")
                        enclave_helper.decrypted_response(
                            response['result'], session_key, session_iv)
                    else:
                        LOGGER.info("Signature verification Failed")
                        exit(1)
                except Exception as e:
                    LOGGER.error("ERROR: Failed to analyze " +
                                 "Signature Verification")
                    exit(1)

            # -----------------------------------------------------------------
    else:
        LOGGER.info("Input Request %s", input_json_str)
        response = uri_client._postmsg(input_json_str)
        LOGGER.info("Received Response: %s , \n \n ", response)

    exit(0)
Esempio n. 4
0
def local_main(config):
    global input_json_str
    if not input_json_str and not input_json_dir:
        LOGGER.error("JSON input file is not provided")
        exit(1)

    if not output_json_file_name:
        LOGGER.error("JSON output file is not provided")
        exit(1)

    if not server_uri:
        LOGGER.error("Server URI is not provided")
        exit(1)

    LOGGER.info("Execute work order")
    uri_client = HttpJrpcClient(server_uri)
    response = None
    wo_id = None
    if input_json_dir:
        directory = os.fsencode(input_json_dir)
        files = os.listdir(directory)

        for file in sorted(files):
            LOGGER.info("---------------- Input file name: %s -------------\n",
                        file.decode("utf-8"))
            input_json_str = futils.read_json_file(
                (directory.decode("utf-8") + file.decode("utf-8")))
            # -----------------------------------------------------------------

            # If Client request is WorkOrderSubmit, a requester payload's
            # signature with the requester private signing key is generated.
            if "WorkOrderSubmit" in input_json_str:
                # Update workOrderId , workerId and workloadId
                input_json_obj = json.loads(input_json_str)
                wo_id = hex(random.randint(1, 2**64 - 1))
                input_json_obj["params"]["workOrderId"] = wo_id
                input_json_obj["params"]["workerId"] = worker_id

                # Convert workloadId to a hex string and update the request
                workload_id = input_json_obj["params"]["workloadId"]
                workload_id_hex = workload_id.encode("UTF-8").hex()
                input_json_obj["params"]["workloadId"] = workload_id_hex

                encrypt = worker_encryption.WorkerEncrypt()
                # Generate session key, session iv and encrypted session key
                session_key = encrypt.generate_session_key()
                session_iv = encrypt.generate_iv()
                encrypted_session_key = encrypt.encrypt_session_key(
                    session_key, worker_obj.encryption_key)

                input_json_obj["params"]["encryptedSessionKey"] = \
                    crypto_utility.byte_array_to_hex(encrypted_session_key)
                input_json_obj["params"]["sessionKeyIv"] = \
                    crypto_utility.byte_array_to_hex(session_iv)

                if "requesterNonce" in input_json_obj["params"]:
                    if len(input_json_obj["params"]["requesterNonce"]) == 0:
                        # [NO_OF_BYTES] 16 BYTES for nonce.
                        # This is the recommendation by NIST to
                        # avoid collisions by the "Birthday Paradox".
                        requester_nonce = secrets.token_hex(NO_OF_BYTES)
                        input_json_obj["params"]["requesterNonce"] = \
                            requester_nonce
                requester_nonce = input_json_obj["params"]["requesterNonce"]

                # Encode data in inData
                for data_obj in input_json_obj["params"]["inData"]:
                    encoded_data = data_obj["data"].encode('UTF-8')
                    data_obj["data"] = encoded_data

                # Encrypt inData
                encrypt.encrypt_work_order_data_json(
                    input_json_obj["params"]["inData"], session_key,
                    session_iv)
                req_hash = worker_hash.WorkerHash().calculate_request_hash(
                    input_json_obj["params"])
                encrypted_req_hash = encrypt.encrypt_data(
                    req_hash, session_key, session_iv)
                input_json_obj["params"]["encryptedRequestHash"] = \
                    encrypted_req_hash.hex()
                signer = worker_signing.WorkerSign()
                signer.generate_signing_key()
                wo_req_sig = signer.sign_message(req_hash)
                input_json_obj["params"]["requesterSignature"] = \
                    crypto_utility.byte_array_to_base64(wo_req_sig)
                input_json_obj["params"]["verifyingKey"] = \
                    signer.get_public_sign_key().decode('utf-8')
                input_json_str = json.dumps(input_json_obj)
                if input_json_str is None:
                    continue
            # -----------------------------------------------------------------

            # Update the worker ID
            if response:
                if "workerId" in input_json_str:
                    # Retrieve the worker id from the "WorkerRetrieve"
                    # response and update the worker id information for
                    # further json requests.
                    if "result" in response and \
                            "ids" in response["result"].keys() and \
                            len(response["result"]["ids"]) > 0:
                        input_json_final = json.loads(input_json_str)
                        worker_id = response["result"]["ids"][0]
                        input_json_final["params"]["workerId"] = worker_id
                        input_json_str = json.dumps(input_json_final)
                        LOGGER.info(
                            "********** Worker details Updated with "
                            "Worker ID*********\n%s\n", input_json_str)

            # -----------------------------------------------------------------
            if "WorkOrderGetResult" in input_json_str or \
                    "WorkOrderReceiptRetrieve" in input_json_str:
                input_json_obj = json.loads(input_json_str)
                input_json_obj["params"]["workOrderId"] = wo_id
                input_json_str = json.dumps(input_json_obj)

            LOGGER.info("*********Request Json********* \n%s\n",
                        input_json_str)
            response = uri_client._postmsg(input_json_str)
            LOGGER.info("**********Received Response*********\n%s\n", response)

            # -----------------------------------------------------------------

            # Worker details are loaded into Worker_Obj
            if "WorkerRetrieve" in input_json_str and "result" in response:
                worker_obj.load_worker(response["result"]["details"])
            # -----------------------------------------------------------------

            # Poll for "WorkOrderGetResult" and break when you get the result
            while ("WorkOrderGetResult" in input_json_str
                   and "result" not in response):
                if response["error"]["code"] != WorkOrderStatus.PENDING:
                    break
                response = uri_client._postmsg(input_json_str)
                LOGGER.info("Received Response: %s, \n \n ", response)
                time.sleep(3)

            # -----------------------------------------------------------------

            # Verify the signature
            if "WorkOrderGetResult" in input_json_str:
                if "error" in response:
                    # Response has error, hence skip Signature verification
                    LOGGER.info("Work order response has error; "
                                "skipping signature verification")
                    continue
                sig_bool = signer.verify_signature(response['result'],
                                                   worker_obj.verification_key,
                                                   requester_nonce)
                try:
                    if sig_bool > 0:
                        LOGGER.info("Signature Verified")
                        encrypt.decrypt_work_order_data_json(
                            response['result']['outData'], session_key,
                            session_iv)
                    else:
                        LOGGER.info("Signature verification Failed")
                        exit(1)
                except Exception as e:
                    LOGGER.error("ERROR: Failed to verify signature of " +
                                 "work order response")
                    exit(1)

            # -----------------------------------------------------------------
    else:
        LOGGER.info("Input Request %s", input_json_str)
        response = uri_client._postmsg(input_json_str)
        LOGGER.info("Received Response: %s , \n \n ", response)

    exit(0)
Esempio n. 5
0
class JRPCWorkOrderImpl(WorkOrder):
    """
    This class is for to manage to the work orders from client side.
    """
    def __init__(self, config):
        self.__uri_client = HttpJrpcClient(config["tcf"]["json_rpc_uri"])

    def work_order_submit(self,
                          work_order_id,
                          worker_id,
                          requester_id,
                          work_order_request,
                          id=None):
        """
        Submit a work order request to an Avalon listener.

        Parameters:
        work_order_id     Work order ID
        worker_id         Worker ID value derived from the worker's DID
        requester_id      Requester ID
        work_order_request Work order request in JSON RPC string format
        id                Optional JSON RPC request ID
        """
        json_rpc_request = {
            "jsonrpc": "2.0",
            "method": "WorkOrderSubmit",
            "id": id
        }
        json_rpc_request["params"] = json.loads(work_order_request)

        logging.debug("Work order request %s", json.dumps(json_rpc_request))
        response = self.__uri_client._postmsg(json.dumps(json_rpc_request))
        return response

    def work_order_get_result_nonblocking(self, work_order_id, id=None):
        """
        Get the work order result in non-blocking way.

        Parameters:
        work_order_id     Work order ID
        id                Optional JSON RPC request ID

        Returns:
        JSON RPC response of dictionary type
        """
        json_rpc_request = {
            "jsonrpc": "2.0",
            "method": "WorkOrderGetResult",
            "id": id,
            "params": {
                "workOrderId": work_order_id
            }
        }
        response = self.__uri_client._postmsg(json.dumps(json_rpc_request))
        return response

    def work_order_get_result(self, work_order_id, id=None):
        """
        Get the work order result in a blocking way until it gets a
        result or error.

        Parameters:
        work_order_id     Work order ID
        id                Optional JSON RPC request ID

        Returns:
        JSON RPC response of dictionary type
        """
        response = self.work_order_get_result_nonblocking(work_order_id, id)
        if "error" in response:
            if response["error"]["code"] != WorkOrderStatus.PENDING:
                return response
            else:
                while "error" in response and \
                        response["error"]["code"] == WorkOrderStatus.PENDING:
                    response = self.work_order_get_result_nonblocking(
                        work_order_id, id)
                    # TODO: currently pooling after every 2 sec interval
                    # forever.
                    # We should implement feature to timeout after
                    # responseTimeoutMsecs in the request.
                    time.sleep(2)
                return response
        else:
            return response

    def encryption_key_get(self,
                           worker_id,
                           requester_id,
                           last_used_key_nonce=None,
                           tag=None,
                           signature_nonce=None,
                           signature=None,
                           id=None):
        """
        API to receive a worker's key.

        Parameters:
        worker_id           Worker ID of the worker whose encryption key
                            is requested
        last_used_key_nonce Optional nonce associated with the last retrieved
                            key. If it is provided, the key retrieved should
                            be newer than this one.
                            Otherwise any key can be retrieved
        tag                 Tag that should be associated with the returned
                            key, e.g. the requester ID. This is an optional
                            parameter. If it is not provided, requester_id is
                            used as a key
        requester_id        ID of the requester that plans to use
                            the returned key to submit one or more work orders
                            using this key
        signature_nonce     Optional nonce associated with the signature and
                            is used only if signature below is also provided
        signature           Optional signature of worker_id,
                            last_used_key_nonce, tag, and signature_nonce.
        id                  Optional JSON RPC request ID
        """
        json_rpc_request = {
            "jsonrpc": "2.0",
            "method": "EncryptionKeyGet",
            "id": id,
            "params": {
                "workerId": worker_id,
                "lastUsedKeyNonce": last_used_key_nonce,
                "tag": tag,
                "requesterId": requester_id,
                "signatureNonce": signature_nonce,
                "signature": signature
            }
        }
        response = self.__uri_client._postmsg(json.dumps(json_rpc_request))
        return response

    def encryption_key_set(self,
                           worker_id,
                           encryption_key,
                           encryption_nonce,
                           tag,
                           signature_nonce,
                           signature,
                           id=None):
        """
        API called by a Worker or Worker Service to receive a Worker's key.

        Parameters:
        worker_id        ID of the worker to set an encryption key
        encryption_key   Encryption key to set
        encryption_nonce Nonce associated with the key
        tag              Tag that should be associated with the returned key,
                         e.g. requester ID.
        signature_nonce  Nonce associated with the signature
        signature        Signature generated by the worker on the worker_id,
                         tag and encryption_nonce
        id               Optional JSON RPC request ID

        Returns:
        JRPC response with the result of the operation.
        """
        # Not supported for direct model.
        return {
            "jsonrpc": "2.0",
            "method": "EncryptionKeySet",
            "id": id,
            "result": {
                "code": JRPCErrorCodes.INVALID_PARAMETER_FORMAT_OR_VALUE,
                "message": "Unsupported method"
            }
        }
class JRPCWorkOrderReceiptImpl(WorkOrderReceipt):
    """
    This class is an implementation of WorkOrderReceiptInterface
    to manage work order receipts from the client side.
    """
    def __init__(self, config):
        self.__uri_client = HttpJrpcClient(config["tcf"]["json_rpc_uri"])

    def work_order_receipt_create(self,
                                  work_order_id,
                                  worker_service_id,
                                  worker_id,
                                  requester_id,
                                  receipt_create_status,
                                  work_order_request_hash,
                                  requester_nonce,
                                  requester_signature,
                                  signature_rules,
                                  receipt_verification_key,
                                  id=None):
        """
        Create a Work Order Receipt JSON RPC request and submit to an
        Avalon listener.

        Parameters:
        work_order_id            Work order ID
        worker_service_id        Worker service ID
        worker_id                Worker ID value derived from the worker's DID
        requester_id             Requester ID
        receipt_create_status    Receipt creation status
        work_order_request_hash  Work order request hash value
        requester_nonce          Requester generated nonce
        requester_signature      Signature generated by the requester
        signature_rules          Defines hashing and signing algorithms;
                                 separated by forward slash '/'
        receipt_verification_key Receipt verification key
        id                       Optional JSON RPC request ID
        """
        json_rpc_request = {
            "jsonrpc": "2.0",
            "method": "WorkOrderReceiptCreate",
            "id": id,
            "params": {
                "workOrderId": work_order_id,
                "workerServiceId": worker_service_id,
                "workerId": worker_id,
                "requesterId": requester_id,
                "receiptCreateStatus": receipt_create_status,
                "workOrderRequestHash": work_order_request_hash,
                "requesterGeneratedNonce": requester_nonce,
                "requesterSignature": requester_signature,
                "signatureRules": signature_rules,
                "receiptVerificationKey": receipt_verification_key
            }
        }
        response = self.__uri_client._postmsg(json.dumps(json_rpc_request))
        return response

    def work_order_receipt_update(self,
                                  work_order_id,
                                  updater_id,
                                  update_type,
                                  update_data,
                                  update_signature,
                                  signature_rules,
                                  id=None):
        """
        Update a Work Order Receipt JSON RPC request and submit an
        Avalon listener.

        Parameters:
        work_order_id    Work Order ID
        updater_id       Updater ID
        update_type      Updater type
        update_data      Receipt update data
        update_signature Signature of the update
        signature_rules  Defines hashing and signing algorithms;
                         separated by forward slash '/'
        id               Optional JSON RPC request ID
        """
        json_rpc_request = {
            "jsonrpc": "2.0",
            "method": "WorkOrderReceiptUpdate",
            "id": id,
            "params": {
                "workOrderId": work_order_id,
                "updaterId": updater_id,
                "updateType": update_type,
                "updateData": update_data,
                "updateSignature": update_signature,
                "signatureRules": signature_rules
            }
        }
        response = self.__uri_client._postmsg(json.dumps(json_rpc_request))
        return response

    def work_order_receipt_retrieve(self, work_order_id, id=None):
        """
        Retrieve a work order receipt JSON RPC request and submit to an
        Avalon listener.

        Parameters:
        work_order_id Work order ID
        id            Optional Optional JSON RPC request ID
        """
        json_rpc_request = {
            "jsonrpc": "2.0",
            "method": "WorkOrderReceiptRetrieve",
            "id": id,
            "params": {
                "workOrderId": work_order_id
            }
        }
        response = self.__uri_client._postmsg(json.dumps(json_rpc_request))
        return response

    def work_order_receipt_update_retrieve(self,
                                           work_order_id,
                                           updater_id,
                                           update_index,
                                           id=None):
        """
        Retrieve a work order receipt update JSON RPC request and submit to an
        Avalon listener.

        Parameters:
        work_order_id Work order ID
        id            Optional Optional JSON RPC request ID
        """
        json_rpc_request = {
            "jsonrpc": "2.0",
            "method": "WorkOrderReceiptUpdateRetrieve",
            "id": id,
            "params": {
                "workOrderId": work_order_id,
                "updaterId": updater_id,
                "updateIndex": update_index
            }
        }
        response = self.__uri_client._postmsg(json.dumps(json_rpc_request))
        return response

    def work_order_receipt_lookup(self,
                                  worker_service_id=None,
                                  worker_id=None,
                                  requester_id=None,
                                  receipt_status=None,
                                  id=None):
        """
        Work Order Receipt Lookup
        All fields are optional and, if present, condition should match for
        all fields. If none are passed it should return all
        work order receipts.

        Parameters:
        worker_service_id        Optional worker service ID to lookup
        worker_id                Optional worker ID value derived from
                                 the worker's DID
        requester_id             Optional requester ID to lookup
        receipt_status           Optional receipt status
        id                       Optional JSON RPC request ID
        """
        json_rpc_request = {
            "jsonrpc": "2.0",
            "method": "WorkOrderReceiptLookUp",
            "id": id,
            "params": {}
        }

        if worker_service_id is not None:
            json_rpc_request["params"]["workerServiceId"] = worker_service_id

        if worker_id is not None:
            json_rpc_request["params"]["workerId"] = worker_id

        if requester_id is not None:
            json_rpc_request["params"]["requesterId"] = requester_id

        if receipt_status is not None:
            json_rpc_request["params"]["requestCreateStatus"] = receipt_status

        response = self.__uri_client._postmsg(json.dumps(json_rpc_request))
        return response

    def work_order_receipt_lookup_next(self,
                                       last_lookup_tag,
                                       worker_service_id=None,
                                       worker_id=None,
                                       requester_id=None,
                                       receipt_status=None,
                                       id=None):
        """
        Work Order Receipt Lookup Next.
        Call to retrieve subsequent results after calling
        work_order_receipt_lookup or

        Parameters:
        last_lookup_tag          Last lookup tag returned by
                                 work_order_receipt_lookup
        worker_service_id        Optional worker service ID to lookup
        worker_id                Optional worker ID value derived from
                                 the worker's DID
        requester_id             Optional requester ID to lookup
        receipt_status           Optional receipt status
        id                       Optional JSON RPC request ID
        """
        json_rpc_request = {
            "jsonrpc": "2.0",
            "method": "WorkOrderReceiptLookUpNext",
            "id": id,
            "params": {
                "lastLookUpTag": last_lookup_tag
            }
        }

        if worker_service_id is not None:
            json_rpc_request["params"]["workerServiceId"] = worker_service_id

        if worker_id is not None:
            json_rpc_request["params"]["workerId"] = worker_id

        if requester_id is not None:
            json_rpc_request["params"]["requesterId"] = requester_id

        if receipt_status is not None:
            json_rpc_request["params"]["requestCreateStatus"] = receipt_status

        response = self.__uri_client._postmsg(json.dumps(json_rpc_request))
        return response