Merge pull request #45 from huitseeker/crash_tests

Proptests exercising `try_from` for most structures based on random data
This commit is contained in:
François Garillot
2020-09-02 17:40:08 -04:00
committed by GitHub
2 changed files with 102 additions and 9 deletions
+47 -9
View File
@@ -34,9 +34,14 @@ pub struct RegisterFirstMessage<Grp> {
impl<Grp: Group> TryFrom<&[u8]> for RegisterFirstMessage<Grp> {
type Error = ProtocolError;
fn try_from(first_message_bytes: &[u8]) -> Result<Self, Self::Error> {
let checked_slice = check_slice_size(
first_message_bytes,
Grp::ElemLen::to_usize(),
"first_message_bytes",
)?;
// Check that the message is actually containing an element of the
// correct subgroup
let arr = GenericArray::from_slice(first_message_bytes);
let arr = GenericArray::from_slice(checked_slice);
let alpha = Grp::from_element_slice(arr)?;
Ok(Self { alpha })
}
@@ -142,14 +147,24 @@ pub struct LoginFirstMessage<CS: CipherSuite> {
impl<CS: CipherSuite> TryFrom<&[u8]> for LoginFirstMessage<CS> {
type Error = ProtocolError;
fn try_from(first_message_bytes: &[u8]) -> Result<Self, Self::Error> {
let min_expected_len = <CS::Group as Group>::ElemLen::to_usize();
let checked_slice = (if first_message_bytes.len() <= min_expected_len {
Err(InternalPakeError::SizeError {
name: "first_message_bytes",
len: min_expected_len,
actual_len: first_message_bytes.len(),
})
} else {
Ok(first_message_bytes)
})?;
// Check that the message is actually containing an element of the
// correct subgroup
let elem_len = <CS::Group as Group>::ElemLen::to_usize();
let arr = GenericArray::from_slice(&first_message_bytes[..elem_len]);
let arr = GenericArray::from_slice(&checked_slice[..elem_len]);
let alpha = CS::Group::from_element_slice(arr)?;
let ke1_message = <CS::KeyExchange as KeyExchange<CS::Hash>>::KE1Message::try_from(
first_message_bytes[elem_len..].to_vec(),
checked_slice[elem_len..].to_vec(),
)?;
Ok(Self { alpha, ke1_message })
}
@@ -275,12 +290,23 @@ pub struct ClientRegistration<CS: CipherSuite> {
impl<CS: CipherSuite> TryFrom<&[u8]> for ClientRegistration<CS> {
type Error = ProtocolError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let min_expected_len = <CS::Group as Group>::ScalarLen::to_usize();
let checked_slice = (if bytes.len() <= min_expected_len {
Err(InternalPakeError::SizeError {
name: "client_registration_bytes",
len: min_expected_len,
actual_len: bytes.len(),
})
} else {
Ok(bytes)
})?;
// Check that the message is actually containing an element of the
// correct subgroup
let scalar_len = <CS::Group as Group>::ScalarLen::to_usize();
let blinding_factor_bytes = GenericArray::from_slice(&bytes[..scalar_len]);
let scalar_len = min_expected_len;
let blinding_factor_bytes = GenericArray::from_slice(&checked_slice[..scalar_len]);
let blinding_factor = CS::Group::from_scalar_slice(blinding_factor_bytes)?;
let password = bytes[scalar_len..].to_vec();
let password = checked_slice[scalar_len..].to_vec();
Ok(Self {
blinding_factor,
password,
@@ -629,11 +655,23 @@ impl<CS: CipherSuite> TryFrom<&[u8]> for ClientLogin<CS> {
type Error = ProtocolError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let scalar_len = <CS::Group as Group>::ScalarLen::to_usize();
let blinding_factor_bytes = GenericArray::from_slice(&bytes[..scalar_len]);
let blinding_factor = CS::Group::from_scalar_slice(blinding_factor_bytes)?;
let ke1_state_size = <CS::KeyExchange as KeyExchange<CS::Hash>>::ke1_state_size();
let min_expected_len = scalar_len + ke1_state_size;
let checked_slice = (if bytes.len() <= min_expected_len {
Err(InternalPakeError::SizeError {
name: "client_login_bytes",
len: min_expected_len,
actual_len: bytes.len(),
})
} else {
Ok(bytes)
})?;
let blinding_factor_bytes = GenericArray::from_slice(&checked_slice[..scalar_len]);
let blinding_factor = CS::Group::from_scalar_slice(blinding_factor_bytes)?;
let ke1_state = <CS::KeyExchange as KeyExchange<CS::Hash>>::KE1State::try_from(
bytes[scalar_len..scalar_len + ke1_state_size].to_vec(),
checked_slice[scalar_len..scalar_len + ke1_state_size].to_vec(),
)?;
let password = bytes[scalar_len + ke1_state_size..].to_vec();
Ok(Self {
+55
View File
@@ -17,6 +17,7 @@ use crate::{
use curve25519_dalek::ristretto::RistrettoPoint;
use generic_array::typenum::Unsigned;
use proptest::{collection::vec, prelude::*};
use rand_core::{OsRng, RngCore};
use sha2::{Digest, Sha256};
@@ -171,3 +172,57 @@ fn login_first_message_roundtrip() {
let reg_bytes = reg.to_bytes();
assert_eq!(reg_bytes, ke1m);
}
proptest! {
#[test]
fn test_nocrash_register_first_message(bytes in vec(any::<u8>(), 0..200)) {
RegisterFirstMessage::<RistrettoPoint>::try_from(&bytes[..]).map_or(true, |_| true);
}
#[test]
fn test_nocrash_register_second_message(bytes in vec(any::<u8>(), 0..200)) {
RegisterSecondMessage::<RistrettoPoint>::try_from(&bytes[..]).map_or(true, |_| true);
}
#[test]
fn test_nocrash_register_third_message(bytes in vec(any::<u8>(), 0..200)) {
RegisterThirdMessage::<crate::keypair::X25519KeyPair, sha2::Sha512>::try_from(&bytes[..]).map_or(true, |_| true);
}
#[test]
fn test_nocrash_login_first_message(bytes in vec(any::<u8>(), 0..500)) {
LoginFirstMessage::<Default>::try_from(&bytes[..]).map_or(true, |_| true);
}
#[test]
fn test_nocrash_login_second_message(bytes in vec(any::<u8>(), 0..500)) {
LoginSecondMessage::<RistrettoPoint, crate::keypair::X25519KeyPair, TripleDH, sha2::Sha512>::try_from(&bytes[..]).map_or(true, |_| true);
}
#[test]
fn test_nocrash_login_third_message(bytes in vec(any::<u8>(), 0..500)) {
LoginThirdMessage::<Default>::try_from(&bytes[..]).map_or(true, |_| true);
}
#[test]
fn test_nocrash_client_registration(bytes in vec(any::<u8>(), 0..700)) {
ClientRegistration::<Default>::try_from(&bytes[..]).map_or(true, |_| true);
}
#[test]
fn test_nocrash_server_registration(bytes in vec(any::<u8>(), 0..700)) {
ServerRegistration::<Default>::try_from(&bytes[..]).map_or(true, |_| true);
}
#[test]
fn test_nocrash_client_login(bytes in vec(any::<u8>(), 0..700)) {
ClientLogin::<Default>::try_from(&bytes[..]).map_or(true, |_| true);
}
#[test]
fn test_nocrash_server_login(bytes in vec(any::<u8>(), 0..700)) {
ServerLogin::<Default>::try_from(&bytes[..]).map_or(true, |_| true);
}
}