Example #1
0
    def dump_contract_transaction_protobuf_message_to_json(self, msg, family=None):
        txn_dict = {}
        details= None

        if msg.verb == 'register':
            details = PdoContractRegister()
        elif msg.verb == "add-enclaves":
            details = PdoContractAddEnclaves()
        elif msg.verb == "remove-enclaves":
            details = PdoContractRemoveEnclaves()
        elif msg.verb != "delete":
            txn_dict["error"] = "invalid transaction verb"

        if details:
            details.ParseFromString(msg.transaction_details)
            txn_dict = MessageToDict(
                details,
                including_default_value_fields=True,
                preserving_proto_field_name=True)

        if family:
            txn_dict["af"] = family

        txn_dict["verb"] = msg.verb
        txn_dict["contract_id"] = msg.contract_id
        print()
        print(json.dumps(txn_dict, indent=2))
        print()
    def dump_contract_transaction(self, payload):
        self._dump_str("")
        self._dump_str("PdoContractTransaction:")
        self._dump_str("verb:  {}".format(payload.verb))
        self._dump_str("contract_id:  {}".format(payload.contract_id))
        self._dump_str("TransactionDetails:")
        if payload.verb == 'register':
            details = PdoContractRegister()
            details.ParseFromString(payload.transaction_details)
            self._dump_str("  contract_code_hash:  {}".format(
                details.contract_code_hash))
            self._dump_str("pdo_contract_creator_pem_key: {}".format(
                details.pdo_contract_creator_pem_key))
            self._dump_str("pdo_signature: {}".format(details.pdo_signature))
            index = 1
            for id in details.provisioning_service_ids:
                self._dump_str("  provisioning_service_id[{0}]: {1}".format(
                    index, id))
                index += 1

        elif payload.verb == "add-enclaves":
            details = PdoContractAddEnclaves()
            details.ParseFromString(payload.transaction_details)
            self._dump_str("pdo_signature: {}".format(details.pdo_signature))
            for e in details.enclaves_info:
                self._dump_str("  contract_enclave_id:  {}".format(
                    e.contract_enclave_id))
                self._dump_str(
                    "    encrypted_contract_state_encryption_key: {}".format(
                        e.encrypted_contract_state_encryption_key))
                self._dump_str("    enclave_signature: {}".format(
                    e.enclave_signature))
                for m in e.enclaves_map:
                    self._dump_str(
                        "      provisioning_service_public_key: {}".format(
                            m.provisioning_service_public_key))
                    self._dump_str(
                        "      provisioning_contract_state_secret: {}".format(
                            m.provisioning_contract_state_secret))
                    self._dump_str("      index: {}".format(m.index))

        elif payload.verb == "remove-enclaves":
            details = PdoContractRemoveEnclaves()
            details.ParseFromString(payload.transaction_details)
            index = 1
            for id in details.contract_enclave_ids:
                self._dump_str("  contract_enclave_id[{0}]: {1}".format(
                    index, id))
                index += 1

        elif payload.verb != "delete":
            self._dump_str("  invalid transaction verb")
    def execute_json_transaction(self,
                                 json_input,
                                 address_family,
                                 wait,
                                 exception_type=None,
                                 verbose=False,
                                 timeout_exception_type=TimeoutError,
                                 transaction_output_list=None,
                                 transaction_input_list=None,
                                 transaction_dependency_list=None):
        json_dict = json.loads(json_input)
        verb = json_dict['verb']

        if not verb:
            if not exception_type:
                return False
            raise exception_type("no 'verb' in the json input")

        if address_family == self.get_enclave_registry_family_name():
            txn = PdoContractEnclaveTransaction()
            txn.verb = verb
            txn.verifying_key = json_dict.get("verifying_key")
            if verb == 'register':
                details = PdoContractEnclaveRegister()
                proof_data = json_dict.get("proof_data")
                if proof_data is None or isinstance(proof_data, str):
                    json_format.Parse(json_input,
                                      details,
                                      ignore_unknown_fields=True)
                else:
                    if not exception_type:
                        return False
                    raise exception_type("missing or invalid 'proof_data'")
            elif verb == 'update':
                details = PdoContractEnclaveUpdate()
                json_format.Parse(json_input,
                                  details,
                                  ignore_unknown_fields=True)
            elif verb == 'delete':
                details = None
            else:
                if not exception_type:
                    return False
                raise exception_type(
                    "unknown verb in the json input '{}'".format(verb))

            if details:
                txn.transaction_details = txn.transaction_details = details.SerializeToString(
                )
            if verbose:
                self._dbg_dump.dump_contract_enclave_transaction(txn)
                self._dbg_dump.dump_enclave_transaction_protobuf_message_to_json(
                    txn)

        elif address_family == self.get_contract_registry_family_name():
            txn = PdoContractTransaction()
            txn.verb = verb
            if 'contract_id' in json_dict:
                txn.contract_id = json_dict.get("contract_id")
            if verb == 'register':
                details = PdoContractRegister()
            elif verb == 'add-enclaves':
                details = PdoContractAddEnclaves()
            elif verb == 'remove-enclaves':
                details = PdoContractRemoveEnclaves()
            elif verb == 'delete':
                details = None
            else:
                if not exception_type:
                    return False
                raise exception_type(
                    "unknown verb in the json input '{}'".format(verb))

            if details:
                json_format.Parse(json_input,
                                  details,
                                  ignore_unknown_fields=True)
                txn.transaction_details = details.SerializeToString()

            if verbose:
                self._dbg_dump.dump_contract_transaction(txn)
                self._dbg_dump.dump_contract_transaction_protobuf_message_to_json(
                    txn)

        elif address_family == self.get_ccl_family_name():
            if verb not in ['initialize', 'update', 'terminate', 'delete']:
                if not exception_type:
                    return False
                raise exception_type(
                    "unknown verb in the json input '{}'".format(verb))
            txn = CCL_TransactionPayload()
            json_format.Parse(json_input, txn, ignore_unknown_fields=True)
            if verbose:
                self._dbg_dump.dump_ccl_transaction(txn)
                self._dbg_dump.dump_ccl_transaction_protobuf_message_to_json(
                    txn)

        else:
            if not exception_type:
                return False
            raise exception_type(
                "unknown 'af' (a.k.a. address family) in the json input '{}'".
                format(address_family))

        result, signature = self.send_transaction(
            txn.SerializeToString(),
            address_family,
            wait=wait,
            exception_type=timeout_exception_type,
            transaction_output_list=transaction_output_list,
            transaction_input_list=transaction_input_list,
            transaction_dependency_list=transaction_dependency_list)

        if verbose:
            self._dbg_dump.dump_str("")
            self._dbg_dump.dump_str(result)
            self._dbg_dump.dump_str("")
            self._dbg_dump.dump_str(
                "Transaction signature: {}".format(signature))

        return signature
Example #4
0
    def apply(self, transaction, context):
        txn_header = transaction.header
        txn_signer_public_key = txn_header.signer_public_key

        payload = PdoContractTransaction()
        payload.ParseFromString(transaction.payload)
        if payload.verb == 'register':
            sig_unxelified = binascii.unhexlify(transaction.signature)
            digest = hashlib.sha256(sig_unxelified).digest()
            sig_base64 = base64.b64encode(digest)
            contract_id = sig_base64.decode("utf-8", "ignore")
        else:
            contract_id = payload.contract_id

        self.dbg_dump.dump_contract_transaction(payload)

        info = self.check_address(context, contract_id,
                                  payload.verb == 'register')

        if payload.verb != 'register':
            self.dbg_dump.dump_contract_state(info, "Received PdoContractInfo")

        if payload.verb == 'register':
            details = PdoContractRegister()
            details.ParseFromString(payload.transaction_details)

            self._verify_register(details, txn_signer_public_key)

            info.contract_id = contract_id
            info.contract_code_hash = details.contract_code_hash
            info.pdo_contract_creator_pem_key = details.pdo_contract_creator_pem_key
            for id in details.provisioning_service_ids:
                info.provisioning_service_ids.append(id)

            self.dbg_dump.dump_contract_state(info,
                                              "Setting new PdoContractInfo")
            self._set_contract_state(context, contract_id,
                                     info.SerializeToString())
            LOGGER.info("Contract %s was added to the registry.",
                        payload.contract_id)

        elif payload.verb == 'delete':
            if not self._debug_on:
                raise InvalidTransaction(
                    'Delete is not allowed, debug support is OFF')

            LOGGER.info("Contract %s was deleted", payload.contract_id)
            self._delete_contract_state(context, contract_id)

        elif payload.verb == 'add-enclaves':
            details = PdoContractAddEnclaves()
            details.ParseFromString(payload.transaction_details)

            if not verify_add_enclave_to_contract_pdo_signature(
                    details, info, txn_signer_public_key):
                raise InvalidTransaction(
                    'Overall PDO signature for add enclaves transaction is invalid'
                )

            for enclave_info in details.enclaves_info:
                self._verify_enclave_info(context, info, enclave_info)

            for ei in details.enclaves_info:
                enclave_info = info.enclaves_info.add()
                enclave_info.CopyFrom(ei)

            self.dbg_dump.dump_contract_state(
                info, "PdoContractInfo After adding enclave(s)")
            self._set_contract_state(context, contract_id,
                                     info.SerializeToString())
            LOGGER.info("Enclaves were added to contract %s.",
                        payload.contract_id)

        elif payload.verb == 'remove-enclaves':
            details = PdoContractRemoveEnclaves()
            details.ParseFromString(payload.transaction_details)

            for id in details.contract_enclave_ids:
                for ei in info.enclaves_info:
                    if ei.contract_enclave_id == id:
                        info.enclaves_info.remove(ei)
                        break

            self.dbg_dump.dump_contract_state(
                info, "PdoContractInfo after removing enclave(s)")
            self._set_contract_state(context, contract_id,
                                     info.SerializeToString())
            LOGGER.info("Enclaves were removed from contract %s.",
                        payload.contract_id)

        else:
            raise InvalidTransaction('Invalid transaction action {}'.format(
                payload.verb))
Example #5
0
    def execute_json_transaction(self, json_input, address_family, wait):
        if self._verbose:
            print("\njson_input:")
            print(json_input)

        json_dict = json.loads(json_input)
        if not address_family:
            try:
                address_family = json_dict['af']
            except:
                raise PdoCliException(
                    "Family not defined, use 'af'in the json or --enclave, --contract, or --ccl on the command line"
                )

        # set contract id and signature(s) if they are empty in case of contract add and remove enclaves transactions
        if address_family == self.connect.get_contract_registry_family_name():
            if json_dict['verb'] != 'delete':
                details = None
                contract = None

                if json_dict['verb'] != 'register' and not json_dict[
                        'contract_id']:
                    contract = self._find_contract_id()

                if json_dict['verb'] == 'register':
                    # generate pdo_signature and pdo_contract_creator_pem_key in case of contract register
                    details = PdoContractRegister()
                    json_format.Parse(json_input,
                                      details,
                                      ignore_unknown_fields=True)

                    details.contract_code_hash = self._to_base64(
                        details.contract_code_hash)

                    # normally it would be done using one time transaction signing key
                    # to simplify test automation we are going to reuse the same key was used for contract registration
                    details.pdo_signature = secp256k1_sign(
                        make_contract_register_hash_input(
                            details,
                            self.connect.get_signer_public_key_as_hex()),
                        self.connect.get_signer_private_key_as_hex())
                    details.pdo_contract_creator_pem_key = self.connect.get_signer_public_key_as_hex(
                    )
                    contract = PdoContractInfo()
                    if 'contract_id' in json_dict:
                        contract.contract_id = json_dict.get('contract_id')
                elif json_dict['verb'] == 'remove-enclaves':
                    details = PdoContractRemoveEnclaves()
                    json_format.Parse(json_input,
                                      details,
                                      ignore_unknown_fields=True)
                elif json_dict['verb'] == 'add-enclaves':
                    details = PdoContractAddEnclaves()
                    json_format.Parse(json_input,
                                      details,
                                      ignore_unknown_fields=True)
                    # generate enclave signatures for each enclave info
                    # if signatures are empty in the json input
                    for enclave_info in details.enclaves_info:
                        if not enclave_info.enclave_signature:
                            if not contract:
                                contract = self._get_contract_state(
                                    json_dict['contract_id'])
                                if not not contract or not contract.contract_id:
                                    raise PdoCliException(
                                        "Cannot load contract to generate signature {}"
                                        .format(json_dict['contract_id']))

                        enclave_info.encrypted_contract_state_encryption_key = \
                            base64.b64encode(enclave_info.encrypted_contract_state_encryption_key.encode())

                        hash_input = make_add_enclave_to_contract_hash_input(
                            enclave_info, contract)
                        enclave_info.enclave_signature = secp256k1_sign(
                            hash_input, self._enclave_signing_private_key)

                    contract_creator_private_key = self.connect.get_signer_private_key_as_hex(
                    )
                    self.connect.generate_new_signer_key()
                    details.pdo_signature = secp256k1_sign(
                        make_add_enclave_to_contract_pdo_hash_input(
                            details, contract,
                            self.connect.get_signer_public_key_as_hex()),
                        contract_creator_private_key)

                if contract:
                    txn = PdoContractTransaction()
                    txn.verb = json_dict['verb']
                    txn.contract_id = contract.contract_id
                    if details:
                        txn.transaction_details = details.SerializeToString()
                    if self._verbose:
                        print("Updated Contract Transaction:")
                        PdoDbgDump().dump_contract_transaction(txn)
                        PdoDbgDump(
                        ).dump_contract_transaction_protobuf_message_to_json(
                            txn)

                    result = self.connect.send_transaction(
                        txn.SerializeToString(), address_family, wait=wait)
                    if self._verbose:
                        print(result)

                    print("OK")
                    return

        # set contract id and signature(s) if they are empty in case of CCL transactions
        if address_family == self.connect.get_ccl_family_name():
            if json_dict['verb'] != 'delete':
                signature = json_dict['contract_enclave_signature']
                contract_id = json_dict['state_update']['contract_id']

                if not contract_id or not signature:
                    contract_creator_private_key = self.connect.get_signer_private_key_as_hex(
                    )
                    self.connect.generate_new_signer_key()

                    txn = CCL_TransactionPayload()
                    json_format.Parse(json_input,
                                      txn,
                                      ignore_unknown_fields=True)

                    # for testing set channel_id to the one time transaction signer key
                    txn.channel_id = self.connect.get_signer_public_key_as_hex(
                    )

                    if not contract_id:
                        contract = self._find_contract_id()
                    else:
                        contract = self._get_contract_state(contract_id)

                    txn.state_update.contract_id = contract.contract_id
                    for d in txn.state_update.dependency_list:
                        d.contract_id = contract.contract_id
                        d.state_hash = self._to_base64(d.state_hash)

                    txn.state_update.current_state_hash = self._to_base64(
                        txn.state_update.current_state_hash)
                    txn.state_update.previous_state_hash = self._to_base64(
                        txn.state_update.previous_state_hash)
                    txn.state_update.message_hash = self._to_base64(
                        txn.state_update.message_hash)

                    contract.contract_code_hash = self._to_base64(
                        contract.contract_code_hash)

                    if not signature:
                        txn.contract_enclave_signature = sign_ccl_transaction(
                            txn, contract, self._enclave_signing_private_key)

                    if json_dict['verb'] == 'initialize':
                        # generate PDO signature normally done using one time transaction signing key
                        # to simplify test automation assume reuse signing key used to register the contract
                        txn.pdo_signature = secp256k1_sign(
                            make_ccl_transaction_pdo_hash_input(txn, contract),
                            contract_creator_private_key)

                    if self._verbose:
                        print("Updated CCL Transaction:")
                        PdoDbgDump().dump_ccl_transaction(txn)
                        PdoDbgDump(
                        ).dump_ccl_transaction_protobuf_message_to_json(txn)

                    result = self.connect.send_transaction(
                        txn.SerializeToString(), address_family, wait=wait)
                    if self._verbose:
                        print(result)

                    print("OK")
                    return

        try:
            if self.connect.execute_json_transaction(json_input,
                                                     address_family, wait,
                                                     PdoCliException,
                                                     self._verbose):
                print("OK")
            else:
                print("Error")
        except PdoCliException as e:
            print(e)
            print("Error")
        except TypeError as err:
            print("missing or invalid key:", err)
            print("Error")