nx_tls13_server_session_emit_ee_alpn.nx source
↩ module page · 138 lines · 5881 B
1// nx_tls13_server_session_emit_ee_alpn.nx -- TUTOR-BOOTSTRAP SCAFFOLD (Claude,
2// authored under the B1 rung(3) ALPN-h2 SERVER workflow of the R4-H2
3// HTTP/2-transport ladder), NOT credited as team self-authoring.
4//
5// The ALPN-h2 SIBLING of the base 6th TLS server stone
6// nx_tls13_server_session_emit_ee (runtime/nx_tls13_server_session_emit_ee.nx).
7// The base stone emits an EMPTY EncryptedExtensions inner '08 00 00 02 00 00'
8// (no extensions -> no ALPN negotiated). THIS variant emits the byte-exact
9// ALPN-h2 EE inner so a sovereign h2 client (which advertises "h2" via
10// tls13_ext_emit_alpn_h2_only) sees its protocol SELECTED:
11//
12// 08 00 00 0b 00 09 00 10 00 05 00 03 02 68 32 (15 bytes)
13// HT_ENCRYPTED_EXTENSIONS = 0x08
14// body_len u24 = 0x00000b = 11
15// ext_list_len = 0x0009 = 9 (one ALPN EE ext, 9 wire bytes)
16// ALPN EE ext = 00 10 00 05 00 03 02 68 32
17// ext_type 0x0010, ext_data_len 0x0005, protocol_name_list_len 0x0003,
18// name_len 0x02, "h2" = 0x68 0x32
19//
20// The trailing 9 ALPN bytes are NOT reinvented here: they are emitted BYTE-FOR-
21// BYTE by the GREEN client emitter tls13_ext_emit_alpn_h2_only
22// (runtime/nx_tls13_ext.nx:236, KAT '00 10 00 05 00 03 02 68 32' at :235),
23// which we call into inner+6. The CLIENT'S tls13_ext_parse_alpn_selected
24// recovers "h2" from exactly the trailing ext_data (00 03 02 68 32).
25//
26// NO-STRIP (rule 25): the base emit_ee + emit_ee_test are left BYTE-INTACT.
27// This is a NEW path used only by the run_h2 server variant; the base server
28// run keeps emitting the empty no-ext EE.
29//
30// Everything else is copied VERBATIM from the base stone: encrypt under
31// server_hs_traffic_key/iv/server_seq via nx_tls13_record_encrypt_v2
32// (CT_HANDSHAKE), feed the 15 PLAINTEXT inner bytes (not the AEAD record) to
33// nx_tls13_transcript_update, ++server_seq, advance EE_SENT -> CERT_SENT.
34//
35// BACK-FILL: the team RE-AUTHORS this from the DATA spec via the
36// emitter-of-emitters (X-AUT-006c/e/f); this hand scaffold is the sanctioned
37// one-time bootstrap only (meter-integrity, mirror
38// nx_tls13_server_session_emit_ee.nx:1-22).
39//
40// Precondition: state == EE_SENT. Postcondition: state == CERT_SENT.
41//
42// license_tier: INDEPENDENT_REDERIVE
43// genealogy_id: international-research-sources/ietf/rfc_8446 + ietf/rfc_7301
44// lineage_id: nishi_tls13_server_ee_alpn_b1r3
45
46import "nx_syscalls.nx"
47import "nx_tls13.nx"
48import "nx_tls13_record.nx"
49import "nx_tls13_transcript.nx"
50import "nx_tls13_server_session.nx"
51import "nx_tls13_ext.nx"
52
53const NX_TLS13_EE_ALPN_INNER_LEN: i64 = 15 // HT + u24 + ext_list_len(2) + ALPN ext(9)
54const NX_TLS13_EE_ALPN_REC_HEADER: i64 = 5
55const NX_TLS13_EE_ALPN_REC_TAG: i64 = 16
56
57func nx_tls13_server_session_emit_ee_alpn(
58 session: *Tls13ServerSession,
59 out: *u8, out_cap: i64
60) -> i64 {
61 if (session as i64) == 0 { return 0 - NX_TLS13_SSESSION_BAD_STATE }
62 if (out as i64) == 0 { return 0 - NX_TLS13_SSESSION_BAD_STATE }
63 if session.state != NX_TLS13_SSTATE_EE_SENT {
64 return 0 - NX_TLS13_SSESSION_BAD_STATE
65 }
66 if (session.server_hs_traffic_key as i64) == 0 {
67 return 0 - NX_TLS13_SSESSION_INTERNAL
68 }
69 if (session.server_hs_iv as i64) == 0 {
70 return 0 - NX_TLS13_SSESSION_INTERNAL
71 }
72
73 // Build the 15-byte ALPN-h2 EncryptedExtensions plaintext.
74 // inner[0..6) = handshake header + ext_list_len
75 // inner[6..15) = ALPN EE ext via the GREEN client emitter (DRY, not reinvented)
76 let inner: *u8 = sys_mmap(NX_TLS13_EE_ALPN_INNER_LEN)
77 inner[0] = HT_ENCRYPTED_EXTENSIONS & 0xff // 0x08
78 inner[1] = 0 // body_len[0]
79 inner[2] = 0 // body_len[1]
80 inner[3] = 11 // body_len[2] = 0x0b = ext_list_len(2) + ext(9)
81 inner[4] = 0 // ext_list_len[0]
82 inner[5] = 9 // ext_list_len[1] = 0x09
83 // ALPN EE ext '00 10 00 05 00 03 02 68 32' -- byte-identical to the GREEN
84 // client emitter tls13_ext_emit_alpn_h2_only (nx_tls13_ext.nx:236).
85 let alpn_off: i64 = 6
86 let an: i64 = tls13_ext_emit_alpn_h2_only((inner as i64 + alpn_off) as *u8, NX_TLS13_EE_ALPN_INNER_LEN - alpn_off)
87 if an != 9 { return 0 - NX_TLS13_SSESSION_INTERNAL }
88
89 // record layout: header(5) + ct(15+1+pad) + tag(16)
90 let total_needed: i64 = NX_TLS13_EE_ALPN_REC_HEADER + NX_TLS13_EE_ALPN_INNER_LEN + 1 + NX_TLS13_EE_ALPN_REC_TAG
91 if out_cap < total_needed { return 0 - NX_TLS13_SSESSION_BUF_OVERFLOW }
92
93 let header_buf: *u8 = sys_mmap(NX_TLS13_EE_ALPN_REC_HEADER)
94 let ct_len: i64 = NX_TLS13_EE_ALPN_INNER_LEN + 1 // plaintext + inner type
95 let ct_buf: *u8 = sys_mmap(ct_len + 16)
96 let tag_buf: *u8 = sys_mmap(NX_TLS13_EE_ALPN_REC_TAG)
97
98 let rv: i64 = nx_tls13_record_encrypt_v2(
99 session.cipher_suite,
100 session.server_hs_traffic_key,
101 session.server_hs_iv,
102 session.server_seq,
103 inner, NX_TLS13_EE_ALPN_INNER_LEN,
104 CT_HANDSHAKE,
105 0, // no padding
106 header_buf, ct_buf, tag_buf)
107 if rv != NX_TLS13_REC_VERDICT_OK {
108 return 0 - NX_TLS13_SSESSION_INTERNAL
109 }
110
111 // Write header + ct + tag to output buffer.
112 var w: i64 = 0
113 var i: i64 = 0
114 while i < NX_TLS13_EE_ALPN_REC_HEADER {
115 out[w + i] = header_buf[i]
116 i = i + 1
117 }
118 w = w + NX_TLS13_EE_ALPN_REC_HEADER
119 var j: i64 = 0
120 while j < ct_len {
121 out[w + j] = ct_buf[j]
122 j = j + 1
123 }
124 w = w + ct_len
125 var k: i64 = 0
126 while k < NX_TLS13_EE_ALPN_REC_TAG {
127 out[w + k] = tag_buf[k]
128 k = k + 1
129 }
130 w = w + NX_TLS13_EE_ALPN_REC_TAG
131
132 // Feed the PLAINTEXT EE handshake bytes into transcript hash.
133 nx_tls13_transcript_update(session.transcript, inner, NX_TLS13_EE_ALPN_INNER_LEN)
134
135 session.server_seq = session.server_seq + 1
136 session.state = NX_TLS13_SSTATE_CERT_SENT
137 return w
138}