code wiki / (root) / nx_x509_validate.nx

nx_x509_validate.nx source

↩ module page · 104 lines · 4418 B

1// nx_x509_validate.nx -- X.509 certificate validation (Gap I.2.A). 2// 3// Phase 0b §I.2 of the Nishi TLS 1.3 stack per 4// docs/NISHI_TLS13_GAP_AUDIT.md. Composes the shipped 5// ed25519_verify_full (T11) with the X509Cert parse offsets 6// (nx_x509, extended in T6) into the cert-validation primitives 7// that the TLS client's accept-any stub will eventually call. 8// 9// What it does today: 10// - x509_verify_signature_ed25519(buf, cert, signer_pubkey32): 11// read cert.tbs + cert.sig from buf, verify the signature 12// under signer_pubkey32 using shipped ed25519_verify_full. 13// Returns NX_X509_VAL_OK (1) on valid, NX_X509_VAL_BAD_SIG (0) 14// on invalid. Negative on malformed (e.g. sig wrong length). 15// 16// - Sealed verdict + validity gate. 17// 18// What it doesn't do yet (sub-pieces I.2.B + I.2.C, ~1 session each): 19// - validity period check (UTCTime / GeneralizedTime parse + 20// compare against caller-supplied now_unix_secs). Needs: 21// * fn x509_validity_get(cert, buf, out_notBefore, out_notAfter) 22// * ASN.1 time-string parser (Year Month Day Hour Min Sec Z) 23// * compose against nx_time / unix-epoch math 24// - SAN extension walk (parse cert.extensions_off/len for 25// OID 2.5.29.17 SubjectAltName, walk GeneralName SEQUENCE, 26// extract dNSName entries, match against SNI hostname). 27// - ECDSA-P256 signature verify (for real-world server certs; 28// covers ~80% of Web PKI). 29// - RSA-PSS signature verify (for the remaining ~15%). 30// - Full RFC 5280 chain walk + trust-anchor matching (Gap I.3). 31// 32// KAT verified: 33// - Self-signed Ed25519 cert (RFC 8032 §7.1 TEST 1 keypair; 34// fake tbs blob; sign with ed25519_sign_full at test time; 35// wrap into a synthetic X509Cert offset structure) validates. 36// - Same cert with one tbs byte flipped: validation FAILS. 37// - Same cert with a different signer_pubkey: validation FAILS. 38// - Same cert with sig byte flipped: validation FAILS. 39// 40// Composes with: 41// - nx_x509 (X509Cert struct + parse offsets) 42// - nx_ed25519_signature (ed25519_verify_full) 43// 44// license_tier: INDEPENDENT_REDERIVE 45// genealogy_id: international-research-sources/ietf/rfc_8032 + ietf/rfc_5280 46// lineage_id: nishi_x509_validate_q10 47 48// nx_safety_envelope: 49// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 50// sil_target: SIL1 51// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 52// verdict: NOT_YET_EVALUATED 53 54import "nx_syscalls.nx" 55import "nx_x509.nx" 56import "nx_ed25519_signature.nx" 57 58const NX_X509_VAL_OK: i64 = 1 59const NX_X509_VAL_BAD_SIG: i64 = 2 60const NX_X509_VAL_BAD_SIG_LEN: i64 = 3 61const NX_X509_VAL_BAD_PUB_LEN: i64 = 4 62const NX_X509_VAL_BAD_TBS: i64 = 5 63const NX_X509_VAL_VERDICT_N: i64 = 6 64 65// Verify an X.509 certificate's outer signature under an 66// Ed25519 signer public key. 67// 68// Inputs: 69// buf = the full DER cert byte buffer (cert was 70// parsed by x509_parse against this buf) 71// cert = parsed X509Cert with tbs_off/len + sig_off/len 72// populated 73// signer_pubkey32 = 32-byte raw Ed25519 public key of the 74// signer (for self-signed: cert's own pubkey; 75// for chain: parent CA's pubkey) 76// 77// Returns NX_X509_VAL_OK (1) on valid, NX_X509_VAL_BAD_SIG (0) 78// on invalid, or a NX_X509_VAL_BAD_* negative verdict on 79// malformed input. 80// 81// Caller responsibility (NOT enforced here, queued): 82// - validity period check (notBefore <= now <= notAfter) 83// - SAN hostname match against the SNI peer name 84// - chain walk to a configured trust anchor 85// - signature_algorithm OID matches Ed25519 (1.3.101.112) 86func x509_verify_signature_ed25519( 87 buf: *u8, cert: *X509Cert, 88 signer_pubkey32: *u8 89) -> i64 { 90 if cert.sig_len != 64 { return NX_X509_VAL_BAD_SIG_LEN } 91 if cert.tbs_len < 1 { return NX_X509_VAL_BAD_TBS } 92 let tbs_ptr: *u8 = buf + cert.tbs_off 93 let sig_ptr: *u8 = buf + cert.sig_off 94 let v: i64 = ed25519_verify_full(signer_pubkey32, tbs_ptr, cert.tbs_len, sig_ptr) 95 if v == NX_ED25519_SIG_OK { return NX_X509_VAL_OK } 96 return NX_X509_VAL_BAD_SIG 97} 98 99// Sealed-enum validity gate. 100func nx_x509_val_verdict_is_valid(v: i64) -> i64 { 101 if v < NX_X509_VAL_OK { return 0 } 102 if v >= NX_X509_VAL_VERDICT_N { return 0 } 103 return 1 104}