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 test_jsonrpc_trustee_signature(live_server): jsonrpc_url = _get_trustee_jsonrpc_url(live_server) trustee_proxy = JsonRpcProxy( url=jsonrpc_url, response_error_handler=status_slugs_response_error_handler) keychain_uid = generate_uuid0() payload_signature_algo = "DSA_DSS" secret = get_random_bytes(101) secret_too_big = get_random_bytes(150) public_key_signature_pem = trustee_proxy.fetch_public_key( keychain_uid=keychain_uid, key_algo=payload_signature_algo) public_key_signature = load_asymmetric_key_from_pem_bytestring( key_pem=public_key_signature_pem, key_algo=payload_signature_algo) signature = trustee_proxy.get_message_signature( keychain_uid=keychain_uid, message=secret, signature_algo=payload_signature_algo) with pytest.raises(ValidationError, match="too big"): trustee_proxy.get_message_signature( keychain_uid=keychain_uid, message=secret_too_big, signature_algo=payload_signature_algo, ) verify_message_signature( message=secret, signature=signature, key=public_key_signature, signature_algo=payload_signature_algo, ) signature["signature_value"] += b"xyz" with pytest.raises(SignatureVerificationError, match="not authentic|Incorrect signature"): verify_message_signature( message=secret, signature=signature, key=public_key_signature, signature_algo=payload_signature_algo, )
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_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