Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustls refuses to establish connections to self signed TLS certificates #10312

Open
lucacasonato opened this issue Apr 22, 2021 · 19 comments · Fixed by denoland/wpt#19
Open

rustls refuses to establish connections to self signed TLS certificates #10312

lucacasonato opened this issue Apr 22, 2021 · 19 comments · Fixed by denoland/wpt#19
Labels
bug Something isn't working correctly ext/fetch related to the ext/fetch ext/websocket related to the ext/websocket crate tls Issues related to TLS implementation upstream Changes in upstream are required to solve these issues

Comments

@lucacasonato
Copy link
Member

Reproduction

The key chain this uses is made up of two parts. The CA (./test_util/wpt/tools/certs/cacert.pem) and the end entity certificate (./test_util/wpt/tools/certs/web-platform.test.pem).

To start the testing server:

deno run -A --unstable ./tools/wpt.ts setup
cd ./test_util/wpt
./wpt serve

See that curling the endpoint with the correct CA cert in the roots works, and without doesn't:

$ curl -v https://web-platform.test:8444/ --cacert ./test_util/wpt/tools/certs/cacert.pem
...
* Server certificate:
*  subject: CN=web-platform.test
*  start date: Apr 12 02:33:49 2021 GMT
*  expire date: Apr 12 02:33:49 2022 GMT
*  subjectAltName: host "web-platform.test" matched cert's "web-platform.test"
*  issuer: CN=web-platform-tests
*  SSL certificate verify ok.
...
<li class="dir"><a href="xslt/">xslt</a></li>
</ul>
* Connection #0 to host web-platform.test left intact


$ curl -v https://web-platform.test:8444/ 
* SSL certificate problem: unable to get local issuer certificate
* Closing connection 0
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

See that it doesn't work with Deno in any configuration:

$ deno eval --cert ./test_util/wpt/tools/certs/cacert.pem -Ldebug 'console.log(await fetch("https://web-platform.test:8444/"))'
Sending fatal alert BadCertificate
error: Uncaught (in promise) TypeError: error sending request for url (https://web-platform.test:8444/): error trying to connect: invalid certificate: UnknownIssuer
console.log(await fetch("https://web-platform.test:8444/"))
            ^
    at unwrapOpResult (deno:core/core.js:100:13)
    at async mainFetch (deno:op_crates/fetch/26_fetch.js:165:18)
    at async fetch (deno:op_crates/fetch/26_fetch.js:295:22)
    at async file:///mnt/starship/Projects/github.com/denoland/deno/$deno$eval.ts:1:13

$ deno eval -Ldebug 'console.log(await fetch("https://web-platform.test:8444/"))'
Sending fatal alert BadCertificate
error: Uncaught (in promise) TypeError: error sending request for url (https://web-platform.test:8444/): error trying to connect: invalid certificate: UnknownIssuer
console.log(await fetch("https://web-platform.test:8444/"))
            ^
    at unwrapOpResult (deno:core/core.js:100:13)
    at async mainFetch (deno:op_crates/fetch/26_fetch.js:165:18)
    at async fetch (deno:op_crates/fetch/26_fetch.js:295:22)
    at async file:///mnt/starship/Projects/github.com/denoland/deno/$deno$eval.ts:1:13

This same issue is reproducible with WebSocket, but for now lets only use fetch because it is easier to test with.

@lucacasonato lucacasonato added bug Something isn't working correctly ext/fetch related to the ext/fetch tls Issues related to TLS implementation ext/websocket related to the ext/websocket crate labels Apr 22, 2021
@lucacasonato
Copy link
Member Author

Analysis so far:

CA cert is being added to rustls here:

deno/op_crates/fetch/lib.rs

Lines 497 to 498 in 21ab4d9

let cert = reqwest::Certificate::from_pem(&ca_data)?;
builder = builder.add_root_certificate(cert);

Error originates at https://github.com/briansmith/webpki/blob/e51f215d2ea45940d98db21b24f3a8be02f7606d/src/verify_cert.rs#L55

Cert doesnt actually end up in webpki trust anchors list. Don't know why.

@piscisaureus
Copy link
Member

Multiple copies of webpki/webpki-roots?

@lucacasonato
Copy link
Member Author

Multiple copies of webpki/webpki-roots?

Nope

@bnoordhuis
Copy link
Contributor

webpki 0.21.4 doesn't like the ca cert. It looks like either webpki or the untrusted crate chokes on the humongous X509v3 Name Constraints field in test_util/wpt/tools/certs/cacert.pem, it's almost 8K big!

@lucacasonato
Copy link
Member Author

lucacasonato commented Apr 23, 2021

Ah great... so I guess this should be reported upstream? OpenSSL can do it, so I think rustls should too. Thanks for digging into this.

@bnoordhuis
Copy link
Contributor

I've opened briansmith/webpki#226 with a failing regression test, to solicit feedback.

@bnoordhuis
Copy link
Contributor

bnoordhuis commented Apr 29, 2021

Maybe this isn't a webpki issue after all. See the linked pull request for more details but tl;dr the DER encoding in the CA certificate looks suspect. - edit: likely a webpki issue after all. The workaround still works though.

There's a workaround: apply this patch and regenerate the certificates with wpt serve --config tools/certs/config.json:

diff --git a/tools/wptserve/wptserve/sslutils/openssl.py b/tools/wptserve/wptserve/sslutils/openssl.py
index 87a8cc9cc7..bbf500d8ca 100644
--- a/tools/wptserve/wptserve/sslutils/openssl.py
+++ b/tools/wptserve/wptserve/sslutils/openssl.py
@@ -216,7 +216,7 @@ basicConstraints = CA:true
 subjectKeyIdentifier=hash
 authorityKeyIdentifier=keyid:always,issuer:always
 keyUsage = keyCertSign
-%(constraints_line)s
+#%(constraints_line)s
 """ % {"root_dir": root_dir,
        "san_line": san_line,
        "duration": duration,

web-platform-tests/wpt#11075 indicates the nameConstraints field was added to make the certificates safe(r) to use in browsers so I don't know if they're open to removing it again.

@bnoordhuis
Copy link
Contributor

Turns out it was indeed a webpki bug. Submitted a fix.

lucacasonato pushed a commit to denoland/wpt that referenced this issue May 5, 2021
Don't emit nameConstraints when generating certificates, webpki can't
parse them.

Fixes denoland/deno#10312.
lucacasonato pushed a commit to denoland/wpt that referenced this issue May 5, 2021
@lucacasonato
Copy link
Member Author

I'm going to reopen this, as the root issue has not been resolved. We only mitigated it for the specific usecase it was causing an issue.

@lucacasonato lucacasonato reopened this May 5, 2021
lucacasonato pushed a commit to denoland/wpt that referenced this issue May 17, 2021
@bnoordhuis bnoordhuis reopened this May 17, 2021
@cryptogohan
Copy link

cryptogohan commented May 23, 2021

I think I'm running into this with a Postgres DB.

Sending fatal alert BadCertificate
error: Uncaught (in promise) InvalidData: invalid certificate: UnknownIssuer

But a ca cert is provided like so:

deno run --unstable -A --cert ca_cert.pem connect.ts

Does a provided ca cert still need a valid issuer? Because then the --cert flag is just not what I need.

@lucacasonato
Copy link
Member Author

No it doesn't need to be valid, but the CA cert and the leaf cert used for TLS may not be the same thing. I will take a look to see if there are any misconfigurations in our TLS ops.

@cryptogohan
Copy link

@lucacasonato do you have a reproducible example already? I wouldn't want you to waste time. I have a pg server that I hit this issue with but I definitely can't rule out the certificate having issues somehow. The more I dive into this the more I'm .. 'impressed' 😅 , with the complexity of TLS.

Besides, I've moved on to a different hosting provider that lets me make unsecured private connections to the DB. It offers secured with self-signed cert too, but only with an IP (Google Cloud) and that seems to be unsupported by rustls.

If I can help by providing a server and cert for example you can reach me at https://t.me/cryptogohan

@lndgalante
Copy link

Don't know if it helps a lot but having the same issue as @cryptogohan with a Postgres database in Heroku, both locally and in the prod deploy over heroku.

lucacasonato pushed a commit to denoland/wpt that referenced this issue May 31, 2021
lucacasonato pushed a commit to denoland/wpt that referenced this issue Jun 7, 2021
Don't emit nameConstraints when generating certificates, webpki can't
parse them.

Fixes denoland/deno#10312.
lucacasonato pushed a commit to denoland/wpt that referenced this issue Jun 7, 2021
@lucacasonato
Copy link
Member Author

still not fixed, so reopening

@lucacasonato lucacasonato reopened this Jun 14, 2021
@cryptogohan
Copy link

Hmm, I think I can step-out here. For my case it seems self-signed certificates are working fine, I've managed to narrow down the issues to different things. There is the Digital Ocean case I discuss over here that hits a InvalidData: invalid certificate: BadDER error but I doubt that is this issue.

@justinmchase
Copy link
Contributor

There was a change made in this area recently, in addition to adding support for loading certs from the certificate store it also did a bit of refactoring which unified a couple places in code to all call a common function.

#11491

It may be worth trying again with the latest version (when it lands with this change, or build from main) and see if it still reproduces.

@bartlomieju
Copy link
Member

@lucacasonato can this be closed given that DENO_TLS_CA_STORE has been added in v1.13?

@lucacasonato
Copy link
Member Author

No, this specific case is a bug in rustls/webpki (briansmith/webpki#226)

@FrankReh
Copy link

FrankReh commented Jun 5, 2023

Just for general information. I was able to get rustls to work with a self-signed certificate building things from the shell script found in https://stackoverflow.com/questions/76049656/unexpected-notvalidforname-with-rusts-tonic-with-tls

The server side was PostgreSQL, not rustls, so this may not at all be relevant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working correctly ext/fetch related to the ext/fetch ext/websocket related to the ext/websocket crate tls Issues related to TLS implementation upstream Changes in upstream are required to solve these issues
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants