nx_x509_trust_store_load_test.nx source
↩ module page · 195 lines · 8177 B
1// nx_x509_trust_store_load_test.nx -- KAT for the bulk trust-store loader.
2//
3// Builds a 2-cert bundle (each cert is a minimal valid v1 DER cert
4// with empty issuer/subject Names + Ed25519 alg-ids) and verifies
5// the loader walks the format + parses each + adds to the store.
6//
7// expect_exit: 0
8// license_tier: ORIGINAL
9
10import "nx_syscalls.nx"
11import "nx_x509.nx"
12import "nx_x509_trust_store.nx"
13import "nx_x509_trust_store_load.nx"
14
15// Ed25519 AlgorithmIdentifier SEQUENCE { OID 1.3.101.112 } (7 bytes).
16func emit_ed25519_algid(buf: *u8, off: i64) -> i64 {
17 buf[off + 0] = 0x30 as u8
18 buf[off + 1] = 5 as u8
19 buf[off + 2] = 0x06 as u8
20 buf[off + 3] = 3 as u8
21 buf[off + 4] = 0x2B as u8
22 buf[off + 5] = 0x65 as u8
23 buf[off + 6] = 0x70 as u8
24 return 7
25}
26
27// UTCTime TLV "YYMMDDhhmmssZ" (15 bytes).
28func emit_utctime(buf: *u8, off: i64,
29 yyyy: i64, mo: i64, d: i64,
30 h: i64, mi: i64, s: i64) -> i64 {
31 buf[off + 0] = 0x17 as u8
32 buf[off + 1] = 13 as u8
33 let yy: i64 = yyyy - 2000
34 buf[off + 2] = (0x30 + (yy / 10)) as u8
35 buf[off + 3] = (0x30 + (yy % 10)) as u8
36 buf[off + 4] = (0x30 + (mo / 10)) as u8
37 buf[off + 5] = (0x30 + (mo % 10)) as u8
38 buf[off + 6] = (0x30 + (d / 10)) as u8
39 buf[off + 7] = (0x30 + (d % 10)) as u8
40 buf[off + 8] = (0x30 + (h / 10)) as u8
41 buf[off + 9] = (0x30 + (h % 10)) as u8
42 buf[off + 10] = (0x30 + (mi / 10)) as u8
43 buf[off + 11] = (0x30 + (mi % 10)) as u8
44 buf[off + 12] = (0x30 + (s / 10)) as u8
45 buf[off + 13] = (0x30 + (s % 10)) as u8
46 buf[off + 14] = 0x5A as u8
47 return 15
48}
49
50// Build a minimal v1 DER cert at buf[off..]. No SAN extension
51// (extensions are optional per x509_parse). Returns total bytes
52// written.
53//
54// Layout (all short-form lengths -> fits in 169 bytes):
55// serial (3) + sigAlg (7) + issuer empty (2) + validity (32)
56// + subject empty (2) + SPKI (44) = TBS body 90
57// TBS SEQ: 0x30 0x5A + 90 = 92
58// Outer body: 92 + 7 (sigAlg) + 67 (sig BIT STRING) = 166
59// Outer SEQ: 0x30 0x81 0xA6 + 166 = 169
60//
61// `serial_byte` lets the caller distinguish cert #1 from cert #2.
62func build_min_v1_cert(buf: *u8, off: i64, serial_byte: i64) -> i64 {
63 let SPKI_BODY: i64 = 7 + 35 // alg(7) + BIT STRING(35) = 42
64 let SPKI_TOTAL: i64 = 2 + SPKI_BODY // 44
65 let VAL_BODY: i64 = 30
66 let VAL_TOTAL: i64 = 2 + VAL_BODY // 32
67 let TBS_BODY: i64 = 3 + 7 + 2 + VAL_TOTAL + 2 + SPKI_TOTAL // 90
68 let TBS_TOTAL: i64 = 2 + TBS_BODY // 92
69 let SIG_TOTAL: i64 = 67
70 let OUTER_BODY: i64 = TBS_TOTAL + 7 + SIG_TOTAL // 166
71
72 var o: i64 = off
73 // Outer Cert SEQUENCE (long-form length)
74 buf[o] = 0x30 as u8; o = o + 1
75 buf[o] = 0x81 as u8; o = o + 1
76 buf[o] = OUTER_BODY as u8; o = o + 1
77
78 // TBS SEQUENCE (short-form length 0x5A = 90)
79 buf[o] = 0x30 as u8; o = o + 1
80 buf[o] = TBS_BODY as u8; o = o + 1
81
82 // serial INTEGER (1 byte body)
83 buf[o] = 0x02 as u8; buf[o+1] = 0x01 as u8; buf[o+2] = serial_byte as u8; o = o + 3
84
85 // TBS-level sigAlg Ed25519
86 o = o + emit_ed25519_algid(buf, o)
87
88 // issuer Name empty SEQUENCE
89 buf[o] = 0x30 as u8; buf[o+1] = 0x00 as u8; o = o + 2
90
91 // validity SEQUENCE { UTCTime 2023-01-01, UTCTime 2026-01-01 }
92 buf[o] = 0x30 as u8; o = o + 1
93 buf[o] = VAL_BODY as u8; o = o + 1
94 o = o + emit_utctime(buf, o, 2023, 1, 1, 0, 0, 0)
95 o = o + emit_utctime(buf, o, 2026, 1, 1, 0, 0, 0)
96
97 // subject Name empty SEQUENCE
98 buf[o] = 0x30 as u8; buf[o+1] = 0x00 as u8; o = o + 2
99
100 // SPKI SEQUENCE
101 buf[o] = 0x30 as u8; o = o + 1
102 buf[o] = SPKI_BODY as u8; o = o + 1
103 o = o + emit_ed25519_algid(buf, o)
104 buf[o] = 0x03 as u8; o = o + 1 // BIT STRING tag
105 buf[o] = 0x21 as u8; o = o + 1 // length 33
106 buf[o] = 0x00 as u8; o = o + 1 // unused bits
107 var ki: i64 = 0
108 while ki < 32 { buf[o + ki] = 0x00 as u8; ki = ki + 1 }
109 o = o + 32
110
111 // Outer sigAlg Ed25519
112 o = o + emit_ed25519_algid(buf, o)
113
114 // signatureValue BIT STRING (64 garbage bytes)
115 buf[o] = 0x03 as u8; o = o + 1
116 buf[o] = 0x41 as u8; o = o + 1
117 buf[o] = 0x00 as u8; o = o + 1
118 var si: i64 = 0
119 while si < 64 { buf[o + si] = 0xAA as u8; si = si + 1 }
120 o = o + 64
121
122 return o - off
123}
124
125func main() -> i64 {
126 // ---- Test A: empty / undersized bundle -> TRUNCATED ----
127 let tiny: *u8 = sys_mmap(4)
128 let store_t: *TrustStore = trust_store_alloc(4)
129 if nx_x509_trust_store_load(tiny, 0, store_t) != NX_TRUST_LOAD_TRUNCATED { return 1 }
130 if nx_x509_trust_store_load(tiny, 1, store_t) != NX_TRUST_LOAD_TRUNCATED { return 2 }
131
132 // ---- Test B: zero-count bundle -> EMPTY ----
133 let zero: *u8 = sys_mmap(4)
134 zero[0] = 0; zero[1] = 0 // cert_count = 0
135 let store_e: *TrustStore = trust_store_alloc(4)
136 if nx_x509_trust_store_load(zero, 2, store_e) != NX_TRUST_LOAD_EMPTY { return 3 }
137 if trust_store_count(store_e) != 0 { return 4 }
138
139 // ---- Test C: bundle declares 1 cert but truncated cert_len ----
140 let trunc: *u8 = sys_mmap(8)
141 trunc[0] = 0; trunc[1] = 1 // cert_count = 1
142 trunc[2] = 0; trunc[3] = 0 // only 2 of 3 cert_len bytes
143 if nx_x509_trust_store_load(trunc, 4, store_e) != NX_TRUST_LOAD_TRUNCATED { return 5 }
144
145 // ---- Test D: bundle declares cert_len=10 but only 5 bytes follow ----
146 let trunc2: *u8 = sys_mmap(16)
147 trunc2[0] = 0; trunc2[1] = 1 // cert_count = 1
148 trunc2[2] = 0; trunc2[3] = 0; trunc2[4] = 10 // cert_len = 10
149 // Only 5 bytes of data follow (bundle_len passed = 5 + 5 = 10)
150 if nx_x509_trust_store_load(trunc2, 10, store_e) != NX_TRUST_LOAD_TRUNCATED { return 6 }
151
152 // ---- Test E: 1-cert bundle with bad DER -> BAD_CERT ----
153 let bad: *u8 = sys_mmap(16)
154 bad[0] = 0; bad[1] = 1 // cert_count = 1
155 bad[2] = 0; bad[3] = 0; bad[4] = 4 // cert_len = 4
156 bad[5] = 0xFF; bad[6] = 0xFF; bad[7] = 0xFF; bad[8] = 0xFF
157 if nx_x509_trust_store_load(bad, 9, store_e) != NX_TRUST_LOAD_BAD_CERT { return 7 }
158
159 // ---- Test F: 2-cert bundle with REAL DER -> OK + count = 2 ----
160 // Each cert is 169 bytes. Bundle = 2 + (3 + 169) * 2 = 346 bytes.
161 let bundle: *u8 = sys_mmap(512)
162 bundle[0] = 0; bundle[1] = 2 // cert_count = 2
163 // Entry 1: cert_len = 169 (=0x00 0x00 0xA9), cert at offset 5
164 bundle[2] = 0; bundle[3] = 0; bundle[4] = 169 as u8
165 let n1: i64 = build_min_v1_cert(bundle, 5, 0x01)
166 if n1 != 169 { return 10 }
167 // Entry 2: cert_len = 169, cert at offset 5+169+3 = 177
168 bundle[174] = 0; bundle[175] = 0; bundle[176] = 169 as u8
169 let n2: i64 = build_min_v1_cert(bundle, 177, 0x02)
170 if n2 != 169 { return 11 }
171
172 let bundle_total: i64 = 346
173 let store: *TrustStore = trust_store_alloc(4)
174 let v_ok: i64 = nx_x509_trust_store_load(bundle, bundle_total, store)
175 if v_ok != NX_TRUST_LOAD_OK { return 12 }
176 if trust_store_count(store) != 2 { return 13 }
177
178 // ---- Test G: same bundle into store with cap=1 -> STORE_FULL ----
179 let store_small: *TrustStore = trust_store_alloc(1)
180 let v_full: i64 = nx_x509_trust_store_load(bundle, bundle_total, store_small)
181 if v_full != NX_TRUST_LOAD_STORE_FULL { return 14 }
182 if trust_store_count(store_small) != 1 { return 15 } // first succeeded
183
184 // ---- Test H: verdict gate ----
185 if nx_x509_trust_store_load_verdict_is_valid(NX_TRUST_LOAD_OK) != 1 { return 20 }
186 if nx_x509_trust_store_load_verdict_is_valid(NX_TRUST_LOAD_TRUNCATED) != 1 { return 21 }
187 if nx_x509_trust_store_load_verdict_is_valid(NX_TRUST_LOAD_BAD_CERT) != 1 { return 22 }
188 if nx_x509_trust_store_load_verdict_is_valid(NX_TRUST_LOAD_STORE_FULL) != 1 { return 23 }
189 if nx_x509_trust_store_load_verdict_is_valid(NX_TRUST_LOAD_EMPTY) != 1 { return 24 }
190 if nx_x509_trust_store_load_verdict_is_valid(NX_TRUST_LOAD_VERDICT_N) != 0 { return 25 }
191 if nx_x509_trust_store_load_verdict_is_valid(0) != 0 { return 26 }
192 if nx_x509_trust_store_load_verdict_is_valid(0 - 1) != 0 { return 27 }
193
194 return 0
195}