diff --git a/src/digest.rs b/src/digest.rs index 39427262ac..23145ebdc1 100644 --- a/src/digest.rs +++ b/src/digest.rs @@ -298,9 +298,10 @@ impl Context { /// # } /// ``` pub fn digest(algorithm: &'static Algorithm, data: &[u8]) -> Digest { - let mut ctx = Context::new(algorithm); - ctx.update(data); - ctx.finish() + let cpu = cpu::features(); + Digest::compute_from(algorithm, data, cpu) + .map_err(error::Unspecified::from) + .unwrap() } /// A calculated digest value. @@ -313,6 +314,16 @@ pub struct Digest { } impl Digest { + pub(crate) fn compute_from( + algorithm: &'static Algorithm, + data: &[u8], + cpu: cpu::Features, + ) -> Result { + let mut ctx = Context::new(algorithm); + ctx.update(data); + ctx.try_finish(cpu) + } + /// The algorithm that was used to calculate the digest value. #[inline(always)] pub fn algorithm(&self) -> &'static Algorithm { diff --git a/src/ec/curve25519/ed25519.rs b/src/ec/curve25519/ed25519.rs index b29bb55210..3f2b31f806 100644 --- a/src/ec/curve25519/ed25519.rs +++ b/src/ec/curve25519/ed25519.rs @@ -15,7 +15,7 @@ //! EdDSA Signatures. use super::ops::ELEM_LEN; -use crate::digest; +use crate::{cpu, digest}; pub mod signing; pub mod verification; @@ -23,10 +23,15 @@ pub mod verification; /// The length of an Ed25519 public key. pub const ED25519_PUBLIC_KEY_LEN: usize = ELEM_LEN; -pub fn eddsa_digest(signature_r: &[u8], public_key: &[u8], msg: &[u8]) -> digest::Digest { +fn eddsa_digest( + signature_r: &[u8], + public_key: &[u8], + msg: &[u8], + cpu: cpu::Features, +) -> Result { let mut ctx = digest::Context::new(&digest::SHA512); ctx.update(signature_r); ctx.update(public_key); ctx.update(msg); - ctx.finish() + ctx.try_finish(cpu) } diff --git a/src/ec/curve25519/ed25519/signing.rs b/src/ec/curve25519/ed25519/signing.rs index d33b29b081..6b758ebc09 100644 --- a/src/ec/curve25519/ed25519/signing.rs +++ b/src/ec/curve25519/ed25519/signing.rs @@ -51,7 +51,7 @@ impl Ed25519KeyPair { ) -> Result { let cpu_features = cpu::features(); let seed: [u8; SEED_LEN] = rand::generate(rng)?.expose(); - let key_pair = Self::from_seed_(&seed, cpu_features); + let key_pair = Self::from_seed_(&seed, cpu_features)?; Ok(pkcs8::wrap_key( &PKCS8_TEMPLATE, &seed[..], @@ -167,11 +167,12 @@ impl Ed25519KeyPair { let seed = seed .try_into() .map_err(|_| error::KeyRejected::invalid_encoding())?; - Ok(Self::from_seed_(seed, cpu::features())) + Self::from_seed_(seed, cpu::features()) } - fn from_seed_(seed: &Seed, cpu_features: cpu::Features) -> Self { - let h = digest::digest(&digest::SHA512, seed); + fn from_seed_(seed: &Seed, cpu_features: cpu::Features) -> Result { + let h = digest::Digest::compute_from(&digest::SHA512, seed, cpu_features) + .map_err(|_: digest::FinishError| error::KeyRejected::unexpected_error())?; let (private_scalar, private_prefix) = h.as_ref().split_at(SCALAR_LEN); let private_scalar = @@ -179,16 +180,26 @@ impl Ed25519KeyPair { let a = ExtPoint::from_scalarmult_base_consttime(&private_scalar, cpu_features); - Self { + Ok(Self { private_scalar, private_prefix: private_prefix.try_into().unwrap(), public_key: PublicKey(a.into_encoded_point(cpu_features)), - } + }) } /// Returns the signature of the message `msg`. pub fn sign(&self, msg: &[u8]) -> signature::Signature { let cpu_features = cpu::features(); + self.try_sign(msg, cpu_features) + .map_err(error::Unspecified::from) + .unwrap() + } + + fn try_sign( + &self, + msg: &[u8], + cpu_features: cpu::Features, + ) -> Result { signature::Signature::new(|signature_bytes| { prefixed_extern! { fn x25519_sc_muladd( @@ -205,13 +216,14 @@ impl Ed25519KeyPair { let mut ctx = digest::Context::new(&digest::SHA512); ctx.update(&self.private_prefix); ctx.update(msg); - ctx.finish() + ctx.try_finish(cpu_features)? }; let nonce = Scalar::from_sha512_digest_reduced(nonce); let r = ExtPoint::from_scalarmult_base_consttime(&nonce, cpu_features); signature_r.copy_from_slice(&r.into_encoded_point(cpu_features)); - let hram_digest = eddsa_digest(signature_r, self.public_key.as_ref(), msg); + let hram_digest = + eddsa_digest(signature_r, self.public_key.as_ref(), msg, cpu_features)?; let hram = Scalar::from_sha512_digest_reduced(hram_digest); unsafe { x25519_sc_muladd( @@ -222,7 +234,7 @@ impl Ed25519KeyPair { ); } - SIGNATURE_LEN + Ok(SIGNATURE_LEN) }) } } diff --git a/src/ec/curve25519/ed25519/verification.rs b/src/ec/curve25519/ed25519/verification.rs index b6802b8563..d1a175bd1b 100644 --- a/src/ec/curve25519/ed25519/verification.rs +++ b/src/ec/curve25519/ed25519/verification.rs @@ -60,7 +60,12 @@ impl signature::VerificationAlgorithm for EdDSAParameters { let mut a = ExtPoint::from_encoded_point_vartime(public_key)?; a.invert_vartime(); - let h_digest = eddsa_digest(signature_r, public_key, msg.as_slice_less_safe()); + let h_digest = eddsa_digest( + signature_r, + public_key, + msg.as_slice_less_safe(), + cpu_features, + )?; let h = Scalar::from_sha512_digest_reduced(h_digest); let mut r = Point::new_at_infinity(); diff --git a/src/ec/suite_b/ecdsa/signing.rs b/src/ec/suite_b/ecdsa/signing.rs index 0369e2c5b4..f05c960178 100644 --- a/src/ec/suite_b/ecdsa/signing.rs +++ b/src/ec/suite_b/ecdsa/signing.rs @@ -160,7 +160,7 @@ impl EcdsaKeyPair { let d = private_key::private_key_as_scalar(n, &seed); let d = alg.private_scalar_ops.to_mont(&d, cpu); - let nonce_key = NonceRandomKey::new(alg, &seed, rng)?; + let nonce_key = NonceRandomKey::new(alg, &seed, rng, cpu)?; Ok(Self { d, nonce_key, @@ -178,7 +178,7 @@ impl EcdsaKeyPair { let cpu = cpu::features(); // Step 4 (out of order). - let h = digest::digest(self.alg.digest_alg, message); + let h = digest::Digest::compute_from(self.alg.digest_alg, message, cpu)?; // Incorporate `h` into the nonce to hedge against faulty RNGs. (This // is not an approved random number generator that is mandated in @@ -198,10 +198,12 @@ impl EcdsaKeyPair { rng: &dyn rand::SecureRandom, message: &[u8], ) -> Result { + let cpu = cpu::features(); + // Step 4 (out of order). - let h = digest::digest(self.alg.digest_alg, message); + let h = digest::Digest::compute_from(self.alg.digest_alg, message, cpu)?; - self.sign_digest(h, rng, cpu::features()) + self.sign_digest(h, rng, cpu) } /// Returns the signature of message digest `h` using a "random" nonce @@ -278,9 +280,9 @@ impl EcdsaKeyPair { } // Step 7 with encoding. - return Ok(signature::Signature::new(|sig_bytes| { - (self.alg.format_rs)(scalar_ops, &r, &s, sig_bytes) - })); + return signature::Signature::new(|sig_bytes| { + Ok((self.alg.format_rs)(scalar_ops, &r, &s, sig_bytes)) + }); } Err(error::Unspecified) @@ -303,6 +305,8 @@ impl core::fmt::Debug for NonceRandom<'_> { impl rand::sealed::SecureRandom for NonceRandom<'_> { fn fill_impl(&self, dest: &mut [u8]) -> Result<(), error::Unspecified> { + let cpu = cpu::features(); + // Use the same digest algorithm that will be used to digest the // message. The digest algorithm's output is exactly the right size; // this is checked below. @@ -331,7 +335,7 @@ impl rand::sealed::SecureRandom for NonceRandom<'_> { ctx.update(self.message_digest.as_ref()); - let nonce = ctx.finish(); + let nonce = ctx.try_finish(cpu)?; // `copy_from_slice()` panics if the lengths differ, so we don't have // to separately assert that the lengths are the same. @@ -350,6 +354,7 @@ impl NonceRandomKey { alg: &EcdsaSigningAlgorithm, seed: &ec::Seed, rng: &dyn rand::SecureRandom, + cpu: cpu::Features, ) -> Result { let mut rand = [0; digest::MAX_OUTPUT_LEN]; let rand = &mut rand[0..alg.curve.elem_scalar_seed_len]; @@ -363,7 +368,9 @@ impl NonceRandomKey { let mut ctx = digest::Context::new(alg.digest_alg); ctx.update(rand); ctx.update(seed.bytes_less_safe()); - Ok(Self(ctx.finish())) + ctx.try_finish(cpu) + .map(Self) + .map_err(|_: digest::FinishError| error::KeyRejected::unexpected_error()) } } diff --git a/src/ec/suite_b/ecdsa/verification.rs b/src/ec/suite_b/ecdsa/verification.rs index b867a29303..2ee6d9576a 100644 --- a/src/ec/suite_b/ecdsa/verification.rs +++ b/src/ec/suite_b/ecdsa/verification.rs @@ -60,7 +60,7 @@ impl signature::VerificationAlgorithm for EcdsaVerificationAlgorithm { let e = { // NSA Guide Step 2: "Use the selected hash function to compute H = // Hash(M)." - let h = digest::digest(self.digest_alg, msg.as_slice_less_safe()); + let h = digest::Digest::compute_from(self.digest_alg, msg.as_slice_less_safe(), cpu)?; // NSA Guide Step 3: "Convert the bit string H to an integer e as // described in Appendix B.2." diff --git a/src/hkdf.rs b/src/hkdf.rs index 868391b09e..d959ea9d66 100644 --- a/src/hkdf.rs +++ b/src/hkdf.rs @@ -18,7 +18,7 @@ //! //! [RFC 5869]: https://tools.ietf.org/html/rfc5869 -use crate::{error, hmac}; +use crate::{cpu, digest, error, hmac}; /// An HKDF algorithm. #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -62,13 +62,33 @@ impl Salt { /// Constructing a `Salt` is relatively expensive so it is good to reuse a /// `Salt` object instead of re-constructing `Salt`s with the same value. pub fn new(algorithm: Algorithm, value: &[u8]) -> Self { - Self(hmac::Key::new(algorithm.0, value)) + Self::try_new(algorithm, value, cpu::features()) + .map_err(error::Unspecified::from) + .unwrap() + } + + pub(crate) fn try_new( + algorithm: Algorithm, + value: &[u8], + cpu: cpu::Features, + ) -> Result { + hmac::Key::try_new(algorithm.0, value, cpu).map(Self) } /// The [HKDF-Extract] operation. /// /// [HKDF-Extract]: https://tools.ietf.org/html/rfc5869#section-2.2 pub fn extract(&self, secret: &[u8]) -> Prk { + self.try_extract(secret, cpu::features()) + .map_err(error::Unspecified::from) + .unwrap() + } + + pub(crate) fn try_extract( + &self, + secret: &[u8], + cpu: cpu::Features, + ) -> Result { // The spec says that if no salt is provided then a key of // `digest_alg.output_len` bytes of zeros is used. But, HMAC keys are // already zero-padded to the block length, which is larger than the output @@ -76,8 +96,8 @@ impl Salt { // `Key` constructor will automatically do the right thing for a // zero-length string. let salt = &self.0; - let prk = hmac::sign(salt, secret); - Prk(hmac::Key::new(salt.algorithm(), prk.as_ref())) + let prk = hmac::try_sign(salt, secret, cpu)?; + hmac::Key::try_new(salt.algorithm(), prk.as_ref(), cpu).map(Prk) } /// The algorithm used to derive this salt. @@ -115,7 +135,18 @@ impl Prk { /// intentionally wants to leak the PRK secret, e.g. to implement /// `SSLKEYLOGFILE` functionality. pub fn new_less_safe(algorithm: Algorithm, value: &[u8]) -> Self { - Self(hmac::Key::new(algorithm.hmac_algorithm(), value)) + let cpu = cpu::features(); + Self::try_new_less_safe(algorithm, value, cpu) + .map_err(error::Unspecified::from) + .unwrap() + } + + pub(crate) fn try_new_less_safe( + algorithm: Algorithm, + value: &[u8], + cpu: cpu::Features, + ) -> Result { + hmac::Key::try_new(algorithm.hmac_algorithm(), value, cpu).map(Self) } /// The [HKDF-Expand] operation. @@ -181,7 +212,8 @@ impl Okm<'_, L> { /// constructed.) #[inline] pub fn fill(self, out: &mut [u8]) -> Result<(), error::Unspecified> { - fill_okm(self.prk, self.info, out, self.len_cached) + let cpu = cpu::features(); + fill_okm(self.prk, self.info, out, self.len_cached, cpu) } } @@ -190,6 +222,7 @@ fn fill_okm( info: &[&[u8]], out: &mut [u8], len: usize, + cpu: cpu::Features, ) -> Result<(), error::Unspecified> { if out.len() != len { return Err(error::Unspecified); @@ -208,7 +241,7 @@ fn fill_okm( } ctx.update(&[n]); - let t = ctx.sign(); + let t = ctx.try_sign(cpu)?; let t = t.as_ref(); // Append `t` to the output. diff --git a/src/hmac.rs b/src/hmac.rs index a62dbd731a..5178dca5b0 100644 --- a/src/hmac.rs +++ b/src/hmac.rs @@ -175,17 +175,21 @@ impl Key { algorithm: Algorithm, rng: &dyn rand::SecureRandom, ) -> Result { - Self::construct(algorithm, |buf| rng.fill(buf)) + Self::construct(algorithm, |buf| rng.fill(buf), cpu::features()) } - fn construct(algorithm: Algorithm, fill: F) -> Result + fn construct( + algorithm: Algorithm, + fill: F, + cpu: cpu::Features, + ) -> Result where F: FnOnce(&mut [u8]) -> Result<(), error::Unspecified>, { let mut key_bytes = [0; digest::MAX_OUTPUT_LEN]; let key_bytes = &mut key_bytes[..algorithm.0.output_len()]; fill(key_bytes)?; - Ok(Self::new(algorithm, key_bytes)) + Self::try_new(algorithm, key_bytes, cpu).map_err(error::Unspecified::from) } /// Construct an HMAC signing key using the given digest algorithm and key @@ -208,8 +212,16 @@ impl Key { /// `digest_alg.output_len * 8` bits. Support for such keys is likely to be /// removed in a future version of *ring*. pub fn new(algorithm: Algorithm, key_value: &[u8]) -> Self { - let cpu_features = cpu::features(); + Self::try_new(algorithm, key_value, cpu::features()) + .map_err(error::Unspecified::from) + .unwrap() + } + pub(crate) fn try_new( + algorithm: Algorithm, + key_value: &[u8], + cpu_features: cpu::Features, + ) -> Result { let digest_alg = algorithm.0; let mut key = Self { inner: digest::BlockContext::new(digest_alg), @@ -222,7 +234,7 @@ impl Key { let key_value = if key_value.len() <= block_len { key_value } else { - key_hash = digest::digest(digest_alg, key_value); + key_hash = digest::Digest::compute_from(digest_alg, key_value, cpu_features)?; key_hash.as_ref() }; @@ -249,7 +261,7 @@ impl Key { let leftover = key.outer.update(padded_key, cpu_features); debug_assert_eq!(leftover.len(), 0); - key + Ok(key) } /// The digest algorithm for the key. @@ -267,7 +279,7 @@ impl hkdf::KeyType for Algorithm { impl From> for Key { fn from(okm: hkdf::Okm) -> Self { - Self::construct(*okm.len(), |buf| okm.fill(buf)).unwrap() + Self::construct(*okm.len(), |buf| okm.fill(buf), cpu::features()).unwrap() } } @@ -312,11 +324,12 @@ impl Context { /// the return value of `sign` to a tag. Use `verify` for verification /// instead. pub fn sign(self) -> Tag { - self.try_sign().map_err(error::Unspecified::from).unwrap() + self.try_sign(cpu::features()) + .map_err(error::Unspecified::from) + .unwrap() } - fn try_sign(self) -> Result { - let cpu_features = cpu::features(); + pub(crate) fn try_sign(self, cpu_features: cpu::Features) -> Result { let inner = self.inner.try_finish(cpu_features)?; let inner = inner.as_ref(); let num_pending = inner.len(); @@ -337,9 +350,19 @@ impl Context { /// It is generally not safe to implement HMAC verification by comparing the /// return value of `sign` to a tag. Use `verify` for verification instead. pub fn sign(key: &Key, data: &[u8]) -> Tag { + try_sign(key, data, cpu::features()) + .map_err(error::Unspecified::from) + .unwrap() +} + +pub(crate) fn try_sign( + key: &Key, + data: &[u8], + cpu: cpu::Features, +) -> Result { let mut ctx = Context::with_key(key); ctx.update(data); - ctx.sign() + ctx.try_sign(cpu) } /// Calculates the HMAC of `data` using the signing key `key`, and verifies @@ -350,7 +373,8 @@ pub fn sign(key: &Key, data: &[u8]) -> Tag { /// /// The verification will be done in constant time to prevent timing attacks. pub fn verify(key: &Key, data: &[u8], tag: &[u8]) -> Result<(), error::Unspecified> { - constant_time::verify_slices_are_equal(sign(key, data).as_ref(), tag) + let cpu = cpu::features(); + constant_time::verify_slices_are_equal(try_sign(key, data, cpu)?.as_ref(), tag) } #[cfg(test)] diff --git a/src/pbkdf2.rs b/src/pbkdf2.rs index 5a25f5d7f6..8095037a1e 100644 --- a/src/pbkdf2.rs +++ b/src/pbkdf2.rs @@ -112,7 +112,7 @@ //! assert!(db.verify_password("alice", "@74d7]404j|W}6u").is_ok()); //! } -use crate::{constant_time, digest, error, hmac}; +use crate::{constant_time, cpu, digest, error, hmac}; use core::num::NonZeroU32; /// A PBKDF2 algorithm. @@ -159,6 +159,19 @@ pub fn derive( secret: &[u8], out: &mut [u8], ) { + try_derive(algorithm, iterations, salt, secret, out, cpu::features()) + .map_err(error::Unspecified::from) + .unwrap() +} + +fn try_derive( + algorithm: Algorithm, + iterations: NonZeroU32, + salt: &[u8], + secret: &[u8], + out: &mut [u8], + cpu: cpu::Features, +) -> Result<(), digest::FinishError> { let digest_alg = algorithm.0.digest_algorithm(); let output_len = digest_alg.output_len(); @@ -167,7 +180,7 @@ pub fn derive( // hasn't been optimized to the same extent as fastpbkdf2. In particular, // this implementation is probably doing a lot of unnecessary copying. - let secret = hmac::Key::new(algorithm.0, secret); + let secret = hmac::Key::try_new(algorithm.0, secret, cpu)?; // Clear |out|. out.fill(0); @@ -176,16 +189,25 @@ pub fn derive( for chunk in out.chunks_mut(output_len) { idx = idx.checked_add(1).expect("derived key too long"); - derive_block(&secret, iterations, salt, idx, chunk); + derive_block(&secret, iterations, salt, idx, chunk, cpu)?; } + + Ok(()) } -fn derive_block(secret: &hmac::Key, iterations: NonZeroU32, salt: &[u8], idx: u32, out: &mut [u8]) { +fn derive_block( + secret: &hmac::Key, + iterations: NonZeroU32, + salt: &[u8], + idx: u32, + out: &mut [u8], + cpu: cpu::Features, +) -> Result<(), digest::FinishError> { let mut ctx = hmac::Context::with_key(secret); ctx.update(salt); ctx.update(&u32::to_be_bytes(idx)); - let mut u = ctx.sign(); + let mut u = ctx.try_sign(cpu)?; let mut remaining: u32 = iterations.into(); loop { @@ -196,8 +218,10 @@ fn derive_block(secret: &hmac::Key, iterations: NonZeroU32, salt: &[u8], idx: u3 } remaining -= 1; - u = hmac::sign(secret, u.as_ref()); + u = hmac::try_sign(secret, u.as_ref(), cpu)?; } + + Ok(()) } /// Verifies that a previously-derived (e.g., using `derive`) PBKDF2 value @@ -227,6 +251,8 @@ pub fn verify( secret: &[u8], previously_derived: &[u8], ) -> Result<(), error::Unspecified> { + let cpu = cpu::features(); + let digest_alg = algorithm.0.digest_algorithm(); if previously_derived.is_empty() { @@ -236,7 +262,7 @@ pub fn verify( let mut derived_buf = [0u8; digest::MAX_OUTPUT_LEN]; let output_len = digest_alg.output_len(); - let secret = hmac::Key::new(algorithm.0, secret); + let secret = hmac::Key::try_new(algorithm.0, secret, cpu)?; let mut idx: u32 = 0; let mut matches = 1; @@ -247,7 +273,7 @@ pub fn verify( let derived_chunk = &mut derived_buf[..previously_derived_chunk.len()]; derived_chunk.fill(0); - derive_block(&secret, iterations, salt, idx, derived_chunk); + derive_block(&secret, iterations, salt, idx, derived_chunk, cpu)?; // XXX: This isn't fully constant-time-safe. TODO: Fix that. #[allow(clippy::bool_to_int_with_if)] diff --git a/src/rsa/padding.rs b/src/rsa/padding.rs index 2fe7dda575..90b3307e93 100644 --- a/src/rsa/padding.rs +++ b/src/rsa/padding.rs @@ -12,7 +12,7 @@ // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -use crate::{bits, constant_time, digest, error, rand}; +use crate::{bits, constant_time, cpu, digest, error, rand}; mod pkcs1; mod pss; @@ -60,7 +60,12 @@ pub trait Verification: Padding { // Masks `out` with the output of the mask-generating function MGF1 as // described in https://tools.ietf.org/html/rfc3447#appendix-B.2.1. -fn mgf1(digest_alg: &'static digest::Algorithm, seed: &[u8], out: &mut [u8]) { +fn mgf1( + digest_alg: &'static digest::Algorithm, + seed: &[u8], + out: &mut [u8], + cpu: cpu::Features, +) -> Result<(), digest::FinishError> { let digest_len = digest_alg.output_len(); // Maximum counter value is the value of (mask_len / digest_len) rounded up. @@ -70,12 +75,14 @@ fn mgf1(digest_alg: &'static digest::Algorithm, seed: &[u8], out: &mut [u8]) { // The counter will always fit in a `u32` because we reject absurdly // long inputs very early. ctx.update(&u32::to_be_bytes(i.try_into().unwrap())); - let digest = ctx.finish(); + let digest = ctx.try_finish(cpu)?; // The last chunk may legitimately be shorter than `digest`, but // `digest` will never be shorter than `out`. constant_time::xor_assign_at_start(out, digest.as_ref()); } + + Ok(()) } #[cfg(test)] diff --git a/src/rsa/padding/pss.rs b/src/rsa/padding/pss.rs index 35fc82be7c..8313110fe5 100644 --- a/src/rsa/padding/pss.rs +++ b/src/rsa/padding/pss.rs @@ -13,7 +13,7 @@ // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. use super::{super::PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN, mgf1, Padding, RsaEncoding, Verification}; -use crate::{bits, constant_time, digest, error, rand}; +use crate::{bits, constant_time, cpu, digest, error, rand}; /// RSA PSS padding as described in [RFC 3447 Section 8.1]. /// @@ -45,6 +45,8 @@ impl RsaEncoding for PSS { mod_bits: bits::BitLength, rng: &dyn rand::SecureRandom, ) -> Result<(), error::Unspecified> { + let cpu = cpu::features(); + let metrics = PSSMetrics::new(self.digest_alg, mod_bits)?; // The `m_out` this function fills is the big-endian-encoded value of `m` @@ -77,7 +79,7 @@ impl RsaEncoding for PSS { }; // Steps 5 and 6. - let h = pss_digest(self.digest_alg, m_hash, salt); + let h = pss_digest(self.digest_alg, m_hash, salt, cpu)?; // Step 7. db[..separator_pos].fill(0); // ps @@ -86,7 +88,7 @@ impl RsaEncoding for PSS { db[separator_pos] = 0x01; // Steps 9 and 10. - mgf1(self.digest_alg, h.as_ref(), db); + mgf1(self.digest_alg, h.as_ref(), db, cpu)?; // Step 11. db[0] &= metrics.top_byte_mask; @@ -108,6 +110,8 @@ impl Verification for PSS { m: &mut untrusted::Reader, mod_bits: bits::BitLength, ) -> Result<(), error::Unspecified> { + let cpu = cpu::features(); + let metrics = PSSMetrics::new(self.digest_alg, mod_bits)?; // RSASSA-PSS-VERIFY Step 2(c). The `m` this function is given is the @@ -146,7 +150,7 @@ impl Verification for PSS { let mut db = [0u8; PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN]; let db = &mut db[..metrics.db_len]; - mgf1(self.digest_alg, h_hash.as_slice_less_safe(), db); + mgf1(self.digest_alg, h_hash.as_slice_less_safe(), db, cpu)?; masked_db.read_all(error::Unspecified, |masked_bytes| { // Step 6. Check the top bits of first byte are zero. @@ -179,7 +183,7 @@ impl Verification for PSS { let salt = &db[(db.len() - metrics.s_len)..]; // Step 12 and 13. - let h_prime = pss_digest(self.digest_alg, m_hash, salt); + let h_prime = pss_digest(self.digest_alg, m_hash, salt, cpu)?; // Step 14. if h_hash.as_slice_less_safe() != h_prime.as_ref() { @@ -243,7 +247,8 @@ fn pss_digest( digest_alg: &'static digest::Algorithm, m_hash: digest::Digest, salt: &[u8], -) -> digest::Digest { + cpu: cpu::Features, +) -> Result { // Fixed prefix. const PREFIX_ZEROS: [u8; 8] = [0u8; 8]; @@ -252,7 +257,7 @@ fn pss_digest( ctx.update(&PREFIX_ZEROS); ctx.update(m_hash.as_ref()); ctx.update(salt); - ctx.finish() + ctx.try_finish(cpu) } macro_rules! rsa_pss_padding { diff --git a/src/signature.rs b/src/signature.rs index b1f910e03f..6d994ce225 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -307,16 +307,15 @@ pub struct Signature { impl Signature { // Panics if `value` is too long. - pub(crate) fn new(fill: F) -> Self - where - F: FnOnce(&mut [u8; MAX_LEN]) -> usize, - { + pub(crate) fn new( + fill: impl FnOnce(&mut [u8; MAX_LEN]) -> Result, + ) -> Result { let mut r = Self { value: [0; MAX_LEN], len: 0, }; - r.len = fill(&mut r.value); - r + r.len = fill(&mut r.value)?; + Ok(r) } }