#![allow(clippy::module_name_repetitions)]
use rcgen::KeyPair;
use x509_certificate::{CapturedX509Certificate, InMemorySigningKeyPair};
pub struct SigningKey {
pub(crate) key_rcgen: KeyPair,
pub(crate) key_cms: InMemorySigningKeyPair,
}
impl SigningKey {
pub fn from_pem(pem_str: &str) -> Result<Self, SigningKeyParseError> {
let key_rcgen = KeyPair::from_pem(pem_str)?;
let key_cms = InMemorySigningKeyPair::from_pkcs8_pem(pem_str)?;
Ok(Self { key_rcgen, key_cms })
}
pub fn from_der(der: &[u8]) -> Result<Self, SigningKeyParseError> {
let key_rcgen = KeyPair::try_from(der)?;
let key_cms = InMemorySigningKeyPair::from_pkcs8_der(der)?;
Ok(Self { key_rcgen, key_cms })
}
}
impl std::fmt::Debug for SigningKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SigningKey").finish()
}
}
#[derive(Debug, Clone)]
pub struct SigningCertificate {
pub(crate) cert: CapturedX509Certificate,
}
impl SigningCertificate {
pub fn from_pem(pem_str: &str) -> Result<Self, SigningCertificateParseError> {
let cert = CapturedX509Certificate::from_pem(pem_str)?;
Ok(Self { cert })
}
pub fn from_der(der: &[u8]) -> Result<Self, SigningCertificateParseError> {
let cert = CapturedX509Certificate::from_der(der)?;
Ok(Self { cert })
}
}
#[derive(Debug)]
pub enum SigningKeyParseError {
Csr(rcgen::Error),
Cms(x509_certificate::X509CertificateError),
}
impl std::fmt::Display for SigningKeyParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Csr(e) => write!(f, "failed to parse key for CSR signing: {e}"),
Self::Cms(e) => write!(f, "failed to parse key for CMS signing: {e}"),
}
}
}
impl std::error::Error for SigningKeyParseError {}
impl From<rcgen::Error> for SigningKeyParseError {
fn from(value: rcgen::Error) -> Self {
Self::Csr(value)
}
}
impl From<x509_certificate::X509CertificateError> for SigningKeyParseError {
fn from(value: x509_certificate::X509CertificateError) -> Self {
Self::Cms(value)
}
}
#[derive(Debug)]
pub struct SigningCertificateParseError(x509_certificate::X509CertificateError);
impl std::fmt::Display for SigningCertificateParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "failed to parse certificate: {}", self.0)
}
}
impl std::error::Error for SigningCertificateParseError {}
impl From<x509_certificate::X509CertificateError> for SigningCertificateParseError {
fn from(value: x509_certificate::X509CertificateError) -> Self {
Self(value)
}
}
#[cfg(test)]
mod tests {
use super::*;
const EXAMPLE_RSA_CERT_PEM: &str = include_str!("../test/example.rsa.pem.cert");
const EXAMPLE_RSA_CERT_DER: &[u8] = include_bytes!("../test/example.rsa.der.cert");
const EXAMPLE_EC_KEY_PEM: &str = include_str!("../test/example.ec.pem.key");
const EXAMPLE_EC_KEY_DER: &[u8] = include_bytes!("../test/example.ec.der.key");
impl SigningKey {
pub(crate) fn new_testing_key() -> Self {
Self::from_pem(EXAMPLE_EC_KEY_PEM).unwrap()
}
}
impl SigningCertificate {
pub(crate) fn new_testing_cert() -> Self {
Self::from_pem(EXAMPLE_RSA_CERT_PEM).unwrap()
}
}
#[test]
fn test_example_idempotency() {
let once = SigningKey::new_testing_key();
let twice = SigningKey::new_testing_key();
assert_eq!(
once.key_rcgen.serialized_der(),
twice.key_rcgen.serialized_der()
);
let once = SigningCertificate::new_testing_cert();
let twice = SigningCertificate::new_testing_cert();
assert_eq!(
once.cert.encode_der().unwrap(),
twice.cert.encode_der().unwrap()
);
}
#[test]
fn test_signing_key_from_pem() {
SigningKey::from_pem(EXAMPLE_EC_KEY_PEM).unwrap();
assert!(SigningKey::from_pem("invalid").is_err());
}
#[test]
fn test_signing_key_from_der() {
SigningKey::from_der(EXAMPLE_EC_KEY_DER).unwrap();
assert!(SigningKey::from_der(b"invalid").is_err());
}
#[test]
fn test_certificate_from_pem() {
SigningCertificate::from_pem(EXAMPLE_RSA_CERT_PEM).unwrap();
assert!(SigningCertificate::from_pem("invalid").is_err());
}
#[test]
fn test_certificate_from_der() {
SigningCertificate::from_der(EXAMPLE_RSA_CERT_DER).unwrap();
assert!(SigningCertificate::from_der(b"invalid").is_err());
}
}