#[macro_export]
macro_rules! cert {
(
profile: Root,
subject: $subject:expr,
serial: $serial:expr,
validity: ($not_before:expr, $not_after:expr),
signer: $signer:expr,
subject_public_key: $spki:expr
) => {{
use core::str::FromStr;
use $crate::crypto::x509::builder::Builder;
let subject = $crate::crypto::x509::name::Name::from_str($subject)?;
let serial = $crate::crypto::x509::serial_number::SerialNumber::from($serial);
let builder = $crate::crypto::x509::builder::CertificateBuilder::new(
$crate::crypto::x509::builder::Profile::Root,
serial,
$crate::crypto::x509::time::Validity::from_now($not_after - $not_before)?,
subject.clone(),
$spki,
$signer,
)?;
builder.build::<$crate::crypto::sign::ecdsa::der::Signature<$crate::crypto::sign::ecdsa::Secp256k1>>()
}};
(
profile: Root,
subject: $subject:expr,
serial: $serial:expr,
validity: ($not_before:expr, $not_after:expr),
signer: $signer:expr
) => {{
compile_error!(
"cert!(profile: Root, ...) requires [subject_public_key: <SPKI>](http://_vscodecontentref_/0).\n\
Pass the subject's SPKI explicitly to avoid argument shifting.\n\
If you want it derived from the signer, please specify how to obtain SPKI from your signer type."
);
}};
(
profile: Leaf,
subject: $subject:expr,
issuer: $issuer:expr,
serial: $serial:expr,
validity: ($not_before:expr, $not_after:expr),
subject_public_key: $spki:expr,
signer: $signer:expr
$(, extensions: [$($ext:expr),* $(,)?])?
) => {{
use core::str::FromStr;
use $crate::crypto::x509::builder::Builder;
let subject = $crate::crypto::x509::name::Name::from_str($subject)?;
let issuer = $crate::crypto::x509::name::Name::from_str($issuer)?;
let serial = $crate::crypto::x509::serial_number::SerialNumber::from($serial);
let mut builder = $crate::crypto::x509::builder::CertificateBuilder::new(
$crate::crypto::x509::builder::Profile::Leaf { issuer: issuer.clone(), enable_key_agreement: false },
serial,
$crate::crypto::x509::time::Validity::from_now($not_after - $not_before)?,
subject,
$spki,
$signer,
)?;
$(
$(
builder.add_extension(&$ext)?;
)*
)?
builder.build::<$crate::crypto::sign::Signer>()
}};
(
profile: SubCA,
subject: $subject:expr,
issuer: $issuer:expr,
serial: $serial:expr,
validity: ($not_before:expr, $not_after:expr),
subject_public_key: $spki:expr,
signer: $signer:expr
$(, path_len: $path_len:expr)?
) => {{
use core::str::FromStr;
use $crate::crypto::x509::builder::Builder;
let subject = $crate::crypto::x509::name::Name::from_str($subject)?;
let issuer = $crate::crypto::x509::name::Name::from_str($issuer)?;
let serial = $crate::crypto::x509::serial_number::SerialNumber::from($serial);
let profile = $crate::crypto::x509::builder::Profile::SubCA {
issuer: issuer.clone(),
path_len_constraint: $( Some($path_len) )?,
};
let builder = $crate::crypto::x509::builder::CertificateBuilder::new(
profile,
serial,
$crate::crypto::x509::time::Validity::from_now($not_after - $not_before)?,
subject,
$spki,
$signer,
)?;
builder.build::<$crate::crypto::sign::Signer>()
}};
}
#[cfg(feature = "x509")]
#[macro_export]
macro_rules! csr {
(
subject: $subject:expr,
signer: $signer:expr
$(, extensions: [$($ext:expr),* $(,)?])?
) => {{
use core::str::FromStr;
use $crate::crypto::x509::builder::RequestBuilder;
use $crate::crypto::x509::name::Name;
use $crate::der::Encode;
let subject = Name::from_str($subject)?;
let mut builder = RequestBuilder::new(subject, $signer)?;
$(
$(
builder.add_extension(&$ext)?;
)*
)?
builder.build::<$crate::crypto::sign::Signer>()
}};
}
#[cfg(test)]
mod tests {
use crate::crypto::sign::ecdsa::{Secp256k1SigningKey, Secp256k1VerifyingKey};
use crate::crypto::sign::Sha3Signer;
use crate::spki::SubjectPublicKeyInfoOwned;
#[test]
fn test_cert_macro_root() -> Result<(), Box<dyn core::error::Error>> {
let signing_key = Secp256k1SigningKey::random(&mut rand_core::OsRng);
let verifying_key = Secp256k1VerifyingKey::from(&signing_key);
let sha3_signer = Sha3Signer::from(&signing_key);
let spki = SubjectPublicKeyInfoOwned::from_key(verifying_key)?;
let not_before = std::time::Instant::now();
let not_after = not_before + std::time::Duration::from_secs(365 * 24 * 60 * 60);
let cert = cert!(
profile: Root,
subject: "CN=Test Root CA,O=Test Org,C=US",
serial: 1u32,
validity: (not_before, not_after),
signer: &sha3_signer,
subject_public_key: spki
)?;
assert_eq!(cert.tbs_certificate.subject, cert.tbs_certificate.issuer);
Ok(())
}
}