nx_quic_keys.nx source
↩ module page · 59 lines · 3152 B
1// nx_quic_keys.nx -- RUNG 5a of the sovereign QUIC transport: the Initial key schedule (RFC 9001 sec 5).
2// Builds on the sovereign HKDF-SHA256 (nx_hkdf) + adds the TLS 1.3 HKDF-Expand-Label (RFC 8446 sec 7.1).
3// QUIC Initial keys are derived purely from the client's Destination Connection ID + a fixed salt -- this
4// is what protects the handshake packets (R5b does the AEAD with these keys). Gated byte-exact against the
5// RFC 9001 A.1 worked example (DCID 0x8394c8f03e515708). No float. license_tier: ORIGINAL
6import "nx_hkdf.nx"
7
8// RFC 9001 sec 5.2 QUIC v1 initial salt (20 bytes).
9func quic_initial_salt(out: *u8) -> i64 {
10 out[0]=0x38 as u8; out[1]=0x76 as u8; out[2]=0x2c as u8; out[3]=0xf7 as u8; out[4]=0xf5 as u8
11 out[5]=0x59 as u8; out[6]=0x34 as u8; out[7]=0xb3 as u8; out[8]=0x4d as u8; out[9]=0x17 as u8
12 out[10]=0x9a as u8; out[11]=0xe6 as u8; out[12]=0xa4 as u8; out[13]=0xc8 as u8; out[14]=0x0c as u8
13 out[15]=0xad as u8; out[16]=0xcc as u8; out[17]=0xbb as u8; out[18]=0x7f as u8; out[19]=0x0a as u8
14 return 20
15}
16
17// HKDF-Expand-Label (RFC 8446 sec 7.1): info = uint16(L) || u8(6+label_len) || "tls13 "||label || u8(ctx_len) || ctx
18func hkdf_expand_label(secret: *u8, label: *u8, label_len: i64, ctx: *u8, ctx_len: i64, l: i64, out: *u8) -> i64 {
19 let info: *u8 = sys_mmap(512)
20 info[0] = ((l >> 8) & 0xff) as u8
21 info[1] = (l & 0xff) as u8
22 var o: i64 = 2
23 info[o] = (6 + label_len) as u8; o = o + 1
24 info[o]=0x74 as u8; info[o+1]=0x6c as u8; info[o+2]=0x73 as u8; info[o+3]=0x31 as u8; info[o+4]=0x33 as u8; info[o+5]=0x20 as u8 // "tls13 "
25 o = o + 6
26 var i: i64 = 0; while i < label_len { info[o + i] = label[i]; i = i + 1 } o = o + label_len
27 info[o] = ctx_len as u8; o = o + 1
28 i = 0; while i < ctx_len { info[o + i] = ctx[i]; i = i + 1 } o = o + ctx_len
29 return hkdf_expand(secret, info, o, l, out)
30}
31
32// derive client_initial_secret + server_initial_secret from the DCID (RFC 9001 sec 5.2).
33func quic_initial_secrets(dcid: *u8, dcil: i64, client_secret: *u8, server_secret: *u8) -> i64 {
34 let salt: *u8 = sys_mmap(20)
35 quic_initial_salt(salt)
36 let initial_secret: *u8 = sys_mmap(32)
37 hkdf_extract(salt, 20, dcid, dcil, initial_secret)
38 hkdf_expand_label(initial_secret, "client in" as *u8, 9, 0 as *u8, 0, 32, client_secret)
39 hkdf_expand_label(initial_secret, "server in" as *u8, 9, 0 as *u8, 0, 32, server_secret)
40 return 0
41}
42
43// also expose the intermediate initial_secret for the gate / debugging.
44func quic_initial_extract(dcid: *u8, dcil: i64, initial_secret: *u8) -> i64 {
45 let salt: *u8 = sys_mmap(20)
46 quic_initial_salt(salt)
47 hkdf_extract(salt, 20, dcid, dcil, initial_secret)
48 return 0
49}
50
51// derive packet-protection key (16B AES-128), iv (12B), header-protection key (16B) from a secret.
52func quic_derive_keys(secret: *u8, key: *u8, iv: *u8, hp: *u8) -> i64 {
53 hkdf_expand_label(secret, "quic key" as *u8, 8, 0 as *u8, 0, 16, key)
54 hkdf_expand_label(secret, "quic iv" as *u8, 7, 0 as *u8, 0, 12, iv)
55 hkdf_expand_label(secret, "quic hp" as *u8, 7, 0 as *u8, 0, 16, hp)
56 return 0
57}
58
59func main() -> i64 { return 0 }