kanidm_lib_crypto/
mtls.rs

1use crate::CryptoError;
2
3use openssl::asn1;
4use openssl::bn;
5use openssl::ec;
6use openssl::error::ErrorStack as OpenSSLError;
7use openssl::hash;
8use openssl::nid::Nid;
9use openssl::pkey::{PKey, Private};
10use openssl::x509::extension::BasicConstraints;
11use openssl::x509::extension::ExtendedKeyUsage;
12use openssl::x509::extension::KeyUsage;
13use openssl::x509::extension::SubjectAlternativeName;
14use openssl::x509::extension::SubjectKeyIdentifier;
15use openssl::x509::X509NameBuilder;
16use openssl::x509::X509;
17
18use uuid::Uuid;
19
20/// Gets an [ec::EcGroup] for P-256
21pub fn get_group() -> Result<ec::EcGroup, OpenSSLError> {
22    ec::EcGroup::from_curve_name(Nid::X9_62_PRIME256V1)
23}
24
25pub fn build_self_signed_server_and_client_identity(
26    cn: Uuid,
27    domain_name: &str,
28    expiration_days: u32,
29) -> Result<(PKey<Private>, X509), CryptoError> {
30    let ecgroup = get_group()?;
31    let eckey = ec::EcKey::generate(&ecgroup)?;
32    let ca_key = PKey::from_ec_key(eckey)?;
33    let mut x509_name = X509NameBuilder::new()?;
34
35    // x509_name.append_entry_by_text("C", "AU")?;
36    // x509_name.append_entry_by_text("ST", "QLD")?;
37    x509_name.append_entry_by_text("O", "Kanidm Replication")?;
38    x509_name.append_entry_by_text("CN", &cn.as_hyphenated().to_string())?;
39    let x509_name = x509_name.build();
40
41    let mut cert_builder = X509::builder()?;
42    // Yes, 2 actually means 3 here ...
43    cert_builder.set_version(2)?;
44
45    let serial_number = bn::BigNum::from_u32(1).and_then(|serial| serial.to_asn1_integer())?;
46
47    cert_builder.set_serial_number(&serial_number)?;
48    cert_builder.set_subject_name(&x509_name)?;
49    cert_builder.set_issuer_name(&x509_name)?;
50
51    let not_before = asn1::Asn1Time::days_from_now(0)?;
52    cert_builder.set_not_before(&not_before)?;
53    let not_after = asn1::Asn1Time::days_from_now(expiration_days)?;
54    cert_builder.set_not_after(&not_after)?;
55
56    // Do we need pathlen 0?
57    cert_builder.append_extension(BasicConstraints::new().critical().build()?)?;
58    cert_builder.append_extension(
59        KeyUsage::new()
60            .critical()
61            .digital_signature()
62            .key_encipherment()
63            .build()?,
64    )?;
65
66    cert_builder.append_extension(
67        ExtendedKeyUsage::new()
68            .server_auth()
69            .client_auth()
70            .build()?,
71    )?;
72
73    let subject_key_identifier =
74        SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(None, None))?;
75    cert_builder.append_extension(subject_key_identifier)?;
76
77    let subject_alt_name = SubjectAlternativeName::new()
78        .dns(domain_name)
79        .build(&cert_builder.x509v3_context(None, None))?;
80
81    cert_builder.append_extension(subject_alt_name)?;
82
83    cert_builder.set_pubkey(&ca_key)?;
84
85    cert_builder.sign(&ca_key, hash::MessageDigest::sha256())?;
86    let ca_cert = cert_builder.build();
87
88    Ok((ca_key, ca_cert))
89}