nx_https_get_live_github_test.nx source
↩ module page · 101 lines · 5194 B
1// nx_https_get_live_github_test.nx -- LIVE external-CA regression gate for the GitHub certificate class.
2//
3// WHY THIS EXISTS (2026-07-15): the live MCP `nx_https_get` on the NAS could NOT fetch github.com/
4// api.github.com/raw.githubusercontent.com ("unknown certificate verification error"), while the current
5// source verifies them fine. Root cause = a STALE NAS binary predating the 2026-06-25 ECDSA-P384 +
6// chain-verify fixes; GitHub's chain (Sectigo/USERTrust ECC + Fastly) exercises exactly that path.
7// This gate makes the capability SELF-VERIFYING: current source must verify GitHub's live chain, and a
8// KNOWN-BAD cert must still be REJECTED (fail-closed) -- so the regression can never land silently again.
9//
10// Joins the live-CA family: nx_https_get_live_{real_ca,google,demo}_test.nx. Network-dependent (positive
11// legs need github reachable); the fail-closed neg-control is safe under network loss (connect-fail also
12// yields "did not fetch"). Deterministic cert-REJECTION is additionally covered offline by
13// nx_tls13_client_validate_certificate_test + nx_x509_chain_verify_test.
14//
15// expect_exit: 0 license_tier: ORIGINAL
16
17import "nx_syscalls.nx"
18import "nx_x509_trust_store.nx"
19import "nx_trust_store_load_from_certdata.nx"
20import "nx_https_get.nx"
21
22const GHT_CERTDATA: *u8 = "data/mozilla_certdata.txt" as *u8
23const GHT_CAP: i64 = 1048576
24
25func ght_put(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
26func ght_pn(v: i64) -> i64 {
27 let b: *u8 = sys_mmap(24)
28 var m: i64 = v
29 if m == 0 { b[0] = 48 as u8; sys_write(1, b, 1); return 0 }
30 if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m }
31 var nd: i64 = 0
32 var t: i64 = m
33 while t > 0 { nd = nd + 1; t = t / 10 }
34 var i: i64 = nd - 1
35 while i >= 0 { b[i] = (48 + (m % 10)) as u8; m = m / 10; i = i - 1 }
36 sys_write(1, b, nd)
37 return 0
38}
39// clean "HTTP/1.1 200" status-line check: bytes 9..11 == "200"
40func ght_is200(out: *u8, n: i64) -> i64 {
41 if n < 12 { return 0 }
42 if out[9] != (50 as u8) { return 0 }
43 if out[10] != (48 as u8) { return 0 }
44 if out[11] != (48 as u8) { return 0 }
45 return 1
46}
47
48// POSITIVE leg: fetch must succeed AND return a 200 status line (i.e., cert verified end-to-end).
49func ght_positive(url: *u8, cr: *u8, priv: *u8, store: *TrustStore, now: i64, out: *u8) -> i64 {
50 ght_put(" GET " as *u8); ght_put(url); ght_put(" -> " as *u8)
51 let n: i64 = nx_https_get(url, cr, priv, store, now, out, GHT_CAP)
52 if n <= 0 { ght_put("FETCH-FAIL code=" as *u8); ght_pn(0 - n); ght_put(" (cert verify FAILED = the regression)\n" as *u8); return 0 }
53 if ght_is200(out, n) == 0 { ght_put("no-200 (bytes=" as *u8); ght_pn(n); ght_put(")\n" as *u8); return 0 }
54 ght_put("200 OK, bytes=" as *u8); ght_pn(n); ght_put(" (cert chain VERIFIED)\n" as *u8)
55 return 1
56}
57
58func main() -> i64 {
59 ght_put("=== nx_https_get_live_github_test -- live external-CA regression (GitHub chain) ===\n" as *u8)
60 let r: i64 = nx_trust_store_load_from_certdata(GHT_CERTDATA, 512, 4194304)
61 if r <= 0 { ght_put("FATAL: trust-store load failed (data/mozilla_certdata.txt)\n" as *u8); sys_exit(1); return 1 }
62 let store: *TrustStore = r as *TrustStore
63 let cas: i64 = trust_store_count(store)
64 ght_put(" trust store CAs=" as *u8); ght_pn(cas); ght_put("\n" as *u8)
65 if cas < 50 { ght_put("FATAL: too few CAs loaded\n" as *u8); sys_exit(1); return 1 }
66
67 let cr: *u8 = sys_mmap(32)
68 var i: i64 = 0
69 while i < 32 { cr[i] = (0xC0 + i) as u8; i = i + 1 }
70 let priv: *u8 = sys_mmap(32)
71 i = 0
72 while i < 32 { priv[i] = (0xA0 + i) as u8; i = i + 1 }
73 let now: i64 = sys_now_realtime_sec()
74 let out: *u8 = sys_mmap(GHT_CAP)
75 var fails: i64 = 0
76
77 // POSITIVE 1: api.github.com (GitHub's own ECC chain)
78 if ght_positive("https://api.github.com/repos/kekzl/imp\x00" as *u8, cr, priv, store, now, out) == 0 { fails = fails + 1 }
79 // POSITIVE 2: raw.githubusercontent.com (Fastly chain -- the other distinct authority)
80 if ght_positive("https://raw.githubusercontent.com/kekzl/imp/HEAD/README.md\x00" as *u8, cr, priv, store, now, out) == 0 { fails = fails + 1 }
81
82 // NEG-CONTROL: a known-EXPIRED cert must be REJECTED (fail-closed). A fetch that SUCCEEDS here = a
83 // security regression (we accepted an invalid cert) -> RED. Network loss -> connect-fail -> also <0 -> safe.
84 ght_put(" NEG expired.badssl.com -> " as *u8)
85 let nb: i64 = nx_https_get("https://expired.badssl.com/\x00" as *u8, cr, priv, store, now, out, GHT_CAP)
86 if nb > 0 {
87 ght_put("ACCEPTED (bytes=" as *u8); ght_pn(nb); ght_put(") -- SECURITY REGRESSION, expired cert must be rejected\n" as *u8)
88 fails = fails + 1
89 } else {
90 ght_put("rejected/unreachable (code=" as *u8); ght_pn(0 - nb); ght_put(") = fail-closed OK\n" as *u8)
91 }
92
93 if fails == 0 {
94 ght_put("NX-HTTPS-GITHUB GREEN -- live GitHub cert chains verify + expired cert rejected (capability self-verified)\n" as *u8)
95 sys_exit(0)
96 return 0
97 }
98 ght_put("NX-HTTPS-GITHUB RED fails=" as *u8); ght_pn(fails); ght_put("\n" as *u8)
99 sys_exit(1)
100 return 1
101}