3

When I access https://example.com on my company's laptop that has a X509 client certificate installed, using my home internet connection, without using a VPN, the requested page is signed using the company's Root CA (which was distributed to my company's laptop through group policies I assume).

When I access https://example.com on my private laptop that has no client certificate installed, with the same connection, I get an access error (403) instead with a Cloudflare logo on it (the address bar is still https://example.com). That error is expected because I have no client certificate. Interestingly, the error page is signed by Cloudflare's own intermediate CA.

How does Cloudflare switch server certificates during TLS handshake depending on the existence of a client certificate? The server certificate is sent before the client certificate. It is brilliant how this all works, but I don't get how they managed to implement it.

What seems to make a difference is the TLS version. If I use a browser without TLS 1.3, all content is signed with the Cloudflare certificate, regardless if I have a client certificate or not. Is there a certificate renegotiation protocol in 1.3? (I can't find the specs)

Company Computer (connected to same ISP, VPN off)

curl -v https://somecompany.com > page.html
* Rebuilt URL to: https://somecompany.com/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying xx.xx.xx.xx...
* TCP_NODELAY set
* Connected to somecompany.com (xx.xx.xx.xx) port 443 (#0)
* schannel: SSL/TLS connection with somecompany.com port 443 (step 1/3)
* schannel: checking server certificate revocation
* schannel: sending initial handshake data: sending 183 bytes...
* schannel: sent initial handshake data: sent 183 bytes
* schannel: SSL/TLS connection with somecompany.com port 443 (step 2/3)
* schannel: failed to receive handshake, need more data
* schannel: SSL/TLS connection with somecompany.com port 443 (step 2/3)
* schannel: encrypted data got 3148
* schannel: encrypted data buffer: offset 3148 length 4096
* schannel: sending next handshake data: sending 3501 bytes...
* schannel: SSL/TLS connection with somecompany.com port 443 (step 2/3)
* schannel: encrypted data got 3394
* schannel: encrypted data buffer: offset 3394 length 4096
* schannel: SSL/TLS handshake complete
* schannel: SSL/TLS connection with somecompany.com port 443 (step 3/3)
* schannel: stored credential handle in session cache
> GET / HTTP/1.1
> Host: somecompany.com
> User-Agent: curl/7.55.1
> Accept: */*
>
* schannel: client wants to read 102400 bytes
* schannel: encdata_buffer resized 103424
* schannel: encrypted data buffer: offset 0 length 103424
* schannel: encrypted data got 37765
* schannel: encrypted data buffer: offset 37765 length 103424
* schannel: decrypted data length: 1369
* schannel: decrypted data added: 1369
* schannel: decrypted data cached: offset 1369 length 102400
(... more similar stuff here, encrypted data/decrypted data...)
< HTTP/1.1 200 OK
(...)

Private Computer (connected to same ISP)

curl -v https://somecompany.com > page.html
* Rebuilt URL to: https://somecompany.com/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying xx.xx.xx.xx...
* TCP_NODELAY set
* Connected to somecompany.com (xx.xx.xx.xx) port 443 (#0)
* schannel: SSL/TLS connection with somecompany.com port 443 (step 1/3)
* schannel: checking server certificate revocation
* schannel: sending initial handshake data: sending 183 bytes...
* schannel: sent initial handshake data: sent 183 bytes
* schannel: SSL/TLS connection with somecompany.com port 443 (step 2/3)
* schannel: failed to receive handshake, need more data
* schannel: SSL/TLS connection with somecompany.com port 443 (step 2/3)
* schannel: encrypted data got 3148
* schannel: encrypted data buffer: offset 3148 length 4096
* schannel: a client certificate has been requested
* schannel: SSL/TLS connection with somecompany.com port 443 (step 2/3)
* schannel: encrypted data buffer: offset 3148 length 4172
* schannel: sending next handshake data: sending 100 bytes...
* schannel: SSL/TLS connection with somecompany.com port 443 (step 2/3)
* schannel: encrypted data got 258
* schannel: encrypted data buffer: offset 258 length 4172
* schannel: SSL/TLS handshake complete
* schannel: SSL/TLS connection with somecompany.com port 443 (step 3/3)
* schannel: stored credential handle in session cache
> GET / HTTP/1.1
> Host: somecompany.com
> User-Agent: curl/7.55.1
> Accept: */*
>
* schannel: client wants to read 102400 bytes
* schannel: encdata_buffer resized 103424
* schannel: encrypted data buffer: offset 0 length 103424
* schannel: encrypted data got 12572
* schannel: encrypted data buffer: offset 12572 length 103424
* schannel: decrypted data length: 1369
* schannel: decrypted data added: 1369
* schannel: decrypted data cached: offset 1369 length 102400
(... more similar stuff here, encrypted data/decrypted data...)
< HTTP/1.1 403 Forbidden
(...)
Lemon Sky
  • 153
  • 4
  • 1
    A renegotiation (as can be done to request the client certificate) can in theory also use a different server certificate. But I'm not sure if this is actually the case here. – Steffen Ullrich Mar 18 '20 at 21:06
  • Would it be possible for you to post the output of `curl -v`, ideally in both scenarios? Additionaly, CloudFlare's docs on client certificates is interesting but I don't think it fully answers your question: https://developers.cloudflare.com/access/service-auth/mtls/ – multithr3at3d Mar 19 '20 at 00:01
  • I added it above. Seems like the line "a client certificate has been requested" does not appear in the case of the company computer. – Lemon Sky Mar 20 '20 at 08:00

0 Answers0