nx_tls13_server_session_run_mtls.nx source
↩ module page · 207 lines · 11841 B
1// nx_tls13_server_session_run_mtls.nx -- R7: the live-terminator mTLS handshake run loop (Ed25519 server
2// cert path). Composes the proven server stones + the gated mTLS rungs into the full mutual-TLS handshake:
3//
4// recv ClientHello -> ServerHello -> derive -> EncryptedExtensions
5// -> CertificateRequest (rung 7a, request-NOT-require)
6// -> server Certificate -> server CertificateVerify(Ed25519) -> server Finished
7// -> [snapshot th_app = transcript THROUGH ServerFinished -- the app-key context]
8// -> client Certificate (rung 7b logic, EMPTY-cert aware) [-> client CertificateVerify+verify (rung 7c)]
9// -> client Finished (mTLS-aware: MAC over THROUGH-CLIENT-CV, app keys over th_app) -> CONNECTED
10//
11// out_auth: 0 = client presented NO cert (handshake still completes -> caller falls back to the X-Nishi-Session
12// header path: NEVER-LOCKOUT), 1 = a client cert was presented + its CertificateVerify VERIFIED (the identity
13// is in out_client_cert), -1 = a cert was presented but verification FAILED (deny). Because the request is
14// not-require, a no-cert or bad-cert client never breaks the handshake -- it just gets no mTLS identity.
15//
16// NOT in-process gateable (there is no Nishi mTLS CLIENT to loopback-present a cert); its live behavior --
17// the browser's empty-cert response + the dual-snapshot key schedule -- is verified against a real browser
18// presenting one of the provisioned .p12 files. Deploy is request-not-require + backup/rollback => safe:
19// every NON-cert client completes exactly as today. license_tier: ORIGINAL
20import "nx_syscalls.nx"
21import "nx_tls13.nx"
22import "nx_tls13_record.nx"
23import "nx_tls13_transcript.nx"
24import "nx_tls13_kdf.nx"
25import "nx_hmac.nx"
26import "nx_hkdf.nx"
27import "nx_tls13_server_session.nx"
28import "nx_tls13_read_record_from_fd.nx"
29import "nx_tls13_server_session_run.nx" // _srun_recv_client_hello + emit stones + SRUN consts
30import "nx_tls13_server_session_emit_certreq.nx" // 7a
31import "nx_tls13_auth.nx" // Certificate parser (empty-cert aware)
32import "nx_tls13_server_recv_client_cv.nx" // 7c (recv + verify CertificateVerify)
33import "nx_tls13_mtls_finished.nx" // the GATED mTLS dual-snapshot client Finished handler
34import "nx_tls13_mtls_recv_cert.nx" // the GATED empty-cert-aware client Certificate receive
35
36const NX_MRUN_CV_LEN: i64 = 32
37const NX_MRUN_REC_HEADER: i64 = 5
38const NX_MRUN_REC_TAG: i64 = 16
39const NX_MRUN_BUF: i64 = 16645
40
41func _mrun_write(fd: i64, buf: *u8, n: i64) -> i64 {
42 var off: i64 = 0
43 while off < n { let w: i64 = sys_write(fd, (buf as i64 + off) as *u8, n - off); if w <= 0 { return 0 - 1 } off = off + w }
44 return 0
45}
46
47// read the next handshake record from fd, skipping middlebox-compat ChangeCipherSpec (type 0x14). len or <0.
48func _mrun_read_hs(fd: i64, buf: *u8, cap: i64) -> i64 {
49 var loops: i64 = 0
50 while loops < 4 {
51 let n: i64 = nx_tls13_read_record_from_fd(fd, buf, cap)
52 if n < 0 { return 0 - 1 }
53 if (buf[0] & 0xff) != 0x14 { return n }
54 loops = loops + 1
55 }
56 return 0 - 1
57}
58
59// (The empty-cert-aware client Certificate receive -- and its constant-time/empty-hash helpers -- now live in
60// and are GATED by nx_tls13_mtls_recv_cert.nx [nx_tls13_mtls_recv_client_cert, 6/6]. Imported above.)
61
62// (The mTLS-aware client Finished handler -- the dual-snapshot key schedule -- now lives in and is GATED by
63// nx_tls13_mtls_finished.nx [nx_tls13_mtls_recv_finished, 6/6: MAC over the current transcript, app-keys over
64// th_app]. Imported above; single source of truth for this security-critical step.)
65
66// THE mTLS RUN LOOP. Returns the session as i64 (positive) on CONNECTED, or a negative -(NX_TLS13_SRUN_*).
67// out_auth: 0 no-cert (fall back to header), 1 verified (identity in out_client_cert), -1 verify-failed.
68func nx_tls13_server_session_run_ed25519_mtls(
69 fd: i64,
70 srv_rand: *u8, srv_x25519_priv: *u8,
71 cert_der: *u8, cert_der_len: i64,
72 ed25519_priv_32: *u8,
73 out_client_cert: *u8, out_cc_cap: i64, out_cc_len: *i64, out_auth: *i64
74) -> i64 {
75 out_auth[0] = 0; out_cc_len[0] = 0
76 let s: *Tls13ServerSession = nx_tls13_server_session_new(srv_rand, srv_x25519_priv)
77 if (s as i64) == 0 { return 0 - NX_TLS13_SRUN_RECV_CH_FAIL }
78 if _srun_recv_client_hello(fd, s) < 0 { return 0 - NX_TLS13_SRUN_RECV_CH_FAIL }
79
80 let sh: *u8 = sys_mmap(NX_MRUN_BUF); let n_sh: i64 = nx_tls13_server_session_emit_sh(s, sh, NX_MRUN_BUF)
81 if n_sh <= 0 { return 0 - NX_TLS13_SRUN_EMIT_SH_FAIL }
82 if _mrun_write(fd, sh, n_sh) < 0 { return 0 - NX_TLS13_SRUN_WRITE_SH_FAIL }
83 if nx_tls13_server_session_derive_hs_secrets(s) != NX_TLS13_SSESSION_OK { return 0 - NX_TLS13_SRUN_DERIVE_HS_FAIL }
84 if nx_tls13_server_session_derive_traffic(s) != NX_TLS13_SSESSION_OK { return 0 - NX_TLS13_SRUN_DERIVE_TRAFFIC_FAIL }
85
86 let ee: *u8 = sys_mmap(NX_MRUN_BUF); let n_ee: i64 = nx_tls13_server_session_emit_ee(s, ee, NX_MRUN_BUF)
87 if n_ee <= 0 { return 0 - NX_TLS13_SRUN_EMIT_EE_FAIL }
88 if _mrun_write(fd, ee, n_ee) < 0 { return 0 - NX_TLS13_SRUN_WRITE_EE_FAIL }
89
90 // ---- rung 7a: CertificateRequest (request-not-require) ----
91 let cr: *u8 = sys_mmap(NX_MRUN_BUF); let n_cr: i64 = nx_tls13_server_session_emit_certreq(s, cr, NX_MRUN_BUF)
92 if n_cr <= 0 { return 0 - NX_TLS13_SRUN_EMIT_EE_FAIL }
93 if _mrun_write(fd, cr, n_cr) < 0 { return 0 - NX_TLS13_SRUN_WRITE_EE_FAIL }
94
95 let ce: *u8 = sys_mmap(NX_MRUN_BUF); let n_ce: i64 = nx_tls13_server_session_emit_certificate(s, cert_der, cert_der_len, ce, NX_MRUN_BUF)
96 if n_ce <= 0 { return 0 - NX_TLS13_SRUN_EMIT_CERT_FAIL }
97 if _mrun_write(fd, ce, n_ce) < 0 { return 0 - NX_TLS13_SRUN_WRITE_CERT_FAIL }
98
99 let cv: *u8 = sys_mmap(NX_MRUN_BUF); let n_cv: i64 = nx_tls13_server_session_emit_cv_ed25519(s, ed25519_priv_32, cv, NX_MRUN_BUF)
100 if n_cv <= 0 { return 0 - NX_TLS13_SRUN_EMIT_CV_FAIL }
101 if _mrun_write(fd, cv, n_cv) < 0 { return 0 - NX_TLS13_SRUN_WRITE_CV_FAIL }
102
103 let sf: *u8 = sys_mmap(NX_MRUN_BUF); let n_sf: i64 = nx_tls13_server_session_emit_sf(s, sf, NX_MRUN_BUF)
104 if n_sf <= 0 { return 0 - NX_TLS13_SRUN_EMIT_SF_FAIL }
105 if _mrun_write(fd, sf, n_sf) < 0 { return 0 - NX_TLS13_SRUN_WRITE_SF_FAIL }
106
107 // ---- snapshot th_app = transcript THROUGH ServerFinished (app-key context, RFC 8446 ยง7.1) ----
108 let th_app: *u8 = sys_mmap(32)
109 if nx_tls13_transcript_snapshot(s.transcript, th_app) != NX_TLS13_TX_VERDICT_OK { return 0 - NX_TLS13_SRUN_RECV_CF_FAIL }
110
111 // ---- client flight: Certificate [+ CertificateVerify] + Finished ----
112 let cert_rec: *u8 = sys_mmap(NX_MRUN_BUF)
113 let cert_total: i64 = _mrun_read_hs(fd, cert_rec, NX_MRUN_BUF)
114 if cert_total < 0 { return 0 - NX_TLS13_SRUN_READ_CF_FAIL }
115 let present: *i64 = sys_mmap(8) as *i64
116 if nx_tls13_mtls_recv_client_cert(s, cert_rec, cert_total, out_client_cert, out_cc_cap, out_cc_len, present) != NX_TLS13_SSESSION_OK { return 0 - NX_TLS13_SRUN_RECV_CF_FAIL }
117
118 if present[0] == 1 {
119 let cv_rec: *u8 = sys_mmap(NX_MRUN_BUF)
120 let cv_total: i64 = _mrun_read_hs(fd, cv_rec, NX_MRUN_BUF)
121 if cv_total < 0 { return 0 - NX_TLS13_SRUN_READ_CF_FAIL }
122 if nx_tls13_server_recv_client_cv(s, cv_rec, cv_total, out_client_cert, out_cc_len[0]) == NX_RCV_OK {
123 out_auth[0] = 1
124 } else {
125 out_auth[0] = 0 - 1
126 }
127 }
128
129 let fin_rec: *u8 = sys_mmap(NX_MRUN_BUF)
130 let fin_total: i64 = _mrun_read_hs(fd, fin_rec, NX_MRUN_BUF)
131 if fin_total < 0 { return 0 - NX_TLS13_SRUN_READ_CF_FAIL }
132 if nx_tls13_mtls_recv_finished(s, fin_rec, fin_total, th_app) != NX_TLS13_SSESSION_OK { return 0 - NX_TLS13_SRUN_RECV_CF_FAIL }
133
134 return s as i64
135}
136
137// ECDSA-P256 server-cert variant -- the live nx_opaque_login_tls_daemon serves the browser-trusted LE cert,
138// which is ECDSA, so THIS is the variant the cutover wires in. Identical mutual-auth flow; only the SERVER's
139// own CertificateVerify is ECDSA (emit_cv) vs Ed25519. ecdsa_priv_be = 32-byte big-endian P-256 scalar.
140func nx_tls13_server_session_run_ecdsa_mtls(
141 fd: i64,
142 srv_rand: *u8, srv_x25519_priv: *u8,
143 cert_der: *u8, cert_der_len: i64,
144 ecdsa_priv_be: *u8,
145 out_client_cert: *u8, out_cc_cap: i64, out_cc_len: *i64, out_auth: *i64
146) -> i64 {
147 out_auth[0] = 0; out_cc_len[0] = 0
148 let s: *Tls13ServerSession = nx_tls13_server_session_new(srv_rand, srv_x25519_priv)
149 if (s as i64) == 0 { return 0 - NX_TLS13_SRUN_RECV_CH_FAIL }
150 if _srun_recv_client_hello(fd, s) < 0 { return 0 - NX_TLS13_SRUN_RECV_CH_FAIL }
151
152 let sh: *u8 = sys_mmap(NX_MRUN_BUF); let n_sh: i64 = nx_tls13_server_session_emit_sh(s, sh, NX_MRUN_BUF)
153 if n_sh <= 0 { return 0 - NX_TLS13_SRUN_EMIT_SH_FAIL }
154 if _mrun_write(fd, sh, n_sh) < 0 { return 0 - NX_TLS13_SRUN_WRITE_SH_FAIL }
155 if nx_tls13_server_session_derive_hs_secrets(s) != NX_TLS13_SSESSION_OK { return 0 - NX_TLS13_SRUN_DERIVE_HS_FAIL }
156 if nx_tls13_server_session_derive_traffic(s) != NX_TLS13_SSESSION_OK { return 0 - NX_TLS13_SRUN_DERIVE_TRAFFIC_FAIL }
157
158 let ee: *u8 = sys_mmap(NX_MRUN_BUF); let n_ee: i64 = nx_tls13_server_session_emit_ee(s, ee, NX_MRUN_BUF)
159 if n_ee <= 0 { return 0 - NX_TLS13_SRUN_EMIT_EE_FAIL }
160 if _mrun_write(fd, ee, n_ee) < 0 { return 0 - NX_TLS13_SRUN_WRITE_EE_FAIL }
161
162 let cr: *u8 = sys_mmap(NX_MRUN_BUF); let n_cr: i64 = nx_tls13_server_session_emit_certreq(s, cr, NX_MRUN_BUF)
163 if n_cr <= 0 { return 0 - NX_TLS13_SRUN_EMIT_EE_FAIL }
164 if _mrun_write(fd, cr, n_cr) < 0 { return 0 - NX_TLS13_SRUN_WRITE_EE_FAIL }
165
166 let ce: *u8 = sys_mmap(NX_MRUN_BUF); let n_ce: i64 = nx_tls13_server_session_emit_certificate(s, cert_der, cert_der_len, ce, NX_MRUN_BUF)
167 if n_ce <= 0 { return 0 - NX_TLS13_SRUN_EMIT_CERT_FAIL }
168 if _mrun_write(fd, ce, n_ce) < 0 { return 0 - NX_TLS13_SRUN_WRITE_CERT_FAIL }
169
170 // server's OWN CertificateVerify -- ECDSA-P256 (the LE server cert); the only difference from the Ed25519 variant
171 let cv: *u8 = sys_mmap(NX_MRUN_BUF); let n_cv: i64 = nx_tls13_server_session_emit_cv(s, ecdsa_priv_be, cv, NX_MRUN_BUF)
172 if n_cv <= 0 { return 0 - NX_TLS13_SRUN_EMIT_CV_FAIL }
173 if _mrun_write(fd, cv, n_cv) < 0 { return 0 - NX_TLS13_SRUN_WRITE_CV_FAIL }
174
175 let sf: *u8 = sys_mmap(NX_MRUN_BUF); let n_sf: i64 = nx_tls13_server_session_emit_sf(s, sf, NX_MRUN_BUF)
176 if n_sf <= 0 { return 0 - NX_TLS13_SRUN_EMIT_SF_FAIL }
177 if _mrun_write(fd, sf, n_sf) < 0 { return 0 - NX_TLS13_SRUN_WRITE_SF_FAIL }
178
179 let th_app: *u8 = sys_mmap(32)
180 if nx_tls13_transcript_snapshot(s.transcript, th_app) != NX_TLS13_TX_VERDICT_OK { return 0 - NX_TLS13_SRUN_RECV_CF_FAIL }
181
182 let cert_rec: *u8 = sys_mmap(NX_MRUN_BUF)
183 let cert_total: i64 = _mrun_read_hs(fd, cert_rec, NX_MRUN_BUF)
184 if cert_total < 0 { return 0 - NX_TLS13_SRUN_READ_CF_FAIL }
185 let present: *i64 = sys_mmap(8) as *i64
186 if nx_tls13_mtls_recv_client_cert(s, cert_rec, cert_total, out_client_cert, out_cc_cap, out_cc_len, present) != NX_TLS13_SSESSION_OK { return 0 - NX_TLS13_SRUN_RECV_CF_FAIL }
187
188 if present[0] == 1 {
189 let cv_rec: *u8 = sys_mmap(NX_MRUN_BUF)
190 let cv_total: i64 = _mrun_read_hs(fd, cv_rec, NX_MRUN_BUF)
191 if cv_total < 0 { return 0 - NX_TLS13_SRUN_READ_CF_FAIL }
192 if nx_tls13_server_recv_client_cv(s, cv_rec, cv_total, out_client_cert, out_cc_len[0]) == NX_RCV_OK {
193 out_auth[0] = 1
194 } else {
195 out_auth[0] = 0 - 1
196 }
197 }
198
199 let fin_rec: *u8 = sys_mmap(NX_MRUN_BUF)
200 let fin_total: i64 = _mrun_read_hs(fd, fin_rec, NX_MRUN_BUF)
201 if fin_total < 0 { return 0 - NX_TLS13_SRUN_READ_CF_FAIL }
202 if nx_tls13_mtls_recv_finished(s, fin_rec, fin_total, th_app) != NX_TLS13_SSESSION_OK { return 0 - NX_TLS13_SRUN_RECV_CF_FAIL }
203
204 return s as i64
205}
206
207func main() -> i64 { return 0 }