ALPACA Attack

How to Mitigate ALPACA Attacks With ALPN and SNI

Here we give instructions and references how to implement strict verification of ALPN and SNI in common TLS libraries. We thank the maintainers of these libraries for their help in assembling these instructions, and apologize for any errors we made in editing. Please let us know if you find inaccuracies or areas for improvement.

Recommended Behavior for ALPN

Implementing these countermeasures is effective in preventing cross-protocol attacks irregardless of hostnames and ports used for application servers. The most important recommendations are highlighted below.

ALPN for Servers

We recommend that the server aborts the handshake if the client sends the ALPN extension, but the list of protocols does not include a protocol supported by the server.

We also recommend that the server acknowledge the ALPN extension, so the client can verify that the server supports ALPN and selected a valid protocol.

We do not recommend that the server aborts the handshake if the client does not send the ALPN extension, unless backwards compatibility wth legacy clients that do not support ALPN is not a concern.

ALPN for Clients

We recommend that the client sends the ALPN extension with a list of the intended protocols, and the SNI extension with the intended hostname.

We also recommend that the client aborts the handshake if the server acknowledges the ALPN extension, but does not select a protocol from the client list.

We do not recommend that the client aborts the handshake if the server does not acknowledge the ALPN extension, unless backwards compatibility with legacy servers that do not support or acknowledge the ALPN extension is not a concern.

Recommended Behavior for SNI

Implementing these countermeasures is effective in preventing same-protocol attacks on servers with different hostnames, as well as cross-protocol attacks on servers with different hostnames even if the ALPN countermeasures can not be implemented.

Compared to ALPN, the SNI extension is more difficult to configure, because the application server needs to be aware of its configuration in the network. While the supported protocol list for ALPN is usually determined statically at time of development of the application server, the list of acceptable hostnames for SNI is dependent on the location of the server in the network, and how it is accessed by clients, for example through the use of gateway and proxy servers. We recognize that in complicated deployment scenarios, implementing the following recommendations can be challenging. In particular, implementing these SNI-based countermeasures can potentially break legitimate connections that depend on inappropriately configured legacy environments, such as SNI fallback for unknown hosts.

SNI for Servers

We recommend that the server aborts the handshake if the client sends an SNI hostname that the server does not recognize.

We also recommend that the server acknowledges the SNI hostname to the client so the client can verify that the server supports SNI and recognized the hostname.

We do not recommend that the server aborts the handshake if the client does not send an SNI hostname, unless backwards compatibility wth legacy clients that do not support SNI is not a concern.

SNI for Clients

We recommend that all clients are configured to send the SNI extension with the hostname of the intended server.

We also recommend that clients abort the handshake if the server acknowledges the SNI hostname with a different hostname than the one sent by the client.

We do not recommend that clients abort the handshake if the server does not acknowledge the SNI hostname, unless backwards compatibility with legacy servers that do not support or acknowledge the SNI hostname is not a concern.

ALPN and SNI Support in TLS Libraries

OpenSSL

ALPN Support in OpenSSL

ALPN selection in the client is supported by SSL_CTX_set_alpn_protos(), which takes as input a list of supported protocols for negotiation.

ALPN selection in the server is supported by an application callback set with SSL_CTX_set_alpn_select_cb(). The callback should return one of three values:

Note that if there is no ALPN proposed in the ClientHello, the callback is not invoked.

To protect against ALPACA attacks with OpenSSL and ALPN, the client should configure the supported protocols with SSL_CTX_set_alpn_protos(), and the server should configure the SSL_CTX_set_alpn_select_cb callback. If an expected protocol identifier is provided, the server should return SSL_TLSEXT_ERR_OK, otherwise it should return SSL_TLSEXT_ERR_ALERT_FATAL.

SNI Support in OpenSSL

The SNI hostname is set in the client by calling SSL_set_tlsext_host_name().

In the server, SNI selection is supported by an application callback set with SSL_CTX_set_tlsext_servername_callback(). The callback should return one of four values:

To protect against ALPACA attacks with OpenSSL and SNI, the client should configure the SNI hostname with SSL_set_tlsext_host_name(), and the server should configure SSL_CTX_set_tlsext_servername_callback(). If a matching SNI hostname is sent by the client, the server should return SSL_TLSEXT_ERR_OK, otherwise it should return SSL_TLSEXT_ERR_ALERT_FATAL.

Oracle Java

ALPN Support in Java

The TLS stack in Java implements strict ALPN verification by default. The server and the client can configure ALPN support by passing acceptable values to the SSLParameters configuration object using the javax.net.ssl.SSLParameters.getSSLParameters method, which is then passed to the SSLEngine/SSLSocket to be configured. Overlapping values will be selected.

Alternatively, the server can examine the values of the client ALPN extension and its own SSLSocket/SSLEngine before a protocol is negotiated, using the javax.net.ssl.SSLSocket.setHandshakeApplicationProtocolSelector callback function. The function must return a String value that is in the client's list, and takes priority over the SSLParameters list. The function can also return the empty string if ALPN should not be acknowledged by the server, and null (or a String value not in the client's list) to abort the connection with a no_application_protocol alert.

To protect against ALPACA attacks with Java and ALPN, the client should set the list of supported protocols with the getSSLParameters method, and the server should either do the same or implement the setHandshakeApplicationProtocolSelect and return either a recognized protocol or null to abort the handshake.

SNI Support in Java

The server can use SSLParameters.setSNIMatchers to enable strict hostname verification.

The client can set the SNI hostname with SSLParameters.setServerNames.

To protect against ALPACA attacks with Java and SNI, the client should set the SNI hostname with SSLParameters.setServerNames, and the server should set a SNI matcher with SSLParameters.setSNIMatchers that returns true if the hostname is recognized and false to abort the handshake.

GoLang (crypto/tls)

ALPN Support in GoLang

The client and server can be configured to negotiate a protocol using the tls.Config.NextProtos field. At the time of writing (2021-02-16), the handshake will not be aborted on the client side if the server ignores the clients ALPN extension, or on the server side if the server does not support any of the clients requested protocols. However, application developers can still implement stricter enforcement by setting the tls.Config.VerifyConnection callback, although this is considered an advanced pattern.

Note: The default behavior might change in the future to implement strict checking according to RFC 7301.

To protect against ALPACA attacks with GoLang and ALPN, the client and server should configure the supported protocols in tls.Config.NextProtos, and the server should abort the handshake if no protocol can be negotiated, using manual verification in the tls.Config.VerifyConnection callback. If and when the default behavior changes to enforce strict ALPN verification, this custom callback can be removed.

SNI Support in GoLang

The server does not strictly enforce the SNI hostname. Instead, the SNI hostname is used to select the right certificate if multiple certificates are configured. However, application developers can still implement stricter enforcement by setting the tls.Config.VerifyConnection, although this is considered an advanced pattern.

On the client side, setting the tls.Config.ServerName is required. This is sent in the ClientHello and used to verify the certificate provided by the server, unless certificate verification is disabled.

To protect against ALPACA attacks with GoLang and SNI, the client should configure the SNI hostname in tls.Config.ServerName, and the server should abort the handshake if the client provided an SNI hostname that is not recognized, using manual verification in the tls.Config.VerifyConnection callback.

Windows TLS Stack (SChannel)

ALPN Support in the Windows TLS Stack

The Windows TLS stack implements RFC 7301 faithfully and always terminates if the client and the server ALPN extensions are configured and the server does not recognize a supported protocol.

To protect against ALPACA attacks with the Windows TLS stack and ALPN, the client and server should configure the supported ALPN protocols.

SNI Support in the Windows TLS Stack

The Windows TLS stack provides SNI information to the TLS server application. It is up to the server application to handle SNI in an application-specific manner. The Windows TLS stack has no way to enforce disconnects on SNI mismatch: it does not own the socket, and does not have any information about the network. On the TLS client side, any caller-provided SNI information is used for server certificate validation.

To protect against ALPACA attacks with the Windows TLS stack and SNI, the client should configure the SNI hostname, and the server should abort the handshake if the client provided an SNI hostname that is not recognized, using manual verification.

Mbed TLS

Mbed TLS

Mbed TLS implements RFC 7301 faithfully and always terminates if the client and the server ALPN extensions are configured and the server does not recognize a supported protocol.

The server and the client can enable ALPN by defining MBEDTLS_SSL_ALPN in the configuration script, and set the list of supported protocols with mbedtls_ssl_conf_alpn_protocols (see the example in programs/ssl/ssl_client2.c).

To protect against ALPACA attacks with Mbed TLS and ALPN, the client and server should configure the supported ALPN protocols.

SNI Support in Mbed TLS

Mbed TLS supports SNI with the MBEDTLS_SSL_SERVER_NAME_INDICATION setting in the configuration script, which is enabled by default.

The client can enable SNI by setting the hostname of the server with mbedtls_ssl_set_hostname().

The server can set a callback function with mbedtls_ssl_conf_sni() and compare the hostname in the third argument with the list of supported hostnames. In case no match is found, the server can terminate the connection by returning a non-zero value from the callback (see the example sni_callback() in ssl_server2.c).

To protect against ALPACA attacks with Mbed TLS and SNI, the client should configure the SNI hostname, and the server should abort the handshake if the client provided an SNI hostname that is not recognized, using manual verification.

BoringSSL

ALPN Support in BoringSSL

BoringSSL leaves server ALPN selection to an application-supplied callback. In response to our findings, BoringSSL has made changes to allow strict ALPN verification by returning SSL_TLSEXT_ERR_ALERT_FATAL from this callback (same as OpenSSL).

To protect against ALPACA attacks with BoringSSL and ALPN, the server should return SSL_TLSEXT_ERR_ALERT_FATAL in the ALPN callback to abort the connection if no matching protocol is found.

SNI Support in BoringSSL

BoringSSL implements SNI support with the application-supplied servername callback. The application can terminate the connection by returning SSL_TLSEXT_ERR_ALERT_FATAL.

Beside the servername callback, there are two more SNI-related callbacks that offer more flexibility, and have other return values to indicate an error. The cert callback can return zero on error, and the select_certificate callback can return ssl_select_cert_error.

To protect against ALPACA attacks with BoringSSL and SNI, the server should return SSL_TLSEXT_ERR_ALERT_FATAL from the servername callback if the clients provides an SNI hostname that is not recognized, or equivalently return an appropriate error from the cert or select_certificate callback functions in this case.

Botan

ALPN Support in Botan

The server implements a callback tls_server_choose_app_protocol which takes a list of the protocols offered by the client, and returns a string which is either empty (meaning to ignore the ALPN) or some protocol, or it may choose to throw an exception at that point which will cause the connection to be closed with an alert. The default implementation returns an empty string, thus ignoring ALPN.

On the client side, the ALPN protocol list can be set in the next_protocols argument when creating the TLS::Client instance.

To protect against ALPACA attacks with Botan and ALPN, the server should implement the tls_server_choose_app_protocol callback and throw an exception if none of the protocols provided by the client are recognized. The client should set the list of protocols in the next_protocols argument of TLS::Client.

SNI Support in Botan

The server invokes a callback on Credentials_Manager, cert_chain_single_type, which asks to return a certificate chain usable for the named host. If the callback throws an exception if the named host does not match an expected hostname, then the connection will be closed.

Clients can send the SNI hostname by passing an initialized Server_Information struct to the TLS::Client constructor.

To protect against ALPACA attacks with Botan and SNI, the server should implement the cert_chain_single_type callback and throw an exception if the SNI hostname provided by the client is not recognized. The client should set the hostname in the Server_Information struct of the TLS::Client constructor.

BearSSL

ALPN Support in BearSSL

The client and server can be configured to negotiate a protocol using the br_ssl_engine_set_protocol_names() function. A mismatch can be detected by either the server or the client, if the ALPN extension was used, and the list of protocols sent by the client or resp. the protocol chosen by the server is not part of the configured list. In this case, the behavior depends on the BR_OPT_FAIL_ON_ALPN_MISMATCH flag: If the flag was set with br_ssl_engine_add_flag(), a mismatch implies a handshake failure with fatal alert 120. If the flag was not set, then the handshake continues.

The selected protocol can be obtained with br_ssl_engine_get_selected_protocol(). The result is NULL if no protocol was selected, which can happen on mismatch (with the BR_OPT_FAIL_ON_ALPN_MISMATCH not set), or if the peer did not send an ALPN extension.

To protect against ALPACA attacks with BearSSL and ALPN, the client and server should configure the list of supported protocols with br_ssl_engine_set_protocol_names() and the server (and preferably the client, too) should set the BR_OPT_FAIL_ON_ALPN_MISMATCH flag.

SNI Support in BearSSL

The client initializes its context with br_ssl_client_reset(), which also takes an SNI hostname parameter.

The server can retrieve the SNI hostname with br_ssl_engine_get_server_name() and implement strict checking manually in the callback configured to select the certificate chain to be sent to the client.

To protect against ALPACA attacks with BearSSL and SNI, the client should set the SNI hostname with the server_name parameter in br_ssl_client_reset(). The server should retrieve that hostname with br_ssl_engine_get_server_name() in the certificate chain selection callback, verify that the SNI hostname provided by the client is recognized, and otherwise abort the handshake.

WolfSSL

ALPN Support in WolfSSL

To support ALPN, WolfSSL should be configured with --enable-alpn or by defining HAVE_ALPN and HAVE_TLS_EXTENSIONS in a settings header. The default behavior is configurable and must be set when ALPN is initialized, using wolfSSL_UseALPN() with the opion WOLFSSL_ALPN_CONTINUE_ON_MISMATCH or WOLFSSL_ALPN_FAILED_ON_MISMATCH.

To protect against ALPACA attacks with WolfSSL and ALPN, the client and server should enable ALPN by setting the appropriate compilation flags, and initialize it by calling wolfSSL_UseALPN. The server (and preferably the client, too) should use the WOLFSSL_ALPN_FAILED_ON_MISMATCH option to enforce strict ALPN verification.

SNI Support in WolfSSL

To support SNI, WolfSSL should be configured with --enable-sni or by defining HAVE_SNI and HAVE_TLS_EXTENSIONS in a settings header. The client can set the SNI hostname with wolfSSL_CTX_UseSNI or woflSSL_UseSNI, and the server can implement custom verification using the callback function wolfSSL_CTX_set_servername_callback().

To protect against ALPACA attacks with WolfSSL and SNI, the client and server should enable SNI by setting the appropriate compilation flags. The client should initialize it by calling wolfSSL_UseSNI. The server should implement a custom verification for the SNI hostname using the wolfSSL_CTX_set_servername_callback.

GnuTLS

ALPN Support in GnuTLS

To support ALPN in GnuTLS, the client or server can call gnutls_alpn_set_protocols before the handshake to configure the list of supported protocols. The function takes an array of gnutls_datum_t elements with protocol names. If the flag GNUTLS_ALPN_MANDATORY is set when calling that function, the connection is terminated when no matching protocol is found. The seelcted protocol can be obtained through gnutls_alpn_get_selected_protocol.

To protect against ALPACA attacks with GnuTLS and ALPN, the client and server should call gnutls_alpn_set_protocol with the GNUTLS_ALPN_MANDATORY flag set to enforce strict ALPN verification.

SNI Support in GnuTLS

To support SNI in GnuTLS, the client should call gnutls_server_name_set before the handshake starts to set the intended server name. The server can retrieve the name sent by the client with gnutls_server_name_get.

To protect against ALPACA attacks with GnuTLS and SNI, the client should initialize it by calling gnutls_server_name_set, and the server should set a hook function on the ClientHello, call gnutls_server_name_get and manually verify the SNI hostname.