Mbedtls TLS 1.3 with or without SNI?

I am using mbedtls v3.2.1 and compiling only TLS 1.3, and using ccadb pem certs for a simple RSS reader.

I found that defining SNI with mbedtls_ssl_set_hostname() works on some websites while fails on others.
For example :

  1. https://news.google.com
  • with SNI set will pass handshake & fetches the news
  • if I comment out the SNI settings it will fail handshake. It fails with " -0x2700 - X509 - Certificate verification failed, e.g. CRL, CA or signature check failed" because the peer cert has text that says “No SNI provided; please fix your client”.
  1. https://www.aljazeera.com
  • with SNI set will fail handshake with error -0x7500 “Client received an extended server hello containing an unsupported extension”.
  • But if I comment out SNI settings it will pass handshake and fetches the news.

How would I know which website needs to have SNI set and which website site does not?
Is there a mbedtls function that can automatically set the SNI for websites that needs one?

My code is as follows:
As there is no TLS 1.3 only example, I knocked this up from my previous mbedtls code.

Thanks.

	psa_crypto_init();
	mbedtls_ssl_init( &ssl );
	mbedtls_ssl_config_init( &conf );	
	mbedtls_ctr_drbg_init( &rng.drbg );
	mbedtls_entropy_init( &rng.entropy );
	mbedtls_x509_crt_init( &cacert );
	
	ret = mbedtls_ctr_drbg_seed( &rng.drbg, mbedtls_entropy_func, &rng.entropy, (const unsigned char *) pers, strlen( pers ) );
	
	if( ret != 0 ) {
		my_error_str("TLS init error");		
		return PHW_SSLERR_INIT;
	}

	ret = mbedtls_x509_crt_parse( &cacert, ccadb_pem, sizeof(ccadb_pem) );
	if (ret < 0) {
		my_error_str( "TLS can't load CCADB PEM data");
		return PHW_SSLERR_INIT;
	}

	if( ( rc = mbedtls_ssl_config_defaults( &conf,
									MBEDTLS_SSL_IS_CLIENT,
									MBEDTLS_SSL_TRANSPORT_STREAM,
									MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 )
	{
		my_error_str("HTTP SSL config error");
		return PHW_SSLERR_INIT;
	}
    mbedtls_ssl_conf_rng( &conf, rng_get, &rng );
    mbedtls_ssl_conf_read_timeout( &conf, 0 );
    mbedtls_ssl_conf_tls13_key_exchange_modes( &conf, MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_ALL );
	mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );
	
	if( ( rc = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 ) {
			my_error_str("TLS setup error");
			return PHW_SSLERR_INIT;
	}

	mbedtls_ssl_set_bio( &ssl, &net_ctx, mywin_net_send, mywin_net_recv, NULL );
	
	if( ( rc = mbedtls_ssl_set_hostname( &ssl, hostname ) ) != 0 ) {
			my_error_str("HTTP SSL set hostname error");
		 return PHW_SSLERR_INIT;
	}		
		
	while( ( rc = mbedtls_ssl_handshake( &ssl ) ) != 0 ) {
			if( rc != MBEDTLS_ERR_SSL_WANT_READ && rc != MBEDTLS_ERR_SSL_WANT_WRITE ) {
				my_error_str("TLS handshake error");
				return PHW_SSLERR_HANDSHAKE;
			}
	}	

I think it is a bug in the mbedtls code, I hope someone from the mbedtls team will verify this.
But I am not sure what I did is the correct way to fix it, as I do not want to go over all the mbedtls code to understand what it is doing.

So from the debug logging I noticed this error logging

  library/ssl_tls13_client.c:1391: dumping encrypted extensions (14 bytes)
  library/ssl_tls13_client.c:1391: 0000:  00 00 00 00 00 0a 00 06 00 04 00 17 00 1d
  library/ssl_tls13_client.c:1437: 'unsupported extension found: 0' 
  library/ssl_tls13_client.c:1491: <= parse encrypted extensions

The unsupported extension found: 0 looked suspicious.
I thought it mean it did not find any unsupported extension but some how registered it did & bombed out. However looking at code in ssl_tls13_client.c:1437, I discovered that the 0 is the Extension Type and checking IANA TLS Extensions reviews that 0 = server_name.

It is weird that mbedtls is using SNI and when the server replies with the SNI extension, it says “huh, thats not supported”.

Looking at the code, for “Supported groups” extensions, it just prints out it found supported groups extensions found and does nothing, So I just added “server name extension” to the code. The MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME is already defined in ssl.h file.

I added following into the ssl_tls13_client.c

            case MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME:
                MBEDTLS_SSL_DEBUG_MSG( 3, ( "found extensions server name" ) );
                break;

in the switch, just above the MBEDTLS_TLS_EXT_SUPPORTED_GROUPS case statement and it worked.

        switch( extension_type )
        {
            case MBEDTLS_TLS_EXT_SUPPORTED_GROUPS:
                MBEDTLS_SSL_DEBUG_MSG( 3, ( "found extensions supported groups" ) );
                break;

#if defined(MBEDTLS_SSL_ALPN)
            case MBEDTLS_TLS_EXT_ALPN:
                MBEDTLS_SSL_DEBUG_MSG( 3, ( "found alpn extension" ) );

                if( ( ret = ssl_tls13_parse_alpn_ext( ssl, p, (size_t)extension_data_len ) ) != 0 )
                {
                    return( ret );
                }

                break;
#endif /* MBEDTLS_SSL_ALPN */
            default:
                MBEDTLS_SSL_DEBUG_MSG(
                    3, ( "unsupported extension found: %u ", extension_type) );
                MBEDTLS_SSL_PEND_FATAL_ALERT(
                    MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_EXT,
                    MBEDTLS_ERR_SSL_UNSUPPORTED_EXTENSION );
                return ( MBEDTLS_ERR_SSL_UNSUPPORTED_EXTENSION );
        }

        p += extension_data_len;
    }

So now both news.yahoo.com and www.aljazeera.com works with SNI using the code without any change in the 1st post.