use crate::pki_types::{CertificateDer, PrivateKeyDer};
use rama_core::error::BoxError;
use rama_net::address::Domain;
use serde::{Deserialize, Serialize};
#[cfg(feature = "boring")]
#[cfg_attr(docsrs, doc(cfg(feature = "boring")))]
pub mod boring;
#[cfg(any(feature = "aws-lc", feature = "ring"))]
pub mod rcgen;
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct SelfSignedData {
pub organisation_name: Option<String>,
pub common_name: Option<Domain>,
pub subject_alternative_names: Option<Vec<Domain>>,
#[serde(default)]
pub key_kind: SelfSignedKeyKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
pub enum SelfSignedKeyKind {
Rsa2048,
Rsa4096,
#[default]
EcP256,
EcP384,
EcP521,
Ed25519,
}
#[cfg(feature = "boring")]
pub fn self_signed_server_auth(
data: SelfSignedData,
) -> Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>), BoxError> {
boring::self_signed_server_auth(data)
}
#[cfg(all(not(feature = "boring"), any(feature = "aws-lc", feature = "ring")))]
pub fn self_signed_server_auth(
data: SelfSignedData,
) -> Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>), BoxError> {
rcgen::self_signed_server_auth(data)
}
#[cfg(not(any(feature = "boring", feature = "aws-lc", feature = "ring")))]
pub fn self_signed_server_auth(
_data: SelfSignedData,
) -> Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>), BoxError> {
use rama_core::error::BoxErrorExt;
Err(BoxError::from_static_str(
"enable one of the rama-crypto cert providers (boring, aws-lc, ring) to use self_signed_server_auth",
))
}
#[cfg(all(test, any(feature = "boring", feature = "aws-lc", feature = "ring")))]
mod tests {
use super::*;
use x509_parser::prelude::*;
#[test]
fn self_signed_leaf_san_covers_common_name_and_extra_sans() {
let data = SelfSignedData {
common_name: Some(Domain::from_static("primary.rama.test")),
subject_alternative_names: Some(vec![
Domain::from_static("alt-one.rama.test"),
Domain::from_static("alt-two.rama.test"),
]),
..Default::default()
};
let (chain, _key) = self_signed_server_auth(data).expect("generate self-signed");
let (_, cert) =
X509Certificate::from_der(chain[0].as_ref()).expect("parse leaf certificate DER");
let mut dns = Vec::new();
for ext in cert.extensions() {
if let ParsedExtension::SubjectAlternativeName(san) = ext.parsed_extension() {
for gn in &san.general_names {
if let GeneralName::DNSName(name) = gn {
dns.push((*name).to_owned());
}
}
}
}
for expected in [
"primary.rama.test",
"alt-one.rama.test",
"alt-two.rama.test",
] {
assert!(
dns.iter().any(|n| n == expected),
"leaf SAN must contain {expected}; got {dns:?}"
);
}
}
}