nx_rsa_pss_sha256.nx source
↩ module page · 98 lines · 4908 B
1// nx_rsa_pss_sha256.nx -- RSASSA-PSS signature VERIFY with SHA-256 (MGF1-SHA-256, salt_len=32), RSA-2048.
2// This is rsa_pss_rsae_sha256 (TLS SignatureScheme 0x0804) -- the scheme TLS 1.3 MANDATES for RSA-cert servers'
3// CertificateVerify (rsa_pkcs1 is NOT allowed for CV). Without it we fail-closed on EVERY RSA-cert TLS-1.3 server
4// (e.g. i.nhentai.net's Cloudflare edge). COMPOSED (Cardinals 15/22): reuses the SAME RSA modexp
5// (rsa2048_mod_exp_mont) + u2048 bignum + sha256_digest as the PKCS#1 verifier; only the EMSA-PSS-VERIFY padding
6// check (RFC 8017 sec 9.1.2) is new. license_tier: INDEPENDENT_REDERIVE genealogy: ietf/rfc_8017 sec_9_1_2
7import "nx_syscalls.nx"
8import "nx_sha256.nx"
9import "nx_u2048.nx"
10import "nx_rsa2048_mod_exp.nx"
11import "nx_rsa2048_mont.nx"
12
13const NX_RSA_PSS_OK: i64 = 1
14const NX_RSA_PSS_S_OUT_OF_RANGE:i64 = 2
15const NX_RSA_PSS_BAD_PAD: i64 = 3 // EM structure / trailer / masked-bits / DB prefix wrong
16const NX_RSA_PSS_HASH_MISMATCH: i64 = 4 // H != H' (the possession proof fails)
17const NX_RSA_PSS_VERDICT_N: i64 = 5
18
19func rsa_pss_verdict_is_valid(v: i64) -> i64 { if v < NX_RSA_PSS_OK { return 0 } if v >= NX_RSA_PSS_VERDICT_N { return 0 } return 1 }
20
21// MGF1 with SHA-256 (RFC 8017 sec B.2.1): mask = T[0..maskLen], T = SHA256(seed || I2OSP(ctr,4)) for ctr=0,1,...
22func mgf1_sha256(seed: *u8, seed_len: i64, mask: *u8, mask_len: i64) -> i64 {
23 let buf: *u8 = sys_mmap(seed_len + 4)
24 var i: i64 = 0
25 while i < seed_len { buf[i] = seed[i]; i = i + 1 }
26 let dig: *u8 = sys_mmap(32)
27 var ctr: i64 = 0
28 var out: i64 = 0
29 while out < mask_len {
30 buf[seed_len + 0] = ((ctr >> 24) & 0xff) as u8
31 buf[seed_len + 1] = ((ctr >> 16) & 0xff) as u8
32 buf[seed_len + 2] = ((ctr >> 8) & 0xff) as u8
33 buf[seed_len + 3] = ( ctr & 0xff) as u8
34 sha256_digest(buf, seed_len + 4, dig)
35 var j: i64 = 0
36 while j < 32 { if out + j < mask_len { mask[out + j] = dig[j] } j = j + 1 }
37 out = out + 32
38 ctr = ctr + 1
39 }
40 return 0
41}
42
43// Verify an RSASSA-PSS/SHA-256 signature. msg/msg_len = the signed content; sig_bytes = 256-byte BE signature;
44// n_2048 = 64-limb LE modulus; e_i64 = public exponent. NX_RSA_PSS_OK iff valid (fail-closed otherwise).
45// Params fixed for rsa_pss_rsae_sha256 over RSA-2048: emLen=256, hLen=32, sLen=32, emBits=2047 (1 masked bit).
46func rsa_pss_sha256_verify(msg: *u8, msg_len: i64, sig_bytes: *u8, n_2048: *i64, e_i64: i64) -> i64 {
47 let hLen: i64 = 32
48 let sLen: i64 = 32
49 let emLen: i64 = 256
50 // Step 1: EM = sig^e mod n (256 BE bytes)
51 let s_int: *i64 = u2048_alloc()
52 u2048_load_be(s_int, sig_bytes)
53 let m_int: *i64 = u2048_alloc()
54 let rc: i64 = rsa2048_mod_exp_mont(m_int, s_int, e_i64, n_2048)
55 if rc != NX_RSA2048_MONT_OK { return NX_RSA_PSS_S_OUT_OF_RANGE }
56 let em: *u8 = sys_mmap(256)
57 u2048_store_be(em, m_int)
58
59 // Step 2: mHash = SHA256(msg)
60 let mHash: *u8 = sys_mmap(32)
61 sha256_digest(msg, msg_len, mHash)
62
63 // Step 3: length sanity (emLen >= hLen+sLen+2)
64 if emLen < hLen + sLen + 2 { return NX_RSA_PSS_BAD_PAD }
65 // Step 4: rightmost byte must be 0xbc
66 if (em[emLen - 1] & 0xff) != 0xbc { return NX_RSA_PSS_BAD_PAD }
67 // Step 5: split maskedDB = em[0..dbLen), H = em[dbLen..dbLen+hLen)
68 let dbLen: i64 = emLen - hLen - 1 // 223
69 let hpos: i64 = dbLen // 223
70 // Step 6: the leftmost (8*emLen - emBits) = 1 bit of maskedDB[0] must be 0
71 if (em[0] & 0x80) != 0 { return NX_RSA_PSS_BAD_PAD }
72 // Step 7: dbMask = MGF1(H, dbLen); Step 8: DB = maskedDB XOR dbMask
73 let dbMask: *u8 = sys_mmap(dbLen + 32)
74 mgf1_sha256((em as i64 + hpos) as *u8, hLen, dbMask, dbLen)
75 let db: *u8 = sys_mmap(dbLen + 8)
76 var i: i64 = 0
77 while i < dbLen { db[i] = ((em[i] as i64) ^ (dbMask[i] as i64)) as u8; i = i + 1 }
78 // Step 9: clear the leftmost bit of DB
79 db[0] = (db[0] & 0x7f) as u8
80 // Step 10: DB must be PS(0x00 * (emLen-hLen-sLen-2)) || 0x01 || salt(sLen)
81 let psLen: i64 = emLen - hLen - sLen - 2 // 190
82 i = 0
83 while i < psLen { if (db[i] & 0xff) != 0x00 { return NX_RSA_PSS_BAD_PAD } i = i + 1 }
84 if (db[psLen] & 0xff) != 0x01 { return NX_RSA_PSS_BAD_PAD }
85 // salt = db[psLen+1 .. psLen+1+sLen)
86 let salt_off: i64 = psLen + 1
87 // Step 11: M' = (0x00 * 8) || mHash || salt ; Step 12: H' = SHA256(M')
88 let mp: *u8 = sys_mmap(8 + hLen + sLen)
89 i = 0; while i < 8 { mp[i] = 0 as u8; i = i + 1 }
90 i = 0; while i < hLen { mp[8 + i] = mHash[i]; i = i + 1 }
91 i = 0; while i < sLen { mp[8 + hLen + i] = db[salt_off + i]; i = i + 1 }
92 let Hp: *u8 = sys_mmap(32)
93 sha256_digest(mp, 8 + hLen + sLen, Hp)
94 // Step 13: H == H' ?
95 i = 0
96 while i < hLen { if (em[hpos + i] & 0xff) != (Hp[i] & 0xff) { return NX_RSA_PSS_HASH_MISMATCH } i = i + 1 }
97 return NX_RSA_PSS_OK
98}