Commit 11c67eea authored by Matt Caswell's avatar Matt Caswell
Browse files

HelloRetryRequest updates for draft-19



Draft-19 changes the HRR transcript hash so that the initial ClientHello
is replaced in the transcript with a special synthetic message_hash message
that just contains a hash of ClientHello1 as its message body.

Reviewed-by: default avatarRich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2895)
parent 9e0ac6a2
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -2135,6 +2135,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_ADD_KEY_SHARE                              512
# define SSL_F_BYTES_TO_CIPHER_LIST                       519
# define SSL_F_CHECK_SUITEB_CIPHER_LIST                   331
# define SSL_F_CREATE_SYNTHETIC_MESSAGE_HASH              539
# define SSL_F_CT_MOVE_SCTS                               345
# define SSL_F_CT_STRICT                                  349
# define SSL_F_D2I_SSL_SESSION                            103
@@ -2175,6 +2176,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION         418
# define SSL_F_PROCESS_KEY_SHARE_EXT                      439
# define SSL_F_READ_STATE_MACHINE                         352
# define SSL_F_SET_CLIENT_CIPHERSUITE                     540
# define SSL_F_SSL3_CHANGE_CIPHER_STATE                   129
# define SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM              130
# define SSL_F_SSL3_CTRL                                  213
@@ -2464,6 +2466,7 @@ int ERR_load_SSL_strings(void);
# define SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE       143
# define SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE     158
# define SSL_R_BAD_CHANGE_CIPHER_SPEC                     103
# define SSL_R_BAD_CIPHER                                 186
# define SSL_R_BAD_DATA                                   390
# define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK              106
# define SSL_R_BAD_DECOMPRESSION                          107
+3 −2
Original line number Diff line number Diff line
@@ -295,6 +295,7 @@ extern "C" {
# ifndef OPENSSL_NO_NEXTPROTONEG
#  define SSL3_MT_NEXT_PROTO                     67
# endif
# define SSL3_MT_MESSAGE_HASH                    254
# define DTLS1_MT_HELLO_VERIFY_REQUEST           3

/* Dummy message type for handling CCS like a normal handshake message */
+4 −0
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ static ERR_STRING_DATA SSL_str_functs[] = {
    {ERR_FUNC(SSL_F_ADD_KEY_SHARE), "add_key_share"},
    {ERR_FUNC(SSL_F_BYTES_TO_CIPHER_LIST), "bytes_to_cipher_list"},
    {ERR_FUNC(SSL_F_CHECK_SUITEB_CIPHER_LIST), "check_suiteb_cipher_list"},
    {ERR_FUNC(SSL_F_CREATE_SYNTHETIC_MESSAGE_HASH),
     "create_synthetic_message_hash"},
    {ERR_FUNC(SSL_F_CT_MOVE_SCTS), "ct_move_scts"},
    {ERR_FUNC(SSL_F_CT_STRICT), "ct_strict"},
    {ERR_FUNC(SSL_F_D2I_SSL_SESSION), "d2i_SSL_SESSION"},
@@ -74,6 +76,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     "ossl_statem_server_read_transition"},
    {ERR_FUNC(SSL_F_PROCESS_KEY_SHARE_EXT), "process_key_share_ext"},
    {ERR_FUNC(SSL_F_READ_STATE_MACHINE), "read_state_machine"},
    {ERR_FUNC(SSL_F_SET_CLIENT_CIPHERSUITE), "set_client_ciphersuite"},
    {ERR_FUNC(SSL_F_SSL3_CHANGE_CIPHER_STATE), "ssl3_change_cipher_state"},
    {ERR_FUNC(SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM),
     "ssl3_check_cert_and_algorithm"},
@@ -481,6 +484,7 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
    {ERR_REASON(SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE),
     "at least (D)TLS 1.2 needed in Suite B mode"},
    {ERR_REASON(SSL_R_BAD_CHANGE_CIPHER_SPEC), "bad change cipher spec"},
    {ERR_REASON(SSL_R_BAD_CIPHER), "bad cipher"},
    {ERR_REASON(SSL_R_BAD_DATA), "bad data"},
    {ERR_REASON(SSL_R_BAD_DATA_RETURNED_BY_CALLBACK),
     "bad data returned by callback"},
+88 −39
Original line number Diff line number Diff line
@@ -1243,14 +1243,65 @@ MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt)
    return MSG_PROCESS_ERROR;
}

MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
static int set_client_ciphersuite(SSL *s, const unsigned char *cipherchars)
{
    STACK_OF(SSL_CIPHER) *sk;
    const SSL_CIPHER *c;
    int i;

    c = ssl_get_cipher_by_char(s, cipherchars, 0);
    if (c == NULL) {
        /* unknown cipher */
        SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE, SSL_R_UNKNOWN_CIPHER_RETURNED);
        return 0;
    }
    /*
     * If it is a disabled cipher we either didn't send it in client hello,
     * or it's not allowed for the selected protocol. So we return an error.
     */
    if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_CHECK)) {
        SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE, SSL_R_WRONG_CIPHER_RETURNED);
        return 0;
    }

    sk = ssl_get_ciphers_by_id(s);
    i = sk_SSL_CIPHER_find(sk, c);
    if (i < 0) {
        /* we did not say we would use this cipher */
        SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE, SSL_R_WRONG_CIPHER_RETURNED);
        return 0;
    }

    if (SSL_IS_TLS13(s) && s->s3->tmp.new_cipher != NULL
            && s->s3->tmp.new_cipher->id != c->id) {
        /* ServerHello selected a different ciphersuite to that in the HRR */
        SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE, SSL_R_WRONG_CIPHER_RETURNED);
        return 0;
    }

    /*
     * Depending on the session caching (internal/external), the cipher
     * and/or cipher_id values may not be set. Make sure that cipher_id is
     * set and use it for comparison.
     */
    if (s->session->cipher != NULL)
        s->session->cipher_id = s->session->cipher->id;
    if (s->hit && (s->session->cipher_id != c->id)) {
        SSLerr(SSL_F_SET_CLIENT_CIPHERSUITE,
               SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
        return 0;
    }
    s->s3->tmp.new_cipher = c;

    return 1;
}

MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
{
    PACKET session_id, extpkt;
    size_t session_id_len;
    const unsigned char *cipherchars;
    int i, al = SSL_AD_INTERNAL_ERROR;
    int al = SSL_AD_INTERNAL_ERROR;
    unsigned int compression;
    unsigned int sversion;
    unsigned int context;
@@ -1437,53 +1488,17 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
               SSL_R_SSL_SESSION_VERSION_MISMATCH);
        goto f_err;
    }

    c = ssl_get_cipher_by_char(s, cipherchars, 0);
    if (c == NULL) {
        /* unknown cipher */
        al = SSL_AD_ILLEGAL_PARAMETER;
        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_UNKNOWN_CIPHER_RETURNED);
        goto f_err;
    }
    /*
     * Now that we know the version, update the check to see if it's an allowed
     * version.
     */
    s->s3->tmp.min_ver = s->version;
    s->s3->tmp.max_ver = s->version;
    /*
     * If it is a disabled cipher we either didn't send it in client hello,
     * or it's not allowed for the selected protocol. So we return an error.
     */
    if (ssl_cipher_disabled(s, c, SSL_SECOP_CIPHER_CHECK)) {
        al = SSL_AD_ILLEGAL_PARAMETER;
        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED);
        goto f_err;
    }

    sk = ssl_get_ciphers_by_id(s);
    i = sk_SSL_CIPHER_find(sk, c);
    if (i < 0) {
        /* we did not say we would use this cipher */
    if (!set_client_ciphersuite(s, cipherchars)) {
        al = SSL_AD_ILLEGAL_PARAMETER;
        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_WRONG_CIPHER_RETURNED);
        goto f_err;
    }

    /*
     * Depending on the session caching (internal/external), the cipher
     * and/or cipher_id values may not be set. Make sure that cipher_id is
     * set and use it for comparison.
     */
    if (s->session->cipher)
        s->session->cipher_id = s->session->cipher->id;
    if (s->hit && (s->session->cipher_id != c->id)) {
        al = SSL_AD_ILLEGAL_PARAMETER;
        SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO,
               SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
        goto f_err;
    }
    s->s3->tmp.new_cipher = c;

#ifdef OPENSSL_NO_COMP
    if (compression != 0) {
@@ -1580,6 +1595,7 @@ static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt)
{
    unsigned int sversion;
    int errorcode;
    const unsigned char *cipherchars;
    RAW_EXTENSION *extensions = NULL;
    int al;
    PACKET extpkt;
@@ -1600,6 +1616,17 @@ static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt)
        goto f_err;
    }

    if (!PACKET_get_bytes(pkt, &cipherchars, TLS_CIPHER_LEN)) {
        SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, SSL_R_LENGTH_MISMATCH);
        al = SSL_AD_DECODE_ERROR;
        goto f_err;
    }

    if (!set_client_ciphersuite(s, cipherchars)) {
        al = SSL_AD_ILLEGAL_PARAMETER;
        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);
@@ -1614,6 +1641,28 @@ static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt)

    OPENSSL_free(extensions);

    /*
     * Re-initialise the Transcript Hash. We're going to prepopulate it with
     * a synthetic message_hash in place of ClientHello1.
     */
    if (!create_synthetic_message_hash(s)) {
        al = SSL_AD_INTERNAL_ERROR;
        goto f_err;
    }

    /*
     * Add this message to the Transcript Hash. Normally this is done
     * automatically prior to the message processing stage. However due to the
     * need to create the synthetic message hash, we defer that step until now
     * for HRR messages.
     */
    if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
                                s->init_num + SSL3_HM_HEADER_LENGTH)) {
        al = SSL_AD_INTERNAL_ERROR;
        SSLerr(SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST, ERR_R_INTERNAL_ERROR);
        goto f_err;
    }

    return MSG_PROCESS_FINISHED_READING;
 f_err:
    ssl3_send_alert(s, SSL3_AL_FATAL, al);
+41 −2
Original line number Diff line number Diff line
@@ -1149,7 +1149,12 @@ int tls_get_message_body(SSL *s, size_t *len)
            s->msg_callback(0, SSL2_VERSION, 0, s->init_buf->data,
                            (size_t)s->init_num, s, s->msg_callback_arg);
    } else {
        if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
        /*
         * We defer feeding in the HRR until later. We'll do it as part of
         * processing the message
         */
        if (s->s3->tmp.message_type != SSL3_MT_HELLO_RETRY_REQUEST
                && !ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
                                    s->init_num + SSL3_HM_HEADER_LENGTH)) {
            SSLerr(SSL_F_TLS_GET_MESSAGE_BODY, ERR_R_EVP_LIB);
            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
@@ -1870,3 +1875,37 @@ int check_in_list(SSL *s, unsigned int group_id, const unsigned char *groups,
    return i < num_groups;
}
#endif

/* Replace ClientHello1 in the transcript hash with a synthetic message */
int create_synthetic_message_hash(SSL *s)
{
    unsigned char hashval[EVP_MAX_MD_SIZE];
    size_t hashlen = 0;
    unsigned char msghdr[SSL3_HM_HEADER_LENGTH] = {
        SSL3_MT_MESSAGE_HASH,
        0,
        0,
        0
    };

    /* Get the hash of the initial ClientHello */
    if (!ssl3_digest_cached_records(s, 0)
            || !ssl_handshake_hash(s, hashval, sizeof(hashval), &hashlen)) {
        SSLerr(SSL_F_CREATE_SYNTHETIC_MESSAGE_HASH, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    /* Reinitialise the transcript hash */
    if (!ssl3_init_finished_mac(s))
        return 0;

    /* Inject the synthetic message_hash message */
    msghdr[SSL3_HM_HEADER_LENGTH - 1] = hashlen;
    if (!ssl3_finish_mac(s, msghdr, SSL3_HM_HEADER_LENGTH)
            || !ssl3_finish_mac(s, hashval, hashlen)) {
        SSLerr(SSL_F_CREATE_SYNTHETIC_MESSAGE_HASH, ERR_R_INTERNAL_ERROR);
        return 0;
    }

    return 1;
}
Loading