kanidmd_core/
crypto.rs

1//! This module contains cryptographic setup code, a long with what policy
2//! and ciphers we accept.
3
4use openssl::ec::{EcGroup, EcKey};
5use openssl::error::ErrorStack;
6use openssl::nid::Nid;
7use openssl::rsa::Rsa;
8use openssl::x509::{
9    extension::{
10        AuthorityKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage,
11        SubjectAlternativeName, SubjectKeyIdentifier,
12    },
13    X509NameBuilder, X509ReqBuilder, X509,
14};
15use openssl::{asn1, bn, hash, pkey};
16
17// use sketching::*;
18use crate::config::TlsConfiguration;
19use crypto_glue::{
20    pkcs8::PrivateKeyInfo,
21    rsa::RS256PrivateKey,
22    traits::{DecodeDer, Pkcs1DecodeRsaPrivateKey, PublicKeyParts},
23    x509::oiddb::rfc5912,
24};
25use rustls::{
26    pki_types::{pem::PemObject, CertificateDer, CertificateRevocationListDer, PrivateKeyDer},
27    server::{ServerConfig, WebPkiClientVerifier},
28    RootCertStore,
29};
30use sec1::EcPrivateKey;
31use std::fs;
32use std::io::{Read, Write};
33use std::path::Path;
34use std::sync::Arc;
35use tokio_rustls::TlsAcceptor;
36
37const CA_VALID_DAYS: u32 = 30;
38const CERT_VALID_DAYS: u32 = 5;
39
40// Basing minimums off https://www.keylength.com setting "year" to 2030 - tested as at 2023-09-25
41//
42// |Method           |Date     |Symmetric| FM      |DL Key| DL Group|Elliptic Curve|Hash|
43// |   ---           |   ---   |   ---   |   ---   | ---  |   ---   |  ---         | ---|
44// |Lenstra / Verheul|2030     |  93     |2493^2016|165   | 2493    |  176         | 186|
45// |Lenstra Updated  |2030     |  88     |1698^2063|176   | 1698    |  176         | 176|
46// |ECRYPT           |2029-2068|  256    |15360    |512   | 15360   |  512         | 512|
47// |NIST             |2019-2030|  112    |2048     |224   | 2048    |  224         | 224|
48// |ANSSI            |> 2030   |  128    |3072     |200   | 3072    |  256         | 256|
49// |NSA              |-        |  256    |3072     |-     | -       |  384         | 384|
50// |RFC3766          |-        |  -      |   -     | -    |   -     |   -          |  - |
51// |BSI              |-        |  -      |   -     | -    |   -     |   -          |  - |
52// DL - Discrete Logarithm
53// FM - Factoring Modulus
54
55const RSA_MIN_KEY_SIZE_BITS: u64 = 2048;
56const EC_MIN_KEY_SIZE_BITS: u64 = 224;
57
58/// returns a signing function that meets a sensible minimum
59fn get_signing_func() -> hash::MessageDigest {
60    hash::MessageDigest::sha256()
61}
62
63/// Ensure we're enforcing safe minimums for TLS keys
64pub fn check_privkey_minimums(privkey: &PrivateKeyDer<'_>) -> Result<(), String> {
65    match privkey {
66        PrivateKeyDer::Pkcs8(pkcs8_der) => {
67            let private_key_info = PrivateKeyInfo::try_from(pkcs8_der.secret_pkcs8_der())
68                .map_err(|_err| "Invalid pkcs8 der".to_string())?;
69
70            let oids = private_key_info
71                .algorithm
72                .oids()
73                .map_err(|_err| "Invalid pkcs8 key oids".to_string())?;
74
75            match oids {
76                (rfc5912::ID_EC_PUBLIC_KEY, Some(rfc5912::SECP_256_R_1)) => {
77                    debug!("The EC private key size is: 256 bits, that's OK!");
78                    Ok(())
79                }
80                (rfc5912::ID_EC_PUBLIC_KEY, Some(rfc5912::SECP_384_R_1)) => {
81                    debug!("The EC private key size is: 384 bits, that's OK!");
82                    Ok(())
83                }
84                (rfc5912::RSA_ENCRYPTION, None) => {
85                    let priv_key = RS256PrivateKey::try_from(private_key_info)
86                        .map_err(|_err| "Invalid rsa key".to_string())?;
87
88                    let priv_key_bits = priv_key.size() * 8;
89
90                    if priv_key_bits < RSA_MIN_KEY_SIZE_BITS as usize {
91                        Err(format!(
92                            "TLS RSA key is less than {RSA_MIN_KEY_SIZE_BITS} bits!"
93                        ))
94                    } else {
95                        debug!(
96                            "The RSA private key size is: {} bits, that's OK!",
97                            priv_key_bits
98                        );
99                        Ok(())
100                    }
101                }
102                _ => Err("TLS Private Key Oids not understood".into()),
103            }
104        }
105        PrivateKeyDer::Sec1(sec1_der) => {
106            // ECDSA only
107            let priv_key = EcPrivateKey::from_der(sec1_der.secret_sec1_der())
108                .map_err(|_err| "Invalid sec1 der".to_string())?;
109
110            match priv_key.parameters.and_then(|params| params.named_curve()) {
111                Some(rfc5912::SECP_256_R_1) => {
112                    debug!("The EC private key size is: 256 bits, that's OK!");
113                    Ok(())
114                }
115                Some(rfc5912::SECP_384_R_1) => {
116                    debug!("The EC private key size is: 384 bits, that's OK!");
117                    Ok(())
118                }
119                Some(_) => Err("TLS Private Key Oids not understood".into()),
120                None => Err("TLS Private Key has no oids".into()),
121            }
122        }
123        PrivateKeyDer::Pkcs1(pkcs1_der) => {
124            // RSA only
125            let priv_key = RS256PrivateKey::from_pkcs1_der(pkcs1_der.secret_pkcs1_der())
126                .map_err(|_err| "Invalid pkcs1 der".to_string())?;
127
128            let priv_key_bits = priv_key.size() * 8;
129
130            if priv_key_bits < RSA_MIN_KEY_SIZE_BITS as usize {
131                Err(format!(
132                    "TLS RSA key is less than {RSA_MIN_KEY_SIZE_BITS} bits!"
133                ))
134            } else {
135                debug!(
136                    "The RSA private key size is: {} bits, that's OK!",
137                    priv_key_bits
138                );
139                Ok(())
140            }
141        }
142        _ => Err("TLS Private Key Format not understood".into()),
143    }
144}
145
146/// From the server configuration, generate an OpenSSL acceptor that we can use
147/// to build our sockets for HTTPS/LDAPS.
148pub fn setup_tls(
149    tls_config: &Option<TlsConfiguration>,
150) -> Result<Option<TlsAcceptor>, std::io::Error> {
151    let Some(tls_param) = tls_config.as_ref() else {
152        return Ok(None);
153    };
154
155    let cert_iter = CertificateDer::pem_file_iter(&tls_param.chain)
156        .map_err(|err| std::io::Error::other(format!("Failed to create TLS listener: {err:?}")))?;
157
158    let cert_chain_der = cert_iter
159        .collect::<Result<Vec<_>, _>>()
160        .map_err(|err| std::io::Error::other(format!("Failed to create TLS listener: {err:?}")))?;
161
162    let private_key_der = PrivateKeyDer::from_pem_file(&tls_param.key)
163        .map_err(|err| std::io::Error::other(format!("Failed to create TLS listener: {err:?}")))?;
164
165    check_privkey_minimums(&private_key_der).map_err(|err| {
166        std::io::Error::other(format!("Private key minimums were not met: {err:?}"))
167    })?;
168
169    // Configure the rustls cryptoprovider. We currently use aws-lc-rc as the
170    // default. We may swap to rustcrypto in future.
171    let provider: Arc<_> = rustls::crypto::aws_lc_rs::default_provider().into();
172
173    let client_cert_verifier = if let Some(client_ca) = tls_param.client_ca.as_ref() {
174        info!("Loading client certificates from {}", client_ca.display());
175
176        let read_dir = fs::read_dir(client_ca).map_err(|err| {
177            std::io::Error::other(format!(
178                "Failed to create TLS listener while loading client ca from {}: {:?}",
179                client_ca.display(),
180                err
181            ))
182        })?;
183
184        let dirents: Vec<_> = read_dir.filter_map(|item| item.ok()).collect();
185
186        let mut client_cert_roots = RootCertStore::empty();
187
188        for cert_dir_ent in dirents.iter().filter(|item| {
189            item.file_name()
190                .to_str()
191                // Hashed certs end in .0
192                // Hashed crls are .r0
193                .map(|fname| fname.ends_with(".0"))
194                .unwrap_or_default()
195        }) {
196            let cert_pem = CertificateDer::from_pem_file(cert_dir_ent.path()).map_err(|err| {
197                std::io::Error::other(format!("Failed to create TLS listener: {err:?}"))
198            })?;
199
200            client_cert_roots.add(cert_pem).map_err(|err| {
201                std::io::Error::other(format!("Failed to create TLS listener: {err:?}"))
202            })?;
203        }
204
205        let mut client_cert_crls = Vec::new();
206
207        for cert_dir_ent in dirents.iter().filter(|item| {
208            item.file_name()
209                .to_str()
210                // Hashed certs end in .0
211                // Hashed crls are .r0
212                .map(|fname| fname.ends_with(".r0"))
213                .unwrap_or_default()
214        }) {
215            let cert_pem = CertificateRevocationListDer::from_pem_file(cert_dir_ent.path())
216                .map_err(|err| {
217                    std::io::Error::other(format!("Failed to create TLS listener: {err:?}"))
218                })?;
219
220            client_cert_crls.push(cert_pem);
221        }
222
223        WebPkiClientVerifier::builder_with_provider(client_cert_roots.into(), provider.clone())
224            .with_crls(client_cert_crls)
225            .allow_unauthenticated()
226            .build()
227            .map_err(|err| {
228                std::io::Error::other(format!("Failed to create TLS listener: {err:?}"))
229            })?
230    } else {
231        WebPkiClientVerifier::no_client_auth()
232    };
233
234    let tls_server_config = ServerConfig::builder_with_provider(provider)
235        .with_safe_default_protocol_versions()
236        .and_then(|builder| {
237            builder
238                .with_client_cert_verifier(client_cert_verifier)
239                .with_single_cert(cert_chain_der, private_key_der)
240        })
241        .map_err(|err| std::io::Error::other(format!("Failed to create TLS listener: {err:?}")))?;
242
243    let tls_acceptor = TlsAcceptor::from(Arc::new(tls_server_config));
244
245    Ok(Some(tls_acceptor))
246}
247
248fn get_ec_group() -> Result<EcGroup, ErrorStack> {
249    EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)
250}
251
252#[derive(Debug)]
253pub(crate) struct CaHandle {
254    key: pkey::PKey<pkey::Private>,
255    cert: X509,
256}
257
258pub(crate) fn write_ca(
259    key_ar: impl AsRef<Path>,
260    cert_ar: impl AsRef<Path>,
261    handle: &CaHandle,
262) -> Result<(), ()> {
263    let key_path: &Path = key_ar.as_ref();
264    let cert_path: &Path = cert_ar.as_ref();
265
266    let key_pem = handle.key.private_key_to_pem_pkcs8().map_err(|e| {
267        error!(err = ?e, "Failed to convert key to PEM");
268    })?;
269
270    let cert_pem = handle.cert.to_pem().map_err(|e| {
271        error!(err = ?e, "Failed to convert cert to PEM");
272    })?;
273
274    fs::File::create(key_path)
275        .and_then(|mut file| file.write_all(&key_pem))
276        .map_err(|e| {
277            error!(err = ?e, "Failed to create {:?}", key_path);
278        })?;
279
280    fs::File::create(cert_path)
281        .and_then(|mut file| file.write_all(&cert_pem))
282        .map_err(|e| {
283            error!(err = ?e, "Failed to create {:?}", cert_path);
284        })
285}
286
287#[derive(Debug)]
288pub enum KeyType {
289    #[allow(dead_code)]
290    Rsa,
291    Ec,
292}
293impl Default for KeyType {
294    fn default() -> Self {
295        Self::Ec
296    }
297}
298
299#[derive(Debug)]
300pub struct CAConfig {
301    pub key_type: KeyType,
302    pub key_bits: u64,
303    #[allow(dead_code)]
304    pub skip_enforce_minimums: bool,
305}
306
307impl Default for CAConfig {
308    fn default() -> Self {
309        #[allow(clippy::expect_used)]
310        Self::new(KeyType::Ec, 256, false)
311            .expect("Somehow the defaults failed to pass validation while building a CA Config?")
312    }
313}
314
315impl CAConfig {
316    fn new(key_type: KeyType, key_bits: u64, skip_enforce_minimums: bool) -> Result<Self, String> {
317        let res = Self {
318            key_type,
319            key_bits,
320            skip_enforce_minimums,
321        };
322        if !skip_enforce_minimums {
323            res.enforce_minimums()?;
324        };
325        Ok(res)
326    }
327
328    /// Make sure we're meeting the minimum spec for key length etc
329    fn enforce_minimums(&self) -> Result<(), String> {
330        match self.key_type {
331            KeyType::Rsa => {
332                trace!(
333                    "Generating CA Config for RSA Key with {} bits",
334                    self.key_bits
335                );
336                if self.key_bits < RSA_MIN_KEY_SIZE_BITS {
337                    return Err(format!(
338                        "RSA key size must be at least {RSA_MIN_KEY_SIZE_BITS} bits"
339                    ));
340                }
341            }
342            KeyType::Ec => {
343                trace!("Generating CA Config for EcKey with {} bits", self.key_bits);
344                if self.key_bits < EC_MIN_KEY_SIZE_BITS {
345                    return Err(format!(
346                        "EC key size must be at least {EC_MIN_KEY_SIZE_BITS} bits"
347                    ));
348                }
349            }
350        };
351        Ok(())
352    }
353}
354
355pub(crate) fn gen_private_key(
356    key_type: &KeyType,
357    key_bits: Option<u64>,
358) -> Result<pkey::PKey<pkey::Private>, ErrorStack> {
359    match key_type {
360        KeyType::Rsa => {
361            let key_bits = key_bits.unwrap_or(RSA_MIN_KEY_SIZE_BITS);
362            let rsa = Rsa::generate(key_bits as u32)?;
363            pkey::PKey::from_rsa(rsa)
364        }
365        KeyType::Ec => {
366            // TODO: take key bitlength and use it for the curve group, somehow?
367            let ecgroup = get_ec_group()?;
368            let eckey = EcKey::generate(&ecgroup)?;
369            pkey::PKey::from_ec_key(eckey)
370        }
371    }
372}
373
374/// build up a CA certificate and key.
375pub(crate) fn build_ca(ca_config: Option<CAConfig>) -> Result<CaHandle, ErrorStack> {
376    // We never actually call ca_config from any external input, it's fully internal
377    // and controlled by us. Should we remove ca_config instead?
378    let ca_config = ca_config.unwrap_or_default();
379
380    // We don't need to check minimums here because we are the ones generating the key.
381    let ca_key = gen_private_key(&ca_config.key_type, Some(ca_config.key_bits))?;
382
383    let mut x509_name = X509NameBuilder::new()?;
384
385    x509_name.append_entry_by_text("C", "AU")?;
386    x509_name.append_entry_by_text("ST", "QLD")?;
387    x509_name.append_entry_by_text("O", "Kanidm")?;
388    x509_name.append_entry_by_text("CN", "Kanidm Generated CA")?;
389    x509_name.append_entry_by_text("OU", "Development and Evaluation - NOT FOR PRODUCTION")?;
390    let x509_name = x509_name.build();
391
392    let mut cert_builder = X509::builder()?;
393    // Yes, 2 actually means 3 here ...
394    cert_builder.set_version(2)?;
395
396    let serial_number = bn::BigNum::from_u32(1).and_then(|serial| serial.to_asn1_integer())?;
397
398    cert_builder.set_serial_number(&serial_number)?;
399    cert_builder.set_subject_name(&x509_name)?;
400    cert_builder.set_issuer_name(&x509_name)?;
401
402    let not_before = asn1::Asn1Time::days_from_now(0)?;
403    cert_builder.set_not_before(&not_before)?;
404    let not_after = asn1::Asn1Time::days_from_now(CA_VALID_DAYS)?;
405    cert_builder.set_not_after(&not_after)?;
406
407    cert_builder.append_extension(BasicConstraints::new().critical().ca().pathlen(0).build()?)?;
408    cert_builder.append_extension(
409        KeyUsage::new()
410            .critical()
411            .key_cert_sign()
412            .crl_sign()
413            .build()?,
414    )?;
415
416    let subject_key_identifier =
417        SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(None, None))?;
418    cert_builder.append_extension(subject_key_identifier)?;
419
420    cert_builder.set_pubkey(&ca_key)?;
421
422    cert_builder.sign(&ca_key, get_signing_func())?;
423    let ca_cert = cert_builder.build();
424
425    Ok(CaHandle {
426        key: ca_key,
427        cert: ca_cert,
428    })
429}
430
431pub(crate) fn load_ca(
432    ca_key_ar: impl AsRef<Path>,
433    ca_cert_ar: impl AsRef<Path>,
434) -> Result<CaHandle, ()> {
435    let ca_key_path: &Path = ca_key_ar.as_ref();
436    let ca_cert_path: &Path = ca_cert_ar.as_ref();
437
438    let mut ca_key_pem = vec![];
439    fs::File::open(ca_key_path)
440        .and_then(|mut file| file.read_to_end(&mut ca_key_pem))
441        .map_err(|e| {
442            error!(err = ?e, "Failed to read {:?}", ca_key_path);
443        })?;
444
445    let mut ca_cert_pem = vec![];
446    fs::File::open(ca_cert_path)
447        .and_then(|mut file| file.read_to_end(&mut ca_cert_pem))
448        .map_err(|e| {
449            error!(err = ?e, "Failed to read {:?}", ca_cert_path);
450        })?;
451
452    let ca_key = pkey::PKey::private_key_from_pem(&ca_key_pem).map_err(|e| {
453        error!(err = ?e, "Failed to convert PEM to key");
454    })?;
455
456    /*
457    check_privkey_minimums(&ca_key).map_err(|err| {
458        #[cfg(any(test, debug_assertions))]
459        println!("{:?}", err);
460        admin_error!("{}", err);
461    })?;
462    */
463
464    let ca_cert = X509::from_pem(&ca_cert_pem).map_err(|e| {
465        error!(err = ?e, "Failed to convert PEM to cert");
466    })?;
467
468    Ok(CaHandle {
469        key: ca_key,
470        cert: ca_cert,
471    })
472}
473
474pub(crate) struct CertHandle {
475    key: pkey::PKey<pkey::Private>,
476    cert: X509,
477    chain: Vec<X509>,
478}
479
480pub(crate) fn write_cert(
481    key_ar: impl AsRef<Path>,
482    chain_ar: impl AsRef<Path>,
483    cert_ar: impl AsRef<Path>,
484    handle: &CertHandle,
485) -> Result<(), ()> {
486    let key_path: &Path = key_ar.as_ref();
487    let chain_path: &Path = chain_ar.as_ref();
488    let cert_path: &Path = cert_ar.as_ref();
489
490    let key_pem = handle.key.private_key_to_pem_pkcs8().map_err(|e| {
491        error!(err = ?e, "Failed to convert key to PEM");
492    })?;
493
494    let cert_pem = handle.cert.to_pem().map_err(|e| {
495        error!(err = ?e, "Failed to convert cert to PEM");
496    })?;
497
498    let mut chain_pem = cert_pem.clone();
499
500    // Build the chain PEM.
501    for ca_cert in &handle.chain {
502        match ca_cert.to_pem() {
503            Ok(c) => {
504                chain_pem.extend_from_slice(&c);
505            }
506            Err(e) => {
507                error!(err = ?e, "Failed to convert cert to PEM");
508                return Err(());
509            }
510        }
511    }
512
513    fs::File::create(key_path)
514        .and_then(|mut file| file.write_all(&key_pem))
515        .map_err(|e| {
516            error!(err = ?e, "Failed to create {:?}", key_path);
517        })?;
518
519    fs::File::create(chain_path)
520        .and_then(|mut file| file.write_all(&chain_pem))
521        .map_err(|e| {
522            error!(err = ?e, "Failed to create {:?}", chain_path);
523        })?;
524
525    fs::File::create(cert_path)
526        .and_then(|mut file| file.write_all(&cert_pem))
527        .map_err(|e| {
528            error!(err = ?e, "Failed to create {:?}", cert_path);
529        })
530}
531
532pub(crate) fn build_cert(
533    domain_name: &str,
534    ca_handle: &CaHandle,
535    key_type: Option<KeyType>,
536    key_bits: Option<u64>,
537) -> Result<CertHandle, ErrorStack> {
538    let key_type = key_type.unwrap_or_default();
539    let int_key = gen_private_key(&key_type, key_bits)?;
540
541    let mut req_builder = X509ReqBuilder::new()?;
542    req_builder.set_pubkey(&int_key)?;
543
544    let mut x509_name = X509NameBuilder::new()?;
545    x509_name.append_entry_by_text("C", "AU")?;
546    x509_name.append_entry_by_text("ST", "QLD")?;
547    x509_name.append_entry_by_text("O", "Kanidm")?;
548    x509_name.append_entry_by_text("CN", domain_name)?;
549    // Requirement of packed attestation.
550    x509_name.append_entry_by_text("OU", "Development and Evaluation - NOT FOR PRODUCTION")?;
551    let x509_name = x509_name.build();
552
553    req_builder.set_subject_name(&x509_name)?;
554    req_builder.sign(&int_key, get_signing_func())?;
555    let req = req_builder.build();
556    // ==
557
558    let mut cert_builder = X509::builder()?;
559    // Yes, 2 actually means 3 here ...
560    cert_builder.set_version(2)?;
561    let serial_number = bn::BigNum::from_u32(2).and_then(|serial| serial.to_asn1_integer())?;
562
563    cert_builder.set_pubkey(&int_key)?;
564
565    cert_builder.set_serial_number(&serial_number)?;
566    cert_builder.set_subject_name(req.subject_name())?;
567    cert_builder.set_issuer_name(ca_handle.cert.subject_name())?;
568
569    let not_before = asn1::Asn1Time::days_from_now(0)?;
570    cert_builder.set_not_before(&not_before)?;
571    let not_after = asn1::Asn1Time::days_from_now(CERT_VALID_DAYS)?;
572    cert_builder.set_not_after(&not_after)?;
573
574    cert_builder.append_extension(BasicConstraints::new().build()?)?;
575
576    cert_builder.append_extension(
577        KeyUsage::new()
578            .critical()
579            .digital_signature()
580            .key_encipherment()
581            .build()?,
582    )?;
583
584    cert_builder.append_extension(
585        ExtendedKeyUsage::new()
586            // .critical()
587            .server_auth()
588            .build()?,
589    )?;
590
591    let subject_key_identifier = SubjectKeyIdentifier::new()
592        .build(&cert_builder.x509v3_context(Some(&ca_handle.cert), None))?;
593    cert_builder.append_extension(subject_key_identifier)?;
594
595    let auth_key_identifier = AuthorityKeyIdentifier::new()
596        .keyid(false)
597        .issuer(false)
598        .build(&cert_builder.x509v3_context(Some(&ca_handle.cert), None))?;
599    cert_builder.append_extension(auth_key_identifier)?;
600
601    let subject_alt_name = SubjectAlternativeName::new()
602        .dns(domain_name)
603        .build(&cert_builder.x509v3_context(Some(&ca_handle.cert), None))?;
604    cert_builder.append_extension(subject_alt_name)?;
605
606    cert_builder.sign(&ca_handle.key, get_signing_func())?;
607    let int_cert = cert_builder.build();
608
609    Ok(CertHandle {
610        key: int_key,
611        cert: int_cert,
612        chain: vec![ca_handle.cert.clone()],
613    })
614}
615
616#[test]
617// might as well test my logic
618fn test_enforced_minimums() {
619    let good_ca_configs = vec![
620        // test rsa 4096 (ok)
621        (KeyType::Rsa, 4096, false),
622        // test rsa 2048 (ok)
623        (KeyType::Rsa, 2048, false),
624        // test ec 256 (ok)
625        (KeyType::Ec, 256, false),
626    ];
627    good_ca_configs.into_iter().for_each(|config| {
628        dbg!(&config);
629        assert!(CAConfig::new(config.0, config.1, config.2).is_ok());
630    });
631    /*
632    let bad_ca_configs = vec![
633        // test rsa 1024 (no)
634        (KeyType::Rsa, 1024, false),
635        // test ec 128 (no)
636        (KeyType::Ec, 128, false),
637    ];
638    bad_ca_configs.into_iter().for_each(|config| {
639        dbg!(&config);
640        assert!(CAConfig::new(config.0, config.1, config.2).is_err());
641    });
642    */
643}
644
645#[test]
646fn test_ca_loader() {
647    let ca_key_tempfile = tempfile::NamedTempFile::new().unwrap();
648    let ca_cert_tempfile = tempfile::NamedTempFile::new().unwrap();
649    // let's test the defaults first
650
651    let ca_config = CAConfig::default();
652    if let Ok(ca) = build_ca(Some(ca_config)) {
653        write_ca(ca_key_tempfile.path(), ca_cert_tempfile.path(), &ca).unwrap();
654        assert!(load_ca(ca_key_tempfile.path(), ca_cert_tempfile.path()).is_ok());
655    };
656
657    let good_ca_configs = vec![
658        // test rsa 4096 (ok)
659        (KeyType::Rsa, 4096, false),
660        // test rsa 2048 (ok)
661        (KeyType::Rsa, 2048, false),
662        // test ec 256 (ok)
663        (KeyType::Ec, 256, false),
664    ];
665    good_ca_configs.into_iter().for_each(|config| {
666        println!("testing good config {config:?}");
667        let ca_config = CAConfig::new(config.0, config.1, config.2).unwrap();
668        let ca = build_ca(Some(ca_config)).unwrap();
669        write_ca(ca_key_tempfile.path(), ca_cert_tempfile.path(), &ca).unwrap();
670        let ca_result = load_ca(ca_key_tempfile.path(), ca_cert_tempfile.path());
671        println!("result: {ca_result:?}");
672        assert!(ca_result.is_ok());
673    });
674
675    /*
676    let bad_ca_configs = vec![
677        // test rsa 1024 (bad)
678        (KeyType::Rsa, 1024, true),
679    ];
680    bad_ca_configs.into_iter().for_each(|config| {
681        println!(
682            "\ntesting bad config keytype: {:?} key size: {}, skip_enforce_minimums: {}",
683            config.0, config.1, config.2
684        );
685        let ca_config = CAConfig::new(config.0, config.1, config.2).unwrap();
686        let ca = build_ca(Some(ca_config)).unwrap();
687        write_ca(ca_key_tempfile.path(), ca_cert_tempfile.path(), &ca).unwrap();
688        let ca_result = load_ca(ca_key_tempfile.path(), ca_cert_tempfile.path());
689        println!("result: {:?}", ca_result);
690        assert!(ca_result.is_err());
691    });
692    */
693}