nx_rsa_pss_sha256_gate.nx source
↩ module page · 57 lines · 4943 B
1// nx_rsa_pss_sha256_gate.nx -- KAT for rsa_pss_sha256_verify vs a REAL OpenSSL-3.2 RSA-PSS/SHA-256/salt32
2// signature (2048-bit key; "openssl dgst -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:32 -sign";
3// self-verified "Verified OK"). T1 accept the genuine sig; T2/T3/T4 reject a 1-bit-flipped sig / wrong message /
4// flipped modulus (no false accept -- the possession-proof invariant). GREEN iff 4/4. expect_exit: 0
5import "nx_syscalls.nx"
6import "nx_u2048.nx"
7import "nx_rsa_pss_sha256.nx"
8import "nx_gate_verdict.nx"
9
10func gw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
11func gn(v: i64) -> i64 { let b: *u8 = sys_mmap(24); var m: i64 = v; if m<0 { gw("-" as *u8); m=0-m } let t: *u8=sys_mmap(24); var k: i64=0; if m==0 {t[0]=48 as u8;k=1} while m>0 {t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k {b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 }
12func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("\n" as *u8); return ok }
13func hx(c: i64) -> i64 { if c>=48 { if c<=57 { return c-48 } } if c>=97 { if c<=102 { return c-87 } } if c>=65 { if c<=70 { return c-55 } } return 0 }
14func h2b(s: *u8, out: *u8) -> i64 { var i: i64=0; var o: i64=0; while s[i]!=(0 as u8) { if s[i+1]==(0 as u8) { i=i+1 } else { out[o]=((hx(s[i] as i64)<<4)|hx(s[i+1] as i64)) as u8; o=o+1; i=i+2 } } return o }
15
16func main() -> i64 {
17 gw("rsa-pss-sha256 KAT gate (real OpenSSL-3.2 PSS/salt32 signature)\n" as *u8)
18 var pass: i64 = 0
19 let nb: *u8 = sys_mmap(256); let sig: *u8 = sys_mmap(256); let msg: *u8 = sys_mmap(64)
20 h2b("BA3587BEFFA3F1F3B404C0B7903FA421C8194531A13811BBDAE5B347B02DC1AF57E97F4FA568303E00BC9079952C30ECCBFEBBDCA9C88CB1F69D5C80708283B72F34710EF9F4BA2DEA98C2A4E5733CE9B6468376FF00C069D70474AC4EBF8869FE140E619EC67EB86864B3AF146A68CC2D61AB55FC4EA3C334FC8FB3F5026F6E17521BC99C7D6D7EA3013E99F0C11431EF6AB6EF56A7A90FD817821190C2658225330EFA0B45B8E6D0707ACC6363582D16D873B5C289B339E0F23D2A8293C0C4610C8DFBB7AFF2ED10C30F6BF984D96808EED802E703CCDA6BAAE910BC0821CFE9E42A4A41AD05B942F6028167CB2FA1D8BDD65194F0962CC30652EF1592D981" as *u8, nb)
21 let siglen: i64 = h2b("878017588f6270126ff98f1f538d8435fa5e3ae6dbb6f568beaccbec2e41705eda3a2610a14d4b46de29b053eff3a5a691944a56429236006d1fa7676a07013db347a50546dd72c26fac513dc8ab7c93763981e94a7f3824816c53d9f759e09bc085f845207986d60e7d6d61b14fc0ac0101bc37572dc3e4b701b846132778ce00d8dbee15b723c6829ebdd2ba4343ea5a3149baa66867f110eece887bbbdef468f90c4221e09d484e2b37e7c19d1c3230ead6b085c3c8f6970e5d958e32af6dba926cb09b8de736094b196263a84a76cefe55da7d4165a6d9a230379879cd55e103cd1b0c3740feb5385a653878edb73519615acabe4cf7cf5ec1c3c67e1b45" as *u8, sig)
22 let mlen: i64 = h2b("6e6973686920707373206b6174206d657373616765" as *u8, msg)
23
24 let n_int: *i64 = u2048_alloc(); u2048_load_be(n_int, nb)
25
26 // T1 accept the genuine signature
27 let r1: i64 = rsa_pss_sha256_verify(msg, mlen, sig, n_int, 65537)
28 gw(" verify(genuine) verdict=" as *u8); gn(r1); gw("\n" as *u8)
29 pass = pass + grow("T1 accept genuine OpenSSL RSA-PSS/SHA256 signature\x00" as *u8, r1 == NX_RSA_PSS_OK)
30
31 // T2 flip one signature byte -> reject
32 let sig2: *u8 = sys_mmap(256); var i: i64 = 0; while i < siglen { sig2[i] = sig[i]; i = i + 1 } sig2[100] = ((sig[100] as i64) ^ 0x01) as u8
33 let r2: i64 = rsa_pss_sha256_verify(msg, mlen, sig2, n_int, 65537)
34 pass = pass + grow("T2 REJECT 1-bit-flipped signature (no false accept)\x00" as *u8, r2 != NX_RSA_PSS_OK)
35
36 // T3 wrong message -> reject
37 let msg3: *u8 = sys_mmap(64); i = 0; while i < mlen { msg3[i] = msg[i]; i = i + 1 } msg3[0] = ((msg[0] as i64) ^ 0xff) as u8
38 let r3: i64 = rsa_pss_sha256_verify(msg3, mlen, sig, n_int, 65537)
39 pass = pass + grow("T3 REJECT altered message (possession proof binds the msg)\x00" as *u8, r3 != NX_RSA_PSS_OK)
40
41 // T4 flip a modulus byte -> reject
42 let nb4: *u8 = sys_mmap(256); i = 0; while i < 256 { nb4[i] = nb[i]; i = i + 1 } nb4[200] = ((nb[200] as i64) ^ 0x01) as u8
43 let n4: *i64 = u2048_alloc(); u2048_load_be(n4, nb4)
44 let r4: i64 = rsa_pss_sha256_verify(msg, mlen, sig, n4, 65537)
45 pass = pass + grow("T4 REJECT under a corrupted modulus (wrong key never accepts)\x00" as *u8, r4 != NX_RSA_PSS_OK)
46
47 gw("pass=" as *u8); gn(pass); gw("/4\n" as *u8)
48 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
49 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
50 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
51 let ctr__dry: *i64 = gv_ctr()
52 ctr__dry[0] = pass
53 ctr__dry[1] = 4
54 let rc__dry: i64 = gv_verdict("RSA-PSS-SHA256-GATE" as *u8, ctr__dry, "RSA-PSS-SHA256 verify: accepts genuine OpenSSL sig, fail-closed on every tamper)" as *u8)
55 sys_exit(rc__dry)
56 return rc__dry
57}