Firefox does not upgrade to QUIC (HTTP/3) when the origin’s certificate chains to a custom CA
Categories
(Core :: Networking, defect)
Tracking
()
People
(Reporter: redlion2112, Unassigned)
References
Details
Attachments
(1 file)
|
230.45 KB,
image/png
|
Details |
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36
Steps to reproduce:
Environment
- Firefox 142.0 on Linux, network.http.http3.enable = true
- Custom CA installed into Firefox Authorities
- nginx/1.29.1 built with http_v3_module
- Server certificate has SAN=DNS:localhost (and IP:127.0.0.1)
Server config (minimal):
server {
listen 443 ssl;
http2 on;
listen 443 quic reuseport;
server_name localhost;
ssl_certificate /home/ubuntu/nginx-certs/server.crt;
ssl_certificate_key /home/ubuntu/nginx-certs/server.key;
ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers off;
add_header Alt-Svc 'h3=":443"; ma=86400' always;
add_header X-HTTP3 $http3 always;
default_type text/plain;
location / {
return 200 "OK h3 test\n";
}
}
Steps
- Import the custom CA into Firefox (Authorities) and restart Firefox.
- start nginx.
- Visit https://localhost/ in Firefox once (Alt-Svc discovery), then reload / open it again.
- In DevTools → Network, check the protocol in Headers.
- Control check:
curl --http3 https://localhost/returnsHTTP/3 200with the same cert chain.
Actual results:
Firefox stays on HTTP/2: DevTools → Network shows Protocol = h2 for https://localhost/ (Version HTTP/2 and X-Firefox-Sody: h2).
Response headers include Alt-Svc: h3=":443"; ma=300.
The custom-CA chain is trusted by Firefox (page loads without warnings).
nginx access log shows $http3 empty for Firefox requests.
Optional: tcpdump shows no QUIC traffic from Firefox to UDP/443.
Control: static curl with --http3 connects successfully and returns HTTP/3 200.
Expected results:
Firefox should attempt QUIC and upgrade to HTTP/3:
- DevTools → Network should show Protocol = h3 (Version HTTP/3 and X-Firefox-Sody: h3)
- nginx should log $http3=1 for the request
- QUIC (UDP/443) traffic should be visible on the wire
(In reply to Yuriy from comment #0)
Created attachment 9509582 [details]
Снимок экрана 2025-08-26 в 18.29.04.pngUser Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36
Steps to reproduce:
Environment
- Firefox 142.0 on Linux, network.http.http3.enable = true
- Custom CA installed into Firefox Authorities
- nginx/1.29.1 built with http_v3_module
- Server certificate has SAN=DNS:localhost (and IP:127.0.0.1)
Server config (minimal):
> server {
> listen 443 ssl;
> http2 on;
> listen 443 quic reuseport;
>
> server_name localhost;
>
> ssl_certificate /home/ubuntu/nginx-certs/server.crt;
> ssl_certificate_key /home/ubuntu/nginx-certs/server.key;
>
> ssl_protocols TLSv1.3;
> ssl_prefer_server_ciphers off;
>
> add_header Alt-Svc 'h3=":443"; ma=86400' always;
> add_header X-HTTP3 $http3 always;
>
> default_type text/plain;
> location / {
> return 200 "OK h3 test\n";
> }
> }
> ```
> Steps
> 1) Import the custom CA into Firefox (Authorities) and restart Firefox.
> 2) start nginx.
> 3) Visit https://localhost/ in Firefox once (Alt-Svc discovery), then reload / open it again.
> 4) In DevTools → Network, check the protocol in Headers.
> 5) Control check: `curl --http3 https://localhost/` returns `HTTP/3 200` with the same cert chain.
>
>
> Actual results:
>
> Firefox stays on HTTP/2: DevTools → Network shows Protocol = h2 for https://localhost/ (Version HTTP/2 and X-Firefox-Sody: h2).
> Response headers include Alt-Svc: h3=":443"; ma=300.
> The custom-CA chain is trusted by Firefox (page loads without warnings).
> nginx access log shows $http3 empty for Firefox requests.
> Optional: tcpdump shows no QUIC traffic from Firefox to UDP/443.
> Control: static curl with --http3 connects successfully and returns HTTP/3 200.
>
>
> Expected results:
>
> Firefox should attempt QUIC and upgrade to HTTP/3:
> - DevTools → Network should show Protocol = h3 (Version HTTP/3 and X-Firefox-Sody: h3)
> - nginx should log $http3=1 for the request
> - QUIC (UDP/443) traffic should be visible on the wire
Comment 2•1 year ago
|
||
The Bugbug bot thinks this bug should belong to the 'Core::Networking' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.
Max, will Http logging help here or do you have an alternative debugging suggestion?
Comment 4•1 year ago
|
||
This behavior is by design. We have this pref network.http.http3.disable_when_third_party_roots_found to control whether to block HTTP/3 connection when a third party certificate is found.
Reporter, could you try to disable network.http.http3.disable_when_third_party_roots_found and see if you can create HTTP/3 connections?
(In reply to Kershaw Chang [:kershaw] from comment #4)
This behavior is by design. We have this pref
network.http.http3.disable_when_third_party_roots_foundto control whether to block HTTP/3 connection when a third party certificate is found.Reporter, could you try to disable
network.http.http3.disable_when_third_party_roots_foundand see if you can create HTTP/3 connections?
Confirmed. Setting network.http.http3.disable_when_third_party_roots_found to false resolved the issue for me — Firefox now negotiates HTTP/3. Thanks!
(In reply to Kershaw Chang [:kershaw] from comment #4)
This behavior is by design. We have this pref
network.http.http3.disable_when_third_party_roots_foundto control whether to block HTTP/3 connection when a third party certificate is found.Reporter, could you try to disable
network.http.http3.disable_when_third_party_roots_foundand see if you can create HTTP/3 connections?
Could you explain the security rationale for disabling HTTP/3 when third-party roots are detected, even with security.enterprise_roots.enabled? Does “third-party roots” include user-imported roots in the Firefox NSS store (Authorities), or only OS/enterprise/managed roots? Also, is there a policy or per-origin allowlist to permit H3 in managed environments?
Could you explain the security rationale for disabling HTTP/3 when third-party roots are detected
We take a third-party root as an indicator, that the TLS connection is being intercepted, e.g. by an anti-virus software. We had multiple occasions where such machine-in-the-middle software did not proxy the connection according to the specification, leading to bugs very hard to root cause. In addition, these would lead users to blame Firefox, not the buggy machine-in-the-middle software. Thus we have decided to disable HTTP/3 and thus QUIC in such occasions all together. The assumption being that those machine-in-the-middle software does a better job proxying HTTP/2 and HTTP/1. (Unfortunately I can't say that that assumption always holds true either.)
even with security.enterprise_roots.enabled
That would just be yet another indicator that the connection is being intercepted.
Does “third-party roots” include user-imported roots in the Firefox NSS store (Authorities), or only OS/enterprise/managed roots?
I believe so. Others here know better.
Also, is there a policy or per-origin allowlist to permit H3 in managed environments?
I am not aware of such an option. That said, I would assume we are open to a contribution adding such mechanism. After all, the more HTTP/3 the better :)
Note that Chrome behaves the same way:
Note that the server's certificate must be trusted by a default CA for Chrome/Chromium to accept it for QUIC. If you are using a self-signed certificate or a certificate that is signed by a custom CA, you need to use the --ignore-certificate-errors-spki-list command line flag to trust an individual certificate based on its SPKI. It is not possible to trust a custom CA using this flag. If you wish to deploy a MITM proxy that intercepts traffic, you need to block QUIC entirely and intercept TLS instead.
https://www.chromium.org/quic/playing-with-quic/#run-the-quic-server-and-client-with-cached-data
I know this is not ideal. In case you have suggestions to improve the status quo, e.g. through better flags, better heuristic, better documentation, ... please share them.
Comment 8•1 year ago
|
||
(In reply to Yuriy from comment #6)
Could you explain the security rationale for disabling HTTP/3 when third-party roots are detected, even with security.enterprise_roots.enabled?
Note that security.enterprise_roots.enabled is true by default.
Does “third-party roots” include user-imported roots in the Firefox NSS store (Authorities)
Yes.
Description
•