c++sslopensslsni

OpenSSL/C++: can't get SNI extension to appear in ClientHello


I'm trying to initiate a TLS connection and it must include a SNI extension. The following program works but, despite SSL_set_tlsext_host_name being called, does not produce a SNI record in the Client Hello packet:

#include <openssl/ssl.h>
#include <openssl/bio.h>

int main()
{
    SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());
    SSL* ssl = SSL_new(ctx);
    BIO* bio = BIO_new_ssl_connect(ctx);
    BIO_set_conn_hostname(bio, "demo.piesocket.com:443");
    SSL_set_tlsext_host_name(ssl, "demo.piesocket.com");
    BIO_do_connect(bio);
    BIO_free_all(bio);
    SSL_free(ssl);
    SSL_CTX_free(ctx);
    return 0;
}

Yet the following command does:

openssl s_client demo.piesocket.com:443

I've checked both exchanges with Wireshark and the Client Hello packets differ only in the absence/presence of SNI. Yes, I've looked long and hard at s_client.c but it does too many things and I'm new to OpenSSL and TLS. What am I missing?

(For brevity I've removed all checks from this example code but it works, the server I'm using here doesn't seem to require SNI and the TLS connection is indeed established in both cases. The TLS portion of the packet from openssl.exe looks like this:

TLSv1.2 Record Layer: Handshake Protocol: Client Hello
    Content Type: Handshake (22)
    Version: TLS 1.0 (0x0301)
    Length: 319
    Handshake Protocol: Client Hello
        Handshake Type: Client Hello (1)
        Length: 315
        Version: TLS 1.2 (0x0303)
        Random: 8772af2a36342435d6b73a0593087c229b67342030d23ae5…
        Session ID Length: 32
        Session ID: 49a1e1b7eb761bd9b279efcb4cac15bae2f09bb92e641a75…
        Cipher Suites Length: 62
        Cipher Suites (31 suites)
        Compression Methods Length: 1
        Compression Methods (1 method)
        Extensions Length: 180
        Extension: server_name (len=23)
        Extension: ec_point_formats (len=4)
        Extension: supported_groups (len=22)
        Extension: session_ticket (len=0)
        Extension: encrypt_then_mac (len=0)
        Extension: extended_master_secret (len=0)
        Extension: signature_algorithms (len=42)
        Extension: supported_versions (len=9)
        Extension: psk_key_exchange_modes (len=2)
        Extension: key_share (len=38)

The packet from the program doesn't have the Extension: server_name (len=23) line. OpenSSL version 3.0.7, Windows 7, MinGW.)


Solution

  • You are creating an SSL BIO via BIO_new_ssl_connect. This essentially creates a BIO and inside it creates a new SSL object for the connection based on the SSL_CTX that you pass it. Entirely separate to that you are creating a different SSL object, setting the SNI hostname on it, and then you're not using it for anything - you just free it.

    Don't create a separate SSL object. Instead get hold of the SSL object inside the BIO using BIO_get_ssl. Set the SNI hostname on that.

    https://www.openssl.org/docs/man3.0/man3/BIO_get_ssl.html