Skip to main content

Module handshake

Module handshake 

Source
Expand description

macula 12’s post-quantum connection handshake, as macula_handshake and macula-go build and check it: the opener, challenge, CONNECT, HELLO and status frames (D16, D22), as CBOR bytes without the length prefix.

The client opens with an opener. The station answers with a challenge: its carried identity key, its TLS binding and status statement, and a fresh nonce. The client checks the challenge against the node_id it dialed and the leaf it received, before it signs anything, and answers with CONNECT: its identity and CONNECT keys, the CONNECT binding and status statement, and a proof by the CONNECT key. The station checks CONNECT, the puzzle before any signature, and answers with HELLO. Status frames renew a peer’s statement on the open connection.

Every frame decodes under the decoding rule and must hold exactly the keys of its type, each of its type and length. Close reasons are local: a refusing station sends only a HELLO with one coarse refusal code.

Version 5 (macula 13.2, DESIGN_NEIGHBOUR_CHANNEL_BINDING) binds both ends to the TLS session. The opener and the challenge stay version 4; the client picks 4 or 5 in CONNECT, and the station answers HELLO in the same version. In version 5 the CONNECT proof (V2) also covers E, the session’s TLS exporter value, and the client’s capabilities, and HELLO carries the station’s session proof, signed by its identity key over E, both frames and both node_ids, only after every check on CONNECT has passed. A station with no exporter answers a v5 CONNECT as an old station does, with unsupported_version.

Structs§

Client
What a station knows of an accepted client.
ClientSession
What a client brings to a handshake: its profile, the node_id it dialed, the leaf DER it received in this TLS handshake, its carried identity key, its CONNECT key with binding and status statement, its capability bits, the time in milliseconds, the realm membership endorsement CONNECT carries, empty for a node that holds none, the version CONNECT carries (VERSION or VERSION_5), and this connection’s TLS exporter, which version 5 needs.
Peer
What a connection checks a peer’s status frames against: the profile, the identity key and binding the handshake verified, and the time in milliseconds.
Station
What a client knows of the station once it has checked the challenge, and what its HELLO must answer: the version the CONNECT carried and, in version 5, what the session proof covers.
StationMaterial
What a station precomputes for its challenges: its carried identity key, and the TLS binding and status statement for the leaf it presents.
StationSession
What a station brings to a CONNECT check: its profile, the challenge bytes it sent, the leaf DER this connection presented, its puzzle difficulty and mode, its capability bits, the time in milliseconds, and what it binds a v5 session with. Without v5 it answers only version 4.
StationV5
A station’s means to bind a v5 session: this connection’s TLS exporter, and its session proof signer.

Enums§

HandshakeError
The handshake’s close reasons, named as macula names them. A binding or status statement that fails its check closes with its BindingError.
PuzzleMode
How a station treats a client’s node_id puzzle.
PuzzleResult
What a station found of a client’s puzzle.
RefusalCode
The one coarse reason a refusing HELLO carries.

Constants§

EXPORTER_LABEL
The TLS 1.3 exporter label (RFC 8446 section 7.5) handshake v5 binds to, over the context client node_id || station node_id, 32 bytes.
VERSION
The handshake’s frame version: 4, as macula 12’s. A peer on another version hears unsupported_version.
VERSION_5
The channel-bound handshake: both proofs over the TLS session’s exporter value.

Functions§

accept_connect
Checks a CONNECT, and returns the verdict with the HELLO to send. It checks, in macula’s order: the frame, the carried keys and the proof’s length, that each key serves one purpose, the puzzle on the derived node_id before any signature, the CONNECT binding and status statement, and the proof against the challenge this station sent and the leaf it presented. A refusal is the local close reason, and the HELLO refuses with one coarse code.
answer_challenge
Checks a challenge and, when every check passes, returns the CONNECT to send. It checks, in macula’s order: the frame, the profile, the station’s carried key, that each key in view serves one purpose, the station’s node_id against the one dialed, the TLS binding against the leaf received, and the status statement. It signs nothing before all of them pass.
challenge
A station’s challenge, with a fresh nonce. The station keeps the bytes it sends, for the proof check.
opener
The client’s first frame on the control stream. It carries nothing that relates to identity.
read_hello
The client’s reading of HELLO against the version its CONNECT carried (station, as answer_challenge returned it): the station’s capability bits, or why not. After a v5 CONNECT an accepting HELLO must be version 5 with a session proof that verifies under the station’s identity key over this session. A v4 refusal is how an old station answers (HandshakeError::Refused); a v4 acceptance is never taken as a v4 connection.
read_opener
The station’s check of the first frame.
read_status
Checks a peer’s status frame, and returns when its statement expires.
status_frame
A status frame carrying a fresh status statement, sent at every reissue.

Type Aliases§

Exporter
A TLS 1.3 session’s exporter: label, context and length to bytes, or None when the session gives none. Both ends of one session export the same bytes.
SessionProofSigner
Signs a v5 session proof with the station’s identity key for the client named, within the station’s budget (HandshakeError::SessionProofRate past it).