1use super::{unix_time::UnixTime, CertType, Certificate, Field, OptionsMap, SigningKey};
4use crate::{public, Result, Signature};
5use alloc::{string::String, vec::Vec};
6
7#[cfg(feature = "rand_core")]
8use rand_core::{CryptoRng, RngCore};
9
10#[cfg(feature = "std")]
11use std::time::SystemTime;
12
13#[cfg(doc)]
14use crate::PrivateKey;
15
16#[cfg_attr(
38 all(feature = "ed25519", feature = "getrandom", feature = "std"),
39 doc = " ```"
40)]
41#[cfg_attr(
42 not(all(feature = "ed25519", feature = "getrandom", feature = "std")),
43 doc = " ```ignore"
44)]
45pub struct Builder {
81 public_key: public::KeyData,
82 nonce: Vec<u8>,
83 serial: Option<u64>,
84 cert_type: Option<CertType>,
85 key_id: Option<String>,
86 valid_principals: Option<Vec<String>>,
87 valid_after: UnixTime,
88 valid_before: UnixTime,
89 critical_options: OptionsMap,
90 extensions: OptionsMap,
91 comment: Option<String>,
92}
93
94impl Builder {
95 pub const RECOMMENDED_NONCE_SIZE: usize = 16;
97
98 pub fn new(
103 nonce: impl Into<Vec<u8>>,
104 public_key: impl Into<public::KeyData>,
105 valid_after: u64,
106 valid_before: u64,
107 ) -> Self {
108 let valid_after = UnixTime::new(valid_after).expect("valid_after time overflow");
111 let valid_before = UnixTime::new(valid_before).expect("valid_before time overflow");
112
113 Self {
114 nonce: nonce.into(),
115 public_key: public_key.into(),
116 serial: None,
117 cert_type: None,
118 key_id: None,
119 valid_principals: None,
120 valid_after,
121 valid_before,
122 critical_options: OptionsMap::new(),
123 extensions: OptionsMap::new(),
124 comment: None,
125 }
126 }
127
128 #[cfg(feature = "std")]
131 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
132 pub fn new_with_validity_times(
133 nonce: impl Into<Vec<u8>>,
134 public_key: impl Into<public::KeyData>,
135 valid_after: SystemTime,
136 valid_before: SystemTime,
137 ) -> Result<Self> {
138 let valid_after =
139 UnixTime::try_from(valid_after).map_err(|_| Field::ValidAfter.invalid_error())?;
140
141 let valid_before =
142 UnixTime::try_from(valid_before).map_err(|_| Field::ValidBefore.invalid_error())?;
143
144 if valid_before < valid_after {
146 return Err(Field::ValidBefore.invalid_error());
147 }
148
149 Ok(Self::new(
150 nonce,
151 public_key,
152 valid_before.into(),
153 valid_after.into(),
154 ))
155 }
156
157 #[cfg(feature = "rand_core")]
160 #[cfg_attr(docsrs, doc(cfg(feature = "rand_core")))]
161 pub fn new_with_random_nonce(
162 mut rng: impl CryptoRng + RngCore,
163 public_key: impl Into<public::KeyData>,
164 valid_after: u64,
165 valid_before: u64,
166 ) -> Self {
167 let mut nonce = vec![0u8; Self::RECOMMENDED_NONCE_SIZE];
168 rng.fill_bytes(&mut nonce);
169 Self::new(nonce, public_key, valid_after, valid_before)
170 }
171
172 pub fn serial(&mut self, serial: u64) -> Result<&mut Self> {
176 if self.serial.is_some() {
177 return Err(Field::Serial.invalid_error());
178 }
179
180 self.serial = Some(serial);
181 Ok(self)
182 }
183
184 pub fn cert_type(&mut self, cert_type: CertType) -> Result<&mut Self> {
188 if self.cert_type.is_some() {
189 return Err(Field::Type.invalid_error());
190 }
191
192 self.cert_type = Some(cert_type);
193 Ok(self)
194 }
195
196 pub fn key_id(&mut self, key_id: impl Into<String>) -> Result<&mut Self> {
200 if self.key_id.is_some() {
201 return Err(Field::KeyId.invalid_error());
202 }
203
204 self.key_id = Some(key_id.into());
205 Ok(self)
206 }
207
208 pub fn valid_principal(&mut self, principal: impl Into<String>) -> Result<&mut Self> {
210 match &mut self.valid_principals {
211 Some(principals) => principals.push(principal.into()),
212 None => self.valid_principals = Some(vec![principal.into()]),
213 }
214
215 Ok(self)
216 }
217
218 pub fn all_principals_valid(&mut self) -> Result<&mut Self> {
226 self.valid_principals = Some(Vec::new());
227 Ok(self)
228 }
229
230 pub fn critical_option(
234 &mut self,
235 name: impl Into<String>,
236 data: impl Into<String>,
237 ) -> Result<&mut Self> {
238 let name = name.into();
239 let data = data.into();
240
241 if self.critical_options.contains_key(&name) {
242 return Err(Field::CriticalOptions.invalid_error());
243 }
244
245 self.critical_options.insert(name, data);
246 Ok(self)
247 }
248
249 pub fn extension(
253 &mut self,
254 name: impl Into<String>,
255 data: impl Into<String>,
256 ) -> Result<&mut Self> {
257 let name = name.into();
258 let data = data.into();
259
260 if self.extensions.contains_key(&name) {
261 return Err(Field::Extensions.invalid_error());
262 }
263
264 self.extensions.insert(name, data);
265 Ok(self)
266 }
267
268 pub fn comment(&mut self, comment: impl Into<String>) -> Result<&mut Self> {
272 if self.comment.is_some() {
273 return Err(Field::Comment.invalid_error());
274 }
275
276 self.comment = Some(comment.into());
277 Ok(self)
278 }
279
280 pub fn sign<S: SigningKey>(self, signing_key: &S) -> Result<Certificate> {
284 let valid_principals = match self.valid_principals {
287 Some(principals) => principals,
288 None => return Err(Field::ValidPrincipals.invalid_error()),
289 };
290
291 let mut cert = Certificate {
292 nonce: self.nonce,
293 public_key: self.public_key,
294 serial: self.serial.unwrap_or_default(),
295 cert_type: self.cert_type.unwrap_or_default(),
296 key_id: self.key_id.unwrap_or_default(),
297 valid_principals,
298 valid_after: self.valid_after,
299 valid_before: self.valid_before,
300 critical_options: self.critical_options,
301 extensions: self.extensions,
302 reserved: Vec::new(),
303 comment: self.comment.unwrap_or_default(),
304 signature_key: signing_key.public_key(),
305 signature: Signature::placeholder(),
306 };
307
308 let mut tbs_cert = Vec::new();
309 cert.encode_tbs(&mut tbs_cert)?;
310 cert.signature = signing_key.try_sign(&tbs_cert)?;
311
312 #[cfg(all(debug_assertions, feature = "fingerprint"))]
313 cert.validate_at(
314 cert.valid_after.into(),
315 &[cert.signature_key.fingerprint(Default::default())],
316 )?;
317
318 Ok(cert)
319 }
320}