From c585acc5306cdabdabe3041128caa8f76cdad5e5 Mon Sep 17 00:00:00 2001 From: Adam Wick Date: Sun, 18 Apr 2021 13:17:01 -0700 Subject: [PATCH] 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. --- Cargo.toml | 4 +- src/lib.rs | 153 +++++++++++++++++++++++++++++++---------------------- 2 files changed, 92 insertions(+), 65 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index acfb072..6ea93f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,5 +16,5 @@ num-traits = { default-features = false, version = "0.2" } thiserror = { default-features = false, version = "1" } [dev-dependencies] -quickcheck = "0.9" -rand = "0.7" +quickcheck = "1.0.3" +rand = "0.8.3" diff --git a/src/lib.rs b/src/lib.rs index c5ebe1a..c1bd391 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -281,6 +281,13 @@ macro_rules! oid { const PRINTABLE_CHARS: &'static str = "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. #[derive(Clone, Debug, Error, PartialEq)] pub enum ASN1DecodeErr { @@ -1040,13 +1047,12 @@ mod tests { use super::*; use chrono::offset::LocalResult; use quickcheck::{Arbitrary, Gen}; - use rand::{distributions::Standard, prelude::SliceRandom, Rng}; use std::fs::File; use std::io::Read; impl Arbitrary for ASN1Class { - fn arbitrary(g: &mut G) -> ASN1Class { - match g.gen::() % 4 { + fn arbitrary(g: &mut Gen) -> ASN1Class { + match u8::arbitrary(g) % 4 { 0 => ASN1Class::Private, 1 => ASN1Class::ContextSpecific, 2 => ASN1Class::Universal, @@ -1072,8 +1078,8 @@ mod tests { } impl Arbitrary for RandomUint { - fn arbitrary(g: &mut G) -> RandomUint { - let v = BigUint::from_u32(g.gen::()).unwrap(); + fn arbitrary(g: &mut Gen) -> RandomUint { + let v = BigUint::from_u32(u32::arbitrary(g)).unwrap(); RandomUint { x: v } } } @@ -1102,54 +1108,64 @@ mod tests { } impl Arbitrary for RandomInt { - fn arbitrary(g: &mut G) -> RandomInt { - let v = BigInt::from_i64(g.gen::()).unwrap(); + fn arbitrary(g: &mut Gen) -> RandomInt { + let v = BigInt::from_i64(i64::arbitrary(g)).unwrap(); RandomInt { x: v } } } #[allow(type_alias_bounds)] - type ASN1BlockGen = fn(&mut G, usize) -> ASN1Block; + type ASN1BlockGen = fn(&mut Gen, usize) -> ASN1Block; - fn arb_boolean(g: &mut G, _d: usize) -> ASN1Block { - let v = g.gen::(); + fn arb_boolean(g: &mut Gen, _d: usize) -> ASN1Block { + let v = bool::arbitrary(g); ASN1Block::Boolean(0, v) } - fn arb_integer(g: &mut G, _d: usize) -> ASN1Block { + fn arb_integer(g: &mut Gen, _d: usize) -> ASN1Block { let d = RandomInt::arbitrary(g); ASN1Block::Integer(0, d.x) } - fn arb_bitstr(g: &mut G, _d: usize) -> ASN1Block { - let size = g.gen::() as usize % 16; + fn arb_bitstr(g: &mut Gen, _d: usize) -> ASN1Block { + let size = u16::arbitrary(g) as usize % 16; let maxbits = (size as usize) * 8; - let modbits = g.gen::() as usize % 8; + let modbits = u8::arbitrary(g) as usize % 8; let nbits = if modbits > maxbits { maxbits } else { maxbits - modbits }; - let bytes = g.sample_iter::(&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) } - fn arb_octstr(g: &mut G, _d: usize) -> ASN1Block { - let size = g.gen::() as usize % 16; - let bytes = g.sample_iter::(&Standard).take(size).collect(); + fn arb_octstr(g: &mut Gen, _d: usize) -> ASN1Block { + let size = usize::arbitrary(g) % 16; + let mut bytes = Vec::with_capacity(size); + + while bytes.len() < size { + bytes.push(u8::arbitrary(g)); + } + ASN1Block::OctetString(0, bytes) } - fn arb_null(_g: &mut G, _d: usize) -> ASN1Block { + fn arb_null(_g: &mut Gen, _d: usize) -> ASN1Block { ASN1Block::Null(0) } impl Arbitrary for OID { - fn arbitrary(g: &mut G) -> OID { - let count = g.gen_range::(0, 40); - let val1 = g.gen::() % 3; + fn arbitrary(g: &mut Gen) -> OID { + let count = usize::arbitrary(g) % 40; + let val1 = u8::arbitrary(g) % 3; let v2mod = if val1 == 2 { 176 } else { 40 }; - let val2 = g.gen::() % v2mod; + let val2 = u8::arbitrary(g) % v2mod; let v1 = BigUint::from_u8(val1).unwrap(); let v2 = BigUint::from_u8(val2).unwrap(); let mut nums = vec![v1, v2]; @@ -1163,13 +1179,13 @@ mod tests { } } - fn arb_objid(g: &mut G, _d: usize) -> ASN1Block { + fn arb_objid(g: &mut Gen, _d: usize) -> ASN1Block { let oid = OID::arbitrary(g); ASN1Block::ObjectIdentifier(0, oid) } - fn arb_seq(g: &mut G, d: usize) -> ASN1Block { - let count = g.gen_range::(1, 64); + fn arb_seq(g: &mut Gen, d: usize) -> ASN1Block { + let count = usize::arbitrary(g) % 63 + 1; let mut items = Vec::new(); for _ in 0..count { @@ -1179,8 +1195,8 @@ mod tests { ASN1Block::Sequence(0, items) } - fn arb_set(g: &mut G, d: usize) -> ASN1Block { - let count = g.gen_range::(1, 64); + fn arb_set(g: &mut Gen, d: usize) -> ASN1Block { + let count = usize::arbitrary(g) % 63 + 1; let mut items = Vec::new(); for _ in 0..count { @@ -1190,60 +1206,60 @@ mod tests { ASN1Block::Set(0, items) } - fn arb_print(g: &mut G, _d: usize) -> ASN1Block { - let count = g.gen_range::(0, 384); + fn arb_print(g: &mut Gen, _d: usize) -> ASN1Block { + let count = usize::arbitrary(g) % 384; let mut items = Vec::new(); for _ in 0..count { - let v = PRINTABLE_CHARS.as_bytes().choose(g).unwrap(); - items.push(*v as char); + let v = g.choose(PRINTABLE_CHARS.as_bytes()); + items.push(*v.unwrap() as char); } ASN1Block::PrintableString(0, String::from_iter(items.iter())) } - fn arb_ia5(g: &mut G, _d: usize) -> ASN1Block { - let count = g.gen_range::(0, 384); + fn arb_ia5(g: &mut Gen, _d: usize) -> ASN1Block { + let count = usize::arbitrary(g) % 384; let mut items = Vec::new(); for _ in 0..count { - items.push(g.gen::() as char); + items.push(u8::arbitrary(g) as char); } ASN1Block::IA5String(0, String::from_iter(items.iter())) } - fn arb_utf8(g: &mut G, _d: usize) -> ASN1Block { + fn arb_utf8(g: &mut Gen, _d: usize) -> ASN1Block { let val = String::arbitrary(g); ASN1Block::UTF8String(0, val) } - fn arb_tele(g: &mut G, _d: usize) -> ASN1Block { + fn arb_tele(g: &mut Gen, _d: usize) -> ASN1Block { let val = String::arbitrary(g); ASN1Block::TeletexString(0, val) } - fn arb_uni(g: &mut G, _d: usize) -> ASN1Block { + fn arb_uni(g: &mut Gen, _d: usize) -> ASN1Block { let val = String::arbitrary(g); ASN1Block::UniversalString(0, val) } - fn arb_bmp(g: &mut G, _d: usize) -> ASN1Block { + fn arb_bmp(g: &mut Gen, _d: usize) -> ASN1Block { let val = String::arbitrary(g); ASN1Block::BMPString(0, val) } - fn arb_utc(g: &mut G, _d: usize) -> ASN1Block { + fn arb_utc(g: &mut Gen, _d: usize) -> ASN1Block { loop { - let y = g.gen_range::(1970, 2069); - let m = g.gen_range::(1, 13); - let d = g.gen_range::(1, 32); + let y = (i32::arbitrary(g) % 100).abs() + 1970; + let m = u32::arbitrary(g) % 12 + 1; + let d = u32::arbitrary(g) % 31 + 1; match Utc.ymd_opt(y, m, d) { LocalResult::None => {} LocalResult::Single(d) => { - let h = g.gen_range::(0, 24); - let m = g.gen_range::(0, 60); - let s = g.gen_range::(0, 60); + let h = u32::arbitrary(g) % 24; + let m = u32::arbitrary(g) % 60; + let s = u32::arbitrary(g) % 60; let t = d.and_hms(h, m, s); return ASN1Block::UTCTime(0, t); } @@ -1252,18 +1268,18 @@ mod tests { } } - fn arb_time(g: &mut G, _d: usize) -> ASN1Block { + fn arb_time(g: &mut Gen, _d: usize) -> ASN1Block { loop { - let y = g.gen_range::(0, 10000); - let m = g.gen_range::(1, 13); - let d = g.gen_range::(1, 32); + let y = (i32::arbitrary(g) % 10000).abs(); + let m = u32::arbitrary(g) % 12 + 1; + let d = u32::arbitrary(g) % 31 + 1; match Utc.ymd_opt(y, m, d) { LocalResult::None => {} LocalResult::Single(d) => { - let h = g.gen_range::(0, 24); - let m = g.gen_range::(0, 60); - let s = g.gen_range::(0, 60); - let n = g.gen_range::(0, 1000000000); + let h = u32::arbitrary(g) % 24; + let m = u32::arbitrary(g) % 60; + let s = u32::arbitrary(g) % 60; + let n = u32::arbitrary(g) % 1000000000; let t = d.and_hms_nano(h, m, s, n); return ASN1Block::GeneralizedTime(0, t); } @@ -1272,7 +1288,7 @@ mod tests { } } - fn arb_explicit(g: &mut G, d: usize) -> ASN1Block { + fn arb_explicit(g: &mut Gen, d: usize) -> ASN1Block { let mut class = ASN1Class::arbitrary(g); if class == ASN1Class::Universal { // Universal is invalid for an explicitly tagged block @@ -1284,17 +1300,28 @@ mod tests { ASN1Block::Explicit(class, 0, tag.x, Box::new(item)) } - fn arb_unknown(g: &mut G, _d: usize) -> ASN1Block { + fn arb_unknown(g: &mut Gen, _d: usize) -> ASN1Block { let class = ASN1Class::arbitrary(g); - let tag = RandomUint::arbitrary(g); - let size = g.gen_range::(0, 128); - let items = g.sample_iter::(&Standard).take(size).collect(); + let tag = loop { + let potential = RandomUint::arbitrary(g); + 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) } - fn limited_arbitrary(g: &mut G, d: usize) -> ASN1Block { - let mut possibles: Vec> = vec![ + fn limited_arbitrary(g: &mut Gen, d: usize) -> ASN1Block { + let mut possibles: Vec = vec![ arb_boolean, arb_integer, arb_bitstr, @@ -1318,14 +1345,14 @@ mod tests { possibles.push(arb_explicit); } - match possibles[..].choose(g) { + match g.choose(&possibles[..]) { Some(f) => f(g, d), None => panic!("Couldn't generate arbitrary value."), } } impl Arbitrary for ASN1Block { - fn arbitrary(g: &mut G) -> ASN1Block { + fn arbitrary(g: &mut Gen) -> ASN1Block { limited_arbitrary(g, 2) } }