New issue
Advanced search Search tips

Issue 789843 link

Starred by 2 users

Issue metadata

Status: WontFix
Owner: ----
Closed: Dec 2017
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux , Android , Windows , Chrome , Mac , Fuchsia
Pri: 2
Type: Bug-Security



Sign in to add a comment

Security: Wildcard SSL certificate not properly validated

Reported by jelle.de...@bizzomate.com, Nov 30 2017

Issue description

VULNERABILITY DETAILS
Wildcard SSL certificates are not validated for subdomains as soon as a single subdomain has served a valid certificate.

VERSION
Chrome Version: Version 62.0.3202.94 (Official Build) (64-bit)
Operating System: Windows 10 PRO, 1709, 16299.64

REPRODUCTION CASE
1. Make sure you have two wildcard certificates for the same domain, one valid today, one expired
2. Host different subdomains from different servers in order to be able to serve different certificates 
I'll call them "https://EXPIRED-cert.DOMAIN.com" (the subdomain serving the expired certificate) and "https://VALID-cert.DOMAIN.com" (serving the valid certificate)
3. Visit "https://EXPIRED-cert.DOMAIN.com" >> you'll get a security error
4. Visit "https://VALID-cert.DOMAIN.com" >> all is fine, you can access the page
5. Visit "https://EXPIRED-cert.DOMAIN.com" again >> suddenly all is fine, no security error anymore even though the server is serving an expired certificate.

 
Components: Internals>Network>SSL
Do you have a server that reproduces this-- if so, can you share the URL? 

Could you provide a network log? https://dev.chromium.org/for-testers/providing-network-details

The one explanation I can think of is HTTP/2 connection coalescing behavior: https://daniel.haxx.se/blog/2016/08/18/http2-connection-coalescing/. That could explain things if the two servers have the same IP address.



Comment 2 by palmer@chromium.org, Nov 30 2017

Cc: agl@chromium.org davidben@chromium.org est...@chromium.org
Components: Internals>Network>Certificate
Labels: M-64 Security_Impact-Stable OS-Android OS-Chrome OS-Fuchsia OS-Linux OS-Mac OS-Windows Pri-1
Owner: rsleevi@chromium.org
Status: Assigned (was: Unconfirmed)
rsleevi: Does this affect iOS as well? I no longer have any clue what all we do for cert validation there.
Cc: rsleevi@chromium.org
Labels: -Pri-1 -Security_Impact-Stable -M-64 Needs-Feedback Pri-2
Owner: ----
Status: Unconfirmed (was: Assigned)
Moving this back to unconfirmed - I think Comment #1 applies, as would the user clicking through the error.

we need more data based on Comment #1 to determine if it's even a valid bug. Removing the triage labels.
As I noticed this on production servers, I can't provide URL's without withholding normal access to these servers for users unfortunately. 

I've attached the log, the url's in question are unite-dev.ibnx-hse.com and unite-accep.ibnx-hse.com. I'll now switch back unite-dev to the correct certificate, so other users are able to user it again.

I've looked at the coalescing behavior URL, and noticed there that it said that Edge and Safari don't do coalescing. Edge does not show this problem, it will always show that the certificate provided is expired.
chrome-net-export-log.json
1.1 MB View Download
Project Member

Comment 5 by sheriffbot@chromium.org, Dec 1 2017

Labels: -Needs-Feedback
Thank you for providing more feedback. Adding requester "rsleevi@chromium.org" to the cc list and removing "Needs-Feedback" label.

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
Just in from the Firefox team, the setup of these URLs should be similar but here there are no problems:

https://expired.badssl.com has an expired certificate for *.badssl.com
https://sha256.badssl.com has an unexpired certificate for *.badssl.com

So something in the setup of our infrastructure provider allows Firefox and Chrome to be fooled by the certificate of the other subdomain.
This is a non-obvious but I believe expected consequence of cross-name HTTP/2 pooling.
http://httpwg.org/specs/rfc7540.html#reuse

Specifically, the description of step 5 isn't quite right;

5. Visit "https://EXPIRED-cert.DOMAIN.com" again >> suddenly all is fine, no security error anymore even though the server is serving an expired certificate.

What is actually happening is:

5. Visit "https://EXPIRED-cert.DOMAIN.com" again >> this time we see that we have an HTTP/2 session open to https://VALID-cert.DOMAIN.com that is also valid for EXPIRED-cert.DOMAIN.com. Rather than connect to EXPIRED-cert.DOMAIN.com (and then reject the connection for a bad certificate), the browser reuses the exist session, which does have a valid certificate, and requests EXPIRED-cert.DOMAIN.com resources through there.

You can confirm this by looking in DevTools for the certificate used in step 5. You will see the newer unexpired certificate associated with the request, not the older one.

The reason you don't see this on badssl.com is because they're not running HTTP/2.
I'll let Ryan or David "Won't Fix, Working as Intended" for this issue.

From the network log in #4, both unite-dev.ibnx-hse.com and unite-accep.ibnx-hse.com have the same IP addresses:

  --> address_list = ["52.58.88.187:443","52.58.246.150:443"]
  --> address_list = ["52.58.88.187:443","52.58.246.150:443"]

= Here's the first request to dev, blocked by the bad certificate ========================

140073: HTTP_STREAM_JOB
https://unite-dev.ibnx-hse.com/
t=59960 [st= 0] +HTTP_STREAM_JOB  [dt=34]
                 --> expect_spdy = "false"
                 --> original_url = "https://unite-dev.ibnx-hse.com/"
                 --> priority = "HIGHEST"
                 --> source_dependency = 140072 (HTTP_STREAM_JOB_CONTROLLER)
                 --> url = "https://unite-dev.ibnx-hse.com/"
                 --> using_quic = "false"
t=59960 [st= 0]     +SOCKET_POOL  [dt=34]
t=59993 [st=33]        SOCKET_POOL_BOUND_TO_CONNECT_JOB
                       --> source_dependency = 140058 (SSL_CONNECT_JOB)
t=59994 [st=34]        SOCKET_POOL_BOUND_TO_SOCKET
                       --> source_dependency = 140060 (SOCKET)
t=59994 [st=34]     -SOCKET_POOL
                     --> net_error = -201 (ERR_CERT_DATE_INVALID)

= Here's the second request to dev, not blocked on a reused connection  ========================
140300: URL_REQUEST
https://unite-dev.ibnx-hse.com/
Start Time: 2017-12-01 01:47:54.546

t=72658 [st= 0] +REQUEST_ALIVE  [dt=21]
                 --> priority = "HIGHEST"
                 --> url = "https://unite-dev.ibnx-hse.com/"
t=72658 [st= 0]   +URL_REQUEST_DELEGATE  [dt=0]
t=72658 [st= 0]      DELEGATE_INFO  [dt=0]
                     --> delegate_blocked_by = "extension Adblock Plus"
t=72658 [st= 0]   -URL_REQUEST_DELEGATE
t=72658 [st= 0]   +URL_REQUEST_START_JOB  [dt=19]
                   --> load_flags = 37120 (MAIN_FRAME_DEPRECATED | MAYBE_USER_GESTURE | VERIFY_EV_CERT)
                   --> method = "GET"
                   --> url = "https://unite-dev.ibnx-hse.com/"
t=72658 [st= 0]      URL_REQUEST_DELEGATE  [dt=0]
t=72659 [st= 1]      HTTP_CACHE_GET_BACKEND  [dt=0]
t=72659 [st= 1]      HTTP_CACHE_OPEN_ENTRY  [dt=0]
                     --> net_error = -2 (ERR_FAILED)
t=72659 [st= 1]      HTTP_CACHE_CREATE_ENTRY  [dt=0]
t=72659 [st= 1]      HTTP_CACHE_ADD_TO_ENTRY  [dt=0]
t=72659 [st= 1]     +HTTP_STREAM_REQUEST  [dt=0]
t=72659 [st= 1]        HTTP_STREAM_JOB_CONTROLLER_BOUND
                       --> source_dependency = 140303 (HTTP_STREAM_JOB_CONTROLLER)
t=72659 [st= 1]        HTTP_STREAM_REQUEST_BOUND_TO_JOB
                       --> source_dependency = 140304 (HTTP_STREAM_JOB)
t=72659 [st= 1]     -HTTP_STREAM_REQUEST
t=72659 [st= 1]     +HTTP_TRANSACTION_SEND_REQUEST  [dt=0]

--- Looking at the stream Job used by that second request, we get: ---------------------------------
140304: HTTP_STREAM_JOB
https://unite-dev.ibnx-hse.com/
Start Time: 2017-12-01 01:47:54.547

t=72659 [st=0] +HTTP_STREAM_JOB  [dt=0]
                --> expect_spdy = "false"
                --> original_url = "https://unite-dev.ibnx-hse.com/"
                --> priority = "HIGHEST"
                --> source_dependency = 140303 (HTTP_STREAM_JOB_CONTROLLER)
                --> url = "https://unite-dev.ibnx-hse.com/"
                --> using_quic = "false"
t=72659 [st=0]    HTTP_STREAM_JOB_WAITING  [dt=0]
                  --> should_wait = false
t=72659 [st=0]   +HTTP_STREAM_JOB_INIT_CONNECTION  [dt=0]
t=72659 [st=0]      HTTP2_SESSION_POOL_FOUND_EXISTING_SESSION_FROM_IP_POOL
                    --> source_dependency = 140229 (HTTP2_SESSION)
t=72659 [st=0]      HTTP_STREAM_JOB_BOUND_TO_REQUEST
                    --> source_dependency = 140300 (URL_REQUEST)
t=72659 [st=0] -HTTP_STREAM_JOB

--- Looking at the HTTP2_SESSION from that stream job, we get: -----------------------

140229: HTTP2_SESSION
unite-accep.ibnx-hse.com:443 (DIRECT)
Start Time: 2017-12-01 01:47:51.446

t=69558 [st=   0] +HTTP2_SESSION  [dt=4168+]
                   --> host = "unite-accep.ibnx-hse.com:443"
                   --> proxy = "DIRECT"
t=69559 [st=   1]    HTTP2_SESSION_INITIALIZED


So, yes, this looks exactly like HTTP2 session reuse. 


Status: WontFix (was: Unconfirmed)
Marking WontFix - elawrence@, not sure the rules on removing visibility restrictions so I left it for chrome-sec to do that :)
Labels: -Restrict-View-SecurityTeam allpublic

Sign in to add a comment