code wiki / _hdl_build / nx_x509_trust_root_kat.nx
nx_x509_trust_root_kat.nx source
↩ module page · 112 lines · 6660 B
1// nx_x509_trust_root_kat.nx -- the RSA-verify crypto gate the ECDSA fixture couldn't provide (HONESTY SYSTEM
2// follow-up 2026-07-16). A self-signed ROOT's signature is over its own TBS with its own key, so it verifies
3// under its OWN extracted public key -- a self-contained RSA KAT needing NO chain-splitting and NO external
4// vector. We load the REAL Mozilla bundle (data/mozilla_certdata.txt), find real RSA-2048 (sig=256) and
5// RSA-4096 (sig=512) roots, and prove: extract issuer key -> self-verify -> OK ; corrupt a byte -> FAIL.
6// This directly exercises (with real crypto that CANNOT fake-green) all four flagged organs:
7// nx_x509_pubkey_extract_rsa, nx_x509_verify_rsa_pkcs1_sha256, + the _4096 pair.
8// license_tier: ORIGINAL expect_exit:0
9import "nx_syscalls.nx"
10import "nx_x509.nx"
11import "nx_x509_trust_store.nx"
12import "nx_trust_store_load_from_certdata.nx"
13import "nx_x509_pubkey_rsa.nx"
14import "nx_x509_verify_rsa_pkcs1_sha256.nx"
15import "nx_x509_pubkey_rsa_4096.nx"
16import "nx_x509_verify_rsa_pkcs1_sha256_4096.nx"
17
18func kw(s: *u8) -> i64 { var n:i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
19func kn(v: i64) -> i64 { let b:*u8=sys_mmap(24); var m:i64=v; if m<0{sys_write(1,"-" as *u8,1);m=0-m} let t:*u8=sys_mmap(24); var k:i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var j:i64=0; while j<k{b[j]=t[k-1-j];j=j+1} sys_write(1,b,k); return 0 }
20
21const ANCHOR_STRIDE: i64 = 16 // TrustAnchor = { buf:*u8, cert:*X509Cert } = two 8-byte pointers
22
23func main() -> i64 {
24 var pass: i64 = 0
25 let r: i64 = nx_trust_store_load_from_certdata("data/mozilla_certdata.txt\x00" as *u8, 1024, 8388608)
26 if r <= 0 { kw("ERROR trust store load rc=" as *u8); kn(r); kw("\n" as *u8); return 9 }
27 let store: *TrustStore = r as *TrustStore
28 let nroots: i64 = store.n
29 kw(" loaded roots=" as *u8); kn(nroots); kw("\n" as *u8)
30
31 let out_n: *i64 = sys_mmap(80*8) as *i64
32 let out_e: *i64 = sys_mmap(16) as *i64
33
34 var rsa2048_ok: i64 = 0
35 var rsa4096_ok: i64 = 0
36 var first2048: i64 = 0 - 1
37 var first4096: i64 = 0 - 1
38
39 var i: i64 = 0
40 while i < nroots {
41 let a: *TrustAnchor = ((store.anchors as i64) + i * ANCHOR_STRIDE) as *TrustAnchor
42 let buf: *u8 = a.buf
43 let cert: *X509Cert = a.cert
44 let sl: i64 = cert.sig_len
45 if sl == 256 {
46 let erc: i64 = nx_x509_pubkey_extract_rsa(buf, cert, out_n, out_e)
47 if erc >= 0 {
48 let v: i64 = nx_x509_verify_rsa_pkcs1_sha256(((buf as i64)+cert.tbs_off) as *u8, cert.tbs_len, ((buf as i64)+cert.sig_off) as *u8, 256, out_n, out_e[0])
49 if v == NX_X509_RSA_PKCS1_SHA256_OK { rsa2048_ok = rsa2048_ok + 1; if first2048 < 0 { first2048 = i } }
50 }
51 }
52 if sl == 512 {
53 let erc4: i64 = nx_x509_pubkey_extract_rsa_4096(buf, cert, out_n, out_e)
54 if erc4 >= 0 {
55 let v4: i64 = nx_x509_verify_rsa_pkcs1_sha256_4096(((buf as i64)+cert.tbs_off) as *u8, cert.tbs_len, ((buf as i64)+cert.sig_off) as *u8, 512, out_n, out_e[0])
56 if v4 == NX_X509_RSA_PKCS1_SHA256_4096_OK { rsa4096_ok = rsa4096_ok + 1; if first4096 < 0 { first4096 = i } }
57 }
58 }
59 i = i + 1
60 }
61 kw(" RSA-2048 roots self-verified=" as *u8); kn(rsa2048_ok); kw(" RSA-4096 roots self-verified=" as *u8); kn(rsa4096_ok); kw("\n" as *u8)
62
63 // T1: at least one real RSA-2048 root self-verifies (extract_rsa + verify_rsa, real crypto)
64 if rsa2048_ok >= 1 { pass = pass + 1; kw("T1 rsa2048-selfverify PASS\n" as *u8) } else { kw("T1 FAIL no rsa2048 root verified\n" as *u8) }
65
66 // T2 (NEG): corrupt the first verified RSA-2048 root's signature -> must NOT verify
67 if first2048 >= 0 {
68 let a2: *TrustAnchor = ((store.anchors as i64) + first2048 * ANCHOR_STRIDE) as *TrustAnchor
69 let buf2: *u8 = a2.buf
70 let c2: *X509Cert = a2.cert
71 nx_x509_pubkey_extract_rsa(buf2, c2, out_n, out_e)
72 let bad: *u8 = sys_mmap(300)
73 var j: i64 = 0
74 while j < 256 { bad[j] = buf2[c2.sig_off+j]; j = j + 1 }
75 bad[10] = (bad[10] + 1) & 0xff
76 let vb: i64 = nx_x509_verify_rsa_pkcs1_sha256(((buf2 as i64)+c2.tbs_off) as *u8, c2.tbs_len, bad, 256, out_n, out_e[0])
77 if vb != NX_X509_RSA_PKCS1_SHA256_OK { pass = pass + 1; kw("T2 rsa2048-corrupt-rejected PASS\n" as *u8) } else { kw("T2 FAIL corrupt rsa2048 sig accepted\n" as *u8) }
78 } else { kw("T2 SKIP (no rsa2048 root)\n" as *u8) }
79
80 // T3: at least one RSA-4096 root self-verifies (exercises the _4096 pair)
81 if rsa4096_ok >= 1 { pass = pass + 1; kw("T3 rsa4096-selfverify PASS\n" as *u8) } else { kw("T3 FAIL no rsa4096 root verified\n" as *u8) }
82
83 // T4 (NEG): corrupt the first verified RSA-4096 root's signature -> must NOT verify
84 if first4096 >= 0 {
85 let a4: *TrustAnchor = ((store.anchors as i64) + first4096 * ANCHOR_STRIDE) as *TrustAnchor
86 let buf4: *u8 = a4.buf
87 let c4: *X509Cert = a4.cert
88 nx_x509_pubkey_extract_rsa_4096(buf4, c4, out_n, out_e)
89 let bad4: *u8 = sys_mmap(600)
90 var j4: i64 = 0
91 while j4 < 512 { bad4[j4] = buf4[c4.sig_off+j4]; j4 = j4 + 1 }
92 bad4[10] = (bad4[10] + 1) & 0xff
93 let vb4: i64 = nx_x509_verify_rsa_pkcs1_sha256_4096(((buf4 as i64)+c4.tbs_off) as *u8, c4.tbs_len, bad4, 512, out_n, out_e[0])
94 if vb4 != NX_X509_RSA_PKCS1_SHA256_4096_OK { pass = pass + 1; kw("T4 rsa4096-corrupt-rejected PASS\n" as *u8) } else { kw("T4 FAIL corrupt rsa4096 sig accepted\n" as *u8) }
95 } else { kw("T4 SKIP (no rsa4096 root)\n" as *u8) }
96
97 // T5: verdict validators well-formed (+neg) for BOTH families
98 var ok5: i64 = 1
99 if nx_x509_rsa_pkcs1_sha256_verdict_is_valid(NX_X509_RSA_PKCS1_SHA256_OK) != 1 { ok5 = 0 }
100 if nx_x509_rsa_pkcs1_sha256_verdict_is_valid(777) != 0 { ok5 = 0 }
101 if nx_x509_rsa_pkcs1_sha256_4096_verdict_is_valid(NX_X509_RSA_PKCS1_SHA256_4096_OK) != 1 { ok5 = 0 }
102 if nx_x509_rsa_pkcs1_sha256_4096_verdict_is_valid(777) != 0 { ok5 = 0 }
103 if ok5 == 1 { pass = pass + 1; kw("T5 verdict-validators PASS\n" as *u8) } else { kw("T5 FAIL verdict validators\n" as *u8) }
104
105 // T6: population sanity -- a real Mozilla bundle has many roots, most RSA
106 if nroots >= 50 { if rsa2048_ok + rsa4096_ok >= 20 { pass = pass + 1; kw("T6 population PASS\n" as *u8) } else { kw("T6 FAIL too few RSA roots verified\n" as *u8) } } else { kw("T6 FAIL store too small\n" as *u8) }
107
108 kw("NX-X509-TRUST-ROOT-KAT " as *u8); kn(pass); kw("/6" as *u8)
109 if pass == 6 { kw(" GREEN\n" as *u8); return 0 }
110 kw(" RED\n" as *u8)
111 return 1
112}