Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,24 @@ missing. Keep real values in a `.env` you do not commit.
Script output is written to be safe to paste into a public thread: identifiers
are reported as a comparison result or a hash prefix rather than printed. Read
the output before you post it anyway.

## Tests for the #115 Python PSK probe

The tested environment uses Python 3.12.13, pytest 9.1.1, pyOpenSSL 26.4.0,
cryptography 50.0.2, cbor2 6.1.5, and OpenSSL 4.0.3.
These versions describe the tested environment, not minimum requirements.
The OpenSSL fixture uses pyOpenSSL's private CFFI bindings.

Create a virtual environment and install the tested dependencies:

```sh
python3.12 -m venv .venv
.venv/bin/python -m pip install pytest==9.1.1 pyOpenSSL==26.4.0 cryptography==50.0.2 cbor2==6.1.5
cd pr-115-purepy-psk
PYTHONDONTWRITEBYTECODE=1 ../.venv/bin/python -B -m pytest -p no:cacheprovider test_dtls_psk.py test_oven_psk_test.py -q
```

The expected result is 26 passing tests.
The tests require no appliance credentials or hardware.
The OpenSSL tests use memory BIOs.
The probe tests use localhost UDP, including replies from another source port.
18 changes: 12 additions & 6 deletions pr-115-purepy-psk/dtls_psk.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,10 +343,10 @@ def _send_client_hello(self, cookie: bytes) -> None:
+ bytes([1, 0])
)
body += struct.pack("!H", len(extensions)) + extensions
# RFC 6347 4.2.1: the initial ClientHello and the HelloVerifyRequest are
# excluded from the transcript; the cookie ClientHello starts it.
# Keep ClientHello when the server skips HelloVerifyRequest.
# The cookie path resets the transcript before its replacement hello.
self._start_flight()
self._emit_handshake(_HT_CLIENT_HELLO, bytes(body), transcript=bool(cookie))
self._emit_handshake(_HT_CLIENT_HELLO, bytes(body), transcript=True)

def _send_client_flight(self) -> None:
"""ClientKeyExchange + ChangeCipherSpec + Finished."""
Expand Down Expand Up @@ -469,11 +469,17 @@ def _drain_inbox(self) -> None:

def _handle_record(self, record: bytes) -> None:
content_type = record[0]
if record[1:3] != _VERSION:
return
epoch = int.from_bytes(record[3:5], "big")
seq = int.from_bytes(record[5:11], "big")
fragment = record[_RECORD_HEADER:]
if record[1:3] != _VERSION:
# DTLS 1.2 servers may frame HelloVerifyRequest as DTLS 1.0.
# Accept that framing only for the initial plaintext cookie reply.
if not (record[1:3] == b"\xfe\xff" and epoch == 0
and content_type == _CT_HANDSHAKE
and self._state == "sent_hello"
and fragment[:1] == bytes([_HT_HELLO_VERIFY_REQUEST])):
return
seq = int.from_bytes(record[5:11], "big")

expected_epoch = 1 if self._read_active else 0
if epoch != expected_epoch:
Expand Down
Loading