nx_x509_trust_store_load.nx source
↩ module page · 128 lines · 5054 B
1// nx_x509_trust_store_load.nx -- bulk-load a TrustStore from a
2// length-prefixed bundle of DER certificates.
3//
4// Phase 0b §I.4 piece 10 of the chain-walker arc. The data-
5// loader that turns "embedded CA root bytes" into "ready-to-use
6// trust store". Format-agnostic about how the bundle was
7// produced (Mozilla NSS certdata.txt parser, hand-curated DER
8// blobs, etc.) -- as long as the input matches the layout below,
9// the loader handles the rest.
10//
11// Bundle wire format:
12//
13// [2 bytes BE] cert_count N
14// for each i in 0..N:
15// [3 bytes BE] cert_len_i
16// [cert_len_i bytes] cert_DER_i
17//
18// Total bundle bytes = 2 + sum_i (3 + cert_len_i).
19//
20// For each cert in the bundle:
21// - x509_parse against the cert bytes (caller's bundle_buf at
22// the appropriate offset)
23// - trust_store_add(store, &cert_bytes, parsed_cert)
24// - If parse fails, the loader returns BAD_CERT and the store
25// is partially populated (caller can inspect trust_store_count
26// to see how many succeeded before the failure).
27//
28// Why a custom wire format (vs. NSS certdata.txt):
29// - Sovereign: parser is bits-up + small.
30// - certdata.txt is a complex text format requiring tokenization
31// and base64 decoding. Parsing it bits-up is a separate
32// primitive (queued: nx_nss_certdata_parse.nx). The wire
33// format here is what that parser would emit; or the user can
34// hand-build it from raw DER blobs.
35//
36// Public API:
37// nx_x509_trust_store_load(bundle_buf, bundle_len, store)
38// -> verdict
39// nx_x509_trust_store_load_verdict_is_valid(v) -> 0|1
40//
41// Sealed verdict enum:
42// NX_TRUST_LOAD_OK all certs loaded
43// NX_TRUST_LOAD_TRUNCATED bundle ended mid-record
44// NX_TRUST_LOAD_BAD_CERT x509_parse failed on some entry
45// NX_TRUST_LOAD_STORE_FULL store hit capacity mid-load
46// NX_TRUST_LOAD_EMPTY bundle declares 0 certs
47//
48// Per Cardinals 9 (single-responsibility -- load, not parse the
49// bundle wire format from a higher-level source like certdata.txt),
50// 12 (defensive at boundaries -- bounded reads + partial-load
51// rollback semantics documented), 22 (composition -- this loader
52// is what a higher-level certdata.txt parser compose on top of),
53// 23 (preamble explains why the format is custom).
54//
55// license_tier: INDEPENDENT_REDERIVE
56// genealogy_id: international-research-sources/ietf/rfc_5280
57// lineage_id: nishi_x509_trust_store_load_q10
58
59// nx_safety_envelope:
60// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
61// sil_target: SIL1
62// evidence: [bulk_applied_2026-05-19, x509-trust-store-bulk-loader]
63// verdict: NOT_YET_EVALUATED
64
65import "nx_syscalls.nx"
66import "nx_x509.nx"
67import "nx_x509_trust_store.nx"
68
69const NX_TRUST_LOAD_OK: i64 = 1
70const NX_TRUST_LOAD_TRUNCATED: i64 = 2
71const NX_TRUST_LOAD_BAD_CERT: i64 = 3
72const NX_TRUST_LOAD_STORE_FULL: i64 = 4
73const NX_TRUST_LOAD_EMPTY: i64 = 5
74const NX_TRUST_LOAD_VERDICT_N: i64 = 6
75
76func nx_x509_trust_store_load_verdict_is_valid(v: i64) -> i64 {
77 if v < NX_TRUST_LOAD_OK { return 0 }
78 if v >= NX_TRUST_LOAD_VERDICT_N { return 0 }
79 return 1
80}
81
82// Bulk-load a TrustStore from a length-prefixed bundle.
83//
84// Returns the number of certs loaded via *out_n_loaded (always
85// written, even on partial failure). Caller can use this to
86// detect "loaded the first K then choked on K+1".
87func nx_x509_trust_store_load(
88 bundle_buf: *u8, bundle_len: i64,
89 store: *TrustStore
90) -> i64 {
91 if bundle_len < 2 { return NX_TRUST_LOAD_TRUNCATED }
92 let cert_count: i64 = ((bundle_buf[0] & 0xff) << 8) | (bundle_buf[1] & 0xff)
93 if cert_count == 0 { return NX_TRUST_LOAD_EMPTY }
94
95 var off: i64 = 2
96 var i: i64 = 0
97 while i < cert_count {
98 if off + 3 > bundle_len { return NX_TRUST_LOAD_TRUNCATED }
99 let cert_len: i64 = ((bundle_buf[off] & 0xff) << 16)
100 | ((bundle_buf[off + 1] & 0xff) << 8)
101 | (bundle_buf[off + 2] & 0xff)
102 if cert_len < 1 { return NX_TRUST_LOAD_BAD_CERT }
103 if off + 3 + cert_len > bundle_len { return NX_TRUST_LOAD_TRUNCATED }
104
105 let cert_der: *u8 = bundle_buf + off + 3
106 // Parse the cert into a fresh X509Cert struct. Allocate
107 // a new struct per anchor; the TrustStore holds pointers
108 // to them so they need to outlive the loader.
109 let cert_raw: *u8 = sys_mmap(256)
110 let cert: *X509Cert = cert_raw as *X509Cert
111 let rc: i64 = x509_parse(cert_der, cert_len, cert)
112 if rc < 0 { return NX_TRUST_LOAD_BAD_CERT }
113
114 let add_v: i64 = trust_store_add(store, cert_der, cert)
115 if add_v == NX_TRUST_STORE_FULL { return NX_TRUST_LOAD_STORE_FULL }
116 if add_v != NX_TRUST_STORE_OK { return NX_TRUST_LOAD_BAD_CERT }
117
118 off = off + 3 + cert_len
119 i = i + 1
120 }
121
122 return NX_TRUST_LOAD_OK
123}
124
125// Compile-only smoke. Real KAT in nx_x509_trust_store_load_test.nx.
126func main() -> i64 {
127 return 0
128}