nx_rsa_pkcs1_v1_5_k.nx source
↩ module page · 125 lines · 5123 B
1// nx_rsa_pkcs1_v1_5_k.nx -- k-aware RSA-PKCS#1 v1.5 verify for RSA moduli
2// whose byte-length k is NOT exactly 256 or 512 (e.g. RSA-3072 = 384 bytes,
3// common on Sectigo/USERTrust intermediates like iana.org's chain).
4//
5// Mechanism: load the (zero-extended) k-byte signature into a u4096 and
6// mod-exp under the (zero-extended) modulus. The recovered EM value is
7// < n < 2^(8k), so its big-endian 512-byte form has the high (512-k) bytes
8// = 0x00 and the real k-byte PKCS#1 EM (00 01 PS 00 T H) in the LOW k bytes,
9// i.e. starting at offset zoff = 512-k. We verify the high zero-extension
10// AND the EM structure at zoff with PS_LEN = k-3-19-hashlen.
11//
12// For k=512 this reduces to the existing RSA-4096 check (zoff=0); we only
13// route here for k not in {256,512} so the proven 2048/4096 paths are
14// untouched. Verdicts reuse the SHA-384 module's enum (same shape).
15//
16// license_tier: INDEPENDENT_REDERIVE
17// genealogy_id: international-research-sources/ietf/rfc_8017
18// lineage_id: nishi_rsa_pkcs1_v1_5_k_q1
19
20import "nx_syscalls.nx"
21import "nx_sha256.nx"
22import "nx_sha512.nx"
23import "nx_u4096.nx"
24import "nx_rsa4096_mod_exp.nx"
25import "nx_rsa_pkcs1_v1_5_sha256.nx" // rsa_pkcs1_sha256_di_byte
26import "nx_rsa_pkcs1_v1_5_sha384.nx" // rsa_pkcs1_sha384_di_byte + NX_RSA_PKCS1_V15_384_*
27
28// Recover EM (512-byte BE) from a k-byte signature via the u4096 path.
29// Writes 512 bytes to em_out; returns OK or S_OUT_OF_RANGE.
30func _rsa_k_recover(sig_bytes: *u8, sig_len: i64, n_4096: *i64, e_i64: i64, em_out: *u8) -> i64 {
31 let sig512: *u8 = sys_mmap(512)
32 var i: i64 = 0
33 while i < 512 { sig512[i] = 0 as u8; i = i + 1 }
34 let off: i64 = 512 - sig_len
35 i = 0
36 while i < sig_len { sig512[off + i] = sig_bytes[i]; i = i + 1 }
37 let s_int: *i64 = u4096_alloc()
38 u4096_load_be(s_int, sig512)
39 let m_int: *i64 = u4096_alloc()
40 let rc: i64 = rsa4096_mod_exp(m_int, s_int, e_i64, n_4096)
41 if rc != NX_RSA4096_MOD_EXP_OK { return NX_RSA_PKCS1_V15_384_S_OUT_OF_RANGE }
42 u4096_store_be(em_out, m_int)
43 return NX_RSA_PKCS1_V15_384_OK
44}
45
46// Verify the leading zero-extension + PKCS#1 EM prefix (00 01 FF.. 00) at
47// offset zoff. Returns OK or BAD_PAD; leaves DigestInfo+hash to the caller.
48func _rsa_k_check_prefix(em: *u8, zoff: i64, ps_len: i64) -> i64 {
49 var i: i64 = 0
50 while i < zoff {
51 if (em[i] & 0xff) != 0x00 { return NX_RSA_PKCS1_V15_384_BAD_PAD }
52 i = i + 1
53 }
54 if (em[zoff] & 0xff) != 0x00 { return NX_RSA_PKCS1_V15_384_BAD_PAD }
55 if (em[zoff + 1] & 0xff) != 0x01 { return NX_RSA_PKCS1_V15_384_BAD_PAD }
56 i = 0
57 while i < ps_len {
58 if (em[zoff + 2 + i] & 0xff) != 0xff { return NX_RSA_PKCS1_V15_384_BAD_PAD }
59 i = i + 1
60 }
61 if (em[zoff + 2 + ps_len] & 0xff) != 0x00 { return NX_RSA_PKCS1_V15_384_BAD_PAD }
62 return NX_RSA_PKCS1_V15_384_OK
63}
64
65// k-aware RSA-PKCS#1 v1.5 + SHA-256 (sig_len = issuer modulus bytes, e.g. 384).
66func rsa_pkcs1_v1_5_sha256_k_verify(msg: *u8, msg_len: i64,
67 sig_bytes: *u8, sig_len: i64,
68 n_4096: *i64, e_i64: i64) -> i64 {
69 let em: *u8 = sys_mmap(512)
70 let rc: i64 = _rsa_k_recover(sig_bytes, sig_len, n_4096, e_i64, em)
71 if rc != NX_RSA_PKCS1_V15_384_OK { return rc }
72 let h: *u8 = sys_mmap(32)
73 sha256_digest(msg, msg_len, h)
74 let k: i64 = sig_len
75 let zoff: i64 = 512 - k
76 let ps_len: i64 = k - 3 - 19 - 32
77 let pc: i64 = _rsa_k_check_prefix(em, zoff, ps_len)
78 if pc != NX_RSA_PKCS1_V15_384_OK { return pc }
79 let di_off: i64 = zoff + 2 + ps_len + 1
80 var i: i64 = 0
81 while i < 19 {
82 if (em[di_off + i] & 0xff) != (rsa_pkcs1_sha256_di_byte(i) & 0xff) { return NX_RSA_PKCS1_V15_384_BAD_PAD }
83 i = i + 1
84 }
85 let h_off: i64 = di_off + 19
86 i = 0
87 while i < 32 {
88 if (em[h_off + i] & 0xff) != (h[i] & 0xff) { return NX_RSA_PKCS1_V15_384_HASH_MISMATCH }
89 i = i + 1
90 }
91 return NX_RSA_PKCS1_V15_384_OK
92}
93
94// k-aware RSA-PKCS#1 v1.5 + SHA-384.
95func rsa_pkcs1_v1_5_sha384_k_verify(msg: *u8, msg_len: i64,
96 sig_bytes: *u8, sig_len: i64,
97 n_4096: *i64, e_i64: i64) -> i64 {
98 let em: *u8 = sys_mmap(512)
99 let rc: i64 = _rsa_k_recover(sig_bytes, sig_len, n_4096, e_i64, em)
100 if rc != NX_RSA_PKCS1_V15_384_OK { return rc }
101 let h: *u8 = sys_mmap(48)
102 sha384_digest(msg, msg_len, h)
103 let k: i64 = sig_len
104 let zoff: i64 = 512 - k
105 let ps_len: i64 = k - 3 - 19 - 48
106 let pc: i64 = _rsa_k_check_prefix(em, zoff, ps_len)
107 if pc != NX_RSA_PKCS1_V15_384_OK { return pc }
108 let di_off: i64 = zoff + 2 + ps_len + 1
109 var i: i64 = 0
110 while i < 19 {
111 if (em[di_off + i] & 0xff) != (rsa_pkcs1_sha384_di_byte(i) & 0xff) { return NX_RSA_PKCS1_V15_384_BAD_PAD }
112 i = i + 1
113 }
114 let h_off: i64 = di_off + 19
115 i = 0
116 while i < 48 {
117 if (em[h_off + i] & 0xff) != (h[i] & 0xff) { return NX_RSA_PKCS1_V15_384_HASH_MISMATCH }
118 i = i + 1
119 }
120 return NX_RSA_PKCS1_V15_384_OK
121}
122
123func main() -> i64 {
124 return 0
125}