Great Firewalls: Watching Blocking Censoring Disappearing You with Loving Oppression
https://mailarchive.ietf.org/arch/msg/tls/Dae-cukKMqfzmTT4Ksh1Bzlx7ws/ Present in and coming to your own countries soon... Re: [TLS] Possible blocking of Encrypted SNI extension in China David Fifield <david@bamsoftware.com> Fri, 07 August 2020 23:56 UTC On Thu, Jul 30, 2020 at 03:45:48PM +0000, onoketa wrote:
The Great Firewall of China may have identified and blocked Cloudflare's ESNI implementation.
I have found that when using a TLS client hello with ESNI extension to connect to servers behind Cloudflare's CDN, the connection will be cut off after the whole TLS handshake is done. And then that IP address will be blocked at the TCP level for several minutes.
There is now a detailed written report on the new phenomenon of ESNI blocking in China. It was produced by a collaboration of researchers from Geneva (https://censorship.ai/), GFW Report (https://gfw.report/), and iYouPort (https://www.iyouport.org/). https://geneva.cs.umd.edu/posts/china-censors-esni/esni/ (English) https://geneva.cs.umd.edu/zh/posts/china-censors-esni/esni/ (Chinese) Here are some of the points most likely to be of interest to this group: * The detector is not merely matching on the lack of plaintext SNI; it is specifically looking for the ESNI extension 0xffce. * The ESNI detector only matches the ESNI encrypted_server_name extension 0xffce (draft-ietf-tls-esni-00 through -06), not the ECH extensions encrypted_client_hello 0xff02, ech_nonce 0xff03, outer_extension 0xff04 (draft-ietf-tls-esni-07). * The encrypted_server_name extension has to be syntactically correct; the detector is not just looking for the byte patter ff cc. * Once an ESNI-containing ClientHello is detected, the firewall drops packets in the client→server direction for 120 or 180 seconds. * The detector runs on all TCP ports, not just 443. This short payload is sufficient to trigger blocking: 160303003b0100003703035b72616e646f6d72616e646f6d72616e646f6d7261 6e646f6d72616e646f6d5d0000000100000effce000a53754772000000000000 Python code to generate this payload is appended to this message. Most of the functions of the Great Firewall work bidirectionally, and the ESNI detection and blocking are no exception. Sending an ESNI-containing ClientHello from *outside* of China to a server *inside* results in temporary blocking, just the same as sending one from the inside to the outside. This makes it easy to experiment with, even if you don't control a host in China. To experience ESNI blocking for yourself, choose a responsive TCP port in China (doesn't have to be port 443), for example www.tsinghua.edu.cn:80. Begin a TCP ping to the port, for example using one of these commands: hping3 -S www.tsinghua.edu.cn -p 80 nping -4 -c 0 --tcp-connect www.tsinghua.edu.cn -p 80 Then send the trigger payload: printf '\x16\x03\x03\x00\x3b\x01\x00\x00\x37\x03\x03[randomrandomrandomrandomrandom]\x00\x00\x00\x01\x00\x00\x0e\xff\xce\x00\nSuGr\x00\x00\x00\x00\x00\x00' | nc -4 -v www.tsinghua.edu.cn 80 The TCP pings will stop receiving replies for 120 or 180 seconds, then will start back up again. ---- #!/usr/bin/env python3 # Generates a small TLS ClientHello that trigger's the GFW's ESNI detector. # Writes output to the file minimal.bin. import struct from scapy.all import * load_layer("tls") from scapy.layers.tls.all import * # https://tools.ietf.org/html/rfc8446#section-3.4 def var(ceiling, data): if ceiling < 256: fmt = ">B" elif ceiling < 65536: fmt = ">H" else: raise ValueError(ceiling) return struct.pack(fmt, len(data)) + data # https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-01#section-5 def encrypted_server_name(suite, group, key_exchange, record_digest, encrypted_sni): return struct.pack(">HH", suite, group) \ + var(65535, key_exchange) \ + var(65535, record_digest) \ + var(65535, encrypted_sni) clienthello = TLS( msg = TLSClientHello( gmt_unix_time = 0x5b72616e, # "[ran" random_bytes = b"domrandomrandomrandomrandom]", ciphers = [], ext = [ # The GFW detector requires a syntactically valid # server_name_extension, but the actual values it contains may be # nonsense. Here we use a CipherSuite of 0x5375 ("Su"), a NamedGroup # of 0x4772 ("Gr"), and zero-length key_exchange, record_digest, and # encrypted_sni. TLS_Ext_Unknown(type=0xffce, val=encrypted_server_name(0x5375, 0x4772, b"", b"", b"")), ], ) ) TLS(bytes(clienthello)).show() print(bytes(clienthello)) FILENAME = "minimal.bin" open(FILENAME, "wb").write(bytes(clienthello)) print("output written to {}".format(FILENAME))
‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐ On Sunday, August 9, 2020 6:09 PM, grarpamp <grarpamp@gmail.com> wrote: ...
There is now a detailed written report on the new phenomenon of ESNI blocking in China. ... Here are some of the points most likely to be of interest to this group: ... - The ESNI detector only matches the ESNI encrypted_server_name extension 0xffce (draft-ietf-tls-esni-00 through -06), not the ECH extensions encrypted_client_hello 0xff02, ech_nonce 0xff03, outer_extension 0xff04 (draft-ietf-tls-esni-07).
interesting that encrypted client hello is not blocked, as this would also make the SNI private! perhaps this is targeting by adoption, rather than capability. if hosts move to encrypted client hello, will this next be blocked? also, per https://tools.ietf.org/html/draft-ietf-tls-esni-07#section-10.5.4 : ``` Moreover, as more clients enable ECH support, e.g., as normal part of Web browser functionality, with keys supplied by shared hosting providers, the presence of ECH extensions becomes less unusual and part of typical client behavior. In other words, if all Web browsers start using ECH, the presence of this value will not signal unusual behavior to passive eavesdroppers. ``` :P best regards,
participants (2)
-
coderman
-
grarpamp