From 7c5072b94178a6e01a981bfdaae852f5cf3f5829 Mon Sep 17 00:00:00 2001 From: katelyn martin Date: Tue, 5 May 2026 11:19:00 -0400 Subject: [PATCH] fix(tls): migrate from `rustls-pemfile` to `rustls-pki-types` `rustls-pemfile` is unmaintained and has been archived since august 2025 (see https://rustsec.org/advisories/RUSTSEC-2025-0134), leading to rustsec audit errors downstream. `rustls-pemfile` at this point is thin wrappers around the parsing logic in `rustls-pki-types`, so this does a direct translation to those apis. this commit is based upon work originally done in #432, but includes additional changes to address this comment that was noted during review: > I was wondering why we now need to call `map_err()` here, so I went > check for changes in the error types, before and after. > > After a few indirections I found out that rustls-pemfile ultimately > maps to either returning directly an `std::io::Error` as a result of > file operations, or a newly crafted `io::Error` type with > `InvalidData` kind and a lossy string out of the byte buffer > (presumably with PEM data), see > https://docs.rs/rustls-pemfile/2.2.0/src/rustls_pemfile/pemfile.rs.html#123-145. > With the new crate and this mapping we'll end up with an `io::Error` > type with an other/custom kind that prints out PEM data buffers > directly, see > https://docs.rs/rustls-pki-types/latest/src/rustls_pki_types/pem.rs.html#498-513. > > Consumers won't be able to match on the kind directly (it's always the > same kind now), although they will still be able to downcast the inner > error at the cost of depending on rustls-pki-types. The display > implementation prints out bytes directly instead of a string, which > I'm not sure is an improvement. > > Not sure this matters much in practice, but it changes the semantics > of error handling code. I think if we want to keep the same semantics > we could adapt the code in rustls-pemfile converting to an > `io::Error`. \- https://github.com/olix0r/kubert/pull/437#discussion_r3080056682 this commit carries forward the precise pem error semantics from before, now mapping errors caused by missing section end markers, illegal section starts, and decoding errors into an "invalid data" error. the same lossy string formatting is also carried forward, instead of directly printing bytes. Signed-off-by: katelyn martin --- kubert/Cargo.toml | 4 +-- kubert/src/server/tls_rustls.rs | 49 +++++++++++++++++++++++++++++---- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/kubert/Cargo.toml b/kubert/Cargo.toml index ec49c3c..ecdd46e 100644 --- a/kubert/Cargo.toml +++ b/kubert/Cargo.toml @@ -11,7 +11,7 @@ keywords = ["kubernetes", "client", "runtime", "server"] [features] _tls = [ - "dep:rustls-pemfile", + "dep:rustls-pki-types", "dep:tokio-rustls", "kube-client?/rustls-tls", ] @@ -194,7 +194,7 @@ once_cell = { version = "1", optional = true } parking_lot = { version = "0.12", optional = true } pin-project-lite = { version = "0.2", optional = true } prometheus-client = { workspace = true, optional = true } -rustls-pemfile = { version = "2", optional = true } +rustls-pki-types = { version = "1", optional = true } serde = { version = "1", optional = true } serde_json = { version = "1", optional = true } sha2 = { version = "0.10", optional = true } diff --git a/kubert/src/server/tls_rustls.rs b/kubert/src/server/tls_rustls.rs index 52e0354..ec34d70 100644 --- a/kubert/src/server/tls_rustls.rs +++ b/kubert/src/server/tls_rustls.rs @@ -1,4 +1,8 @@ use super::*; +use rustls_pki_types::{ + pem::{Error as PemError, PemObject as _}, + PrivatePkcs1KeyDer, PrivatePkcs8KeyDer, +}; use std::sync::Arc; use tokio_rustls::{ rustls::{ @@ -39,19 +43,23 @@ async fn load_certs( TlsCertPath(cp): &TlsCertPath, ) -> std::io::Result>> { let pem = tokio::fs::read(cp).await?; - rustls_pemfile::certs(&mut pem.as_slice()).collect() + CertificateDer::pem_slice_iter(pem.as_slice()) + .collect::, _>>() + .map_err(pem_error_into_io_error) } async fn load_private_key(TlsKeyPath(kp): &TlsKeyPath) -> std::io::Result> { let pem = tokio::fs::read(kp).await?; - let mut keys = rustls_pemfile::pkcs8_private_keys(&mut pem.as_slice()) + let mut keys = PrivatePkcs8KeyDer::pem_slice_iter(pem.as_slice()) .map(|res| res.map(PrivateKeyDer::from)) - .collect::, _>>()?; + .collect::, _>>() + .map_err(pem_error_into_io_error)?; if keys.is_empty() { - keys = rustls_pemfile::rsa_private_keys(&mut pem.as_slice()) + keys = PrivatePkcs1KeyDer::pem_slice_iter(pem.as_slice()) .map(|res| res.map(PrivateKeyDer::from)) - .collect::, _>>()?; + .collect::, _>>() + .map_err(pem_error_into_io_error)?; } let key = keys @@ -62,3 +70,34 @@ async fn load_private_key(TlsKeyPath(kp): &TlsKeyPath) -> std::io::Result std::io::Error { + use std::io::{self, ErrorKind}; + + match error { + PemError::MissingSectionEnd { end_marker } => io::Error::new( + ErrorKind::InvalidData, + format!( + "section end {:?} missing", + String::from_utf8_lossy(&end_marker) + ), + ), + + PemError::IllegalSectionStart { line } => io::Error::new( + ErrorKind::InvalidData, + format!( + "illegal section start: {:?}", + String::from_utf8_lossy(&line) + ), + ), + + PemError::Base64Decode(err) => io::Error::new(ErrorKind::InvalidData, err), + error => io::Error::other(error), + } +}