Skip to content

fix(tls): Migrate from rustls-pemfile to rustls-pki-types#432

Closed
sfleen wants to merge 1 commit intoolix0r:mainfrom
sfleen:sfleen/rustls-pemfile-migrate
Closed

fix(tls): Migrate from rustls-pemfile to rustls-pki-types#432
sfleen wants to merge 1 commit intoolix0r:mainfrom
sfleen:sfleen/rustls-pemfile-migrate

Conversation

@sfleen
Copy link
Copy Markdown
Contributor

@sfleen sfleen commented Jan 9, 2026

rustls-pemfile is unmaintained and has been archived since Aug 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 also requires an MSRV bump from 1.85 to 1.88

@sfleen sfleen force-pushed the sfleen/rustls-pemfile-migrate branch 5 times, most recently from eb3b180 to 7921c71 Compare January 9, 2026 15:14
@sfleen sfleen marked this pull request as draft January 9, 2026 15:19
@sfleen sfleen force-pushed the sfleen/rustls-pemfile-migrate branch 2 times, most recently from e7b1510 to 31fc6a9 Compare January 9, 2026 16:54
@sfleen sfleen marked this pull request as ready for review January 9, 2026 17:00
@sfleen sfleen marked this pull request as draft January 12, 2026 16:35
`rustls-pemfile` is unmaintained and has been archived since Aug 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.
@sfleen sfleen force-pushed the sfleen/rustls-pemfile-migrate branch from 31fc6a9 to c873394 Compare January 12, 2026 16:37
@cratelyn

This comment was marked as resolved.

cratelyn added a commit to linkerd/linkerd2-proxy that referenced this pull request Apr 13, 2026
see rustls/pemfile#61, and [RUSTSEC-2025-0134](https://rustsec.org/advisories/RUSTSEC-2025-0134). see also, olix0r/kubert#432.

this branch updates the place where we invoke `rustls_pemfile::certs`
inside of `linkerd-meshtls` and `linkerd-app-integration`.

see <https://docs.rs/rustls-pemfile/latest/src/rustls_pemfile/lib.rs.html#85-93>
for a link to the original `certs()` function being replaced here:

```rust
 // https://docs.rs/rustls-pemfile/latest/src/rustls_pemfile/lib.rs.html#85-93
 pub fn certs(
     rd: &mut dyn io::BufRead,
 ) -> impl Iterator<Item = Result<CertificateDer<'static>, io::Error>> + '_ {
     iter::from_fn(move || read_one(rd).transpose()).filter_map(|item| match item {
         Ok(Item::X509Certificate(cert)) => Some(Ok(cert)),
         Err(err) => Some(Err(err)),
         _ => None,
     })
 }

 // https://docs.rs/rustls-pemfile/latest/src/rustls_pemfile/pemfile.rs.html
 /// Extract and decode the next PEM section from `rd`.
 ///
 /// - Ok(None) is returned if there is no PEM section read from `rd`.
 /// - Underlying IO errors produce a `Err(...)`
 /// - Otherwise each decoded section is returned with a `Ok(Some(Item::...))`
 ///
 /// You can use this function to build an iterator, for example:
 /// `for item in iter::from_fn(|| read_one(rd).transpose()) { ... }`
 #[cfg(feature = "std")]
 pub fn read_one(rd: &mut dyn io::BufRead) -> Result<Option<Item>, io::Error> {
     Item::from_buf(rd).map_err(|err| match err {
         pem::Error::Io(io) => io,
         other => Error::from(other).into(),
     })
 }
```

in `rustls_pki_types`, we do this using the `PemObject` trait. this
provides facilities to read PEM files through various interfaces, but
`pem_slice_iter()` feels like the most natural fit here. this takes an
in-memory `&'a [u8]` byte slice representing the contents of a PEM file,
and returns an iterator yielding `CertificateDer` deserialized
certificates.

that closely follows the same interface that `certs()` (above) presented
us.

<https://docs.rs/rustls-pki-types/latest/rustls_pki_types/pem/trait.PemObject.html#method.pem_slice_iter>

---

* refactor: `rustls-pemfile` is a workspace dependency

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor: replace `rustls-pemfile` with `rustls-pki-types`

NB: code is not update here, only package manifests.

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(meshtls): update `rustls_pemfile::certs` call

this commit updates the place where we invoke `rustls_pemfile::certs`
inside of `linkerd-meshtls`.

see <https://docs.rs/rustls-pemfile/latest/src/rustls_pemfile/lib.rs.html#85-93>
for a link to the original `certs()` function being replaced here:

```rust
 // https://docs.rs/rustls-pemfile/latest/src/rustls_pemfile/lib.rs.html#85-93
 pub fn certs(
     rd: &mut dyn io::BufRead,
 ) -> impl Iterator<Item = Result<CertificateDer<'static>, io::Error>> + '_ {
     iter::from_fn(move || read_one(rd).transpose()).filter_map(|item| match item {
         Ok(Item::X509Certificate(cert)) => Some(Ok(cert)),
         Err(err) => Some(Err(err)),
         _ => None,
     })
 }

 // https://docs.rs/rustls-pemfile/latest/src/rustls_pemfile/pemfile.rs.html
 /// Extract and decode the next PEM section from `rd`.
 ///
 /// - Ok(None) is returned if there is no PEM section read from `rd`.
 /// - Underlying IO errors produce a `Err(...)`
 /// - Otherwise each decoded section is returned with a `Ok(Some(Item::...))`
 ///
 /// You can use this function to build an iterator, for example:
 /// `for item in iter::from_fn(|| read_one(rd).transpose()) { ... }`
 #[cfg(feature = "std")]
 pub fn read_one(rd: &mut dyn io::BufRead) -> Result<Option<Item>, io::Error> {
     Item::from_buf(rd).map_err(|err| match err {
         pem::Error::Io(io) => io,
         other => Error::from(other).into(),
     })
 }
```

in `rustls_pki_types`, we do this using the `PemObject` trait. this
provides facilities to read PEM files through various interfaces, but
`pem_slice_iter()` feels like the most natural fit here. this takes an
in-memory `&'a [u8]` byte slice representing the contents of a PEM file,
and returns an iterator yielding `CertificateDer` deserialized
certificates.

that closely follows the same interface that `certs()` (above) presented
us.

<https://docs.rs/rustls-pki-types/latest/rustls_pki_types/pem/trait.PemObject.html#method.pem_slice_iter>

Signed-off-by: katelyn martin <kate@buoyant.io>

* chore(app/integration): update `rustls_pemfile::certs` calls

as with the previous commit, we update calls to `rustls_pemfile::certs`.

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor: use `AsRef<[u8]>` for byte slices

this polishes some type signatures. `CertificateDer::pem_slice_iter`
accepts a slice of bytes. we must, for various reasons such as dealing
with our `TestEnv` system, sometimes hold our PEM data in the form of a
UTF-8 string.

this commit uses `AsRef` to coerce types to a slice of bytes rather
than presenting these parameters as `&str` string slices, which is
needlessly specific.

Signed-off-by: katelyn martin <kate@buoyant.io>

* refactor: `rustls-webpki` is a workspace dependency

this crate is related to rustls-pki-types, and the feature flags we set
on rustls-webpki affects which flags are enabled on rustls-pki-types.

defining both as workspace dependencies should help make this
relationship slightly more discoverable.

Signed-off-by: katelyn martin <kate@buoyant.io>

* nit(app/integration): add `rustls-pki-typess/std` flag

strictly speaking, we need this feature flag.

it's enabled for us already as part of `linkerd-meshtls`'s dependency on
the `rustls-webpki/alloc` flag, which `linkerd-app-integration` in turns
depends on.

that said, it's nice to be extra clear that we depend upon the `std`
flag should that change in the future.

Signed-off-by: katelyn martin <kate@buoyant.io>

---------

Signed-off-by: katelyn martin <kate@buoyant.io>
@cratelyn
Copy link
Copy Markdown
Collaborator

this is superseded by #437.

@cratelyn cratelyn closed this Apr 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants