From 14ccaf0fc4a975c1775a46ba8ed33a1284fd5232 Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Sun, 5 Oct 2025 10:21:34 -0400 Subject: [PATCH] tls: replace rustls-pemfile usage with rustls-pki-types rusts-pemfile has been archived and won't see future updates. The rustls-pki-types crate has supported PEM parsing since 1.9.0. This commit converts the existing parsing while maintaining semver compatibility, with the exception of the Error::Pem() enum variant, that exposed a rustls-pemfile type. This breaking change is **not** considered in-scope for ureq's semver policy based on the pre-existing rustdoc comment. --- Cargo.lock | 10 --------- Cargo.toml | 3 +-- src/error.rs | 2 +- src/tls/cert.rs | 55 +++++++++++++++++++++++++++++++------------------ 4 files changed, 37 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b64f00c..f5050faa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1095,15 +1095,6 @@ dependencies = [ "security-framework 3.2.0", ] -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "rustls-pki-types" version = "1.12.0" @@ -1422,7 +1413,6 @@ dependencies = [ "native-tls", "percent-encoding", "rustls", - "rustls-pemfile", "rustls-pki-types", "rustls-platform-verifier", "serde", diff --git a/Cargo.toml b/Cargo.toml index 8a63cb00..22b63040 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ vendored = ["native-tls?/vendored"] # Supported as long as rustls supports this. _ring = ["rustls?/ring"] _url = ["dep:url"] -_tls = ["dep:rustls-pemfile", "dep:rustls-pki-types"] +_tls = ["dep:rustls-pki-types"] _test = [] _rustls = [] _doc = ["rustls?/aws-lc-rs"] @@ -63,7 +63,6 @@ utf-8 = "0.7.6" percent-encoding = "2.3.1" # These are used regardless of TLS implementation. -rustls-pemfile = { version = "2.1.2", optional = true, default-features = false, features = ["std"] } rustls-pki-types = { version = "1.11.0", optional = true, default-features = false, features = ["std"] } rustls-platform-verifier = { version = "0.6.0", optional = true, default-features = false } webpki-roots = { version = "1.0.0", optional = true, default-features = false } diff --git a/src/error.rs b/src/error.rs index e8eea82f..0721cab3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -86,7 +86,7 @@ pub enum Error { /// Breaking changes in that struct will not be reflected in ureq /// major versions. #[cfg(feature = "_tls")] - Pem(rustls_pemfile::Error), + Pem(rustls_pki_types::pem::Error), /// An error originating in Rustls. /// diff --git a/src/tls/cert.rs b/src/tls/cert.rs index 0408d15b..4251b084 100644 --- a/src/tls/cert.rs +++ b/src/tls/cert.rs @@ -193,7 +193,8 @@ impl<'a> PrivateKey<'a> { /// The data may contain one or many PEM items. The iterator produces the recognized PEM /// items and skip others. pub fn parse_pem(pem: &[u8]) -> impl Iterator, Error>> + '_ { - PemIter(pem) + use rustls_pki_types::pem::PemObject; + PemIter(<(rustls_pki_types::pem::SectionKind, Vec)>::pem_slice_iter(pem)) } /// Kinds of PEM data found by [`parse_pem`] @@ -206,43 +207,57 @@ pub enum PemItem<'a> { PrivateKey(PrivateKey<'a>), } -struct PemIter<'a>(&'a [u8]); - -impl<'a> Iterator for PemIter<'a> { +struct PemIter(I) +where + I: Iterator< + Item = Result<(rustls_pki_types::pem::SectionKind, Vec), rustls_pki_types::pem::Error>, + >; + +impl Iterator for PemIter +where + I: Iterator< + Item = Result<(rustls_pki_types::pem::SectionKind, Vec), rustls_pki_types::pem::Error>, + >, +{ type Item = Result, Error>; fn next(&mut self) -> Option { loop { - match rustls_pemfile::read_one_from_slice(self.0) { - Ok(Some((cert, rest))) => { - // Move slice along for next iterator next() - self.0 = rest; - - match cert { - rustls_pemfile::Item::X509Certificate(der) => { + match self.0.next() { + Some(Ok((section_kind, der_data))) => { + match section_kind { + rustls_pki_types::pem::SectionKind::Certificate => { return Some(Ok(Certificate { - der: CertDer::Rustls(der), + der: CertDer::Rustls(rustls_pki_types::CertificateDer::from( + der_data, + )), } .into())); } - rustls_pemfile::Item::Pkcs1Key(der) => { + rustls_pki_types::pem::SectionKind::RsaPrivateKey => { return Some(Ok(PrivateKey { kind: KeyKind::Pkcs1, - der: PrivateKeyDer::Rustls(der.into()), + der: PrivateKeyDer::Rustls(rustls_pki_types::PrivateKeyDer::from( + rustls_pki_types::PrivatePkcs1KeyDer::from(der_data), + )), } .into())); } - rustls_pemfile::Item::Pkcs8Key(der) => { + rustls_pki_types::pem::SectionKind::PrivateKey => { return Some(Ok(PrivateKey { kind: KeyKind::Pkcs8, - der: PrivateKeyDer::Rustls(der.into()), + der: PrivateKeyDer::Rustls(rustls_pki_types::PrivateKeyDer::from( + rustls_pki_types::PrivatePkcs8KeyDer::from(der_data), + )), } .into())); } - rustls_pemfile::Item::Sec1Key(der) => { + rustls_pki_types::pem::SectionKind::EcPrivateKey => { return Some(Ok(PrivateKey { kind: KeyKind::Sec1, - der: PrivateKeyDer::Rustls(der.into()), + der: PrivateKeyDer::Rustls(rustls_pki_types::PrivateKeyDer::from( + rustls_pki_types::PrivateSec1KeyDer::from(der_data), + )), } .into())); } @@ -253,9 +268,9 @@ impl<'a> Iterator for PemIter<'a> { } // It's over - Ok(None) => return None, + None => return None, - Err(e) => { + Some(Err(e)) => { return Some(Err(Error::Pem(e))); } }