Upgrade the QuickCheck/rand dependencies.

This also adds a check in the synthesis of arbitary items of unknown type,
to ensure that we don't accidentally create objects with a known type. I'm
actually not 100% sure how the old tests were passing so reliably, which
is worrying.
This commit is contained in:
2021-04-18 13:17:01 -07:00
parent 483e692109
commit c585acc530
2 changed files with 92 additions and 65 deletions

View File

@@ -16,5 +16,5 @@ num-traits = { default-features = false, version = "0.2" }
thiserror = { default-features = false, version = "1" } thiserror = { default-features = false, version = "1" }
[dev-dependencies] [dev-dependencies]
quickcheck = "0.9" quickcheck = "1.0.3"
rand = "0.7" rand = "0.8.3"

View File

@@ -281,6 +281,13 @@ macro_rules! oid {
const PRINTABLE_CHARS: &'static str = const PRINTABLE_CHARS: &'static str =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'()+,-./:=? "; "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'()+,-./:=? ";
#[cfg(test)]
const KNOWN_TAGS: &[u8] =
&[0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x0c, 0x10, 0x11, 0x13, 0x14, 0x16,
0x17, 0x18, 0x1c, 0x1e,
];
/// An error that can arise decoding ASN.1 primitive blocks. /// An error that can arise decoding ASN.1 primitive blocks.
#[derive(Clone, Debug, Error, PartialEq)] #[derive(Clone, Debug, Error, PartialEq)]
pub enum ASN1DecodeErr { pub enum ASN1DecodeErr {
@@ -1040,13 +1047,12 @@ mod tests {
use super::*; use super::*;
use chrono::offset::LocalResult; use chrono::offset::LocalResult;
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
use rand::{distributions::Standard, prelude::SliceRandom, Rng};
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
impl Arbitrary for ASN1Class { impl Arbitrary for ASN1Class {
fn arbitrary<G: Gen>(g: &mut G) -> ASN1Class { fn arbitrary(g: &mut Gen) -> ASN1Class {
match g.gen::<u8>() % 4 { match u8::arbitrary(g) % 4 {
0 => ASN1Class::Private, 0 => ASN1Class::Private,
1 => ASN1Class::ContextSpecific, 1 => ASN1Class::ContextSpecific,
2 => ASN1Class::Universal, 2 => ASN1Class::Universal,
@@ -1072,8 +1078,8 @@ mod tests {
} }
impl Arbitrary for RandomUint { impl Arbitrary for RandomUint {
fn arbitrary<G: Gen>(g: &mut G) -> RandomUint { fn arbitrary(g: &mut Gen) -> RandomUint {
let v = BigUint::from_u32(g.gen::<u32>()).unwrap(); let v = BigUint::from_u32(u32::arbitrary(g)).unwrap();
RandomUint { x: v } RandomUint { x: v }
} }
} }
@@ -1102,54 +1108,64 @@ mod tests {
} }
impl Arbitrary for RandomInt { impl Arbitrary for RandomInt {
fn arbitrary<G: Gen>(g: &mut G) -> RandomInt { fn arbitrary(g: &mut Gen) -> RandomInt {
let v = BigInt::from_i64(g.gen::<i64>()).unwrap(); let v = BigInt::from_i64(i64::arbitrary(g)).unwrap();
RandomInt { x: v } RandomInt { x: v }
} }
} }
#[allow(type_alias_bounds)] #[allow(type_alias_bounds)]
type ASN1BlockGen<G: Gen> = fn(&mut G, usize) -> ASN1Block; type ASN1BlockGen = fn(&mut Gen, usize) -> ASN1Block;
fn arb_boolean<G: Gen>(g: &mut G, _d: usize) -> ASN1Block { fn arb_boolean(g: &mut Gen, _d: usize) -> ASN1Block {
let v = g.gen::<bool>(); let v = bool::arbitrary(g);
ASN1Block::Boolean(0, v) ASN1Block::Boolean(0, v)
} }
fn arb_integer<G: Gen>(g: &mut G, _d: usize) -> ASN1Block { fn arb_integer(g: &mut Gen, _d: usize) -> ASN1Block {
let d = RandomInt::arbitrary(g); let d = RandomInt::arbitrary(g);
ASN1Block::Integer(0, d.x) ASN1Block::Integer(0, d.x)
} }
fn arb_bitstr<G: Gen>(g: &mut G, _d: usize) -> ASN1Block { fn arb_bitstr(g: &mut Gen, _d: usize) -> ASN1Block {
let size = g.gen::<u16>() as usize % 16; let size = u16::arbitrary(g) as usize % 16;
let maxbits = (size as usize) * 8; let maxbits = (size as usize) * 8;
let modbits = g.gen::<u8>() as usize % 8; let modbits = u8::arbitrary(g) as usize % 8;
let nbits = if modbits > maxbits { let nbits = if modbits > maxbits {
maxbits maxbits
} else { } else {
maxbits - modbits maxbits - modbits
}; };
let bytes = g.sample_iter::<u8, _>(&Standard).take(size).collect();
let mut bytes = Vec::with_capacity(size);
while bytes.len() < size {
bytes.push(u8::arbitrary(g));
}
ASN1Block::BitString(0, nbits, bytes) ASN1Block::BitString(0, nbits, bytes)
} }
fn arb_octstr<G: Gen>(g: &mut G, _d: usize) -> ASN1Block { fn arb_octstr(g: &mut Gen, _d: usize) -> ASN1Block {
let size = g.gen::<u16>() as usize % 16; let size = usize::arbitrary(g) % 16;
let bytes = g.sample_iter::<u8, _>(&Standard).take(size).collect(); let mut bytes = Vec::with_capacity(size);
while bytes.len() < size {
bytes.push(u8::arbitrary(g));
}
ASN1Block::OctetString(0, bytes) ASN1Block::OctetString(0, bytes)
} }
fn arb_null<G: Gen>(_g: &mut G, _d: usize) -> ASN1Block { fn arb_null(_g: &mut Gen, _d: usize) -> ASN1Block {
ASN1Block::Null(0) ASN1Block::Null(0)
} }
impl Arbitrary for OID { impl Arbitrary for OID {
fn arbitrary<G: Gen>(g: &mut G) -> OID { fn arbitrary(g: &mut Gen) -> OID {
let count = g.gen_range::<usize, _, _>(0, 40); let count = usize::arbitrary(g) % 40;
let val1 = g.gen::<u8>() % 3; let val1 = u8::arbitrary(g) % 3;
let v2mod = if val1 == 2 { 176 } else { 40 }; let v2mod = if val1 == 2 { 176 } else { 40 };
let val2 = g.gen::<u8>() % v2mod; let val2 = u8::arbitrary(g) % v2mod;
let v1 = BigUint::from_u8(val1).unwrap(); let v1 = BigUint::from_u8(val1).unwrap();
let v2 = BigUint::from_u8(val2).unwrap(); let v2 = BigUint::from_u8(val2).unwrap();
let mut nums = vec![v1, v2]; let mut nums = vec![v1, v2];
@@ -1163,13 +1179,13 @@ mod tests {
} }
} }
fn arb_objid<G: Gen>(g: &mut G, _d: usize) -> ASN1Block { fn arb_objid(g: &mut Gen, _d: usize) -> ASN1Block {
let oid = OID::arbitrary(g); let oid = OID::arbitrary(g);
ASN1Block::ObjectIdentifier(0, oid) ASN1Block::ObjectIdentifier(0, oid)
} }
fn arb_seq<G: Gen>(g: &mut G, d: usize) -> ASN1Block { fn arb_seq(g: &mut Gen, d: usize) -> ASN1Block {
let count = g.gen_range::<usize, _, _>(1, 64); let count = usize::arbitrary(g) % 63 + 1;
let mut items = Vec::new(); let mut items = Vec::new();
for _ in 0..count { for _ in 0..count {
@@ -1179,8 +1195,8 @@ mod tests {
ASN1Block::Sequence(0, items) ASN1Block::Sequence(0, items)
} }
fn arb_set<G: Gen>(g: &mut G, d: usize) -> ASN1Block { fn arb_set(g: &mut Gen, d: usize) -> ASN1Block {
let count = g.gen_range::<usize, _, _>(1, 64); let count = usize::arbitrary(g) % 63 + 1;
let mut items = Vec::new(); let mut items = Vec::new();
for _ in 0..count { for _ in 0..count {
@@ -1190,60 +1206,60 @@ mod tests {
ASN1Block::Set(0, items) ASN1Block::Set(0, items)
} }
fn arb_print<G: Gen>(g: &mut G, _d: usize) -> ASN1Block { fn arb_print(g: &mut Gen, _d: usize) -> ASN1Block {
let count = g.gen_range::<usize, _, _>(0, 384); let count = usize::arbitrary(g) % 384;
let mut items = Vec::new(); let mut items = Vec::new();
for _ in 0..count { for _ in 0..count {
let v = PRINTABLE_CHARS.as_bytes().choose(g).unwrap(); let v = g.choose(PRINTABLE_CHARS.as_bytes());
items.push(*v as char); items.push(*v.unwrap() as char);
} }
ASN1Block::PrintableString(0, String::from_iter(items.iter())) ASN1Block::PrintableString(0, String::from_iter(items.iter()))
} }
fn arb_ia5<G: Gen>(g: &mut G, _d: usize) -> ASN1Block { fn arb_ia5(g: &mut Gen, _d: usize) -> ASN1Block {
let count = g.gen_range::<usize, _, _>(0, 384); let count = usize::arbitrary(g) % 384;
let mut items = Vec::new(); let mut items = Vec::new();
for _ in 0..count { for _ in 0..count {
items.push(g.gen::<u8>() as char); items.push(u8::arbitrary(g) as char);
} }
ASN1Block::IA5String(0, String::from_iter(items.iter())) ASN1Block::IA5String(0, String::from_iter(items.iter()))
} }
fn arb_utf8<G: Gen>(g: &mut G, _d: usize) -> ASN1Block { fn arb_utf8(g: &mut Gen, _d: usize) -> ASN1Block {
let val = String::arbitrary(g); let val = String::arbitrary(g);
ASN1Block::UTF8String(0, val) ASN1Block::UTF8String(0, val)
} }
fn arb_tele<G: Gen>(g: &mut G, _d: usize) -> ASN1Block { fn arb_tele(g: &mut Gen, _d: usize) -> ASN1Block {
let val = String::arbitrary(g); let val = String::arbitrary(g);
ASN1Block::TeletexString(0, val) ASN1Block::TeletexString(0, val)
} }
fn arb_uni<G: Gen>(g: &mut G, _d: usize) -> ASN1Block { fn arb_uni(g: &mut Gen, _d: usize) -> ASN1Block {
let val = String::arbitrary(g); let val = String::arbitrary(g);
ASN1Block::UniversalString(0, val) ASN1Block::UniversalString(0, val)
} }
fn arb_bmp<G: Gen>(g: &mut G, _d: usize) -> ASN1Block { fn arb_bmp(g: &mut Gen, _d: usize) -> ASN1Block {
let val = String::arbitrary(g); let val = String::arbitrary(g);
ASN1Block::BMPString(0, val) ASN1Block::BMPString(0, val)
} }
fn arb_utc<G: Gen>(g: &mut G, _d: usize) -> ASN1Block { fn arb_utc(g: &mut Gen, _d: usize) -> ASN1Block {
loop { loop {
let y = g.gen_range::<i32, _, _>(1970, 2069); let y = (i32::arbitrary(g) % 100).abs() + 1970;
let m = g.gen_range::<u32, _, _>(1, 13); let m = u32::arbitrary(g) % 12 + 1;
let d = g.gen_range::<u32, _, _>(1, 32); let d = u32::arbitrary(g) % 31 + 1;
match Utc.ymd_opt(y, m, d) { match Utc.ymd_opt(y, m, d) {
LocalResult::None => {} LocalResult::None => {}
LocalResult::Single(d) => { LocalResult::Single(d) => {
let h = g.gen_range::<u32, _, _>(0, 24); let h = u32::arbitrary(g) % 24;
let m = g.gen_range::<u32, _, _>(0, 60); let m = u32::arbitrary(g) % 60;
let s = g.gen_range::<u32, _, _>(0, 60); let s = u32::arbitrary(g) % 60;
let t = d.and_hms(h, m, s); let t = d.and_hms(h, m, s);
return ASN1Block::UTCTime(0, t); return ASN1Block::UTCTime(0, t);
} }
@@ -1252,18 +1268,18 @@ mod tests {
} }
} }
fn arb_time<G: Gen>(g: &mut G, _d: usize) -> ASN1Block { fn arb_time(g: &mut Gen, _d: usize) -> ASN1Block {
loop { loop {
let y = g.gen_range::<i32, _, _>(0, 10000); let y = (i32::arbitrary(g) % 10000).abs();
let m = g.gen_range::<u32, _, _>(1, 13); let m = u32::arbitrary(g) % 12 + 1;
let d = g.gen_range::<u32, _, _>(1, 32); let d = u32::arbitrary(g) % 31 + 1;
match Utc.ymd_opt(y, m, d) { match Utc.ymd_opt(y, m, d) {
LocalResult::None => {} LocalResult::None => {}
LocalResult::Single(d) => { LocalResult::Single(d) => {
let h = g.gen_range::<u32, _, _>(0, 24); let h = u32::arbitrary(g) % 24;
let m = g.gen_range::<u32, _, _>(0, 60); let m = u32::arbitrary(g) % 60;
let s = g.gen_range::<u32, _, _>(0, 60); let s = u32::arbitrary(g) % 60;
let n = g.gen_range::<u32, _, _>(0, 1000000000); let n = u32::arbitrary(g) % 1000000000;
let t = d.and_hms_nano(h, m, s, n); let t = d.and_hms_nano(h, m, s, n);
return ASN1Block::GeneralizedTime(0, t); return ASN1Block::GeneralizedTime(0, t);
} }
@@ -1272,7 +1288,7 @@ mod tests {
} }
} }
fn arb_explicit<G: Gen>(g: &mut G, d: usize) -> ASN1Block { fn arb_explicit(g: &mut Gen, d: usize) -> ASN1Block {
let mut class = ASN1Class::arbitrary(g); let mut class = ASN1Class::arbitrary(g);
if class == ASN1Class::Universal { if class == ASN1Class::Universal {
// Universal is invalid for an explicitly tagged block // Universal is invalid for an explicitly tagged block
@@ -1284,17 +1300,28 @@ mod tests {
ASN1Block::Explicit(class, 0, tag.x, Box::new(item)) ASN1Block::Explicit(class, 0, tag.x, Box::new(item))
} }
fn arb_unknown<G: Gen>(g: &mut G, _d: usize) -> ASN1Block { fn arb_unknown(g: &mut Gen, _d: usize) -> ASN1Block {
let class = ASN1Class::arbitrary(g); let class = ASN1Class::arbitrary(g);
let tag = RandomUint::arbitrary(g); let tag = loop {
let size = g.gen_range::<usize, _, _>(0, 128); let potential = RandomUint::arbitrary(g);
let items = g.sample_iter::<u8, _>(&Standard).take(size).collect(); match potential.x.to_u8() {
None => break potential,
Some(x) if KNOWN_TAGS.contains(&x) => {},
Some(_) => break potential,
}
};
let size = usize::arbitrary(g) % 128;
let mut items = Vec::with_capacity(size);
while items.len() < size {
items.push(u8::arbitrary(g));
}
ASN1Block::Unknown(class, false, 0, tag.x, items) ASN1Block::Unknown(class, false, 0, tag.x, items)
} }
fn limited_arbitrary<G: Gen>(g: &mut G, d: usize) -> ASN1Block { fn limited_arbitrary(g: &mut Gen, d: usize) -> ASN1Block {
let mut possibles: Vec<ASN1BlockGen<G>> = vec![ let mut possibles: Vec<ASN1BlockGen> = vec![
arb_boolean, arb_boolean,
arb_integer, arb_integer,
arb_bitstr, arb_bitstr,
@@ -1318,14 +1345,14 @@ mod tests {
possibles.push(arb_explicit); possibles.push(arb_explicit);
} }
match possibles[..].choose(g) { match g.choose(&possibles[..]) {
Some(f) => f(g, d), Some(f) => f(g, d),
None => panic!("Couldn't generate arbitrary value."), None => panic!("Couldn't generate arbitrary value."),
} }
} }
impl Arbitrary for ASN1Block { impl Arbitrary for ASN1Block {
fn arbitrary<G: Gen>(g: &mut G) -> ASN1Block { fn arbitrary(g: &mut Gen) -> ASN1Block {
limited_arbitrary(g, 2) limited_arbitrary(g, 2)
} }
} }