1use crate::{
2 x509::{
3 AlgorithmIdentifierWrapper, DistinguishedName, GeneralNames, Oid,
4 SubjectPublicKeyInfoWrapper,
5 },
6 CryptoError, HasAlgorithmIdentifier, HasByteSource, HasPublicKey, Signer, SourceError,
7};
8use chrono::prelude::*;
9use rand::{thread_rng, Rng};
10use sha1::{Digest, Sha1};
11use std::{
12 convert::TryInto,
13 error::Error,
14 fmt::{self, Display, Formatter},
15};
16use x509::Extension;
17use der::Encodable;
18
19#[derive(Debug)]
20pub enum X509Error {
21 RandError { source: rand::Error },
23
24 SourceError { source: SourceError },
26
27 X509SerializationError { source: cookie_factory::GenError },
29
30 DerSerializationError { source: der::Error },
32
33 CryptoError { source: CryptoError },
35
36 SanTooLong { san: String },
38}
39
40impl Error for X509Error {
41 fn source(&self) -> Option<&(dyn Error + 'static)> {
42 match *self {
43 X509Error::RandError { ref source } => Some(source),
44 X509Error::SourceError { ref source } => Some(source),
45 X509Error::X509SerializationError { ref source } => Some(source),
46 X509Error::CryptoError { ref source } => Some(source),
47 X509Error::SanTooLong { .. } => None,
48 X509Error::DerSerializationError { .. } => None,
49 }
50 }
51}
52
53impl Display for X509Error {
54 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
55 match *self {
56 X509Error::RandError { .. } => {
57 write!(f, "Error occured during random number generation")
58 }
59 X509Error::SourceError { .. } => {
60 write!(f, "Error occured while handling a source")
61 }
62 X509Error::X509SerializationError { .. } => {
63 write!(f, "Error occured while serializing to x509")
64 }
65 X509Error::CryptoError { .. } => {
66 write!(f, "Error occured while performing a crypto operation")
67 }
68 X509Error::SanTooLong { ref san } => {
69 write!(f, "Provided SAN was too long: {}", san)
70 }
71 X509Error::DerSerializationError { source } => {
72 write!(f, "{}", source)
73 }
74 }
75 }
76}
77
78impl From<CryptoError> for X509Error {
79 fn from(e: CryptoError) -> Self {
80 X509Error::CryptoError { source: e }
81 }
82}
83
84pub fn setup_cert<
85 SK: Signer + HasPublicKey + HasByteSource + HasAlgorithmIdentifier,
86 BPK: HasByteSource + HasAlgorithmIdentifier,
87>(
88 issuer_key: &SK,
89 subject_key: Option<&BPK>,
90 issuer_dn: &DistinguishedName,
91 subject_dn: Option<&DistinguishedName>,
92 not_before: DateTime<Utc>,
93 not_after: DateTime<Utc>,
94 is_ca: bool,
95 subject_alternative_names: Option<&[&str]>,
96) -> Result<Vec<u8>, X509Error> {
97 let mut serial_number: [u8; 20] = [0; 20];
99 thread_rng()
100 .try_fill(&mut serial_number)
101 .map_err(|source| X509Error::RandError { source })?;
102
103 let signature_ai = AlgorithmIdentifierWrapper(issuer_key.algorithm_identifier());
105
106 let subject_key_ai = match subject_key {
108 Some(sk) => sk.algorithm_identifier(),
109 None => signature_ai.0,
110 };
111
112 let subject_key_bytes = match subject_key {
114 Some(sk) => sk.byte_source(),
115 None => issuer_key.public_key()?.byte_source(),
116 };
117
118 let spki = SubjectPublicKeyInfoWrapper(spki::SubjectPublicKeyInfo {
120 algorithm: subject_key_ai,
121 subject_public_key: subject_key_bytes
122 .get()
123 .map_err(|source| X509Error::SourceError { source })?,
124 });
125
126 let issuer_rdn: [x509::RelativeDistinguishedName; 3] = [
128 x509::RelativeDistinguishedName::organization(issuer_dn.o),
129 x509::RelativeDistinguishedName::organizational_unit(issuer_dn.ou),
130 x509::RelativeDistinguishedName::common_name(issuer_dn.cn),
131 ];
132 let subject_rdn: [x509::RelativeDistinguishedName; 3] = [
133 x509::RelativeDistinguishedName::organization(match subject_dn {
134 Some(dn) => dn.o,
135 None => issuer_dn.o,
136 }),
137 x509::RelativeDistinguishedName::organizational_unit(match subject_dn {
138 Some(dn) => dn.ou,
139 None => issuer_dn.ou,
140 }),
141 x509::RelativeDistinguishedName::common_name(match subject_dn {
142 Some(dn) => dn.cn,
143 None => issuer_dn.cn,
144 }),
145 ];
146
147 let mut sha1hasher = Sha1::new();
149 let mut extensions: Vec<Extension<Oid>> = vec![];
150
151 let subject_key_identifier_oid: Oid = Oid(vec![2, 5, 29, 14]);
153 sha1hasher.update(
154 subject_key_bytes
155 .get()
156 .map_err(|source| X509Error::SourceError { source })?,
157 );
158 let subject_key_hash = &sha1hasher.finalize_reset()[..];
159 let mut subject_key_identifier_value: Vec<u8> = vec![0x4, 0x14];
160 subject_key_identifier_value.extend_from_slice(subject_key_hash);
161 let ext_subject_key_identifier = Extension::regular(
162 subject_key_identifier_oid,
163 subject_key_identifier_value.as_slice(),
164 );
165 extensions.push(ext_subject_key_identifier);
166
167 let mut authority_key_identifier_value: Vec<u8> = vec![0x30, 0x16, 0x80, 0x14];
169 if subject_key.is_some() {
170 sha1hasher.update(
171 issuer_key
172 .public_key()?
173 .byte_source()
174 .get()
175 .map_err(|source| X509Error::SourceError { source })?,
176 );
177 let issuer_key_hash = &sha1hasher.finalize_reset()[..];
178 authority_key_identifier_value.extend_from_slice(issuer_key_hash);
179 let authority_key_identifier_oid: Oid = Oid(vec![2, 5, 29, 35]);
180 let ext_authority_key_identifier = Extension::regular(
181 authority_key_identifier_oid,
182 authority_key_identifier_value.as_slice(),
183 );
184 extensions.push(ext_authority_key_identifier);
185 }
186
187 let basic_constraints_oid: Oid = Oid(vec![2, 5, 29, 19]);
189 let mut basic_constraints_value: Vec<u8> = vec![0x30];
190 if is_ca {
191 basic_constraints_value.extend_from_slice(&[0x03, 0x01, 0x01, 0xFF]);
192 } else {
193 basic_constraints_value.extend_from_slice(&[0x00]);
194 }
195 let ext_basic_constraints =
196 Extension::critical(basic_constraints_oid, basic_constraints_value.as_slice());
197 extensions.push(ext_basic_constraints);
198
199 let key_usage_oid: Oid = Oid(vec![2, 5, 29, 15]);
201 let mut key_usage_value: Vec<u8> = vec![0x03, 0x02];
202 if is_ca {
203 key_usage_value.extend_from_slice(&[0x01, 0x06]);
204 } else {
205 key_usage_value.extend_from_slice(&[0x05, 0xA0]);
206 }
207 let ext_key_usage = Extension::critical(key_usage_oid, key_usage_value.as_slice());
208 extensions.push(ext_key_usage);
209
210 let mut extended_key_usage_value: Vec<u8> = vec![0x30, 0x14];
212 if !is_ca {
213 let extended_key_usage_oid: Oid = Oid(vec![2, 5, 29, 37]);
214 extended_key_usage_value.extend_from_slice(&[
215 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2B, 0x06,
216 0x01, 0x05, 0x05, 0x07, 0x03, 0x02,
217 ]);
218 let ext_extended_key_usage =
219 Extension::regular(extended_key_usage_oid, extended_key_usage_value.as_slice());
220 extensions.push(ext_extended_key_usage);
221 }
222
223 let mut sans_value = vec![];
225 if let Some(sans) = subject_alternative_names {
226 let sans: GeneralNames = sans
227 .try_into()
228 .map_err(|e| X509Error::DerSerializationError { source: e })?;
229 let sans_oid: Oid = Oid(vec![2, 5, 29, 17]);
230 let sans_bytes = sans
231 .to_vec()
232 .map_err(|e| X509Error::DerSerializationError { source: e })?;
233 sans_value.extend_from_slice(sans_bytes.as_slice());
234 let ext_sans = Extension::regular(sans_oid, sans_value.as_slice());
235 extensions.push(ext_sans);
236 }
237
238 let tbs_cert_vec: Vec<u8> = vec![];
240
241 let tbs_cert_fn = x509::write::tbs_certificate(
243 &serial_number,
244 &signature_ai,
245 &issuer_rdn,
246 not_before,
247 Some(not_after),
248 &subject_rdn,
249 &spki,
250 extensions.as_slice(),
251 );
252
253 let (tbs_cert_vec, _) = tbs_cert_fn(tbs_cert_vec.into())
255 .map_err(|source| X509Error::X509SerializationError { source })?
256 .into_inner();
257
258 let signature = issuer_key.sign(tbs_cert_vec.as_slice().into())?;
260
261 let cert_vec: Vec<u8> = vec![];
263
264 let cert_fn = x509::write::certificate(
267 &tbs_cert_vec,
268 &signature_ai,
269 signature
270 .get()
271 .map_err(|source| X509Error::SourceError { source })?,
272 );
273
274 let (cert_vec, _) = cert_fn(cert_vec.into())
276 .map_err(|source| X509Error::X509SerializationError { source })?
277 .into_inner();
278 Ok(cert_vec)
279}