code wiki / (root) / nx_tls13_kdf_test.nx

nx_tls13_kdf_test.nx source

↩ module page · 119 lines · 5767 B

1// nx_tls13_kdf_test.nx -- RFC 8446 §7.1 + RFC 8448 §3 KAT for the 2// TLS 1.3 HKDF-Expand-Label + Derive-Secret wrappers. 3// 4// Three verification steps: 5// 6// A. HkdfLabel byte construction for the canonical first-call 7// ("derived" label, empty-message SHA-256 hash as context, 8// length 32). Verifies the structure layout exactly matches 9// RFC 8446 §7.1's `struct HkdfLabel`. 10// 11// B. RFC 8448 §3 early_secret = HKDF-Extract(salt=0, IKM=0^32) 12// = 33ad0a1c607ec03b09e6cd9893680ce210adf300aa1f2660e1b22e10f170f92a 13// (the first secret in TLS 1.3's 5-stage key schedule, in the 14// no-PSK case which is what 99% of fresh TLS handshakes use). 15// 16// C. RFC 8448 §3 derived = Derive-Secret(early_secret, "derived", empty) 17// = 6f2615a108c702c5678f54fc9dbab69716c076189c48250cebeac3576c3611ba 18// (the secret that gets HKDF-Extract'd with ECDHE output to 19// produce the handshake_secret). 20// 21// The empty SHA-256 hash is hardcoded as the well-known constant 22// e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 23// to keep this test focused on the KDF logic (the SHA-256 module 24// has its own KAT). 25// 26// expect_exit: 0 27// license_tier: ORIGINAL 28 29import "nx_syscalls.nx" 30import "nx_hkdf.nx" 31import "nx_tls13_kdf.nx" 32 33func main() -> i64 { 34 // ---- The "derived" label = 7 bytes ---- 35 let label: *u8 = sys_mmap(16) 36 label[0]=0x64; label[1]=0x65; label[2]=0x72; label[3]=0x69 // "deri" 37 label[4]=0x76; label[5]=0x65; label[6]=0x64 // "ved" 38 39 // ---- Empty SHA-256 hash (well-known constant) ---- 40 let empty_hash: *u8 = sys_mmap(64) 41 empty_hash[0]=0xe3; empty_hash[1]=0xb0; empty_hash[2]=0xc4; empty_hash[3]=0x42 42 empty_hash[4]=0x98; empty_hash[5]=0xfc; empty_hash[6]=0x1c; empty_hash[7]=0x14 43 empty_hash[8]=0x9a; empty_hash[9]=0xfb; empty_hash[10]=0xf4; empty_hash[11]=0xc8 44 empty_hash[12]=0x99; empty_hash[13]=0x6f; empty_hash[14]=0xb9; empty_hash[15]=0x24 45 empty_hash[16]=0x27; empty_hash[17]=0xae; empty_hash[18]=0x41; empty_hash[19]=0xe4 46 empty_hash[20]=0x64; empty_hash[21]=0x9b; empty_hash[22]=0x93; empty_hash[23]=0x4c 47 empty_hash[24]=0xa4; empty_hash[25]=0x95; empty_hash[26]=0x99; empty_hash[27]=0x1b 48 empty_hash[28]=0x78; empty_hash[29]=0x52; empty_hash[30]=0xb8; empty_hash[31]=0x55 49 50 // ---- Test A: HkdfLabel byte construction ---- 51 let info: *u8 = sys_mmap(128) 52 let info_len: i64 = tls13_build_hkdf_label(32, label, 7, empty_hash, 32, info) 53 // Expected total = 2 (length) + 1 (label_len) + 6 ("tls13 ") + 7 ("derived") 54 // + 1 (context_len) + 32 (empty hash) = 49 bytes 55 if info_len != 49 { return 1 } 56 if (info[0] & 0xff) != 0x00 { return 2 } // length hi 57 if (info[1] & 0xff) != 0x20 { return 3 } // length lo = 32 58 if (info[2] & 0xff) != 0x0d { return 4 } // label total = 13 59 if (info[3] & 0xff) != 0x74 { return 5 } // 't' of "tls13 " 60 if (info[4] & 0xff) != 0x6c { return 6 } // 'l' 61 if (info[5] & 0xff) != 0x73 { return 7 } // 's' 62 if (info[6] & 0xff) != 0x31 { return 8 } // '1' 63 if (info[7] & 0xff) != 0x33 { return 9 } // '3' 64 if (info[8] & 0xff) != 0x20 { return 10 } // ' ' 65 if (info[9] & 0xff) != 0x64 { return 11 } // 'd' of "derived" 66 if (info[15] & 0xff) != 0x64 { return 12 } // last 'd' of "derived" 67 if (info[16] & 0xff) != 0x20 { return 13 } // context_len = 32 68 if (info[17] & 0xff) != 0xe3 { return 14 } // first byte of empty hash 69 if (info[48] & 0xff) != 0x55 { return 15 } // last byte of empty hash 70 71 // ---- Test B: RFC 8448 §3 early_secret ---- 72 let zeros: *u8 = sys_mmap(64) 73 let early_secret: *u8 = sys_mmap(64) 74 // hkdf_extract with salt_len=0 auto-fills with HashLen zeros. 75 hkdf_extract(zeros, 0, zeros, 32, early_secret) 76 // Expected: 33ad0a1c607ec03b09e6cd9893680ce210adf300aa1f2660e1b22e10f170f92a 77 if (early_secret[0] & 0xff) != 0x33 { return 20 } 78 if (early_secret[1] & 0xff) != 0xad { return 21 } 79 if (early_secret[2] & 0xff) != 0x0a { return 22 } 80 if (early_secret[3] & 0xff) != 0x1c { return 23 } 81 if (early_secret[7] & 0xff) != 0x3b { return 24 } 82 if (early_secret[15] & 0xff) != 0xe2 { return 25 } 83 if (early_secret[23] & 0xff) != 0x60 { return 26 } 84 if (early_secret[31] & 0xff) != 0x2a { return 27 } 85 86 // ---- Test C: Derive-Secret(early_secret, "derived", empty) ---- 87 let derived: *u8 = sys_mmap(64) 88 let v: i64 = tls13_derive_secret( 89 early_secret, label, 7, empty_hash, 32, derived 90 ) 91 if v != NX_TLS13_KDF_VERDICT_OK { return 30 } 92 // Expected: 6f2615a108c702c5 678f54fc9dbab697 16c076189c48250c ebeac3576c3611ba 93 if (derived[0] & 0xff) != 0x6f { return 31 } 94 if (derived[1] & 0xff) != 0x26 { return 32 } 95 if (derived[2] & 0xff) != 0x15 { return 33 } 96 if (derived[3] & 0xff) != 0xa1 { return 34 } 97 if (derived[7] & 0xff) != 0xc5 { return 35 } 98 if (derived[15] & 0xff) != 0x97 { return 36 } 99 if (derived[23] & 0xff) != 0x0c { return 37 } 100 if (derived[30] & 0xff) != 0x11 { return 38 } 101 if (derived[31] & 0xff) != 0xba { return 39 } 102 103 // ---- Bounds: label too long rejected ---- 104 let big_label: *u8 = sys_mmap(512) 105 var bl: i64 = 0 106 while bl < 250 { 107 big_label[bl] = 0x41 108 bl = bl + 1 109 } 110 let bad: i64 = tls13_build_hkdf_label(32, big_label, 250, empty_hash, 32, info) 111 if bad != 0 - NX_TLS13_KDF_VERDICT_LABEL_TOO_LONG { return 50 } 112 113 // ---- Verdict gate ---- 114 if nx_tls13_kdf_verdict_is_valid(NX_TLS13_KDF_VERDICT_OK) != 1 { return 60 } 115 if nx_tls13_kdf_verdict_is_valid(NX_TLS13_KDF_VERDICT_N) != 0 { return 61 } 116 if nx_tls13_kdf_verdict_is_valid(0 - 1) != 0 { return 62 } 117 118 return 0 119}