#![cfg(feature = "experimental-x509-identity-verification")]
mod errors;
mod raw_x509_signature;
mod x509_signer;
mod x509_verify;
pub use errors::{
IntoX509SignatureError, X509SignatureSigningError, X509SignatureVerificationError,
};
pub use raw_x509_signature::{RawX509Signature, X509SignatureScheme};
pub(crate) use x509_signer::X509Signer;
pub use x509_signer::{RawX509Signer, ValidityError};
pub use x509_verify::RawX509Verifier;
pub(crate) use x509_verify::X509Verifier;
#[cfg(any(test, feature = "rust-x509-verifier-impl"))]
mod rust_raw_x509_signer;
#[cfg(any(test, feature = "rust-x509-verifier-impl"))]
mod rust_raw_x509_verifier;
#[cfg(any(test, feature = "rust-x509-verifier-impl"))]
pub use rust_raw_x509_signer::RustRawX509Signer;
#[cfg(any(test, feature = "rust-x509-verifier-impl"))]
pub use rust_raw_x509_verifier::RustRawX509Verifier;
#[cfg(test)]
pub(crate) mod tests {
use std::sync::Arc;
use rcgen::{
Certificate, CertificateParams, CustomExtension, DnType, Issuer, KeyPair, PublicKeyData,
SanType,
};
use ruma::OwnedUserId;
use crate::x509::{RustRawX509Signer, RustRawX509Verifier, X509Signer, X509Verifier};
pub(crate) const OID_PKCS9_EMAIL_ADDRESS: &[u64] = &[1, 2, 840, 113549, 1, 9, 1];
pub(crate) const OID_SUBJECT_KEY_IDENTIFIER: &[u64] = &[2, 5, 29, 14];
pub(crate) fn generate_rsa_key() -> KeyPair {
KeyPair::generate_for(&rcgen::PKCS_RSA_SHA512).expect("Failed to generate key pair")
}
pub(crate) fn cert_and_key_with_email_in_subject_distinguished_name(
email: &str,
) -> (Certificate, KeyPair) {
set_up_default_crypto_provider();
let signing_key = generate_rsa_key();
let mut cert_params = CertificateParams::default();
cert_params.use_authority_key_identifier_extension = true;
cert_params.custom_extensions.push(subject_key_identifier_extension(&signing_key));
cert_params.distinguished_name.push(DnType::from_oid(OID_PKCS9_EMAIL_ADDRESS), email);
let cert = cert_params.self_signed(&signing_key).expect("Failed to generate certificate");
(cert, signing_key)
}
pub(crate) fn cert_and_key_with_email_in_subject_alternate_name(
email: &str,
) -> (Certificate, KeyPair) {
set_up_default_crypto_provider();
let signing_key = generate_rsa_key();
let mut cert_params = CertificateParams::default();
cert_params.use_authority_key_identifier_extension = true;
cert_params.custom_extensions.push(subject_key_identifier_extension(&signing_key));
cert_params.subject_alt_names.push(SanType::Rfc822Name(
email.try_into().expect("Failed to convert email address to Ia5String"),
));
let cert = cert_params.self_signed(&signing_key).expect("Failed to generate certificate");
(cert, signing_key)
}
pub(crate) fn cert_and_key_with_user_id_in_subject_alternate_name(
user_id: &str,
) -> (Certificate, KeyPair) {
set_up_default_crypto_provider();
let signing_key = generate_rsa_key();
let user_id_uri =
OwnedUserId::try_from(user_id).expect("Invalid user ID!").matrix_uri(false);
let mut cert_params = CertificateParams::default();
cert_params.use_authority_key_identifier_extension = true;
cert_params.custom_extensions.push(subject_key_identifier_extension(&signing_key));
cert_params.subject_alt_names.push(SanType::URI(
user_id_uri.to_string().try_into().expect("Failed to convert user_id URI to Ia5String"),
));
let cert = cert_params.self_signed(&signing_key).expect("Failed to generate certificate");
(cert, signing_key)
}
pub(crate) fn cert_and_key_with_no_user_id() -> (Certificate, KeyPair) {
set_up_default_crypto_provider();
let signing_key = generate_rsa_key();
let mut cert_params = CertificateParams::default();
cert_params.use_authority_key_identifier_extension = true;
cert_params.custom_extensions.push(subject_key_identifier_extension(&signing_key));
let cert = cert_params.self_signed(&signing_key).expect("Failed to generate certificate");
(cert, signing_key)
}
pub(crate) fn subject_key_identifier_extension(
signing_key: &impl PublicKeyData,
) -> CustomExtension {
use sha2::{Digest, Sha256};
let spki = signing_key.subject_public_key_info();
let spki_hash = Sha256::digest(&spki);
let ski_bytes = &spki_hash.as_slice()[0..20];
let ski_der = [&[0x04, ski_bytes.len() as u8], ski_bytes].concat();
CustomExtension::from_oid_content(OID_SUBJECT_KEY_IDENTIFIER, ski_der)
}
pub(crate) fn cert_params(common_name: &str) -> CertificateParams {
let mut cert_params = CertificateParams::default();
cert_params.distinguished_name.remove(DnType::CommonName);
cert_params.distinguished_name.push(DnType::CommonName, common_name);
cert_params.use_authority_key_identifier_extension = true;
cert_params
}
pub(crate) fn ca_cert() -> (Certificate, KeyPair) {
set_up_default_crypto_provider();
let cert_params = cert_params("You Can Trust Us Certificate Authority");
let signing_key = generate_rsa_key();
let cert = cert_params.self_signed(&signing_key).expect("Failed to generate certificate");
(cert, signing_key)
}
pub(crate) fn cert_and_key_with_email_signed_by(
email: &str,
ca_cert: &Certificate,
ca_signing_key: &KeyPair,
) -> (Certificate, KeyPair) {
let signing_key = generate_rsa_key();
let mut cert_params = cert_params(&format!("Cert for {email}"));
cert_params.distinguished_name.push(DnType::from_oid(OID_PKCS9_EMAIL_ADDRESS), email);
cert_params.custom_extensions.push(subject_key_identifier_extension(&signing_key));
let issuer = Issuer::from_ca_cert_pem(&ca_cert.pem(), ca_signing_key)
.expect("Failed to create Issuer from CA cert and key");
let cert =
cert_params.signed_by(&signing_key, &issuer).expect("Failed to generate certificate");
(cert, signing_key)
}
pub(crate) fn create_rust_signer_and_verifier(
cert: Certificate,
signing_key: KeyPair,
) -> (X509Signer, X509Verifier) {
let cert_pem = cert.pem();
let key_pem = signing_key.serialize_pem();
let x509_signer = {
let rust_raw_x509_signer =
RustRawX509Signer::new_from_pem_data(&cert_pem, &key_pem).unwrap();
X509Signer::new(Arc::new(rust_raw_x509_signer))
};
let x509_verifier = {
let rust_raw_x509_verifier = RustRawX509Verifier::new_from_pem_data(&cert_pem).unwrap();
X509Verifier::new(Arc::new(rust_raw_x509_verifier))
};
(x509_signer, x509_verifier)
}
fn set_up_default_crypto_provider() {
let _ = rustls::crypto::ring::default_provider().install_default();
}
pub(crate) fn signers_with_different_validity() -> (X509Signer, X509Signer, X509Signer) {
let signing_key =
KeyPair::generate_for(&rcgen::PKCS_RSA_SHA512).expect("Failed to generate key pair");
let mut cert_params = CertificateParams::default();
cert_params.use_authority_key_identifier_extension = true;
cert_params.custom_extensions.push(subject_key_identifier_extension(&signing_key));
cert_params.not_after = rcgen::date_time_ymd(2025, 7, 1);
let cert_old =
cert_params.self_signed(&signing_key).expect("Failed to generate certificate");
let x509_signer_old = {
let rust_raw_x509_signer =
RustRawX509Signer::new_from_pem_data(&cert_old.pem(), &signing_key.serialize_pem())
.unwrap();
X509Signer::new(Arc::new(rust_raw_x509_signer))
};
cert_params.not_after = rcgen::date_time_ymd(2026, 7, 1);
let cert = cert_params.self_signed(&signing_key).expect("Failed to generate certificate");
let x509_signer_current = {
let rust_raw_x509_signer =
RustRawX509Signer::new_from_pem_data(&cert.pem(), &signing_key.serialize_pem())
.unwrap();
X509Signer::new(Arc::new(rust_raw_x509_signer))
};
cert_params.not_after = rcgen::date_time_ymd(2027, 7, 1);
let cert_new =
cert_params.self_signed(&signing_key).expect("Failed to generate certificate");
let x509_signer_new = {
let rust_raw_x509_signer =
RustRawX509Signer::new_from_pem_data(&cert_new.pem(), &signing_key.serialize_pem())
.unwrap();
X509Signer::new(Arc::new(rust_raw_x509_signer))
};
(x509_signer_old, x509_signer_current, x509_signer_new)
}
}