tls13.nx source
↩ module page · 188 lines · 6834 B
1// tls13.nx -- TLS 1.3 (RFC 8446) record-layer constants + framing.
2//
3// This is the skeleton of the TLS 1.3 implementation, not the full
4// state machine. Ships:
5// - ContentType + HandshakeType enum constants
6// - ExtensionType enum constants
7// - Version constants
8// - Record-layer struct definitions + byte-level parse / emit
9//
10// What it does NOT ship (follow-up):
11// - ClientHello / ServerHello / EncryptedExtensions / Finished
12// state-machine driver
13// - HKDF-based key-schedule ordering
14// - 0-RTT / session resumption
15// - Full extension parsing (SNI, ALPN, signature_algorithms, etc.)
16//
17// Pair with AEAD (chacha20-poly1305 shipped; AES-256-GCM pending)
18// + HMAC + HKDF + X25519 + Ed25519 + X.509 primitives that are all
19// already in-tree.
20//
21// References:
22// RFC 8446 (TLS 1.3) -- primary specification
23// RFC 9001 (QUIC TLS) -- alternate framing; outside this file's scope
24// RFC 9578 (X25519Kyber768Draft00) -- PQ hybrid; tls13_extension
25// constants prepared for it
26
27import "syscalls.nx"
28
29// ---- version constants -----------------------------------------
30//
31// TLS 1.3 retains TLS 1.2's legacy_version (0x0303) in the record
32// header for backward compatibility; the real version is signalled
33// via extension 0x002B (supported_versions).
34
35const TLS_LEGACY_VERSION: i64 = 0x0303 // TLS 1.2 wire value
36const TLS_13_VERSION: i64 = 0x0304 // "real" TLS 1.3 advertised via extension
37
38// ---- ContentType (RFC 8446 §B.1) -------------------------------
39
40const CT_INVALID: i64 = 0
41const CT_CHANGE_CIPHER_SPEC: i64 = 20
42const CT_ALERT: i64 = 21
43const CT_HANDSHAKE: i64 = 22
44const CT_APPLICATION_DATA: i64 = 23
45const CT_HEARTBEAT: i64 = 24
46
47// ---- HandshakeType (RFC 8446 §B.3) -----------------------------
48
49const HT_CLIENT_HELLO: i64 = 1
50const HT_SERVER_HELLO: i64 = 2
51const HT_NEW_SESSION_TICKET: i64 = 4
52const HT_END_OF_EARLY_DATA: i64 = 5
53const HT_ENCRYPTED_EXTENSIONS: i64 = 8
54const HT_CERTIFICATE: i64 = 11
55const HT_CERTIFICATE_REQUEST: i64 = 13
56const HT_CERTIFICATE_VERIFY: i64 = 15
57const HT_FINISHED: i64 = 20
58const HT_KEY_UPDATE: i64 = 24
59const HT_MESSAGE_HASH: i64 = 254
60
61// ---- ExtensionType (RFC 8446 §4.2 + IANA updates) --------------
62
63const EXT_SERVER_NAME: i64 = 0
64const EXT_MAX_FRAGMENT_LENGTH: i64 = 1
65const EXT_STATUS_REQUEST: i64 = 5
66const EXT_SUPPORTED_GROUPS: i64 = 10
67const EXT_SIGNATURE_ALGORITHMS: i64 = 13
68const EXT_USE_SRTP: i64 = 14
69const EXT_APPLICATION_LAYER_PROTOCOL: i64 = 16 // ALPN
70const EXT_SIGNED_CERTIFICATE_TIMESTAMP: i64 = 18
71const EXT_PADDING: i64 = 21
72const EXT_PRE_SHARED_KEY: i64 = 41
73const EXT_EARLY_DATA: i64 = 42
74const EXT_SUPPORTED_VERSIONS: i64 = 43
75const EXT_COOKIE: i64 = 44
76const EXT_PSK_KEY_EXCHANGE_MODES: i64 = 45
77const EXT_CERTIFICATE_AUTHORITIES: i64 = 47
78const EXT_OID_FILTERS: i64 = 48
79const EXT_POST_HANDSHAKE_AUTH: i64 = 49
80const EXT_SIGNATURE_ALGORITHMS_CERT: i64 = 50
81const EXT_KEY_SHARE: i64 = 51
82
83// ---- NamedGroup (RFC 8446 §4.2.7) ------------------------------
84//
85// Curves available for key exchange. X25519 is the modern
86// default; Kyber768 (PQC hybrid) additions are draft / RFC 9578.
87
88const NG_SECP256R1: i64 = 23
89const NG_SECP384R1: i64 = 24
90const NG_SECP521R1: i64 = 25
91const NG_X25519: i64 = 29
92const NG_X448: i64 = 30
93// Post-quantum hybrid per RFC 9578 (draft).
94const NG_X25519_KYBER768_DRAFT00: i64 = 0x6399
95
96// ---- SignatureScheme (RFC 8446 §4.2.3) -------------------------
97
98const SS_RSA_PKCS1_SHA256: i64 = 0x0401
99const SS_RSA_PKCS1_SHA384: i64 = 0x0501
100const SS_RSA_PKCS1_SHA512: i64 = 0x0601
101const SS_ECDSA_SECP256R1_SHA256: i64 = 0x0403
102const SS_ECDSA_SECP384R1_SHA384: i64 = 0x0503
103const SS_ED25519: i64 = 0x0807
104const SS_ED448: i64 = 0x0808
105const SS_RSA_PSS_RSAE_SHA256: i64 = 0x0804
106const SS_RSA_PSS_RSAE_SHA384: i64 = 0x0805
107const SS_RSA_PSS_RSAE_SHA512: i64 = 0x0806
108
109// ---- record-layer TLSPlaintext header parse / emit -------------
110//
111// TLSPlaintext {
112// ContentType type; (1 byte)
113// ProtocolVersion legacy; (2 bytes, big-endian, 0x0303)
114// uint16 length; (2 bytes, big-endian, <= 2^14 + 256)
115// opaque fragment[length];
116// }
117
118const TLS_MAX_RECORD: i64 = 16384 // 2^14 bytes TLSPlaintext cap
119
120// Read the 5-byte record header from buf[0..5]. Writes type,
121// version, length to the caller-supplied *i64 slots. Returns 0
122// on success, -1 if buf_len < 5.
123func tls_read_record_header(buf: *u8, buf_len: i64,
124 out_type: *i64,
125 out_ver: *i64,
126 out_len: *i64) -> i64 {
127 if buf_len < 5 { return -1 }
128 *out_type = buf[0]
129 *out_ver = (buf[1] << 8) | buf[2]
130 *out_len = (buf[3] << 8) | buf[4]
131 return 0
132}
133
134// Write a record header. `buf` must hold >= 5 bytes. length
135// must be <= TLS_MAX_RECORD + 256 (TLSCiphertext allows +256
136// for AEAD overhead).
137func tls_write_record_header(buf: *u8,
138 content_type: i64,
139 length: i64) -> i64 {
140 buf[0] = content_type & 0xFF
141 buf[1] = (TLS_LEGACY_VERSION >> 8) & 0xFF
142 buf[2] = TLS_LEGACY_VERSION & 0xFF
143 buf[3] = (length >> 8) & 0xFF
144 buf[4] = length & 0xFF
145 return 5
146}
147
148// Big-endian 24-bit length (used in Handshake message headers).
149func tls_read_u24_be(buf: *u8, off: i64) -> i64 {
150 return (buf[off] << 16) | (buf[off + 1] << 8) | buf[off + 2]
151}
152
153func tls_write_u24_be(buf: *u8, off: i64, v: i64) -> i64 {
154 buf[off] = (v >> 16) & 0xFF
155 buf[off + 1] = (v >> 8) & 0xFF
156 buf[off + 2] = v & 0xFF
157 return 3
158}
159
160// Big-endian 16-bit (used for TLS lengths, extension lengths,
161// etc.).
162func tls_read_u16_be(buf: *u8, off: i64) -> i64 {
163 return (buf[off] << 8) | buf[off + 1]
164}
165
166func tls_write_u16_be(buf: *u8, off: i64, v: i64) -> i64 {
167 buf[off] = (v >> 8) & 0xFF
168 buf[off + 1] = v & 0xFF
169 return 2
170}
171
172// Compile-only smoke: build then parse a record header for a
173// 42-byte handshake message.
174func main() -> i64 {
175 let buf: *u8 = sys_mmap(64)
176 tls_write_record_header(buf, CT_HANDSHAKE, 42)
177 if buf[0] != CT_HANDSHAKE { return 1 }
178 if buf[1] != 0x03 { return 2 }
179 if buf[2] != 0x03 { return 3 }
180
181 let t: *i64 = sys_mmap(16) as *i64
182 let v: *i64 = sys_mmap(16) as *i64
183 let l: *i64 = sys_mmap(16) as *i64
184 tls_read_record_header(buf, 5, t, v, l)
185 if *t != CT_HANDSHAKE { return 4 }
186 if *l != 42 { return 5 }
187 return 0
188}