From 40974f110ba88a5709981806548459ea0fc0dd1e Mon Sep 17 00:00:00 2001 From: Lukas Velikov Date: Wed, 7 Aug 2024 14:46:00 -0400 Subject: [PATCH] Add KeyUsagePurpose::from_u16 --- rcgen/src/certificate.rs | 35 +++-------------------------------- rcgen/src/lib.rs | 25 ++++++++++++++++++++++++- rcgen/tests/webpki.rs | 5 +++++ 3 files changed, 32 insertions(+), 33 deletions(-) diff --git a/rcgen/src/certificate.rs b/rcgen/src/certificate.rs index 6763a02d..1d634c37 100644 --- a/rcgen/src/certificate.rs +++ b/rcgen/src/certificate.rs @@ -324,38 +324,9 @@ impl CertificateParams { .key_usage() .or(Err(Error::CouldNotParseCertificate))? .map(|ext| ext.value); - - let mut key_usages = Vec::new(); - if let Some(key_usage) = key_usage { - if key_usage.digital_signature() { - key_usages.push(KeyUsagePurpose::DigitalSignature); - } - if key_usage.non_repudiation() { - key_usages.push(KeyUsagePurpose::ContentCommitment); - } - if key_usage.key_encipherment() { - key_usages.push(KeyUsagePurpose::KeyEncipherment); - } - if key_usage.data_encipherment() { - key_usages.push(KeyUsagePurpose::DataEncipherment); - } - if key_usage.key_agreement() { - key_usages.push(KeyUsagePurpose::KeyAgreement); - } - if key_usage.key_cert_sign() { - key_usages.push(KeyUsagePurpose::KeyCertSign); - } - if key_usage.crl_sign() { - key_usages.push(KeyUsagePurpose::CrlSign); - } - if key_usage.encipher_only() { - key_usages.push(KeyUsagePurpose::EncipherOnly); - } - if key_usage.decipher_only() { - key_usages.push(KeyUsagePurpose::DecipherOnly); - } - } - Ok(key_usages) + // This x509 parser stores flags in reversed bit BIT STRING order + let flags = key_usage.map_or(0u16, |k| k.flags).reverse_bits(); + Ok(KeyUsagePurpose::from_u16(flags)) } #[cfg(feature = "x509-parser")] fn convert_x509_extended_key_usages( diff --git a/rcgen/src/lib.rs b/rcgen/src/lib.rs index ea7f0e83..0caecbeb 100644 --- a/rcgen/src/lib.rs +++ b/rcgen/src/lib.rs @@ -413,7 +413,7 @@ impl<'a> Iterator for DistinguishedNameIterator<'a> { } /// One of the purposes contained in the [key usage](https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3) extension -#[derive(Debug, PartialEq, Eq, Hash, Clone)] +#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] pub enum KeyUsagePurpose { /// digitalSignature DigitalSignature, @@ -452,6 +452,29 @@ impl KeyUsagePurpose { KeyUsagePurpose::DecipherOnly => 8, } } + + /// Parse a collection of key usages from a [`u16`] representing the value + /// of a KeyUsage BIT STRING as defined by RFC 5280. + #[cfg(feature = "x509-parser")] + fn from_u16(value: u16) -> Vec { + [ + KeyUsagePurpose::DigitalSignature, + KeyUsagePurpose::ContentCommitment, + KeyUsagePurpose::KeyEncipherment, + KeyUsagePurpose::DataEncipherment, + KeyUsagePurpose::KeyAgreement, + KeyUsagePurpose::KeyCertSign, + KeyUsagePurpose::CrlSign, + KeyUsagePurpose::EncipherOnly, + KeyUsagePurpose::DecipherOnly, + ] + .iter() + .filter_map(|key_usage| { + let present = key_usage.to_u16() & value != 0; + present.then_some(*key_usage) + }) + .collect() + } } /// Method to generate key identifiers from public keys. diff --git a/rcgen/tests/webpki.rs b/rcgen/tests/webpki.rs index 8f076952..01eec1ec 100644 --- a/rcgen/tests/webpki.rs +++ b/rcgen/tests/webpki.rs @@ -412,11 +412,16 @@ fn test_webpki_separate_ca_name_constraints() { fn test_webpki_imported_ca() { let (mut params, ca_key) = util::default_params(); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); + params.key_usages.push(KeyUsagePurpose::KeyCertSign); let ca_cert = params.self_signed(&ca_key).unwrap(); let ca_cert_der = ca_cert.der(); let imported_ca_cert_params = CertificateParams::from_ca_cert_der(ca_cert_der).unwrap(); + assert_eq!( + imported_ca_cert_params.key_usages, + vec![KeyUsagePurpose::KeyCertSign] + ); let imported_ca_cert = imported_ca_cert_params.self_signed(&ca_key).unwrap(); let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]).unwrap();