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)
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, }
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
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)
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
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)
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