nx_x509_verify_ecdsa_test.nx source
↩ module page · 120 lines · 6440 B
1// nx_x509_verify_ecdsa_test.nx -- end-to-end KAT for the X.509
2// outer-signature verify pipeline (SHA-256 + DER parse + ECDSA verify).
3//
4// Test vector exploit: RFC 6979 §A.2.5 documents (NIST P-256 +
5// SHA-256, msg = "sample") -> r, s. Since SHA-256("sample") is
6// the documented hash AND our nx_x509_verify_ecdsa_p256 hashes
7// the tbs input with SHA-256 before verifying, we can use:
8// tbs = "sample" (6 ASCII bytes)
9// sig_der = DER-encoded RFC 6979 r/s
10// pub_x/y = RFC 6979 pubkey
11// and the verify should return OK. This proves the FULL pipeline
12// (hash + parse + ECDSA verify) without needing a real ECDSA-
13// signed X.509 cert + chain.
14//
15// expect_exit: 0
16// license_tier: ORIGINAL
17
18import "nx_syscalls.nx"
19import "nx_u256.nx"
20import "nx_ecdsa_p256.nx"
21import "nx_x509_verify_ecdsa.nx"
22
23func main() -> i64 {
24 // ---- tbs = "sample" ----
25 let tbs: *u8 = sys_mmap(16)
26 tbs[0] = 0x73; tbs[1] = 0x61; tbs[2] = 0x6D
27 tbs[3] = 0x70; tbs[4] = 0x6C; tbs[5] = 0x65 // "sample"
28 let tbs_len: i64 = 6
29
30 // ---- DER-encoded RFC 6979 §A.2.5 sig ----
31 let sig: *u8 = sys_mmap(128)
32 sig[0] = 0x30; sig[1] = 0x46 // SEQUENCE 70
33 sig[2] = 0x02; sig[3] = 0x21; sig[4] = 0x00 // INTEGER 33
34 sig[5] = 0xEF; sig[6] = 0xD4; sig[7] = 0x8B; sig[8] = 0x2A
35 sig[9] = 0xAC; sig[10] = 0xB6; sig[11] = 0xA8; sig[12] = 0xFD
36 sig[13] = 0x11; sig[14] = 0x40; sig[15] = 0xDD; sig[16] = 0x9C
37 sig[17] = 0xD4; sig[18] = 0x5E; sig[19] = 0x81; sig[20] = 0xD6
38 sig[21] = 0x9D; sig[22] = 0x2C; sig[23] = 0x87; sig[24] = 0x7B
39 sig[25] = 0x56; sig[26] = 0xAA; sig[27] = 0xF9; sig[28] = 0x91
40 sig[29] = 0xC3; sig[30] = 0x4D; sig[31] = 0x0E; sig[32] = 0xA8
41 sig[33] = 0x4E; sig[34] = 0xAF; sig[35] = 0x37; sig[36] = 0x16
42 sig[37] = 0x02; sig[38] = 0x21; sig[39] = 0x00 // INTEGER 33
43 sig[40] = 0xF7; sig[41] = 0xCB; sig[42] = 0x1C; sig[43] = 0x94
44 sig[44] = 0x2D; sig[45] = 0x65; sig[46] = 0x7C; sig[47] = 0x41
45 sig[48] = 0xD4; sig[49] = 0x36; sig[50] = 0xC7; sig[51] = 0xA1
46 sig[52] = 0xB6; sig[53] = 0xE2; sig[54] = 0x9F; sig[55] = 0x65
47 sig[56] = 0xF3; sig[57] = 0xE9; sig[58] = 0x00; sig[59] = 0xDB
48 sig[60] = 0xB9; sig[61] = 0xAF; sig[62] = 0xF4; sig[63] = 0x06
49 sig[64] = 0x4D; sig[65] = 0xC4; sig[66] = 0xAB; sig[67] = 0x2F
50 sig[68] = 0x84; sig[69] = 0x3A; sig[70] = 0xCD; sig[71] = 0xA8
51 let sig_len: i64 = 72
52
53 // ---- Pubkey (X, Y) as BE bytes -> LE limbs ----
54 let qx_bytes: *u8 = sys_mmap(32)
55 qx_bytes[0] = 0x60; qx_bytes[1] = 0xFE; qx_bytes[2] = 0xD4; qx_bytes[3] = 0xBA
56 qx_bytes[4] = 0x25; qx_bytes[5] = 0x5A; qx_bytes[6] = 0x9D; qx_bytes[7] = 0x31
57 qx_bytes[8] = 0xC9; qx_bytes[9] = 0x61; qx_bytes[10] = 0xEB; qx_bytes[11] = 0x74
58 qx_bytes[12] = 0xC6; qx_bytes[13] = 0x35; qx_bytes[14] = 0x6D; qx_bytes[15] = 0x68
59 qx_bytes[16] = 0xC0; qx_bytes[17] = 0x49; qx_bytes[18] = 0xB8; qx_bytes[19] = 0x92
60 qx_bytes[20] = 0x3B; qx_bytes[21] = 0x61; qx_bytes[22] = 0xFA; qx_bytes[23] = 0x6C
61 qx_bytes[24] = 0xE6; qx_bytes[25] = 0x69; qx_bytes[26] = 0x62; qx_bytes[27] = 0x2E
62 qx_bytes[28] = 0x60; qx_bytes[29] = 0xF2; qx_bytes[30] = 0x9F; qx_bytes[31] = 0xB6
63 let qy_bytes: *u8 = sys_mmap(32)
64 qy_bytes[0] = 0x79; qy_bytes[1] = 0x03; qy_bytes[2] = 0xFE; qy_bytes[3] = 0x10
65 qy_bytes[4] = 0x08; qy_bytes[5] = 0xB8; qy_bytes[6] = 0xBC; qy_bytes[7] = 0x99
66 qy_bytes[8] = 0xA4; qy_bytes[9] = 0x1A; qy_bytes[10] = 0xE9; qy_bytes[11] = 0xE9
67 qy_bytes[12] = 0x56; qy_bytes[13] = 0x28; qy_bytes[14] = 0xBC; qy_bytes[15] = 0x64
68 qy_bytes[16] = 0xF2; qy_bytes[17] = 0xF1; qy_bytes[18] = 0xB2; qy_bytes[19] = 0x0C
69 qy_bytes[20] = 0x2D; qy_bytes[21] = 0x7E; qy_bytes[22] = 0x9F; qy_bytes[23] = 0x51
70 qy_bytes[24] = 0x77; qy_bytes[25] = 0xA3; qy_bytes[26] = 0xC2; qy_bytes[27] = 0x94
71 qy_bytes[28] = 0xD4; qy_bytes[29] = 0x46; qy_bytes[30] = 0x22; qy_bytes[31] = 0x99
72 let qx: *i64 = u256_alloc()
73 let qy: *i64 = u256_alloc()
74 u256_load_be(qx, qx_bytes)
75 u256_load_be(qy, qy_bytes)
76
77 // ---- Test A: full pipeline succeeds ----
78 // <-- THE MILESTONE: tbs -> SHA-256 -> e, DER -> r,s, ECDSA verify -> OK
79 let v: i64 = nx_x509_verify_ecdsa_p256(tbs, tbs_len, sig, sig_len, qx, qy)
80 if v != NX_X509_ECDSA_OK { return 1 }
81
82 // ---- Test B: tamper tbs (flip a byte) -> BAD_SIG ----
83 tbs[2] = tbs[2] ^ 0x01 // flip 'm' bit
84 if nx_x509_verify_ecdsa_p256(tbs, tbs_len, sig, sig_len, qx, qy) != NX_X509_ECDSA_BAD_SIG { return 2 }
85 tbs[2] = tbs[2] ^ 0x01 // restore
86
87 // ---- Test C: tamper sig (flip a byte in r) -> BAD_SIG ----
88 sig[5] = sig[5] ^ 0x01
89 if nx_x509_verify_ecdsa_p256(tbs, tbs_len, sig, sig_len, qx, qy) != NX_X509_ECDSA_BAD_SIG { return 3 }
90 sig[5] = sig[5] ^ 0x01
91
92 // ---- Test D: malformed DER (bad outer tag) -> BAD_SIG_DER ----
93 let bad_der: *u8 = sys_mmap(16)
94 bad_der[0] = 0x99; bad_der[1] = 0x00
95 if nx_x509_verify_ecdsa_p256(tbs, tbs_len, bad_der, 2, qx, qy) != NX_X509_ECDSA_BAD_SIG_DER { return 4 }
96
97 // ---- Test E: off-curve pubkey -> BAD_PUBKEY ----
98 let bad_qx: *i64 = u256_alloc()
99 u256_copy(bad_qx, qx)
100 bad_qx[0] = bad_qx[0] ^ 1
101 if nx_x509_verify_ecdsa_p256(tbs, tbs_len, sig, sig_len, bad_qx, qy) != NX_X509_ECDSA_BAD_PUBKEY { return 5 }
102
103 // ---- Test F: empty tbs -> SHA-256 of empty string still produces
104 // a hash; verify against RFC 6979's sig+pubkey will FAIL since
105 // the documented sig was over SHA-256("sample"), not SHA-256("")
106 // -> expect BAD_SIG.
107 if nx_x509_verify_ecdsa_p256(tbs, 0, sig, sig_len, qx, qy) != NX_X509_ECDSA_BAD_SIG { return 6 }
108
109 // ---- Test G: verdict gate ----
110 if nx_x509_verify_ecdsa_verdict_is_valid(NX_X509_ECDSA_OK) != 1 { return 10 }
111 if nx_x509_verify_ecdsa_verdict_is_valid(NX_X509_ECDSA_BAD_SIG_DER) != 1 { return 11 }
112 if nx_x509_verify_ecdsa_verdict_is_valid(NX_X509_ECDSA_BAD_SIG) != 1 { return 12 }
113 if nx_x509_verify_ecdsa_verdict_is_valid(NX_X509_ECDSA_BAD_PUBKEY) != 1 { return 13 }
114 if nx_x509_verify_ecdsa_verdict_is_valid(NX_X509_ECDSA_INFINITY) != 1 { return 14 }
115 if nx_x509_verify_ecdsa_verdict_is_valid(NX_X509_ECDSA_VERDICT_N) != 0 { return 15 }
116 if nx_x509_verify_ecdsa_verdict_is_valid(0) != 0 { return 16 }
117 if nx_x509_verify_ecdsa_verdict_is_valid(0 - 1) != 0 { return 17 }
118
119 return 0
120}