Resumption Handshake (0-RTT)

PALISADE v1.2 — Informative Appendix

This document describes the resumption handshake flow for PALISADE v1.2, which enables 0-RTT early data transmission with strict security restrictions.

This diagram is informative and should be read together with the normative text of the main specification (Section 12). If a discrepancy appears, the normative text wins.

1. Resumption Handshake Flow (v1.2)

The resumption handshake allows clients to resume a previous session using a resumption ticket, enabling 0-RTT early data transmission.

Client                                                Server
------                                                ------

Retrieve ResumeTicket (from previous session)
Generate new ephemeral KEM keypair (K'_c)
resume_nonce = random(32)

ZeroRTTRequest (wire format):
  resume_ticket (serialized)
  new_ephemeral_KEM_pub (K'_c)
  resume_nonce (32 bytes)
  padding                                    ------->

[Early Data] (optional, if permitted)
  epoch_id = 0xFFFFFFFF
  seq >= 1
  Only KEEPALIVE0 or RESUME_INTENT frames
  Encrypted with early data keys            ------->  (buffered)

                                         Phase 1: Ticket Validation
                                         - Verify ticket signature
                                         - Decrypt TicketInner
                                         - Check ticket not expired
                                         - Atomically validate and mark used
                                         - Extract PSK from ticket
                                         
                                         Phase 2: Key Exchange
                                         - Generate server_nonce'
                                         - Generate K'_s (ephemeral KEM)
                                         - ss'_c = Encap(K'_c) → CT'_c
                                         - ss'_s = Encap(K'_s) → CT'_s
                                         
                                         Phase 3: Early Data Validation
                                         - Check max_early_data_bytes limit
                                         - Validate early data frames (allowlist)
                                         - Set accept_0rtt flag
                                         
                                         Phase 4: Transcript & Signature
                                         - Encode canonical transcript
                                           (ClientHelloResume || ServerHelloResume)
                                         - Sign transcript_hash
                                         - Derive resumption keys

                               <-------  ServerHelloResume:
                                           version (0x12)
                                           accept_0rtt (0x00 or 0x01)
                                           server_nonce' (32 bytes)
                                           K'_s (ephemeral KEM public key)
                                           CT'_c (KEM ciphertext for client)
                                           CT'_s (KEM ciphertext for server)
                                           server_certificate
                                           server_signature
                                           padding

ss'_c = Decap(CT'_c)
ss'_s = Decap(CT'_s)
Encode canonical transcript
Verify ServerSig(transcript_hash)
Derive resumption keys via key schedule:
  - Uses PSK from ticket
  - Binds to transcript_hash
  - Derives epoch 0 keys (C2S, S2C)

[Encrypted Data]               <------>  [Encrypted Data]
  (epoch_id = 0, normal traffic)

                    === ESTABLISHED ===

Round Trips: 0-RTT (zero round trip time) for early data, 1-RTT for handshake completion

Key Points:

  • Client uses a previously obtained ResumeTicket
  • Fresh KEM exchange ensures forward secrecy (keys not reused)
  • Ticket validation and "mark used" MUST be atomic to prevent replay
  • Early data is optional and subject to strict restrictions
  • Resumption key schedule uses PSK from ticket, not full handshake secrets

2. Message Structures (v1.2)

MessageFieldTypeNotes
ZeroRTTRequestresume_ticketvariableSerialized ResumeTicket (opaque to client)
new_ephemeral_KEM_pubvariableFresh KEM public key (K'_c)
resume_nonce32 bytesCryptographically random
paddingvariableVariable-length padding
ServerHelloResumeversionuint80x12 for PALISADE v1.2
accept_0rttuint80x00 = rejected, 0x01 = accepted
server_nonce'32 bytesCryptographically random
K'_svariableServer's ephemeral KEM public key
CT'_cvariableKEM encapsulation to K'_c
CT'_svariableKEM encapsulation to K'_s
server_certificatevariableServer's post-quantum public key
server_signaturevariableSignature over canonical transcript

3. Early Data Restrictions (Section 12.8)

Early data in PALISADE v1.2 is subject to strict security restrictions to prevent replay attacks and state corruption.

Epoch and Sequence Rules

  • Early data MUST use epoch_id = 0xFFFFFFFF (reserved)
  • Early data MUST use seq >= 1
  • Early data MUST use key_phase=0 (key_phase=1 is invalid)
  • Early data sequence numbers are independent from application traffic

Permitted Early Data Frames

Early data MUST contain only the following frame types (strict allowlist):

  • KEEPALIVE0 (0x04): Zero-payload keepalive for connection liveness
  • RESUME_INTENT (0x05): Signals resumption attempt without state changes

All other frame types in early data MUST be silently ignored.

Prohibited Effects

Early data MUST NOT cause:

  • Epoch advancement or key derivation
  • Primary path binding updates (migration)
  • Replay window modifications for non-early epochs
  • Durable protocol state transitions
  • Non-idempotent or security-sensitive operations

Server Enforcement

  • Server MUST enforce ticket-defined max_early_data_bytes limit
  • Server MUST ignore client-offered early data limits (prevents replay-amplification)
  • If early data is rejected, server MUST discard it without side effects
  • Early data is replayable and MUST be treated as advisory only

4. Ticket Validation (Section 12.5)

The server MUST perform atomic ticket validation to prevent replay attacks:

Validation StepRequirementRationale
Signature VerificationVerify ticket server signatureEnsures ticket authenticity
DecryptionDecrypt TicketInner using server secretAccess ticket contents
Expiration CheckVerify ticket not expiredEnforces validity window
Single-Use CheckAtomically validate and mark usedPrevents replay (MUST be atomic)
Early Data PolicyCheck server policy and ticket limitsEnforces early data restrictions

Critical: Ticket validation and "mark used" MUST be atomic. Non-atomic implementations allow race conditions where two threads both validate a ticket before either marks it used, resulting in early data replay.

5. Resumption Key Derivation

Resumption uses a separate key schedule that binds to the resumption transcript:

Resumption Key Schedule Input:
  PSK = extracted from ResumeTicket
  ss'_c = Decap(CT'_c) (KEM shared secret)
  resume_nonce = client nonce (32 bytes)
  server_nonce' = server nonce (32 bytes)
  transcript_hash = SHA3-256(canonical_ClientHelloResume || canonical_ServerHelloResume)

Key Derivation (HKDF):
  resumption_secret = HKDF-Extract(salt=PSK, IKM=ss'_c)
  master_secret = HKDF-Extract(salt=resumption_secret, IKM=transcript_hash)
  
Epoch 0 Keys:
  epoch_0_keys = HKDF-Expand(master_secret, "palisade epoch 0", 64)
  C2S_key = epoch_0_keys[0:32]  (client-to-server)
  S2C_key = epoch_0_keys[32:64]  (server-to-client)
  C2S_IV = HKDF-Expand(master_secret, "palisade iv c2s 0", 12)
  S2C_IV = HKDF-Expand(master_secret, "palisade iv s2c 0", 12)

Note: Keys are cryptographically independent from original session keys
      (beyond PSK input). Forward secrecy is maintained.

PALISADE Protocol Specification Draft 00

INFORMATIONAL