From d742e3ac6572d2b3de43c474a1fe04a458afb773 Mon Sep 17 00:00:00 2001 From: Brian Smith Date: Wed, 18 Dec 2024 13:34:14 -0800 Subject: [PATCH] Use only non-panicking digest API internally. Expose `digest::try_finish` to the rest of the crate. Use it everywhere digests are computed internally, avoiding `digest::finish` completely, including transitive uses. This requires adding new non-panicking variants of several APIs. For now, make those variants non-public, until tests and documentation are updated. This is a bit too extreme because we know some of these cases will never fail as the input is known to be short. We will need to choose to either just accept this, or introduce another new (internal?) infallible API. --- src/digest.rs | 17 ++++++-- src/ec/curve25519/ed25519.rs | 11 ++++-- src/ec/curve25519/ed25519/signing.rs | 30 +++++++++----- src/ec/curve25519/ed25519/verification.rs | 7 +++- src/ec/suite_b/ecdsa/signing.rs | 25 +++++++----- src/ec/suite_b/ecdsa/verification.rs | 2 +- src/hkdf.rs | 47 ++++++++++++++++++---- src/hmac.rs | 48 +++++++++++++++++------ src/pbkdf2.rs | 42 ++++++++++++++++---- src/rsa/padding.rs | 13 ++++-- src/rsa/padding/pss.rs | 19 +++++---- src/signature.rs | 11 +++--- 12 files changed, 203 insertions(+), 69 deletions(-) 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) } }