nx_tls13_server_session_run_h2.nx source
↩ module page · 295 lines · 14450 B
1// nx_tls13_server_session_run_h2.nx -- TUTOR-BOOTSTRAP SCAFFOLD (Claude, authored
2// under the B1 rung(3) ALPN-h2 SERVER workflow of the R4-H2 HTTP/2-transport
3// ladder), NOT credited as team self-authoring.
4//
5// THE ALPN-h2-SELECTING TLS 1.3 server handshake orchestrator. It is the
6// byte-for-byte twin of nx_tls13_server_session_run.nx (the ECDSA path) EXCEPT
7// the EncryptedExtensions it emits SELECTS ALPN "h2" (via the new
8// nx_tls13_server_session_emit_ee_alpn) instead of the base empty no-ext EE.
9// Consequence (RFC 7301 §3.2 / RFC 8446 §4.3.1): an h2-only sovereign client
10// (nx_tls13_client_session_run_h2) that advertised ALPN ["h2"] sees its protocol
11// SELECTED in the encrypted EE, so a CONNECTED session here means the
12// application-data channel IS HTTP/2 -- the server half of "TLS ALPN selects h2".
13//
14// FOUNDED ON (composes, does NOT reinvent -- anti-orphan law; each imported
15// EXACTLY ONCE, the RC6 double-import landmine avoided):
16// - the SAME 10 server stones nx_tls13_server_session_run imports
17// (recv_ch/emit_sh/emit_hrr/derive_hs/derive_traffic/emit_certificate/emit_cv/
18// emit_sf/recv_cf) -- the handshake body is identical to the proven base run.
19// - nx_tls13_server_session_emit_ee_alpn (B1 rung(3), NEW): the ALPN-h2 EE
20// stone, called at the EE step IN PLACE of the base emit_ee. We still import
21// nx_tls13_server_session_emit_ee too (the base no-ext stone) so a caller may
22// pick either, AND because the linker include-guards it (it is also pulled
23// transitively) -- importing it once here is the single canonical import.
24// This module deliberately does NOT import nx_tls13_server_session_run.nx (that
25// would double-define _srun_write_n etc.); helpers carry a _srunh2_ prefix and
26// the verdict consts an _H2 namespace so a caller may import BOTH this and the
27// base server run with no symbol clash.
28//
29// BACK-FILL: the team RE-AUTHORS this from the DATA spec via the
30// emitter-of-emitters (X-AUT-006c/e/f); this hand scaffold is the sanctioned
31// one-time bootstrap only (meter-integrity, mirror
32// nx_tls13_server_session_run.nx:1-39 / nx_tls13_client_h2run.nx:1-33).
33//
34// license_tier: INDEPENDENT_REDERIVE
35// genealogy_id: international-research-sources/ietf/rfc_8446 + ietf/rfc_7301 + ietf/rfc_9113
36// lineage_id: nishi_tls13_server_session_run_h2_b1r3
37
38import "nx_syscalls.nx"
39import "nx_tls13.nx"
40import "nx_tls13_record.nx"
41import "nx_tls13_read_record_from_fd.nx"
42import "nx_tls13_transcript.nx"
43import "nx_tls13_server_session.nx"
44import "nx_tls13_server_session_recv_ch.nx"
45import "nx_tls13_server_session_emit_sh.nx"
46import "nx_tls13_server_session_emit_hrr.nx"
47import "nx_tls13_server_session_derive_hs.nx"
48import "nx_tls13_server_session_derive_traffic.nx"
49import "nx_tls13_server_session_emit_ee.nx"
50import "nx_tls13_server_session_emit_ee_alpn.nx"
51import "nx_tls13_server_session_emit_certificate.nx"
52import "nx_tls13_server_session_emit_cv.nx"
53import "nx_tls13_server_session_emit_sf.nx"
54import "nx_tls13_server_session_recv_cf.nx"
55
56const NX_TLS13_SRUNH2_OK: i64 = 1
57const NX_TLS13_SRUNH2_RECV_CH_FAIL: i64 = 3
58const NX_TLS13_SRUNH2_EMIT_SH_FAIL: i64 = 4
59const NX_TLS13_SRUNH2_WRITE_SH_FAIL: i64 = 5
60const NX_TLS13_SRUNH2_DERIVE_HS_FAIL: i64 = 6
61const NX_TLS13_SRUNH2_DERIVE_TRAFFIC_FAIL: i64 = 7
62const NX_TLS13_SRUNH2_EMIT_EE_FAIL: i64 = 8
63const NX_TLS13_SRUNH2_WRITE_EE_FAIL: i64 = 9
64const NX_TLS13_SRUNH2_EMIT_CERT_FAIL: i64 = 10
65const NX_TLS13_SRUNH2_WRITE_CERT_FAIL: i64 = 11
66const NX_TLS13_SRUNH2_EMIT_CV_FAIL: i64 = 12
67const NX_TLS13_SRUNH2_WRITE_CV_FAIL: i64 = 13
68const NX_TLS13_SRUNH2_EMIT_SF_FAIL: i64 = 14
69const NX_TLS13_SRUNH2_WRITE_SF_FAIL: i64 = 15
70const NX_TLS13_SRUNH2_READ_CF_FAIL: i64 = 16
71const NX_TLS13_SRUNH2_RECV_CF_FAIL: i64 = 17
72const NX_TLS13_SRUNH2_EMIT_HRR_FAIL: i64 = 18
73const NX_TLS13_SRUNH2_WRITE_HRR_FAIL: i64 = 19
74const NX_TLS13_SRUNH2_READ_CH_FAIL: i64 = 2
75
76const NX_TLS13_SRUNH2_CH_BUF_BYTES: i64 = 16645
77const NX_TLS13_SRUNH2_OUT_BUF_BYTES: i64 = 16645
78const NX_TLS13_SRUNH2_MAX_HS_RECORDS: i64 = 4
79
80// Loop writes n bytes to fd via sys_write. Returns 0 OK, -1 fail.
81func _srunh2_write_n(fd: i64, buf: *u8, n: i64) -> i64 {
82 var off: i64 = 0
83 while off < n {
84 let w: i64 = sys_write(fd, (buf as i64 + off) as *u8, n - off)
85 if w <= 0 { return 0 - 1 }
86 off = off + w
87 }
88 return 0
89}
90
91// Read the ClientHello (+ HRR round trip) into the session. Verbatim twin of
92// _srun_recv_client_hello (nx_tls13_server_session_run.nx:106-147). Returns 0
93// OK, or a negative -(NX_TLS13_SRUNH2_*) verdict on failure.
94func _srunh2_recv_client_hello(fd: i64, s: *Tls13ServerSession) -> i64 {
95 let ch_rec: *u8 = sys_mmap(NX_TLS13_SRUNH2_CH_BUF_BYTES)
96 let ch_total: i64 = nx_tls13_read_record_from_fd(fd, ch_rec, NX_TLS13_SRUNH2_CH_BUF_BYTES)
97 if ch_total < 0 { return 0 - NX_TLS13_SRUNH2_READ_CH_FAIL }
98 let r1: i64 = nx_tls13_server_session_recv_ch(
99 s,
100 (ch_rec + NX_TLS13_RECORD_HEADER_LEN),
101 ch_total - NX_TLS13_RECORD_HEADER_LEN)
102 if r1 == NX_TLS13_SSESSION_OK { return 0 }
103 if r1 != NX_TLS13_SSESSION_NEED_HRR { return 0 - NX_TLS13_SRUNH2_RECV_CH_FAIL }
104
105 nx_tls13_transcript_replace_with_hrr(s.transcript)
106 let hrr_buf: *u8 = sys_mmap(NX_TLS13_SRUNH2_OUT_BUF_BYTES)
107 let n_hrr: i64 = nx_tls13_server_session_emit_hrr(s, hrr_buf, NX_TLS13_SRUNH2_OUT_BUF_BYTES)
108 if n_hrr <= 0 { return 0 - NX_TLS13_SRUNH2_EMIT_HRR_FAIL }
109 if _srunh2_write_n(fd, hrr_buf, n_hrr) < 0 { return 0 - NX_TLS13_SRUNH2_WRITE_HRR_FAIL }
110
111 var loop_count: i64 = 0
112 while loop_count < NX_TLS13_SRUNH2_MAX_HS_RECORDS {
113 let ch2_rec: *u8 = sys_mmap(NX_TLS13_SRUNH2_CH_BUF_BYTES)
114 let ch2_total: i64 = nx_tls13_read_record_from_fd(fd, ch2_rec, NX_TLS13_SRUNH2_CH_BUF_BYTES)
115 if ch2_total < 0 { return 0 - NX_TLS13_SRUNH2_READ_CH_FAIL }
116 if (ch2_rec[0] & 0xff) == 0x14 {
117 loop_count = loop_count + 1
118 } else {
119 let r2: i64 = nx_tls13_server_session_recv_ch(
120 s,
121 (ch2_rec + NX_TLS13_RECORD_HEADER_LEN),
122 ch2_total - NX_TLS13_RECORD_HEADER_LEN)
123 if r2 != NX_TLS13_SSESSION_OK { return 0 - NX_TLS13_SRUNH2_RECV_CH_FAIL }
124 return 0
125 }
126 }
127 return 0 - NX_TLS13_SRUNH2_READ_CH_FAIL
128}
129
130// Drive the server-side handshake to CONNECTED, SELECTING ALPN "h2" in the
131// EncryptedExtensions. Twin of nx_tls13_server_session_run (the ECDSA path)
132// EXCEPT the EE step calls nx_tls13_server_session_emit_ee_alpn. Returns the
133// session as i64 (cast caller-side to *Tls13ServerSession) on CONNECTED, or a
134// negative -(NX_TLS13_SRUNH2_*) verdict on failure.
135func nx_tls13_server_session_run_h2(
136 fd: i64,
137 srv_rand: *u8, srv_x25519_priv: *u8,
138 cert_der: *u8, cert_der_len: i64,
139 ecdsa_priv_be: *u8
140) -> i64 {
141 let s: *Tls13ServerSession = nx_tls13_server_session_new(srv_rand, srv_x25519_priv)
142 if (s as i64) == 0 { return 0 - NX_TLS13_SRUNH2_RECV_CH_FAIL }
143
144 // ---- Stone 2: read ClientHello (+ HelloRetryRequest if needed) ----
145 let rch: i64 = _srunh2_recv_client_hello(fd, s)
146 if rch < 0 { return rch }
147
148 // ---- Stone 3: emit ServerHello + write (complete TLSPlaintext) ----
149 let sh_buf: *u8 = sys_mmap(NX_TLS13_SRUNH2_OUT_BUF_BYTES)
150 let n_sh: i64 = nx_tls13_server_session_emit_sh(s, sh_buf, NX_TLS13_SRUNH2_OUT_BUF_BYTES)
151 if n_sh <= 0 { return 0 - NX_TLS13_SRUNH2_EMIT_SH_FAIL }
152 if _srunh2_write_n(fd, sh_buf, n_sh) < 0 { return 0 - NX_TLS13_SRUNH2_WRITE_SH_FAIL }
153
154 // ---- Stone 4 + 5: derive handshake secrets + traffic keys ----
155 let r4: i64 = nx_tls13_server_session_derive_hs_secrets(s)
156 if r4 != NX_TLS13_SSESSION_OK { return 0 - NX_TLS13_SRUNH2_DERIVE_HS_FAIL }
157 let r5: i64 = nx_tls13_server_session_derive_traffic(s)
158 if r5 != NX_TLS13_SSESSION_OK { return 0 - NX_TLS13_SRUNH2_DERIVE_TRAFFIC_FAIL }
159
160 // ---- Stone 6 (ALPN-h2 VARIANT): emit EncryptedExtensions SELECTING "h2" ----
161 // The ONLY difference from the base run: emit_ee_alpn instead of emit_ee.
162 let ee_buf: *u8 = sys_mmap(NX_TLS13_SRUNH2_OUT_BUF_BYTES)
163 let n_ee: i64 = nx_tls13_server_session_emit_ee_alpn(s, ee_buf, NX_TLS13_SRUNH2_OUT_BUF_BYTES)
164 if n_ee <= 0 { return 0 - NX_TLS13_SRUNH2_EMIT_EE_FAIL }
165 if _srunh2_write_n(fd, ee_buf, n_ee) < 0 { return 0 - NX_TLS13_SRUNH2_WRITE_EE_FAIL }
166
167 // ---- Stone 6.5: emit Certificate chain ----
168 let cert_buf: *u8 = sys_mmap(NX_TLS13_SRUNH2_OUT_BUF_BYTES)
169 let n_cert: i64 = nx_tls13_server_session_emit_certificate_chain(
170 s, cert_der, cert_der_len, cert_buf, NX_TLS13_SRUNH2_OUT_BUF_BYTES
171 )
172 if n_cert <= 0 { return 0 - NX_TLS13_SRUNH2_EMIT_CERT_FAIL }
173 if _srunh2_write_n(fd, cert_buf, n_cert) < 0 { return 0 - NX_TLS13_SRUNH2_WRITE_CERT_FAIL }
174
175 // ---- Stone 7.5: emit CertificateVerify ----
176 let cv_buf: *u8 = sys_mmap(NX_TLS13_SRUNH2_OUT_BUF_BYTES)
177 let n_cv: i64 = nx_tls13_server_session_emit_cv(
178 s, ecdsa_priv_be, cv_buf, NX_TLS13_SRUNH2_OUT_BUF_BYTES
179 )
180 if n_cv <= 0 { return 0 - NX_TLS13_SRUNH2_EMIT_CV_FAIL }
181 if _srunh2_write_n(fd, cv_buf, n_cv) < 0 { return 0 - NX_TLS13_SRUNH2_WRITE_CV_FAIL }
182
183 // ---- Stone 7: emit ServerFinished ----
184 let sf_buf: *u8 = sys_mmap(NX_TLS13_SRUNH2_OUT_BUF_BYTES)
185 let n_sf: i64 = nx_tls13_server_session_emit_sf(s, sf_buf, NX_TLS13_SRUNH2_OUT_BUF_BYTES)
186 if n_sf <= 0 { return 0 - NX_TLS13_SRUNH2_EMIT_SF_FAIL }
187 if _srunh2_write_n(fd, sf_buf, n_sf) < 0 { return 0 - NX_TLS13_SRUNH2_WRITE_SF_FAIL }
188
189 // ---- Stone 8: read ClientFinished record + verify (skip optional CCS) ----
190 var loop_count: i64 = 0
191 var keep: i64 = 1
192 while keep == 1 {
193 if loop_count >= NX_TLS13_SRUNH2_MAX_HS_RECORDS {
194 return 0 - NX_TLS13_SRUNH2_READ_CF_FAIL
195 }
196 let cf_rec: *u8 = sys_mmap(NX_TLS13_SRUNH2_CH_BUF_BYTES)
197 let cf_total: i64 = nx_tls13_read_record_from_fd(
198 fd, cf_rec, NX_TLS13_SRUNH2_CH_BUF_BYTES
199 )
200 if cf_total < 0 { return 0 - NX_TLS13_SRUNH2_READ_CF_FAIL }
201 if (cf_rec[0] & 0xff) == 0x14 {
202 loop_count = loop_count + 1
203 } else {
204 let r8: i64 = nx_tls13_server_session_recv_cf(s, cf_rec, cf_total)
205 if r8 != NX_TLS13_SSESSION_OK { return 0 - NX_TLS13_SRUNH2_RECV_CF_FAIL }
206 keep = 0
207 }
208 }
209
210 return s as i64
211}
212
213// Ed25519 ALPN-h2 server run -- the Ed25519-signature sibling of
214// nx_tls13_server_session_run_h2. Identical flow EXCEPT step 7.5 uses
215// nx_tls13_server_session_emit_cv_ed25519 with a 32-byte Ed25519 priv (instead
216// of the ECDSA emit_cv). Used by the live loopback serve gate because the
217// sovereign self-signed cert (nx_cert_gen default path) is Ed25519-signed, which
218// avoids the ECDSA-priv-format risk while still SELECTING ALPN "h2" via
219// emit_ee_alpn. Cert MUST be Ed25519-signed X.509 with SAN covering the SNI.
220func nx_tls13_server_session_run_h2_ed25519(
221 fd: i64,
222 srv_rand: *u8, srv_x25519_priv: *u8,
223 cert_der: *u8, cert_der_len: i64,
224 ed25519_priv_32: *u8
225) -> i64 {
226 let s: *Tls13ServerSession = nx_tls13_server_session_new(srv_rand, srv_x25519_priv)
227 if (s as i64) == 0 { return 0 - NX_TLS13_SRUNH2_RECV_CH_FAIL }
228
229 let rch: i64 = _srunh2_recv_client_hello(fd, s)
230 if rch < 0 { return rch }
231
232 let sh_buf: *u8 = sys_mmap(NX_TLS13_SRUNH2_OUT_BUF_BYTES)
233 let n_sh: i64 = nx_tls13_server_session_emit_sh(s, sh_buf, NX_TLS13_SRUNH2_OUT_BUF_BYTES)
234 if n_sh <= 0 { return 0 - NX_TLS13_SRUNH2_EMIT_SH_FAIL }
235 if _srunh2_write_n(fd, sh_buf, n_sh) < 0 { return 0 - NX_TLS13_SRUNH2_WRITE_SH_FAIL }
236
237 let r4: i64 = nx_tls13_server_session_derive_hs_secrets(s)
238 if r4 != NX_TLS13_SSESSION_OK { return 0 - NX_TLS13_SRUNH2_DERIVE_HS_FAIL }
239 let r5: i64 = nx_tls13_server_session_derive_traffic(s)
240 if r5 != NX_TLS13_SSESSION_OK { return 0 - NX_TLS13_SRUNH2_DERIVE_TRAFFIC_FAIL }
241
242 // ALPN-h2 VARIANT: emit EncryptedExtensions SELECTING "h2".
243 let ee_buf: *u8 = sys_mmap(NX_TLS13_SRUNH2_OUT_BUF_BYTES)
244 let n_ee: i64 = nx_tls13_server_session_emit_ee_alpn(s, ee_buf, NX_TLS13_SRUNH2_OUT_BUF_BYTES)
245 if n_ee <= 0 { return 0 - NX_TLS13_SRUNH2_EMIT_EE_FAIL }
246 if _srunh2_write_n(fd, ee_buf, n_ee) < 0 { return 0 - NX_TLS13_SRUNH2_WRITE_EE_FAIL }
247
248 let cert_buf: *u8 = sys_mmap(NX_TLS13_SRUNH2_OUT_BUF_BYTES)
249 let n_cert: i64 = nx_tls13_server_session_emit_certificate(
250 s, cert_der, cert_der_len, cert_buf, NX_TLS13_SRUNH2_OUT_BUF_BYTES
251 )
252 if n_cert <= 0 { return 0 - NX_TLS13_SRUNH2_EMIT_CERT_FAIL }
253 if _srunh2_write_n(fd, cert_buf, n_cert) < 0 { return 0 - NX_TLS13_SRUNH2_WRITE_CERT_FAIL }
254
255 // Stone 7.5 DIFFERENCE: Ed25519 sig path.
256 let cv_buf: *u8 = sys_mmap(NX_TLS13_SRUNH2_OUT_BUF_BYTES)
257 let n_cv: i64 = nx_tls13_server_session_emit_cv_ed25519(
258 s, ed25519_priv_32, cv_buf, NX_TLS13_SRUNH2_OUT_BUF_BYTES
259 )
260 if n_cv <= 0 { return 0 - NX_TLS13_SRUNH2_EMIT_CV_FAIL }
261 if _srunh2_write_n(fd, cv_buf, n_cv) < 0 { return 0 - NX_TLS13_SRUNH2_WRITE_CV_FAIL }
262
263 let sf_buf: *u8 = sys_mmap(NX_TLS13_SRUNH2_OUT_BUF_BYTES)
264 let n_sf: i64 = nx_tls13_server_session_emit_sf(s, sf_buf, NX_TLS13_SRUNH2_OUT_BUF_BYTES)
265 if n_sf <= 0 { return 0 - NX_TLS13_SRUNH2_EMIT_SF_FAIL }
266 if _srunh2_write_n(fd, sf_buf, n_sf) < 0 { return 0 - NX_TLS13_SRUNH2_WRITE_SF_FAIL }
267
268 var loop_count: i64 = 0
269 var keep: i64 = 1
270 while keep == 1 {
271 if loop_count >= NX_TLS13_SRUNH2_MAX_HS_RECORDS {
272 return 0 - NX_TLS13_SRUNH2_READ_CF_FAIL
273 }
274 let cf_rec: *u8 = sys_mmap(NX_TLS13_SRUNH2_CH_BUF_BYTES)
275 let cf_total: i64 = nx_tls13_read_record_from_fd(
276 fd, cf_rec, NX_TLS13_SRUNH2_CH_BUF_BYTES
277 )
278 if cf_total < 0 { return 0 - NX_TLS13_SRUNH2_READ_CF_FAIL }
279 if (cf_rec[0] & 0xff) == 0x14 {
280 loop_count = loop_count + 1
281 } else {
282 let r8: i64 = nx_tls13_server_session_recv_cf(s, cf_rec, cf_total)
283 if r8 != NX_TLS13_SSESSION_OK { return 0 - NX_TLS13_SRUNH2_RECV_CF_FAIL }
284 keep = 0
285 }
286 }
287
288 return s as i64
289}
290
291// Compile-only smoke. The real proof is the live loopback serve gate that
292// composes this with the h2 server framing + the client h2 run.
293func main() -> i64 {
294 return 0
295}