Skip to content

Improve certificate loading error messages#18924

Merged
zanieb merged 1 commit intomainfrom
zb/cert-err
Apr 8, 2026
Merged

Improve certificate loading error messages#18924
zanieb merged 1 commit intomainfrom
zb/cert-err

Conversation

@zanieb
Copy link
Copy Markdown
Member

@zanieb zanieb commented Apr 8, 2026

See #18890

Adds special-case validation for SSL_CERT_FILE and SSL_CERT_DIR where we actually check if webpki will accept the given certificates and, if not, emit a better error message about why. This means we perform eager validation of certificates, parsing them more than once since reqwest will parse them again on client build. Unfortunately, there's not a straight-forward way to provide our pre-parsed certificates to reqwest without doing a lot more work. Nor is there a clear way to retrieve the parsed certificates on error.

We use https://github.com/rusticata/x509-parser for parsing which seems reputable.

We may want to drop all invalid certificates instead, but that can be a future decision and this machinery can be reused for warnings.

Ideally webpki would just have better error messages, but that's a separate project.

Comment thread crates/uv-client/src/tls.rs Outdated
Comment thread crates/uv-client/src/tls.rs Outdated
Comment thread crates/uv-client/src/tls.rs Outdated
Comment thread crates/uv-requirements-txt/src/lib.rs Outdated
Comment thread crates/uv-requirements-txt/src/lib.rs Outdated
Comment thread crates/uv-client/tests/it/ssl_certs.rs Outdated
Comment thread crates/uv-client/tests/it/ssl_certs.rs Outdated
@zanieb zanieb force-pushed the zb/cert-err branch 2 times, most recently from 69ea42b to c13f0c5 Compare April 8, 2026 17:05
Comment on lines +88 to +95
write!(
f,
"; critical extensions: {}",
critical_extensions
.iter()
.map(|oid| format!("`{oid}`"))
.join(", ")
)?;
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't know which critical extensions are supported without hard-coding copies of webpki internals because they don't expose the values publicly.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably good enough debugging information for now

@zanieb zanieb marked this pull request as ready for review April 8, 2026 17:17
@zanieb zanieb added the error messages Messaging when something goes wrong label Apr 8, 2026
Comment thread crates/uv-client/src/tls.rs Outdated
@nooscraft
Copy link
Copy Markdown
Contributor

nooscraft commented Apr 8, 2026

In light of this certificate validation issue, should we update CONTRIBUTING.md to document the TLS backend changes?

Currently it mentions NASM for Windows but doesn't explain:

  • Why the TLS backend changed (ring → aws-lc-rs in 0.11.0)
  • That certificate validation became stricter
  • How to test certificate-related changes
  • What info to provide for certificate issues

@zanieb
Copy link
Copy Markdown
Member Author

zanieb commented Apr 8, 2026

In light of this certificate validation issue, should we update CONTRIBUTING.md to document the TLS backend changes?

What do you mean?

@zanieb
Copy link
Copy Markdown
Member Author

zanieb commented Apr 8, 2026

I don't think the contributing guide is intended to cover debugging certificate issues, no. It's just covering how to build and test the project there. If certificate problems are commonplace and we can't improve the error messages, we can revisit troubleshooting documentation.

source.path().simplified_display(),
source.env_var()
)?;
if let Some(certificate) = certificate.parse() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also log something when the cert fails to parse?

)?;
if let Some(certificate) = certificate.parse() {
let subject = certificate.subject();
if subject.iter_attributes().next().is_some() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't figure out why this condition is important, maybe worth a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's to assert that the subject is non-empty, but it's a bit weird as-written

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor thing, but worth noting that leaf certificates might have an empty subject and non-empty SANs instead.

(In practice I'd mostly expect this error to occur with CAs rather than leaves though.)

Comment on lines +88 to +95
write!(
f,
"; critical extensions: {}",
critical_extensions
.iter()
.map(|oid| format!("`{oid}`"))
.join(", ")
)?;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably good enough debugging information for now

source.path().simplified_display(),
source.env_var()
)?;
if let Some(certificate) = certificate.parse() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same note here: maybe worth logging something if the cert doesn't parse

@zanieb zanieb merged commit f6d67d5 into main Apr 8, 2026
129 of 134 checks passed
@zanieb zanieb deleted the zb/cert-err branch April 8, 2026 19:16
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Apr 9, 2026
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [uv](https://github.com/astral-sh/uv) | patch | `0.11.3` → `0.11.5` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>astral-sh/uv (uv)</summary>

### [`v0.11.5`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0115)

[Compare Source](astral-sh/uv@0.11.4...0.11.5)

Released on 2026-04-08.

##### Python

- Add CPython 3.13.13, 3.14.4, and 3.15.0a8 ([#&#8203;18908](astral-sh/uv#18908))

##### Enhancements

- Fix `build_system.requires` error message ([#&#8203;18911](astral-sh/uv#18911))
- Remove trailing path separators in path normalization ([#&#8203;18915](astral-sh/uv#18915))
- Improve error messages for unsupported or invalid TLS certificates ([#&#8203;18924](astral-sh/uv#18924))

##### Preview features

- Add `exclude-newer` to `[[tool.uv.index]]` ([#&#8203;18839](astral-sh/uv#18839))
- `uv audit`: add context/warnings for ignored vulnerabilities ([#&#8203;18905](astral-sh/uv#18905))

##### Bug fixes

- Normalize persisted fork markers before lock equality checks ([#&#8203;18612](astral-sh/uv#18612))
- Clear junction properly when uninstalling Python versions on Windows ([#&#8203;18815](astral-sh/uv#18815))
- Report error cleanly instead of panicking on TLS certificate error ([#&#8203;18904](astral-sh/uv#18904))

##### Documentation

- Remove the legacy `PIP_COMPATIBILITY.md` redirect file ([#&#8203;18928](astral-sh/uv#18928))
- Fix `uv init example-bare --bare` examples ([#&#8203;18822](astral-sh/uv#18822), [#&#8203;18925](astral-sh/uv#18925))

### [`v0.11.4`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#0114)

[Compare Source](astral-sh/uv@0.11.3...0.11.4)

Released on 2026-04-07.

##### Enhancements

- Add support for `--upgrade-group` ([#&#8203;18266](astral-sh/uv#18266))
- Merge repeated archive URL hashes by version ID ([#&#8203;18841](astral-sh/uv#18841))
- Require all direct URL hash algorithms to match ([#&#8203;18842](astral-sh/uv#18842))

##### Bug fixes

- Avoid panics in environment finding via cycle detection ([#&#8203;18828](astral-sh/uv#18828))
- Enforce direct URL hashes for `pyproject.toml` dependencies ([#&#8203;18786](astral-sh/uv#18786))
- Error on `--locked` and `--frozen` when script lockfile is missing ([#&#8203;18832](astral-sh/uv#18832))
- Fix `uv export` extra resolution for workspace member and conflicting extras ([#&#8203;18888](astral-sh/uv#18888))
- Include conflicts defined in virtual workspace root ([#&#8203;18886](astral-sh/uv#18886))
- Recompute relative `exclude-newer` values during `uv tree --outdated` ([#&#8203;18899](astral-sh/uv#18899))
- Respect `--exclude-newer` in `uv tool list --outdated` ([#&#8203;18861](astral-sh/uv#18861))
- Sort by comparator to break specifier ties ([#&#8203;18850](astral-sh/uv#18850))
- Store relative timestamps in tool receipts ([#&#8203;18901](astral-sh/uv#18901))
- Track newly-activated extras when determining conflicts ([#&#8203;18852](astral-sh/uv#18852))
- Patch `Cargo.lock` in `uv-build` source distributions ([#&#8203;18831](astral-sh/uv#18831))

##### Documentation

- Clarify that `--exclude-newer` compares artifact upload times ([#&#8203;18830](astral-sh/uv#18830))

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDkuMyIsInVwZGF0ZWRJblZlciI6IjQzLjEwOS4zIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiLCJhdXRvbWF0aW9uOmJvdC1hdXRob3JlZCIsImRlcGVuZGVuY3ktdHlwZTo6cGF0Y2giXX0=-->
zanieb added a commit that referenced this pull request Apr 9, 2026
Closes #18890

Resolves the unexpected regression in 0.11 where `rustls-native-certs`
was previously performing filtering and switching to populating
certificates in reqwest ourselves resulted in stricter validation.

Follows #18924 which added
pre-validation of certificates with better error messages. We retain
some of the error infrastructure for formatting a warning, but no longer
propagate it upward. We emit a log instead of a noisy user-facing
warning because they are often powerless to fix this and it's only
consequential if they attempt to communicate with a service that
requires the certificate (at which point, we'd just fail anyway).

Ideally, there's an upstream resolution in
rustls/webpki#464 as we're still reading and
validating all of these certificates more than once.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

error messages Messaging when something goes wrong

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants