code wiki / (root) / nx_ecdsa_p384_real_bisect_test.nx

nx_ecdsa_p384_real_bisect_test.nx source

↩ module page · 286 lines · 10644 B

1// nx_ecdsa_p384_real_bisect_test.nx -- bisect ECDSA-P384 verify 2// pipeline against the cert2 -> cert3 pair of the real example.com 3// chain to locate the root cause of VUI_VERIFY_FAIL (verdict 6). 4// 5// Steps (each value is compared inline with a golden hex computed 6// off-substrate via Python cryptography): 7// 1. SHA-384(cert2.tbs) -- 48 bytes 8// 2. nx_ecdsa_sig_parse_der_384(cert2.sig) -- r, s (12 LE limbs each) 9// 3. nx_x509_pubkey_extract_ec_p384(cert3) -- pub_x, pub_y 10// 11// All bytes are dumped as hex on stderr so we can `diff` against the 12// Python golden. The test always exits 0; the smoke checks the 13// printed hex matches expected. 14// 15// expect_exit: 0. 16 17import "nx_syscalls.nx" 18import "nx_u384.nx" 19import "nx_x509.nx" 20import "nx_x509_pubkey_ec.nx" 21import "nx_sha512.nx" 22import "nx_ecdsa_sig_der_384.nx" 23import "nx_ecdsa_sig_der.nx" 24import "nx_ecdsa_p384.nx" 25import "nx_x509_verify_ecdsa_p384.nx" 26import "nx_x509_verify_under_issuer.nx" 27import "nx_u256.nx" 28import "nx_x509_verify_ecdsa.nx" 29import "nx_sha256.nx" 30 31func read_to(path: *u8, out_buf: *u8, max: i64) -> i64 { 32 let len_p: *i64 = sys_mmap(16) as *i64 33 let p: *u8 = sys_read_file(path, len_p) 34 let n: i64 = *len_p 35 if n <= 0 { return 0 - 1 } 36 if n > max { return 0 - 2 } 37 var i: i64 = 0 38 while i < n { out_buf[i] = p[i]; i = i + 1 } 39 return n 40} 41 42func emit_label(c0: i64, c1: i64, c2: i64, c3: i64, c4: i64) -> i64 { 43 let b: *u8 = sys_mmap(8) 44 b[0]=c0 as u8; b[1]=c1 as u8; b[2]=c2 as u8; b[3]=c3 as u8 45 b[4]=c4 as u8; b[5]=0x3D 46 sys_write(2, b, 6) 47 return 0 48} 49 50func emit_nl() -> i64 { 51 let nl: *u8 = sys_mmap(8); nl[0]=0x0A; sys_write(2, nl, 1) 52 return 0 53} 54 55func hexnib(v: i64) -> i64 { 56 if v < 10 { return 0x30 + v } 57 return 0x61 + (v - 10) 58} 59 60func dump_bytes(bytes: *u8, n: i64) -> i64 { 61 let buf: *u8 = sys_mmap(n * 2 + 4) 62 var i: i64 = 0 63 while i < n { 64 let v: i64 = bytes[i] & 0xff 65 buf[i*2] = hexnib(v >> 4) as u8 66 buf[i*2 + 1] = hexnib(v & 0xf) as u8 67 i = i + 1 68 } 69 sys_write(2, buf, n * 2) 70 return 0 71} 72 73// Dump U384 (12 LE limbs of 32 bits each) as 96-char big-endian hex. 74func dump_u384(p: *i64) -> i64 { 75 let bytes: *u8 = sys_mmap(48) 76 var i: i64 = 0 77 // U384 LE-limb layout: limb[0] = least-sig 32 bits. 78 // For BE hex we want byte 0 = MSB of limb[11]. 79 while i < 12 { 80 let limb: i64 = p[11 - i] & 0xffffffff 81 bytes[i*4 + 0] = (limb >> 24) & 0xff 82 bytes[i*4 + 1] = (limb >> 16) & 0xff 83 bytes[i*4 + 2] = (limb >> 8) & 0xff 84 bytes[i*4 + 3] = limb & 0xff 85 i = i + 1 86 } 87 dump_bytes(bytes, 48) 88 return 0 89} 90 91func main() -> i64 { 92 // Load cert2.der and cert3.der. 93 let p2: *u8 = sys_mmap(64) 94 p2[0]=0x2F;p2[1]=0x74;p2[2]=0x6D;p2[3]=0x70;p2[4]=0x2F 95 p2[5]=0x63;p2[6]=0x65;p2[7]=0x72;p2[8]=0x74 96 p2[9]=0x32;p2[10]=0x2E;p2[11]=0x64;p2[12]=0x65;p2[13]=0x72 97 p2[14]=0 98 let buf2: *u8 = sys_mmap(4096) 99 let n2: i64 = read_to(p2, buf2, 4096) 100 if n2 <= 0 { return 1 } 101 102 let p3: *u8 = sys_mmap(64) 103 p3[0]=0x2F;p3[1]=0x74;p3[2]=0x6D;p3[3]=0x70;p3[4]=0x2F 104 p3[5]=0x63;p3[6]=0x65;p3[7]=0x72;p3[8]=0x74 105 p3[9]=0x33;p3[10]=0x2E;p3[11]=0x64;p3[12]=0x65;p3[13]=0x72 106 p3[14]=0 107 let buf3: *u8 = sys_mmap(4096) 108 let n3: i64 = read_to(p3, buf3, 4096) 109 if n3 <= 0 { return 2 } 110 111 let c2_raw: *u8 = sys_mmap(512); let c2: *X509Cert = c2_raw as *X509Cert 112 let c3_raw: *u8 = sys_mmap(512); let c3: *X509Cert = c3_raw as *X509Cert 113 if x509_parse(buf2, n2, c2) < 0 { return 3 } 114 if x509_parse(buf3, n3, c3) < 0 { return 4 } 115 116 // ---- 0. SHA-256(cert2.tbs) BEFORE any P-384 work, as a control ---- 117 let h256_early: *u8 = sys_mmap(32) 118 sha256_digest(buf2 + c2.tbs_off, c2.tbs_len, h256_early) 119 emit_label(0x53, 0x32, 0x35, 0x36, 0x30) // "S2560" (early sha256) 120 dump_bytes(h256_early, 32); emit_nl() 121 122 // ---- 1. SHA-384(cert2.tbs) ---- 123 let h: *u8 = sys_mmap(48) 124 let tbs2: *u8 = buf2 + c2.tbs_off 125 sha384_digest(tbs2, c2.tbs_len, h) 126 emit_label(0x48, 0x32, 0x53, 0x33, 0x38) // "H2S38" 127 dump_bytes(h, 48); emit_nl() 128 129 // ---- 2. parse cert2.sig as P-384 DER ---- 130 let r: *i64 = u384_alloc() 131 let s: *i64 = u384_alloc() 132 let sig_ptr: *u8 = buf2 + c2.sig_off 133 let pp: i64 = nx_ecdsa_sig_parse_der_384(sig_ptr, c2.sig_len, r, s) 134 emit_label(0x44, 0x50, 0x52, 0x43, 0x32) // "DPRC2" (DER parse rc) 135 let prc_buf: *u8 = sys_mmap(8) 136 prc_buf[0] = hexnib(pp & 0xf) as u8 137 sys_write(2, prc_buf, 1); emit_nl() 138 139 emit_label(0x52, 0x32, 0x32, 0x32, 0x32) // "R2222" 140 dump_u384(r); emit_nl() 141 emit_label(0x53, 0x32, 0x32, 0x32, 0x32) // "S2222" 142 dump_u384(s); emit_nl() 143 144 // ---- 3. extract cert3 pubkey ---- 145 let px: *i64 = u384_alloc() 146 let py: *i64 = u384_alloc() 147 let ex: i64 = nx_x509_pubkey_extract_ec_p384(buf3, c3, px, py) 148 emit_label(0x45, 0x58, 0x52, 0x43, 0x33) // "EXRC3" 149 let xrc_buf: *u8 = sys_mmap(8) 150 xrc_buf[0] = hexnib(ex & 0xf) as u8 151 sys_write(2, xrc_buf, 1); emit_nl() 152 153 emit_label(0x58, 0x33, 0x33, 0x33, 0x33) // "X3333" 154 dump_u384(px); emit_nl() 155 emit_label(0x59, 0x33, 0x33, 0x33, 0x33) // "Y3333" 156 dump_u384(py); emit_nl() 157 158 // ---- 4. Call nx_ecdsa_p384_verify directly with these inputs ---- 159 let e: *i64 = u384_alloc() 160 u384_load_be(e, h) 161 let v: i64 = nx_ecdsa_p384_verify(px, py, e, r, s) 162 emit_label(0x56, 0x52, 0x44, 0x43, 0x54) // "VRDCT" 163 let v_buf: *u8 = sys_mmap(8) 164 v_buf[0] = hexnib(v & 0xf) as u8 165 sys_write(2, v_buf, 1); emit_nl() 166 167 // ---- 5. Call x509_verify_ecdsa_p384 (the wrapper) ---- 168 let v2: i64 = nx_x509_verify_ecdsa_p384( 169 buf2 + c2.tbs_off, c2.tbs_len, 170 buf2 + c2.sig_off, c2.sig_len, 171 px, py 172 ) 173 emit_label(0x57, 0x52, 0x44, 0x43, 0x54) // "WRDCT" (wrapper verdict) 174 let v2_buf: *u8 = sys_mmap(8) 175 v2_buf[0] = hexnib(v2 & 0xf) as u8 176 sys_write(2, v2_buf, 1); emit_nl() 177 178 // ---- 6. Call x509_verify_under_issuer (the dispatcher) ---- 179 let v3: i64 = nx_x509_verify_under_issuer(buf2, c2, buf3, c3) 180 emit_label(0x44, 0x52, 0x44, 0x43, 0x54) // "DRDCT" (dispatch verdict) 181 let v3_buf: *u8 = sys_mmap(8) 182 v3_buf[0] = hexnib(v3 & 0xf) as u8 183 sys_write(2, v3_buf, 1); emit_nl() 184 185 // ---- 7. Pollution check: parse cert1, verify cert1->cert2 first, 186 // then RE-verify cert2->cert3 to see if prior state breaks 187 // the P-384 path. 188 let p1: *u8 = sys_mmap(64) 189 p1[0]=0x2F;p1[1]=0x74;p1[2]=0x6D;p1[3]=0x70;p1[4]=0x2F 190 p1[5]=0x63;p1[6]=0x65;p1[7]=0x72;p1[8]=0x74 191 p1[9]=0x31;p1[10]=0x2E;p1[11]=0x64;p1[12]=0x65;p1[13]=0x72 192 p1[14]=0 193 let buf1: *u8 = sys_mmap(4096) 194 let n1: i64 = read_to(p1, buf1, 4096) 195 if n1 <= 0 { return 5 } 196 let c1_raw: *u8 = sys_mmap(512); let c1: *X509Cert = c1_raw as *X509Cert 197 if x509_parse(buf1, n1, c1) < 0 { return 6 } 198 let vA: i64 = nx_x509_verify_under_issuer(buf1, c1, buf2, c2) 199 emit_label(0x50, 0x4F, 0x4C, 0x31, 0x32) // "POL12" (post cert1->cert2) 200 let vA_buf: *u8 = sys_mmap(8) 201 vA_buf[0] = hexnib(vA & 0xf) as u8 202 sys_write(2, vA_buf, 1); emit_nl() 203 204 let vB: i64 = nx_x509_verify_under_issuer(buf2, c2, buf3, c3) 205 emit_label(0x50, 0x4F, 0x4C, 0x32, 0x33) // "POL23" (re-cert2->cert3) 206 let vB_buf: *u8 = sys_mmap(8) 207 vB_buf[0] = hexnib(vB & 0xf) as u8 208 sys_write(2, vB_buf, 1); emit_nl() 209 210 // ---- 8. Call cert1->cert2 P-256 TWICE in a row to test self-repeat 211 let vC: i64 = nx_x509_verify_under_issuer(buf1, c1, buf2, c2) 212 emit_label(0x52, 0x50, 0x54, 0x31, 0x32) // "RPT12" (P-256 repeat 1) 213 let vC_buf: *u8 = sys_mmap(8) 214 vC_buf[0] = hexnib(vC & 0xf) as u8 215 sys_write(2, vC_buf, 1); emit_nl() 216 217 let vD: i64 = nx_x509_verify_under_issuer(buf1, c1, buf2, c2) 218 emit_label(0x52, 0x50, 0x54, 0x31, 0x33) // "RPT13" (P-256 repeat 2) 219 let vD_buf: *u8 = sys_mmap(8) 220 vD_buf[0] = hexnib(vD & 0xf) as u8 221 sys_write(2, vD_buf, 1); emit_nl() 222 223 // ---- 9. BYPASS dispatcher: call nx_x509_verify_ecdsa_p256 directly 224 // after the P-384 wrapper has already been called. 225 let p2x: *i64 = u256_alloc() 226 let p2y: *i64 = u256_alloc() 227 let exA: i64 = nx_x509_pubkey_extract_ec_p256(buf2, c2, p2x, p2y) 228 emit_label(0x45, 0x58, 0x32, 0x35, 0x36) // "EX256" 229 let exA_buf: *u8 = sys_mmap(8) 230 exA_buf[0] = hexnib(exA & 0xf) as u8 231 sys_write(2, exA_buf, 1); emit_nl() 232 233 let vE: i64 = nx_x509_verify_ecdsa_p256( 234 buf1 + c1.tbs_off, c1.tbs_len, 235 buf1 + c1.sig_off, c1.sig_len, 236 p2x, p2y 237 ) 238 emit_label(0x42, 0x50, 0x32, 0x35, 0x36) // "BP256" (bypass P-256) 239 let vE_buf: *u8 = sys_mmap(8) 240 vE_buf[0] = hexnib(vE & 0xf) as u8 241 sys_write(2, vE_buf, 1); emit_nl() 242 243 // ---- 10. Re-parse fresh cert1, cert2 and retry P-256 verify ---- 244 let c1b_raw: *u8 = sys_mmap(512); let c1b: *X509Cert = c1b_raw as *X509Cert 245 let c2b_raw: *u8 = sys_mmap(512); let c2b: *X509Cert = c2b_raw as *X509Cert 246 if x509_parse(buf1, n1, c1b) < 0 { return 7 } 247 if x509_parse(buf2, n2, c2b) < 0 { return 8 } 248 let p2bx: *i64 = u256_alloc() 249 let p2by: *i64 = u256_alloc() 250 nx_x509_pubkey_extract_ec_p256(buf2, c2b, p2bx, p2by) 251 let vF: i64 = nx_x509_verify_ecdsa_p256( 252 buf1 + c1b.tbs_off, c1b.tbs_len, 253 buf1 + c1b.sig_off, c1b.sig_len, 254 p2bx, p2by 255 ) 256 emit_label(0x46, 0x50, 0x32, 0x35, 0x36) // "FP256" (fresh-parse P-256) 257 let vF_buf: *u8 = sys_mmap(8) 258 vF_buf[0] = hexnib(vF & 0xf) as u8 259 sys_write(2, vF_buf, 1); emit_nl() 260 261 // ---- 11. Dump TBS offsets to compare against the leaf test ---- 262 let off1: i64 = c1.tbs_off 263 let len1: i64 = c1.tbs_len 264 let off2: i64 = c1.sig_off 265 let len2: i64 = c1.sig_len 266 emit_label(0x54, 0x42, 0x4F, 0x46, 0x46) // "TBOFF" 267 let o_buf: *u8 = sys_mmap(8) 268 o_buf[0]=(0x30 + ((off1 / 100) % 10)) as u8 269 o_buf[1]=(0x30 + ((off1 / 10) % 10)) as u8 270 o_buf[2]=(0x30 + (off1 % 10)) as u8 271 sys_write(2, o_buf, 3); emit_nl() 272 emit_label(0x54, 0x42, 0x4C, 0x45, 0x4E) // "TBLEN" 273 let l_buf: *u8 = sys_mmap(8) 274 l_buf[0]=(0x30 + ((len1 / 100) % 10)) as u8 275 l_buf[1]=(0x30 + ((len1 / 10) % 10)) as u8 276 l_buf[2]=(0x30 + (len1 % 10)) as u8 277 sys_write(2, l_buf, 3); emit_nl() 278 279 // ---- 12. SHA-256 isolation check after all the P-384 calls ---- 280 let h256: *u8 = sys_mmap(32) 281 sha256_digest(buf1 + c1.tbs_off, c1.tbs_len, h256) 282 emit_label(0x53, 0x32, 0x35, 0x36, 0x3A) // "S256:" 283 dump_bytes(h256, 32); emit_nl() 284 285 return 0 286}