Code change:
2.3. <del> The cTLS handshake framing is same as the TLS 1.3 handshake framing, except for two changes: The length field is omitted. The HelloRetryRequest message is a true handshake message instead of a specialization of ServerHello. </del> <ins> When "template.handshakeFraming" is not "true", cTLS uses a custom handshake framing that saves space by relying on the record layer for message lengths.  (This saves 3 bytes per message compared to TLS, or 9 bytes compared to DTLS.)  This compact framing is defined by the "CTLSHandshake" and "CTLSDatagramHandshake" structs. Any handshake type registered in the IANA TLS HandshakeType Registry can be conveyed in a "CTLS[Datagram]Handshake", but not all messages are actually allowed on a given connection.  This definition shows the messages types supported in "CTLSHandshake" as of TLS 1.3 and DTLS 1.3, but any future message types are also permitted. Each "CTLSHandshake" or "CTLSDatagramHandshake" MUST be conveyed as a single "CTLSClientPlaintext.fragment", "CTLSServerPlaintext.fragment", or "CTLSCiphertext.encrypted_record", and is therefore limited to a maximum length of "2^16-1" or less. When operating over UDP, large "CTLSDatagramHandshake" messages will also require the use of IP fragmentation, which is sometimes undesirable.  Operators can avoid these concerns by setting "template.handshakeFraming = true". </ins> 3. <del> In general, we retain the basic structure of each individual TLS handshake message.  However, the following handshake messages have been modified for space reduction and cleaned up to remove pre-TLS 1.3 baggage. </del> <ins> In general, we retain the basic structure of each individual TLS or DTLS handshake message.  However, the following handshake messages have been modified for space reduction and cleaned up to remove pre- TLS 1.3 baggage. </ins> 3.1. The cTLS ClientHello is defined as follows. <del> The "profile_id" field MUST identify the profile that is in use.  A zero-length ID corresponds to the cTLS default protocol. </del> 3.2. We redefine ServerHello in the following way. 3.3. <del> The HelloRetryRequest has the following format. </del> <ins> In cTLS, the HelloRetryRequest message is a true handshake message instead of a specialization of ServerHello.  The HelloRetryRequest has the following format. </ins> The HelloRetryRequest is the same as the ServerHello above but without the unnecessary sentinel Random value.

Related discussion:
text: FYI, this PR now moves out of the ClientHello back into (now called ). This avoids confusing questions about how to demultiplex profiles that use different modes.
LGTM.
This would allow recipients to detect the end of a handshake message from the CTLSPlaintext header alone, allowing the recipient to reconstruct the entire handshake message before parsing it. Currently, a streaming parser is required in order to detect the end. Suggested implementation: Senders set contenttype = ctlshandshake_end for a message’s final fragment.
I can see why you want that, but it's not generally a TLS property, and I'm reluctant to change things.
AFAIK, TLS does not require a streaming ClientHello parser. The recipient can read (uint24) and then buffer the remainder before parsing. cTLS, as currently specified, does not have . This means that the recipient has to cross all the way down into the extension parsing code before it finds out that the ClientHello is still incomplete. Given the complex template-driven handshake parsing code, I think making a streaming parser required is ill-advised. Given the desire for compactness, I think a flag of some kind on the final handshake message record seems like a reasonable solution, replacing the uint24 length. It would also simplify Pseudorandom cTLS. However, if that's not appealing, you could simply reintroduce .
NAME proposed a solution on slide 5 : I'm fine with that, so long as it doesn't end up requiring recipients to do something heroic to reconstruct the ClientHello. Thus, "framing = none" should imply that messages cannot be fragmented at all (max size limited to 2^14-1). I'm not sure I see the utility of the explicit distinction between "length" and "full". Surely "length" is not usable with DTLS due to reordering, and "full" is redundant in TLS/TCP. Perhaps we only need a single bit to enable/disable framing, and length-vs-full can be implicit from the transport.
I could live with this. Objections?
Solved by
The current text doesn’t mention this, although it seems relatively clear how it’s expected to work (using the DTLS Handshake struct).