nx_tls13_client_verify_cv.nx
buildroot/runtime/nx_tls13_client_verify_cv.nx
about
nx_tls13_client_verify_cv.nx -- CLOSE THE TLS 1.3 CLIENT AUTH BYPASS.
The live client handshake (nx_tls13_client_session_recv_hs -> tls13_client_dispatch_with_validation)
validated the server's certificate CHAIN (RFC 5280) but SKIPPED the server's CertificateVerify signature
(documented STUB in nx_tls13_client.nx:170 "signature verification deferred to Gap I"). In TLS 1.3 the
cert chain is PUBLIC data; only the CertificateVerify signature -- made with the leaf cert's PRIVATE key
over Transcript-Hash(ClientHello..Certificate) -- proves the peer actually holds the key. Without it a MITM
presents the real public chain + a garbage CertificateVerify and is accepted. The server Finished MAC does
NOT save you (it only proves knowledge of the DHE secret the MITM itself negotiated). THIS closes it.
Verifies the server CertificateVerify per RFC 8446 sec 4.4.3: signed content = 64*0x20 ||
"TLS 1.3, server CertificateVerify" || 0x00 || transcript_hash(32), against the leaf cert's public key.
Dispatches the modern schemes we hold verifiers for -- ECDSA-secp256r1-SHA256 (0x0403), ECDSA-secp384r1-
SHA384 (0x0503), Ed25519 (0x0807) -- and FAILS CLOSED (reject, never accept) on any scheme we cannot yet
verify (RSA-PSS is the known follow-up). Re-composes the SAME verify primitives proven by the server-side
nx_tls13_server_recv_client_cv gate (4/4) + the ecdsa/ed25519 KATs; accept-valid is proven END-TO-END by a
real TLS fetch (nx_https_fetch_follow) landing HTTP 200 with verification enforced.
license_tier: ORIGINAL
genealogy_id: international-research-sources/ietf/rfc_8446_sec_4_4_3
dependencies 11 imports · 1 importers
diagram shows first 10 each side; +1 more imports, +0 more importers in the complete lists below.
imports: nx_syscalls.nxnx_tls13_auth.nxnx_ed25519_signature.nxnx_x509.nxnx_x509_verify_ecdsa.nxnx_x509_verify_ecdsa_p384.nxnx_u256.nxnx_u384.nxnx_u2048.nxnx_x509_pubkey_rsa.nxnx_rsa_pss_sha256.nx
imported by: nx_tls13_client_session_recv_hs.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 33 | const NX_CVV_OK: i64 = 0 |
| 34 | const NX_CVV_PARSE_FAIL: i64 = 1 // CertificateVerify message malformed |
| 35 | const NX_CVV_BAD_CERT: i64 = 2 // leaf cert unparseable / wrong key shape for the scheme |
| 36 | const NX_CVV_VERIFY_FAIL: i64 = 3 // signature did NOT verify -> REJECT (impersonation attempt) |
| 37 | const NX_CVV_UNSUPPORTED: i64 = 4 // scheme we cannot verify -> fail closed (REJECT) |
| 39 | const CVV_CONTENT_LEN: i64 = 130 |
| 40 | const CVV_SS_ECDSA_P256: i64 = 0x0403 |
| 41 | const CVV_SS_ECDSA_P384: i64 = 0x0503 |
| 42 | const CVV_SS_ED25519: i64 = 0x0807 |
| 43 | const CVV_SS_RSA_PSS_SHA256: i64 = 0x0804 // rsa_pss_rsae_sha256 -- MANDATORY for RSA-cert TLS 1.3 CertificateVerify |
functions
| 45 | func nx_tls13_client_cv_is_ok(v: i64) -> i64 { if v == NX_CVV_OK { return 1 } return 0 } |
| 48 | func cvv_content(th32: *u8, out130: *u8) -> i64 |
| 63 | func nx_tls13_client_verify_server_cv(cv_msg: *u8, cv_msg_len: i64, |
| 119 | func cvv_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } |
| 120 | func cvv_row(name: *u8, ok: i64) -> i64 { if ok == 1 { cvv_w(" PASS " as *u8) } else { cvv_w(" FAIL " as *u8) } cvv_w(name); cvv_w("\n" as *u8); return ok } |
| 121 | func cvv_u24(b: *u8, o: i64, v: i64) -> i64 { b[o] = ((v >> 16) & 0xff) as u8; b[o+1] = ((v >> 8) & 0xff) as u8; b[o+2] = (v & 0xff) as u8; return o + 3 } called by 1: cvv_build |
| 122 | func cvv_build(scheme: i64, sig: *u8, sig_len: i64, msg: *u8) -> i64 |
| 133 | func main() -> i64 |