Commit cd998837 authored by Matt Caswell's avatar Matt Caswell
Browse files

Add server side support for supported_versions extension



Reviewed-by: default avatarRich Salz <rsalz@openssl.org>
parent 5506e835
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -2077,6 +2077,9 @@ __owur int dtls1_process_heartbeat(SSL *s, unsigned char *p,
                                   size_t length);
#  endif

__owur RAW_EXTENSION *tls_get_extension_by_type(RAW_EXTENSION *exts,
                                                size_t numexts,
                                                unsigned int type);
__owur int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
                                      SSL_SESSION **ret);
__owur int tls_check_client_ems_support(SSL *s, const CLIENTHELLO_MSG *hello);
+6 −1
Original line number Diff line number Diff line
@@ -779,8 +779,13 @@ int tls_construct_client_hello(SSL *s, WPACKET *pkt)
     * TLS 1.0 and renegotiating with TLS 1.2. We do this by using
     * client_version in client hello and not resetting it to
     * the negotiated version.
     *
     * For TLS 1.3 we always set the ClientHello version to 1.2 and rely on the
     * supported_versions extension for the reall supported versions.
     */
    if (!WPACKET_put_bytes_u16(pkt, s->client_version)
    if (!WPACKET_put_bytes_u16(pkt,
                (!SSL_IS_DTLS(s) && s->client_version >= TLS1_3_VERSION)
                ? TLS1_2_VERSION : s->client_version)
            || !WPACKET_memcpy(pkt, s->s3->client_random, SSL3_RANDOM_SIZE)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
        return 0;
+68 −0
Original line number Diff line number Diff line
@@ -996,6 +996,7 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello)
    const version_info *vent;
    const version_info *table;
    int disabled = 0;
    RAW_EXTENSION *suppversions;

    s->client_version = client_version;

@@ -1019,6 +1020,73 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello)
        break;
    }

    suppversions = tls_get_extension_by_type(hello->pre_proc_exts,
                                             hello->num_extensions,
                                             TLSEXT_TYPE_supported_versions);

    /*
     * TODO(TLS1.3): We only look at this if our max protocol version is TLS1.3
     * or above. Should we allow it for lower versions too?
     */
    if (suppversions != NULL && !SSL_IS_DTLS(s)
            && (s->max_proto_version == 0
                || TLS1_3_VERSION <= s->max_proto_version)) {
        unsigned int candidate_vers = 0;
        unsigned int best_vers = 0;
        const SSL_METHOD *best_method = NULL;
        PACKET versionslist;

        if (!PACKET_get_length_prefixed_1(&suppversions->data, &versionslist)
                || PACKET_remaining(&suppversions->data) != 0) {
            /* Trailing or invalid data? */
            return SSL_R_LENGTH_MISMATCH;
        }

        while (PACKET_get_net_2(&versionslist, &candidate_vers)) {
            /* TODO(TLS1.3): Remove this before release */
            if (candidate_vers == TLS1_3_VERSION_DRAFT)
                candidate_vers = TLS1_3_VERSION;
            if ((int)candidate_vers > s->client_version)
                s->client_version = candidate_vers;
            if (version_cmp(s, candidate_vers, best_vers) <= 0)
                continue;
            for (vent = table;
                 vent->version != 0 && vent->version != (int)candidate_vers;
                 ++vent);
            if (vent->version != 0) {
                const SSL_METHOD *method;

                method = vent->smeth();
                if (ssl_method_error(s, method) == 0) {
                    best_vers = candidate_vers;
                    best_method = method;
                }
            }
        }
        if (PACKET_remaining(&versionslist) != 0) {
            /* Trailing data? */
            return SSL_R_LENGTH_MISMATCH;
        }

        if (best_vers > 0) {
            s->version = best_vers;
            s->method = best_method;
            return 0;
        }
        return SSL_R_UNSUPPORTED_PROTOCOL;
    }

    /*
     * If the supported versions extension isn't present, then the highest
     * version we can negotiate is TLSv1.2
     */
    if (version_cmp(s, client_version, TLS1_3_VERSION) >= 0)
        client_version = TLS1_2_VERSION;

    /*
     * No supported versions extension, so we just use the version supplied in
     * the ClientHello.
     */
    for (vent = table; vent->version != 0; ++vent) {
        const SSL_METHOD *method;

+8 −7
Original line number Diff line number Diff line
@@ -2826,7 +2826,7 @@ int ssl_parse_serverhello_tlsext(SSL *s, PACKET *pkt)
 *
 * Returns a pointer to the found RAW_EXTENSION data, or NULL if not found.
 */
static RAW_EXTENSION *get_extension_by_type(RAW_EXTENSION *exts, size_t numexts,
RAW_EXTENSION *tls_get_extension_by_type(RAW_EXTENSION *exts, size_t numexts,
                                         unsigned int type)
{
    size_t loop;
@@ -2885,7 +2885,7 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
    if (s->version <= SSL3_VERSION || !tls_use_ticket(s))
        return 0;

    ticketext = get_extension_by_type(hello->pre_proc_exts,
    ticketext = tls_get_extension_by_type(hello->pre_proc_exts,
                                          hello->num_extensions,
                                          TLSEXT_TYPE_session_ticket);
    if (ticketext == NULL)
@@ -2948,7 +2948,8 @@ int tls_check_client_ems_support(SSL *s, const CLIENTHELLO_MSG *hello)
    if (s->version <= SSL3_VERSION)
        return 1;

    emsext = get_extension_by_type(hello->pre_proc_exts, hello->num_extensions,
    emsext = tls_get_extension_by_type(hello->pre_proc_exts,
                                       hello->num_extensions,
                                       TLSEXT_TYPE_extended_master_secret);

    /*
+6 −3
Original line number Diff line number Diff line
@@ -34,15 +34,18 @@ my $proxy = TLSProxy::Proxy->new(
    (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
);

#Test 1: Asking for TLS1.3 should pass
my $client_version = TLSProxy::Record::VERS_TLS_1_3;
#Test 1: Asking for TLS1.4 should pass
my $client_version = TLSProxy::Record::VERS_TLS_1_4;
#We don't want the supported versions extension for this test
$proxy->clientflags("-no_tls1_3");
$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
plan tests => 2;
ok(TLSProxy::Message->success(), "Version tolerance test, TLS 1.3");
ok(TLSProxy::Message->success(), "Version tolerance test, TLS 1.4");

#Test 2: Testing something below SSLv3 should fail
$client_version = TLSProxy::Record::VERS_SSL_3_0 - 1;
$proxy->clear();
$proxy->clientflags("-no_tls1_3");
$proxy->start();
ok(TLSProxy::Message->fail(), "Version tolerance test, SSL < 3.0");

Loading