diff --git a/x509-cert/src/serial_number.rs b/x509-cert/src/serial_number.rs index 416d59dc1..1eed88210 100644 --- a/x509-cert/src/serial_number.rs +++ b/x509-cert/src/serial_number.rs @@ -12,7 +12,7 @@ use { core::ops::Add, generic_array::{ typenum::{ - consts::{U17, U19, U8}, + consts::{self, U17, U19, U8}, marker_traits::Unsigned, type_operators::{Max, Min}, uint::UTerm, @@ -110,6 +110,45 @@ impl SerialNumber

{ Self::generate_with_prefix::(GenericArray::default(), rng) } + /// Generates a random serial number from RNG. + /// + /// This follows the recommendation the CAB forum [ballot 164] and uses a minimum of 64 bits + /// of output from the CSPRNG. + /// + /// [ballot 164]: https://cabforum.org/2016/03/31/ballot-164/ + #[cfg(feature = "builder")] + #[allow(unused_qualifications)] + pub fn generate_with_dyn_length(rng: &mut impl CryptoRngCore, len: usize) -> Result { + macro_rules! impl_generate { + ($len:literal => $u:ty) => { + if (len == $len) { + return Self::generate_with_prefix::(GenericArray::default(), rng); + } + }; + ($len:literal => $u:ty, $($rest:tt)*) => { + impl_generate!($len => $u); + impl_generate!($($rest)*); + }; + } + + impl_generate!( + 8 => consts::U8, + 9 => consts::U9, + 10 => consts::U10, + 11 => consts::U11, + 12 => consts::U12, + 13 => consts::U13, + 14 => consts::U14, + 15 => consts::U15, + 16 => consts::U16, + 17 => consts::U17, + 18 => consts::U18, + 19 => consts::U19 + ); + + Err(ErrorKind::Failed.into()) + } + /// Generates a random serial number from RNG. Include a prefix value. /// /// This follows the recommendation the CAB forum [ballot 164] and uses a minimum of 64 bits @@ -294,5 +333,16 @@ mod tests { ) .unwrap(); assert_eq!(sn.as_bytes().len(), 20); + + let sn = SerialNumber::::generate_with_dyn_length(&mut rand::thread_rng(), 4); + assert!(sn.is_err()); + let sn = SerialNumber::::generate_with_dyn_length(&mut rand::thread_rng(), 7); + assert!(sn.is_err()); + let sn = SerialNumber::::generate_with_dyn_length(&mut rand::thread_rng(), 21); + assert!(sn.is_err()); + let sn = SerialNumber::::generate_with_dyn_length(&mut rand::thread_rng(), 8); + assert!(sn.is_ok()); + let sn = SerialNumber::::generate_with_dyn_length(&mut rand::thread_rng(), 19); + assert!(sn.is_ok()); } }