From 9a1da55aab69064dc9fe566993d91e71187e6278 Mon Sep 17 00:00:00 2001 From: Joe Birr-Pixton Date: Fri, 27 Sep 2024 13:46:22 +0100 Subject: [PATCH] Add helper for combined PEM decoding of ech+key --- src/lib.rs | 44 ++++++++++++++++++++++++++++++++++++++++++++ tests/pem.rs | 14 ++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 4d20fb2..9402d63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -761,6 +761,50 @@ impl EchConfigListBytes<'_> { } } +#[cfg(feature = "alloc")] +impl EchConfigListBytes<'static> { + /// Convert an iterator over PEM items into an `EchConfigListBytes` and private key. + /// + /// This handles the "ECHConfig file" format specified in + /// + /// + /// Use it like: + /// + /// ```rust + /// # #[cfg(all(feature = "alloc", feature = "std"))] { + /// # use rustls_pki_types::{EchConfigListBytes, pem::PemObject}; + /// let (config, key) = EchConfigListBytes::config_and_key_from_iter( + /// PemObject::pem_file_iter("tests/data/ech.pem").unwrap() + /// ).unwrap(); + /// # } + /// ``` + pub fn config_and_key_from_iter( + iter: impl Iterator), pem::Error>>, + ) -> Result<(Self, PrivatePkcs8KeyDer<'static>), pem::Error> { + let mut key = None; + let mut config = None; + + for item in iter { + let (kind, data) = item?; + match kind { + SectionKind::PrivateKey => { + key = PrivatePkcs8KeyDer::from_pem(kind, data); + } + SectionKind::EchConfigList => { + config = Self::from_pem(kind, data); + } + _ => continue, + }; + + if let (Some(_key), Some(_config)) = (&key, &config) { + return Ok((config.take().unwrap(), key.take().unwrap())); + } + } + + Err(pem::Error::NoItemsFound) + } +} + #[cfg(feature = "alloc")] impl PemObjectFilter for EchConfigListBytes<'static> { const KIND: SectionKind = SectionKind::EchConfigList; diff --git a/tests/pem.rs b/tests/pem.rs index 23ae537..a82e409 100644 --- a/tests/pem.rs +++ b/tests/pem.rs @@ -193,6 +193,20 @@ fn ech_config() { EchConfigListBytes::from_pem_file("tests/data/certificate.chain.pem").unwrap_err(), pem::Error::NoItemsFound )); + + let (config, key) = EchConfigListBytes::config_and_key_from_iter( + PemObject::pem_file_iter("tests/data/ech.pem").unwrap(), + ) + .unwrap(); + println!("{config:?} {key:?}"); + + assert!(matches!( + EchConfigListBytes::config_and_key_from_iter( + PemObject::pem_file_iter("tests/data/certificate.chain.pem").unwrap(), + ) + .unwrap_err(), + pem::Error::NoItemsFound, + )); } #[test]