uv icon indicating copy to clipboard operation
uv copied to clipboard

`invalid peer certificate: BadSignature` when installing package from private index using ECDSA SHA-512 SSL cert

Open kcon-stackav opened this issue 1 year ago • 7 comments

I use a private Python package index server (anonymized as pypi.internal in the snippets below) that uses an ecdsa-with-SHA512 SSL certificate:

❯ openssl s_client -connect pypi.internal:443 < /dev/null 2>/dev/null | openssl x509 -in /dev/stdin -text -noout -certopt ca_default -certopt no_validity -certopt no_serial -certopt no_subject -certopt no_extensions  -certopt no_sigdump
        Signature Algorithm: ecdsa-with-SHA512

I am able to use pip to fetch and install Python packages from this index, but when I try to use uv it fails with the following error:

❯ uv pip install https://pypi.internal/pypi/package/version/package-version-py3-none-any.whl
error: Failed to download: `package @ https://pypi.internal/pypi/package/version/package-version-py3-none-any.whl`
  Caused by: error sending request for url (https://pypi.internal/pypi/package/version/package-version-py3-none-any.whl)
  Caused by: client error (Connect)
  Caused by: invalid peer certificate: BadSignature

❯ uname -mv
#20~22.04.1-Ubuntu SMP Wed May  1 16:10:50 UTC 2024 x86_64

❯ uv --version
uv 0.2.15

I think this may be the same issue described by https://github.com/rust-lang/rustup/issues/3820, because I understand uv depends on reqwest:

https://github.com/astral-sh/uv/blob/c28a2c758321d3caeead0dd021457b773269d1b3/Cargo.toml#L112

which depends on rustls using the ring feature: https://github.com/seanmonstar/reqwest/blob/c4ebb073438026e09c99469be02fc1f1a254058a/Cargo.toml#L181

and ring does not yet support the ECDSA SHA-512 certificate signature algorithm (WIP but has been open for over 8 months so it's not clear when it would land and be released: https://github.com/briansmith/ring/pull/1631).

I was reading here that it may be possible to configure reqwest to use aws-lc-rs (which does provide support for the ECDSA SHA-512 algorithm for rustls) instead of ring. Here is a draft PR where it looks like rustup is trying to take this approach: https://github.com/rust-lang/rustup/pull/3898

Would ya'll consider switching uv from using ring to aws-lc-rs to support fetching Python packages from an index server whose SSL certificate uses the ECDSA SHA-512 signature algorithm?

kcon-stackav avatar Jun 25 '24 23:06 kcon-stackav

Could you share your private package index TLS setup to reproduce? Are you using nginx as a reverse proxy?

samypr100 avatar Jun 26 '24 02:06 samypr100

@samypr100 thank you for the quick response. 🙏 My private package index's SSL certificate is self-signed by a private CA, and yes I'm using nginx as a reverse proxy where TLS is terminated at the proxy.

kcon-stackav avatar Jun 26 '24 21:06 kcon-stackav

Thanks for confirming @kcon-stackav. Would you be able to share some of the tls settings of the nginx config you're using? (e.g. ssl_protocols, ssl_ciphers, etc.) and also the openssl command used to generate the self-signed certificate? It would help in reproducing the issue.

samypr100 avatar Jun 26 '24 23:06 samypr100

Thanks for the thorough write-up and cross references, that's really helpful. I'd be willing to consider changing backends, though I worry it'd be a breaking change and don't fully understand the implications yet. Would you be interested in opening a pull request to explore the change?

zanieb avatar Jun 27 '24 10:06 zanieb

Thanks for confirming @kcon-stackav. Would you be able to share some of the tls settings of the nginx config you're using? (e.g. ssl_protocols, ssl_ciphers, etc.) and also the openssl command used to generate the self-signed certificate? It would help in reproducing the issue.

We are using nginx with certificates managed by cert-manager. Cert-manager is hooked up to AWS private CA as an issuer. Certificate generation is automated for us. Presumably if you use a ECDSA private key with enough bits it will sign the cert with the problematic algorithm.

Sovietaced avatar Jun 27 '24 17:06 Sovietaced

Thanks for the thorough write-up and cross references, that's really helpful. I'd be willing to consider changing backends, though I worry it'd be a breaking change and don't fully understand the implications yet. Would you be interested in opening a pull request to explore the change?

Thank you! Sure I'll work on a pull request to try to make the change. 🙏

kcon-stackav avatar Jun 27 '24 18:06 kcon-stackav

I created this PR to try out using aws-lc-rs instead of ring for TLS: https://github.com/astral-sh/uv/pull/4734

Unfortunately it looks like it won't solve our issue 😞. Although aws-lc-rs supports the ECDSA SHA-512 certificate signature algorithm we need, our certificate trust chain's issuing CA uses ECDSA P384 for its subject public key algorithm, and I learned that aws-lc-rs does not support verifying that particular combination of subject public key algorithm and signature algorithm.

Instead it only supports verifying a ECDSA SHA-512 signature when the subject public key algorithm is ECDSA P521:

https://github.com/rustls/webpki/blob/dba3b84bcf810612a83c8fd3c750d3c4106e7b9e/src/aws_lc_rs_algs.rs#L70-L75

Or otherwise verifying a ECDSA SHA-384 signature when the subject public key algorithm is ECDSA P384:

https://github.com/rustls/webpki/blob/dba3b84bcf810612a83c8fd3c750d3c4106e7b9e/src/aws_lc_rs_algs.rs#L63-L68

I'm not sure changing our certs to match one of those combinations will be an option, so now I'm thinking our best option may be to leverage https://github.com/astral-sh/uv/issues/1339 once it is available.

kcon-stackav avatar Jul 02 '24 22:07 kcon-stackav

Unfortunately it looks like it won't solve our issue 😞. Although aws-lc-rs supports the ECDSA SHA-512 certificate signature algorithm we need, our certificate trust chain's issuing CA uses ECDSA P384 for its subject public key algorithm, and I learned that aws-lc-rs does not support verifying that particular combination of subject public key algorithm and signature algorithm.

@kcon-stackav Have you tried with the recently released rustls 0.23.12 & the aws-lc-rs provider? There have been a handful of related PRs across the ecosystem:

  • https://github.com/rustls/rustls/pull/2050
  • https://github.com/rustls/webpki/pull/272
  • https://github.com/aws/aws-lc-rs/pull/461

cpu avatar Jul 29 '24 18:07 cpu

@cpu thanks for the heads-up, unfortunately it looks like webpki and the others are still missing support for the particular combination we need (ECDSA P384 with SHA-512 or following their naming convention in https://github.com/rustls/webpki/blob/main/src/aws_lc_rs_algs.rs, I think it would be called something like ECDSA_P384_SHA512).

kcon-stackav avatar Jul 31 '24 18:07 kcon-stackav

@cpu Unrelated, but I just needed to take a moment and appreciate your awesome github handle 🤯

samypr100 avatar Jul 31 '24 20:07 samypr100

I can confirm the support for --allow-insecure-host introduced in 0.3.5 (https://github.com/astral-sh/uv/issues/1339) enables me to use uv with my private Python package index server. 🥳 I'll close this issue for now since we have a workaround. Thanks so much for all of your help! 🙏

kcon-stackav avatar Aug 27 '24 22:08 kcon-stackav