/src/spdm-rs/external/ring/src/rsa/padding/pss.rs
Line | Count | Source |
1 | | // Copyright 2015-2016 Brian Smith. |
2 | | // |
3 | | // Permission to use, copy, modify, and/or distribute this software for any |
4 | | // purpose with or without fee is hereby granted, provided that the above |
5 | | // copyright notice and this permission notice appear in all copies. |
6 | | // |
7 | | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
8 | | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
10 | | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | | // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
14 | | |
15 | | use super::{super::PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN, mgf1, Padding, RsaEncoding, Verification}; |
16 | | use crate::{bb, bits, digest, error, rand}; |
17 | | |
18 | | /// RSA PSS padding as described in [RFC 3447 Section 8.1]. |
19 | | /// |
20 | | /// See "`RSA_PSS_*` Details\" in `ring::signature`'s module-level |
21 | | /// documentation for more details. |
22 | | /// |
23 | | /// [RFC 3447 Section 8.1]: https://tools.ietf.org/html/rfc3447#section-8.1 |
24 | | #[allow(clippy::upper_case_acronyms)] // TODO: Until we implement cargo-semver-checks |
25 | | #[derive(Debug)] |
26 | | pub struct PSS { |
27 | | digest_alg: &'static digest::Algorithm, |
28 | | } |
29 | | |
30 | | impl crate::sealed::Sealed for PSS {} |
31 | | |
32 | | impl Padding for PSS { |
33 | 0 | fn digest_alg(&self) -> &'static digest::Algorithm { |
34 | 0 | self.digest_alg |
35 | 0 | } |
36 | | } |
37 | | |
38 | | impl RsaEncoding for PSS { |
39 | | // Implement padding procedure per EMSA-PSS, |
40 | | // https://tools.ietf.org/html/rfc3447#section-9.1. |
41 | 0 | fn encode( |
42 | 0 | &self, |
43 | 0 | m_hash: digest::Digest, |
44 | 0 | m_out: &mut [u8], |
45 | 0 | mod_bits: bits::BitLength, |
46 | 0 | rng: &dyn rand::SecureRandom, |
47 | 0 | ) -> Result<(), error::Unspecified> { |
48 | 0 | let metrics = PSSMetrics::new(self.digest_alg, mod_bits)?; |
49 | | |
50 | | // The `m_out` this function fills is the big-endian-encoded value of `m` |
51 | | // from the specification, padded to `k` bytes, where `k` is the length |
52 | | // in bytes of the public modulus. The spec says "Note that emLen will |
53 | | // be one less than k if modBits - 1 is divisible by 8 and equal to k |
54 | | // otherwise." In other words we might need to prefix `em` with a |
55 | | // leading zero byte to form a correct value of `m`. |
56 | 0 | let em = if metrics.top_byte_mask == 0xff { |
57 | 0 | m_out[0] = 0; |
58 | 0 | &mut m_out[1..] |
59 | | } else { |
60 | 0 | m_out |
61 | | }; |
62 | 0 | assert_eq!(em.len(), metrics.em_len); |
63 | | |
64 | | // Steps 1 and 2 are done by the caller to produce `m_hash`. |
65 | | |
66 | | // Step 3 is done by `PSSMetrics::new()` above. |
67 | | |
68 | 0 | let (db, digest_terminator) = em.split_at_mut(metrics.db_len); |
69 | | |
70 | 0 | let separator_pos = db.len() - 1 - metrics.s_len; |
71 | | |
72 | | // Step 4. |
73 | 0 | let salt: &[u8] = { |
74 | 0 | let salt = &mut db[(separator_pos + 1)..]; |
75 | 0 | rng.fill(salt)?; // salt |
76 | 0 | salt |
77 | | }; |
78 | | |
79 | | // Steps 5 and 6. |
80 | 0 | let h = pss_digest(self.digest_alg, m_hash, salt); |
81 | | |
82 | | // Step 7. |
83 | 0 | db[..separator_pos].fill(0); // ps |
84 | | |
85 | | // Step 8. |
86 | 0 | db[separator_pos] = 0x01; |
87 | | |
88 | | // Steps 9 and 10. |
89 | 0 | mgf1(self.digest_alg, h.as_ref(), db); |
90 | | |
91 | | // Step 11. |
92 | 0 | db[0] &= metrics.top_byte_mask; |
93 | | |
94 | | // Step 12. |
95 | 0 | digest_terminator[..metrics.h_len].copy_from_slice(h.as_ref()); |
96 | 0 | digest_terminator[metrics.h_len] = 0xbc; |
97 | | |
98 | 0 | Ok(()) |
99 | 0 | } |
100 | | } |
101 | | |
102 | | impl Verification for PSS { |
103 | | // RSASSA-PSS-VERIFY from https://tools.ietf.org/html/rfc3447#section-8.1.2 |
104 | | // where steps 1, 2(a), and 2(b) have been done for us. |
105 | 0 | fn verify( |
106 | 0 | &self, |
107 | 0 | m_hash: digest::Digest, |
108 | 0 | m: &mut untrusted::Reader, |
109 | 0 | mod_bits: bits::BitLength, |
110 | 0 | ) -> Result<(), error::Unspecified> { |
111 | 0 | let metrics = PSSMetrics::new(self.digest_alg, mod_bits)?; |
112 | | |
113 | | // RSASSA-PSS-VERIFY Step 2(c). The `m` this function is given is the |
114 | | // big-endian-encoded value of `m` from the specification, padded to |
115 | | // `k` bytes, where `k` is the length in bytes of the public modulus. |
116 | | // The spec. says "Note that emLen will be one less than k if |
117 | | // modBits - 1 is divisible by 8 and equal to k otherwise," where `k` |
118 | | // is the length in octets of the RSA public modulus `n`. In other |
119 | | // words, `em` might have an extra leading zero byte that we need to |
120 | | // strip before we start the PSS decoding steps which is an artifact of |
121 | | // the `Verification` interface. |
122 | 0 | if metrics.top_byte_mask == 0xff { |
123 | 0 | if m.read_byte()? != 0 { |
124 | 0 | return Err(error::Unspecified); |
125 | 0 | } |
126 | 0 | }; |
127 | 0 | let em = m; |
128 | | |
129 | | // The rest of this function is EMSA-PSS-VERIFY from |
130 | | // https://tools.ietf.org/html/rfc3447#section-9.1.2. |
131 | | |
132 | | // Steps 1 and 2 are done by the caller to produce `m_hash`. |
133 | | |
134 | | // Step 3 is done by `PSSMetrics::new()` above. |
135 | | |
136 | | // Step 5, out of order. |
137 | 0 | let masked_db = em.read_bytes(metrics.db_len)?; |
138 | 0 | let h_hash = em.read_bytes(metrics.h_len)?; |
139 | | |
140 | | // Step 4. |
141 | 0 | if em.read_byte()? != 0xbc { |
142 | 0 | return Err(error::Unspecified); |
143 | 0 | } |
144 | | |
145 | | // Step 7. |
146 | 0 | let mut db = [0u8; PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN]; |
147 | 0 | let db = &mut db[..metrics.db_len]; |
148 | | |
149 | 0 | mgf1(self.digest_alg, h_hash.as_slice_less_safe(), db); |
150 | | |
151 | 0 | masked_db.read_all(error::Unspecified, |masked_bytes| { |
152 | | // Step 6. Check the top bits of first byte are zero. |
153 | 0 | let b = masked_bytes.read_byte()?; |
154 | 0 | if b & !metrics.top_byte_mask != 0 { |
155 | 0 | return Err(error::Unspecified); |
156 | 0 | } |
157 | 0 | db[0] ^= b; |
158 | | |
159 | | // Step 8. |
160 | 0 | let db_rest = &mut db[1..]; |
161 | 0 | let masked_bytes = masked_bytes.read_bytes(db_rest.len())?; |
162 | 0 | bb::xor_assign_at_start(db_rest, masked_bytes.as_slice_less_safe()); |
163 | 0 | Ok(()) |
164 | 0 | })?; |
165 | | |
166 | | // Step 9. |
167 | 0 | db[0] &= metrics.top_byte_mask; |
168 | | |
169 | | // Step 10. |
170 | 0 | let ps_len = metrics.ps_len; |
171 | 0 | if db[0..ps_len].iter().any(|&db| db != 0) { |
172 | 0 | return Err(error::Unspecified); |
173 | 0 | } |
174 | 0 | if db[metrics.ps_len] != 1 { |
175 | 0 | return Err(error::Unspecified); |
176 | 0 | } |
177 | | |
178 | | // Step 11. |
179 | 0 | let salt = &db[(db.len() - metrics.s_len)..]; |
180 | | |
181 | | // Step 12 and 13. |
182 | 0 | let h_prime = pss_digest(self.digest_alg, m_hash, salt); |
183 | | |
184 | | // Step 14. |
185 | 0 | if h_hash.as_slice_less_safe() != h_prime.as_ref() { |
186 | 0 | return Err(error::Unspecified); |
187 | 0 | } |
188 | | |
189 | 0 | Ok(()) |
190 | 0 | } |
191 | | } |
192 | | |
193 | | struct PSSMetrics { |
194 | | #[cfg_attr(not(feature = "alloc"), allow(dead_code))] |
195 | | em_len: usize, |
196 | | db_len: usize, |
197 | | ps_len: usize, |
198 | | s_len: usize, |
199 | | h_len: usize, |
200 | | top_byte_mask: u8, |
201 | | } |
202 | | |
203 | | impl PSSMetrics { |
204 | 0 | fn new( |
205 | 0 | digest_alg: &'static digest::Algorithm, |
206 | 0 | mod_bits: bits::BitLength, |
207 | 0 | ) -> Result<Self, error::Unspecified> { |
208 | 0 | let em_bits = mod_bits.try_sub_1()?; |
209 | 0 | let em_len = em_bits.as_usize_bytes_rounded_up(); |
210 | 0 | let leading_zero_bits = (8 * em_len) - em_bits.as_bits(); |
211 | 0 | debug_assert!(leading_zero_bits < 8); |
212 | 0 | let top_byte_mask = 0xffu8 >> leading_zero_bits; |
213 | | |
214 | 0 | let h_len = digest_alg.output_len(); |
215 | | |
216 | | // We require the salt length to be equal to the digest length. |
217 | 0 | let s_len = h_len; |
218 | | |
219 | | // Step 3 of both `EMSA-PSS-ENCODE` is `EMSA-PSS-VERIFY` requires that |
220 | | // we reject inputs where "emLen < hLen + sLen + 2". The definition of |
221 | | // `emBits` in RFC 3447 Sections 9.1.1 and 9.1.2 says `emBits` must be |
222 | | // "at least 8hLen + 8sLen + 9". Since 9 bits requires two bytes, these |
223 | | // two conditions are equivalent. 9 bits are required as the 0x01 |
224 | | // before the salt requires 1 bit and the 0xbc after the digest |
225 | | // requires 8 bits. |
226 | 0 | let db_len = em_len.checked_sub(1 + s_len).ok_or(error::Unspecified)?; |
227 | 0 | let ps_len = db_len.checked_sub(h_len + 1).ok_or(error::Unspecified)?; |
228 | | |
229 | 0 | debug_assert!(em_bits.as_bits() >= (8 * h_len) + (8 * s_len) + 9); |
230 | | |
231 | 0 | Ok(Self { |
232 | 0 | em_len, |
233 | 0 | db_len, |
234 | 0 | ps_len, |
235 | 0 | s_len, |
236 | 0 | h_len, |
237 | 0 | top_byte_mask, |
238 | 0 | }) |
239 | 0 | } |
240 | | } |
241 | | |
242 | 0 | fn pss_digest( |
243 | 0 | digest_alg: &'static digest::Algorithm, |
244 | 0 | m_hash: digest::Digest, |
245 | 0 | salt: &[u8], |
246 | 0 | ) -> digest::Digest { |
247 | | // Fixed prefix. |
248 | | const PREFIX_ZEROS: [u8; 8] = [0u8; 8]; |
249 | | |
250 | | // Encoding step 5 and 6, Verification step 12 and 13. |
251 | 0 | let mut ctx = digest::Context::new(digest_alg); |
252 | 0 | ctx.update(&PREFIX_ZEROS); |
253 | 0 | ctx.update(m_hash.as_ref()); |
254 | 0 | ctx.update(salt); |
255 | 0 | ctx.finish() |
256 | 0 | } |
257 | | |
258 | | macro_rules! rsa_pss_padding { |
259 | | ( $vis:vis $PADDING_ALGORITHM:ident, $digest_alg:expr, $doc_str:expr ) => { |
260 | | #[doc=$doc_str] |
261 | | $vis static $PADDING_ALGORITHM: PSS = PSS { |
262 | | digest_alg: $digest_alg, |
263 | | }; |
264 | | }; |
265 | | } |
266 | | |
267 | | rsa_pss_padding!( |
268 | | pub RSA_PSS_SHA256, |
269 | | &digest::SHA256, |
270 | | "RSA PSS padding using SHA-256 for RSA signatures.\n\nSee |
271 | | \"`RSA_PSS_*` Details\" in `ring::signature`'s module-level |
272 | | documentation for more details." |
273 | | ); |
274 | | |
275 | | rsa_pss_padding!( |
276 | | pub RSA_PSS_SHA384, |
277 | | &digest::SHA384, |
278 | | "RSA PSS padding using SHA-384 for RSA signatures.\n\nSee |
279 | | \"`RSA_PSS_*` Details\" in `ring::signature`'s module-level |
280 | | documentation for more details." |
281 | | ); |
282 | | |
283 | | rsa_pss_padding!( |
284 | | pub RSA_PSS_SHA512, |
285 | | &digest::SHA512, |
286 | | "RSA PSS padding using SHA-512 for RSA signatures.\n\nSee |
287 | | \"`RSA_PSS_*` Details\" in `ring::signature`'s module-level |
288 | | documentation for more details." |
289 | | ); |