1use super::{unix_time::UnixTime, CertType, Certificate, Field, OptionsMap};
4use crate::{public, Result, Signature, SigningKey};
5use alloc::{string::String, vec::Vec};
6
7#[cfg(feature = "rand_core")]
8use rand_core::CryptoRngCore;
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 ) -> Result<Self> {
108 let valid_after =
109 UnixTime::new(valid_after).map_err(|_| Field::ValidAfter.invalid_error())?;
110
111 let valid_before =
112 UnixTime::new(valid_before).map_err(|_| Field::ValidBefore.invalid_error())?;
113
114 if valid_before < valid_after {
115 return Err(Field::ValidBefore.invalid_error());
116 }
117
118 Ok(Self {
119 nonce: nonce.into(),
120 public_key: public_key.into(),
121 serial: None,
122 cert_type: None,
123 key_id: None,
124 valid_principals: None,
125 valid_after,
126 valid_before,
127 critical_options: OptionsMap::new(),
128 extensions: OptionsMap::new(),
129 comment: None,
130 })
131 }
132
133 #[cfg(feature = "std")]
136 pub fn new_with_validity_times(
137 nonce: impl Into<Vec<u8>>,
138 public_key: impl Into<public::KeyData>,
139 valid_after: SystemTime,
140 valid_before: SystemTime,
141 ) -> Result<Self> {
142 let valid_after =
143 UnixTime::try_from(valid_after).map_err(|_| Field::ValidAfter.invalid_error())?;
144
145 let valid_before =
146 UnixTime::try_from(valid_before).map_err(|_| Field::ValidBefore.invalid_error())?;
147
148 Self::new(nonce, public_key, valid_after.into(), valid_before.into())
149 }
150
151 #[cfg(feature = "rand_core")]
154 pub fn new_with_random_nonce(
155 rng: &mut impl CryptoRngCore,
156 public_key: impl Into<public::KeyData>,
157 valid_after: u64,
158 valid_before: u64,
159 ) -> Result<Self> {
160 let mut nonce = vec![0u8; Self::RECOMMENDED_NONCE_SIZE];
161 rng.fill_bytes(&mut nonce);
162 Self::new(nonce, public_key, valid_after, valid_before)
163 }
164
165 pub fn serial(&mut self, serial: u64) -> Result<&mut Self> {
169 if self.serial.is_some() {
170 return Err(Field::Serial.invalid_error());
171 }
172
173 self.serial = Some(serial);
174 Ok(self)
175 }
176
177 pub fn cert_type(&mut self, cert_type: CertType) -> Result<&mut Self> {
181 if self.cert_type.is_some() {
182 return Err(Field::Type.invalid_error());
183 }
184
185 self.cert_type = Some(cert_type);
186 Ok(self)
187 }
188
189 pub fn key_id(&mut self, key_id: impl Into<String>) -> Result<&mut Self> {
193 if self.key_id.is_some() {
194 return Err(Field::KeyId.invalid_error());
195 }
196
197 self.key_id = Some(key_id.into());
198 Ok(self)
199 }
200
201 pub fn valid_principal(&mut self, principal: impl Into<String>) -> Result<&mut Self> {
203 match &mut self.valid_principals {
204 Some(principals) => principals.push(principal.into()),
205 None => self.valid_principals = Some(vec![principal.into()]),
206 }
207
208 Ok(self)
209 }
210
211 pub fn all_principals_valid(&mut self) -> Result<&mut Self> {
219 self.valid_principals = Some(Vec::new());
220 Ok(self)
221 }
222
223 pub fn critical_option(
227 &mut self,
228 name: impl Into<String>,
229 data: impl Into<String>,
230 ) -> Result<&mut Self> {
231 let name = name.into();
232 let data = data.into();
233
234 if self.critical_options.contains_key(&name) {
235 return Err(Field::CriticalOptions.invalid_error());
236 }
237
238 self.critical_options.insert(name, data);
239 Ok(self)
240 }
241
242 pub fn extension(
246 &mut self,
247 name: impl Into<String>,
248 data: impl Into<String>,
249 ) -> Result<&mut Self> {
250 let name = name.into();
251 let data = data.into();
252
253 if self.extensions.contains_key(&name) {
254 return Err(Field::Extensions.invalid_error());
255 }
256
257 self.extensions.insert(name, data);
258 Ok(self)
259 }
260
261 pub fn comment(&mut self, comment: impl Into<String>) -> Result<&mut Self> {
265 if self.comment.is_some() {
266 return Err(Field::Comment.invalid_error());
267 }
268
269 self.comment = Some(comment.into());
270 Ok(self)
271 }
272
273 pub fn sign<S: SigningKey>(self, signing_key: &S) -> Result<Certificate> {
277 let valid_principals = match self.valid_principals {
280 Some(principals) => principals,
281 None => return Err(Field::ValidPrincipals.invalid_error()),
282 };
283
284 let mut cert = Certificate {
285 nonce: self.nonce,
286 public_key: self.public_key,
287 serial: self.serial.unwrap_or_default(),
288 cert_type: self.cert_type.unwrap_or_default(),
289 key_id: self.key_id.unwrap_or_default(),
290 valid_principals,
291 valid_after: self.valid_after,
292 valid_before: self.valid_before,
293 critical_options: self.critical_options,
294 extensions: self.extensions,
295 reserved: Vec::new(),
296 comment: self.comment.unwrap_or_default(),
297 signature_key: signing_key.public_key(),
298 signature: Signature::placeholder(),
299 };
300
301 let mut tbs_cert = Vec::new();
302 cert.encode_tbs(&mut tbs_cert)?;
303 cert.signature = signing_key.try_sign(&tbs_cert)?;
304
305 #[cfg(debug_assertions)]
306 cert.validate_at(
307 cert.valid_after.into(),
308 &[cert.signature_key.fingerprint(Default::default())],
309 )?;
310
311 Ok(cert)
312 }
313}