code wiki / (root) / nx_x509_verify_ecdsa_test.nx

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}