fwdmachine: verify upstream TLS certificates - #5141
Conversation
AI-Assisted: yes (GPT-5.6-Cyber)
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #5141 +/- ##
==========================================
+ Coverage 80.63% 80.72% +0.09%
==========================================
Files 390 390
Lines 96936 96939 +3
==========================================
+ Hits 78168 78258 +90
+ Misses 18768 18681 -87
🚀 New features to boost your workflow:
|
|
The one red job here is not this change.
pkt = UDS_RMBARandomEnumerator._random_memory_addr_pkt()
pkt2 = UDS_RMBARandomEnumerator._random_memory_addr_pkt()
assert pkt != pkt2Those are two independently random packets, so the assertion holds only most of the time. Happy to send a separate pull request making that assertion deterministic if you would like — the straightforward fix is to draw until the two differ, or to compare the generator's spread over a number of draws instead of two single ones. Say the word and I will open it; I did not want to fold an unrelated test change into this one. The rest of the matrix is green. |
ForwardMachinein TLS mode terminates the client's connection and opens its own onward connectionto the real server. The downstream side is an interception by design — it generates lookalike
certificates — but the upstream side is an ordinary TLS client connection.
scapy/fwdmachine.py:365-379loads the system certificates and then switches both forms of authentication off:
Anything on the path between the machine and the origin can therefore present any certificate and
have its data relayed onward. A self-signed upstream and a validly signed one for a different
hostname both went through.
The change uses Python's default client policy, which requires a trusted chain and checks the
hostname:
Two details matter for not breaking working setups.
The hostname checked comes from the downstream ClientHello's SNI, and a client may send none. The
name passed to
wrap_socket()therefore falls back to the destination, matching the idiom thecertificate cache already uses at
scapy/fwdmachine.py:349(ident = server_name or dest):And because interception against an upstream that cannot be verified is a legitimate use of this
class,
verify_upstream=Trueis a constructor option rather than a hard change of behaviour.The added regressions assert the verifying context is used by default, the opt-out still reaches
the old one, and a connection with no SNI is checked against the destination host. Reverting the
source with the tests in place fails them.
Performance was measured on one computer, before and after the fix: building the context took
758.7 ns before and 542.2 ns after — 28.5% faster. Repeat runs moved by about 3%, so this is
larger than the test's own variation.
create_default_context()does in one step what the previousfour lines did separately.