mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-24 04:57:00 +01:00
592 lines
19 KiB
Rust
592 lines
19 KiB
Rust
//! This module contains cryptographic setup code, a long with what policy
|
||
//! and ciphers we accept.
|
||
|
||
use openssl::ec::{EcGroup, EcKey};
|
||
use openssl::error::ErrorStack;
|
||
use openssl::nid::Nid;
|
||
use openssl::pkey::{PKeyRef, Private};
|
||
use openssl::rsa::Rsa;
|
||
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
|
||
use openssl::x509::{
|
||
extension::{
|
||
AuthorityKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage,
|
||
SubjectAlternativeName, SubjectKeyIdentifier,
|
||
},
|
||
X509NameBuilder, X509ReqBuilder, X509,
|
||
};
|
||
use openssl::{asn1, bn, hash, pkey};
|
||
use sketching::*;
|
||
|
||
use crate::config::Configuration;
|
||
|
||
use std::fs::File;
|
||
use std::io::{Read, Write};
|
||
use std::path::Path;
|
||
|
||
const CA_VALID_DAYS: u32 = 30;
|
||
const CERT_VALID_DAYS: u32 = 5;
|
||
|
||
// Basing minimums off https://www.keylength.com setting "year" to 2030 - tested as at 2023-09-25
|
||
//
|
||
// |Method |Date |Symmetric| FM |DL Key| DL Group|Elliptic Curve|Hash|
|
||
// | --- | --- | --- | --- | --- | --- | --- | ---|
|
||
// |Lenstra / Verheul|2030 | 93 |2493^2016|165 | 2493 | 176 | 186|
|
||
// |Lenstra Updated |2030 | 88 |1698^2063|176 | 1698 | 176 | 176|
|
||
// |ECRYPT |2029-2068| 256 |15360 |512 | 15360 | 512 | 512|
|
||
// |NIST |2019-2030| 112 |2048 |224 | 2048 | 224 | 224|
|
||
// |ANSSI |> 2030 | 128 |3072 |200 | 3072 | 256 | 256|
|
||
// |NSA |- | 256 |3072 |- | - | 384 | 384|
|
||
// |RFC3766 |- | - | - | - | - | - | - |
|
||
// |BSI |- | - | - | - | - | - | - |
|
||
// DL - Discrete Logarithm
|
||
// FM - Factoring Modulus
|
||
|
||
const RSA_MIN_KEY_SIZE_BITS: u64 = 2048;
|
||
const EC_MIN_KEY_SIZE_BITS: u64 = 224;
|
||
|
||
/// returns a signing function that meets a sensible minimum
|
||
fn get_signing_func() -> hash::MessageDigest {
|
||
hash::MessageDigest::sha256()
|
||
}
|
||
|
||
/// Ensure we're enforcing safe minimums for TLS keys
|
||
pub fn check_privkey_minimums(privkey: &PKeyRef<Private>) -> Result<(), String> {
|
||
if let Ok(key) = privkey.rsa() {
|
||
if key.size() < (RSA_MIN_KEY_SIZE_BITS / 8) as u32 {
|
||
Err(format!(
|
||
"TLS RSA key is less than {} bits!",
|
||
RSA_MIN_KEY_SIZE_BITS
|
||
))
|
||
} else {
|
||
debug!(
|
||
"The RSA private key size is: {} bits, that's OK!",
|
||
key.size() * 8
|
||
);
|
||
Ok(())
|
||
}
|
||
} else if let Ok(key) = privkey.ec_key() {
|
||
// allowing this to panic because ... it's an i32 and hopefully we don't have negative bit lengths?
|
||
#[allow(clippy::panic)]
|
||
let key_bits: u64 = key.private_key().num_bits().try_into().unwrap_or_else(|_| {
|
||
panic!(
|
||
"Failed to convert EC bitlength {} to u64",
|
||
key.private_key().num_bits()
|
||
)
|
||
});
|
||
|
||
if key_bits < EC_MIN_KEY_SIZE_BITS {
|
||
Err(format!(
|
||
"TLS EC key is less than {} bits! Got: {}",
|
||
EC_MIN_KEY_SIZE_BITS, key_bits
|
||
))
|
||
} else {
|
||
#[cfg(any(test, debug_assertions))]
|
||
println!("The EC private key size is: {} bits, that's OK!", key_bits);
|
||
debug!("The EC private key size is: {} bits, that's OK!", key_bits);
|
||
Ok(())
|
||
}
|
||
} else {
|
||
error!("TLS key is not RSA or EC, cannot check minimums!");
|
||
Ok(())
|
||
}
|
||
}
|
||
|
||
/// From the server configuration, generate an OpenSSL acceptor that we can use
|
||
/// to build our sockets for HTTPS/LDAPS.
|
||
pub fn setup_tls(config: &Configuration) -> Result<Option<SslAcceptor>, ()> {
|
||
match &config.tls_config {
|
||
Some(tls_config) => {
|
||
// Signing algorithm minimums are enforced by the SSLAcceptor - it won't start up with a sha1-signed cert.
|
||
// https://wiki.mozilla.org/Security/Server_Side_TLS
|
||
let mut ssl_builder =
|
||
SslAcceptor::mozilla_intermediate_v5(SslMethod::tls()).map_err(|openssl_err| {
|
||
error!("Failed to start TLS builder");
|
||
error!(?openssl_err);
|
||
})?;
|
||
|
||
ssl_builder
|
||
.set_certificate_chain_file(&tls_config.chain)
|
||
.map_err(|openssl_err| {
|
||
error!("Failed to access certificate chain file");
|
||
error!(?openssl_err);
|
||
let diag = kanidm_lib_file_permissions::diagnose_path(&tls_config.chain);
|
||
info!(%diag);
|
||
})?;
|
||
|
||
ssl_builder
|
||
.set_private_key_file(&tls_config.key, SslFiletype::PEM)
|
||
.map_err(|openssl_err| {
|
||
error!("Failed to access private key file");
|
||
error!(?openssl_err);
|
||
let diag = kanidm_lib_file_permissions::diagnose_path(&tls_config.chain);
|
||
info!(%diag);
|
||
})?;
|
||
|
||
ssl_builder.check_private_key().map_err(|openssl_err| {
|
||
error!("Failed to validate private key");
|
||
error!(?openssl_err);
|
||
})?;
|
||
|
||
let acceptor = ssl_builder.build();
|
||
|
||
// let's enforce some TLS minimums!
|
||
let privkey = acceptor.context().private_key().ok_or_else(|| {
|
||
error!("Failed to access acceptor private key");
|
||
})?;
|
||
|
||
check_privkey_minimums(privkey).map_err(|err| {
|
||
error!("{}", err);
|
||
})?;
|
||
|
||
Ok(Some(acceptor))
|
||
}
|
||
None => Ok(None),
|
||
}
|
||
}
|
||
|
||
fn get_ec_group() -> Result<EcGroup, ErrorStack> {
|
||
EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)
|
||
}
|
||
|
||
#[derive(Debug)]
|
||
pub(crate) struct CaHandle {
|
||
key: pkey::PKey<pkey::Private>,
|
||
cert: X509,
|
||
}
|
||
|
||
pub(crate) fn write_ca(
|
||
key_ar: impl AsRef<Path>,
|
||
cert_ar: impl AsRef<Path>,
|
||
handle: &CaHandle,
|
||
) -> Result<(), ()> {
|
||
let key_path: &Path = key_ar.as_ref();
|
||
let cert_path: &Path = cert_ar.as_ref();
|
||
|
||
let key_pem = handle.key.private_key_to_pem_pkcs8().map_err(|e| {
|
||
error!(err = ?e, "Failed to convert key to PEM");
|
||
})?;
|
||
|
||
let cert_pem = handle.cert.to_pem().map_err(|e| {
|
||
error!(err = ?e, "Failed to convert cert to PEM");
|
||
})?;
|
||
|
||
File::create(key_path)
|
||
.and_then(|mut file| file.write_all(&key_pem))
|
||
.map_err(|e| {
|
||
error!(err = ?e, "Failed to create {:?}", key_path);
|
||
})?;
|
||
|
||
File::create(cert_path)
|
||
.and_then(|mut file| file.write_all(&cert_pem))
|
||
.map_err(|e| {
|
||
error!(err = ?e, "Failed to create {:?}", cert_path);
|
||
})
|
||
}
|
||
|
||
#[derive(Debug)]
|
||
pub enum KeyType {
|
||
#[allow(dead_code)]
|
||
Rsa,
|
||
Ec,
|
||
}
|
||
impl Default for KeyType {
|
||
fn default() -> Self {
|
||
Self::Ec
|
||
}
|
||
}
|
||
|
||
#[derive(Debug)]
|
||
pub struct CAConfig {
|
||
pub key_type: KeyType,
|
||
pub key_bits: u64,
|
||
pub skip_enforce_minimums: bool,
|
||
}
|
||
|
||
impl Default for CAConfig {
|
||
fn default() -> Self {
|
||
#[allow(clippy::expect_used)]
|
||
Self::new(KeyType::Ec, 256, false)
|
||
.expect("Somehow the defaults failed to pass validation while building a CA Config?")
|
||
}
|
||
}
|
||
|
||
impl CAConfig {
|
||
fn new(key_type: KeyType, key_bits: u64, skip_enforce_minimums: bool) -> Result<Self, String> {
|
||
let res = Self {
|
||
key_type,
|
||
key_bits,
|
||
skip_enforce_minimums,
|
||
};
|
||
if !skip_enforce_minimums {
|
||
res.enforce_minimums()?;
|
||
};
|
||
Ok(res)
|
||
}
|
||
|
||
/// Make sure we're meeting the minimum spec for key length etc
|
||
fn enforce_minimums(&self) -> Result<(), String> {
|
||
match self.key_type {
|
||
KeyType::Rsa => {
|
||
trace!(
|
||
"Generating CA Config for RSA Key with {} bits",
|
||
self.key_bits
|
||
);
|
||
if self.key_bits < RSA_MIN_KEY_SIZE_BITS {
|
||
return Err(format!(
|
||
"RSA key size must be at least {} bits",
|
||
RSA_MIN_KEY_SIZE_BITS
|
||
));
|
||
}
|
||
}
|
||
KeyType::Ec => {
|
||
trace!("Generating CA Config for EcKey with {} bits", self.key_bits);
|
||
if self.key_bits < EC_MIN_KEY_SIZE_BITS {
|
||
return Err(format!(
|
||
"EC key size must be at least {} bits",
|
||
EC_MIN_KEY_SIZE_BITS
|
||
));
|
||
}
|
||
}
|
||
};
|
||
Ok(())
|
||
}
|
||
}
|
||
|
||
pub(crate) fn gen_private_key(
|
||
key_type: &KeyType,
|
||
key_bits: Option<u64>,
|
||
) -> Result<pkey::PKey<pkey::Private>, ErrorStack> {
|
||
match key_type {
|
||
KeyType::Rsa => {
|
||
let key_bits = key_bits.unwrap_or(RSA_MIN_KEY_SIZE_BITS);
|
||
let rsa = Rsa::generate(key_bits as u32)?;
|
||
pkey::PKey::from_rsa(rsa)
|
||
}
|
||
KeyType::Ec => {
|
||
// TODO: take key bitlength and use it for the curve group, somehow?
|
||
let ecgroup = get_ec_group()?;
|
||
let eckey = EcKey::generate(&ecgroup)?;
|
||
pkey::PKey::from_ec_key(eckey)
|
||
}
|
||
}
|
||
}
|
||
|
||
/// build up a CA certificate and key.
|
||
pub(crate) fn build_ca(ca_config: Option<CAConfig>) -> Result<CaHandle, ErrorStack> {
|
||
let ca_config = ca_config.unwrap_or_default();
|
||
|
||
let ca_key = gen_private_key(&ca_config.key_type, Some(ca_config.key_bits))?;
|
||
|
||
if !ca_config.skip_enforce_minimums {
|
||
check_privkey_minimums(&ca_key).map_err(|err| {
|
||
admin_error!("failed to build_ca due to privkey minimums {}", err);
|
||
#[cfg(any(test, debug_assertions))]
|
||
println!("failed to build_ca due to privkey minimums: {}", err);
|
||
ErrorStack::get() // this probably should be a real errorstack but... how?
|
||
})?;
|
||
}
|
||
let mut x509_name = X509NameBuilder::new()?;
|
||
|
||
x509_name.append_entry_by_text("C", "AU")?;
|
||
x509_name.append_entry_by_text("ST", "QLD")?;
|
||
x509_name.append_entry_by_text("O", "Kanidm")?;
|
||
x509_name.append_entry_by_text("CN", "Kanidm Generated CA")?;
|
||
x509_name.append_entry_by_text("OU", "Development and Evaluation - NOT FOR PRODUCTION")?;
|
||
let x509_name = x509_name.build();
|
||
|
||
let mut cert_builder = X509::builder()?;
|
||
// Yes, 2 actually means 3 here ...
|
||
cert_builder.set_version(2)?;
|
||
|
||
let serial_number = bn::BigNum::from_u32(1).and_then(|serial| serial.to_asn1_integer())?;
|
||
|
||
cert_builder.set_serial_number(&serial_number)?;
|
||
cert_builder.set_subject_name(&x509_name)?;
|
||
cert_builder.set_issuer_name(&x509_name)?;
|
||
|
||
let not_before = asn1::Asn1Time::days_from_now(0)?;
|
||
cert_builder.set_not_before(¬_before)?;
|
||
let not_after = asn1::Asn1Time::days_from_now(CA_VALID_DAYS)?;
|
||
cert_builder.set_not_after(¬_after)?;
|
||
|
||
cert_builder.append_extension(BasicConstraints::new().critical().ca().pathlen(0).build()?)?;
|
||
cert_builder.append_extension(
|
||
KeyUsage::new()
|
||
.critical()
|
||
.key_cert_sign()
|
||
.crl_sign()
|
||
.build()?,
|
||
)?;
|
||
|
||
let subject_key_identifier =
|
||
SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(None, None))?;
|
||
cert_builder.append_extension(subject_key_identifier)?;
|
||
|
||
cert_builder.set_pubkey(&ca_key)?;
|
||
|
||
cert_builder.sign(&ca_key, get_signing_func())?;
|
||
let ca_cert = cert_builder.build();
|
||
|
||
Ok(CaHandle {
|
||
key: ca_key,
|
||
cert: ca_cert,
|
||
})
|
||
}
|
||
|
||
pub(crate) fn load_ca(
|
||
ca_key_ar: impl AsRef<Path>,
|
||
ca_cert_ar: impl AsRef<Path>,
|
||
) -> Result<CaHandle, ()> {
|
||
let ca_key_path: &Path = ca_key_ar.as_ref();
|
||
let ca_cert_path: &Path = ca_cert_ar.as_ref();
|
||
|
||
let mut ca_key_pem = vec![];
|
||
File::open(ca_key_path)
|
||
.and_then(|mut file| file.read_to_end(&mut ca_key_pem))
|
||
.map_err(|e| {
|
||
error!(err = ?e, "Failed to read {:?}", ca_key_path);
|
||
})?;
|
||
|
||
let mut ca_cert_pem = vec![];
|
||
File::open(ca_cert_path)
|
||
.and_then(|mut file| file.read_to_end(&mut ca_cert_pem))
|
||
.map_err(|e| {
|
||
error!(err = ?e, "Failed to read {:?}", ca_cert_path);
|
||
})?;
|
||
|
||
let ca_key = pkey::PKey::private_key_from_pem(&ca_key_pem).map_err(|e| {
|
||
error!(err = ?e, "Failed to convert PEM to key");
|
||
})?;
|
||
|
||
check_privkey_minimums(&ca_key).map_err(|err| {
|
||
#[cfg(any(test, debug_assertions))]
|
||
println!("{:?}", err);
|
||
admin_error!("{}", err);
|
||
})?;
|
||
|
||
let ca_cert = X509::from_pem(&ca_cert_pem).map_err(|e| {
|
||
error!(err = ?e, "Failed to convert PEM to cert");
|
||
})?;
|
||
|
||
Ok(CaHandle {
|
||
key: ca_key,
|
||
cert: ca_cert,
|
||
})
|
||
}
|
||
|
||
pub(crate) struct CertHandle {
|
||
key: pkey::PKey<pkey::Private>,
|
||
cert: X509,
|
||
chain: Vec<X509>,
|
||
}
|
||
|
||
pub(crate) fn write_cert(
|
||
key_ar: impl AsRef<Path>,
|
||
chain_ar: impl AsRef<Path>,
|
||
cert_ar: impl AsRef<Path>,
|
||
handle: &CertHandle,
|
||
) -> Result<(), ()> {
|
||
let key_path: &Path = key_ar.as_ref();
|
||
let chain_path: &Path = chain_ar.as_ref();
|
||
let cert_path: &Path = cert_ar.as_ref();
|
||
|
||
let key_pem = handle.key.private_key_to_pem_pkcs8().map_err(|e| {
|
||
error!(err = ?e, "Failed to convert key to PEM");
|
||
})?;
|
||
|
||
let cert_pem = handle.cert.to_pem().map_err(|e| {
|
||
error!(err = ?e, "Failed to convert cert to PEM");
|
||
})?;
|
||
|
||
let mut chain_pem = cert_pem.clone();
|
||
|
||
// Build the chain PEM.
|
||
for ca_cert in &handle.chain {
|
||
match ca_cert.to_pem() {
|
||
Ok(c) => {
|
||
chain_pem.extend_from_slice(&c);
|
||
}
|
||
Err(e) => {
|
||
error!(err = ?e, "Failed to convert cert to PEM");
|
||
return Err(());
|
||
}
|
||
}
|
||
}
|
||
|
||
File::create(key_path)
|
||
.and_then(|mut file| file.write_all(&key_pem))
|
||
.map_err(|e| {
|
||
error!(err = ?e, "Failed to create {:?}", key_path);
|
||
})?;
|
||
|
||
File::create(chain_path)
|
||
.and_then(|mut file| file.write_all(&chain_pem))
|
||
.map_err(|e| {
|
||
error!(err = ?e, "Failed to create {:?}", chain_path);
|
||
})?;
|
||
|
||
File::create(cert_path)
|
||
.and_then(|mut file| file.write_all(&cert_pem))
|
||
.map_err(|e| {
|
||
error!(err = ?e, "Failed to create {:?}", cert_path);
|
||
})
|
||
}
|
||
|
||
pub(crate) fn build_cert(
|
||
domain_name: &str,
|
||
ca_handle: &CaHandle,
|
||
key_type: Option<KeyType>,
|
||
key_bits: Option<u64>,
|
||
) -> Result<CertHandle, ErrorStack> {
|
||
let key_type = key_type.unwrap_or_default();
|
||
let int_key = gen_private_key(&key_type, key_bits)?;
|
||
|
||
let mut req_builder = X509ReqBuilder::new()?;
|
||
req_builder.set_pubkey(&int_key)?;
|
||
|
||
let mut x509_name = X509NameBuilder::new()?;
|
||
x509_name.append_entry_by_text("C", "AU")?;
|
||
x509_name.append_entry_by_text("ST", "QLD")?;
|
||
x509_name.append_entry_by_text("O", "Kanidm")?;
|
||
x509_name.append_entry_by_text("CN", domain_name)?;
|
||
// Requirement of packed attestation.
|
||
x509_name.append_entry_by_text("OU", "Development and Evaluation - NOT FOR PRODUCTION")?;
|
||
let x509_name = x509_name.build();
|
||
|
||
req_builder.set_subject_name(&x509_name)?;
|
||
req_builder.sign(&int_key, get_signing_func())?;
|
||
let req = req_builder.build();
|
||
// ==
|
||
|
||
let mut cert_builder = X509::builder()?;
|
||
// Yes, 2 actually means 3 here ...
|
||
cert_builder.set_version(2)?;
|
||
let serial_number = bn::BigNum::from_u32(2).and_then(|serial| serial.to_asn1_integer())?;
|
||
|
||
cert_builder.set_pubkey(&int_key)?;
|
||
|
||
cert_builder.set_serial_number(&serial_number)?;
|
||
cert_builder.set_subject_name(req.subject_name())?;
|
||
cert_builder.set_issuer_name(ca_handle.cert.subject_name())?;
|
||
|
||
let not_before = asn1::Asn1Time::days_from_now(0)?;
|
||
cert_builder.set_not_before(¬_before)?;
|
||
let not_after = asn1::Asn1Time::days_from_now(CERT_VALID_DAYS)?;
|
||
cert_builder.set_not_after(¬_after)?;
|
||
|
||
cert_builder.append_extension(BasicConstraints::new().build()?)?;
|
||
|
||
cert_builder.append_extension(
|
||
KeyUsage::new()
|
||
.critical()
|
||
.digital_signature()
|
||
.key_encipherment()
|
||
.build()?,
|
||
)?;
|
||
|
||
cert_builder.append_extension(
|
||
ExtendedKeyUsage::new()
|
||
// .critical()
|
||
.server_auth()
|
||
.build()?,
|
||
)?;
|
||
|
||
let subject_key_identifier = SubjectKeyIdentifier::new()
|
||
.build(&cert_builder.x509v3_context(Some(&ca_handle.cert), None))?;
|
||
cert_builder.append_extension(subject_key_identifier)?;
|
||
|
||
let auth_key_identifier = AuthorityKeyIdentifier::new()
|
||
.keyid(false)
|
||
.issuer(false)
|
||
.build(&cert_builder.x509v3_context(Some(&ca_handle.cert), None))?;
|
||
cert_builder.append_extension(auth_key_identifier)?;
|
||
|
||
let subject_alt_name = SubjectAlternativeName::new()
|
||
.dns(domain_name)
|
||
.build(&cert_builder.x509v3_context(Some(&ca_handle.cert), None))?;
|
||
cert_builder.append_extension(subject_alt_name)?;
|
||
|
||
cert_builder.sign(&ca_handle.key, get_signing_func())?;
|
||
let int_cert = cert_builder.build();
|
||
|
||
Ok(CertHandle {
|
||
key: int_key,
|
||
cert: int_cert,
|
||
chain: vec![ca_handle.cert.clone()],
|
||
})
|
||
}
|
||
|
||
#[test]
|
||
// might as well test my logic
|
||
fn test_enforced_minimums() {
|
||
let good_ca_configs = vec![
|
||
// test rsa 4096 (ok)
|
||
(KeyType::Rsa, 4096, false),
|
||
// test rsa 2048 (ok)
|
||
(KeyType::Rsa, 2048, false),
|
||
// test ec 256 (ok)
|
||
(KeyType::Ec, 256, false),
|
||
];
|
||
good_ca_configs.into_iter().for_each(|config| {
|
||
dbg!(&config);
|
||
assert!(CAConfig::new(config.0, config.1, config.2).is_ok());
|
||
});
|
||
let bad_ca_configs = vec![
|
||
// test rsa 1024 (no)
|
||
(KeyType::Rsa, 1024, false),
|
||
// test ec 128 (no)
|
||
(KeyType::Ec, 128, false),
|
||
];
|
||
bad_ca_configs.into_iter().for_each(|config| {
|
||
dbg!(&config);
|
||
assert!(CAConfig::new(config.0, config.1, config.2).is_err());
|
||
});
|
||
}
|
||
|
||
#[test]
|
||
fn test_ca_loader() {
|
||
let ca_key_tempfile = tempfile::NamedTempFile::new().unwrap();
|
||
let ca_cert_tempfile = tempfile::NamedTempFile::new().unwrap();
|
||
// let's test the defaults first
|
||
|
||
let ca_config = CAConfig::default();
|
||
if let Ok(ca) = build_ca(Some(ca_config)) {
|
||
write_ca(ca_key_tempfile.path(), ca_cert_tempfile.path(), &ca).unwrap();
|
||
assert!(load_ca(ca_key_tempfile.path(), ca_cert_tempfile.path()).is_ok());
|
||
};
|
||
|
||
let good_ca_configs = vec![
|
||
// test rsa 4096 (ok)
|
||
(KeyType::Rsa, 4096, false),
|
||
// test rsa 2048 (ok)
|
||
(KeyType::Rsa, 2048, false),
|
||
// test ec 256 (ok)
|
||
(KeyType::Ec, 256, false),
|
||
];
|
||
good_ca_configs.into_iter().for_each(|config| {
|
||
println!("testing good config {:?}", config);
|
||
let ca_config = CAConfig::new(config.0, config.1, config.2).unwrap();
|
||
let ca = build_ca(Some(ca_config)).unwrap();
|
||
write_ca(ca_key_tempfile.path(), ca_cert_tempfile.path(), &ca).unwrap();
|
||
let ca_result = load_ca(ca_key_tempfile.path(), ca_cert_tempfile.path());
|
||
println!("result: {:?}", ca_result);
|
||
assert!(ca_result.is_ok());
|
||
});
|
||
let bad_ca_configs = vec![
|
||
// test rsa 1024 (bad)
|
||
(KeyType::Rsa, 1024, true),
|
||
];
|
||
bad_ca_configs.into_iter().for_each(|config| {
|
||
println!(
|
||
"\ntesting bad config keytype: {:?} key size: {}, skip_enforce_minimums: {}",
|
||
config.0, config.1, config.2
|
||
);
|
||
let ca_config = CAConfig::new(config.0, config.1, config.2).unwrap();
|
||
let ca = build_ca(Some(ca_config)).unwrap();
|
||
write_ca(ca_key_tempfile.path(), ca_cert_tempfile.path(), &ca).unwrap();
|
||
let ca_result = load_ca(ca_key_tempfile.path(), ca_cert_tempfile.path());
|
||
println!("result: {:?}", ca_result);
|
||
assert!(ca_result.is_err());
|
||
});
|
||
}
|