code wiki / (root) / nx_tls13_record_test.nx

nx_tls13_record_test.nx source

↩ module page · 192 lines · 6800 B

1// nx_tls13_record_test.nx -- internal-consistency KAT for the 2// TLS 1.3 record-layer protection wrapper. 3// 4// We don't pin to RFC 8448 ยง3 wire bytes here because those depend 5// on the full key schedule + traffic-secret derivation tied to 6// specific handshake messages. Instead we verify: 7// 8// A. Round-trip: encrypt then decrypt restores plaintext + type 9// B. Nonce-with-seq: encrypt(seq=0) != encrypt(seq=1) given 10// same (key, iv, content) -- confirms IV XOR seq actually 11// varies the keystream 12// C. Tampered tag rejected (TAG_MISMATCH) 13// D. Tampered header (wrong length in AAD) rejected 14// E. Padding: encrypt with padding_len > 0, decrypt strips it 15// F. All-zeros inner (no type byte) rejected (EMPTY_INNER) 16// G. Nonce construction byte-exact for known (iv, seq) pair 17// 18// expect_exit: 0 19// license_tier: ORIGINAL 20 21import "nx_syscalls.nx" 22import "nx_chacha20_poly1305.nx" 23import "nx_tls13_record.nx" 24 25func main() -> i64 { 26 // ---- Test G: nonce construction byte-exact ---- 27 // iv = 01 02 03 04 05 06 07 08 09 0a 0b 0c 28 // seq = 0x0000000000000001 29 // nonce = iv XOR (4 zero bytes || 8-byte BE seq) 30 // = 01 02 03 04 05 06 07 08 09 0a 0b 0d (last byte = 0c ^ 01) 31 let iv: *u8 = sys_mmap(16) 32 var ii: i64 = 0 33 while ii < 12 { 34 iv[ii] = ii + 1 35 ii = ii + 1 36 } 37 let nonce: *u8 = sys_mmap(16) 38 tls13_record_build_nonce(iv, 1, nonce) 39 if (nonce[0] & 0xff) != 0x01 { return 1 } 40 if (nonce[3] & 0xff) != 0x04 { return 2 } 41 if (nonce[4] & 0xff) != 0x05 { return 3 } // iv[4] XOR 0 42 if (nonce[10] & 0xff) != 0x0b { return 4 } // iv[10] XOR 0 43 if (nonce[11] & 0xff) != 0x0d { return 5 } // iv[11] (0x0c) XOR 0x01 44 45 // Seq = 0x0102030405060708 -> last 8 bytes of nonce should XOR 46 // those big-endian bytes into iv[4..12]. 47 tls13_record_build_nonce(iv, 0x0102030405060708, nonce) 48 if (nonce[4] & 0xff) != (0x05 ^ 0x01) { return 10 } 49 if (nonce[5] & 0xff) != (0x06 ^ 0x02) { return 11 } 50 if (nonce[6] & 0xff) != (0x07 ^ 0x03) { return 12 } 51 if (nonce[11] & 0xff) != (0x0c ^ 0x08) { return 13 } 52 53 // ---- Test A: round-trip encrypt+decrypt ---- 54 let key: *u8 = sys_mmap(64) 55 var k: i64 = 0 56 while k < 32 { 57 key[k] = 0xa0 + k 58 k = k + 1 59 } 60 let content: *u8 = sys_mmap(64) 61 let msg_bytes: i64 = 23 // arbitrary length 62 var c: i64 = 0 63 while c < msg_bytes { 64 content[c] = 0x40 + c 65 c = c + 1 66 } 67 let header: *u8 = sys_mmap(16) 68 let ct: *u8 = sys_mmap(128) 69 let tag: *u8 = sys_mmap(32) 70 let v1: i64 = nx_tls13_record_encrypt( 71 key, iv, 7, 72 content, msg_bytes, 73 NX_TLS13_CT_HANDSHAKE, 74 0, 75 header, ct, tag 76 ) 77 if v1 != NX_TLS13_REC_VERDICT_OK { return 20 } 78 // Header length field should equal msg_bytes + 1 (content_type) + 16 (tag). 79 let expected_len: i64 = msg_bytes + 1 + 16 80 let actual_len: i64 = ((header[3] & 0xff) << 8) | (header[4] & 0xff) 81 if actual_len != expected_len { return 21 } 82 83 let pt_out: *u8 = sys_mmap(128) 84 let ct_type_out: *i64 = sys_mmap(16) as *i64 85 let ct_len_out: *i64 = sys_mmap(16) as *i64 86 let v2: i64 = nx_tls13_record_decrypt( 87 key, iv, 7, 88 header, 89 ct, msg_bytes + 1, // inner length = content + type byte 90 tag, 91 pt_out, ct_type_out, ct_len_out 92 ) 93 if v2 != NX_TLS13_REC_VERDICT_OK { return 30 } 94 if *ct_type_out != NX_TLS13_CT_HANDSHAKE { return 31 } 95 if *ct_len_out != msg_bytes { return 32 } 96 var r: i64 = 0 97 while r < msg_bytes { 98 if (pt_out[r] & 0xff) != (content[r] & 0xff) { return 40 + r } 99 r = r + 1 100 } 101 102 // ---- Test B: nonce-with-seq varies output ---- 103 let ct_seq0: *u8 = sys_mmap(128) 104 let tag_seq0: *u8 = sys_mmap(32) 105 let header0: *u8 = sys_mmap(16) 106 nx_tls13_record_encrypt( 107 key, iv, 0, 108 content, msg_bytes, 109 NX_TLS13_CT_HANDSHAKE, 110 0, 111 header0, ct_seq0, tag_seq0 112 ) 113 let ct_seq1: *u8 = sys_mmap(128) 114 let tag_seq1: *u8 = sys_mmap(32) 115 let header1: *u8 = sys_mmap(16) 116 nx_tls13_record_encrypt( 117 key, iv, 1, 118 content, msg_bytes, 119 NX_TLS13_CT_HANDSHAKE, 120 0, 121 header1, ct_seq1, tag_seq1 122 ) 123 // Ciphertexts MUST differ (different keystream). 124 var diff_count: i64 = 0 125 var d: i64 = 0 126 while d < msg_bytes + 1 { 127 if (ct_seq0[d] & 0xff) != (ct_seq1[d] & 0xff) { diff_count = diff_count + 1 } 128 d = d + 1 129 } 130 if diff_count < (msg_bytes + 1) - 2 { return 80 } // expect almost all bytes to differ 131 132 // Tags MUST differ. 133 if (tag_seq0[0] & 0xff) == (tag_seq1[0] & 0xff) { 134 if (tag_seq0[8] & 0xff) == (tag_seq1[8] & 0xff) { return 81 } 135 } 136 137 // ---- Test C: tampered tag rejected ---- 138 let bad_tag: *u8 = sys_mmap(32) 139 var bi: i64 = 0 140 while bi < 16 { 141 bad_tag[bi] = tag[bi] 142 bi = bi + 1 143 } 144 bad_tag[7] = bad_tag[7] ^ 0x40 145 let v_bad_tag: i64 = nx_tls13_record_decrypt( 146 key, iv, 7, header, ct, msg_bytes + 1, bad_tag, 147 pt_out, ct_type_out, ct_len_out 148 ) 149 if v_bad_tag != NX_TLS13_REC_VERDICT_TAG_MISMATCH { return 90 } 150 151 // ---- Test D: tampered header (wrong length in AAD) rejected ---- 152 let bad_header: *u8 = sys_mmap(16) 153 bad_header[0] = header[0] 154 bad_header[1] = header[1] 155 bad_header[2] = header[2] 156 bad_header[3] = header[3] 157 bad_header[4] = header[4] ^ 1 // wrong length lo byte 158 let v_bad_h: i64 = nx_tls13_record_decrypt( 159 key, iv, 7, bad_header, ct, msg_bytes + 1, tag, 160 pt_out, ct_type_out, ct_len_out 161 ) 162 if v_bad_h != NX_TLS13_REC_VERDICT_TAG_MISMATCH { return 91 } 163 164 // ---- Test E: padding round-trip ---- 165 let header_pad: *u8 = sys_mmap(16) 166 let ct_pad: *u8 = sys_mmap(128) 167 let tag_pad: *u8 = sys_mmap(32) 168 let pad_len: i64 = 7 169 nx_tls13_record_encrypt( 170 key, iv, 42, 171 content, msg_bytes, 172 NX_TLS13_CT_APPLICATION_DATA, 173 pad_len, 174 header_pad, ct_pad, tag_pad 175 ) 176 let pt_pad: *u8 = sys_mmap(128) 177 let v_pad: i64 = nx_tls13_record_decrypt( 178 key, iv, 42, header_pad, 179 ct_pad, msg_bytes + 1 + pad_len, tag_pad, 180 pt_pad, ct_type_out, ct_len_out 181 ) 182 if v_pad != NX_TLS13_REC_VERDICT_OK { return 100 } 183 if *ct_type_out != NX_TLS13_CT_APPLICATION_DATA { return 101 } 184 if *ct_len_out != msg_bytes { return 102 } // padding stripped 185 186 // ---- Test F: verdict gate ---- 187 if nx_tls13_rec_verdict_is_valid(NX_TLS13_REC_VERDICT_OK) != 1 { return 110 } 188 if nx_tls13_rec_verdict_is_valid(NX_TLS13_REC_VERDICT_N) != 0 { return 111 } 189 if nx_tls13_rec_verdict_is_valid(0 - 1) != 0 { return 112 } 190 191 return 0 192}