From 964f9c6f6d09c4ccbbc322fd05ff006950373c9e Mon Sep 17 00:00:00 2001 From: Lukas Velikov Date: Wed, 7 Aug 2024 14:50:04 -0400 Subject: [PATCH] Add KeyUsagePurpose support to CSR from DER; add CSR test --- rcgen/src/csr.rs | 7 +++++++ rcgen/tests/generic.rs | 30 +++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/rcgen/src/csr.rs b/rcgen/src/csr.rs index e79e21eb..79fab8e2 100644 --- a/rcgen/src/csr.rs +++ b/rcgen/src/csr.rs @@ -94,7 +94,9 @@ impl CertificateSigningRequestParams { /// [`rustls_pemfile::csr()`]: https://docs.rs/rustls-pemfile/latest/rustls_pemfile/fn.csr.html #[cfg(feature = "x509-parser")] pub fn from_der(csr: &CertificateSigningRequestDer<'_>) -> Result { + use crate::KeyUsagePurpose; use x509_parser::prelude::FromDer; + let csr = x509_parser::certification_request::X509CertificationRequest::from_der(csr) .map_err(|_| Error::CouldNotParseCertificationRequest)? .1; @@ -117,6 +119,11 @@ impl CertificateSigningRequestParams { if let Some(extensions) = csr.requested_extensions() { for ext in extensions { match ext { + x509_parser::extensions::ParsedExtension::KeyUsage(key_usage) => { + // This x509 parser stores flags in reversed bit BIT STRING order + params.key_usages = + KeyUsagePurpose::from_u16(key_usage.flags.reverse_bits()); + }, x509_parser::extensions::ParsedExtension::SubjectAlternativeName(san) => { for name in &san.general_names { params diff --git a/rcgen/tests/generic.rs b/rcgen/tests/generic.rs index 0af46b17..d9eef933 100644 --- a/rcgen/tests/generic.rs +++ b/rcgen/tests/generic.rs @@ -360,7 +360,7 @@ mod test_parse_other_name_alt_name { #[cfg(feature = "x509-parser")] mod test_csr { - use rcgen::{CertificateParams, CertificateSigningRequestParams, KeyPair}; + use rcgen::{CertificateParams, CertificateSigningRequestParams, KeyPair, KeyUsagePurpose}; #[test] fn test_csr_roundtrip() { @@ -375,4 +375,32 @@ mod test_csr { // Ensure algorithms match. assert_eq!(key_pair.algorithm(), csrp.public_key.algorithm()); } + + #[test] + fn test_nontrivial_csr_roundtrip() { + let key_pair = KeyPair::generate().unwrap(); + + // We should be able to serialize a CSR, and then parse the CSR. + let mut params = CertificateParams::default(); + params.key_usages = vec![ + KeyUsagePurpose::DigitalSignature, + KeyUsagePurpose::ContentCommitment, + KeyUsagePurpose::KeyEncipherment, + KeyUsagePurpose::DataEncipherment, + KeyUsagePurpose::KeyAgreement, + KeyUsagePurpose::KeyCertSign, + KeyUsagePurpose::CrlSign, + // It doesn't make sense to have both encipher and decipher only + // So we'll take this opportunity to test omitting a key usage + // KeyUsagePurpose::EncipherOnly, + KeyUsagePurpose::DecipherOnly, + ]; + let csr = params.serialize_request(&key_pair).unwrap(); + let csrp = CertificateSigningRequestParams::from_der(csr.der()).unwrap(); + + // Ensure algorithms match. + assert_eq!(key_pair.algorithm(), csrp.public_key.algorithm()); + // Ensure key usages match. + assert_eq!(csrp.params.key_usages, params.key_usages); + } }