trz_gateway_common/x509/signed_extension/
mod.rs1use std::sync::OnceLock;
2use std::time::SystemTimeError;
3use std::time::UNIX_EPOCH;
4
5use nameth::NamedEnumValues as _;
6use nameth::nameth;
7use openssl::asn1::Asn1Object;
8use openssl::asn1::Asn1ObjectRef;
9use openssl::cms::CMSOptions;
10use openssl::error::ErrorStack;
11use openssl::hash::DigestBytes;
12use openssl::hash::Hasher;
13use openssl::hash::MessageDigest;
14
15use super::validity::Validity;
16use super::validity::ValidityError;
17
18mod make;
19mod verify;
20
21pub use self::make::MakeSignedExtensionError;
22pub use self::make::make_signed_extension;
23pub use self::verify::ValidateSignedExtensionError;
24pub use self::verify::validate_signed_extension;
25
26const SIGNED_EXTENSION_OID: &str = "1.3.6.1.4.1.311.10.99.1";
27
28fn signed_extension_oid() -> &'static Asn1ObjectRef {
29 static ASN1_OBJECT: OnceLock<Asn1Object> = OnceLock::new();
30 ASN1_OBJECT.get_or_init(|| {
31 Asn1Object::from_str(SIGNED_EXTENSION_OID)
32 .expect("Failed to cast SIGNED_EXTENSION_OID to Asn1Object")
33 })
34}
35
36fn make_certificate_properties_hash(
37 common_name: &str,
38 validity: Validity,
39 public_key_der: &[u8],
40) -> Result<Vec<u8>, MakeCertificatePropertiesHashError> {
41 let validity = validity.try_map(|t| t.duration_since(UNIX_EPOCH))?;
42 let mut certificate_properties_hash = format!(
43 "{common_name}:{}:{}:",
44 validity.from.as_secs(),
45 validity.to.as_secs(),
46 )
47 .into_bytes();
48 let public_key_sha256 = make_public_key_sha256(public_key_der)
49 .map_err(MakeCertificatePropertiesHashError::PublicKeySha256)?;
50 certificate_properties_hash.extend(public_key_sha256.as_ref());
51 Ok(certificate_properties_hash)
52}
53
54#[nameth]
55#[derive(thiserror::Error, Debug)]
56pub enum MakeCertificatePropertiesHashError {
57 #[error("[{n}] Failed to create validity hash: {0}", n = self.name())]
58 Validity(#[from] ValidityError<SystemTimeError>),
59
60 #[error("[{n}] Failed to compute public key's sha256: {0}", n = self.name())]
61 PublicKeySha256(ErrorStack),
62}
63
64fn make_public_key_sha256(public_key_der: &[u8]) -> Result<DigestBytes, ErrorStack> {
65 let mut hasher = Hasher::new(MessageDigest::sha256())?;
66 hasher.update(public_key_der)?;
67 hasher.finish()
68}
69
70fn cms_options() -> CMSOptions {
71 CMSOptions::BINARY | CMSOptions::USE_KEYID
72}