code wiki / (root) / nx_tls13_server_session_run_mtls.nx

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 }