From: Matt Caswell Date: Sat, 22 Oct 2016 16:24:37 +0000 (+0100) Subject: Refactor ClientHello processing so that extensions get parsed earlier X-Git-Tag: OpenSSL_1_1_1-pre1~3157 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=1ab3836b3bb8ccfa4da7ce529d420e750cd56b32;p=oweals%2Fopenssl.git Refactor ClientHello processing so that extensions get parsed earlier Reviewed-by: Kurt Roeckx Reviewed-by: Rich Salz --- diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index c781323fb4..905eeb510f 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -2256,6 +2256,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE 377 # define SSL_F_TLS_GET_MESSAGE_BODY 351 # define SSL_F_TLS_GET_MESSAGE_HEADER 387 +# define SSL_F_TLS_PARSE_RAW_EXTENSIONS 432 # define SSL_F_TLS_POST_PROCESS_CLIENT_HELLO 378 # define SSL_F_TLS_POST_PROCESS_CLIENT_KEY_EXCHANGE 384 # define SSL_F_TLS_PREPARE_CLIENT_CERTIFICATE 360 diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 5c2e961096..eb5675b9eb 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -279,6 +279,7 @@ static ERR_STRING_DATA SSL_str_functs[] = { "tls_construct_server_key_exchange"}, {ERR_FUNC(SSL_F_TLS_GET_MESSAGE_BODY), "tls_get_message_body"}, {ERR_FUNC(SSL_F_TLS_GET_MESSAGE_HEADER), "tls_get_message_header"}, + {ERR_FUNC(SSL_F_TLS_PARSE_RAW_EXTENSIONS), "tls_parse_raw_extensions"}, {ERR_FUNC(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO), "tls_post_process_client_hello"}, {ERR_FUNC(SSL_F_TLS_POST_PROCESS_CLIENT_KEY_EXCHANGE), diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 0c6bd31993..8f7f930deb 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1624,6 +1624,29 @@ typedef struct ssl3_comp_st { } SSL3_COMP; # endif +typedef struct { + unsigned int type; + PACKET data; +} RAW_EXTENSION; + +#define MAX_COMPRESSIONS_SIZE 255 + +typedef struct { + unsigned int isv2; + unsigned int version; + unsigned char random[SSL3_RANDOM_SIZE]; + size_t session_id_len; + unsigned char session_id[SSL_MAX_SSL_SESSION_ID_LENGTH]; + size_t dtls_cookie_len; + unsigned char dtls_cookie[DTLS1_COOKIE_LENGTH]; + PACKET ciphersuites; + size_t compressions_len; + unsigned char compressions[MAX_COMPRESSIONS_SIZE]; + PACKET extensions; + size_t num_extensions; + RAW_EXTENSION *pre_proc_exts; +} CLIENTHELLO_MSG; + extern SSL3_ENC_METHOD ssl3_undef_enc_method; __owur const SSL_METHOD *ssl_bad_method(int ver); @@ -1797,8 +1820,7 @@ __owur CERT *ssl_cert_dup(CERT *cert); void ssl_cert_clear_certs(CERT *c); void ssl_cert_free(CERT *c); __owur int ssl_get_new_session(SSL *s, int session); -__owur int ssl_get_prev_session(SSL *s, const PACKET *ext, - const PACKET *session_id); +__owur int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello); __owur SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket); __owur int ssl_cipher_id_cmp(const SSL_CIPHER *a, const SSL_CIPHER *b); DECLARE_OBJ_BSEARCH_GLOBAL_CMP_FN(SSL_CIPHER, SSL_CIPHER, ssl_cipher_id); @@ -1919,7 +1941,7 @@ __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); +__owur int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello); __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); @@ -2020,7 +2042,7 @@ __owur int tls1_shared_list(SSL *s, const unsigned char *l2, size_t l2len, int nmatch); __owur int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al); __owur int ssl_add_serverhello_tlsext(SSL *s, WPACKET *pkt, int *al); -__owur int ssl_parse_clienthello_tlsext(SSL *s, PACKET *pkt); +__owur int ssl_parse_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello); void ssl_set_default_md(SSL *s); __owur int tls1_set_server_sigalgs(SSL *s); __owur int ssl_check_clienthello_tlsext_late(SSL *s, int *al); @@ -2034,9 +2056,9 @@ __owur int dtls1_process_heartbeat(SSL *s, unsigned char *p, size_t length); # endif -__owur int tls_check_serverhello_tlsext_early(SSL *s, const PACKET *ext, - const PACKET *session_id, - SSL_SESSION **ret); +__owur int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello, + SSL_SESSION **ret); +__owur int tls_check_client_ems_support(SSL *s, CLIENTHELLO_MSG *hello); __owur int tls12_get_sigandhash(WPACKET *pkt, const EVP_PKEY *pk, const EVP_MD *md); diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index 44101cbb0c..a8bfeb7761 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -445,7 +445,7 @@ int ssl_get_new_session(SSL *s, int session) * - Both for new and resumed sessions, s->tlsext_ticket_expected is set to 1 * if the server should issue a new session ticket (to 0 otherwise). */ -int ssl_get_prev_session(SSL *s, const PACKET *ext, const PACKET *session_id) +int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello) { /* This is used only by servers. */ @@ -454,11 +454,11 @@ int ssl_get_prev_session(SSL *s, const PACKET *ext, const PACKET *session_id) int try_session_cache = 1; int r; - if (PACKET_remaining(session_id) == 0) + if (hello->session_id_len == 0) try_session_cache = 0; - /* sets s->tlsext_ticket_expected and extended master secret flag */ - r = tls_check_serverhello_tlsext_early(s, ext, session_id, &ret); + /* sets s->tlsext_ticket_expected */ + r = tls_get_ticket_from_client(s, hello, &ret); switch (r) { case -1: /* Error during processing */ fatal = 1; @@ -479,14 +479,12 @@ int ssl_get_prev_session(SSL *s, const PACKET *ext, const PACKET *session_id) !(s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) { SSL_SESSION data; - size_t local_len; + data.ssl_version = s->version; memset(data.session_id, 0, sizeof(data.session_id)); - if (!PACKET_copy_all(session_id, data.session_id, - sizeof(data.session_id), &local_len)) { - goto err; - } - data.session_id_length = local_len; + memcpy(data.session_id, hello->session_id, hello->session_id_len); + data.session_id_length = hello->session_id_len; + CRYPTO_THREAD_read_lock(s->session_ctx->lock); ret = lh_SSL_SESSION_retrieve(s->session_ctx->sessions, &data); if (ret != NULL) { @@ -501,8 +499,9 @@ int ssl_get_prev_session(SSL *s, const PACKET *ext, const PACKET *session_id) if (try_session_cache && ret == NULL && s->session_ctx->get_session_cb != NULL) { int copy = 1; - ret = s->session_ctx->get_session_cb(s, PACKET_data(session_id), - (int)PACKET_remaining(session_id), + + ret = s->session_ctx->get_session_cb(s, hello->session_id, + hello->session_id_len, ©); if (ret != NULL) { diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index 24159da3e7..3d2e3f319a 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -152,6 +152,94 @@ static void ssl3_take_mac(SSL *s) } #endif +static int compare_extensions(const void *p1, const void *p2) +{ + const RAW_EXTENSION *e1 = (const RAW_EXTENSION *)p1; + const RAW_EXTENSION *e2 = (const RAW_EXTENSION *)p2; + if (e1->type < e2->type) + return -1; + else if (e1->type > e2->type) + return 1; + else + return 0; +} + +/* + * Gather a list of all the extensions. We don't actually process the content + * of the extensions yet, except to check their types. + * + * Per http://tools.ietf.org/html/rfc5246#section-7.4.1.4, there may not be + * more than one extension of the same type in a ClientHello or ServerHello. + * This function returns 1 if all extensions are unique and we have parsed their + * types, and 0 if the extensions contain duplicates, could not be successfully + * parsed, or an internal error occurred. + */ +int tls_parse_raw_extensions(PACKET *packet, RAW_EXTENSION **res, + size_t *numfound, int *ad) +{ + PACKET extensions = *packet; + size_t num_extensions = 0, i = 0; + RAW_EXTENSION *raw_extensions = NULL; + + /* First pass: count the extensions. */ + while (PACKET_remaining(&extensions) > 0) { + unsigned int type; + PACKET extension; + if (!PACKET_get_net_2(&extensions, &type) || + !PACKET_get_length_prefixed_2(&extensions, &extension)) { + *ad = SSL_AD_DECODE_ERROR; + goto done; + } + num_extensions++; + } + + if (num_extensions > 0) { + raw_extensions = OPENSSL_malloc(sizeof(RAW_EXTENSION) * num_extensions); + if (raw_extensions == NULL) { + *ad = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PARSE_RAW_EXTENSIONS, ERR_R_MALLOC_FAILURE); + goto done; + } + + /* Second pass: gather the extension types. */ + for (i = 0; i < num_extensions; i++) { + if (!PACKET_get_net_2(packet, &raw_extensions[i].type) || + !PACKET_get_length_prefixed_2(packet, + &raw_extensions[i].data)) { + /* This should not happen. */ + *ad = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PARSE_RAW_EXTENSIONS, ERR_R_INTERNAL_ERROR); + goto done; + } + } + + if (PACKET_remaining(packet) != 0) { + *ad = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PARSE_RAW_EXTENSIONS, SSL_R_LENGTH_MISMATCH); + goto done; + } + /* Sort the extensions and make sure there are no duplicates. */ + qsort(raw_extensions, num_extensions, sizeof(RAW_EXTENSION), + compare_extensions); + for (i = 1; i < num_extensions; i++) { + if (raw_extensions[i - 1].type == raw_extensions[i].type) { + *ad = SSL_AD_DECODE_ERROR; + goto done; + } + } + } + + *res = raw_extensions; + *numfound = num_extensions; + return 1; + + done: + OPENSSL_free(raw_extensions); + return 0; +} + + + MSG_PROCESS_RETURN tls_process_change_cipher_spec(SSL *s, PACKET *pkt) { int al; @@ -875,7 +963,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) +int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello) { /*- * With version-flexible methods we have an initial state with: @@ -887,11 +975,13 @@ int ssl_choose_server_version(SSL *s) * handle version. */ int server_version = s->method->version; - int client_version = s->client_version; + int client_version = hello->version; const version_info *vent; const version_info *table; int disabled = 0; + s->client_version = client_version; + switch (server_version) { default: if (version_cmp(s, client_version, s->version) < 0) diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h index a360fc9427..9c1def78cd 100644 --- a/ssl/statem/statem_locl.h +++ b/ssl/statem/statem_locl.h @@ -86,6 +86,9 @@ __owur int tls_construct_finished(SSL *s, WPACKET *pkt); __owur WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst); __owur WORK_STATE dtls_wait_for_dry(SSL *s); +int tls_parse_raw_extensions(PACKET *packet, RAW_EXTENSION **res, + size_t *numfound, int *ad); + /* some client-only functions */ __owur int tls_construct_client_hello(SSL *s, WPACKET *pkt); __owur MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt); diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 6aa897bfd5..9911e3ccde 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -889,7 +889,7 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) { int i, al = SSL_AD_INTERNAL_ERROR; unsigned int j; - size_t loop, complen = 0; + size_t loop; unsigned long id; const SSL_CIPHER *c; #ifndef OPENSSL_NO_COMP @@ -898,16 +898,20 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) STACK_OF(SSL_CIPHER) *ciphers = NULL; int protverr; /* |cookie| will only be initialized for DTLS. */ - PACKET session_id, cipher_suites, compression, extensions, cookie; - int is_v2_record; + PACKET session_id, compression, extensions, cookie; static const unsigned char null_compression = 0; + CLIENTHELLO_MSG clienthello; - is_v2_record = RECORD_LAYER_is_sslv2_record(&s->rlayer); + /* + * First step is to parse the raw ClientHello data into the CLIENTHELLO_MSG + * structure. + */ + + clienthello.isv2 = RECORD_LAYER_is_sslv2_record(&s->rlayer); PACKET_null_init(&cookie); - /* First lets get s->client_version set correctly */ - if (is_v2_record) { - unsigned int version; + + if (clienthello.isv2) { unsigned int mt; /*- * An SSLv3/TLSv1 backwards-compatible CLIENT-HELLO in an SSLv2 @@ -934,73 +938,25 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, ERR_R_INTERNAL_ERROR); goto err; } - - if (!PACKET_get_net_2(pkt, &version)) { - /* No protocol version supplied! */ - SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); - goto err; - } - if (version == 0x0002) { - /* This is real SSLv2. We don't support it. */ - SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); - goto err; - } else if ((version & 0xff00) == (SSL3_VERSION_MAJOR << 8)) { - /* SSLv3/TLS */ - s->client_version = version; - } else { - /* No idea what protocol this is */ - SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); - goto err; - } - } else { - /* - * use version from inside client hello, not from record header (may - * differ: see RFC 2246, Appendix E, second paragraph) - */ - if (!PACKET_get_net_2(pkt, (unsigned int *)&s->client_version)) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT); - goto f_err; - } } - /* - * Do SSL/TLS version negotiation if applicable. For DTLS we just check - * versions are potentially compatible. Version negotiation comes later. - */ - if (!SSL_IS_DTLS(s)) { - protverr = ssl_choose_server_version(s); - } else if (s->method->version != DTLS_ANY_VERSION && - DTLS_VERSION_LT(s->client_version, s->version)) { - protverr = SSL_R_VERSION_TOO_LOW; - } else { - protverr = 0; - } - - if (protverr) { - SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, protverr); - if ((!s->enc_write_ctx && !s->write_hash)) { - /* - * similar to ssl3_get_record, send alert using remote version - * number - */ - s->version = s->client_version; - } - al = SSL_AD_PROTOCOL_VERSION; - goto f_err; + if (!PACKET_get_net_2(pkt, &clienthello.version)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_TOO_SHORT); + goto err; } /* Parse the message and load client random. */ - if (is_v2_record) { + if (clienthello.isv2) { /* * Handle an SSLv2 backwards compatible ClientHello * Note, this is only for SSLv3+ using the backward compatible format. * Real SSLv2 is not supported, and is rejected above. */ - unsigned int cipher_len, session_id_len, challenge_len; + unsigned int ciphersuite_len, session_id_len, challenge_len; PACKET challenge; - if (!PACKET_get_net_2(pkt, &cipher_len) + if (!PACKET_get_net_2(pkt, &ciphersuite_len) || !PACKET_get_net_2(pkt, &session_id_len) || !PACKET_get_net_2(pkt, &challenge_len)) { SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, @@ -1008,6 +964,7 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) al = SSL_AD_DECODE_ERROR; goto f_err; } + clienthello.session_id_len = session_id_len; if (session_id_len > SSL_MAX_SSL_SESSION_ID_LENGTH) { al = SSL_AD_DECODE_ERROR; @@ -1015,8 +972,10 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) goto f_err; } - if (!PACKET_get_sub_packet(pkt, &cipher_suites, cipher_len) - || !PACKET_get_sub_packet(pkt, &session_id, session_id_len) + if (!PACKET_get_sub_packet(pkt, &clienthello.ciphersuites, + ciphersuite_len) + || !PACKET_get_sub_packet(pkt, &session_id, + clienthello.session_id_len) || !PACKET_get_sub_packet(pkt, &challenge, challenge_len) /* No extensions. */ || PACKET_remaining(pkt) != 0) { @@ -1029,9 +988,9 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) /* Load the client random and compression list. */ challenge_len = challenge_len > SSL3_RANDOM_SIZE ? SSL3_RANDOM_SIZE : challenge_len; - memset(s->s3->client_random, 0, SSL3_RANDOM_SIZE); + memset(clienthello.random, 0, SSL3_RANDOM_SIZE); if (!PACKET_copy_bytes(&challenge, - s->s3->client_random + SSL3_RANDOM_SIZE - + clienthello.random + SSL3_RANDOM_SIZE - challenge_len, challenge_len) /* Advertise only null compression. */ || !PACKET_buf_init(&compression, &null_compression, 1)) { @@ -1040,55 +999,136 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) goto f_err; } - PACKET_null_init(&extensions); + PACKET_null_init(&clienthello.extensions); } else { /* Regular ClientHello. */ - if (!PACKET_copy_bytes(pkt, s->s3->client_random, SSL3_RANDOM_SIZE) + if (!PACKET_copy_bytes(pkt, clienthello.random, SSL3_RANDOM_SIZE) || !PACKET_get_length_prefixed_1(pkt, &session_id)) { al = SSL_AD_DECODE_ERROR; SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH); goto f_err; } - if (PACKET_remaining(&session_id) > SSL_MAX_SSL_SESSION_ID_LENGTH) { - al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH); - goto f_err; - } - if (SSL_IS_DTLS(s)) { if (!PACKET_get_length_prefixed_1(pkt, &cookie)) { al = SSL_AD_DECODE_ERROR; SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH); goto f_err; } + if (!PACKET_copy_all(&cookie, clienthello.dtls_cookie, + DTLS1_COOKIE_LENGTH, + &clienthello.dtls_cookie_len)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH); + goto f_err; + } /* * If we require cookies and this ClientHello doesn't contain one, * just return since we do not want to allocate any memory yet. * So check cookie length... */ if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) { - if (PACKET_remaining(&cookie) == 0) + if (clienthello.dtls_cookie_len == 0) return 1; } } - if (!PACKET_get_length_prefixed_2(pkt, &cipher_suites) - || !PACKET_get_length_prefixed_1(pkt, &compression)) { + if (!PACKET_get_length_prefixed_2(pkt, &clienthello.ciphersuites)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + if (!PACKET_get_length_prefixed_1(pkt, &compression) + || !PACKET_copy_all(&compression, clienthello.compressions, + MAX_COMPRESSIONS_SIZE, + &clienthello.compressions_len)) { al = SSL_AD_DECODE_ERROR; SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH); goto f_err; } + /* Could be empty. */ - extensions = *pkt; + if (PACKET_remaining(pkt) == 0) { + PACKET_null_init(&clienthello.extensions); + } else { + if (!PACKET_get_length_prefixed_2(pkt, &clienthello.extensions)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + } + } + + if (!PACKET_copy_all(&session_id, clienthello.session_id, + SSL_MAX_SSL_SESSION_ID_LENGTH, + &clienthello.session_id_len)) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_LENGTH_MISMATCH); + goto f_err; + } + + /* We preserve the raw extensions PACKET for later use */ + extensions = clienthello.extensions; + if (!tls_parse_raw_extensions(&extensions, &clienthello.pre_proc_exts, + &clienthello.num_extensions, &al)) { + /* SSLerr already been called */ + goto f_err; + } + + /* Finished parsing the ClientHello, now we can start processing it */ + + /* Set up the client_random */ + memcpy(s->s3->client_random, clienthello.random, SSL3_RANDOM_SIZE); + + /* Choose the version */ + + if (clienthello.isv2) { + if (clienthello.version == 0x0002) { + /* This is real SSLv2. We don't support it. */ + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); + goto err; + } else if ((clienthello.version & 0xff00) == (SSL3_VERSION_MAJOR << 8)) { + /* SSLv3/TLS */ + s->client_version = clienthello.version; + } else { + /* No idea what protocol this is */ + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_UNKNOWN_PROTOCOL); + goto err; + } + } + /* + * Do SSL/TLS version negotiation if applicable. For DTLS we just check + * versions are potentially compatible. Version negotiation comes later. + */ + if (!SSL_IS_DTLS(s)) { + protverr = ssl_choose_server_version(s, &clienthello); + } else if (s->method->version != DTLS_ANY_VERSION && + DTLS_VERSION_LT((int)clienthello.version, s->version)) { + protverr = SSL_R_VERSION_TOO_LOW; + } else { + protverr = 0; + } + + if (protverr) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, protverr); + if ((!s->enc_write_ctx && !s->write_hash)) { + /* + * similar to ssl3_get_record, send alert using remote version + * number + */ + s->version = s->client_version = clienthello.version; + } + al = SSL_AD_PROTOCOL_VERSION; + goto f_err; } if (SSL_IS_DTLS(s)) { /* Empty cookie was already handled above by returning early. */ if (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE) { if (s->ctx->app_verify_cookie_cb != NULL) { - if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&cookie), - (unsigned int)PACKET_remaining(&cookie)) == 0) { + if (s->ctx->app_verify_cookie_cb(s, clienthello.dtls_cookie, + clienthello.dtls_cookie_len) == 0) { al = SSL_AD_HANDSHAKE_FAILURE; SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH); @@ -1096,7 +1136,9 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) /* else cookie verification succeeded */ } /* default verification */ - } else if (!PACKET_equal(&cookie, s->d1->cookie, s->d1->cookie_len)) { + } else if (s->d1->cookie_len != clienthello.dtls_cookie_len + || memcmp(clienthello.dtls_cookie, s->d1->cookie, + s->d1->cookie_len) != 0) { al = SSL_AD_HANDSHAKE_FAILURE; SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_COOKIE_MISMATCH); goto f_err; @@ -1104,7 +1146,7 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) s->d1->cookie_verified = 1; } if (s->method->version == DTLS_ANY_VERSION) { - protverr = ssl_choose_server_version(s); + protverr = ssl_choose_server_version(s, &clienthello); if (protverr != 0) { SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, protverr); s->version = s->client_version; @@ -1116,6 +1158,15 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) s->hit = 0; + /* We need to do this before getting the session */ + if (!tls_check_client_ems_support(s, &clienthello)) + { + /* Only fails if the extension is malformed */ + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT); + goto f_err; + } + /* * We don't allow resumption in a backwards compatible ClientHello. * TODO(openssl-team): in TLS1.1+, session_id MUST be empty. @@ -1132,13 +1183,13 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION setting will be * ignored. */ - if (is_v2_record || + if (clienthello.isv2 || (s->new_session && (s->options & SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION))) { if (!ssl_get_new_session(s, 1)) goto err; } else { - i = ssl_get_prev_session(s, &extensions, &session_id); + i = ssl_get_prev_session(s, &clienthello); /* * Only resume if the session's version matches the negotiated * version. @@ -1160,8 +1211,8 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) } } - if (ssl_bytes_to_cipher_list(s, &cipher_suites, &(ciphers), - is_v2_record, &al) == NULL) { + if (ssl_bytes_to_cipher_list(s, &clienthello.ciphersuites, &(ciphers), + clienthello.isv2, &al) == NULL) { goto f_err; } @@ -1196,13 +1247,12 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) } } - complen = PACKET_remaining(&compression); - for (loop = 0; loop < complen; loop++) { - if (PACKET_data(&compression)[loop] == 0) + for (loop = 0; loop < clienthello.compressions_len; loop++) { + if (clienthello.compressions[loop] == 0) break; } - if (loop >= complen) { + if (loop >= clienthello.compressions_len) { /* no compress */ al = SSL_AD_DECODE_ERROR; SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_NO_COMPRESSION_SPECIFIED); @@ -1210,11 +1260,9 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) } /* TLS extensions */ - if (s->version >= SSL3_VERSION) { - if (!ssl_parse_clienthello_tlsext(s, &extensions)) { - SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_PARSE_TLSEXT); - goto err; - } + if (!ssl_parse_clienthello_tlsext(s, &clienthello)) { + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_PARSE_TLSEXT); + goto err; } /* @@ -1305,11 +1353,11 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) goto f_err; } /* Look for resumed method in compression list */ - for (k = 0; k < complen; k++) { - if (PACKET_data(&compression)[k] == comp_id) + for (k = 0; k < clienthello.compressions_len; k++) { + if (clienthello.compressions[k] == comp_id) break; } - if (k >= complen) { + if (k >= clienthello.compressions_len) { al = SSL_AD_ILLEGAL_PARAMETER; SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING); @@ -1326,8 +1374,8 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) for (m = 0; m < nn; m++) { comp = sk_SSL_COMP_value(s->ctx->comp_methods, m); v = comp->id; - for (o = 0; o < complen; o++) { - if (v == PACKET_data(&compression)[o]) { + for (o = 0; o < clienthello.compressions_len; o++) { + if (v == clienthello.compressions[o]) { done = 1; break; } diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 0523e54718..e8357afe0d 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -1701,7 +1701,7 @@ static int tls1_alpn_handle_client_hello_late(SSL *s, int *al) * Sadly we cannot differentiate 10.6, 10.7 and 10.8.4 (which work), from * 10.8..10.8.3 (which don't work). */ -static void ssl_check_for_safari(SSL *s, const PACKET *pkt) +static void ssl_check_for_safari(SSL *s, CLIENTHELLO_MSG *hello) { unsigned int type; PACKET sni, tmppkt; @@ -1733,7 +1733,7 @@ static void ssl_check_for_safari(SSL *s, const PACKET *pkt) /* Length of the common prefix (first two extensions). */ static const size_t kSafariCommonExtensionsLength = 18; - tmppkt = *pkt; + tmppkt = hello->extensions; if (!PACKET_forward(&tmppkt, 2) || !PACKET_get_net_2(&tmppkt, &type) @@ -1763,11 +1763,10 @@ static void ssl_check_for_safari(SSL *s, const PACKET *pkt) * Consumes the entire packet in |pkt|. Returns 1 on success and 0 on failure. * Upon failure, sets |al| to the appropriate alert. */ -static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al) +static int ssl_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al) { - unsigned int type; + size_t loop; int renegotiate_seen = 0; - PACKET extensions; *al = SSL_AD_DECODE_ERROR; s->servername_done = 0; @@ -1789,7 +1788,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al) #ifndef OPENSSL_NO_EC if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG) - ssl_check_for_safari(s, pkt); + ssl_check_for_safari(s, hello); #endif /* !OPENSSL_NO_EC */ /* Clear any signature algorithms extension received */ @@ -1804,32 +1803,21 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al) s->srtp_profile = NULL; - if (PACKET_remaining(pkt) == 0) - goto ri_check; - - if (!PACKET_as_length_prefixed_2(pkt, &extensions)) - return 0; - - if (!tls1_check_duplicate_extensions(&extensions)) - return 0; - /* * We parse all extensions to ensure the ClientHello is well-formed but, * unless an extension specifies otherwise, we ignore extensions upon * resumption. */ - while (PACKET_get_net_2(&extensions, &type)) { - PACKET extension; - if (!PACKET_get_length_prefixed_2(&extensions, &extension)) - return 0; - + for (loop = 0; loop < hello->num_extensions; loop++) { if (s->tlsext_debug_cb) - s->tlsext_debug_cb(s, 0, type, PACKET_data(&extension), - (int)PACKET_remaining(&extension), + s->tlsext_debug_cb(s, 0, hello->pre_proc_exts[loop].type, + PACKET_data(&hello->pre_proc_exts[loop].data), + PACKET_remaining(&hello->pre_proc_exts[loop].data), s->tlsext_debug_arg); - if (type == TLSEXT_TYPE_renegotiate) { - if (!ssl_parse_clienthello_renegotiate_ext(s, &extension, al)) + if (hello->pre_proc_exts[loop].type == TLSEXT_TYPE_renegotiate) { + if (!ssl_parse_clienthello_renegotiate_ext(s, + &hello->pre_proc_exts[loop].data, al)) return 0; renegotiate_seen = 1; } else if (s->version == SSL3_VERSION) { @@ -1859,11 +1847,12 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al) * */ - else if (type == TLSEXT_TYPE_server_name) { + else if (hello->pre_proc_exts[loop].type == TLSEXT_TYPE_server_name) { unsigned int servname_type; PACKET sni, hostname; - if (!PACKET_as_length_prefixed_2(&extension, &sni) + if (!PACKET_as_length_prefixed_2(&hello->pre_proc_exts[loop].data, + &sni) /* ServerNameList must be at least 1 byte long. */ || PACKET_remaining(&sni) == 0) { return 0; @@ -1915,10 +1904,11 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al) } } #ifndef OPENSSL_NO_SRP - else if (type == TLSEXT_TYPE_srp) { + else if (hello->pre_proc_exts[loop].type == TLSEXT_TYPE_srp) { PACKET srp_I; - if (!PACKET_as_length_prefixed_1(&extension, &srp_I)) + if (!PACKET_as_length_prefixed_1(&hello->pre_proc_exts[loop].data, + &srp_I)) return 0; if (PACKET_contains_zero_byte(&srp_I)) @@ -1936,10 +1926,12 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al) #endif #ifndef OPENSSL_NO_EC - else if (type == TLSEXT_TYPE_ec_point_formats) { + else if (hello->pre_proc_exts[loop].type + == TLSEXT_TYPE_ec_point_formats) { PACKET ec_point_format_list; - if (!PACKET_as_length_prefixed_1(&extension, &ec_point_format_list) + if (!PACKET_as_length_prefixed_1(&hello->pre_proc_exts[loop].data, + &ec_point_format_list) || PACKET_remaining(&ec_point_format_list) == 0) { return 0; } @@ -1953,11 +1945,13 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al) return 0; } } - } else if (type == TLSEXT_TYPE_elliptic_curves) { + } else if (hello->pre_proc_exts[loop].type + == TLSEXT_TYPE_elliptic_curves) { PACKET elliptic_curve_list; /* Each NamedCurve is 2 bytes and we must have at least 1. */ - if (!PACKET_as_length_prefixed_2(&extension, &elliptic_curve_list) + if (!PACKET_as_length_prefixed_2(&hello->pre_proc_exts[loop].data, + &elliptic_curve_list) || PACKET_remaining(&elliptic_curve_list) == 0 || (PACKET_remaining(&elliptic_curve_list) % 2) != 0) { return 0; @@ -1974,19 +1968,22 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al) } } #endif /* OPENSSL_NO_EC */ - else if (type == TLSEXT_TYPE_session_ticket) { + else if (hello->pre_proc_exts[loop].type + == TLSEXT_TYPE_session_ticket) { if (s->tls_session_ticket_ext_cb && - !s->tls_session_ticket_ext_cb(s, PACKET_data(&extension), - (int)PACKET_remaining(&extension), - s->tls_session_ticket_ext_cb_arg)) - { + !s->tls_session_ticket_ext_cb(s, + PACKET_data(&hello->pre_proc_exts[loop].data), + PACKET_remaining(&hello->pre_proc_exts[loop].data), + s->tls_session_ticket_ext_cb_arg)) { *al = TLS1_AD_INTERNAL_ERROR; return 0; } - } else if (type == TLSEXT_TYPE_signature_algorithms) { + } else if (hello->pre_proc_exts[loop].type + == TLSEXT_TYPE_signature_algorithms) { PACKET supported_sig_algs; - if (!PACKET_as_length_prefixed_2(&extension, &supported_sig_algs) + if (!PACKET_as_length_prefixed_2(&hello->pre_proc_exts[loop].data, + &supported_sig_algs) || (PACKET_remaining(&supported_sig_algs) % 2) != 0 || PACKET_remaining(&supported_sig_algs) == 0) { return 0; @@ -1998,8 +1995,9 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al) return 0; } } - } else if (type == TLSEXT_TYPE_status_request) { - if (!PACKET_get_1(&extension, + } else if (hello->pre_proc_exts[loop].type + == TLSEXT_TYPE_status_request) { + if (!PACKET_get_1(&hello->pre_proc_exts[loop].data, (unsigned int *)&s->tlsext_status_type)) { return 0; } @@ -2008,7 +2006,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al) const unsigned char *ext_data; PACKET responder_id_list, exts; if (!PACKET_get_length_prefixed_2 - (&extension, &responder_id_list)) + (&hello->pre_proc_exts[loop].data, &responder_id_list)) return 0; /* @@ -2058,7 +2056,8 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al) } /* Read in request_extensions */ - if (!PACKET_as_length_prefixed_2(&extension, &exts)) + if (!PACKET_as_length_prefixed_2( + &hello->pre_proc_exts[loop].data, &exts)) return 0; if (PACKET_remaining(&exts) > 0) { @@ -2083,11 +2082,12 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al) } } #ifndef OPENSSL_NO_HEARTBEATS - else if (SSL_IS_DTLS(s) && type == TLSEXT_TYPE_heartbeat) { + else if (SSL_IS_DTLS(s) + && hello->pre_proc_exts[loop].type == TLSEXT_TYPE_heartbeat) { unsigned int hbtype; - if (!PACKET_get_1(&extension, &hbtype) - || PACKET_remaining(&extension)) { + if (!PACKET_get_1(&hello->pre_proc_exts[loop].data, &hbtype) + || PACKET_remaining(&hello->pre_proc_exts[loop].data)) { *al = SSL_AD_DECODE_ERROR; return 0; } @@ -2106,8 +2106,8 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al) } #endif #ifndef OPENSSL_NO_NEXTPROTONEG - else if (type == TLSEXT_TYPE_next_proto_neg && - s->s3->tmp.finish_md_len == 0) { + else if (hello->pre_proc_exts[loop].type == TLSEXT_TYPE_next_proto_neg + && s->s3->tmp.finish_md_len == 0) { /*- * We shouldn't accept this extension on a * renegotiation. @@ -2129,26 +2129,29 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al) } #endif - else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation && - s->s3->tmp.finish_md_len == 0) { - if (!tls1_alpn_handle_client_hello(s, &extension, al)) + else if (hello->pre_proc_exts[loop].type + == TLSEXT_TYPE_application_layer_protocol_negotiation + && s->s3->tmp.finish_md_len == 0) { + if (!tls1_alpn_handle_client_hello(s, + &hello->pre_proc_exts[loop].data, al)) return 0; } /* session ticket processed earlier */ #ifndef OPENSSL_NO_SRTP else if (SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s) - && type == TLSEXT_TYPE_use_srtp) { - if (ssl_parse_clienthello_use_srtp_ext(s, &extension, al)) + && hello->pre_proc_exts[loop].type == TLSEXT_TYPE_use_srtp) { + if (ssl_parse_clienthello_use_srtp_ext(s, + &hello->pre_proc_exts[loop].data, al)) return 0; } #endif - else if (type == TLSEXT_TYPE_encrypt_then_mac && - !(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)) + else if (hello->pre_proc_exts[loop].type == TLSEXT_TYPE_encrypt_then_mac + && !(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)) s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC; /* * Note: extended master secret extension handled in - * tls_check_serverhello_tlsext_early() + * tls_check_client_ems_support() */ /* @@ -2159,22 +2162,13 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al) * ServerHello may be later returned. */ else if (!s->hit) { - if (custom_ext_parse(s, 1, type, PACKET_data(&extension), - PACKET_remaining(&extension), al) <= 0) + if (custom_ext_parse(s, 1, hello->pre_proc_exts[loop].type, + PACKET_data(&hello->pre_proc_exts[loop].data), + PACKET_remaining(&hello->pre_proc_exts[loop].data), al) <= 0) return 0; } } - if (PACKET_remaining(pkt) != 0) { - /* - * tls1_check_duplicate_extensions should ensure this never happens. - */ - *al = SSL_AD_INTERNAL_ERROR; - return 0; - } - - ri_check: - /* Need RI if renegotiating */ if (!renegotiate_seen && s->renegotiate && @@ -2194,11 +2188,11 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al) return 1; } -int ssl_parse_clienthello_tlsext(SSL *s, PACKET *pkt) +int ssl_parse_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello) { int al = -1; custom_ext_init(&s->cert->srv_ext); - if (ssl_scan_clienthello_tlsext(s, pkt, &al) <= 0) { + if (ssl_scan_clienthello_tlsext(s, hello, &al) <= 0) { ssl3_send_alert(s, SSL3_AL_FATAL, al); return 0; } @@ -2793,16 +2787,23 @@ int ssl_parse_serverhello_tlsext(SSL *s, PACKET *pkt) return 1; } +static RAW_EXTENSION *get_extension_by_type(RAW_EXTENSION *exts, size_t numexts, + unsigned int type) +{ + size_t loop; + + for (loop = 0; loop < numexts; loop++) { + if (exts[loop].type == type) + return &exts[loop]; + } + + return NULL; +} + /*- - * Since the server cache lookup is done early on in the processing of the - * ClientHello and other operations depend on the result some extensions - * need to be handled at the same time. + * Gets the ticket information supplied by the client if any. * - * Two extensions are currently handled, session ticket and extended master - * secret. - * - * session_id: ClientHello session ID. - * ext: ClientHello extensions (including length prefix) + * hello: The parsed ClientHello data * ret: (output) on return, if a ticket was decrypted, then this is set to * point to the resulting session. * @@ -2826,116 +2827,102 @@ int ssl_parse_serverhello_tlsext(SSL *s, PACKET *pkt) * a session ticket or we couldn't use the one it gave us, or if * s->ctx->tlsext_ticket_key_cb asked to renew the client's ticket. * Otherwise, s->tlsext_ticket_expected is set to 0. - * - * For extended master secret flag is set if the extension is present. - * */ -int tls_check_serverhello_tlsext_early(SSL *s, const PACKET *ext, - const PACKET *session_id, - SSL_SESSION **ret) +int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello, + SSL_SESSION **ret) { - unsigned int i; - PACKET local_ext = *ext; - int retv = -1; - - int have_ticket = 0; - int use_ticket = tls_use_ticket(s); + int retv; + const unsigned char *etick; + size_t size; + RAW_EXTENSION *ticketext; *ret = NULL; s->tlsext_ticket_expected = 0; - s->s3->flags &= ~TLS1_FLAGS_RECEIVED_EXTMS; /* * If tickets disabled behave as if no ticket present to permit stateful * resumption. */ - if ((s->version <= SSL3_VERSION)) + if (s->version <= SSL3_VERSION || !tls_use_ticket(s)) return 0; - if (!PACKET_get_net_2(&local_ext, &i)) { - retv = 0; - goto end; + ticketext = get_extension_by_type(hello->pre_proc_exts, + hello->num_extensions, + TLSEXT_TYPE_session_ticket); + if (ticketext == NULL) + return 0; + + size = PACKET_remaining(&ticketext->data); + if (size == 0) { + /* + * The client will accept a ticket but doesn't currently have + * one. + */ + s->tlsext_ticket_expected = 1; + return 1; } - while (PACKET_remaining(&local_ext) >= 4) { - unsigned int type, size; + if (s->tls_session_secret_cb) { + /* + * Indicate that the ticket couldn't be decrypted rather than + * generating the session from ticket now, trigger + * abbreviated handshake based on external mechanism to + * calculate the master secret later. + */ + return 2; + } + if (!PACKET_get_bytes(&ticketext->data, &etick, size)) { + /* Shouldn't ever happen */ + return -1; + } + retv = tls_decrypt_ticket(s, etick, size, hello->session_id, + hello->session_id_len, ret); + switch (retv) { + case 2: /* ticket couldn't be decrypted */ + s->tlsext_ticket_expected = 1; + return 2; - if (!PACKET_get_net_2(&local_ext, &type) - || !PACKET_get_net_2(&local_ext, &size)) { - /* Shouldn't ever happen */ - retv = -1; - goto end; - } - if (PACKET_remaining(&local_ext) < size) { - retv = 0; - goto end; - } - if (type == TLSEXT_TYPE_session_ticket && use_ticket) { - int r; - const unsigned char *etick; + case 3: /* ticket was decrypted */ + return 3; - /* Duplicate extension */ - if (have_ticket != 0) { - retv = -1; - goto end; - } - have_ticket = 1; + case 4: /* ticket decrypted but need to renew */ + s->tlsext_ticket_expected = 1; + return 3; - if (size == 0) { - /* - * The client will accept a ticket but doesn't currently have - * one. - */ - s->tlsext_ticket_expected = 1; - retv = 1; - continue; - } - if (s->tls_session_secret_cb) { - /* - * Indicate that the ticket couldn't be decrypted rather than - * generating the session from ticket now, trigger - * abbreviated handshake based on external mechanism to - * calculate the master secret later. - */ - retv = 2; - continue; - } - if (!PACKET_get_bytes(&local_ext, &etick, size)) { - /* Shouldn't ever happen */ - retv = -1; - goto end; - } - r = tls_decrypt_ticket(s, etick, size, PACKET_data(session_id), - PACKET_remaining(session_id), ret); - switch (r) { - case 2: /* ticket couldn't be decrypted */ - s->tlsext_ticket_expected = 1; - retv = 2; - break; - case 3: /* ticket was decrypted */ - retv = r; - break; - case 4: /* ticket decrypted but need to renew */ - s->tlsext_ticket_expected = 1; - retv = 3; - break; - default: /* fatal error */ - retv = -1; - break; - } - continue; - } else { - if (type == TLSEXT_TYPE_extended_master_secret) - s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS; - if (!PACKET_forward(&local_ext, size)) { - retv = -1; - goto end; - } - } + default: /* fatal error */ + return -1; } - if (have_ticket == 0) - retv = 0; - end: - return retv; +} + +/* + * Sets the extended master secret flag is set if the extension is present + * in the ClientHello + */ +int tls_check_client_ems_support(SSL *s, CLIENTHELLO_MSG *hello) +{ + RAW_EXTENSION *emsext; + + s->s3->flags &= ~TLS1_FLAGS_RECEIVED_EXTMS; + + if (s->version <= SSL3_VERSION) + return 1; + + emsext = get_extension_by_type(hello->pre_proc_exts, hello->num_extensions, + TLSEXT_TYPE_extended_master_secret); + + /* + * No extensions is a success - we have successfully discovered that the + * client doesn't support EMS. + */ + if (emsext == NULL) + return 1; + + /* The extensions must always be empty */ + if (PACKET_remaining(&emsext->data) != 0) + return 0; + + s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS; + + return 1; } /*-