def __init__(self, verifying_key, encryption_key):
        """
        initialize the object

        :param verifying_key: PEM encoded ECDSA verifying key
        :param encryption_key: PEM encoded RSA encryption key
        """
        self._verifying_key = crypto.SIG_PublicKey(verifying_key)
        self._encryption_key = crypto.PKENC_PublicKey(encryption_key)
def verify_store_signature(store_response, expiration, verifying_key):
    block_hashes = map(decode_block_id, store_response['block_ids'])

    signing_hash_accumulator = expiration.to_bytes(32,
                                                   byteorder='big',
                                                   signed=False)
    signing_hash_accumulator += b''.join(block_hashes)
    signing_hash = hashlib.sha256(signing_hash_accumulator).digest()

    decoded_signature = base64.urlsafe_b64decode(store_response['signature'])

    vk = crypto.SIG_PublicKey(verifying_key)
    return vk.VerifySignature(signing_hash, decoded_signature)
Exemple #3
0
    def __init__(self, config):
        self.__registry_helper = PdoRegistryHelper(
            config['Sawtooth']['LedgerURL'])

        self.SigningKey = pcrypto.SIG_PrivateKey(config['SigningKeyPrivate'])
        self.PSPK = pcrypto.SIG_PublicKey(config['SigningKeyPublic'])

        self.secrets_file_path = config['SecretsFilePath']

        self.RequestMap = {
            'secretRequest': self._secretreq,
            'dataRequest': self._datareq,
        }
Exemple #4
0
    def __init__(self, host, port):

        #ensure that ccf keys are present
        ccf_key_dir = os.environ.get("PDO_LEDGER_KEY_ROOT")
        cert_file = os.path.join(ccf_key_dir, "userccf_cert.pem")
        key_file = os.path.join(ccf_key_dir, "userccf_privk.pem")
        ca_file = os.path.join(ccf_key_dir, "networkcert.pem")

        for f in (cert_file, key_file, ca_file):
            if os.path.exists(f) is False:
                logger.error(
                    "Cannot locate CCF key file {0}; aborting transaction".
                    format(f))
                raise Exception("Cannot locate CCF keys.Aborting transaction")

        # create the reuest client
        logger.info("Creating the CCF Request client")
        super().__init__(
            host=host,
            port=port,
            cert=cert_file,
            key=key_file,
            ca=ca_file,
            description=None,
            version="2.0",
            format="json",
            prefix="app",
            connection_timeout=3,
            request_timeout=3,
        )

        #Temporary fix to skip checking CCF host certificate. Version 0.11.7 CCF certificate expiration was hardcoded to end of 2021
        self.client_impl.session.mount("https://", HTTPAdapter())
        self.client_impl.session.verify = False

        self.rpc_loggers = ()  #avoid the default logging to screen

        #get CCF verifying key (specific to PDO TP)
        try:
            ledger_response = self.submit_read_request(
                "get_ledger_verifying_key", dict())
            self.ccf_verifying_key = ledger_response['verifying_key']
            self.__ccf_signature_verifyer__ = crypto.SIG_PublicKey(
                self.ccf_verifying_key)
        except Exception as e:
            logger.exception("Unable to get ledger verifying key")
            raise e
Exemple #5
0
    def __init__(self, ledger_config, *args, **kwargs):
        super().__init__(ledger_config, *args, **kwargs)

        if CCFSubmitter.ccf_client is None:
            try:
                _, host_port = self.url.split('//')
                self.host, self.port = host_port.split(':')
            except Exception as e:
                raise Exception("Unable to parse CCF ledger URL. Must be of the form http://ip:port : %s", str(e))

            ccf_key_dir = os.environ.get("PDO_LEDGER_KEY_ROOT")
            #ensure that ccf keys are present
            self.cert_file = ccf_key_dir + "/userccf_cert.pem"
            self.key_file = ccf_key_dir + "/userccf_privk.pem"
            self.ca_file = ccf_key_dir + "/networkcert.pem"

            if os.path.exists(self.cert_file) is False or os.path.exists(self.key_file) is False or \
                os.path.exists(self.ca_file) is False:
                logger.error("Cannot locate CCF keys. Aborting transaction")
                raise Exception("Cannot locate CCF keys.Aborting transaction")

            # create the reuest client
            logger.info("Creating the CCF Request client")
            CCFSubmitter.ccf_client = ccf_helper.CCFClient(
                                                host=self.host,
                                                port=int(self.port),
                                                cert=self.cert_file,
                                                key=self.key_file,
                                                ca=self.ca_file,
                                                description=None,
                                                version="2.0",
                                                format="json",
                                                prefix="users",
                                                connection_timeout=3,
                                                request_timeout=3,
                                            )

            CCFSubmitter.ccf_client.rpc_loggers = () #avoid the default logging to screen

            #get CCF verifying key (specific to PDO TP)
            ledger_response = self.submit_read_request_to_ccf("get_ledger_verifying_key", dict())
            try:
                ccf_verifying_key_PEM = ledger_response['verifying_key']
                CCFSubmitter.ccf_signature_verifyer = crypto.SIG_PublicKey(ccf_verifying_key_PEM)
            except Exception as e:
                raise Exception("Unable to get ledger verifying key; {}", str(e))
try:
    esk = crypto.SIG_PrivateKey()
    esk.Generate()
    epk = esk.GetPublicKey()
except Exception as exc:
    logger.error(
        "ERROR: Signature Private and Public keys generation test failed: ",
        exc)
    sys.exit(-1)
logger.debug("Signature Private and Public keys generation test successful!")
try:
    eskString = esk.Serialize()
    epkString = epk.Serialize()
    hepkString = epk.SerializeXYToHex()
    esk1 = crypto.SIG_PrivateKey(eskString)
    epk1 = crypto.SIG_PublicKey(epkString)
    eskString1 = esk1.Serialize()
    epkString1 = epk1.Serialize()
    esk2 = crypto.SIG_PrivateKey()
    esk2.Generate()
    epk2 = crypto.SIG_PublicKey(esk2)
    eskString = esk.Serialize()
    esk2.Deserialize(eskString1)
    epk2.Deserialize(epkString1)
    eskString2 = esk2.Serialize()
    epkString2 = epk2.Serialize()
except Exception as exc:
    logger.error(
        "ERROR: Signature Private and Public keys serialize/deserialize test failed: ",
        exc)
    sys.exit(-1)
Exemple #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_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
Exemple #8
0
def test_ecdsa(sig_curve=crypto.SigCurve_UNDEFINED):
    try:
        if (sig_curve == crypto.SigCurve_UNDEFINED):
            # test with private key from default constructor
            esk = crypto.SIG_PrivateKey()
        elif (sig_curve == crypto.SigCurve_SECP256K1
              or sig_curve == crypto.SigCurve_SECP384R1):
            # test with private key from curve-defined constructor
            esk = crypto.SIG_PrivateKey(sig_curve)
        else:
            logger.error("ERROR: unsupported sigcurve " + crypto.sig_curve)
            sys.exit(-1)

        # test private key generation
        esk.Generate()

        # test public key retrieval from public key
        epk = esk.GetPublicKey()
    except Exception as exc:
        logger.error(
            "ERROR: Signature Private and Public keys generation test failed: ",
            exc)
        sys.exit(-1)
    logger.debug(
        "Signature Private and Public keys generation test successful!")

    try:
        # test private key serialization
        eskString = esk.Serialize()
        # test public key serialization
        epkString = epk.Serialize()
        # test public key xy serialization
        hepkString = epk.SerializeXYToHex()
        # test private key PEM constructor
        esk1 = crypto.SIG_PrivateKey(eskString)
        # test public key PEM constructor
        epk1 = crypto.SIG_PublicKey(epkString)
        # test private key serialization
        eskString1 = esk1.Serialize()
        # test public key serialization
        epkString1 = epk1.Serialize()
        # generate key pair for tests
        esk2 = crypto.SIG_PrivateKey()
        esk2.Generate()
        epk2 = crypto.SIG_PublicKey(esk2)
        # test private key deserialization
        esk2.Deserialize(eskString1)
        # test public key deserialization
        epk2.Deserialize(epkString1)
        # test PEM equivalence following deserialization-serialization steps
        eskString2 = esk2.Serialize()
        epkString2 = epk2.Serialize()
        if eskString1 != eskString2 or epkString1 != epkString2:
            logger.error(
                "ERROR: PEM differ after deserialization-serialization steps")
            sys.exit(-1)
    except Exception as exc:
        logger.error(
            "ERROR: Signature Private and Public keys serialize/deserialize test failed: ",
            exc)
        sys.exit(-1)
    logger.debug(
        "Signature Private and Public keys serialize/deserialize test successful!"
    )

    try:
        # test deserializing public key as private key
        esk1.Deserialize(epkString1)
        logger.error(
            "ERROR: Signature invalid private key deserialize test failed: not detected."
        )
        sys.exit(-1)
    except Exception as exc:
        if (type(exc) == ValueError):
            logger.debug(
                "Signature invalid private key deserialize test successful!")
        else:
            logger.error(
                "ERROR: Signature invalid private key deserialize test failed: ",
                exc)
            sys.exit(-1)

    try:
        # test deserializing private key as public key
        epk1.Deserialize(eskString1)
        logger.error(
            "ERROR: Signature invalid public key deserialize test failed: not detected."
        )
        sys.exit(-1)
    except Exception as exc:
        if (type(exc) == ValueError):
            logger.debug(
                "Signature invalid public key deserialize test successful!")
        else:
            logger.error(
                "ERROR: Signature invalid public key deserialize test failed: ",
                exc)
            sys.exit(-1)

    try:
        # test message signing and verification
        msg = b'A message!'
        sig = esk.SignMessage(msg)
        res = epk.VerifySignature(msg, sig)
    except Exception as exc:
        logger.error(
            "ERROR: Signature creation and verification test failed: ", exc)
        sys.exit(-1)
    if (res == 1):
        logger.debug("Signature creation and verification test successful!")
    else:
        logger.error(
            "ERROR: Signature creation and verification test failed: signature does not verify."
        )
        exit(-1)

    try:
        # test invalid signature verification
        res = epk.VerifySignature(msg, bytes("invalid signature", 'ascii'))
    except Exception as exc:
        logger.error("ERROR: Invalid signature detection test failed: ", exc)
        sys.exit(-1)
    if (res != 1):
        logger.debug("Invalid signature detection test successful!")
    else:
        logger.error("ERROR: Invalid signature detection test failed.")
        exit(-1)
Exemple #9
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