code wiki / _hdl_build / _h2_serve_loopback_gate.nx

_h2_serve_loopback_gate.nx source

↩ module page · 359 lines · 16991 B

1// _h2_serve_loopback_gate.nx -- TUTOR-BOOTSTRAP SCAFFOLD (Claude, authored under 2// the B1 rung(3) ALPN-h2 SERVER workflow of the R4-H2 HTTP/2-transport ladder), 3// NOT credited as team self-authoring. 4// 5// THE LIVE LOOPBACK SERVE GATE: a single fork-based organ that stands up OUR 6// sovereign ALPN-h2 TLS 1.3 SERVER and drives OUR sovereign h2 CLIENT against it 7// over a real loopback socket -- both halves OUR stack, no openssl/nghttp2. 8// Modeled byte-for-byte on the GREEN fork pattern of nx_browse_text_test.nx:102- 9// 126 (socket/bind/listen/fork; child spins then connects; parent accepts). 10// 11// PRE-FORK (shared address space, inherited by both sides): 12// - generate an Ed25519 keypair + build a self-signed X.509 leaf with 13// SAN=localhost (sovereign: nx_csprng_fill + ed25519_pub_from_priv + 14// nx_x509_build_self_signed), validity window covering now. 15// - parse the cert into an X509Cert and add it as the SOLE anchor of a 16// 1-entry TrustStore (a self-signed leaf is its own root; the store is 17// subject-DN-keyed so issuer DN == subject DN finds the anchor). NO 18// permissive/insecure validation context is built (fake-green forbidden). 19// CHILD (the h2 CLIENT): spin a short busy-loop, connect, then 20// nx_tls13_client_session_run_h2 (advertises ALPN ["h2"] only, validates 21// the cert against our 1-entry store) -> h2_tls_get GET "/" -> assert it 22// recovered :status 200 + the exact body bytes OUR server sent. 23// PARENT (the ALPN-h2 SERVER): accept, then 24// nx_tls13_server_session_run_h2_ed25519 (SELECTS ALPN "h2" via emit_ee_alpn 25// + signs CV with the Ed25519 priv) -> app_recv the client's h2 open -> 26// h2_server_recv_request (assert :method GET, :path "/") -> app_send the h2 27// response (SETTINGS+ACK+HEADERS :status 200 + DATA END_STREAM via 28// h2_server_send_response). Parent exit code IS the verdict. 29// 30// HONEST verdict discipline: GREEN ONLY if the parent observes a successful 31// server handshake + a correctly-parsed GET / request AND the child observes 32// :status 200 + the exact body end-to-end. Any handshake failure, cert-validate 33// failure, or status mismatch -> a NAMED negative exit code, never a faked 200. 34// This is the one organ whose GREEN depends on the NAMED cert-self-verify risk: 35// if nx_cert_gen's self-signed Ed25519 cert does not cleanly self-verify under 36// nx_https_cert_pipeline_verify_with_store with SAN=localhost, the live half 37// fails HONESTLY here (the in-memory gate nx_h2_server.nx stays the GREEN floor). 38// 39// FOUNDED ON (composes, each imported EXACTLY ONCE, RC6 double-import avoided): 40// - nx_h2_server.nx: h2_server_recv_request / h2_server_send_response (it 41// transitively pulls h2_conformance + h2_client_over_tls -> all framing/HPACK 42// + h2_tls_get/h2_extract_status_and_body + tls13_ext, ONE import). 43// - nx_tls13_server_session_run_h2.nx: the ALPN-h2 server run (Ed25519 variant) 44// -- imported ONCE; it pulls the server stones + emit_ee_alpn. 45// - nx_tls13_server_session_app_data.nx: server app_send/app_recv. 46// - nx_tls13_client_h2run.nx: the client ALPN-["h2"]-only handshake run. 47// - nx_tls13_client_session.nx (client struct/app keys), nx_x25519_ephemeral 48// (x25519 keypair), nx_csprng (randomness), nx_ed25519_signature 49// (ed25519_pub_from_priv), hub/nx_x509_build (self-signed builder), 50// nx_x509 (x509_parse), nx_x509_trust_store (store alloc/add), 51// nx_tls13_client_validate_certificate (TlsValidationContext), 52// nx_tls13_read_record_from_fd (one record reader for the server app_recv). 53// 54// license_tier: INDEPENDENT_REDERIVE 55// genealogy_id: international-research-sources/ietf/rfc_8446 + rfc_7301 + rfc_9113 + rfc_5280 56// lineage_id: nishi_h2_serve_loopback_b1r3 57 58import "nx_syscalls.nx" 59import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host 60import "nx_h2_server.nx" 61import "nx_tls13_server_session_run_h2.nx" 62import "nx_tls13_server_session_app_data.nx" 63import "nx_tls13_client_h2run.nx" 64import "nx_x25519_ephemeral.nx" 65import "nx_csprng.nx" 66import "nx_ed25519_signature.nx" 67import "hub/nx_x509_build.nx" 68import "nx_x509.nx" 69import "nx_x509_trust_store.nx" 70import "nx_tls13_read_record_from_fd.nx" 71 72const HSL_PORT: i64 = 0x2333 // 9011 73 74// ---- public-domain civil-date math (Howard Hinnant) -- reimplemented inline so 75// we don't import bin/nx_cert_gen.nx (which carries its own main()). ---- 76func hsl_civil_from_days(days: i64, out_y: *i64, out_m: *i64, out_d: *i64) -> i64 { 77 let z: i64 = days + 719468 78 let era: i64 = if z >= 0 then z / 146097 else (z - 146096) / 146097 79 let doe: i64 = z - era * 146097 80 let yoe: i64 = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365 81 let y: i64 = yoe + era * 400 82 let doy: i64 = doe - (365 * yoe + yoe / 4 - yoe / 100) 83 let mp: i64 = (5 * doy + 2) / 153 84 let d: i64 = doy - (153 * mp + 2) / 5 + 1 85 var m: i64 = mp + 3 86 if mp < 10 { m = mp + 3 } else { m = mp - 9 } 87 var yy: i64 = y 88 if m <= 2 { yy = y + 1 } 89 out_y[0] = yy; out_m[0] = m; out_d[0] = d 90 return 0 91} 92func hsl_format_generalized_time(unix_sec: i64, out_15: *u8) -> i64 { 93 let days: i64 = unix_sec / 86400 94 let sod: i64 = unix_sec - days * 86400 95 let hh: i64 = sod / 3600 96 let mm: i64 = (sod - hh * 3600) / 60 97 let ss: i64 = sod - hh * 3600 - mm * 60 98 let yp: *i64 = sys_mmap(8) as *i64 99 let mp: *i64 = sys_mmap(8) as *i64 100 let dp: *i64 = sys_mmap(8) as *i64 101 hsl_civil_from_days(days, yp, mp, dp) 102 let y: i64 = yp[0]; let mo: i64 = mp[0]; let d: i64 = dp[0] 103 out_15[0] = ((0x30 + ((y / 1000) % 10)) & 0xff) as u8 104 out_15[1] = ((0x30 + ((y / 100) % 10)) & 0xff) as u8 105 out_15[2] = ((0x30 + ((y / 10) % 10)) & 0xff) as u8 106 out_15[3] = ((0x30 + ( y % 10)) & 0xff) as u8 107 out_15[4] = ((0x30 + (mo / 10)) & 0xff) as u8 108 out_15[5] = ((0x30 + (mo % 10)) & 0xff) as u8 109 out_15[6] = ((0x30 + (d / 10)) & 0xff) as u8 110 out_15[7] = ((0x30 + (d % 10)) & 0xff) as u8 111 out_15[8] = ((0x30 + (hh / 10)) & 0xff) as u8 112 out_15[9] = ((0x30 + (hh % 10)) & 0xff) as u8 113 out_15[10] = ((0x30 + (mm / 10)) & 0xff) as u8 114 out_15[11] = ((0x30 + (mm % 10)) & 0xff) as u8 115 out_15[12] = ((0x30 + (ss / 10)) & 0xff) as u8 116 out_15[13] = ((0x30 + (ss % 10)) & 0xff) as u8 117 out_15[14] = 0x5A as u8 // 'Z' 118 return 0 119} 120 121// Build the 16-byte sockaddr_in for 127.0.0.1:port (AF_INET=2, htons port, 122// 0x0100007f = 127.0.0.1 in network order). Mirror nx_browse_text_test bt_addr. 123func hsl_addr(out: *u8, port: i64) -> i64 { 124 out[0] = 2 as u8; out[1] = 0 as u8 // AF_INET 125 out[2] = ((port >> 8) & 0xff) as u8 // port hi (network order) 126 out[3] = (port & 0xff) as u8 // port lo 127 out[4] = 127 as u8; out[5] = 0 as u8; out[6] = 0 as u8; out[7] = 1 as u8 // 127.0.0.1 128 var i: i64 = 8 129 while i < 16 { out[i] = 0 as u8; i = i + 1 } 130 return 0 131} 132 133// Generate the shared self-signed Ed25519 leaf (SAN=localhost) + build the 134// 1-entry trust store. Returns 0 ok with *out_cert_der/*out_cert_len/*out_priv 135// set + *out_store the anchor store; negative on any failure. 136func hsl_make_cert( 137 out_cert_der: *u8, out_cert_len: *i64, out_priv: *u8, out_store_box: *i64 138) -> i64 { 139 // 1. Ed25519 keypair. 140 if nx_csprng_fill(out_priv, 32) != 0 { return 0 - 1 } 141 let pub32: *u8 = sys_mmap(32) 142 if ed25519_pub_from_priv(out_priv, pub32) != 0 { return 0 - 2 } 143 144 // 2. validity window: notBefore = now - 1 day, notAfter = now + 365 days. 145 let now: i64 = sys_now_realtime_sec() 146 let nb: *u8 = sys_mmap(16) 147 let na: *u8 = sys_mmap(16) 148 hsl_format_generalized_time(now - 86400, nb) 149 hsl_format_generalized_time(now + 365 * 86400, na) 150 151 // 3. SAN = "localhost" (parallel arrays for nx_x509_inputs_init). 152 let san_name: *u8 = sys_mmap(16); nx_str_cpy(san_name, "localhost" as *u8) 153 let san_ptrs: *i64 = sys_mmap(8) as *i64; san_ptrs[0] = san_name as i64 154 let san_lens: *i64 = sys_mmap(8) as *i64; san_lens[0] = 9 155 let domain: *u8 = sys_mmap(16); nx_str_cpy(domain, "localhost" as *u8) 156 157 // 4. inputs + build self-signed. 158 let inp: *NxX509BuildInputs = sys_mmap(256) as *NxX509BuildInputs 159 let in_rc: i64 = nx_x509_inputs_init(inp, domain, 9, 160 san_ptrs, san_lens, 1, 161 out_priv, pub32, 162 nb, na, now) 163 if in_rc != NX_X509_OK { return 0 - 3 } 164 let cdn: *i64 = sys_mmap(8) as *i64; cdn[0] = 0 165 let brc: i64 = nx_x509_build_self_signed(inp, out_cert_der, 8192, cdn) 166 if brc != NX_X509_OK { return 0 - 4 } 167 out_cert_len[0] = cdn[0] 168 169 // 5. parse + add to a 1-entry trust store (self-signed leaf = its own anchor). 170 let cert: *X509Cert = sys_mmap(512) as *X509Cert 171 if x509_parse(out_cert_der, cdn[0], cert) != 0 { return 0 - 5 } 172 let store: *TrustStore = trust_store_alloc(1) 173 if trust_store_add(store, out_cert_der, cert) != NX_TRUST_STORE_OK { return 0 - 6 } 174 out_store_box[0] = store as i64 175 return 0 176} 177 178// ---- child: the sovereign h2 CLIENT ---- 179// Connect, run the ALPN-["h2"] handshake against OUR server (validating the cert 180// against the inherited 1-entry store), GET "/", assert :status 200 + exact body. 181// Returns 0 ok; a NAMED small positive code on any failure (becomes child exit). 182func hsl_run_client(addr: *u8, store: *TrustStore, exp_body: *u8, exp_len: i64) -> i64 { 183 var spin: i64 = 0 184 while spin < 400000 { spin = spin + 1 } // let the parent reach accept() 185 186 let cfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 187 if cfd < 0 { return 11 } 188 if nx_connect_bounded(cfd, addr, 16, NX_CONN_DEFAULT_MS) < 0 { return 12 } 189 190 // client random + x25519 ephemeral priv. 191 let crand: *u8 = sys_mmap(32) 192 if nx_csprng_fill(crand, 32) != 0 { return 13 } 193 let xpriv: *u8 = sys_mmap(32) 194 if x25519_keypair_private(xpriv) != 0 { return 14 } 195 196 // validation context: our 1-entry store, SNI=localhost, now. 197 let vctx: *TlsValidationContext = sys_mmap(64) as *TlsValidationContext 198 let sni: *u8 = sys_mmap(16); nx_str_cpy(sni, "localhost" as *u8) 199 vctx.store = store 200 vctx.sni_host = sni 201 vctx.sni_host_len = 9 202 vctx.now_epoch = sys_now_realtime_sec() 203 204 let sret: i64 = nx_tls13_client_session_run_h2(cfd, sni, 9, crand, xpriv, vctx) 205 if sret <= 0 { return 20 } // handshake/cert-validate failed -> HONEST 206 let cs: *Tls13ClientSession = sret as *Tls13ClientSession 207 208 let authority: *u8 = sys_mmap(16); nx_str_cpy(authority, "localhost" as *u8) 209 let path: *u8 = sys_mmap(8); nx_str_cpy(path, "/" as *u8) 210 let body: *u8 = sys_mmap(4096) 211 let status: *i64 = sys_mmap(8) as *i64 212 let blen: i64 = h2_tls_get(cs, cfd, authority, 9, path, 1, body, 4096, status) 213 if blen < 0 { return 30 } 214 if status[0] != 200 { return 31 } 215 if blen != exp_len { return 32 } 216 var i: i64 = 0 217 while i < exp_len { if (body[i] & 0xff) != (exp_body[i] & 0xff) { return 33 } i = i + 1 } 218 sys_close(cfd) 219 return 0 // :status 200 + exact body -> child OK 220} 221 222// ---- parent: the sovereign ALPN-h2 SERVER ---- 223// Handshake (SELECT "h2"), recv the client's h2 open request (assert GET /), 224// send the h2 response. Returns 0 ok; a NAMED negative code on failure. 225func hsl_run_server( 226 scfd: i64, srand: *u8, sxpriv: *u8, 227 cert_der: *u8, cert_len: i64, ed_priv: *u8, 228 body: *u8, blen: i64 229) -> i64 { 230 let sret: i64 = nx_tls13_server_session_run_h2_ed25519( 231 scfd, srand, sxpriv, cert_der, cert_len, ed_priv) 232 if sret <= 0 { return sret } // handshake failed -> propagate honest <0 233 let ss: *Tls13ServerSession = sret as *Tls13ServerSession 234 235 // recv the client's first app-data record (its h2 open: preface+SETTINGS+HEADERS). 236 let rec: *u8 = sys_mmap(16645) 237 let rtot: i64 = nx_tls13_read_record_from_fd(scfd, rec, 16645) 238 if rtot < 0 { return 0 - 50 } 239 let openbuf: *u8 = sys_mmap(4096) 240 let on: i64 = nx_tls13_server_session_app_recv(ss, rec, rtot, openbuf, 4096) 241 if on < 0 { return 0 - 51 } 242 243 // parse the request -> assert GET /. 244 let m: *i64 = sys_mmap(8) as *i64 245 let po: *i64 = sys_mmap(8) as *i64 246 let pl: *i64 = sys_mmap(8) as *i64 247 let pbuf: *u8 = sys_mmap(64) 248 let rr: i64 = h2_server_recv_request(openbuf, on, m, po, pl, pbuf) 249 if rr < 0 { return 0 - 52 } 250 if m[0] != H2_METHOD_GET { return 0 - 53 } 251 if pl[0] != 1 { return 0 - 54 } 252 if (pbuf[0] & 0xff) != 0x2f { return 0 - 55 } 253 254 // build the h2 response + app_send it. 255 let resp: *u8 = sys_mmap(512) 256 let rn: i64 = h2_server_send_response(resp, 200, body, blen) 257 if rn < 0 { return 0 - 56 } 258 let outrec: *u8 = sys_mmap(rn + 64) 259 let sn: i64 = nx_tls13_server_session_app_send(ss, resp, rn, outrec, rn + 64) 260 if sn < 0 { return 0 - 57 } 261 var w: i64 = 0 262 while w < sn { 263 let k: i64 = sys_write(scfd, (outrec as i64 + w) as *u8, sn - w) 264 if k <= 0 { return 0 - 58 } 265 w = w + k 266 } 267 return 0 268} 269 270func hsl_log(verdict_green: i64, code: i64) -> i64 { 271 let lfd: i64 = sys_openat_append("knowledge/status/h2_nx_h2_serve_loopback.log" as *u8, 0x1a4) 272 if lfd < 0 { return 0 } 273 sys_write(lfd, "B1-R3-H2-SERVE-LOOPBACK organ=_h2_serve_loopback_gate " as *u8, 54) 274 if verdict_green == 1 { 275 sys_write(lfd, "alpn=h2 status=200 verdict=GREEN\n" as *u8, 32) 276 } else { 277 sys_write(lfd, "verdict=RED code=" as *u8, 16) 278 // small decimal of code 279 var v: i64 = code; if v < 0 { sys_write(lfd, "-" as *u8, 1); v = 0 - v } 280 let t: *u8 = sys_mmap(28); var kk: i64 = 0 281 if v == 0 { t[0] = 48 as u8; kk = 1 } 282 while v > 0 { t[kk] = (48 + (v % 10)) as u8; v = v / 10; kk = kk + 1 } 283 while kk > 0 { kk = kk - 1; sys_write(lfd, (((t as i64)+kk) as *u8), 1) } 284 sys_write(lfd, "\n" as *u8, 1) 285 } 286 sys_close(lfd) 287 return 0 288} 289 290func main() -> i64 { 291 sys_write(1, "_h2_serve_loopback_gate: OUR h2 client <-> OUR ALPN-h2 server, loopback\n" as *u8, 71) 292 293 // ---- shared body the server will serve + the client must recover ---- 294 let body: *u8 = sys_mmap(64) 295 let bsrc: *u8 = "hello from nishi h2 server" as *u8 296 var blen: i64 = 0 297 while bsrc[blen] != (0 as u8) { body[blen] = bsrc[blen]; blen = blen + 1 } // 26 298 299 // ---- PRE-FORK: cert + trust store (inherited by both sides) ---- 300 let cert_der: *u8 = sys_mmap(8192) 301 let cert_len: *i64 = sys_mmap(8) as *i64 302 let ed_priv: *u8 = sys_mmap(32) 303 let store_box: *i64 = sys_mmap(8) as *i64 304 let crc: i64 = hsl_make_cert(cert_der, cert_len, ed_priv, store_box) 305 if crc < 0 { 306 sys_write(1, " FAIL cert/store build\n" as *u8, 24) 307 hsl_log(0, 0 - 90) 308 sys_exit(90); return 90 309 } 310 let store: *TrustStore = store_box[0] as *TrustStore 311 sys_write(1, " cert+1-entry-store built (SAN=localhost, Ed25519 self-signed)\n" as *u8, 63) 312 313 // ---- server x25519 + random ---- 314 let srand: *u8 = sys_mmap(32) 315 if nx_csprng_fill(srand, 32) != 0 { hsl_log(0, 0 - 91); sys_exit(91); return 91 } 316 let sxpriv: *u8 = sys_mmap(32) 317 if x25519_keypair_private(sxpriv) != 0 { hsl_log(0, 0 - 92); sys_exit(92); return 92 } 318 319 // ---- socket / bind / listen ---- 320 let addr: *u8 = sys_mmap(16) 321 hsl_addr(addr, HSL_PORT) 322 let lfd: i64 = sys_socket(AF_INET, SOCK_STREAM, 0) 323 if lfd < 0 { hsl_log(0, 0 - 93); sys_exit(93); return 93 } 324 if sys_bind(lfd, addr, 16) < 0 { hsl_log(0, 0 - 94); sys_exit(94); return 94 } 325 if sys_listen(lfd, 4) < 0 { hsl_log(0, 0 - 95); sys_exit(95); return 95 } 326 327 // ---- fork ---- 328 let pid: i64 = sys_fork() 329 if pid < 0 { hsl_log(0, 0 - 96); sys_exit(96); return 96 } 330 if pid == 0 { 331 // CHILD = h2 CLIENT. 332 let crc2: i64 = hsl_run_client(addr, store, body, blen) 333 sys_exit(crc2); return crc2 334 } 335 336 // PARENT = ALPN-h2 SERVER. 337 let scfd: i64 = sys_accept(lfd) 338 if scfd < 0 { hsl_log(0, 0 - 97); sys_exit(97); return 97 } 339 let sr: i64 = hsl_run_server(scfd, srand, sxpriv, cert_der, cert_len[0], ed_priv, body, blen) 340 341 // reap child + read its exit code. 342 let status: *i64 = sys_mmap(8) as *i64 343 sys_wait4(pid, status, 0) 344 let child_code: i64 = (status[0] >> 8) & 0xff // WEXITSTATUS 345 346 if sr == 0 { 347 if child_code == 0 { 348 sys_write(1, " PASS live loopback: server saw GET /, client saw :status 200 + exact body\n" as *u8, 75) 349 hsl_log(1, 0) 350 sys_exit(0); return 0 351 } 352 sys_write(1, " FAIL client side (exit code printed below)\n" as *u8, 45) 353 hsl_log(0, child_code) 354 sys_exit(child_code); return child_code 355 } 356 sys_write(1, " FAIL server side\n" as *u8, 19) 357 hsl_log(0, sr) 358 sys_exit(0 - sr); return 0 - sr 359}