1use super::{CertType, Certificate, Field, OptionsMap};
4use crate::{Result, Signature, SigningKey, public};
5use alloc::{string::String, vec::Vec};
6
7#[cfg(feature = "rand_core")]
8use rand_core::CryptoRng;
9
10#[cfg(feature = "std")]
11use {super::UnixTime, 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: u64,
88 valid_before: u64,
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 if valid_before < valid_after {
109 return Err(Field::ValidBefore.invalid_error());
110 }
111
112 Ok(Self {
113 nonce: nonce.into(),
114 public_key: public_key.into(),
115 serial: None,
116 cert_type: None,
117 key_id: None,
118 valid_principals: None,
119 valid_after,
120 valid_before,
121 critical_options: OptionsMap::new(),
122 extensions: OptionsMap::new(),
123 comment: None,
124 })
125 }
126
127 #[cfg(feature = "std")]
130 pub fn new_with_validity_times(
131 nonce: impl Into<Vec<u8>>,
132 public_key: impl Into<public::KeyData>,
133 valid_after: SystemTime,
134 valid_before: SystemTime,
135 ) -> Result<Self> {
136 let valid_after =
137 UnixTime::try_from(valid_after).map_err(|_| Field::ValidAfter.invalid_error())?;
138
139 let valid_before =
140 UnixTime::try_from(valid_before).map_err(|_| Field::ValidBefore.invalid_error())?;
141
142 Self::new(nonce, public_key, valid_after.into(), valid_before.into())
143 }
144
145 #[cfg(feature = "rand_core")]
148 pub fn new_with_random_nonce(
149 rng: &mut impl CryptoRng,
150 public_key: impl Into<public::KeyData>,
151 valid_after: u64,
152 valid_before: u64,
153 ) -> Result<Self> {
154 let mut nonce = vec![0u8; Self::RECOMMENDED_NONCE_SIZE];
155 rng.fill_bytes(&mut nonce);
156 Self::new(nonce, public_key, valid_after, valid_before)
157 }
158
159 pub fn serial(&mut self, serial: u64) -> Result<&mut Self> {
163 if self.serial.is_some() {
164 return Err(Field::Serial.invalid_error());
165 }
166
167 self.serial = Some(serial);
168 Ok(self)
169 }
170
171 pub fn cert_type(&mut self, cert_type: CertType) -> Result<&mut Self> {
175 if self.cert_type.is_some() {
176 return Err(Field::Type.invalid_error());
177 }
178
179 self.cert_type = Some(cert_type);
180 Ok(self)
181 }
182
183 pub fn key_id(&mut self, key_id: impl Into<String>) -> Result<&mut Self> {
187 if self.key_id.is_some() {
188 return Err(Field::KeyId.invalid_error());
189 }
190
191 self.key_id = Some(key_id.into());
192 Ok(self)
193 }
194
195 pub fn valid_principal(&mut self, principal: impl Into<String>) -> Result<&mut Self> {
197 match &mut self.valid_principals {
198 Some(principals) => principals.push(principal.into()),
199 None => self.valid_principals = Some(vec![principal.into()]),
200 }
201
202 Ok(self)
203 }
204
205 pub fn all_principals_valid(&mut self) -> Result<&mut Self> {
213 self.valid_principals = Some(Vec::new());
214 Ok(self)
215 }
216
217 pub fn critical_option(
221 &mut self,
222 name: impl Into<String>,
223 data: impl Into<String>,
224 ) -> Result<&mut Self> {
225 let name = name.into();
226 let data = data.into();
227
228 if self.critical_options.contains_key(&name) {
229 return Err(Field::CriticalOptions.invalid_error());
230 }
231
232 self.critical_options.insert(name, data);
233 Ok(self)
234 }
235
236 pub fn extension(
240 &mut self,
241 name: impl Into<String>,
242 data: impl Into<String>,
243 ) -> Result<&mut Self> {
244 let name = name.into();
245 let data = data.into();
246
247 if self.extensions.contains_key(&name) {
248 return Err(Field::Extensions.invalid_error());
249 }
250
251 self.extensions.insert(name, data);
252 Ok(self)
253 }
254
255 pub fn comment(&mut self, comment: impl Into<String>) -> Result<&mut Self> {
259 if self.comment.is_some() {
260 return Err(Field::Comment.invalid_error());
261 }
262
263 self.comment = Some(comment.into());
264 Ok(self)
265 }
266
267 pub fn sign<S: SigningKey>(self, signing_key: &S) -> Result<Certificate> {
271 let valid_principals = match self.valid_principals {
274 Some(principals) => principals,
275 None => return Err(Field::ValidPrincipals.invalid_error()),
276 };
277
278 let mut cert = Certificate {
279 nonce: self.nonce,
280 public_key: self.public_key,
281 serial: self.serial.unwrap_or_default(),
282 cert_type: self.cert_type.unwrap_or_default(),
283 key_id: self.key_id.unwrap_or_default(),
284 valid_principals,
285 valid_after: self.valid_after,
286 valid_before: self.valid_before,
287 critical_options: self.critical_options,
288 extensions: self.extensions,
289 reserved: Vec::new(),
290 comment: self.comment.unwrap_or_default(),
291 signature_key: signing_key.public_key(),
292 signature: Signature::placeholder(),
293 };
294
295 let mut tbs_cert = Vec::new();
296 cert.encode_tbs(&mut tbs_cert)?;
297 cert.signature = signing_key.try_sign(&tbs_cert)?;
298
299 #[cfg(debug_assertions)]
300 cert.validate_at(
301 cert.valid_after,
302 &[cert.signature_key.fingerprint(Default::default())],
303 )?;
304
305 Ok(cert)
306 }
307}