code wiki / (root) / nx_rsa_pss_sha256.nx

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}