code wiki / (root) / nx_tls13_server_session_run_h2.nx

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}