Add missing tests for `SSHAgentClient.query_extensions` runtime errors
Marco Ricci

Marco Ricci commited on 2024-11-27 20:23:06
Zeige 1 geänderte Dateien mit 67 Einfügungen und 1 Löschungen.


Currently, this is still a white-box, maliciously compliant design that
relies heavily on implementation details of the function under test.
That said, the failure cases being triggered here are all SSH agent
protocol violations, which would otherwise be difficult to trigger in
"real" SSH agents.
... ...
@@ -23,7 +23,7 @@ from derivepassphrase import _types, cli, ssh_agent, vault
23 23
 if TYPE_CHECKING:
24 24
     from collections.abc import Iterable
25 25
 
26
-    from typing_extensions import Any
26
+    from typing_extensions import Any, Buffer
27 27
 
28 28
 
29 29
 class TestStaticFunctionality:
... ...
@@ -595,6 +595,72 @@ class TestAgentInteraction:
595 595
         ):
596 596
             client.request(request_code, b'', response_code=response_code)
597 597
 
598
+    @pytest.mark.parametrize(
599
+        'response_data',
600
+        [
601
+            b'\xde\xad\xbe\xef',
602
+            b'\x00\x00\x00\x0fwrong extension',
603
+            b'\x00\x00\x00\x05query\xde\xad\xbe\xef',
604
+            b'\x00\x00\x00\x05query\x00\x00\x00\x04ext1\x00\x00',
605
+        ],
606
+    )
607
+    def test_350_query_extensions_malformed_responses(
608
+        self,
609
+        monkeypatch: pytest.MonkeyPatch,
610
+        running_ssh_agent: tests.RunningSSHAgentInfo,
611
+        response_data: bytes,
612
+    ) -> None:
613
+        del running_ssh_agent
614
+
615
+        def request(
616
+            code: int | _types.SSH_AGENTC,
617
+            payload: Buffer,
618
+            /,
619
+            *,
620
+            response_code: (
621
+                Iterable[_types.SSH_AGENT | int]
622
+                | _types.SSH_AGENT
623
+                | int
624
+                | None
625
+            ) = None,
626
+        ) -> tuple[int, bytes] | bytes:
627
+            request_codes = {
628
+                _types.SSH_AGENTC.EXTENSION,
629
+                _types.SSH_AGENTC.EXTENSION.value,
630
+            }
631
+            assert code in request_codes
632
+            response_codes = {
633
+                _types.SSH_AGENT.EXTENSION_RESPONSE,
634
+                _types.SSH_AGENT.EXTENSION_RESPONSE.value,
635
+                _types.SSH_AGENT.SUCCESS,
636
+                _types.SSH_AGENT.SUCCESS.value,
637
+            }
638
+            assert payload == b'\x00\x00\x00\x05query'
639
+            if response_code is None:  # pragma: no cover
640
+                return (
641
+                    _types.SSH_AGENT.EXTENSION_RESPONSE.value,
642
+                    response_data,
643
+                )
644
+            if isinstance(  # pragma: no cover
645
+                response_code, (_types.SSH_AGENT, int)
646
+            ):
647
+                assert response_code in response_codes
648
+                return response_data
649
+            for single_code in response_code:  # pragma: no cover
650
+                assert single_code in response_codes
651
+            return response_data  # pragma: no cover
652
+
653
+        with (
654
+            monkeypatch.context() as monkeypatch2,
655
+            ssh_agent.SSHAgentClient() as client,
656
+        ):
657
+            monkeypatch2.setattr(client, 'request', request)
658
+            with pytest.raises(
659
+                RuntimeError,
660
+                match='Malformed response|does not match request'
661
+            ):
662
+                client.query_extensions()
663
+
598 664
 
599 665
 class TestHypotheses:
600 666
     @hypothesis.given(strategies.integers(min_value=0, max_value=0xFFFFFFFF))
601 667