Commit 3847d426 authored by Matt Caswell's avatar Matt Caswell
Browse files

Add client side support for parsing Hello Retry Request

parent 7d061fce
Loading
Loading
Loading
Loading
+4 −1
Original line number Original line Diff line number Diff line
@@ -881,7 +881,8 @@ typedef enum {
    TLS_ST_CR_CERT_VRFY,
    TLS_ST_CR_CERT_VRFY,
    TLS_ST_SW_CERT_VRFY,
    TLS_ST_SW_CERT_VRFY,
    TLS_ST_CR_HELLO_REQ,
    TLS_ST_CR_HELLO_REQ,
    TLS_ST_SW_HELLO_RETRY_REQUEST
    TLS_ST_SW_HELLO_RETRY_REQUEST,
    TLS_ST_CR_HELLO_RETRY_REQUEST
} OSSL_HANDSHAKE_STATE;
} OSSL_HANDSHAKE_STATE;


/*
/*
@@ -2073,6 +2074,7 @@ int ERR_load_SSL_strings(void);


/* Function codes. */
/* Function codes. */
# define SSL_F_ADD_CLIENT_KEY_SHARE_EXT                   438
# define SSL_F_ADD_CLIENT_KEY_SHARE_EXT                   438
# define SSL_F_ADD_KEY_SHARE                              512
# define SSL_F_CHECK_SUITEB_CIPHER_LIST                   331
# define SSL_F_CHECK_SUITEB_CIPHER_LIST                   331
# define SSL_F_CT_MOVE_SCTS                               345
# define SSL_F_CT_MOVE_SCTS                               345
# define SSL_F_CT_STRICT                                  349
# define SSL_F_CT_STRICT                                  349
@@ -2355,6 +2357,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_TLS_PROCESS_ENCRYPTED_EXTENSIONS           444
# define SSL_F_TLS_PROCESS_ENCRYPTED_EXTENSIONS           444
# define SSL_F_TLS_PROCESS_FINISHED                       364
# define SSL_F_TLS_PROCESS_FINISHED                       364
# define SSL_F_TLS_PROCESS_HELLO_REQ                      507
# define SSL_F_TLS_PROCESS_HELLO_REQ                      507
# define SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST            511
# define SSL_F_TLS_PROCESS_INITIAL_SERVER_FLIGHT          442
# define SSL_F_TLS_PROCESS_INITIAL_SERVER_FLIGHT          442
# define SSL_F_TLS_PROCESS_KEY_EXCHANGE                   365
# define SSL_F_TLS_PROCESS_KEY_EXCHANGE                   365
# define SSL_F_TLS_PROCESS_NEW_SESSION_TICKET             366
# define SSL_F_TLS_PROCESS_NEW_SESSION_TICKET             366
+3 −0
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@


static ERR_STRING_DATA SSL_str_functs[] = {
static ERR_STRING_DATA SSL_str_functs[] = {
    {ERR_FUNC(SSL_F_ADD_CLIENT_KEY_SHARE_EXT), "add_client_key_share_ext"},
    {ERR_FUNC(SSL_F_ADD_CLIENT_KEY_SHARE_EXT), "add_client_key_share_ext"},
    {ERR_FUNC(SSL_F_ADD_KEY_SHARE), "add_key_share"},
    {ERR_FUNC(SSL_F_CHECK_SUITEB_CIPHER_LIST), "check_suiteb_cipher_list"},
    {ERR_FUNC(SSL_F_CHECK_SUITEB_CIPHER_LIST), "check_suiteb_cipher_list"},
    {ERR_FUNC(SSL_F_CT_MOVE_SCTS), "ct_move_scts"},
    {ERR_FUNC(SSL_F_CT_MOVE_SCTS), "ct_move_scts"},
    {ERR_FUNC(SSL_F_CT_STRICT), "ct_strict"},
    {ERR_FUNC(SSL_F_CT_STRICT), "ct_strict"},
@@ -412,6 +413,8 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     "tls_process_encrypted_extensions"},
     "tls_process_encrypted_extensions"},
    {ERR_FUNC(SSL_F_TLS_PROCESS_FINISHED), "tls_process_finished"},
    {ERR_FUNC(SSL_F_TLS_PROCESS_FINISHED), "tls_process_finished"},
    {ERR_FUNC(SSL_F_TLS_PROCESS_HELLO_REQ), "tls_process_hello_req"},
    {ERR_FUNC(SSL_F_TLS_PROCESS_HELLO_REQ), "tls_process_hello_req"},
    {ERR_FUNC(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST),
     "tls_process_hello_retry_request"},
    {ERR_FUNC(SSL_F_TLS_PROCESS_INITIAL_SERVER_FLIGHT),
    {ERR_FUNC(SSL_F_TLS_PROCESS_INITIAL_SERVER_FLIGHT),
     "tls_process_initial_server_flight"},
     "tls_process_initial_server_flight"},
    {ERR_FUNC(SSL_F_TLS_PROCESS_KEY_EXCHANGE), "tls_process_key_exchange"},
    {ERR_FUNC(SSL_F_TLS_PROCESS_KEY_EXCHANGE), "tls_process_key_exchange"},
+110 −47
Original line number Original line Diff line number Diff line
@@ -528,12 +528,57 @@ int tls_construct_ctos_psk_kex_modes(SSL *s, WPACKET *pkt, unsigned int context,
    return 1;
    return 1;
}
}


#ifndef OPENSSL_NO_TLS1_3
static int add_key_share(SSL *s, WPACKET *pkt, unsigned int curve_id)
{
    unsigned char *encodedPoint = NULL;
    EVP_PKEY *key_share_key = NULL;
    size_t encodedlen;

    key_share_key = ssl_generate_pkey_curve(curve_id);
    if (key_share_key == NULL) {
        SSLerr(SSL_F_ADD_KEY_SHARE, ERR_R_EVP_LIB);
        return 0;
    }

    /* Encode the public key. */
    encodedlen = EVP_PKEY_get1_tls_encodedpoint(key_share_key,
                                                &encodedPoint);
    if (encodedlen == 0) {
        SSLerr(SSL_F_ADD_KEY_SHARE, ERR_R_EC_LIB);
        EVP_PKEY_free(key_share_key);
        return 0;
    }

    /* Create KeyShareEntry */
    if (!WPACKET_put_bytes_u16(pkt, curve_id)
            || !WPACKET_sub_memcpy_u16(pkt, encodedPoint, encodedlen)) {
        SSLerr(SSL_F_ADD_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        EVP_PKEY_free(key_share_key);
        OPENSSL_free(encodedPoint);
        return 0;
    }

    /*
     * TODO(TLS1.3): When changing to send more than one key_share we're
     * going to need to be able to save more than one EVP_PKEY. For now
     * we reuse the existing tmp.pkey
     */
    s->s3->tmp.pkey = key_share_key;
    s->s3->group_id = curve_id;
    OPENSSL_free(encodedPoint);

    return 1;
}
#endif

int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, unsigned int context,
int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, unsigned int context,
                                 X509 *x, size_t chainidx, int *al)
                                 X509 *x, size_t chainidx, int *al)
{
{
#ifndef OPENSSL_NO_TLS1_3
#ifndef OPENSSL_NO_TLS1_3
    size_t i, sharessent = 0, num_curves = 0;
    size_t i, num_curves = 0;
    const unsigned char *pcurves = NULL;
    const unsigned char *pcurves = NULL;
    unsigned int curve_id = 0;


    /* key_share extension */
    /* key_share extension */
    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
    if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
@@ -551,61 +596,36 @@ int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, unsigned int context,
        return 0;
        return 0;
    }
    }


    if (s->s3->tmp.pkey != NULL) {
        /* Shouldn't happen! */
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    /*
    /*
     * TODO(TLS1.3): Make the number of key_shares sent configurable. For
     * TODO(TLS1.3): Make the number of key_shares sent configurable. For
     * now, just send one
     * now, just send one
     */
     */
    for (i = 0; i < num_curves && sharessent < 1; i++, pcurves += 2) {
    if (s->s3->group_id != 0) {
        unsigned char *encodedPoint = NULL;
        curve_id = s->s3->group_id;
        unsigned int curve_id = 0;
    } else {
        EVP_PKEY *key_share_key = NULL;
        for (i = 0; i < num_curves; i++, pcurves += 2) {
        size_t encodedlen;


            if (!tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED))
            if (!tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED))
                continue;
                continue;


        if (s->s3->tmp.pkey != NULL) {
            /* Shouldn't happen! */
            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
            return 0;
        }

        /* Generate a key for this key_share */
            curve_id = (pcurves[0] << 8) | pcurves[1];
            curve_id = (pcurves[0] << 8) | pcurves[1];
        key_share_key = ssl_generate_pkey_curve(curve_id);
            break;
        if (key_share_key == NULL) {
            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_EVP_LIB);
            return 0;
        }
        }

        /* Encode the public key. */
        encodedlen = EVP_PKEY_get1_tls_encodedpoint(key_share_key,
                                                    &encodedPoint);
        if (encodedlen == 0) {
            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_EC_LIB);
            EVP_PKEY_free(key_share_key);
            return 0;
    }
    }


        /* Create KeyShareEntry */
    if (curve_id == 0) {
        if (!WPACKET_put_bytes_u16(pkt, curve_id)
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, SSL_R_NO_SUITABLE_KEY_SHARE);
                || !WPACKET_sub_memcpy_u16(pkt, encodedPoint, encodedlen)) {
            SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
            EVP_PKEY_free(key_share_key);
            OPENSSL_free(encodedPoint);
        return 0;
        return 0;
    }
    }


        /*
    if (!add_key_share(s, pkt, curve_id))
         * TODO(TLS1.3): When changing to send more than one key_share we're
        return 0;
         * going to need to be able to save more than one EVP_PKEY. For now
         * we reuse the existing tmp.pkey
         */
        s->s3->group_id = curve_id;
        s->s3->tmp.pkey = key_share_key;
        sharessent++;
        OPENSSL_free(encodedPoint);
    }


    if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
    if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
        SSLerr(SSL_F_TLS_CONSTRUCT_CTOS_KEY_SHARE, ERR_R_INTERNAL_ERROR);
@@ -1188,6 +1208,49 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
        return 0;
        return 0;
    }
    }


    if ((context & EXT_TLS1_3_HELLO_RETRY_REQUEST) != 0) {
        unsigned const char *pcurves = NULL;
        size_t i, num_curves;

        if (PACKET_remaining(pkt) != 0) {
            *al = SSL_AD_HANDSHAKE_FAILURE;
            SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_LENGTH_MISMATCH);
            return 0;
        }

        /*
         * It is an error if the HelloRetryRequest wants a key_share that we
         * already sent in the first ClientHello
         */
        if (group_id == s->s3->group_id) {
            *al = SSL_AD_ILLEGAL_PARAMETER;
            SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_BAD_KEY_SHARE);
            return 0;
        }

        /* Validate the selected group is one we support */
        pcurves = s->ext.supportedgroups;
        if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
            SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
            return 0;
        }
        for (i = 0; i < num_curves; i++, pcurves += 2) {
            if (group_id == (unsigned int)((pcurves[0] << 8) | pcurves[1]))
                break;
        }
        if (i >= num_curves
                || !tls_curve_allowed(s, pcurves, SSL_SECOP_CURVE_SUPPORTED)) {
            *al = SSL_AD_ILLEGAL_PARAMETER;
            SSLerr(SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_BAD_KEY_SHARE);
            return 0;
        }

        s->s3->group_id = group_id;
        EVP_PKEY_free(s->s3->tmp.pkey);
        s->s3->tmp.pkey = NULL;
        return 1;
    }

    if (group_id != s->s3->group_id) {
    if (group_id != s->s3->group_id) {
        /*
        /*
         * This isn't for the group that we sent in the original
         * This isn't for the group that we sent in the original
+82 −5
Original line number Original line Diff line number Diff line
@@ -60,6 +60,7 @@
#include <openssl/bn.h>
#include <openssl/bn.h>
#include <openssl/engine.h>
#include <openssl/engine.h>


static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt);
static MSG_PROCESS_RETURN tls_process_encrypted_extensions(SSL *s, PACKET *pkt);
static MSG_PROCESS_RETURN tls_process_encrypted_extensions(SSL *s, PACKET *pkt);


static ossl_inline int cert_req_allowed(SSL *s);
static ossl_inline int cert_req_allowed(SSL *s);
@@ -137,6 +138,17 @@ static int ossl_statem_client13_read_transition(SSL *s, int mt)
    default:
    default:
        break;
        break;


    case TLS_ST_CW_CLNT_HELLO:
        /*
         * This must a ClientHello following a HelloRetryRequest, so the only
         * thing we can get now is a ServerHello.
         */
        if (mt == SSL3_MT_SERVER_HELLO) {
            st->hand_state = TLS_ST_CR_SRVR_HELLO;
            return 1;
        }
        break;

    case TLS_ST_CR_SRVR_HELLO:
    case TLS_ST_CR_SRVR_HELLO:
        if (mt == SSL3_MT_ENCRYPTED_EXTENSIONS) {
        if (mt == SSL3_MT_ENCRYPTED_EXTENSIONS) {
            st->hand_state = TLS_ST_CR_ENCRYPTED_EXTENSIONS;
            st->hand_state = TLS_ST_CR_ENCRYPTED_EXTENSIONS;
@@ -210,8 +222,8 @@ int ossl_statem_client_read_transition(SSL *s, int mt)
    int ske_expected;
    int ske_expected;


    /*
    /*
     * Note that after a ClientHello we don't know what version we are going
     * Note that after writing the first ClientHello we don't know what version
     * to negotiate yet, so we don't take this branch until later
     * we are going to negotiate yet, so we don't take this branch until later.
     */
     */
    if (SSL_IS_TLS13(s)) {
    if (SSL_IS_TLS13(s)) {
        if (!ossl_statem_client13_read_transition(s, mt))
        if (!ossl_statem_client13_read_transition(s, mt))
@@ -234,6 +246,11 @@ int ossl_statem_client_read_transition(SSL *s, int mt)
                st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST;
                st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST;
                return 1;
                return 1;
            }
            }
        } else {
            if (mt == SSL3_MT_HELLO_RETRY_REQUEST) {
                st->hand_state = TLS_ST_CR_HELLO_RETRY_REQUEST;
                return 1;
            }
        }
        }
        break;
        break;


@@ -390,15 +407,23 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
     */
     */


    /*
    /*
     * Note: There are no cases for TLS_ST_BEFORE or TLS_ST_CW_CLNT_HELLO,
     * Note: There are no cases for TLS_ST_BEFORE because we haven't negotiated
     * because we haven't negotiated TLSv1.3 yet at that point. They are
     * TLSv1.3 yet at that point. They are handled by
     * handled by ossl_statem_client_write_transition().
     * ossl_statem_client_write_transition().
     */
     */
    switch (st->hand_state) {
    switch (st->hand_state) {
    default:
    default:
        /* Shouldn't happen */
        /* Shouldn't happen */
        return WRITE_TRAN_ERROR;
        return WRITE_TRAN_ERROR;


    case TLS_ST_CW_CLNT_HELLO:
        /* We only hit this in the case of HelloRetryRequest */
        return WRITE_TRAN_FINISHED;

    case TLS_ST_CR_HELLO_RETRY_REQUEST:
        st->hand_state = TLS_ST_CW_CLNT_HELLO;
        return WRITE_TRAN_CONTINUE;

    case TLS_ST_CR_FINISHED:
    case TLS_ST_CR_FINISHED:
        st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT
        st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT
                                                    : TLS_ST_CW_FINISHED;
                                                    : TLS_ST_CW_FINISHED;
@@ -779,6 +804,9 @@ size_t ossl_statem_client_max_message_size(SSL *s)
    case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
    case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
        return HELLO_VERIFY_REQUEST_MAX_LENGTH;
        return HELLO_VERIFY_REQUEST_MAX_LENGTH;


    case TLS_ST_CR_HELLO_RETRY_REQUEST:
        return HELLO_RETRY_REQUEST_MAX_LENGTH;

    case TLS_ST_CR_CERT:
    case TLS_ST_CR_CERT:
        return s->max_cert_list;
        return s->max_cert_list;


@@ -836,6 +864,9 @@ MSG_PROCESS_RETURN ossl_statem_client_process_message(SSL *s, PACKET *pkt)
    case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
    case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
        return dtls_process_hello_verify(s, pkt);
        return dtls_process_hello_verify(s, pkt);


    case TLS_ST_CR_HELLO_RETRY_REQUEST:
        return tls_process_hello_retry_request(s, pkt);

    case TLS_ST_CR_CERT:
    case TLS_ST_CR_CERT:
        return tls_process_server_certificate(s, pkt);
        return tls_process_server_certificate(s, pkt);


@@ -1432,6 +1463,52 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
    return MSG_PROCESS_ERROR;
    return MSG_PROCESS_ERROR;
}
}


static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt)
{
    unsigned int sversion;
    int protverr;
    RAW_EXTENSION *extensions = NULL;
    int al;
    PACKET extpkt;

    if (!PACKET_get_net_2(pkt, &sversion)) {
        al = SSL_AD_DECODE_ERROR;
        SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, SSL_R_LENGTH_MISMATCH);
        goto f_err;
    }

    s->hello_retry_request = 1;

    /* This will fail if it doesn't choose TLSv1.3+ */
    protverr = ssl_choose_client_version(s, sversion);
    if (protverr != 0) {
        al = SSL_AD_PROTOCOL_VERSION;
        SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, protverr);
        goto f_err;
    }

    if (!PACKET_as_length_prefixed_2(pkt, &extpkt)) {
        al = SSL_AD_DECODE_ERROR;
        SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, SSL_R_BAD_LENGTH);
        goto f_err;
    }

    if (!tls_collect_extensions(s, &extpkt, EXT_TLS1_3_HELLO_RETRY_REQUEST,
                                &extensions, &al)
            || !tls_parse_all_extensions(s, EXT_TLS1_3_HELLO_RETRY_REQUEST,
                                         extensions, NULL, 0, &al))
        goto f_err;

    OPENSSL_free(extensions);

    return MSG_PROCESS_FINISHED_READING;
 f_err:
    ssl3_send_alert(s, SSL3_AL_FATAL, al);
    ossl_statem_set_error(s);
    OPENSSL_free(extensions);
    return MSG_PROCESS_ERROR;
}

MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt)
MSG_PROCESS_RETURN tls_process_server_certificate(SSL *s, PACKET *pkt)
{
{
    int al, i, ret = MSG_PROCESS_ERROR, exp_idx;
    int al, i, ret = MSG_PROCESS_ERROR, exp_idx;
+3 −0
Original line number Original line Diff line number Diff line
@@ -1595,6 +1595,9 @@ int ssl_choose_client_version(SSL *s, int version)
            continue;
            continue;
        if (vent->cmeth == NULL)
        if (vent->cmeth == NULL)
            break;
            break;
        if (s->hello_retry_request && version != TLS1_3_VERSION)
            return SSL_R_WRONG_SSL_VERSION;

        method = vent->cmeth();
        method = vent->cmeth();
        err = ssl_method_error(s, method);
        err = ssl_method_error(s, method);
        if (err != 0)
        if (err != 0)
Loading