redact_crypto/
cert.rs

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    /// Error happened during random number generation
22    RandError { source: rand::Error },
23
24    /// Error happened when handling a source
25    SourceError { source: SourceError },
26
27    /// Error happened during X509 serialization
28    X509SerializationError { source: cookie_factory::GenError },
29
30    /// Error happened during DER serialization
31    DerSerializationError { source: der::Error },
32
33    /// Error happened during a crypto operation
34    CryptoError { source: CryptoError },
35
36    /// Provided SAN was too long
37    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    // Generate a random 20-byte serial number
98    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    // Identify the issuer key algorithm
104    let signature_ai = AlgorithmIdentifierWrapper(issuer_key.algorithm_identifier());
105
106    // Identify the subject key algorithm
107    let subject_key_ai = match subject_key {
108        Some(sk) => sk.algorithm_identifier(),
109        None => signature_ai.0,
110    };
111
112    // Get the subject key bytes, either given or a self-signed cert
113    let subject_key_bytes = match subject_key {
114        Some(sk) => sk.byte_source(),
115        None => issuer_key.public_key()?.byte_source(),
116    };
117
118    // Define the SPKI block of the cert
119    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    // Define the issuer and subject RDNs
127    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    // Define x509v3 extensions
148    let mut sha1hasher = Sha1::new();
149    let mut extensions: Vec<Extension<Oid>> = vec![];
150
151    // Subject key identifier
152    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    // Authority key identifier
168    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    // Basic constraints
188    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    // Key usage
200    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    // Extended key usage
211    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    // SANs
224    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    // To-be-signed certificate bytes will be serialized into this vector
239    let tbs_cert_vec: Vec<u8> = vec![];
240
241    // Create the serialization function for the TBS certificate
242    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    // Generate the TBS cert bytes and write them to the vector
254    let (tbs_cert_vec, _) = tbs_cert_fn(tbs_cert_vec.into())
255        .map_err(|source| X509Error::X509SerializationError { source })?
256        .into_inner();
257
258    // Sign the TBS cert
259    let signature = issuer_key.sign(tbs_cert_vec.as_slice().into())?;
260
261    // Final certificate will be serialized into this vector
262    let cert_vec: Vec<u8> = vec![];
263
264    // Create the serialization function for the final certificate from the TBS
265    // certificate and the signature
266    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    // Generate the final certificate bytes and write them to the vector
275    let (cert_vec, _) = cert_fn(cert_vec.into())
276        .map_err(|source| X509Error::X509SerializationError { source })?
277        .into_inner();
278    Ok(cert_vec)
279}