ot_certs/template/
testgen.rs1use anyhow::{Result, ensure};
9use rand::distributions::{DistString, Distribution, Uniform};
10
11use openssl::bn::{BigNum, BigNumContext};
12use openssl::ec::{EcGroup, EcKey};
13use openssl::nid::Nid;
14use openssl::pkey::Private;
15
16use crate::template::subst::{SubstData, SubstValue};
17use crate::template::{EcCurve, EcPublicKeyInfo, SubjectPublicKeyInfo, Template, Value, Variable};
18
19fn ecgroup_from_curve(curve: &EcCurve) -> EcGroup {
21 match curve {
22 EcCurve::Prime256v1 => EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(),
23 }
24}
25
26impl Template {
27 pub fn random_test(&self) -> Result<SubstData> {
30 let mut data = SubstData::new();
31 for (var, var_type) in &self.variables {
32 let val = match *var_type {
33 super::VariableType::ByteArray { .. } => {
34 SubstValue::ByteArray(self.random_bytes(var_type))
35 }
36 super::VariableType::String { .. } => {
37 let size = self.random_size(var_type);
38 let s = rand::distributions::Alphanumeric
39 .sample_string(&mut rand::thread_rng(), size);
40 SubstValue::String(s)
41 }
42 super::VariableType::Integer { .. } => {
43 if var_type.size() == 4 {
44 let value = self.random_bytes(var_type);
47 let value = u32::from_be_bytes(value.try_into().unwrap());
48
49 SubstValue::Uint32(value)
50 } else {
51 SubstValue::ByteArray(self.random_bytes(var_type))
52 }
53 }
54 super::VariableType::Boolean => SubstValue::Boolean(rand::random::<bool>()),
55 };
56 data.values.insert(var.to_string(), val);
57 }
58 if let Value::Variable(Variable { name, .. }) = &self.certificate.not_before {
61 data.values.insert(name.clone(), self.random_time());
62 }
63 if let Value::Variable(Variable { name, .. }) = &self.certificate.not_after {
64 data.values.insert(name.clone(), self.random_time());
65 }
66 for (key, val) in self.random_public_key()?.values {
69 data.values.insert(key, val);
70 }
71 Ok(data)
72 }
73
74 fn random_size(&self, var_type: &super::VariableType) -> usize {
76 let (min_size, max_size) = var_type.array_size();
77 if min_size == max_size {
78 min_size
79 } else {
80 Uniform::from(min_size..max_size + 1).sample(&mut rand::thread_rng())
81 }
82 }
83
84 fn random_bytes(&self, var_type: &super::VariableType) -> Vec<u8> {
88 let size = self.random_size(var_type);
89 let mut bytes = (0..size).map(|_| rand::random::<u8>()).collect::<Vec<_>>();
90
91 if var_type.use_msb_tweak() {
92 bytes[0] |= 0x80;
93 } else if matches!(var_type, super::VariableType::Integer { .. }) {
94 let (min_int_size, _) = var_type.int_size(0);
95 if min_int_size > 0 {
96 bytes[size - min_int_size] |= 0x1;
97 }
98 }
99 bytes
100 }
101
102 fn random_time(&self) -> SubstValue {
103 let mut rng = rand::thread_rng();
105 let year = Uniform::from(1900..2100).sample(&mut rng);
106 let month = Uniform::from(1..13).sample(&mut rng);
107 let day = Uniform::from(1..29).sample(&mut rng);
108 let hour = Uniform::from(0..24).sample(&mut rng);
109 let minute = Uniform::from(0..60).sample(&mut rng);
110 let sec = Uniform::from(0..60).sample(&mut rng);
111 let time = format!("{year:04}{month:02}{day:02}{hour:02}{minute:02}{sec:02}Z");
112 SubstValue::String(time)
113 }
114
115 fn random_public_key(&self) -> Result<SubstData> {
116 match &self.certificate.subject_public_key_info {
117 SubjectPublicKeyInfo::EcPublicKey(ec) => Self::random_ec_public_key(ec),
118 }
119 }
120
121 fn random_ec_public_key(ec_pubkey: &EcPublicKeyInfo) -> Result<SubstData> {
122 let group = ecgroup_from_curve(&ec_pubkey.curve);
124 let privkey = EcKey::<Private>::generate(&group)?;
125 let mut ctx = BigNumContext::new()?;
126 let mut x = BigNum::new()?;
127 let mut y = BigNum::new()?;
128 let nbytes: i32 = group.degree().div_ceil(8) as i32;
129 privkey
130 .public_key()
131 .affine_coordinates(&group, &mut x, &mut y, &mut ctx)?;
132 let mut data = SubstData::new();
133 if let Value::Variable(Variable { name, convert }) = &ec_pubkey.public_key.x {
135 ensure!(
136 matches!(convert, None | Some(super::Conversion::BigEndian)),
137 "cannot generate a random public key if 'x' a variable with invalid conversion"
138 );
139 data.values.insert(
140 name.clone(),
141 SubstValue::ByteArray(x.to_vec_padded(nbytes)?),
142 );
143 }
144 if let Value::Variable(Variable { name, convert }) = &ec_pubkey.public_key.y {
145 ensure!(
146 matches!(convert, None | Some(super::Conversion::BigEndian)),
147 "cannot generate a random public key if 'y' a variable with invalid conversion"
148 );
149 data.values.insert(
150 name.clone(),
151 SubstValue::ByteArray(y.to_vec_padded(nbytes)?),
152 );
153 }
154 Ok(data)
155 }
156}