1use 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
17use 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
40const RSA_MIN_KEY_SIZE_BITS: u64 = 2048;
56const EC_MIN_KEY_SIZE_BITS: u64 = 224;
57
58fn get_signing_func() -> hash::MessageDigest {
60 hash::MessageDigest::sha256()
61}
62
63pub 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 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 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
146pub 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 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 .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 .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 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 let ecgroup = get_ec_group()?;
368 let eckey = EcKey::generate(&ecgroup)?;
369 pkey::PKey::from_ec_key(eckey)
370 }
371 }
372}
373
374pub(crate) fn build_ca(ca_config: Option<CAConfig>) -> Result<CaHandle, ErrorStack> {
376 let ca_config = ca_config.unwrap_or_default();
379
380 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 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(¬_before)?;
404 let not_after = asn1::Asn1Time::days_from_now(CA_VALID_DAYS)?;
405 cert_builder.set_not_after(¬_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 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 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 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 let mut cert_builder = X509::builder()?;
559 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(¬_before)?;
571 let not_after = asn1::Asn1Time::days_from_now(CERT_VALID_DAYS)?;
572 cert_builder.set_not_after(¬_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 .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]
617fn test_enforced_minimums() {
619 let good_ca_configs = vec![
620 (KeyType::Rsa, 4096, false),
622 (KeyType::Rsa, 2048, false),
624 (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 }
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 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 (KeyType::Rsa, 4096, false),
660 (KeyType::Rsa, 2048, false),
662 (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 }