def test_load_asymmetric_key_from_pem_bytestring(): for key_type in SUPPORTED_ASYMMETRIC_KEY_TYPES: keypair = wacryptolib.key_generation.generate_asymmetric_keypair( key_type=key_type) for field in ["private_key", "public_key"]: key = load_asymmetric_key_from_pem_bytestring( key_pem=keypair[field], key_type=key_type) assert key.export_key # Method of Key object with pytest.raises(ValueError, match="Unknown key type"): load_asymmetric_key_from_pem_bytestring( key_pem=keypair["private_key"], key_type="ZHD")
def test_escrow_api_workflow(): key_storage = DummyKeyStorage() escrow_api = EscrowApi(key_storage=key_storage) keychain_uid = uuid.uuid4() secret = get_random_bytes(101) public_key_pem = escrow_api.get_public_key(keychain_uid=keychain_uid, key_type="RSA") public_key = load_asymmetric_key_from_pem_bytestring( key_pem=public_key_pem, key_type="RSA") signature = escrow_api.get_message_signature(keychain_uid=keychain_uid, message=secret, key_type="RSA", signature_algo="PSS") verify_message_signature(message=secret, signature=signature, key=public_key, signature_algo="PSS") signature["digest"] += b"xyz" with pytest.raises(ValueError, match="Incorrect signature"): verify_message_signature(message=secret, signature=signature, key=public_key, signature_algo="PSS") cipherdict = _encrypt_via_rsa_oaep(plaintext=secret, key=public_key) decrypted = escrow_api.decrypt_with_private_key( keychain_uid=keychain_uid, key_type="RSA", encryption_algo="RSA_OAEP", cipherdict=cipherdict, ) cipherdict["digest_list"].append(b"aaabbbccc") with pytest.raises(ValueError, match="Ciphertext with incorrect length"): escrow_api.decrypt_with_private_key( keychain_uid=keychain_uid, key_type="RSA", encryption_algo="RSA_OAEP", cipherdict=cipherdict, ) assert decrypted == secret
def _verify_message_signatures(self, keychain_uid: uuid.UUID, message: bytes, conf: dict): signature_key_type = conf["signature_key_type"] signature_algo = conf["signature_algo"] encryption_proxy = _get_proxy_for_escrow(conf["signature_escrow"]) public_key_pem = encryption_proxy.get_public_key( keychain_uid=keychain_uid, key_type=signature_key_type) public_key = load_asymmetric_key_from_pem_bytestring( key_pem=public_key_pem, key_type=signature_key_type) verify_message_signature( message=message, signature_algo=signature_algo, signature=conf["signature_value"], key=public_key, ) # Raises if troubles
def _decrypt_private_key_pem_with_passphrases( self, *, private_key_pem: bytes, key_type: str, passphrases: Optional[list] ): """ Attempt decryption of key with and without provided passphrases, and raise if all fail. """ for passphrase in [None] + passphrases: try: key_obj = load_asymmetric_key_from_pem_bytestring( key_pem=private_key_pem, key_type=key_type, passphrase=passphrase ) return key_obj except KeyLoadingError: pass raise DecryptionError( "Could not decrypt private key of type %s (passphrases provided: %d)" % (key_type, len(passphrases)) )
def _encrypt_symmetric_key(self, keychain_uid: uuid.UUID, symmetric_key_data: bytes, conf: dict) -> dict: assert isinstance(symmetric_key_data, bytes), symmetric_key_data escrow_key_type = conf["escrow_key_type"] key_encryption_algo = conf["key_encryption_algo"] encryption_proxy = _get_proxy_for_escrow(conf["key_escrow"]) subkey_pem = encryption_proxy.get_public_key(keychain_uid=keychain_uid, key_type=escrow_key_type) subkey = load_asymmetric_key_from_pem_bytestring( key_pem=subkey_pem, key_type=escrow_key_type) key_cipherdict = encrypt_bytestring( plaintext=symmetric_key_data, encryption_algo=key_encryption_algo, key=subkey, ) return key_cipherdict
def get_message_signature( self, *, keychain_uid: uuid.UUID, message: bytes, signature_algo: str # FIXME name this "key_type" too? ) -> dict: """ Return a signature structure corresponding to the provided key and signature types. """ if len(message) > MAX_PAYLOAD_LENGTH_FOR_SIGNATURE: # SECURITY raise ValueError("Message too big for signing, only a hash should be sent") self._ensure_keypair_exists(keychain_uid=keychain_uid, key_type=signature_algo) private_key_pem = self._key_storage.get_private_key(keychain_uid=keychain_uid, key_type=signature_algo) private_key = load_asymmetric_key_from_pem_bytestring(key_pem=private_key_pem, key_type=signature_algo) signature = sign_message(message=message, signature_algo=signature_algo, key=private_key) return signature
def get_message_signature( self, *, keychain_uid: uuid.UUID, message: bytes, key_type: str, signature_algo: str, ) -> dict: """ Return a signature structure corresponding to the provided key and signature types. """ keypair_pem = self._fetch_keypair_with_caching( keychain_uid=keychain_uid, key_type=key_type) private_key = load_asymmetric_key_from_pem_bytestring( key_pem=keypair_pem["private_key"], key_type=key_type) signature = sign_message(message=message, signature_algo=signature_algo, key=private_key) return signature
def decrypt_with_private_key(self, *, keychain_uid: uuid.UUID, encryption_algo: str, cipherdict: dict) -> bytes: """ Return the message (probably a symmetric key) decrypted with the corresponding key, as bytestring. """ assert (encryption_algo.upper() == "RSA_OAEP" ) # Only supported asymmetric cipher for now self._check_keypair_exists(keychain_uid=keychain_uid, key_type=encryption_algo) private_key_pem = self._key_storage.get_private_key( keychain_uid=keychain_uid, key_type=encryption_algo) private_key = load_asymmetric_key_from_pem_bytestring( key_pem=private_key_pem, key_type=encryption_algo) secret = _decrypt_via_rsa_oaep(cipherdict=cipherdict, key=private_key) return secret
def decrypt_with_private_key( self, *, keychain_uid: uuid.UUID, key_type: str, encryption_algo: str, cipherdict: dict, ) -> bytes: """ Return the message (probably a symmetric key) decrypted with the corresponding key, as bytestring. """ assert key_type.upper() == "RSA" # Only supported key for now assert (encryption_algo.upper() == "RSA_OAEP" ) # Only supported asymmetric cipher for now keypair_pem = self._fetch_keypair_with_caching( keychain_uid=keychain_uid, key_type=key_type) private_key = load_asymmetric_key_from_pem_bytestring( key_pem=keypair_pem["private_key"], key_type=key_type) secret = _decrypt_via_rsa_oaep(cipherdict=cipherdict, key=private_key) return secret
def _encrypt_symmetric_key(self, keychain_uid: uuid.UUID, symmetric_key_data: bytes, conf: dict) -> dict: assert isinstance(symmetric_key_data, bytes), symmetric_key_data key_encryption_algo = conf["key_encryption_algo"] encryption_proxy = self._get_proxy_for_escrow(conf["key_escrow"]) logger.debug("Generating asymmetric key of type %r", key_encryption_algo) subkey_pem = encryption_proxy.get_public_key( keychain_uid=keychain_uid, key_type=key_encryption_algo) logger.debug( "Encrypting symmetric key with asymmetric key of type %r", key_encryption_algo, ) subkey = load_asymmetric_key_from_pem_bytestring( key_pem=subkey_pem, key_type=key_encryption_algo) key_cipherdict = encrypt_bytestring( plaintext=symmetric_key_data, encryption_algo=key_encryption_algo, key=subkey, ) return key_cipherdict
def test_generate_and_load_passphrase_protected_asymmetric_key(): # Both Unicode and Bytes are supported passphrases = ["Thïs is a passphrâse", b"aoh18726"] for passphrase in passphrases: for key_type in SUPPORTED_ASYMMETRIC_KEY_TYPES: keypair = wacryptolib.key_generation.generate_asymmetric_keypair( key_type=key_type, passphrase=passphrase) public_key = load_asymmetric_key_from_pem_bytestring( key_pem=keypair["public_key"], key_type=key_type # NOT encrypted ) assert public_key.export_key if isinstance(passphrase, str): # Different unicode représentations work fine passphrase = unicodedata.normalize("NFD", passphrase) private_key = load_asymmetric_key_from_pem_bytestring( key_pem=keypair["private_key"], key_type=key_type, passphrase=passphrase # Encrypted ) assert private_key.export_key error_matcher = "key format is not supported|Invalid DER encoding" with pytest.raises(KeyLoadingError, match=error_matcher): load_asymmetric_key_from_pem_bytestring( key_pem=keypair["private_key"], key_type=key_type, passphrase=b"wrong passphrase") with pytest.raises(KeyLoadingError, match=error_matcher): load_asymmetric_key_from_pem_bytestring( key_pem=keypair["private_key"], key_type=key_type, passphrase=None # Missing passphrase )
def test_generate_and_load_passphrase_protected_asymmetric_key(): passphrase = b"this is a passphrase" for key_type in SUPPORTED_ASYMMETRIC_KEY_TYPES: keypair = wacryptolib.key_generation.generate_asymmetric_keypair( key_type=key_type, passphrase=passphrase) public_key = load_asymmetric_key_from_pem_bytestring( key_pem=keypair["public_key"], key_type=key_type # NOT encrypted ) assert public_key.export_key private_key = load_asymmetric_key_from_pem_bytestring( key_pem=keypair["private_key"], key_type=key_type, passphrase=passphrase, # Encrypted ) assert private_key.export_key error_matcher = "key format is not supported|Invalid DER encoding" with pytest.raises(ValueError, match=error_matcher): load_asymmetric_key_from_pem_bytestring( key_pem=keypair["private_key"], key_type=key_type, passphrase=b"wrong passphrase", ) with pytest.raises(ValueError, match=error_matcher): load_asymmetric_key_from_pem_bytestring( key_pem=keypair["private_key"], key_type=key_type, passphrase=None, # Missing passphrase )
def test_escrow_api_workflow(): key_storage = DummyKeyStorage() escrow_api = EscrowApi(key_storage=key_storage) keychain_uid = generate_uuid0() keychain_uid_other = generate_uuid0() keychain_uid_unexisting = generate_uuid0() secret = get_random_bytes(127) secret_too_big = get_random_bytes(140) for _ in range(2): generate_free_keypair_for_least_provisioned_key_type( key_storage=key_storage, max_free_keys_per_type=10, key_types=["RSA_OAEP", "DSA_DSS"]) assert key_storage.get_free_keypairs_count("DSA_DSS") == 1 assert key_storage.get_free_keypairs_count("ECC_DSS") == 0 assert key_storage.get_free_keypairs_count("RSA_OAEP") == 1 assert key_storage.get_free_keypairs_count( "RSA_PSS") == 0 # Different from other RSA keys # Keypair is well auto-created by get_public_key(), by default public_key_rsa_oaep_pem = escrow_api.fetch_public_key( keychain_uid=keychain_uid, key_type="RSA_OAEP") with pytest.raises(KeyDoesNotExist, match="not found"): # Key NOT autogenerated escrow_api.fetch_public_key(keychain_uid=generate_uuid0(), key_type="RSA_OAEP", must_exist=True) _public_key_rsa_oaep_pem2 = escrow_api.fetch_public_key( keychain_uid=keychain_uid, key_type="RSA_OAEP") assert _public_key_rsa_oaep_pem2 == public_key_rsa_oaep_pem # Same KEYS! _public_key_rsa_pss_pem = escrow_api.fetch_public_key( keychain_uid=keychain_uid, key_type="RSA_PSS") assert _public_key_rsa_pss_pem != public_key_rsa_oaep_pem # Different KEYS! public_key_rsa_oaep = load_asymmetric_key_from_pem_bytestring( key_pem=public_key_rsa_oaep_pem, key_type="RSA_OAEP") assert key_storage.get_free_keypairs_count("DSA_DSS") == 1 assert key_storage.get_free_keypairs_count("ECC_DSS") == 0 assert key_storage.get_free_keypairs_count("RSA_OAEP") == 0 # Taken assert key_storage.get_free_keypairs_count("RSA_PSS") == 0 signature = escrow_api.get_message_signature(keychain_uid=keychain_uid, message=secret, signature_algo="DSA_DSS") with pytest.raises(ValueError, match="too big"): escrow_api.get_message_signature(keychain_uid=keychain_uid, message=secret_too_big, signature_algo="DSA_DSS") assert key_storage.get_free_keypairs_count("DSA_DSS") == 0 # Taken assert key_storage.get_free_keypairs_count("ECC_DSS") == 0 assert key_storage.get_free_keypairs_count("RSA_OAEP") == 0 assert key_storage.get_free_keypairs_count("RSA_PSS") == 0 public_key_dsa_pem = escrow_api.fetch_public_key(keychain_uid=keychain_uid, key_type="DSA_DSS") public_key_dsa = load_asymmetric_key_from_pem_bytestring( key_pem=public_key_dsa_pem, key_type="DSA_DSS") verify_message_signature(message=secret, signature=signature, key=public_key_dsa, signature_algo="DSA_DSS") signature["digest"] += b"xyz" with pytest.raises(SignatureVerificationError, match="Failed.*verification"): verify_message_signature(message=secret, signature=signature, key=public_key_dsa, signature_algo="DSA_DSS") # Keypair is well auto-created by get_message_signature(), even when no more free keys signature = escrow_api.get_message_signature( keychain_uid=keychain_uid_other, message=secret, signature_algo="RSA_PSS") assert signature # Keypair well autocreated by get_public_key(), even when no more free keys public_key_pem = escrow_api.fetch_public_key( keychain_uid=keychain_uid_other, key_type="DSA_DSS") assert public_key_pem cipherdict = _encrypt_via_rsa_oaep(plaintext=secret, key=public_key_rsa_oaep) # Works even without decryption authorization request, by default: decrypted = escrow_api.decrypt_with_private_key(keychain_uid=keychain_uid, encryption_algo="RSA_OAEP", cipherdict=cipherdict) assert decrypted == secret # NO auto-creation of keypair in decrypt_with_private_key() with pytest.raises(KeyDoesNotExist, match="not found"): escrow_api.decrypt_with_private_key( keychain_uid=keychain_uid_unexisting, encryption_algo="RSA_OAEP", cipherdict=cipherdict) wrong_cipherdict = copy.deepcopy(cipherdict) wrong_cipherdict["digest_list"].append(b"aaabbbccc") with pytest.raises(ValueError, match="Ciphertext with incorrect length"): escrow_api.decrypt_with_private_key(keychain_uid=keychain_uid, encryption_algo="RSA_OAEP", cipherdict=wrong_cipherdict) with pytest.raises(ValueError, match="empty"): escrow_api.request_decryption_authorization( keypair_identifiers=[], request_message="I need this decryption!") # Authorization always granted for now, in dummy implementation result = escrow_api.request_decryption_authorization( keypair_identifiers=[ dict(keychain_uid=keychain_uid, key_type="RSA_OAEP") ], request_message="I need this decryption!", ) assert "accepted" in result["response_message"] assert not result["has_errors"] assert result["keypair_statuses"]["accepted"] # TEST PASSPHRASE PROTECTIONS keychain_uid_passphrased = generate_uuid0() good_passphrase = "good_passphrase" keypair_cipher_passphrased = generate_asymmetric_keypair_for_storage( key_type="RSA_OAEP", key_storage=key_storage, keychain_uid=keychain_uid_passphrased, passphrase=good_passphrase) result = escrow_api.request_decryption_authorization( keypair_identifiers=[ dict(keychain_uid=keychain_uid_passphrased, key_type="RSA_OAEP") ], request_message="I need this decryption too!", ) assert "denied" in result["response_message"] assert result["has_errors"] assert result["keypair_statuses"]["missing_passphrase"] result = escrow_api.request_decryption_authorization( keypair_identifiers=[ dict(keychain_uid=keychain_uid_passphrased, key_type="RSA_OAEP") ], request_message="I need this decryption too!", passphrases=["aaa"], ) assert "denied" in result["response_message"] assert result["has_errors"] assert result["keypair_statuses"]["missing_passphrase"] result = escrow_api.request_decryption_authorization( keypair_identifiers=[ dict(keychain_uid=keychain_uid_passphrased, key_type="RSA_OAEP") ], request_message="I need this decryption too!", passphrases=["dsd", good_passphrase], ) assert "accepted" in result["response_message"] assert not result["has_errors"] assert result["keypair_statuses"]["accepted"] public_key_rsa_oaep2 = load_asymmetric_key_from_pem_bytestring( key_pem=keypair_cipher_passphrased["public_key"], key_type="RSA_OAEP") cipherdict = _encrypt_via_rsa_oaep(plaintext=secret, key=public_key_rsa_oaep2) with pytest.raises(DecryptionError, match="not decrypt"): escrow_api.decrypt_with_private_key( keychain_uid=keychain_uid_passphrased, encryption_algo="RSA_OAEP", cipherdict=cipherdict) with pytest.raises(DecryptionError, match="not decrypt"): escrow_api.decrypt_with_private_key( keychain_uid=keychain_uid_passphrased, encryption_algo="RSA_OAEP", cipherdict=cipherdict, passphrases=["something"], ) decrypted = escrow_api.decrypt_with_private_key( keychain_uid=keychain_uid_passphrased, encryption_algo="RSA_OAEP", cipherdict=cipherdict, passphrases=[good_passphrase], ) assert decrypted == secret assert key_storage.get_free_keypairs_count("DSA_DSS") == 0 assert key_storage.get_free_keypairs_count("ECC_DSS") == 0 assert key_storage.get_free_keypairs_count("RSA_OAEP") == 0 assert key_storage.get_free_keypairs_count("RSA_PSS") == 0
def test_readonly_escrow_api_behaviour(): key_storage = DummyKeyStorage() escrow_api = ReadonlyEscrowApi(key_storage=key_storage) keychain_uid = generate_uuid0() key_type_cipher = "RSA_OAEP" key_type_signature = "RSA_PSS" secret = get_random_bytes(127) for must_exist in (True, False): with pytest.raises(KeyDoesNotExist, match="not found"): escrow_api.fetch_public_key(keychain_uid=keychain_uid, key_type=key_type_signature, must_exist=must_exist) with pytest.raises(KeyDoesNotExist, match="not found"): escrow_api.get_message_signature(keychain_uid=keychain_uid, message=secret, signature_algo="RSA_PSS") # Always accepted for now, dummy implementation result = escrow_api.request_decryption_authorization( keypair_identifiers=[ dict(keychain_uid=keychain_uid, key_type=key_type_cipher) ], request_message="I need this decryption!", ) assert "denied" in result["response_message"] assert result["has_errors"] assert result["keypair_statuses"]["missing_private_key"] # Still no auto-creation of keypair in decrypt_with_private_key() with pytest.raises(KeyDoesNotExist, match="not found"): escrow_api.decrypt_with_private_key(keychain_uid=keychain_uid, encryption_algo=key_type_cipher, cipherdict={}) # Now we generate wanted keys # keypair_cipher = generate_asymmetric_keypair_for_storage( key_type=key_type_cipher, key_storage=key_storage, keychain_uid=keychain_uid) keypair_signature = generate_asymmetric_keypair_for_storage( key_type=key_type_signature, key_storage=key_storage, keychain_uid=keychain_uid) public_key2 = escrow_api.fetch_public_key(keychain_uid=keychain_uid, key_type=key_type_signature, must_exist=must_exist) assert public_key2 == keypair_signature["public_key"] signature = escrow_api.get_message_signature(keychain_uid=keychain_uid, message=secret, signature_algo="RSA_PSS") assert signature and isinstance(signature, dict) private_key_cipher = load_asymmetric_key_from_pem_bytestring( key_pem=keypair_cipher["private_key"], key_type=key_type_cipher) cipherdict = _encrypt_via_rsa_oaep(plaintext=secret, key=private_key_cipher) decrypted = escrow_api.decrypt_with_private_key( keychain_uid=keychain_uid, encryption_algo=key_type_cipher, cipherdict=cipherdict) assert decrypted == secret
def test_escrow_api_workflow(): key_storage = DummyKeyStorage() escrow_api = EscrowApi(key_storage=key_storage) keychain_uid = generate_uuid0() keychain_uid_other = generate_uuid0() keychain_uid_unexisting = generate_uuid0() secret = get_random_bytes(127) secret_too_big = get_random_bytes(140) for _ in range(2): generate_free_keypair_for_least_provisioned_key_type( key_storage=key_storage, max_free_keys_per_type=10, key_types=["RSA_OAEP", "DSA_DSS"], ) assert key_storage.get_free_keypairs_count("DSA_DSS") == 1 assert key_storage.get_free_keypairs_count("ECC_DSS") == 0 assert key_storage.get_free_keypairs_count("RSA_OAEP") == 1 assert ( key_storage.get_free_keypairs_count("RSA_PSS") == 0 ) # Different from other RSA keys # Keypair is well auto-created by get_public_key() public_key_rsa_oaep_pem = escrow_api.get_public_key( keychain_uid=keychain_uid, key_type="RSA_OAEP" ) _public_key_rsa_oaep_pem2 = escrow_api.get_public_key( keychain_uid=keychain_uid, key_type="RSA_OAEP" ) assert _public_key_rsa_oaep_pem2 == public_key_rsa_oaep_pem # Same KEYS! _public_key_rsa_pss_pem = escrow_api.get_public_key( keychain_uid=keychain_uid, key_type="RSA_PSS" ) assert _public_key_rsa_pss_pem != public_key_rsa_oaep_pem # Different KEYS! public_key_rsa_oaep = load_asymmetric_key_from_pem_bytestring( key_pem=public_key_rsa_oaep_pem, key_type="RSA_OAEP" ) assert key_storage.get_free_keypairs_count("DSA_DSS") == 1 assert key_storage.get_free_keypairs_count("ECC_DSS") == 0 assert key_storage.get_free_keypairs_count("RSA_OAEP") == 0 # Taken assert key_storage.get_free_keypairs_count("RSA_PSS") == 0 signature = escrow_api.get_message_signature( keychain_uid=keychain_uid, message=secret, signature_algo="DSA_DSS" ) with pytest.raises(ValueError, match="too big"): escrow_api.get_message_signature( keychain_uid=keychain_uid, message=secret_too_big, signature_algo="DSA_DSS" ) assert key_storage.get_free_keypairs_count("DSA_DSS") == 0 # Taken assert key_storage.get_free_keypairs_count("ECC_DSS") == 0 assert key_storage.get_free_keypairs_count("RSA_OAEP") == 0 assert key_storage.get_free_keypairs_count("RSA_PSS") == 0 public_key_dsa_pem = escrow_api.get_public_key( keychain_uid=keychain_uid, key_type="DSA_DSS" ) public_key_dsa = load_asymmetric_key_from_pem_bytestring( key_pem=public_key_dsa_pem, key_type="DSA_DSS" ) verify_message_signature( message=secret, signature=signature, key=public_key_dsa, signature_algo="DSA_DSS", ) signature["digest"] += b"xyz" with pytest.raises(ValueError, match="not authentic"): verify_message_signature( message=secret, signature=signature, key=public_key_dsa, signature_algo="DSA_DSS", ) # Keypair is well auto-created by get_message_signature(), even when no more free keys signature = escrow_api.get_message_signature( keychain_uid=keychain_uid_other, message=secret, signature_algo="RSA_PSS" ) assert signature # Keypair well autocreated by get_public_key(), even when no more free keys public_key_pem = escrow_api.get_public_key( keychain_uid=keychain_uid_other, key_type="DSA_DSS" ) assert public_key_pem cipherdict = _encrypt_via_rsa_oaep(plaintext=secret, key=public_key_rsa_oaep) # Works even without decryption authorization request, by default: decrypted = escrow_api.decrypt_with_private_key( keychain_uid=keychain_uid, encryption_algo="RSA_OAEP", cipherdict=cipherdict ) # NO auto-creation of keypair in decrypt_with_private_key() with pytest.raises(ValueError, match="Unexisting"): escrow_api.decrypt_with_private_key( keychain_uid=keychain_uid_unexisting, encryption_algo="RSA_OAEP", cipherdict=cipherdict, ) cipherdict["digest_list"].append(b"aaabbbccc") with pytest.raises(ValueError, match="Ciphertext with incorrect length"): escrow_api.decrypt_with_private_key( keychain_uid=keychain_uid, encryption_algo="RSA_OAEP", cipherdict=cipherdict ) assert decrypted == secret result = escrow_api.request_decryption_authorization( keypair_identifiers=[(keychain_uid, "RSA_OAEP")], request_message="I need this decryption!", ) assert result["response_message"] with pytest.raises(ValueError, match="empty"): escrow_api.request_decryption_authorization( keypair_identifiers=[], request_message="I need this decryption!" ) assert key_storage.get_free_keypairs_count("DSA_DSS") == 0 assert key_storage.get_free_keypairs_count("ECC_DSS") == 0 assert key_storage.get_free_keypairs_count("RSA_OAEP") == 0 assert key_storage.get_free_keypairs_count("RSA_PSS") == 0
def test_waescrow_escrow_api_workflow(db): escrow_proxy = TestingServiceProxy(client=Client(), service_url="/json/", version="2.0") keychain_uid = uuid.uuid4() key_type = "RSA" secret = get_random_bytes(101) public_key_pem = _get_jsonrpc_result( escrow_proxy.get_public_key(keychain_uid=keychain_uid, key_type="RSA")) public_key = load_asymmetric_key_from_pem_bytestring( key_pem=public_key_pem, key_type=key_type) signature = _get_jsonrpc_result( escrow_proxy.get_message_signature(keychain_uid=keychain_uid, message=secret, key_type=key_type, signature_algo="PSS")) verify_message_signature(message=secret, signature=signature, key=public_key, signature_algo="PSS") signature["digest"] += b"xyz" with pytest.raises(ValueError, match="Incorrect signature"): verify_message_signature(message=secret, signature=signature, key=public_key, signature_algo="PSS") cipherdict = _encrypt_via_rsa_oaep(plaintext=secret, key=public_key) def _attempt_decryption(): return escrow_proxy.decrypt_with_private_key( keychain_uid=keychain_uid, key_type=key_type, encryption_algo="RSA_OAEP", cipherdict=cipherdict) with freeze_time() as frozen_datetime: with pytest.raises(RuntimeError, match="Decryption not authorized"): _attempt_decryption() keypair_obj = EscrowKeypair.objects.get(keychain_uid=keychain_uid, key_type=key_type) keypair_obj.decryption_authorized_at = timezone.now() + timedelta( hours=2) keypair_obj.save() with pytest.raises( RuntimeError, match="Decryption authorization is not currently active"): _attempt_decryption() # Too early frozen_datetime.tick(delta=timedelta(hours=3)) decrypted = _get_jsonrpc_result(_attempt_decryption()) assert decrypted == secret # It works! cipherdict["digest_list"].append(b"aaabbbccc") with pytest.raises(ValueError, match="Ciphertext with incorrect length"): # Django test client reraises signalled exception escrow_proxy.decrypt_with_private_key(keychain_uid=keychain_uid, key_type=key_type, encryption_algo="RSA_OAEP", cipherdict=cipherdict) frozen_datetime.tick(delta=timedelta( hours=24)) # We hardcode DECRYPTION_AUTHORIZATION_LIFESPAN_H here with pytest.raises( RuntimeError, match="Decryption authorization is not currently active"): _attempt_decryption( ) # Too late, cipherdict is not even used so no ValueError keypair_obj.decryption_authorized_at = None keypair_obj.save() with pytest.raises(RuntimeError, match="Decryption not authorized"): _attempt_decryption() # No more authorization at all