code wiki / (root) / nx_tls12_ske_verify.nx

nx_tls12_ske_verify.nx source

↩ module page · 132 lines · 6881 B

1// nx_tls12_ske_verify.nx -- TLS 1.2 ECDHE-RSA ServerKeyExchange signature 2// verification (rung 5 of the sovereign TLS 1.2 client; RFC 5246 §7.4.3 + 3// §7.4.1.4.1). The server proves ownership of its certificate's RSA key by 4// signing the ephemeral ECDHE parameters bound to both handshake randoms: 5// 6// signed_data = client_random(32) || server_random(32) || ECDHE_params 7// signature = RSASSA-PKCS1-v1_5( SHA-256(signed_data) ) // leaf RSA key 8// 9// ECDHE_params = curve_type(1=0x03 named_curve) 10// || named_curve(2=0x0017 secp256r1) 11// || point_len(1) || point(point_len, 0x04||X||Y uncompressed) 12// 13// On the TLS 1.2 wire the SKE body additionally carries, AFTER the params, a 14// 2-byte SignatureAndHashAlgorithm (e.g. 0x0401 = {sha256, rsa}) and a 2-byte 15// signature length -- but those frame the signature; the SIGNED bytes are 16// exactly client_random || server_random || ECDHE_params. 17// 18// COMPOSED, not re-implemented (verify-don't-rebuild): 19// - tls12_skx_signed_data -> nx_tls12_parse.nx (signed-data assembly) 20// - tls12_parse_server_key_exchange -> nx_tls12_parse.nx (wire field split) 21// - rsa_pkcs1_v1_5_sha256_verify -> nx_rsa_pkcs1_v1_5_sha256.nx (RSA-2048 22// PKCS1 v1.5 + SHA-256 verify, hashes 23// signed_data internally) 24// - u2048_load_be -> nx_u2048.nx (modulus load) 25// 26// This rung adds ONLY the glue: assemble -> hash+verify -> sealed verdict. 27// 28// license_tier: INDEPENDENT_REDERIVE 29// genealogy_id: international-research-sources/ietf/rfc_5246 + rfc_8017 30// lineage_id: nishi_tls12_ske_verify_q1 31// 32// nx_safety_envelope: 33// intended_use: "TLS 1.2 ECDHE-RSA ServerKeyExchange signature 34// verification (server authentication / anti-MITM)" 35// sil_target: SIL3 (authentication; a forged-accept = MITM) 36// evidence: [composed_from_rsa_pkcs1v15_sha256_verify, 37// openssl_signed_fixture_VERIFIED, 38// neg_control_flipped_sig_and_signed_data_REJECTED] 39// verdict: NOT_YET_EVALUATED 40 41import "nx_syscalls.nx" 42import "nx_u2048.nx" 43import "nx_rsa_pkcs1_v1_5_sha256.nx" 44import "nx_tls12_parse.nx" 45import "nx_x509_verify_ecdsa.nx" // ECDHE-ECDSA SKE: nx_x509_verify_ecdsa_p256 (hash+DER-parse+verify) + NX_X509_ECDSA_OK 46 47// Sealed verdict. 48const NX_TLS12_SKE_OK: i64 = 1 49const NX_TLS12_SKE_BAD_SIG: i64 = 2 // signature did not verify 50const NX_TLS12_SKE_BAD_PARAMS: i64 = 3 // malformed SKE wire body 51const NX_TLS12_SKE_VERDICT_N: i64 = 4 52 53func nx_tls12_ske_verdict_is_valid(v: i64) -> i64 { 54 if v < NX_TLS12_SKE_OK { return 0 } 55 if v >= NX_TLS12_SKE_VERDICT_N { return 0 } 56 return 1 57} 58 59// Verify against an already-loaded U2048 modulus. 60// params/params_len = the ECDHE_params bytes (curve_type..point), 69 bytes 61// for secp256r1 uncompressed. 62// sig/sig_len = the RSA signature (256 bytes for RSA-2048). 63func nx_tls12_ske_verify(client_random: *u8, server_random: *u8, 64 params: *u8, params_len: i64, 65 sig: *u8, sig_len: i64, 66 pub_n: *i64, pub_e: i64) -> i64 { 67 // RSA-2048 PKCS1 v1.5 signatures are exactly 256 bytes. 68 if sig_len != 256 { return NX_TLS12_SKE_BAD_SIG } 69 let signed_len: i64 = 64 + params_len 70 let signed: *u8 = sys_mmap(signed_len + 8) 71 tls12_skx_signed_data(client_random, server_random, params, params_len, signed) 72 let v: i64 = rsa_pkcs1_v1_5_sha256_verify(signed, signed_len, sig, pub_n, pub_e) 73 if v == NX_RSA_PKCS1_V15_OK { return NX_TLS12_SKE_OK } 74 return NX_TLS12_SKE_BAD_SIG 75} 76 77// ECDHE-ECDSA SKE signature verify (RFC 5246 §7.4.3 + §7.4.1.4.1, sig_alg ecdsa_secp256r1_sha256): 78// signed_data = client_random(32) || server_random(32) || ECDHE_params 79// signature = DER ECDSA(SHA-256(signed_data)) under the LEAF's EC P-256 key (pub_x,pub_y as u256 limbs) 80// Composes tls12_skx_signed_data (assemble) + the gated nx_x509_verify_ecdsa_p256 (which SHA-256-hashes the 81// message, parses the DER SEQUENCE{r,s}, and does u1*G+u2*Q). Same anti-MITM contract as the RSA path; a 82// forged/mismatched sig -> BAD_SIG (FAIL-CLOSED by construction -- a wrong signed_data can only make it reject). 83func nx_tls12_ske_verify_ecdsa(client_random: *u8, server_random: *u8, 84 params: *u8, params_len: i64, 85 sig: *u8, sig_len: i64, 86 pub_x: *i64, pub_y: *i64) -> i64 { 87 let signed_len: i64 = 64 + params_len 88 let signed: *u8 = sys_mmap(signed_len + 8) 89 tls12_skx_signed_data(client_random, server_random, params, params_len, signed) 90 let v: i64 = nx_x509_verify_ecdsa_p256(signed, signed_len, sig, sig_len, pub_x, pub_y) 91 if v == NX_X509_ECDSA_OK { return NX_TLS12_SKE_OK } 92 return NX_TLS12_SKE_BAD_SIG 93} 94 95// Convenience: verify with the leaf modulus as 256 raw big-endian bytes (the 96// form it appears in inside the X.509 certificate's RSAPublicKey). 97func nx_tls12_ske_verify_n(client_random: *u8, server_random: *u8, 98 params: *u8, params_len: i64, 99 sig: *u8, sig_len: i64, 100 n_bytes: *u8, pub_e: i64) -> i64 { 101 let n_int: *i64 = u2048_alloc() 102 u2048_load_be(n_int, n_bytes) 103 return nx_tls12_ske_verify(client_random, server_random, 104 params, params_len, sig, sig_len, n_int, pub_e) 105} 106 107// Full wire path: parse the ECDHE ServerKeyExchange handshake body (after the 108// 4-byte handshake header), then verify its signature with the leaf RSA key. 109// body layout: curve_type(1) || named_curve(2) || point_len(1) || point 110// || sig_alg(2) || sig_len(2 BE) || signature(sig_len) 111func nx_tls12_ske_verify_wire(client_random: *u8, server_random: *u8, 112 body: *u8, body_len: i64, 113 n_bytes: *u8, pub_e: i64) -> i64 { 114 let out_curve: *i64 = (sys_mmap(8)) as *i64 115 let out_pub: *u8 = sys_mmap(512) 116 let out_pub_len: *i64 = (sys_mmap(8)) as *i64 117 let out_sigalg: *i64 = (sys_mmap(8)) as *i64 118 let out_sig: *u8 = sys_mmap(512) 119 let out_sig_len: *i64 = (sys_mmap(8)) as *i64 120 let ok: i64 = tls12_parse_server_key_exchange( 121 body, body_len, out_curve, out_pub, out_pub_len, 122 out_sigalg, out_sig, out_sig_len 123 ) 124 if ok != 1 { return NX_TLS12_SKE_BAD_PARAMS } 125 // ECDHE_params occupies the first (4 + point_len) bytes of the body: 126 // curve_type(1) + named_curve(2) + point_len(1) + point(point_len). 127 let params_len: i64 = 4 + out_pub_len[0] 128 return nx_tls12_ske_verify_n( 129 client_random, server_random, body, params_len, 130 out_sig, out_sig_len[0], n_bytes, pub_e 131 ) 132}