code wiki / (root) / nx_x509_trust_store_load_test.nx

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}