diff options
-rw-r--r-- | ssl/ssl_lib.c | 82 | ||||
-rw-r--r-- | ssl/statem/extensions.c | 1 | ||||
-rw-r--r-- | ssl/statem/extensions_srvr.c | 25 |
3 files changed, 86 insertions, 22 deletions
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 5ea310d5c4..b5239d6eb2 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -2753,31 +2753,85 @@ char *SSL_get_shared_ciphers(const SSL *s, char *buf, int size) return buf; } -/** return a servername extension value if provided in Client Hello, or NULL. - * So far, only host_name types are defined (RFC 3546). +/** + * Return the requested servername (SNI) value. Note that the behaviour varies + * depending on: + * - whether this is called by the client or the server, + * - if we are before or during/after the handshake, + * - if a resumption or normal handshake is being attempted/has occurred + * - whether we have negotiated TLSv1.2 (or below) or TLSv1.3 + * + * Note that only the host_name type is defined (RFC 3546). */ - const char *SSL_get_servername(const SSL *s, const int type) { + /* + * If we don't know if we are the client or the server yet then we assume + * client. + */ + int server = s->handshake_func == NULL ? 0 : s->server; if (type != TLSEXT_NAMETYPE_host_name) return NULL; - /* - * SNI is not negotiated in pre-TLS-1.3 resumption flows, so fake up an - * SNI value to return if we are resuming/resumed. N.B. that we still - * call the relevant callbacks for such resumption flows, and callbacks - * might error out if there is not a SNI value available. - */ - if (s->hit) - return s->session->ext.hostname; + if (server) { + /** + * Server side + * In TLSv1.3 on the server SNI is not associated with the session + * but in TLSv1.2 or below it is. + * + * Before the handshake: + * - return NULL + * + * During/after the handshake (TLSv1.2 or below resumption occurred): + * - If a servername was accepted by the server in the original + * handshake then it will return that servername, or NULL otherwise. + * + * During/after the handshake (TLSv1.2 or below resumption did not occur): + * - The function will return the servername requested by the client in + * this handshake or NULL if none was requested. + */ + if (s->hit && !SSL_IS_TLS13(s)) + return s->session->ext.hostname; + } else { + /** + * Client side + * + * Before the handshake: + * - If a servername has been set via a call to + * SSL_set_tlsext_host_name() then it will return that servername + * - If one has not been set, but a TLSv1.2 resumption is being + * attempted and the session from the original handshake had a + * servername accepted by the server then it will return that + * servername + * - Otherwise it returns NULL + * + * During/after the handshake (TLSv1.2 or below resumption occurred): + * - If the session from the orignal handshake had a servername accepted + * by the server then it will return that servername. + * - Otherwise it returns the servername set via + * SSL_set_tlsext_host_name() (or NULL if it was not called). + * + * During/after the handshake (TLSv1.2 or below resumption did not occur): + * - It will return the servername set via SSL_set_tlsext_host_name() + * (or NULL if it was not called). + */ + if (SSL_in_before(s)) { + if (s->ext.hostname == NULL + && s->session != NULL + && s->session->ssl_version != TLS1_3_VERSION) + return s->session->ext.hostname; + } else { + if (!SSL_IS_TLS13(s) && s->hit && s->session->ext.hostname != NULL) + return s->session->ext.hostname; + } + } + return s->ext.hostname; } int SSL_get_servername_type(const SSL *s) { - if (s->session - && (!s->ext.hostname ? s->session-> - ext.hostname : s->ext.hostname)) + if (SSL_get_servername(s, TLSEXT_NAMETYPE_host_name) != NULL) return TLSEXT_NAMETYPE_host_name; return -1; } diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index e2e704543e..d37accac18 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -948,7 +948,6 @@ static int final_server_name(SSL *s, unsigned int context, int sent) * was successful. */ if (s->server) { - /* TODO(OpenSSL1.2) revisit !sent case */ if (sent && ret == SSL_TLSEXT_ERR_OK && !s->hit) { /* Only store the hostname in the session if we accepted it. */ OPENSSL_free(s->session->ext.hostname); diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 194b521877..a2a4ae8a6e 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -127,6 +127,10 @@ int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, unsigned int context, return 0; } + /* + * In TLSv1.2 and below the SNI is associated with the session. In TLSv1.3 + * we always use the SNI value from the handshake. + */ if (!s->hit || SSL_IS_TLS13(s)) { if (PACKET_remaining(&hostname) > TLSEXT_MAXLEN_host_name) { SSLfatal(s, SSL_AD_UNRECOGNIZED_NAME, @@ -155,8 +159,12 @@ int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, unsigned int context, } s->servername_done = 1; - } - if (s->hit) { + } else { + /* + * In TLSv1.2 and below we should check if the SNI is consistent between + * the initial handshake and the resumption. In TLSv1.3 SNI is not + * associated with the session. + */ /* * TODO(openssl-team): if the SNI doesn't match, we MUST * fall back to a full handshake. @@ -164,9 +172,6 @@ int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, unsigned int context, s->servername_done = (s->session->ext.hostname != NULL) && PACKET_equal(&hostname, s->session->ext.hostname, strlen(s->session->ext.hostname)); - - if (!s->servername_done && s->session->ext.hostname != NULL) - s->ext.early_data_ok = 0; } return 1; @@ -1333,8 +1338,14 @@ EXT_RETURN tls_construct_stoc_server_name(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx) { - if (s->hit || s->servername_done != 1 - || s->ext.hostname == NULL) + if (s->servername_done != 1) + return EXT_RETURN_NOT_SENT; + + /* + * Prior to TLSv1.3 we ignore any SNI in the current handshake if resuming. + * We just use the servername from the initial handshake. + */ + if (s->hit && !SSL_IS_TLS13(s)) return EXT_RETURN_NOT_SENT; if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_name) |