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