Reformat src/rsa.
This commit is contained in:
parent
0a9cd4dcd2
commit
730a46f665
@ -40,11 +40,13 @@
|
||||
|
||||
#![allow(box_pointers)]
|
||||
|
||||
use crate::{bits, bssl, c, error, limb, untrusted};
|
||||
use arithmetic::montgomery::*;
|
||||
use core;
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::{
|
||||
self,
|
||||
marker::PhantomData,
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
use crate::{bits, bssl, c, error, limb, untrusted};
|
||||
use std;
|
||||
|
||||
#[cfg(any(test, feature = "rsa_signing"))]
|
||||
@ -70,16 +72,12 @@ struct BoxedLimbs<M> {
|
||||
impl<M> Deref for BoxedLimbs<M> {
|
||||
type Target = [limb::Limb];
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.limbs
|
||||
}
|
||||
fn deref(&self) -> &Self::Target { &self.limbs }
|
||||
}
|
||||
|
||||
impl<M> DerefMut for BoxedLimbs<M> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.limbs
|
||||
}
|
||||
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.limbs }
|
||||
}
|
||||
|
||||
// TODO: `derive(Clone)` after https://github.com/rust-lang/rust/issues/26925
|
||||
@ -94,15 +92,19 @@ impl<M> Clone for BoxedLimbs<M> {
|
||||
}
|
||||
|
||||
impl<M> BoxedLimbs<M> {
|
||||
fn positive_minimal_width_from_be_bytes(input: untrusted::Input)
|
||||
-> Result<Self, error::Unspecified> {
|
||||
fn positive_minimal_width_from_be_bytes(
|
||||
input: untrusted::Input,
|
||||
) -> Result<Self, error::Unspecified> {
|
||||
// Reject leading zeros. Also reject the value zero ([0]) because zero
|
||||
// isn't positive.
|
||||
if untrusted::Reader::new(input).peek(0) {
|
||||
return Err(error::Unspecified);
|
||||
}
|
||||
let num_limbs = (input.len() + limb::LIMB_BYTES - 1) / limb::LIMB_BYTES;
|
||||
let mut r = Self::zero(Width { num_limbs, m: PhantomData });
|
||||
let mut r = Self::zero(Width {
|
||||
num_limbs,
|
||||
m: PhantomData,
|
||||
});
|
||||
limb::parse_big_endian_and_pad_consttime(input, &mut r)?;
|
||||
Ok(r)
|
||||
}
|
||||
@ -117,12 +119,12 @@ impl<M> BoxedLimbs<M> {
|
||||
}
|
||||
}
|
||||
|
||||
fn from_be_bytes_padded_less_than(input: untrusted::Input, m: &Modulus<M>)
|
||||
-> Result<Self, error::Unspecified> {
|
||||
fn from_be_bytes_padded_less_than(
|
||||
input: untrusted::Input, m: &Modulus<M>,
|
||||
) -> Result<Self, error::Unspecified> {
|
||||
let mut r = Self::zero(m.width());
|
||||
limb::parse_big_endian_and_pad_consttime(input, &mut r)?;
|
||||
if limb::limbs_less_than_limbs_consttime(&r, &m.limbs) !=
|
||||
limb::LimbMask::True {
|
||||
if limb::limbs_less_than_limbs_consttime(&r, &m.limbs) != limb::LimbMask::True {
|
||||
return Err(error::Unspecified);
|
||||
}
|
||||
Ok(r)
|
||||
@ -213,8 +215,7 @@ pub struct Modulus<M> {
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for Modulus<super::N> {
|
||||
fn fmt(&self, fmt: &mut ::core::fmt::Formatter)
|
||||
-> Result<(), ::core::fmt::Error> {
|
||||
fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> Result<(), ::core::fmt::Error> {
|
||||
fmt.debug_struct("Modulus")
|
||||
// TODO: Print modulus value.
|
||||
.finish()
|
||||
@ -222,9 +223,9 @@ impl core::fmt::Debug for Modulus<super::N> {
|
||||
}
|
||||
|
||||
impl<M> Modulus<M> {
|
||||
pub fn from_be_bytes_with_bit_length(input: untrusted::Input)
|
||||
-> Result<(Self, bits::BitLength), error::Unspecified>
|
||||
{
|
||||
pub fn from_be_bytes_with_bit_length(
|
||||
input: untrusted::Input,
|
||||
) -> Result<(Self, bits::BitLength), error::Unspecified> {
|
||||
let limbs = BoxedLimbs::positive_minimal_width_from_be_bytes(input)?;
|
||||
let bits = minimal_limbs_bit_length(&limbs);
|
||||
Ok((Self::from_boxed_limbs(limbs)?, bits))
|
||||
@ -243,11 +244,9 @@ impl<M> Modulus<M> {
|
||||
if n.len() > MODULUS_MAX_LIMBS {
|
||||
return Err(error::Unspecified);
|
||||
}
|
||||
Result::from(unsafe {
|
||||
GFp_bn_mul_mont_check_num_limbs(n.len())
|
||||
})?;
|
||||
Result::from(unsafe { GFp_bn_mul_mont_check_num_limbs(n.len()) })?;
|
||||
if limb::limbs_are_even_constant_time(&n) != limb::LimbMask::False {
|
||||
return Err(error::Unspecified)
|
||||
return Err(error::Unspecified);
|
||||
}
|
||||
if limb::limbs_less_than_limb_constant_time(&n, 3) != limb::LimbMask::False {
|
||||
return Err(error::Unspecified);
|
||||
@ -308,7 +307,8 @@ impl<M> Modulus<M> {
|
||||
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
pub fn to_elem<L>(&self, l: &Modulus<L>) -> Elem<L, Unencoded>
|
||||
where M: SmallerModulus<L>
|
||||
where
|
||||
M: SmallerModulus<L>,
|
||||
{
|
||||
// TODO: Encode this assertion into the `where` above.
|
||||
assert_eq!(self.width().num_limbs, l.width().num_limbs);
|
||||
@ -381,9 +381,7 @@ impl<M, E> Elem<M, E> {
|
||||
}
|
||||
|
||||
impl<M, E: ReductionEncoding> Elem<M, E> {
|
||||
fn decode_once(self, m: &Modulus<M>)
|
||||
-> Elem<M, <E as ReductionEncoding>::Output>
|
||||
{
|
||||
fn decode_once(self, m: &Modulus<M>) -> Elem<M, <E as ReductionEncoding>::Output> {
|
||||
// A multiplication isn't required since we're multiplying by the
|
||||
// unencoded value one (1); only a Montgomery reduction is needed.
|
||||
// However the only non-multiplication Montgomery reduction function we
|
||||
@ -394,8 +392,14 @@ impl<M, E: ReductionEncoding> Elem<M, E> {
|
||||
one[0] = 1;
|
||||
let one = &one[..num_limbs]; // assert!(num_limbs <= MODULUS_MAX_LIMBS);
|
||||
unsafe {
|
||||
GFp_bn_mul_mont(limbs.as_mut_ptr(), limbs.as_ptr(),
|
||||
one.as_ptr(), m.limbs.as_ptr(), &m.n0, num_limbs)
|
||||
GFp_bn_mul_mont(
|
||||
limbs.as_mut_ptr(),
|
||||
limbs.as_ptr(),
|
||||
one.as_ptr(),
|
||||
m.limbs.as_ptr(),
|
||||
&m.n0,
|
||||
num_limbs,
|
||||
)
|
||||
}
|
||||
Elem {
|
||||
limbs,
|
||||
@ -406,14 +410,13 @@ impl<M, E: ReductionEncoding> Elem<M, E> {
|
||||
|
||||
impl<M> Elem<M, R> {
|
||||
#[inline]
|
||||
pub fn into_unencoded(self, m: &Modulus<M>) -> Elem<M, Unencoded> {
|
||||
self.decode_once(m)
|
||||
}
|
||||
pub fn into_unencoded(self, m: &Modulus<M>) -> Elem<M, Unencoded> { self.decode_once(m) }
|
||||
}
|
||||
|
||||
impl<M> Elem<M, Unencoded> {
|
||||
pub fn from_be_bytes_padded(input: untrusted::Input, m: &Modulus<M>)
|
||||
-> Result<Self, error::Unspecified> {
|
||||
pub fn from_be_bytes_padded(
|
||||
input: untrusted::Input, m: &Modulus<M>,
|
||||
) -> Result<Self, error::Unspecified> {
|
||||
Ok(Elem {
|
||||
limbs: BoxedLimbs::from_be_bytes_padded_less_than(input, m)?,
|
||||
encoding: PhantomData,
|
||||
@ -433,25 +436,34 @@ impl<M> Elem<M, Unencoded> {
|
||||
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
fn is_one(&self) -> bool {
|
||||
limb::limbs_equal_limb_constant_time(&self.limbs, 1) ==
|
||||
limb::LimbMask::True
|
||||
limb::limbs_equal_limb_constant_time(&self.limbs, 1) == limb::LimbMask::True
|
||||
}
|
||||
}
|
||||
|
||||
pub fn elem_mul<M, AF, BF>(a: &Elem<M, AF>, b: Elem<M, BF>, m: &Modulus<M>)
|
||||
-> Elem<M, <(AF, BF) as ProductEncoding>::Output>
|
||||
where (AF, BF): ProductEncoding
|
||||
pub fn elem_mul<M, AF, BF>(
|
||||
a: &Elem<M, AF>, b: Elem<M, BF>, m: &Modulus<M>,
|
||||
) -> Elem<M, <(AF, BF) as ProductEncoding>::Output>
|
||||
where
|
||||
(AF, BF): ProductEncoding,
|
||||
{
|
||||
elem_mul_(a, b, &m.as_partial())
|
||||
}
|
||||
|
||||
fn elem_mul_<M, AF, BF>(a: &Elem<M, AF>, mut b: Elem<M, BF>, m: &PartialModulus<M>)
|
||||
-> Elem<M, <(AF, BF) as ProductEncoding>::Output>
|
||||
where (AF, BF): ProductEncoding {
|
||||
fn elem_mul_<M, AF, BF>(
|
||||
a: &Elem<M, AF>, mut b: Elem<M, BF>, m: &PartialModulus<M>,
|
||||
) -> Elem<M, <(AF, BF) as ProductEncoding>::Output>
|
||||
where
|
||||
(AF, BF): ProductEncoding,
|
||||
{
|
||||
unsafe {
|
||||
GFp_bn_mul_mont(b.limbs.as_mut_ptr(), a.limbs.as_ptr(),
|
||||
b.limbs.as_ptr(), m.limbs.as_ptr(), &m.n0,
|
||||
m.limbs.len());
|
||||
GFp_bn_mul_mont(
|
||||
b.limbs.as_mut_ptr(),
|
||||
a.limbs.as_ptr(),
|
||||
b.limbs.as_ptr(),
|
||||
m.limbs.as_ptr(),
|
||||
&m.n0,
|
||||
m.limbs.len(),
|
||||
);
|
||||
}
|
||||
Elem {
|
||||
limbs: b.limbs,
|
||||
@ -461,15 +473,19 @@ fn elem_mul_<M, AF, BF>(a: &Elem<M, AF>, mut b: Elem<M, BF>, m: &PartialModulus<
|
||||
|
||||
fn elem_mul_by_2<M, AF>(a: &mut Elem<M, AF>, m: &PartialModulus<M>) {
|
||||
unsafe {
|
||||
LIMBS_shl_mod(a.limbs.as_mut_ptr(), a.limbs.as_ptr(),
|
||||
m.limbs.as_ptr(), m.limbs.len());
|
||||
LIMBS_shl_mod(
|
||||
a.limbs.as_mut_ptr(),
|
||||
a.limbs.as_ptr(),
|
||||
m.limbs.as_ptr(),
|
||||
m.limbs.len(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
pub fn elem_reduced_once<Larger, Smaller: SlightlySmallerModulus<Larger>>(
|
||||
a: &Elem<Larger, Unencoded>, m: &Modulus<Smaller>)
|
||||
-> Elem<Smaller, Unencoded> {
|
||||
a: &Elem<Larger, Unencoded>, m: &Modulus<Smaller>,
|
||||
) -> Elem<Smaller, Unencoded> {
|
||||
let mut r = a.limbs.clone();
|
||||
assert!(r.len() <= m.limbs.len());
|
||||
limb::limbs_reduce_once_constant_time(&mut r, &m.limbs);
|
||||
@ -485,28 +501,42 @@ pub fn elem_reduced_once<Larger, Smaller: SlightlySmallerModulus<Larger>>(
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
#[inline]
|
||||
pub fn elem_reduced<Larger, Smaller: NotMuchSmallerModulus<Larger>>(
|
||||
a: &Elem<Larger, Unencoded>, m: &Modulus<Smaller>)
|
||||
-> Result<Elem<Smaller, RInverse>, error::Unspecified> {
|
||||
a: &Elem<Larger, Unencoded>, m: &Modulus<Smaller>,
|
||||
) -> Result<Elem<Smaller, RInverse>, error::Unspecified> {
|
||||
let mut tmp = [0; MODULUS_MAX_LIMBS];
|
||||
let tmp = &mut tmp[..a.limbs.len()];
|
||||
tmp.copy_from_slice(&a.limbs);
|
||||
|
||||
let mut r = m.zero();
|
||||
Result::from(unsafe {
|
||||
GFp_bn_from_montgomery_in_place(r.limbs.as_mut_ptr(), r.limbs.len(),
|
||||
tmp.as_mut_ptr(), tmp.len(),
|
||||
m.limbs.as_ptr(), m.limbs.len(), &m.n0)
|
||||
GFp_bn_from_montgomery_in_place(
|
||||
r.limbs.as_mut_ptr(),
|
||||
r.limbs.len(),
|
||||
tmp.as_mut_ptr(),
|
||||
tmp.len(),
|
||||
m.limbs.as_ptr(),
|
||||
m.limbs.len(),
|
||||
&m.n0,
|
||||
)
|
||||
})?;
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
fn elem_squared<M, E>(mut a: Elem<M, E>, m: &PartialModulus<M>)
|
||||
-> Elem<M, <(E, E) as ProductEncoding>::Output>
|
||||
where (E, E): ProductEncoding {
|
||||
fn elem_squared<M, E>(
|
||||
mut a: Elem<M, E>, m: &PartialModulus<M>,
|
||||
) -> Elem<M, <(E, E) as ProductEncoding>::Output>
|
||||
where
|
||||
(E, E): ProductEncoding,
|
||||
{
|
||||
unsafe {
|
||||
GFp_bn_mul_mont(a.limbs.as_mut_ptr(), a.limbs.as_ptr(),
|
||||
a.limbs.as_ptr(), m.limbs.as_ptr(), &m.n0,
|
||||
m.limbs.len());
|
||||
GFp_bn_mul_mont(
|
||||
a.limbs.as_mut_ptr(),
|
||||
a.limbs.as_ptr(),
|
||||
a.limbs.as_ptr(),
|
||||
m.limbs.as_ptr(),
|
||||
&m.n0,
|
||||
m.limbs.len(),
|
||||
);
|
||||
};
|
||||
Elem {
|
||||
limbs: a.limbs,
|
||||
@ -516,40 +546,43 @@ fn elem_squared<M, E>(mut a: Elem<M, E>, m: &PartialModulus<M>)
|
||||
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
pub fn elem_widen<Larger, Smaller: SmallerModulus<Larger>>(
|
||||
a: Elem<Smaller, Unencoded>, m: &Modulus<Larger>)
|
||||
-> Elem<Larger, Unencoded>
|
||||
{
|
||||
a: Elem<Smaller, Unencoded>, m: &Modulus<Larger>,
|
||||
) -> Elem<Larger, Unencoded> {
|
||||
let mut r = m.zero();
|
||||
r.limbs[..a.limbs.len()].copy_from_slice(&a.limbs);
|
||||
r
|
||||
}
|
||||
|
||||
|
||||
// TODO: Document why this works for all Montgomery factors.
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
pub fn elem_add<M, E>(mut a: Elem<M, E>, b: Elem<M, E>, m: &Modulus<M>)
|
||||
-> Elem<M, E>
|
||||
{
|
||||
pub fn elem_add<M, E>(mut a: Elem<M, E>, b: Elem<M, E>, m: &Modulus<M>) -> Elem<M, E> {
|
||||
unsafe {
|
||||
LIMBS_add_mod(a.limbs.as_mut_ptr(), a.limbs.as_ptr(),
|
||||
b.limbs.as_ptr(), m.limbs.as_ptr(), m.limbs.len())
|
||||
LIMBS_add_mod(
|
||||
a.limbs.as_mut_ptr(),
|
||||
a.limbs.as_ptr(),
|
||||
b.limbs.as_ptr(),
|
||||
m.limbs.as_ptr(),
|
||||
m.limbs.len(),
|
||||
)
|
||||
}
|
||||
a
|
||||
}
|
||||
|
||||
// TODO: Document why this works for all Montgomery factors.
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
pub fn elem_sub<M, E>(mut a: Elem<M, E>, b: &Elem<M, E>, m: &Modulus<M>)
|
||||
-> Elem<M, E>
|
||||
{
|
||||
pub fn elem_sub<M, E>(mut a: Elem<M, E>, b: &Elem<M, E>, m: &Modulus<M>) -> Elem<M, E> {
|
||||
unsafe {
|
||||
LIMBS_sub_mod(a.limbs.as_mut_ptr(), a.limbs.as_ptr(), b.limbs.as_ptr(),
|
||||
m.limbs.as_ptr(), m.limbs.len());
|
||||
LIMBS_sub_mod(
|
||||
a.limbs.as_mut_ptr(),
|
||||
a.limbs.as_ptr(),
|
||||
b.limbs.as_ptr(),
|
||||
m.limbs.as_ptr(),
|
||||
m.limbs.len(),
|
||||
);
|
||||
}
|
||||
a
|
||||
}
|
||||
|
||||
|
||||
// The value 1, Montgomery-encoded some number of times.
|
||||
pub struct One<M, E>(Elem<M, E>);
|
||||
|
||||
@ -613,8 +646,9 @@ impl<M, E> AsRef<Elem<M, E>> for One<M, E> {
|
||||
pub struct PublicExponent(u64);
|
||||
|
||||
impl PublicExponent {
|
||||
pub fn from_be_bytes(input: untrusted::Input, min_value: u64)
|
||||
-> Result<Self, error::Unspecified> {
|
||||
pub fn from_be_bytes(
|
||||
input: untrusted::Input, min_value: u64,
|
||||
) -> Result<Self, error::Unspecified> {
|
||||
if input.len() > 5 {
|
||||
return Err(error::Unspecified);
|
||||
}
|
||||
@ -674,16 +708,14 @@ const PUBLIC_EXPONENT_MAX_VALUE: u64 = (1u64 << 33) - 1;
|
||||
// TODO: The test coverage needs to be expanded, e.g. test with the largest
|
||||
// accepted exponent and with the most common values of 65537 and 3.
|
||||
pub fn elem_exp_vartime<M>(
|
||||
base: Elem<M, Unencoded>, PublicExponent(exponent): PublicExponent,
|
||||
m: &Modulus<M>) -> Elem<M, R> {
|
||||
base: Elem<M, Unencoded>, PublicExponent(exponent): PublicExponent, m: &Modulus<M>,
|
||||
) -> Elem<M, R> {
|
||||
let base = elem_mul(m.oneRR().as_ref(), base, &m);
|
||||
elem_exp_vartime_(base, exponent, &m.as_partial())
|
||||
}
|
||||
|
||||
/// Calculates base**exponent (mod m).
|
||||
fn elem_exp_vartime_<M>(
|
||||
base: Elem<M, R>, exponent: u64, m: &PartialModulus<M>) -> Elem<M, R>
|
||||
{
|
||||
fn elem_exp_vartime_<M>(base: Elem<M, R>, exponent: u64, m: &PartialModulus<M>) -> Elem<M, R> {
|
||||
// Use what [Knuth] calls the "S-and-X binary method", i.e. variable-time
|
||||
// square-and-multiply that scans the exponent from the most significant
|
||||
// bit to the least significant bit (left-to-right). Left-to-right requires
|
||||
@ -727,8 +759,9 @@ pub struct PrivateExponent<M> {
|
||||
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
impl<M> PrivateExponent<M> {
|
||||
pub fn from_be_bytes_padded(input: untrusted::Input, p: &Modulus<M>)
|
||||
-> Result<Self, error::Unspecified> {
|
||||
pub fn from_be_bytes_padded(
|
||||
input: untrusted::Input, p: &Modulus<M>,
|
||||
) -> Result<Self, error::Unspecified> {
|
||||
let dP = BoxedLimbs::from_be_bytes_padded_less_than(input, p)?;
|
||||
|
||||
// Proof that `dP < p - 1`:
|
||||
@ -743,9 +776,7 @@ impl<M> PrivateExponent<M> {
|
||||
return Err(error::Unspecified);
|
||||
}
|
||||
|
||||
Ok(PrivateExponent {
|
||||
limbs: dP,
|
||||
})
|
||||
Ok(PrivateExponent { limbs: dP })
|
||||
}
|
||||
}
|
||||
|
||||
@ -763,8 +794,8 @@ impl<M: Prime> PrivateExponent<M> {
|
||||
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
pub fn elem_exp_consttime<M>(
|
||||
base: Elem<M, R>, exponent: &PrivateExponent<M>, m: &Modulus<M>)
|
||||
-> Result<Elem<M, Unencoded>, error::Unspecified> {
|
||||
base: Elem<M, R>, exponent: &PrivateExponent<M>, m: &Modulus<M>,
|
||||
) -> Result<Elem<M, Unencoded>, error::Unspecified> {
|
||||
let mut r = Elem {
|
||||
limbs: base.limbs,
|
||||
encoding: PhantomData,
|
||||
@ -774,10 +805,15 @@ pub fn elem_exp_consttime<M>(
|
||||
elem_mul(m.oneRR().as_ref(), one, m)
|
||||
};
|
||||
Result::from(unsafe {
|
||||
GFp_BN_mod_exp_mont_consttime(r.limbs.as_mut_ptr(), r.limbs.as_ptr(),
|
||||
exponent.limbs.as_ptr(),
|
||||
oneR.limbs.as_ptr(), m.limbs.as_ptr(),
|
||||
m.limbs.len(), &m.n0)
|
||||
GFp_BN_mod_exp_mont_consttime(
|
||||
r.limbs.as_mut_ptr(),
|
||||
r.limbs.as_ptr(),
|
||||
exponent.limbs.as_ptr(),
|
||||
oneR.limbs.as_ptr(),
|
||||
m.limbs.as_ptr(),
|
||||
m.limbs.len(),
|
||||
&m.n0,
|
||||
)
|
||||
})?;
|
||||
|
||||
// XXX: On x86-64 only, `GFp_BN_mod_exp_mont_consttime` does the conversion
|
||||
@ -798,17 +834,16 @@ pub fn elem_exp_consttime<M>(
|
||||
/// Uses Fermat's Little Theorem to calculate modular inverse in constant time.
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
pub fn elem_inverse_consttime<M: Prime>(
|
||||
a: Elem<M, R>,
|
||||
m: &Modulus<M>) -> Result<Elem<M, Unencoded>, error::Unspecified> {
|
||||
a: Elem<M, R>, m: &Modulus<M>,
|
||||
) -> Result<Elem<M, Unencoded>, error::Unspecified> {
|
||||
elem_exp_consttime(a, &PrivateExponent::for_flt(&m), m)
|
||||
}
|
||||
|
||||
/// Verified a == b**-1 (mod m), i.e. a**-1 == b (mod m).
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
pub fn verify_inverses_consttime<M>(a: &Elem<M, R>, b: Elem<M, Unencoded>,
|
||||
m: &Modulus<M>)
|
||||
-> Result<(), error::Unspecified>
|
||||
{
|
||||
pub fn verify_inverses_consttime<M>(
|
||||
a: &Elem<M, R>, b: Elem<M, Unencoded>, m: &Modulus<M>,
|
||||
) -> Result<(), error::Unspecified> {
|
||||
if elem_mul(a, b, m).is_one() {
|
||||
Ok(())
|
||||
} else {
|
||||
@ -817,10 +852,13 @@ pub fn verify_inverses_consttime<M>(a: &Elem<M, R>, b: Elem<M, Unencoded>,
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "rsa_signing"))]
|
||||
pub fn elem_verify_equal_consttime<M, E>(a: &Elem<M, E>, b: &Elem<M, E>)
|
||||
-> Result<(), error::Unspecified> {
|
||||
constant_time::verify_slices_are_equal(limb::limbs_as_bytes(&a.limbs),
|
||||
limb::limbs_as_bytes(&b.limbs))
|
||||
pub fn elem_verify_equal_consttime<M, E>(
|
||||
a: &Elem<M, E>, b: &Elem<M, E>,
|
||||
) -> Result<(), error::Unspecified> {
|
||||
constant_time::verify_slices_are_equal(
|
||||
limb::limbs_as_bytes(&a.limbs),
|
||||
limb::limbs_as_bytes(&b.limbs),
|
||||
)
|
||||
}
|
||||
|
||||
/// Nonnegative integers.
|
||||
@ -831,10 +869,10 @@ pub struct Nonnegative {
|
||||
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
impl Nonnegative {
|
||||
pub fn from_be_bytes_with_bit_length(input: untrusted::Input)
|
||||
-> Result<(Self, bits::BitLength), error::Unspecified> {
|
||||
let mut limbs =
|
||||
vec![0; (input.len() + limb::LIMB_BYTES - 1) / limb::LIMB_BYTES];
|
||||
pub fn from_be_bytes_with_bit_length(
|
||||
input: untrusted::Input,
|
||||
) -> Result<(Self, bits::BitLength), error::Unspecified> {
|
||||
let mut limbs = vec![0; (input.len() + limb::LIMB_BYTES - 1) / limb::LIMB_BYTES];
|
||||
// Rejects empty inputs.
|
||||
limb::parse_big_endian_and_pad_consttime(input, &mut limbs)?;
|
||||
while limbs.last() == Some(&0) {
|
||||
@ -849,35 +887,31 @@ impl Nonnegative {
|
||||
limb::limbs_are_even_constant_time(&self.limbs) != limb::LimbMask::True
|
||||
}
|
||||
|
||||
pub fn verify_less_than(&self, other: &Self)
|
||||
-> Result<(), error::Unspecified> {
|
||||
pub fn verify_less_than(&self, other: &Self) -> Result<(), error::Unspecified> {
|
||||
if !greater_than(other, self) {
|
||||
return Err(error::Unspecified);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn to_elem<M>(&self, m: &Modulus<M>)
|
||||
-> Result<Elem<M, Unencoded>, error::Unspecified> {
|
||||
pub fn to_elem<M>(&self, m: &Modulus<M>) -> Result<Elem<M, Unencoded>, error::Unspecified> {
|
||||
self.verify_less_than_modulus(&m)?;
|
||||
let mut r = m.zero();
|
||||
r.limbs[0..self.limbs.len()].copy_from_slice(&self.limbs);
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
pub fn verify_less_than_modulus<M>(&self, m: &Modulus<M>)
|
||||
-> Result<(), error::Unspecified>
|
||||
{
|
||||
pub fn verify_less_than_modulus<M>(&self, m: &Modulus<M>) -> Result<(), error::Unspecified> {
|
||||
if self.limbs.len() > m.limbs.len() {
|
||||
return Err(error::Unspecified);
|
||||
}
|
||||
if self.limbs.len() == m.limbs.len() {
|
||||
if limb::limbs_less_than_limbs_consttime(&self.limbs, &m.limbs)
|
||||
!= limb::LimbMask::True {
|
||||
return Err(error::Unspecified)
|
||||
if limb::limbs_less_than_limbs_consttime(&self.limbs, &m.limbs) != limb::LimbMask::True
|
||||
{
|
||||
return Err(error::Unspecified);
|
||||
}
|
||||
}
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
@ -929,48 +963,50 @@ impl From<u64> for N0 {
|
||||
}
|
||||
}
|
||||
|
||||
extern {
|
||||
extern "C" {
|
||||
// `r` and/or 'a' and/or 'b' may alias.
|
||||
fn GFp_bn_mul_mont(r: *mut limb::Limb, a: *const limb::Limb,
|
||||
b: *const limb::Limb, n: *const limb::Limb,
|
||||
n0: &N0, num_limbs: c::size_t);
|
||||
fn GFp_bn_mul_mont(
|
||||
r: *mut limb::Limb, a: *const limb::Limb, b: *const limb::Limb, n: *const limb::Limb,
|
||||
n0: &N0, num_limbs: c::size_t,
|
||||
);
|
||||
fn GFp_bn_mul_mont_check_num_limbs(num_limbs: c::size_t) -> bssl::Result;
|
||||
|
||||
fn GFp_bn_neg_inv_mod_r_u64(n: u64) -> u64;
|
||||
|
||||
fn LIMBS_shl_mod(r: *mut limb::Limb, a: *const limb::Limb,
|
||||
m: *const limb::Limb, num_limbs: c::size_t);
|
||||
fn LIMBS_shl_mod(
|
||||
r: *mut limb::Limb, a: *const limb::Limb, m: *const limb::Limb, num_limbs: c::size_t,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
extern {
|
||||
fn GFp_bn_from_montgomery_in_place(r: *mut limb::Limb, num_r: c::size_t,
|
||||
a: *mut limb::Limb, num_a: c::size_t,
|
||||
n: *const limb::Limb, num_n: c::size_t,
|
||||
n0: &N0) -> bssl::Result;
|
||||
extern "C" {
|
||||
fn GFp_bn_from_montgomery_in_place(
|
||||
r: *mut limb::Limb, num_r: c::size_t, a: *mut limb::Limb, num_a: c::size_t,
|
||||
n: *const limb::Limb, num_n: c::size_t, n0: &N0,
|
||||
) -> bssl::Result;
|
||||
|
||||
// `r` and `a` may alias.
|
||||
fn GFp_BN_mod_exp_mont_consttime(r: *mut limb::Limb,
|
||||
a_mont: *const limb::Limb,
|
||||
p: *const limb::Limb,
|
||||
one_mont: *const limb::Limb,
|
||||
n: *const limb::Limb,
|
||||
num_limbs: c::size_t, n0: &N0) -> bssl::Result;
|
||||
fn GFp_BN_mod_exp_mont_consttime(
|
||||
r: *mut limb::Limb, a_mont: *const limb::Limb, p: *const limb::Limb,
|
||||
one_mont: *const limb::Limb, n: *const limb::Limb, num_limbs: c::size_t, n0: &N0,
|
||||
) -> bssl::Result;
|
||||
|
||||
// `r` and `a` may alias.
|
||||
fn LIMBS_add_mod(r: *mut limb::Limb, a: *const limb::Limb,
|
||||
b: *const limb::Limb, m: *const limb::Limb,
|
||||
num_limbs: c::size_t);
|
||||
fn LIMBS_sub_mod(r: *mut limb::Limb, a: *const limb::Limb,
|
||||
b: *const limb::Limb, m: *const limb::Limb,
|
||||
num_limbs: c::size_t);
|
||||
fn LIMBS_add_mod(
|
||||
r: *mut limb::Limb, a: *const limb::Limb, b: *const limb::Limb, m: *const limb::Limb,
|
||||
num_limbs: c::size_t,
|
||||
);
|
||||
fn LIMBS_sub_mod(
|
||||
r: *mut limb::Limb, a: *const limb::Limb, b: *const limb::Limb, m: *const limb::Limb,
|
||||
num_limbs: c::size_t,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use untrusted;
|
||||
use crate::test;
|
||||
use untrusted;
|
||||
|
||||
// Type-level representation of an arbitrary modulus.
|
||||
struct M {}
|
||||
@ -978,49 +1014,52 @@ mod tests {
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
#[test]
|
||||
fn test_elem_exp_consttime() {
|
||||
test::from_file("src/rsa/bigint_elem_exp_consttime_tests.txt",
|
||||
|section, test_case| {
|
||||
assert_eq!(section, "");
|
||||
test::from_file(
|
||||
"src/rsa/bigint_elem_exp_consttime_tests.txt",
|
||||
|section, test_case| {
|
||||
assert_eq!(section, "");
|
||||
|
||||
let m = consume_modulus::<M>(test_case, "M");
|
||||
let expected_result = consume_elem(test_case, "ModExp", &m);
|
||||
let base = consume_elem(test_case, "A", &m);
|
||||
let e = {
|
||||
let bytes = test_case.consume_bytes("E");
|
||||
PrivateExponent::from_be_bytes_padded(
|
||||
untrusted::Input::from(&bytes), &m).expect("valid exponent")
|
||||
};
|
||||
let base = into_encoded(base, &m);
|
||||
let actual_result = elem_exp_consttime(base, &e, &m).unwrap();
|
||||
assert_elem_eq(&actual_result, &expected_result);
|
||||
let m = consume_modulus::<M>(test_case, "M");
|
||||
let expected_result = consume_elem(test_case, "ModExp", &m);
|
||||
let base = consume_elem(test_case, "A", &m);
|
||||
let e = {
|
||||
let bytes = test_case.consume_bytes("E");
|
||||
PrivateExponent::from_be_bytes_padded(untrusted::Input::from(&bytes), &m)
|
||||
.expect("valid exponent")
|
||||
};
|
||||
let base = into_encoded(base, &m);
|
||||
let actual_result = elem_exp_consttime(base, &e, &m).unwrap();
|
||||
assert_elem_eq(&actual_result, &expected_result);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_elem_exp_vartime() {
|
||||
test::from_file("src/rsa/bigint_elem_exp_vartime_tests.txt",
|
||||
|section, test_case| {
|
||||
assert_eq!(section, "");
|
||||
test::from_file(
|
||||
"src/rsa/bigint_elem_exp_vartime_tests.txt",
|
||||
|section, test_case| {
|
||||
assert_eq!(section, "");
|
||||
|
||||
let m = consume_modulus::<M>(test_case, "M");
|
||||
let expected_result = consume_elem(test_case, "ModExp", &m);
|
||||
let base = consume_elem(test_case, "A", &m);
|
||||
let e = consume_public_exponent(test_case, "E");
|
||||
let m = consume_modulus::<M>(test_case, "M");
|
||||
let expected_result = consume_elem(test_case, "ModExp", &m);
|
||||
let base = consume_elem(test_case, "A", &m);
|
||||
let e = consume_public_exponent(test_case, "E");
|
||||
|
||||
let actual_result = elem_exp_vartime(base, e, &m);
|
||||
let actual_result = actual_result.into_unencoded(&m);
|
||||
assert_elem_eq(&actual_result, &expected_result);
|
||||
let actual_result = elem_exp_vartime(base, e, &m);
|
||||
let actual_result = actual_result.into_unencoded(&m);
|
||||
assert_elem_eq(&actual_result, &expected_result);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_elem_mul() {
|
||||
test::from_file("src/rsa/bigint_elem_mul_tests.txt",
|
||||
|section, test_case| {
|
||||
test::from_file("src/rsa/bigint_elem_mul_tests.txt", |section, test_case| {
|
||||
assert_eq!(section, "");
|
||||
|
||||
let m = consume_modulus::<M>(test_case, "M");
|
||||
@ -1040,83 +1079,94 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_elem_squared() {
|
||||
test::from_file("src/rsa/bigint_elem_squared_tests.txt",
|
||||
|section, test_case| {
|
||||
assert_eq!(section, "");
|
||||
test::from_file(
|
||||
"src/rsa/bigint_elem_squared_tests.txt",
|
||||
|section, test_case| {
|
||||
assert_eq!(section, "");
|
||||
|
||||
let m = consume_modulus::<M>(test_case, "M");
|
||||
let expected_result = consume_elem(test_case, "ModSquare", &m);
|
||||
let a = consume_elem(test_case, "A", &m);
|
||||
let m = consume_modulus::<M>(test_case, "M");
|
||||
let expected_result = consume_elem(test_case, "ModSquare", &m);
|
||||
let a = consume_elem(test_case, "A", &m);
|
||||
|
||||
let a = into_encoded(a, &m);
|
||||
let actual_result = elem_squared(a, &m.as_partial());
|
||||
let actual_result = actual_result.into_unencoded(&m);
|
||||
assert_elem_eq(&actual_result, &expected_result);
|
||||
let a = into_encoded(a, &m);
|
||||
let actual_result = elem_squared(a, &m.as_partial());
|
||||
let actual_result = actual_result.into_unencoded(&m);
|
||||
assert_elem_eq(&actual_result, &expected_result);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
#[test]
|
||||
fn test_elem_reduced() {
|
||||
test::from_file("src/rsa/bigint_elem_reduced_tests.txt",
|
||||
|section, test_case| {
|
||||
assert_eq!(section, "");
|
||||
test::from_file(
|
||||
"src/rsa/bigint_elem_reduced_tests.txt",
|
||||
|section, test_case| {
|
||||
assert_eq!(section, "");
|
||||
|
||||
struct MM {}
|
||||
unsafe impl SmallerModulus<MM> for M {}
|
||||
unsafe impl NotMuchSmallerModulus<MM> for M {}
|
||||
struct MM {}
|
||||
unsafe impl SmallerModulus<MM> for M {}
|
||||
unsafe impl NotMuchSmallerModulus<MM> for M {}
|
||||
|
||||
let m = consume_modulus::<M>(test_case, "M");
|
||||
let expected_result = consume_elem(test_case, "R", &m);
|
||||
let a = consume_elem_unchecked::<MM>(
|
||||
test_case, "A", expected_result.limbs.len() * 2);
|
||||
let m = consume_modulus::<M>(test_case, "M");
|
||||
let expected_result = consume_elem(test_case, "R", &m);
|
||||
let a =
|
||||
consume_elem_unchecked::<MM>(test_case, "A", expected_result.limbs.len() * 2);
|
||||
|
||||
let actual_result = elem_reduced(&a, &m).unwrap();
|
||||
let oneRR = m.oneRR();
|
||||
let actual_result = elem_mul(oneRR.as_ref(), actual_result, &m);
|
||||
assert_elem_eq(&actual_result, &expected_result);
|
||||
let actual_result = elem_reduced(&a, &m).unwrap();
|
||||
let oneRR = m.oneRR();
|
||||
let actual_result = elem_mul(oneRR.as_ref(), actual_result, &m);
|
||||
assert_elem_eq(&actual_result, &expected_result);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
#[test]
|
||||
fn test_elem_reduced_once() {
|
||||
test::from_file("src/rsa/bigint_elem_reduced_once_tests.txt",
|
||||
|section, test_case| {
|
||||
assert_eq!(section, "");
|
||||
test::from_file(
|
||||
"src/rsa/bigint_elem_reduced_once_tests.txt",
|
||||
|section, test_case| {
|
||||
assert_eq!(section, "");
|
||||
|
||||
struct N {}
|
||||
struct QQ {}
|
||||
unsafe impl SmallerModulus<N> for QQ {}
|
||||
unsafe impl SlightlySmallerModulus<N> for QQ {}
|
||||
struct N {}
|
||||
struct QQ {}
|
||||
unsafe impl SmallerModulus<N> for QQ {}
|
||||
unsafe impl SlightlySmallerModulus<N> for QQ {}
|
||||
|
||||
let qq = consume_modulus::<QQ>(test_case, "QQ");
|
||||
let expected_result = consume_elem::<QQ>(test_case, "R", &qq);
|
||||
let n = consume_modulus::<N>(test_case, "N");
|
||||
let a = consume_elem::<N>(test_case, "A", &n);
|
||||
let qq = consume_modulus::<QQ>(test_case, "QQ");
|
||||
let expected_result = consume_elem::<QQ>(test_case, "R", &qq);
|
||||
let n = consume_modulus::<N>(test_case, "N");
|
||||
let a = consume_elem::<N>(test_case, "A", &n);
|
||||
|
||||
let actual_result = elem_reduced_once(&a, &qq);
|
||||
assert_elem_eq(&actual_result, &expected_result);
|
||||
let actual_result = elem_reduced_once(&a, &qq);
|
||||
assert_elem_eq(&actual_result, &expected_result);
|
||||
|
||||
Ok(())
|
||||
})
|
||||
Ok(())
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn consume_elem<M>(test_case: &mut test::TestCase, name: &str, m: &Modulus<M>)
|
||||
-> Elem<M, Unencoded> {
|
||||
fn consume_elem<M>(
|
||||
test_case: &mut test::TestCase, name: &str, m: &Modulus<M>,
|
||||
) -> Elem<M, Unencoded> {
|
||||
let value = test_case.consume_bytes(name);
|
||||
Elem::from_be_bytes_padded(untrusted::Input::from(&value), m).unwrap()
|
||||
}
|
||||
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
fn consume_elem_unchecked<M>(test_case: &mut test::TestCase, name: &str,
|
||||
num_limbs: usize) -> Elem<M, Unencoded> {
|
||||
fn consume_elem_unchecked<M>(
|
||||
test_case: &mut test::TestCase, name: &str, num_limbs: usize,
|
||||
) -> Elem<M, Unencoded> {
|
||||
let value = consume_nonnegative(test_case, name);
|
||||
let mut limbs = BoxedLimbs::zero(Width { num_limbs, m: PhantomData });
|
||||
let mut limbs = BoxedLimbs::zero(Width {
|
||||
num_limbs,
|
||||
m: PhantomData,
|
||||
});
|
||||
limbs[0..value.limbs.len()].copy_from_slice(&value.limbs);
|
||||
Elem {
|
||||
limbs,
|
||||
@ -1124,27 +1174,23 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn consume_modulus<M>(test_case: &mut test::TestCase, name: &str)
|
||||
-> Modulus<M> {
|
||||
fn consume_modulus<M>(test_case: &mut test::TestCase, name: &str) -> Modulus<M> {
|
||||
let value = test_case.consume_bytes(name);
|
||||
let (value, _) = Modulus::from_be_bytes_with_bit_length(
|
||||
untrusted::Input::from(&value)).unwrap();
|
||||
let (value, _) =
|
||||
Modulus::from_be_bytes_with_bit_length(untrusted::Input::from(&value)).unwrap();
|
||||
value
|
||||
}
|
||||
|
||||
fn consume_public_exponent(test_case: &mut test::TestCase, name: &str)
|
||||
-> PublicExponent {
|
||||
fn consume_public_exponent(test_case: &mut test::TestCase, name: &str) -> PublicExponent {
|
||||
let bytes = test_case.consume_bytes(name);
|
||||
PublicExponent::from_be_bytes(
|
||||
untrusted::Input::from(&bytes), 3).unwrap()
|
||||
PublicExponent::from_be_bytes(untrusted::Input::from(&bytes), 3).unwrap()
|
||||
}
|
||||
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
fn consume_nonnegative(test_case: &mut test::TestCase, name: &str)
|
||||
-> Nonnegative {
|
||||
fn consume_nonnegative(test_case: &mut test::TestCase, name: &str) -> Nonnegative {
|
||||
let bytes = test_case.consume_bytes(name);
|
||||
let (r, _r_bits) = Nonnegative::from_be_bytes_with_bit_length(
|
||||
untrusted::Input::from(&bytes)).unwrap();
|
||||
let (r, _r_bits) =
|
||||
Nonnegative::from_be_bytes_with_bit_length(untrusted::Input::from(&bytes)).unwrap();
|
||||
r
|
||||
}
|
||||
|
||||
|
@ -18,8 +18,7 @@
|
||||
// components.
|
||||
|
||||
/// RSA signatures.
|
||||
|
||||
use crate::{bits, der, limb, error};
|
||||
use crate::{bits, der, error, limb};
|
||||
use untrusted;
|
||||
|
||||
mod padding;
|
||||
@ -29,24 +28,16 @@ mod padding;
|
||||
pub use self::padding::RSAEncoding;
|
||||
|
||||
pub use self::padding::{
|
||||
RSA_PKCS1_SHA256,
|
||||
RSA_PKCS1_SHA384,
|
||||
RSA_PKCS1_SHA512,
|
||||
|
||||
RSA_PSS_SHA256,
|
||||
RSA_PSS_SHA384,
|
||||
RSA_PSS_SHA512
|
||||
RSA_PKCS1_SHA256, RSA_PKCS1_SHA384, RSA_PKCS1_SHA512, RSA_PSS_SHA256, RSA_PSS_SHA384,
|
||||
RSA_PSS_SHA512,
|
||||
};
|
||||
|
||||
|
||||
// Maximum RSA modulus size supported for signature verification (in bytes).
|
||||
const PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN: usize =
|
||||
bigint::MODULUS_MAX_LIMBS * limb::LIMB_BYTES;
|
||||
const PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN: usize = bigint::MODULUS_MAX_LIMBS * limb::LIMB_BYTES;
|
||||
|
||||
// Keep in sync with the documentation comment for `KeyPair`.
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
const PRIVATE_KEY_PUBLIC_MODULUS_MAX_BITS: bits::BitLength =
|
||||
bits::BitLength(4096);
|
||||
const PRIVATE_KEY_PUBLIC_MODULUS_MAX_BITS: bits::BitLength = bits::BitLength(4096);
|
||||
|
||||
/// Parameters for RSA verification.
|
||||
pub struct RSAParameters {
|
||||
@ -66,9 +57,9 @@ enum RSAParametersID {
|
||||
RSA_PSS_2048_8192_SHA512,
|
||||
}
|
||||
|
||||
fn parse_public_key(input: untrusted::Input)
|
||||
-> Result<(untrusted::Input, untrusted::Input),
|
||||
error::Unspecified> {
|
||||
fn parse_public_key(
|
||||
input: untrusted::Input,
|
||||
) -> Result<(untrusted::Input, untrusted::Input), error::Unspecified> {
|
||||
input.read_all(error::Unspecified, |input| {
|
||||
der::nested(input, der::Tag::Sequence, error::Unspecified, |input| {
|
||||
let n = der::positive_integer(input)?;
|
||||
|
@ -12,8 +12,8 @@
|
||||
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
use crate::{bits, der, digest, error, polyfill};
|
||||
use super::PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN;
|
||||
use crate::{bits, der, digest, error, polyfill};
|
||||
use untrusted;
|
||||
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
@ -32,9 +32,10 @@ pub trait RSAPadding: 'static + Sync + ::private::Sealed {
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
pub trait RSAEncoding: RSAPadding {
|
||||
#[doc(hidden)]
|
||||
fn encode(&self, m_hash: &digest::Digest, m_out: &mut [u8],
|
||||
mod_bits: bits::BitLength, rng: &rand::SecureRandom)
|
||||
-> Result<(), error::Unspecified>;
|
||||
fn encode(
|
||||
&self, m_hash: &digest::Digest, m_out: &mut [u8], mod_bits: bits::BitLength,
|
||||
rng: &rand::SecureRandom,
|
||||
) -> Result<(), error::Unspecified>;
|
||||
}
|
||||
|
||||
/// Verification of an RSA signature encoding as described in
|
||||
@ -42,8 +43,9 @@ pub trait RSAEncoding: RSAPadding {
|
||||
///
|
||||
/// [RFC 3447 Section 8]: https://tools.ietf.org/html/rfc3447#section-8
|
||||
pub trait RSAVerification: RSAPadding {
|
||||
fn verify(&self, m_hash: &digest::Digest, m: &mut untrusted::Reader,
|
||||
mod_bits: bits::BitLength) -> Result<(), error::Unspecified>;
|
||||
fn verify(
|
||||
&self, m_hash: &digest::Digest, m: &mut untrusted::Reader, mod_bits: bits::BitLength,
|
||||
) -> Result<(), error::Unspecified>;
|
||||
}
|
||||
|
||||
/// PKCS#1 1.5 padding as described in [RFC 3447 Section 8.2].
|
||||
@ -57,30 +59,31 @@ pub struct PKCS1 {
|
||||
digestinfo_prefix: &'static [u8],
|
||||
}
|
||||
|
||||
impl ::private::Sealed for PKCS1 { }
|
||||
impl ::private::Sealed for PKCS1 {}
|
||||
|
||||
impl RSAPadding for PKCS1 {
|
||||
fn digest_alg(&self) -> &'static digest::Algorithm { self.digest_alg }
|
||||
}
|
||||
|
||||
#[cfg(feature ="rsa_signing")]
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
impl RSAEncoding for PKCS1 {
|
||||
fn encode(&self, m_hash: &digest::Digest, m_out: &mut [u8],
|
||||
_mod_bits: bits::BitLength, _rng: &rand::SecureRandom)
|
||||
-> Result<(), error::Unspecified> {
|
||||
fn encode(
|
||||
&self, m_hash: &digest::Digest, m_out: &mut [u8], _mod_bits: bits::BitLength,
|
||||
_rng: &rand::SecureRandom,
|
||||
) -> Result<(), error::Unspecified> {
|
||||
pkcs1_encode(&self, m_hash, m_out);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl RSAVerification for PKCS1 {
|
||||
fn verify(&self, m_hash: &digest::Digest, m: &mut untrusted::Reader,
|
||||
mod_bits: bits::BitLength) -> Result<(), error::Unspecified> {
|
||||
fn verify(
|
||||
&self, m_hash: &digest::Digest, m: &mut untrusted::Reader, mod_bits: bits::BitLength,
|
||||
) -> Result<(), error::Unspecified> {
|
||||
// `mod_bits.as_usize_bytes_rounded_up() <=
|
||||
// PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN` is ensured by `verify_rsa()`.
|
||||
let mut calculated = [0u8; PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN];
|
||||
let calculated =
|
||||
&mut calculated[..mod_bits.as_usize_bytes_rounded_up()];
|
||||
let calculated = &mut calculated[..mod_bits.as_usize_bytes_rounded_up()];
|
||||
pkcs1_encode(&self, m_hash, calculated);
|
||||
if m.skip_to_end() != polyfill::ref_from_mut_ref(calculated) {
|
||||
return Err(error::Unspecified);
|
||||
@ -96,8 +99,7 @@ impl RSAVerification for PKCS1 {
|
||||
fn pkcs1_encode(pkcs1: &PKCS1, m_hash: &digest::Digest, m_out: &mut [u8]) {
|
||||
let em = m_out;
|
||||
|
||||
let digest_len =
|
||||
pkcs1.digestinfo_prefix.len() + pkcs1.digest_alg.output_len;
|
||||
let digest_len = pkcs1.digestinfo_prefix.len() + pkcs1.digest_alg.output_len;
|
||||
|
||||
// The specification requires at least 8 bytes of padding. Since we
|
||||
// disallow keys smaller than 2048 bits, this should always be true.
|
||||
@ -110,8 +112,7 @@ fn pkcs1_encode(pkcs1: &PKCS1, m_hash: &digest::Digest, m_out: &mut [u8]) {
|
||||
}
|
||||
em[2 + pad_len] = 0;
|
||||
|
||||
let (digest_prefix, digest_dst) = em[3 + pad_len..]
|
||||
.split_at_mut(pkcs1.digestinfo_prefix.len());
|
||||
let (digest_prefix, digest_dst) = em[3 + pad_len..].split_at_mut(pkcs1.digestinfo_prefix.len());
|
||||
digest_prefix.copy_from_slice(pkcs1.digestinfo_prefix);
|
||||
digest_dst.copy_from_slice(m_hash.as_ref());
|
||||
}
|
||||
@ -125,21 +126,33 @@ macro_rules! rsa_pkcs1_padding {
|
||||
digest_alg: $digest_alg,
|
||||
digestinfo_prefix: $digestinfo_prefix,
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
rsa_pkcs1_padding!(RSA_PKCS1_SHA1, &digest::SHA1,
|
||||
&SHA1_PKCS1_DIGESTINFO_PREFIX,
|
||||
"PKCS#1 1.5 padding using SHA-1 for RSA signatures.");
|
||||
rsa_pkcs1_padding!(RSA_PKCS1_SHA256, &digest::SHA256,
|
||||
&SHA256_PKCS1_DIGESTINFO_PREFIX,
|
||||
"PKCS#1 1.5 padding using SHA-256 for RSA signatures.");
|
||||
rsa_pkcs1_padding!(RSA_PKCS1_SHA384, &digest::SHA384,
|
||||
&SHA384_PKCS1_DIGESTINFO_PREFIX,
|
||||
"PKCS#1 1.5 padding using SHA-384 for RSA signatures.");
|
||||
rsa_pkcs1_padding!(RSA_PKCS1_SHA512, &digest::SHA512,
|
||||
&SHA512_PKCS1_DIGESTINFO_PREFIX,
|
||||
"PKCS#1 1.5 padding using SHA-512 for RSA signatures.");
|
||||
rsa_pkcs1_padding!(
|
||||
RSA_PKCS1_SHA1,
|
||||
&digest::SHA1,
|
||||
&SHA1_PKCS1_DIGESTINFO_PREFIX,
|
||||
"PKCS#1 1.5 padding using SHA-1 for RSA signatures."
|
||||
);
|
||||
rsa_pkcs1_padding!(
|
||||
RSA_PKCS1_SHA256,
|
||||
&digest::SHA256,
|
||||
&SHA256_PKCS1_DIGESTINFO_PREFIX,
|
||||
"PKCS#1 1.5 padding using SHA-256 for RSA signatures."
|
||||
);
|
||||
rsa_pkcs1_padding!(
|
||||
RSA_PKCS1_SHA384,
|
||||
&digest::SHA384,
|
||||
&SHA384_PKCS1_DIGESTINFO_PREFIX,
|
||||
"PKCS#1 1.5 padding using SHA-384 for RSA signatures."
|
||||
);
|
||||
rsa_pkcs1_padding!(
|
||||
RSA_PKCS1_SHA512,
|
||||
&digest::SHA512,
|
||||
&SHA512_PKCS1_DIGESTINFO_PREFIX,
|
||||
"PKCS#1 1.5 padding using SHA-512 for RSA signatures."
|
||||
);
|
||||
|
||||
macro_rules! pkcs1_digestinfo_prefix {
|
||||
( $name:ident, $digest_len:expr, $digest_oid_len:expr,
|
||||
@ -155,20 +168,32 @@ macro_rules! pkcs1_digestinfo_prefix {
|
||||
}
|
||||
|
||||
pkcs1_digestinfo_prefix!(
|
||||
SHA1_PKCS1_DIGESTINFO_PREFIX, 20, 5, [ 0x2b, 0x0e, 0x03, 0x02, 0x1a ]);
|
||||
SHA1_PKCS1_DIGESTINFO_PREFIX,
|
||||
20,
|
||||
5,
|
||||
[0x2b, 0x0e, 0x03, 0x02, 0x1a]
|
||||
);
|
||||
|
||||
pkcs1_digestinfo_prefix!(
|
||||
SHA256_PKCS1_DIGESTINFO_PREFIX, 32, 9,
|
||||
[ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 ]);
|
||||
SHA256_PKCS1_DIGESTINFO_PREFIX,
|
||||
32,
|
||||
9,
|
||||
[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01]
|
||||
);
|
||||
|
||||
pkcs1_digestinfo_prefix!(
|
||||
SHA384_PKCS1_DIGESTINFO_PREFIX, 48, 9,
|
||||
[ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 ]);
|
||||
SHA384_PKCS1_DIGESTINFO_PREFIX,
|
||||
48,
|
||||
9,
|
||||
[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02]
|
||||
);
|
||||
|
||||
pkcs1_digestinfo_prefix!(
|
||||
SHA512_PKCS1_DIGESTINFO_PREFIX, 64, 9,
|
||||
[ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 ]);
|
||||
|
||||
SHA512_PKCS1_DIGESTINFO_PREFIX,
|
||||
64,
|
||||
9,
|
||||
[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03]
|
||||
);
|
||||
|
||||
/// RSA PSS padding as described in [RFC 3447 Section 8.1].
|
||||
///
|
||||
@ -180,7 +205,7 @@ pub struct PSS {
|
||||
digest_alg: &'static digest::Algorithm,
|
||||
}
|
||||
|
||||
impl ::private::Sealed for PSS { }
|
||||
impl ::private::Sealed for PSS {}
|
||||
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
// Maximum supported length of the salt in bytes.
|
||||
@ -195,9 +220,10 @@ impl RSAPadding for PSS {
|
||||
impl RSAEncoding for PSS {
|
||||
// Implement padding procedure per EMSA-PSS,
|
||||
// https://tools.ietf.org/html/rfc3447#section-9.1.
|
||||
fn encode(&self, m_hash: &digest::Digest, m_out: &mut [u8],
|
||||
mod_bits: bits::BitLength, rng: &rand::SecureRandom)
|
||||
-> Result<(), error::Unspecified> {
|
||||
fn encode(
|
||||
&self, m_hash: &digest::Digest, m_out: &mut [u8], mod_bits: bits::BitLength,
|
||||
rng: &rand::SecureRandom,
|
||||
) -> Result<(), error::Unspecified> {
|
||||
let metrics = PSSMetrics::new(self.digest_alg, mod_bits)?;
|
||||
|
||||
// The `m_out` this function fills is the big-endian-encoded value of `m`
|
||||
@ -230,8 +256,7 @@ impl RSAEncoding for PSS {
|
||||
// into `em`, and then XOR the value of db.
|
||||
|
||||
// Step 9. First output the mask into the out buffer.
|
||||
let (mut masked_db, digest_terminator) =
|
||||
em.split_at_mut(metrics.db_len);
|
||||
let (mut masked_db, digest_terminator) = em.split_at_mut(metrics.db_len);
|
||||
mgf1(self.digest_alg, h_hash.as_ref(), &mut masked_db)?;
|
||||
|
||||
{
|
||||
@ -264,8 +289,9 @@ impl RSAEncoding for PSS {
|
||||
impl RSAVerification for PSS {
|
||||
// RSASSA-PSS-VERIFY from https://tools.ietf.org/html/rfc3447#section-8.1.2
|
||||
// where steps 1, 2(a), and 2(b) have been done for us.
|
||||
fn verify(&self, m_hash: &digest::Digest, m: &mut untrusted::Reader,
|
||||
mod_bits: bits::BitLength) -> Result<(), error::Unspecified> {
|
||||
fn verify(
|
||||
&self, m_hash: &digest::Digest, m: &mut untrusted::Reader, mod_bits: bits::BitLength,
|
||||
) -> Result<(), error::Unspecified> {
|
||||
let metrics = PSSMetrics::new(self.digest_alg, mod_bits)?;
|
||||
|
||||
// RSASSA-PSS-VERIFY Step 2(c). The `m` this function is given is the
|
||||
@ -351,7 +377,8 @@ impl RSAVerification for PSS {
|
||||
}
|
||||
|
||||
struct PSSMetrics {
|
||||
#[cfg_attr(not(feature = "rsa_signing"), allow(dead_code))] em_len: usize,
|
||||
#[cfg_attr(not(feature = "rsa_signing"), allow(dead_code))]
|
||||
em_len: usize,
|
||||
db_len: usize,
|
||||
ps_len: usize,
|
||||
s_len: usize,
|
||||
@ -360,8 +387,9 @@ struct PSSMetrics {
|
||||
}
|
||||
|
||||
impl PSSMetrics {
|
||||
fn new(digest_alg: &'static digest::Algorithm, mod_bits: bits::BitLength)
|
||||
-> Result<PSSMetrics, error::Unspecified> {
|
||||
fn new(
|
||||
digest_alg: &'static digest::Algorithm, mod_bits: bits::BitLength,
|
||||
) -> Result<PSSMetrics, error::Unspecified> {
|
||||
let em_bits = mod_bits.try_sub(bits::ONE)?;
|
||||
let em_len = em_bits.as_usize_bytes_rounded_up();
|
||||
let leading_zero_bits = (8 * em_len) - em_bits.as_usize_bits();
|
||||
@ -386,20 +414,21 @@ impl PSSMetrics {
|
||||
debug_assert!(em_bits.as_usize_bits() >= (8 * h_len) + (8 * s_len) + 9);
|
||||
|
||||
Ok(PSSMetrics {
|
||||
em_len: em_len,
|
||||
db_len: db_len,
|
||||
ps_len: ps_len,
|
||||
s_len: s_len,
|
||||
h_len: h_len,
|
||||
top_byte_mask: top_byte_mask,
|
||||
em_len,
|
||||
db_len,
|
||||
ps_len,
|
||||
s_len,
|
||||
h_len,
|
||||
top_byte_mask,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 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], mask: &mut [u8])
|
||||
-> Result<(), error::Unspecified> {
|
||||
fn mgf1(
|
||||
digest_alg: &'static digest::Algorithm, seed: &[u8], mask: &mut [u8],
|
||||
) -> Result<(), error::Unspecified> {
|
||||
let digest_len = digest_alg.output_len;
|
||||
|
||||
// Maximum counter value is the value of (mask_len / digest_len) rounded up.
|
||||
@ -417,8 +446,9 @@ fn mgf1(digest_alg: &'static digest::Algorithm, seed: &[u8], mask: &mut [u8])
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pss_digest(digest_alg: &'static digest::Algorithm, m_hash: &digest::Digest,
|
||||
salt: &[u8]) -> digest::Digest {
|
||||
fn pss_digest(
|
||||
digest_alg: &'static digest::Algorithm, m_hash: &digest::Digest, salt: &[u8],
|
||||
) -> digest::Digest {
|
||||
// Fixed prefix.
|
||||
const PREFIX_ZEROS: [u8; 8] = [0u8; 8];
|
||||
|
||||
@ -437,32 +467,40 @@ macro_rules! rsa_pss_padding {
|
||||
pub static $PADDING_ALGORITHM: PSS = PSS {
|
||||
digest_alg: $digest_alg,
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
rsa_pss_padding!(RSA_PSS_SHA256, &digest::SHA256,
|
||||
"RSA PSS padding using SHA-256 for RSA signatures.\n\nSee
|
||||
rsa_pss_padding!(
|
||||
RSA_PSS_SHA256,
|
||||
&digest::SHA256,
|
||||
"RSA PSS padding using SHA-256 for RSA signatures.\n\nSee
|
||||
\"`RSA_PSS_*` Details\" in `ring::signature`'s module-level
|
||||
documentation for more details.");
|
||||
rsa_pss_padding!(RSA_PSS_SHA384, &digest::SHA384,
|
||||
"RSA PSS padding using SHA-384 for RSA signatures.\n\nSee
|
||||
documentation for more details."
|
||||
);
|
||||
rsa_pss_padding!(
|
||||
RSA_PSS_SHA384,
|
||||
&digest::SHA384,
|
||||
"RSA PSS padding using SHA-384 for RSA signatures.\n\nSee
|
||||
\"`RSA_PSS_*` Details\" in `ring::signature`'s module-level
|
||||
documentation for more details.");
|
||||
rsa_pss_padding!(RSA_PSS_SHA512, &digest::SHA512,
|
||||
"RSA PSS padding using SHA-512 for RSA signatures.\n\nSee
|
||||
documentation for more details."
|
||||
);
|
||||
rsa_pss_padding!(
|
||||
RSA_PSS_SHA512,
|
||||
&digest::SHA512,
|
||||
"RSA PSS padding using SHA-512 for RSA signatures.\n\nSee
|
||||
\"`RSA_PSS_*` Details\" in `ring::signature`'s module-level
|
||||
documentation for more details.");
|
||||
documentation for more details."
|
||||
);
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{digest, error, test};
|
||||
use super::*;
|
||||
use crate::{digest, error, test};
|
||||
use untrusted;
|
||||
|
||||
#[test]
|
||||
fn test_pss_padding_verify() {
|
||||
test::from_file("src/rsa/rsa_pss_padding_tests.txt",
|
||||
|section, test_case| {
|
||||
test::from_file("src/rsa/rsa_pss_padding_tests.txt", |section, test_case| {
|
||||
assert_eq!(section, "");
|
||||
|
||||
let digest_name = test_case.consume_string("Digest");
|
||||
@ -470,13 +508,12 @@ mod test {
|
||||
"SHA256" => &RSA_PSS_SHA256,
|
||||
"SHA384" => &RSA_PSS_SHA384,
|
||||
"SHA512" => &RSA_PSS_SHA512,
|
||||
_ => { panic!("Unsupported digest: {}", digest_name) }
|
||||
_ => panic!("Unsupported digest: {}", digest_name),
|
||||
};
|
||||
|
||||
let msg = test_case.consume_bytes("Msg");
|
||||
let msg = untrusted::Input::from(&msg);
|
||||
let m_hash = digest::digest(alg.digest_alg(),
|
||||
msg.as_slice_less_safe());
|
||||
let m_hash = digest::digest(alg.digest_alg(), msg.as_slice_less_safe());
|
||||
|
||||
let encoded = test_case.consume_bytes("EM");
|
||||
let encoded = untrusted::Input::from(&encoded);
|
||||
@ -488,8 +525,7 @@ mod test {
|
||||
let expected_result = test_case.consume_string("Result");
|
||||
|
||||
let actual_result =
|
||||
encoded.read_all(error::Unspecified,
|
||||
|m| alg.verify(&m_hash, m, bit_len));
|
||||
encoded.read_all(error::Unspecified, |m| alg.verify(&m_hash, m, bit_len));
|
||||
assert_eq!(actual_result.is_ok(), expected_result == "P");
|
||||
|
||||
Ok(())
|
||||
@ -500,8 +536,7 @@ mod test {
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
#[test]
|
||||
fn test_pss_padding_encode() {
|
||||
test::from_file("src/rsa/rsa_pss_padding_tests.txt",
|
||||
|section, test_case| {
|
||||
test::from_file("src/rsa/rsa_pss_padding_tests.txt", |section, test_case| {
|
||||
assert_eq!(section, "");
|
||||
|
||||
let digest_name = test_case.consume_string("Digest");
|
||||
@ -509,7 +544,7 @@ mod test {
|
||||
"SHA256" => &RSA_PSS_SHA256,
|
||||
"SHA384" => &RSA_PSS_SHA384,
|
||||
"SHA512" => &RSA_PSS_SHA512,
|
||||
_ => { panic!("Unsupported digest: {}", digest_name) }
|
||||
_ => panic!("Unsupported digest: {}", digest_name),
|
||||
};
|
||||
|
||||
let msg = test_case.consume_bytes("Msg");
|
||||
@ -520,7 +555,7 @@ mod test {
|
||||
|
||||
// Only test the valid outputs
|
||||
if expected_result != "P" {
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let rng = test::rand::FixedSliceRandom { bytes: &salt };
|
||||
|
@ -12,12 +12,14 @@
|
||||
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
use super::{
|
||||
bigint::{self, Prime},
|
||||
verification, N,
|
||||
};
|
||||
use arithmetic::montgomery::R;
|
||||
/// RSA PKCS#1 1.5 signatures.
|
||||
|
||||
use crate::{bits, der, digest, error, pkcs8, rand};
|
||||
use std;
|
||||
use super::{bigint, bigint::Prime, N, verification};
|
||||
use arithmetic::montgomery::R;
|
||||
use untrusted;
|
||||
|
||||
/// An RSA key pair, used for signing. Feature: `rsa_signing`.
|
||||
@ -91,7 +93,8 @@ impl KeyPair {
|
||||
/// regarding these expectations are not done.
|
||||
/// * Section 6.4.1.2.1, Step 3: Since neither the public key nor the
|
||||
/// expected modulus length is provided as a parameter, the consistency
|
||||
/// check between these values and the private key's value of n isn't done.
|
||||
/// check between these values and the private key's value of n isn't
|
||||
/// done.
|
||||
/// * Section 6.4.1.2.1, Step 5: No primality tests are done, both for
|
||||
/// performance reasons and to avoid any side channels that such tests
|
||||
/// would provide.
|
||||
@ -133,13 +136,9 @@ impl KeyPair {
|
||||
///
|
||||
/// [RFC 5958]:
|
||||
/// https://tools.ietf.org/html/rfc5958
|
||||
///
|
||||
pub fn from_pkcs8(input: untrusted::Input)
|
||||
-> Result<Self, error::Unspecified> {
|
||||
const RSA_ENCRYPTION: &[u8] =
|
||||
include_bytes!("../data/alg-rsa-encryption.der");
|
||||
let (der, _) = pkcs8::unwrap_key_(&RSA_ENCRYPTION,
|
||||
pkcs8::Version::V1Only, input)?;
|
||||
pub fn from_pkcs8(input: untrusted::Input) -> Result<Self, error::Unspecified> {
|
||||
const RSA_ENCRYPTION: &[u8] = include_bytes!("../data/alg-rsa-encryption.der");
|
||||
let (der, _) = pkcs8::unwrap_key_(&RSA_ENCRYPTION, pkcs8::Version::V1Only, input)?;
|
||||
Self::from_der(der)
|
||||
}
|
||||
|
||||
@ -158,8 +157,7 @@ impl KeyPair {
|
||||
///
|
||||
/// [NIST SP-800-56B rev. 1]:
|
||||
/// http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br1.pdf
|
||||
pub fn from_der(input: untrusted::Input)
|
||||
-> Result<Self, error::Unspecified> {
|
||||
pub fn from_der(input: untrusted::Input) -> Result<Self, error::Unspecified> {
|
||||
input.read_all(error::Unspecified, |input| {
|
||||
der::nested(input, der::Tag::Sequence, error::Unspecified, |input| {
|
||||
let version = der::small_nonnegative_integer(input)?;
|
||||
@ -175,18 +173,15 @@ impl KeyPair {
|
||||
let dQ = der::positive_integer(input)?;
|
||||
let qInv = der::positive_integer(input)?;
|
||||
|
||||
let (p, p_bits) =
|
||||
bigint::Nonnegative::from_be_bytes_with_bit_length(p)?;
|
||||
let (q, q_bits) =
|
||||
bigint::Nonnegative::from_be_bytes_with_bit_length(q)?;
|
||||
let (p, p_bits) = bigint::Nonnegative::from_be_bytes_with_bit_length(p)?;
|
||||
let (q, q_bits) = bigint::Nonnegative::from_be_bytes_with_bit_length(q)?;
|
||||
|
||||
// Our implementation of CRT-based modular exponentiation used
|
||||
// requires that `p > q` so swap them if `p < q`. If swapped,
|
||||
// `qInv` is recalculated below. `p != q` is verified
|
||||
// implicitly below, e.g. when `q_mod_p` is constructed.
|
||||
let ((p, p_bits, dP), (q, q_bits, dQ, qInv)) =
|
||||
match q.verify_less_than(&p) {
|
||||
Ok(_) => ((p, p_bits, dP), (q, q_bits, dQ, Some(qInv))),
|
||||
let ((p, p_bits, dP), (q, q_bits, dQ, qInv)) = match q.verify_less_than(&p) {
|
||||
Ok(_) => ((p, p_bits, dP), (q, q_bits, dQ, Some(qInv))),
|
||||
Err(_) => {
|
||||
// TODO: verify `q` and `qInv` are inverses (mod p).
|
||||
((q, q_bits, dQ), (p, p_bits, dP, None))
|
||||
@ -214,8 +209,12 @@ impl KeyPair {
|
||||
|
||||
// Step 1.c. We validate e >= 65537.
|
||||
let public_key = verification::Key::from_modulus_and_exponent(
|
||||
n, e, bits::BitLength::from_usize_bits(2048),
|
||||
super::PRIVATE_KEY_PUBLIC_MODULUS_MAX_BITS, 65537)?;
|
||||
n,
|
||||
e,
|
||||
bits::BitLength::from_usize_bits(2048),
|
||||
super::PRIVATE_KEY_PUBLIC_MODULUS_MAX_BITS,
|
||||
65537,
|
||||
)?;
|
||||
|
||||
// 6.4.1.4.3 says to skip 6.4.1.2.1 Step 2.
|
||||
|
||||
@ -270,12 +269,13 @@ impl KeyPair {
|
||||
// and then assume that these preconditions are enough to
|
||||
// let us assume that checking p * q == 0 (mod n) is equivalent
|
||||
// to checking p * q == n.
|
||||
let q_mod_n = bigint::elem_mul(public_key.n.oneRR().as_ref(),
|
||||
q_mod_n_decoded.clone(),
|
||||
&public_key.n);
|
||||
let q_mod_n = bigint::elem_mul(
|
||||
public_key.n.oneRR().as_ref(),
|
||||
q_mod_n_decoded.clone(),
|
||||
&public_key.n,
|
||||
);
|
||||
let p_mod_n = p.to_elem(&public_key.n)?;
|
||||
let pq_mod_n =
|
||||
bigint::elem_mul(&q_mod_n, p_mod_n, &public_key.n);
|
||||
let pq_mod_n = bigint::elem_mul(&q_mod_n, p_mod_n, &public_key.n);
|
||||
if !pq_mod_n.is_zero() {
|
||||
return Err(error::Unspecified);
|
||||
}
|
||||
@ -288,8 +288,7 @@ impl KeyPair {
|
||||
// has a bit length of half_n_bits + 1, this check gives us
|
||||
// 2**half_n_bits <= d, and knowing d is odd makes the
|
||||
// inequality strict.
|
||||
let (d, d_bits) =
|
||||
bigint::Nonnegative::from_be_bytes_with_bit_length(d)?;
|
||||
let (d, d_bits) = bigint::Nonnegative::from_be_bytes_with_bit_length(d)?;
|
||||
if !(half_n_bits < d_bits) {
|
||||
return Err(error::Unspecified);
|
||||
}
|
||||
@ -319,9 +318,8 @@ impl KeyPair {
|
||||
} else {
|
||||
// We swapped `p` and `q` above, so we need to calculate
|
||||
// `qInv`. Step 7.f below will verify `qInv` is correct.
|
||||
let q_mod_p = bigint::elem_mul(p.modulus.oneRR().as_ref(),
|
||||
q_mod_p.clone(),
|
||||
&p.modulus);
|
||||
let q_mod_p =
|
||||
bigint::elem_mul(p.modulus.oneRR().as_ref(), q_mod_p.clone(), &p.modulus);
|
||||
bigint::elem_inverse_consttime(q_mod_p, &p.modulus)?
|
||||
};
|
||||
|
||||
@ -330,12 +328,10 @@ impl KeyPair {
|
||||
// do modulo with an even modulus.
|
||||
|
||||
// Step 7.f.
|
||||
let qInv =
|
||||
bigint::elem_mul(p.modulus.oneRR().as_ref(), qInv, &p.modulus);
|
||||
let qInv = bigint::elem_mul(p.modulus.oneRR().as_ref(), qInv, &p.modulus);
|
||||
bigint::verify_inverses_consttime(&qInv, q_mod_p, &p.modulus)?;
|
||||
|
||||
let qq =
|
||||
bigint::elem_mul(&q_mod_n, q_mod_n_decoded, &public_key.n)
|
||||
let qq = bigint::elem_mul(&q_mod_n, q_mod_n_decoded, &public_key.n)
|
||||
.into_modulus::<QQ>()?;
|
||||
|
||||
Ok(Self {
|
||||
@ -353,9 +349,7 @@ impl KeyPair {
|
||||
/// Returns the length in bytes of the key pair's public modulus.
|
||||
///
|
||||
/// A signature has the same length as the public modulus.
|
||||
pub fn public_modulus_len(&self) -> usize {
|
||||
self.public_key.modulus_len()
|
||||
}
|
||||
pub fn public_modulus_len(&self) -> usize { self.public_key.modulus_len() }
|
||||
}
|
||||
|
||||
struct PrivatePrime<M: Prime> {
|
||||
@ -366,8 +360,7 @@ struct PrivatePrime<M: Prime> {
|
||||
impl<M: Prime + Clone> PrivatePrime<M> {
|
||||
/// Constructs a `PrivatePrime` from the private prime `p` and `dP` where
|
||||
/// dP == d % (p - 1).
|
||||
fn new(p: bigint::Nonnegative, dP: untrusted::Input)
|
||||
-> Result<Self, error::Unspecified> {
|
||||
fn new(p: bigint::Nonnegative, dP: untrusted::Input) -> Result<Self, error::Unspecified> {
|
||||
let p = bigint::Modulus::from(p)?;
|
||||
|
||||
// [NIST SP-800-56B rev. 1] 6.4.1.4.3 - Steps 7.a & 7.b.
|
||||
@ -389,10 +382,13 @@ impl<M: Prime + Clone> PrivatePrime<M> {
|
||||
}
|
||||
}
|
||||
|
||||
fn elem_exp_consttime<M, MM>(c: &bigint::Elem<MM>, p: &PrivatePrime<M>)
|
||||
-> Result<bigint::Elem<M>, error::Unspecified>
|
||||
where M: bigint::NotMuchSmallerModulus<MM>,
|
||||
M: Prime {
|
||||
fn elem_exp_consttime<M, MM>(
|
||||
c: &bigint::Elem<MM>, p: &PrivatePrime<M>,
|
||||
) -> Result<bigint::Elem<M>, error::Unspecified>
|
||||
where
|
||||
M: bigint::NotMuchSmallerModulus<MM>,
|
||||
M: Prime,
|
||||
{
|
||||
let c_mod_m = bigint::elem_reduced(c, &p.modulus)?;
|
||||
// We could precompute `oneRRR = elem_squared(&p.oneRR`) as mentioned
|
||||
// in the Smooth CRT-RSA paper.
|
||||
@ -401,7 +397,6 @@ fn elem_exp_consttime<M, MM>(c: &bigint::Elem<MM>, p: &PrivatePrime<M>)
|
||||
bigint::elem_exp_consttime(c_mod_m, &p.exponent, &p.modulus)
|
||||
}
|
||||
|
||||
|
||||
// Type-level representations of the different moduli used in RSA signing, in
|
||||
// addition to `super::N`. See `super::bigint`'s modulue-level documentation.
|
||||
|
||||
@ -435,7 +430,6 @@ unsafe impl bigint::SlightlySmallerModulus<P> for Q {}
|
||||
unsafe impl bigint::SmallerModulus<QQ> for Q {}
|
||||
unsafe impl bigint::NotMuchSmallerModulus<QQ> for Q {}
|
||||
|
||||
|
||||
/// State used for RSA Signing. Feature: `rsa_signing`.
|
||||
//
|
||||
// TODO: Remove this; it's not needed if we don't have RSA blinding.
|
||||
@ -445,11 +439,8 @@ pub struct SigningState {
|
||||
|
||||
impl SigningState {
|
||||
/// Construct a signing state appropriate for use with the given key pair.
|
||||
pub fn new(key_pair: std::sync::Arc<KeyPair>)
|
||||
-> Result<Self, error::Unspecified> {
|
||||
Ok(SigningState {
|
||||
key_pair: key_pair,
|
||||
})
|
||||
pub fn new(key_pair: std::sync::Arc<KeyPair>) -> Result<Self, error::Unspecified> {
|
||||
Ok(SigningState { key_pair })
|
||||
}
|
||||
|
||||
/// The key pair. This can be used, for example, to access the key pair's
|
||||
@ -472,9 +463,10 @@ impl SigningState {
|
||||
/// constant time to protect the private key from side channel attacks. On
|
||||
/// x86-64, this is done pretty well, but not perfectly. On other
|
||||
/// platforms, it is done less perfectly.
|
||||
pub fn sign(&mut self, padding_alg: &'static ::signature::RSAEncoding,
|
||||
rng: &rand::SecureRandom, msg: &[u8], signature: &mut [u8])
|
||||
-> Result<(), error::Unspecified> {
|
||||
pub fn sign(
|
||||
&mut self, padding_alg: &'static ::signature::RSAEncoding, rng: &rand::SecureRandom,
|
||||
msg: &[u8], signature: &mut [u8],
|
||||
) -> Result<(), error::Unspecified> {
|
||||
let mod_bits = self.key_pair.public_key.n_bits;
|
||||
if signature.len() != mod_bits.as_usize_bytes_rounded_up() {
|
||||
return Err(error::Unspecified);
|
||||
@ -491,8 +483,7 @@ impl SigningState {
|
||||
let n = &key.public_key.n;
|
||||
|
||||
// Step 1. The value zero is also rejected.
|
||||
let base = bigint::Elem::from_be_bytes_padded(
|
||||
untrusted::Input::from(signature), n)?;
|
||||
let base = bigint::Elem::from_be_bytes_padded(untrusted::Input::from(signature), n)?;
|
||||
|
||||
// Step 2
|
||||
let c = base;
|
||||
@ -530,8 +521,7 @@ impl SigningState {
|
||||
// minimum value, since the relationship of `e` to `d`, `p`, and `q` is
|
||||
// not verified during `KeyPair` construction.
|
||||
{
|
||||
let verify =
|
||||
bigint::elem_exp_vartime(m.clone(), key.public_key.e, n);
|
||||
let verify = bigint::elem_exp_vartime(m.clone(), key.public_key.e, n);
|
||||
let verify = verify.into_unencoded(n);
|
||||
bigint::elem_verify_equal_consttime(&verify, &c)?;
|
||||
}
|
||||
@ -545,7 +535,6 @@ impl SigningState {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
// We intentionally avoid `use super::*` so that we are sure to use only
|
||||
@ -568,25 +557,25 @@ mod tests {
|
||||
let key_bytes_der = untrusted::Input::from(PRIVATE_KEY_DER);
|
||||
let key_pair = signature::RSAKeyPair::from_der(key_bytes_der).unwrap();
|
||||
let key_pair = std::sync::Arc::new(key_pair);
|
||||
let mut signing_state =
|
||||
signature::RSASigningState::new(key_pair).unwrap();
|
||||
let mut signing_state = signature::RSASigningState::new(key_pair).unwrap();
|
||||
|
||||
// The output buffer is one byte too short.
|
||||
let mut signature =
|
||||
vec![0; signing_state.key_pair().public_modulus_len() - 1];
|
||||
let mut signature = vec![0; signing_state.key_pair().public_modulus_len() - 1];
|
||||
|
||||
assert!(signing_state.sign(&signature::RSA_PKCS1_SHA256, &rng, MESSAGE,
|
||||
&mut signature).is_err());
|
||||
assert!(signing_state
|
||||
.sign(&signature::RSA_PKCS1_SHA256, &rng, MESSAGE, &mut signature)
|
||||
.is_err());
|
||||
|
||||
// The output buffer is the right length.
|
||||
signature.push(0);
|
||||
assert!(signing_state.sign(&signature::RSA_PKCS1_SHA256, &rng, MESSAGE,
|
||||
&mut signature).is_ok());
|
||||
|
||||
assert!(signing_state
|
||||
.sign(&signature::RSA_PKCS1_SHA256, &rng, MESSAGE, &mut signature)
|
||||
.is_ok());
|
||||
|
||||
// The output buffer is one byte too long.
|
||||
signature.push(0);
|
||||
assert!(signing_state.sign(&signature::RSA_PKCS1_SHA256, &rng, MESSAGE,
|
||||
&mut signature).is_err());
|
||||
assert!(signing_state
|
||||
.sign(&signature::RSA_PKCS1_SHA256, &rng, MESSAGE, &mut signature)
|
||||
.is_err());
|
||||
}
|
||||
}
|
||||
|
@ -12,15 +12,12 @@
|
||||
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
use super::{bigint, parse_public_key, RSAParameters, N, PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN};
|
||||
/// RSA PKCS#1 1.5 signatures.
|
||||
|
||||
use core;
|
||||
use crate::{bits, digest, error, private, signature};
|
||||
use super::{bigint, N, PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN, RSAParameters,
|
||||
parse_public_key};
|
||||
use untrusted;
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Key {
|
||||
pub n: bigint::Modulus<N>,
|
||||
@ -31,9 +28,8 @@ pub struct Key {
|
||||
impl Key {
|
||||
pub fn from_modulus_and_exponent(
|
||||
n: untrusted::Input, e: untrusted::Input, n_min_bits: bits::BitLength,
|
||||
n_max_bits: bits::BitLength, e_min_value: u64)
|
||||
-> Result<Self, error::Unspecified>
|
||||
{
|
||||
n_max_bits: bits::BitLength, e_min_value: u64,
|
||||
) -> Result<Self, error::Unspecified> {
|
||||
// This is an incomplete implementation of NIST SP800-56Br1 Section
|
||||
// 6.4.2.2, "Partial Public-Key Validation for RSA." That spec defers
|
||||
// to NIST SP800-89 Section 5.3.3, "(Explicit) Partial Public Key
|
||||
@ -82,15 +78,13 @@ impl Key {
|
||||
///
|
||||
/// A signature has the same length as the public modulus.
|
||||
#[cfg(feature = "rsa_signing")]
|
||||
pub fn modulus_len(&self) -> usize {
|
||||
self.n_bits.as_usize_bytes_rounded_up()
|
||||
}
|
||||
pub fn modulus_len(&self) -> usize { self.n_bits.as_usize_bytes_rounded_up() }
|
||||
}
|
||||
|
||||
impl signature::VerificationAlgorithm for RSAParameters {
|
||||
fn verify(&self, public_key: untrusted::Input, msg: untrusted::Input,
|
||||
signature: untrusted::Input)
|
||||
-> Result<(), error::Unspecified> {
|
||||
fn verify(
|
||||
&self, public_key: untrusted::Input, msg: untrusted::Input, signature: untrusted::Input,
|
||||
) -> Result<(), error::Unspecified> {
|
||||
let public_key = parse_public_key(public_key)?;
|
||||
verify_rsa(self, public_key, msg, signature)
|
||||
}
|
||||
@ -102,16 +96,20 @@ impl core::fmt::Debug for RSAParameters {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
|
||||
use super::RSAParametersID::*;
|
||||
// XXX: This doesn't include the padding algorithm nor the size range.
|
||||
write!(f, "ring::signature::{}", match self.id {
|
||||
RSA_PKCS1_2048_8192_SHA1 => "RSA_PKCS1_2048_8192_SHA1",
|
||||
RSA_PKCS1_2048_8192_SHA256 => "RSA_PKCS1_2048_8192_SHA256",
|
||||
RSA_PKCS1_2048_8192_SHA384 => "RSA_PKCS1_2048_8192_SHA384",
|
||||
RSA_PKCS1_2048_8192_SHA512 => "RSA_PKCS1_2048_8192_SHA512",
|
||||
RSA_PKCS1_3072_8192_SHA384 => "RSA_PKCS1_3072_8192_SHA384",
|
||||
RSA_PSS_2048_8192_SHA256 => "RSA_PSS_2048_8192_SHA256",
|
||||
RSA_PSS_2048_8192_SHA384 => "RSA_PSS_2048_8192_SHA384",
|
||||
RSA_PSS_2048_8192_SHA512 => "RSA_PSS_2048_8192_SHA512",
|
||||
})
|
||||
write!(
|
||||
f,
|
||||
"ring::signature::{}",
|
||||
match self.id {
|
||||
RSA_PKCS1_2048_8192_SHA1 => "RSA_PKCS1_2048_8192_SHA1",
|
||||
RSA_PKCS1_2048_8192_SHA256 => "RSA_PKCS1_2048_8192_SHA256",
|
||||
RSA_PKCS1_2048_8192_SHA384 => "RSA_PKCS1_2048_8192_SHA384",
|
||||
RSA_PKCS1_2048_8192_SHA512 => "RSA_PKCS1_2048_8192_SHA512",
|
||||
RSA_PKCS1_3072_8192_SHA384 => "RSA_PKCS1_3072_8192_SHA384",
|
||||
RSA_PSS_2048_8192_SHA256 => "RSA_PSS_2048_8192_SHA256",
|
||||
RSA_PSS_2048_8192_SHA384 => "RSA_PSS_2048_8192_SHA384",
|
||||
RSA_PSS_2048_8192_SHA512 => "RSA_PSS_2048_8192_SHA512",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,49 +119,79 @@ macro_rules! rsa_params {
|
||||
#[doc=$doc_str]
|
||||
///
|
||||
/// Only available in `use_heap` mode.
|
||||
pub static $VERIFY_ALGORITHM: RSAParameters =
|
||||
RSAParameters {
|
||||
padding_alg: $PADDING_ALGORITHM,
|
||||
min_bits: bits::BitLength($min_bits),
|
||||
id: super::RSAParametersID::$VERIFY_ALGORITHM,
|
||||
};
|
||||
}
|
||||
pub static $VERIFY_ALGORITHM: RSAParameters = RSAParameters {
|
||||
padding_alg: $PADDING_ALGORITHM,
|
||||
min_bits: bits::BitLength($min_bits),
|
||||
id: super::RSAParametersID::$VERIFY_ALGORITHM,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
rsa_params!(RSA_PKCS1_2048_8192_SHA1, 2048, &super::padding::RSA_PKCS1_SHA1,
|
||||
"Verification of signatures using RSA keys of 2048-8192 bits,
|
||||
rsa_params!(
|
||||
RSA_PKCS1_2048_8192_SHA1,
|
||||
2048,
|
||||
&super::padding::RSA_PKCS1_SHA1,
|
||||
"Verification of signatures using RSA keys of 2048-8192 bits,
|
||||
PKCS#1.5 padding, and SHA-1.\n\nSee \"`RSA_PKCS1_*` Details\" in
|
||||
`ring::signature`'s module-level documentation for more details.");
|
||||
rsa_params!(RSA_PKCS1_2048_8192_SHA256, 2048, &super::RSA_PKCS1_SHA256,
|
||||
"Verification of signatures using RSA keys of 2048-8192 bits,
|
||||
`ring::signature`'s module-level documentation for more details."
|
||||
);
|
||||
rsa_params!(
|
||||
RSA_PKCS1_2048_8192_SHA256,
|
||||
2048,
|
||||
&super::RSA_PKCS1_SHA256,
|
||||
"Verification of signatures using RSA keys of 2048-8192 bits,
|
||||
PKCS#1.5 padding, and SHA-256.\n\nSee \"`RSA_PKCS1_*` Details\" in
|
||||
`ring::signature`'s module-level documentation for more details.");
|
||||
rsa_params!(RSA_PKCS1_2048_8192_SHA384, 2048, &super::RSA_PKCS1_SHA384,
|
||||
"Verification of signatures using RSA keys of 2048-8192 bits,
|
||||
`ring::signature`'s module-level documentation for more details."
|
||||
);
|
||||
rsa_params!(
|
||||
RSA_PKCS1_2048_8192_SHA384,
|
||||
2048,
|
||||
&super::RSA_PKCS1_SHA384,
|
||||
"Verification of signatures using RSA keys of 2048-8192 bits,
|
||||
PKCS#1.5 padding, and SHA-384.\n\nSee \"`RSA_PKCS1_*` Details\" in
|
||||
`ring::signature`'s module-level documentation for more details.");
|
||||
rsa_params!(RSA_PKCS1_2048_8192_SHA512, 2048, &super::RSA_PKCS1_SHA512,
|
||||
"Verification of signatures using RSA keys of 2048-8192 bits,
|
||||
`ring::signature`'s module-level documentation for more details."
|
||||
);
|
||||
rsa_params!(
|
||||
RSA_PKCS1_2048_8192_SHA512,
|
||||
2048,
|
||||
&super::RSA_PKCS1_SHA512,
|
||||
"Verification of signatures using RSA keys of 2048-8192 bits,
|
||||
PKCS#1.5 padding, and SHA-512.\n\nSee \"`RSA_PKCS1_*` Details\" in
|
||||
`ring::signature`'s module-level documentation for more details.");
|
||||
rsa_params!(RSA_PKCS1_3072_8192_SHA384, 3072, &super::RSA_PKCS1_SHA384,
|
||||
"Verification of signatures using RSA keys of 3072-8192 bits,
|
||||
`ring::signature`'s module-level documentation for more details."
|
||||
);
|
||||
rsa_params!(
|
||||
RSA_PKCS1_3072_8192_SHA384,
|
||||
3072,
|
||||
&super::RSA_PKCS1_SHA384,
|
||||
"Verification of signatures using RSA keys of 3072-8192 bits,
|
||||
PKCS#1.5 padding, and SHA-384.\n\nSee \"`RSA_PKCS1_*` Details\" in
|
||||
`ring::signature`'s module-level documentation for more details.");
|
||||
`ring::signature`'s module-level documentation for more details."
|
||||
);
|
||||
|
||||
rsa_params!(RSA_PSS_2048_8192_SHA256, 2048, &super::RSA_PSS_SHA256,
|
||||
"Verification of signatures using RSA keys of 2048-8192 bits,
|
||||
rsa_params!(
|
||||
RSA_PSS_2048_8192_SHA256,
|
||||
2048,
|
||||
&super::RSA_PSS_SHA256,
|
||||
"Verification of signatures using RSA keys of 2048-8192 bits,
|
||||
PSS padding, and SHA-256.\n\nSee \"`RSA_PSS_*` Details\" in
|
||||
`ring::signature`'s module-level documentation for more details.");
|
||||
rsa_params!(RSA_PSS_2048_8192_SHA384, 2048, &super::RSA_PSS_SHA384,
|
||||
"Verification of signatures using RSA keys of 2048-8192 bits,
|
||||
`ring::signature`'s module-level documentation for more details."
|
||||
);
|
||||
rsa_params!(
|
||||
RSA_PSS_2048_8192_SHA384,
|
||||
2048,
|
||||
&super::RSA_PSS_SHA384,
|
||||
"Verification of signatures using RSA keys of 2048-8192 bits,
|
||||
PSS padding, and SHA-384.\n\nSee \"`RSA_PSS_*` Details\" in
|
||||
`ring::signature`'s module-level documentation for more details.");
|
||||
rsa_params!(RSA_PSS_2048_8192_SHA512, 2048, &super::RSA_PSS_SHA512,
|
||||
"Verification of signatures using RSA keys of 2048-8192 bits,
|
||||
`ring::signature`'s module-level documentation for more details."
|
||||
);
|
||||
rsa_params!(
|
||||
RSA_PSS_2048_8192_SHA512,
|
||||
2048,
|
||||
&super::RSA_PSS_SHA512,
|
||||
"Verification of signatures using RSA keys of 2048-8192 bits,
|
||||
PSS padding, and SHA-512.\n\nSee \"`RSA_PSS_*` Details\" in
|
||||
`ring::signature`'s module-level documentation for more details.");
|
||||
|
||||
`ring::signature`'s module-level documentation for more details."
|
||||
);
|
||||
|
||||
/// Lower-level API for the verification of RSA signatures.
|
||||
///
|
||||
@ -190,19 +218,17 @@ rsa_params!(RSA_PSS_2048_8192_SHA512, 2048, &super::RSA_PSS_SHA512,
|
||||
// testing `verify_rsa` directly, but the testing work for RSA PKCS#1
|
||||
// verification was done during the implementation of
|
||||
// `signature::VerificationAlgorithm`, before `verify_rsa` was factored out).
|
||||
pub fn verify_rsa(params: &RSAParameters,
|
||||
(n, e): (untrusted::Input, untrusted::Input),
|
||||
msg: untrusted::Input, signature: untrusted::Input)
|
||||
-> Result<(), error::Unspecified> {
|
||||
let max_bits = bits::BitLength::from_usize_bytes(
|
||||
PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN)?;
|
||||
pub fn verify_rsa(
|
||||
params: &RSAParameters, (n, e): (untrusted::Input, untrusted::Input), msg: untrusted::Input,
|
||||
signature: untrusted::Input,
|
||||
) -> Result<(), error::Unspecified> {
|
||||
let max_bits = bits::BitLength::from_usize_bytes(PUBLIC_KEY_PUBLIC_MODULUS_MAX_LEN)?;
|
||||
|
||||
// XXX: FIPS 186-4 seems to indicate that the minimum
|
||||
// exponent value is 2**16 + 1, but it isn't clear if this is just for
|
||||
// signing or also for verification. We support exponents of 3 and larger
|
||||
// for compatibility with other commonly-used crypto libraries.
|
||||
let Key { n, e, n_bits } =
|
||||
Key::from_modulus_and_exponent(n, e, params.min_bits, max_bits, 3)?;
|
||||
let Key { n, e, n_bits } = Key::from_modulus_and_exponent(n, e, params.min_bits, max_bits, 3)?;
|
||||
|
||||
// The signature must be the same length as the modulus, in bytes.
|
||||
if signature.len() != n_bits.as_usize_bytes_rounded_up() {
|
||||
@ -227,8 +253,8 @@ pub fn verify_rsa(params: &RSAParameters,
|
||||
m.fill_be_bytes(decoded);
|
||||
|
||||
// Verify the padded message is correct.
|
||||
let m_hash = digest::digest(params.padding_alg.digest_alg(),
|
||||
msg.as_slice_less_safe());
|
||||
untrusted::Input::from(decoded).read_all(
|
||||
error::Unspecified, |m| params.padding_alg.verify(&m_hash, m, n_bits))
|
||||
let m_hash = digest::digest(params.padding_alg.digest_alg(), msg.as_slice_less_safe());
|
||||
untrusted::Input::from(decoded).read_all(error::Unspecified, |m| {
|
||||
params.padding_alg.verify(&m_hash, m, n_bits)
|
||||
})
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user