nx_x509_pubkey_ec_test.nx source
↩ module page · 123 lines · 5736 B
1// nx_x509_pubkey_ec_test.nx -- KAT for ECDSA-P256 pubkey extraction
2// from a parsed X509Cert.
3//
4// Uses the RFC 6979 §A.2.5 pubkey (a known-on-curve P-256 point)
5// laid out in uncompressed format (0x04 || X || Y) inside a
6// synthetic buffer at a known offset. Tests:
7// - happy path: extract X, Y match the documented limbs
8// - bad length (e.g. 64 or 66 bytes) -> BAD_LEN
9// - wrong leading byte (0x02 instead of 0x04) -> NOT_UNCOMPRESSED
10// - verdict gate
11//
12// expect_exit: 0
13// license_tier: ORIGINAL
14
15import "nx_syscalls.nx"
16import "nx_u256.nx"
17import "nx_x509.nx"
18import "nx_x509_pubkey_ec.nx"
19
20func main() -> i64 {
21 // ---- Build a 65-byte uncompressed P-256 pubkey (RFC 6979 §A.2.5) ----
22 let pk: *u8 = sys_mmap(128)
23 pk[0] = 0x04 // uncompressed indicator
24 // X coordinate (32 bytes BE)
25 pk[1] = 0x60; pk[2] = 0xFE; pk[3] = 0xD4; pk[4] = 0xBA
26 pk[5] = 0x25; pk[6] = 0x5A; pk[7] = 0x9D; pk[8] = 0x31
27 pk[9] = 0xC9; pk[10] = 0x61; pk[11] = 0xEB; pk[12] = 0x74
28 pk[13] = 0xC6; pk[14] = 0x35; pk[15] = 0x6D; pk[16] = 0x68
29 pk[17] = 0xC0; pk[18] = 0x49; pk[19] = 0xB8; pk[20] = 0x92
30 pk[21] = 0x3B; pk[22] = 0x61; pk[23] = 0xFA; pk[24] = 0x6C
31 pk[25] = 0xE6; pk[26] = 0x69; pk[27] = 0x62; pk[28] = 0x2E
32 pk[29] = 0x60; pk[30] = 0xF2; pk[31] = 0x9F; pk[32] = 0xB6
33 // Y coordinate (32 bytes BE)
34 pk[33] = 0x79; pk[34] = 0x03; pk[35] = 0xFE; pk[36] = 0x10
35 pk[37] = 0x08; pk[38] = 0xB8; pk[39] = 0xBC; pk[40] = 0x99
36 pk[41] = 0xA4; pk[42] = 0x1A; pk[43] = 0xE9; pk[44] = 0xE9
37 pk[45] = 0x56; pk[46] = 0x28; pk[47] = 0xBC; pk[48] = 0x64
38 pk[49] = 0xF2; pk[50] = 0xF1; pk[51] = 0xB2; pk[52] = 0x0C
39 pk[53] = 0x2D; pk[54] = 0x7E; pk[55] = 0x9F; pk[56] = 0x51
40 pk[57] = 0x77; pk[58] = 0xA3; pk[59] = 0xC2; pk[60] = 0x94
41 pk[61] = 0xD4; pk[62] = 0x46; pk[63] = 0x22; pk[64] = 0x99
42
43 // ---- Build a manual X509Cert with pubkey_off/_len pointed at it ----
44 let cert_raw: *u8 = sys_mmap(256)
45 let cert: *X509Cert = cert_raw as *X509Cert
46 cert.tbs_off = 0; cert.tbs_len = 0
47 cert.serial_off = 0; cert.serial_len = 0
48 cert.sig_alg_off = 0; cert.sig_alg_len = 0
49 cert.spki_off = 0; cert.spki_len = 0
50 cert.sig_off = 0; cert.sig_len = 0
51 cert.pubkey_off = 0; cert.pubkey_len = 65 // <-- points at pk[0..65]
52 cert.pubkey_alg_off = 0; cert.pubkey_alg_len = 0
53 cert.validity_off = 0; cert.validity_len = 0
54 cert.extensions_off = 0 - 1; cert.extensions_len = 0
55
56 // ---- Test A: extract OK ----
57 let x: *i64 = u256_alloc()
58 let y: *i64 = u256_alloc()
59 let v: i64 = nx_x509_pubkey_extract_ec_p256(pk, cert, x, y)
60 if v != NX_X509_PUBKEY_EC_OK { return 1 }
61
62 // Verify X limbs (LE; limb[7] = top of X = 0x60FED4BA, limb[0] = LSB = 0x60F29FB6)
63 if x[7] != 0x60FED4BA { return 2 }
64 if x[6] != 0x255A9D31 { return 3 }
65 if x[5] != 0xC961EB74 { return 4 }
66 if x[4] != 0xC6356D68 { return 5 }
67 if x[3] != 0xC049B892 { return 6 }
68 if x[2] != 0x3B61FA6C { return 7 }
69 if x[1] != 0xE669622E { return 8 }
70 if x[0] != 0x60F29FB6 { return 9 }
71
72 // Verify Y limbs
73 if y[7] != 0x7903FE10 { return 10 }
74 if y[6] != 0x08B8BC99 { return 11 }
75 if y[5] != 0xA41AE9E9 { return 12 }
76 if y[4] != 0x5628BC64 { return 13 }
77 if y[3] != 0xF2F1B20C { return 14 }
78 if y[2] != 0x2D7E9F51 { return 15 }
79 if y[1] != 0x77A3C294 { return 16 }
80 if y[0] != 0xD4462299 { return 17 }
81
82 // ---- Test B: wrong length -> BAD_LEN ----
83 cert.pubkey_len = 64
84 if nx_x509_pubkey_extract_ec_p256(pk, cert, x, y) != NX_X509_PUBKEY_EC_BAD_LEN { return 20 }
85 cert.pubkey_len = 66
86 if nx_x509_pubkey_extract_ec_p256(pk, cert, x, y) != NX_X509_PUBKEY_EC_BAD_LEN { return 21 }
87 cert.pubkey_len = 0
88 if nx_x509_pubkey_extract_ec_p256(pk, cert, x, y) != NX_X509_PUBKEY_EC_BAD_LEN { return 22 }
89 cert.pubkey_len = 65
90
91 // ---- Test C: wrong leading byte -> NOT_UNCOMPRESSED ----
92 pk[0] = 0x02 // compressed indicator
93 if nx_x509_pubkey_extract_ec_p256(pk, cert, x, y) != NX_X509_PUBKEY_EC_NOT_UNCOMPRESSED { return 30 }
94 pk[0] = 0x03
95 if nx_x509_pubkey_extract_ec_p256(pk, cert, x, y) != NX_X509_PUBKEY_EC_NOT_UNCOMPRESSED { return 31 }
96 pk[0] = 0x05 // hybrid (deprecated)
97 if nx_x509_pubkey_extract_ec_p256(pk, cert, x, y) != NX_X509_PUBKEY_EC_NOT_UNCOMPRESSED { return 32 }
98 pk[0] = 0x00
99 if nx_x509_pubkey_extract_ec_p256(pk, cert, x, y) != NX_X509_PUBKEY_EC_NOT_UNCOMPRESSED { return 33 }
100 pk[0] = 0x04 // restore
101
102 // ---- Test D: extract at nonzero pubkey_off (cert-realistic) ----
103 let bigger: *u8 = sys_mmap(128)
104 var i: i64 = 0
105 while i < 128 { bigger[i] = 0xCC; i = i + 1 }
106 i = 0
107 while i < 65 { bigger[10 + i] = pk[i]; i = i + 1 }
108 cert.pubkey_off = 10
109 if nx_x509_pubkey_extract_ec_p256(bigger, cert, x, y) != NX_X509_PUBKEY_EC_OK { return 40 }
110 if x[7] != 0x60FED4BA { return 41 }
111 if y[0] != 0xD4462299 { return 42 }
112
113 // ---- Test E: verdict gate ----
114 if nx_x509_pubkey_ec_verdict_is_valid(NX_X509_PUBKEY_EC_OK) != 1 { return 50 }
115 if nx_x509_pubkey_ec_verdict_is_valid(NX_X509_PUBKEY_EC_BAD_LEN) != 1 { return 51 }
116 if nx_x509_pubkey_ec_verdict_is_valid(NX_X509_PUBKEY_EC_NOT_UNCOMPRESSED) != 1 { return 52 }
117 if nx_x509_pubkey_ec_verdict_is_valid(NX_X509_PUBKEY_EC_VERDICT_N) != 0 { return 53 }
118 if nx_x509_pubkey_ec_verdict_is_valid(0) != 0 { return 54 }
119 if nx_x509_pubkey_ec_verdict_is_valid(0 - 1) != 0 { return 55 }
120 if nx_x509_pubkey_ec_verdict_is_valid(999) != 0 { return 56 }
121
122 return 0
123}