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}