HTTP headers/TLS padding as a censorship circumvention method

TLS Padding Extension

We can apply the same principle for HTTPS data, using TLS Padding Extension. This extension was introduced as a workaround of F5 SSLv3/TLS code, which incorrectly handled ClientHello packets between 256 byte and 512 byte size.

Padding extension allows to include up to 16 KiB of null-byte padding data in TLS ClientHello packet.

To perform this test, I’ve patched OpenSSL to include ~12KB of padding data to each ClientHello packet and to move Server Name Indication extension to the end of the packet, after padding. Did not forget it this time. I tested only TLS connection establishment, with certificate validation. Did not test underlying protocol (HTTP request).

The padded handshake looks as follows:

Transport Layer Security
    TLSv1.3 Record Layer: Handshake Protocol: Client Hello
        Content Type: Handshake (22)
        Version: TLS 1.0 (0x0301)
        Length: 12305
        Handshake Protocol: Client Hello
            Handshake Type: Client Hello (1)
            Length: 12301
            Version: TLS 1.2 (0x0303)
            Random: 054d101ad3fec689ea2363fb609e801275b87e34739e47a3…
            Session ID Length: 32
            Session ID: 97aca2269676ac73eddf51a17bd85d8fef30bb74bda63339…
            Cipher Suites Length: 62
            Cipher Suites (31 suites)
            Compression Methods Length: 1
            Compression Methods (1 method)
            Extensions Length: 12166
            Extension: ec_point_formats (len=4)
            Extension: supported_groups (len=12)
            Extension: session_ticket (len=0)
            Extension: encrypt_then_mac (len=0)
            Extension: extended_master_secret (len=0)
            Extension: signature_algorithms (len=48)
            Extension: supported_versions (len=9)
            Extension: psk_key_exchange_modes (len=2)
            Extension: key_share (len=38)
            Extension: padding (len=11996)    ← almost 12 KB
            Extension: server_name (len=13)   ← SNI here

The command used to check common HTTPS request is:
timeout 15 openssl s_client -host "$1" -port 443 -servername "$1" -bugs < /dev/null &> /dev/null

And for padded request patched OpenSSL was used:
timeout 15 ./openssl s_client -host "$1" -port 443 -servername "$1" -bugs -nosni_first -add_sni_after_padding < /dev/null &> /dev/null

Which produced the following result:

   8889 OK
   1111 FAIL

And for padded handshake:

   8800 OK
   1200 FAIL

Large TLS Padding Extension may disrupt only about 0.9% of top web sites.

Result

This method could be used in most cases and is compatible with large amount of CDNs, web servers and encryption stacks, but still may break some websites.

https-padding-test.7z (105.7 KB)
OpenSSL patches included.

1 Like