Skip to content

Commit 964f9c6

Browse files
lvkvdjc
authored andcommitted
Add KeyUsagePurpose support to CSR from DER; add CSR test
1 parent 40974f1 commit 964f9c6

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

rcgen/src/csr.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,9 @@ impl CertificateSigningRequestParams {
9494
/// [`rustls_pemfile::csr()`]: https://docs.rs/rustls-pemfile/latest/rustls_pemfile/fn.csr.html
9595
#[cfg(feature = "x509-parser")]
9696
pub fn from_der(csr: &CertificateSigningRequestDer<'_>) -> Result<Self, Error> {
97+
use crate::KeyUsagePurpose;
9798
use x509_parser::prelude::FromDer;
99+
98100
let csr = x509_parser::certification_request::X509CertificationRequest::from_der(csr)
99101
.map_err(|_| Error::CouldNotParseCertificationRequest)?
100102
.1;
@@ -117,6 +119,11 @@ impl CertificateSigningRequestParams {
117119
if let Some(extensions) = csr.requested_extensions() {
118120
for ext in extensions {
119121
match ext {
122+
x509_parser::extensions::ParsedExtension::KeyUsage(key_usage) => {
123+
// This x509 parser stores flags in reversed bit BIT STRING order
124+
params.key_usages =
125+
KeyUsagePurpose::from_u16(key_usage.flags.reverse_bits());
126+
},
120127
x509_parser::extensions::ParsedExtension::SubjectAlternativeName(san) => {
121128
for name in &san.general_names {
122129
params

rcgen/tests/generic.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ mod test_parse_other_name_alt_name {
360360

361361
#[cfg(feature = "x509-parser")]
362362
mod test_csr {
363-
use rcgen::{CertificateParams, CertificateSigningRequestParams, KeyPair};
363+
use rcgen::{CertificateParams, CertificateSigningRequestParams, KeyPair, KeyUsagePurpose};
364364

365365
#[test]
366366
fn test_csr_roundtrip() {
@@ -375,4 +375,32 @@ mod test_csr {
375375
// Ensure algorithms match.
376376
assert_eq!(key_pair.algorithm(), csrp.public_key.algorithm());
377377
}
378+
379+
#[test]
380+
fn test_nontrivial_csr_roundtrip() {
381+
let key_pair = KeyPair::generate().unwrap();
382+
383+
// We should be able to serialize a CSR, and then parse the CSR.
384+
let mut params = CertificateParams::default();
385+
params.key_usages = vec![
386+
KeyUsagePurpose::DigitalSignature,
387+
KeyUsagePurpose::ContentCommitment,
388+
KeyUsagePurpose::KeyEncipherment,
389+
KeyUsagePurpose::DataEncipherment,
390+
KeyUsagePurpose::KeyAgreement,
391+
KeyUsagePurpose::KeyCertSign,
392+
KeyUsagePurpose::CrlSign,
393+
// It doesn't make sense to have both encipher and decipher only
394+
// So we'll take this opportunity to test omitting a key usage
395+
// KeyUsagePurpose::EncipherOnly,
396+
KeyUsagePurpose::DecipherOnly,
397+
];
398+
let csr = params.serialize_request(&key_pair).unwrap();
399+
let csrp = CertificateSigningRequestParams::from_der(csr.der()).unwrap();
400+
401+
// Ensure algorithms match.
402+
assert_eq!(key_pair.algorithm(), csrp.public_key.algorithm());
403+
// Ensure key usages match.
404+
assert_eq!(csrp.params.key_usages, params.key_usages);
405+
}
378406
}

0 commit comments

Comments
 (0)