From 8def5056fbc5b8e49727fd950ae5080f60f7a7a9 Mon Sep 17 00:00:00 2001 From: Tudyx <56633664+Tudyx@users.noreply.github.com> Date: Wed, 14 Feb 2024 23:52:47 +0100 Subject: [PATCH] add certificate signing request --- Cargo.toml | 2 +- src/lib.rs | 29 ++++++++++++++++++++++++++--- src/pemfile.rs | 10 ++++++++-- tests/data/csr.pem | 18 ++++++++++++++++++ tests/data/zen.pem | 18 ++++++++++++++++++ tests/integration.rs | 14 +++++++++++++- 6 files changed, 84 insertions(+), 7 deletions(-) create mode 100644 tests/data/csr.pem diff --git a/Cargo.toml b/Cargo.toml index 19139a6..3e7c976 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ categories = ["network-programming", "cryptography"] [dependencies] base64 = { version = "0.21", default-features = false, features = ["alloc"] } -pki-types = { package = "rustls-pki-types", version = "1" } +pki-types = { package = "rustls-pki-types", version = "1.3" } [dev-dependencies] bencher = "0.1.5" diff --git a/src/lib.rs b/src/lib.rs index 9c5f993..1cdd426 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,6 +30,7 @@ //! match item.unwrap() { //! Item::X509Certificate(cert) => println!("certificate {:?}", cert), //! Item::Crl(crl) => println!("certificate revocation list: {:?}", crl), +//! Item::Csr(csr) => println!("certificate signing request: {:?}", csr), //! Item::Pkcs1Key(key) => println!("rsa pkcs1 key {:?}", key), //! Item::Pkcs8Key(key) => println!("pkcs8 key {:?}", key), //! Item::Sec1Key(key) => println!("sec1 ec key {:?}", key), @@ -67,8 +68,8 @@ pub use pemfile::{read_one_from_slice, Error, Item}; use pki_types::PrivateKeyDer; #[cfg(feature = "std")] use pki_types::{ - CertificateDer, CertificateRevocationListDer, PrivatePkcs1KeyDer, PrivatePkcs8KeyDer, - PrivateSec1KeyDer, + CertificateDer, CertificateRevocationListDer, CertificateSigningRequestDer, PrivatePkcs1KeyDer, + PrivatePkcs8KeyDer, PrivateSec1KeyDer, }; #[cfg(feature = "std")] @@ -103,7 +104,29 @@ pub fn private_key(rd: &mut dyn io::BufRead) -> Result return Ok(Some(key.into())), Item::Pkcs8Key(key) => return Ok(Some(key.into())), Item::Sec1Key(key) => return Ok(Some(key.into())), - Item::X509Certificate(_) | Item::Crl(_) => continue, + Item::X509Certificate(_) | Item::Crl(_) | Item::Csr(_) => continue, + } + } + + Ok(None) +} + +/// Return the first certificate signing request (CSR) found in `rd`. +/// +/// Yields the first PEM section describing a certificate signing request, or an error if a +/// problem occurs while trying to read PEM sections. +#[cfg(feature = "std")] +pub fn csr( + rd: &mut dyn io::BufRead, +) -> Result>, io::Error> { + for result in iter::from_fn(move || read_one(rd).transpose()) { + match result? { + Item::Csr(csr) => return Ok(Some(csr)), + Item::Pkcs1Key(_) + | Item::Pkcs8Key(_) + | Item::Sec1Key(_) + | Item::X509Certificate(_) + | Item::Crl(_) => continue, } } diff --git a/src/pemfile.rs b/src/pemfile.rs index d60da0a..f633204 100644 --- a/src/pemfile.rs +++ b/src/pemfile.rs @@ -9,8 +9,8 @@ use core::ops::ControlFlow; use std::io::{self, ErrorKind}; use pki_types::{ - CertificateDer, CertificateRevocationListDer, PrivatePkcs1KeyDer, PrivatePkcs8KeyDer, - PrivateSec1KeyDer, + CertificateDer, CertificateRevocationListDer, CertificateSigningRequestDer, PrivatePkcs1KeyDer, + PrivatePkcs8KeyDer, PrivateSec1KeyDer, }; /// The contents of a single recognised block in a PEM file. @@ -41,6 +41,11 @@ pub enum Item { /// /// Appears as "X509 CRL" in PEM files. Crl(CertificateRevocationListDer<'static>), + + /// A Certificate Signing Request; as specified in RFC 2986 + /// + /// Appears as "CERTIFICATE REQUEST" in PEM files. + Csr(CertificateSigningRequestDer<'static>), } /// Errors that may arise when parsing the contents of a PEM file @@ -195,6 +200,7 @@ fn read_one_impl( b"PRIVATE KEY" => Some(Item::Pkcs8Key(der.into())), b"EC PRIVATE KEY" => Some(Item::Sec1Key(der.into())), b"X509 CRL" => Some(Item::Crl(der.into())), + b"CERTIFICATE REQUEST" => Some(Item::Csr(der.into())), _ => { *section = None; b64buf.clear(); diff --git a/tests/data/csr.pem b/tests/data/csr.pem new file mode 100644 index 0000000..b1ea6d4 --- /dev/null +++ b/tests/data/csr.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIIC+zCCAeMCAQAwfDELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRQwEgYD +VQQHDAtTYW4gQW50b25pbzEdMBsGA1UECgwURXhhbXBsZSBPcmdhbml6YXRpb24x +EjAQBgNVBAsMCU1hcmtldGluZzEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCwJw0BcbuqZyiABlmSYTi1tcr8DB0D +NcTtzsYe7tlyIKd3mEs+u6Pi3rEQGvOw5eo6CmWII2qmVOqJ2f6gjl2lZJ5DUE6B +I+NNE73zfFMrttUtI8X4ChnE4rrGqqUsSvYz1YVU0KiJ/00YMjEY5XlJYYa9FgfZ +sUrhj4aCFdXS6CU9jueRr+udEBElDcgTS9+pB+LFhVfUMTdxnJ3BcT4ZDDqODH3/ +5RAgq03dhRpkkaVIg2uVKTBDoM3hs8T1zIxLM7hItaZzMv4uHdfI8y+BdHrePT33 +BoTlocvTEZEqqXEdw2kUd4PDgyUTjFE3b9OeLk0Ju5GRvuCW3UcS5gFvAgMBAAGg +OjA4BgkqhkiG9w0BCQ4xKzApMCcGA1UdEQQgMB6CC2V4YW1wbGUuY29tgg9mb28u +ZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggEBACWsgxPw13QUpoCJOqvp8B1A +EfsxRJITSROmukV3ZQycPT76Y3GVrM9sGjO8p13J/CVw2KcWc9xmgHF0MdvPNhnW +OB6Y07hVpNnJVHb1KglOkNkTy6sVDtnZHg2klqGSyzIbwZ9R3JG8HtRdkceIrm3D +gdiZyLcf1VDCCUGaskEi2CsggCQQJNyGi+8BSQ8MPKm/m0KrSchGQ157eWCCjopz +f5GQe2UGOg5T7g8+S4GdECMwkMlTGUwlAM6LuOG/NZqP528PCAYQv0eOYdSwALQT +GwTyU4AZ9y1uBFuaFxABew9GbDEtNY/XHTF8308edUwGBk6jfD+UuTeEwRZGs9E= +-----END CERTIFICATE REQUEST----- diff --git a/tests/data/zen.pem b/tests/data/zen.pem index a62add2..6959b73 100644 --- a/tests/data/zen.pem +++ b/tests/data/zen.pem @@ -117,4 +117,22 @@ vTwHyadGSMK4CWtrn9fCAgSLw6NX74D7Cx1IaS8vstMjpeUqOS0dk5ThiW47HceB DTko7rV5N+RGH2nW1ynLoZKCJQqqZcLilFMyKPui3jifJnQlMFi54jGVgg/D6UQn 7dA7wb2ux/1hSiaarp+mi7ncVOyByz6/WQP8mfc= -----END X509 CRL----- +-----BEGIN CERTIFICATE REQUEST----- +MIIC+zCCAeMCAQAwfDELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRQwEgYD +VQQHDAtTYW4gQW50b25pbzEdMBsGA1UECgwURXhhbXBsZSBPcmdhbml6YXRpb24x +EjAQBgNVBAsMCU1hcmtldGluZzEUMBIGA1UEAwwLZXhhbXBsZS5jb20wggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCwJw0BcbuqZyiABlmSYTi1tcr8DB0D +NcTtzsYe7tlyIKd3mEs+u6Pi3rEQGvOw5eo6CmWII2qmVOqJ2f6gjl2lZJ5DUE6B +I+NNE73zfFMrttUtI8X4ChnE4rrGqqUsSvYz1YVU0KiJ/00YMjEY5XlJYYa9FgfZ +sUrhj4aCFdXS6CU9jueRr+udEBElDcgTS9+pB+LFhVfUMTdxnJ3BcT4ZDDqODH3/ +5RAgq03dhRpkkaVIg2uVKTBDoM3hs8T1zIxLM7hItaZzMv4uHdfI8y+BdHrePT33 +BoTlocvTEZEqqXEdw2kUd4PDgyUTjFE3b9OeLk0Ju5GRvuCW3UcS5gFvAgMBAAGg +OjA4BgkqhkiG9w0BCQ4xKzApMCcGA1UdEQQgMB6CC2V4YW1wbGUuY29tgg9mb28u +ZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggEBACWsgxPw13QUpoCJOqvp8B1A +EfsxRJITSROmukV3ZQycPT76Y3GVrM9sGjO8p13J/CVw2KcWc9xmgHF0MdvPNhnW +OB6Y07hVpNnJVHb1KglOkNkTy6sVDtnZHg2klqGSyzIbwZ9R3JG8HtRdkceIrm3D +gdiZyLcf1VDCCUGaskEi2CsggCQQJNyGi+8BSQ8MPKm/m0KrSchGQ157eWCCjopz +f5GQe2UGOg5T7g8+S4GdECMwkMlTGUwlAM6LuOG/NZqP528PCAYQv0eOYdSwALQT +GwTyU4AZ9y1uBFuaFxABew9GbDEtNY/XHTF8308edUwGBk6jfD+UuTeEwRZGs9E= +-----END CERTIFICATE REQUEST----- ... that's all folks! diff --git a/tests/integration.rs b/tests/integration.rs index 10684f6..27d5b9c 100644 --- a/tests/integration.rs +++ b/tests/integration.rs @@ -26,6 +26,17 @@ fn private_key() { assert!(rustls_pemfile::private_key(&mut reader).unwrap().is_none()); } +#[test] +fn test_csr() { + let data = include_bytes!("data/csr.pem"); + let mut reader = BufReader::new(&data[..]); + rustls_pemfile::csr(&mut reader).unwrap().unwrap(); + + let data = include_bytes!("data/certificate.chain.pem"); + let mut reader = BufReader::new(&data[..]); + assert!(rustls_pemfile::private_key(&mut reader).unwrap().is_none()); +} + #[test] fn test_certs() { let data = include_bytes!("data/certificate.chain.pem"); @@ -139,7 +150,7 @@ fn parse_in_order() { let items = rustls_pemfile::read_all(&mut reader) .collect::, _>>() .unwrap(); - assert_eq!(items.len(), 9); + assert_eq!(items.len(), 10); assert!(matches!(items[0], rustls_pemfile::Item::X509Certificate(_))); assert!(matches!(items[1], rustls_pemfile::Item::X509Certificate(_))); assert!(matches!(items[2], rustls_pemfile::Item::X509Certificate(_))); @@ -149,6 +160,7 @@ fn parse_in_order() { assert!(matches!(items[6], rustls_pemfile::Item::Pkcs1Key(_))); assert!(matches!(items[7], rustls_pemfile::Item::Pkcs8Key(_))); assert!(matches!(items[8], rustls_pemfile::Item::Crl(_))); + assert!(matches!(items[9], rustls_pemfile::Item::Csr(_))); } #[test]