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

Add server side support for TLSv1.3 downgrade mechanism

parent a41815f0
Loading
Loading
Loading
Loading
+27 −5
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@
 */

#include <stdio.h>
#include <assert.h>
#include <openssl/objects.h>
#include "ssl_locl.h"
#include <openssl/md5.h>
@@ -4007,9 +4008,10 @@ long ssl_get_algorithm2(SSL *s)
 * Fill a ClientRandom or ServerRandom field of length len. Returns <= 0 on
 * failure, 1 on success.
 */
int ssl_fill_hello_random(SSL *s, int server, unsigned char *result, size_t len)
int ssl_fill_hello_random(SSL *s, int server, unsigned char *result, size_t len,
                          DOWNGRADE dgrd)
{
    int send_time = 0;
    int send_time = 0, ret;

    if (len < 4)
        return 0;
@@ -4022,9 +4024,29 @@ int ssl_fill_hello_random(SSL *s, int server, unsigned char *result, size_t len)
        unsigned char *p = result;
        l2n(Time, p);
        /* TODO(size_t): Convert this */
        return RAND_bytes(p, (int)(len - 4));
    } else
        return RAND_bytes(result, (int)len);
        ret = RAND_bytes(p, (int)(len - 4));
    } else {
        ret = RAND_bytes(result, (int)len);
    }
#ifndef OPENSSL_NO_TLS13DOWNGRADE
    if (ret) {
        static const unsigned char tls11downgrade[] = {
            0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x00
        };
        static const unsigned char tls12downgrade[] = {
            0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01
        };

        assert(sizeof(tls11downgrade) < len && sizeof(tls12downgrade) < len);
        if (dgrd == DOWNGRADE_TO_1_2)
            memcpy(result + len - sizeof(tls12downgrade), tls12downgrade,
                   sizeof(tls12downgrade));
        else if (dgrd == DOWNGRADE_TO_1_1)
            memcpy(result + len - sizeof(tls11downgrade), tls11downgrade,
                   sizeof(tls11downgrade));
    }
#endif
    return ret;
}

int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen,
+9 −2
Original line number Diff line number Diff line
@@ -1783,6 +1783,12 @@ typedef struct ssl3_comp_st {
} SSL3_COMP;
# endif

typedef enum downgrade_en {
    DOWNGRADE_NONE,
    DOWNGRADE_TO_1_2,
    DOWNGRADE_TO_1_1
} DOWNGRADE;

/*
 * Extension index values NOTE: Any updates to these defines should be mirrored
 * with equivalent updates to ext_defs in extensions.c
@@ -2101,7 +2107,7 @@ __owur int ssl_verify_alarm_type(long type);
void ssl_sort_cipher_list(void);
void ssl_load_ciphers(void);
__owur int ssl_fill_hello_random(SSL *s, int server, unsigned char *field,
                                 size_t len);
                                 size_t len, DOWNGRADE dgrd);
__owur int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen,
                                      int free_pms);
__owur EVP_PKEY *ssl_generate_pkey(EVP_PKEY *pm);
@@ -2167,7 +2173,8 @@ __owur int ssl_version_supported(const SSL *s, int version);
__owur int ssl_set_client_hello_version(SSL *s);
__owur int ssl_check_version_downgrade(SSL *s);
__owur int ssl_set_version_bound(int method_version, int version, int *bound);
__owur int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello);
__owur int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello,
                                     DOWNGRADE *dgrd);
__owur int ssl_choose_client_version(SSL *s, int version);
int ssl_get_client_min_max_version(const SSL *s, int *min_version,
                                   int *max_version);
+2 −1
Original line number Diff line number Diff line
@@ -1094,7 +1094,8 @@ int tls_construct_client_hello(SSL *s, WPACKET *pkt)
    } else
        i = 1;

    if (i && ssl_fill_hello_random(s, 0, p, sizeof(s->s3->client_random)) <= 0)
    if (i && ssl_fill_hello_random(s, 0, p, sizeof(s->s3->client_random),
                                   DOWNGRADE_NONE) <= 0)
        return 0;

    /*-
+20 −1
Original line number Diff line number Diff line
@@ -1295,6 +1295,7 @@ typedef struct {
# error Code needs update for TLS_method() support beyond TLS1_3_VERSION.
#endif

/* Must be in order high to low */
static const version_info tls_version_table[] = {
#ifndef OPENSSL_NO_TLS1_3
    {TLS1_3_VERSION, tlsv1_3_client_method, tlsv1_3_server_method},
@@ -1328,6 +1329,7 @@ static const version_info tls_version_table[] = {
# error Code needs update for DTLS_method() support beyond DTLS1_2_VERSION.
#endif

/* Must be in order high to low */
static const version_info dtls_version_table[] = {
#ifndef OPENSSL_NO_DTLS1_2
    {DTLS1_2_VERSION, dtlsv1_2_client_method, dtlsv1_2_server_method},
@@ -1510,6 +1512,20 @@ int ssl_set_version_bound(int method_version, int version, int *bound)
    return 1;
}

static void check_for_downgrade(SSL *s, int vers, DOWNGRADE *dgrd)
{
    if (vers == TLS1_2_VERSION
            && ssl_version_supported(s, TLS1_3_VERSION)) {
        *dgrd = DOWNGRADE_TO_1_2;
    } else if (!SSL_IS_DTLS(s) && vers < TLS1_2_VERSION
            && (ssl_version_supported(s, TLS1_2_VERSION)
                || ssl_version_supported(s, TLS1_3_VERSION))) {
        *dgrd = DOWNGRADE_TO_1_1;
    } else {
        *dgrd = DOWNGRADE_NONE;
    }
}

/*
 * ssl_choose_server_version - Choose server (D)TLS version.  Called when the
 * client HELLO is received to select the final server protocol version and
@@ -1519,7 +1535,7 @@ int ssl_set_version_bound(int method_version, int version, int *bound)
 *
 * Returns 0 on success or an SSL error reason number on failure.
 */
int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello)
int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello, DOWNGRADE *dgrd)
{
    /*-
     * With version-flexible methods we have an initial state with:
@@ -1544,6 +1560,7 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello)
        if (!SSL_IS_TLS13(s)) {
            if (version_cmp(s, client_version, s->version) < 0)
                return SSL_R_WRONG_SSL_VERSION;
            *dgrd = DOWNGRADE_NONE;
            /*
             * If this SSL handle is not from a version flexible method we don't
             * (and never did) check min/max FIPS or Suite B constraints.  Hope
@@ -1620,6 +1637,7 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello)
                    return SSL_R_UNSUPPORTED_PROTOCOL;
                return 0;
            }
            check_for_downgrade(s, best_vers, dgrd);
            s->version = best_vers;
            s->method = best_method;
            return 0;
@@ -1646,6 +1664,7 @@ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello)
            continue;
        method = vent->smeth();
        if (ssl_method_error(s, method) == 0) {
            check_for_downgrade(s, vent->version, dgrd);
            s->version = vent->version;
            s->method = method;
            return 0;
+4 −3
Original line number Diff line number Diff line
@@ -1476,6 +1476,7 @@ static int tls_early_post_process_client_hello(SSL *s, int *al)
    STACK_OF(SSL_CIPHER) *ciphers = NULL;
    STACK_OF(SSL_CIPHER) *scsvs = NULL;
    CLIENTHELLO_MSG *clienthello = s->clienthello;
    DOWNGRADE dgrd = DOWNGRADE_NONE;

    *al = SSL_AD_INTERNAL_ERROR;
    /* Finished parsing the ClientHello, now we can start processing it */
@@ -1516,7 +1517,7 @@ static int tls_early_post_process_client_hello(SSL *s, int *al)
     * versions are potentially compatible. Version negotiation comes later.
     */
    if (!SSL_IS_DTLS(s)) {
        protverr = ssl_choose_server_version(s, clienthello);
        protverr = ssl_choose_server_version(s, clienthello, &dgrd);
    } else if (s->method->version != DTLS_ANY_VERSION &&
               DTLS_VERSION_LT((int)clienthello->legacy_version, s->version)) {
        protverr = SSL_R_VERSION_TOO_LOW;
@@ -1565,7 +1566,7 @@ static int tls_early_post_process_client_hello(SSL *s, int *al)
            s->d1->cookie_verified = 1;
        }
        if (s->method->version == DTLS_ANY_VERSION) {
            protverr = ssl_choose_server_version(s, clienthello);
            protverr = ssl_choose_server_version(s, clienthello, &dgrd);
            if (protverr != 0) {
                SSLerr(SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO, protverr);
                s->version = s->client_version;
@@ -1722,7 +1723,7 @@ static int tls_early_post_process_client_hello(SSL *s, int *al)
    {
        unsigned char *pos;
        pos = s->s3->server_random;
        if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE) <= 0) {
        if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE, dgrd) <= 0) {
            goto err;
        }
    }