From: Matt Caswell Date: Fri, 25 Nov 2016 12:34:29 +0000 (+0000) Subject: Move client parsing of ServerHello extensions into new framework X-Git-Tag: OpenSSL_1_1_1-pre1~2908 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=6dd083fd6804a3ee6ac3adc019f81910f1c63f21;p=oweals%2Fopenssl.git Move client parsing of ServerHello extensions into new framework Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich Salz Reviewed-by: Rich Salz Reviewed-by: Richard Levitte --- diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 98313af6a8..81826a3431 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -2297,6 +2297,9 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_PARSE_CLIENT_KEY_SHARE 445 # define SSL_F_TLS_PARSE_CLIENT_RENEGOTIATE 448 # define SSL_F_TLS_PARSE_CLIENT_USE_SRTP 446 +# define SSL_F_TLS_PARSE_SERVER_KEY_SHARE 463 +# define SSL_F_TLS_PARSE_SERVER_RENEGOTIATE 464 +# define SSL_F_TLS_PARSE_SERVER_USE_SRTP 465 # 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/build.info b/ssl/build.info index fb2265e145..f13c11f425 100644 --- a/ssl/build.info +++ b/ssl/build.info @@ -3,13 +3,13 @@ SOURCE[../libssl]=\ pqueue.c packet.c \ statem/statem_srvr.c statem/statem_clnt.c s3_lib.c s3_enc.c record/rec_layer_s3.c \ statem/statem_lib.c statem/extensions.c statem/extensions_srvr.c \ - s3_cbc.c s3_msg.c \ + statem/extensions_clnt.c s3_cbc.c s3_msg.c \ methods.c t1_lib.c t1_enc.c tls13_enc.c t1_ext.c \ d1_lib.c record/rec_layer_d1.c d1_msg.c \ statem/statem_dtls.c d1_srtp.c \ ssl_lib.c ssl_cert.c ssl_sess.c \ ssl_ciph.c ssl_stat.c ssl_rsa.c \ ssl_asn1.c ssl_txt.c ssl_init.c ssl_conf.c ssl_mcnf.c \ - bio_ssl.c ssl_err.c t1_reneg.c tls_srp.c t1_trce.c ssl_utst.c \ + bio_ssl.c ssl_err.c tls_srp.c t1_trce.c ssl_utst.c \ record/ssl3_buffer.c record/ssl3_record.c record/dtls1_bitmap.c \ statem/statem.c record/ssl3_record_tls13.c diff --git a/ssl/d1_srtp.c b/ssl/d1_srtp.c index e99fd45409..ff8f0c5712 100644 --- a/ssl/d1_srtp.c +++ b/ssl/d1_srtp.c @@ -136,61 +136,4 @@ SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s) { return s->srtp_profile; } - -int ssl_parse_serverhello_use_srtp_ext(SSL *s, PACKET *pkt, int *al) -{ - unsigned int id, ct, mki; - int i; - - STACK_OF(SRTP_PROTECTION_PROFILE) *clnt; - SRTP_PROTECTION_PROFILE *prof; - - if (!PACKET_get_net_2(pkt, &ct) - || ct != 2 || !PACKET_get_net_2(pkt, &id) - || !PACKET_get_1(pkt, &mki) - || PACKET_remaining(pkt) != 0) { - SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT, - SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - *al = SSL_AD_DECODE_ERROR; - return 1; - } - - if (mki != 0) { - /* Must be no MKI, since we never offer one */ - SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT, - SSL_R_BAD_SRTP_MKI_VALUE); - *al = SSL_AD_ILLEGAL_PARAMETER; - return 1; - } - - clnt = SSL_get_srtp_profiles(s); - - /* Throw an error if the server gave us an unsolicited extension */ - if (clnt == NULL) { - SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT, - SSL_R_NO_SRTP_PROFILES); - *al = SSL_AD_DECODE_ERROR; - return 1; - } - - /* - * Check to see if the server gave us something we support (and - * presumably offered) - */ - for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(clnt); i++) { - prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i); - - if (prof->id == id) { - s->srtp_profile = prof; - *al = 0; - return 0; - } - } - - SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_USE_SRTP_EXT, - SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - *al = SSL_AD_DECODE_ERROR; - return 1; -} - #endif diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 2539d6e740..3523682c3a 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -319,6 +319,11 @@ static ERR_STRING_DATA SSL_str_functs[] = { {ERR_FUNC(SSL_F_TLS_PARSE_CLIENT_RENEGOTIATE), "tls_parse_client_renegotiate"}, {ERR_FUNC(SSL_F_TLS_PARSE_CLIENT_USE_SRTP), "tls_parse_client_use_srtp"}, + {ERR_FUNC(SSL_F_TLS_PARSE_SERVER_KEY_SHARE), + "tls_parse_server_key_share"}, + {ERR_FUNC(SSL_F_TLS_PARSE_SERVER_RENEGOTIATE), + "tls_parse_server_renegotiate"}, + {ERR_FUNC(SSL_F_TLS_PARSE_SERVER_USE_SRTP), "tls_parse_server_use_srtp"}, {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 926c6c6396..178a5d0690 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -2117,7 +2117,6 @@ __owur int ssl_security_cert_chain(SSL *s, STACK_OF(X509) *sk, X509 *ex, __owur EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash, const EVP_MD *md); void ssl_clear_hash_ctx(EVP_MD_CTX **hash); -__owur int ssl_parse_serverhello_renegotiate_ext(SSL *s, PACKET *pkt, int *al); __owur long ssl_get_algorithm2(SSL *s); __owur int tls12_copy_sigalgs(SSL *s, WPACKET *pkt, const unsigned char *psig, size_t psiglen); @@ -2129,8 +2128,6 @@ __owur int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s, void ssl_set_client_disabled(SSL *s); __owur int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c, int op); -__owur int ssl_parse_serverhello_use_srtp_ext(SSL *s, PACKET *pkt, int *al); - __owur int ssl_handshake_hash(SSL *s, unsigned char *out, size_t outlen, size_t *hashlen); __owur const EVP_MD *ssl_md(int idx); diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index 898b9b97d1..8aba3218aa 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -14,10 +14,14 @@ typedef struct { /* The ID for the extension */ unsigned int type; - int (*server_parse)(SSL *s, PACKET *pkt, int *al); - int (*client_parse)(SSL *s, PACKET *pkt, int *al); - int (*server_construct)(SSL *s, WPACKET *pkt, int *al); - int (*client_construct)(SSL *s, WPACKET *pkt, int *al); + /* Parse extension received by server from client */ + int (*parse_client_ext)(SSL *s, PACKET *pkt, int *al); + /* Parse extension received by client from server */ + int (*parse_server_ext)(SSL *s, PACKET *pkt, int *al); + /* Construct extension sent by server */ + int (*construct_server_ext)(SSL *s, WPACKET *pkt, int *al); + /* Construct extension sent by client */ + int (*construct_client_ext)(SSL *s, WPACKET *pkt, int *al); unsigned int context; } EXTENSION_DEFINITION; @@ -30,7 +34,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { { TLSEXT_TYPE_renegotiate, tls_parse_client_renegotiate, - NULL, + tls_parse_server_renegotiate, tls_construct_server_renegotiate, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_SSL3_ALLOWED @@ -39,11 +43,11 @@ static const EXTENSION_DEFINITION ext_defs[] = { { TLSEXT_TYPE_server_name, tls_parse_client_server_name, - NULL, + tls_parse_server_server_name, tls_construct_server_server_name, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO - | /*EXT_TLS1_3_ENCRYPTED_EXTENSIONS*/EXT_TLS1_3_SERVER_HELLO + | EXT_TLS1_3_ENCRYPTED_EXTENSIONS }, #ifndef OPENSSL_NO_SRP { @@ -59,7 +63,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { { TLSEXT_TYPE_ec_point_formats, tls_parse_client_ec_pt_formats, - NULL, + tls_parse_server_ec_pt_formats, tls_construct_server_ec_pt_formats, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_AND_BELOW_ONLY @@ -71,13 +75,13 @@ static const EXTENSION_DEFINITION ext_defs[] = { NULL /* TODO(TLS1.3): Need to add this */, NULL, EXT_CLIENT_HELLO - | /*EXT_TLS1_3_ENCRYPTED_EXTENSIONS*/EXT_TLS1_3_SERVER_HELLO + | EXT_TLS1_3_ENCRYPTED_EXTENSIONS }, #endif { TLSEXT_TYPE_session_ticket, tls_parse_client_session_ticket, - NULL, + tls_parse_server_session_ticket, tls_construct_server_session_ticket, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY @@ -93,17 +97,17 @@ static const EXTENSION_DEFINITION ext_defs[] = { { TLSEXT_TYPE_status_request, tls_parse_client_status_request, - NULL, + tls_parse_server_status_request, tls_construct_server_status_request, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO - | /*EXT_TLS1_3_CERTIFICATE*/EXT_TLS1_3_SERVER_HELLO + | EXT_TLS1_3_CERTIFICATE }, #ifndef OPENSSL_NO_NEXTPROTONEG { TLSEXT_TYPE_next_proto_neg, tls_parse_client_npn, - NULL, + tls_parse_server_npn, tls_construct_server_next_proto_neg, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY @@ -112,17 +116,17 @@ static const EXTENSION_DEFINITION ext_defs[] = { { TLSEXT_TYPE_application_layer_protocol_negotiation, tls_parse_client_alpn, - NULL, + tls_parse_server_alpn, tls_construct_server_alpn, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO - | /*EXT_TLS1_3_ENCRYPTED_EXTENSIONS*/EXT_TLS1_3_SERVER_HELLO + | EXT_TLS1_3_ENCRYPTED_EXTENSIONS }, #ifndef OPENSSL_NO_SRTP { TLSEXT_TYPE_use_srtp, tls_parse_client_use_srtp, - NULL, + tls_parse_server_use_srtp, tls_construct_server_use_srtp, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO @@ -132,11 +136,12 @@ static const EXTENSION_DEFINITION ext_defs[] = { { TLSEXT_TYPE_encrypt_then_mac, tls_parse_client_etm, - NULL, + tls_parse_server_etm, tls_construct_server_etm, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY }, +#ifndef OPENSSL_NO_CT { TLSEXT_TYPE_signed_certificate_timestamp, /* @@ -145,16 +150,17 @@ static const EXTENSION_DEFINITION ext_defs[] = { * cannot override built in ones. */ NULL, - NULL, + tls_parse_server_sct, NULL, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO - | /*EXT_TLS1_3_CERTIFICATE*/EXT_TLS1_3_SERVER_HELLO + | EXT_TLS1_3_CERTIFICATE }, +#endif { TLSEXT_TYPE_extended_master_secret, tls_parse_client_ems, - NULL, + tls_parse_server_ems, tls_construct_server_ems, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY @@ -180,7 +186,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { { TLSEXT_TYPE_key_share, tls_parse_client_key_share, - NULL, + tls_parse_server_key_share, tls_construct_server_key_share, NULL, EXT_CLIENT_HELLO | EXT_TLS1_3_SERVER_HELLO @@ -277,7 +283,7 @@ static int find_extension_definition(SSL *s, unsigned int type, /* * Gather a list of all the extensions from the data in |packet]. |context| - * tells us which message this extension is for. The raw extension data is + * tells us which message this extension is for. Ttls_parse_server_ec_pt_formatshe raw extension data is * stored in |*res| with the number of found extensions in |*numfound|. In the * event of an error the alert type to use is stored in |*ad|. We don't actually * process the content of the extensions yet, except to check their types. @@ -288,10 +294,7 @@ static int find_extension_definition(SSL *s, unsigned int type, * types, and 0 if the extensions contain duplicates, could not be successfully * parsed, or an internal error occurred. */ -/* - * TODO(TLS1.3): Refactor ServerHello extension parsing to use this and then - * remove tls1_check_duplicate_extensions() - */ + int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context, RAW_EXTENSION **res, size_t *numfound, int *ad) { @@ -376,7 +379,7 @@ int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts, int (*parser)(SSL *s, PACKET *pkt, int *al) = NULL; if (s->tlsext_debug_cb) - s->tlsext_debug_cb(s, 0, currext->type, + s->tlsext_debug_cb(s, !s->server, currext->type, PACKET_data(&currext->data), PACKET_remaining(&currext->data), s->tlsext_debug_arg); @@ -389,7 +392,8 @@ int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts, parser = NULL; if (find_extension_definition(s, currext->type, &extdef)) { - parser = s->server ? extdef->server_parse : extdef->client_parse; + parser = s->server ? extdef->parse_client_ext + : extdef->parse_server_ext; /* Check if extension is defined for our protocol. If not, skip */ if ((SSL_IS_DTLS(s) @@ -480,8 +484,8 @@ int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context, if ((ext_defs[loop].context & context) == 0) continue; - construct = s->server ? ext_defs[loop].server_construct - : ext_defs[loop].client_construct; + construct = s->server ? ext_defs[loop].construct_server_ext + : ext_defs[loop].construct_client_ext; /* Check if this extension is defined for our protocol. If not, skip */ if ((SSL_IS_DTLS(s) diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c new file mode 100644 index 0000000000..f51a2de041 --- /dev/null +++ b/ssl/statem/extensions_clnt.c @@ -0,0 +1,608 @@ +/* + * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include +#include "../ssl_locl.h" +#include "statem_locl.h" + +/* + * Parse the server's renegotiation binding and abort if it's not right + */ +int tls_parse_server_renegotiate(SSL *s, PACKET *pkt, int *al) +{ + size_t expected_len = s->s3->previous_client_finished_len + + s->s3->previous_server_finished_len; + size_t ilen; + const unsigned char *data; + + /* Check for logic errors */ + assert(expected_len == 0 || s->s3->previous_client_finished_len != 0); + assert(expected_len == 0 || s->s3->previous_server_finished_len != 0); + + /* Parse the length byte */ + if (!PACKET_get_1_len(pkt, &ilen)) { + SSLerr(SSL_F_TLS_PARSE_SERVER_RENEGOTIATE, + SSL_R_RENEGOTIATION_ENCODING_ERR); + *al = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + /* Consistency check */ + if (PACKET_remaining(pkt) != ilen) { + SSLerr(SSL_F_TLS_PARSE_SERVER_RENEGOTIATE, + SSL_R_RENEGOTIATION_ENCODING_ERR); + *al = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + /* Check that the extension matches */ + if (ilen != expected_len) { + SSLerr(SSL_F_TLS_PARSE_SERVER_RENEGOTIATE, + SSL_R_RENEGOTIATION_MISMATCH); + *al = SSL_AD_HANDSHAKE_FAILURE; + return 0; + } + + if (!PACKET_get_bytes(pkt, &data, s->s3->previous_client_finished_len) + || memcmp(data, s->s3->previous_client_finished, + s->s3->previous_client_finished_len) != 0) { + SSLerr(SSL_F_TLS_PARSE_SERVER_RENEGOTIATE, + SSL_R_RENEGOTIATION_MISMATCH); + *al = SSL_AD_HANDSHAKE_FAILURE; + return 0; + } + + if (!PACKET_get_bytes(pkt, &data, s->s3->previous_server_finished_len) + || memcmp(data, s->s3->previous_server_finished, + s->s3->previous_server_finished_len) != 0) { + SSLerr(SSL_F_TLS_PARSE_SERVER_RENEGOTIATE, + SSL_R_RENEGOTIATION_MISMATCH); + *al = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + s->s3->send_connection_binding = 1; + + return 1; +} + +int tls_parse_server_server_name(SSL *s, PACKET *pkt, int *al) +{ + if (s->tlsext_hostname == NULL || PACKET_remaining(pkt) > 0) { + *al = SSL_AD_UNRECOGNIZED_NAME; + return 0; + } + + if (!s->hit) { + if (s->session->tlsext_hostname != NULL) { + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + s->session->tlsext_hostname = OPENSSL_strdup(s->tlsext_hostname); + if (s->session->tlsext_hostname == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + } + + return 1; +} + +#ifndef OPENSSL_NO_EC +int tls_parse_server_ec_pt_formats(SSL *s, PACKET *pkt, int *al) +{ + unsigned int ecpointformatlist_length; + PACKET ecptformatlist; + + if (!PACKET_as_length_prefixed_1(pkt, &ecptformatlist)) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if (!s->hit) { + ecpointformatlist_length = PACKET_remaining(&ecptformatlist); + s->session->tlsext_ecpointformatlist_length = 0; + + OPENSSL_free(s->session->tlsext_ecpointformatlist); + s->session->tlsext_ecpointformatlist = + OPENSSL_malloc(ecpointformatlist_length); + if (s->session->tlsext_ecpointformatlist == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + + s->session->tlsext_ecpointformatlist_length = ecpointformatlist_length; + + if (!PACKET_copy_bytes(&ecptformatlist, + s->session->tlsext_ecpointformatlist, + ecpointformatlist_length)) { + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + } + + return 1; +} +#endif + +int tls_parse_server_session_ticket(SSL *s, PACKET *pkt, int *al) +{ + if (s->tls_session_ticket_ext_cb && + !s->tls_session_ticket_ext_cb(s, PACKET_data(pkt), + PACKET_remaining(pkt), + s->tls_session_ticket_ext_cb_arg)) { + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + if (!tls_use_ticket(s) || PACKET_remaining(pkt) > 0) { + *al = SSL_AD_UNSUPPORTED_EXTENSION; + return 0; + } + s->tlsext_ticket_expected = 1; + + return 1; +} + +int tls_parse_server_status_request(SSL *s, PACKET *pkt, int *al) +{ + /* + * MUST be empty and only sent if we've requested a status + * request message. + */ + if (s->tlsext_status_type == -1 || PACKET_remaining(pkt) > 0) { + *al = SSL_AD_UNSUPPORTED_EXTENSION; + return 0; + } + /* Set flag to expect CertificateStatus message */ + s->tlsext_status_expected = 1; + + return 1; +} + + +#ifndef OPENSSL_NO_CT +int tls_parse_server_sct(SSL *s, PACKET *pkt, int *al) +{ + /* + * Only take it if we asked for it - i.e if there is no CT validation + * callback set, then a custom extension MAY be processing it, so we + * need to let control continue to flow to that. + */ + if (s->ct_validation_callback != NULL) { + size_t size = PACKET_remaining(pkt); + + /* Simply copy it off for later processing */ + if (s->tlsext_scts != NULL) { + OPENSSL_free(s->tlsext_scts); + s->tlsext_scts = NULL; + } + s->tlsext_scts_len = size; + if (size > 0) { + s->tlsext_scts = OPENSSL_malloc(size); + if (s->tlsext_scts == NULL + || !PACKET_copy_bytes(pkt, s->tlsext_scts, size)) { + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + } + } else { + if (custom_ext_parse(s, 0, TLSEXT_TYPE_signed_certificate_timestamp, + PACKET_data(pkt), PACKET_remaining(pkt), al) <= 0) + return 0; + } + + return 1; +} +#endif + + +#ifndef OPENSSL_NO_NEXTPROTONEG +/* + * ssl_next_proto_validate validates a Next Protocol Negotiation block. No + * elements of zero length are allowed and the set of elements must exactly + * fill the length of the block. Returns 1 on success or 0 on failure. + */ +static int ssl_next_proto_validate(PACKET *pkt) +{ + PACKET tmp_protocol; + + while (PACKET_remaining(pkt)) { + if (!PACKET_get_length_prefixed_1(pkt, &tmp_protocol) + || PACKET_remaining(&tmp_protocol) == 0) + return 0; + } + + return 1; +} + +int tls_parse_server_npn(SSL *s, PACKET *pkt, int *al) +{ + unsigned char *selected; + unsigned char selected_len; + PACKET tmppkt; + + if (s->s3->tmp.finish_md_len != 0) + return 1; + + /* We must have requested it. */ + if (s->ctx->next_proto_select_cb == NULL) { + *al = SSL_AD_UNSUPPORTED_EXTENSION; + return 0; + } + /* The data must be valid */ + tmppkt = *pkt; + if (!ssl_next_proto_validate(&tmppkt)) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + if (s->ctx->next_proto_select_cb(s, &selected, &selected_len, + PACKET_data(pkt), + PACKET_remaining(pkt), + s->ctx->next_proto_select_cb_arg) != + SSL_TLSEXT_ERR_OK) { + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + /* + * Could be non-NULL if server has sent multiple NPN extensions in + * a single Serverhello + */ + OPENSSL_free(s->next_proto_negotiated); + s->next_proto_negotiated = OPENSSL_malloc(selected_len); + if (s->next_proto_negotiated == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + + memcpy(s->next_proto_negotiated, selected, selected_len); + s->next_proto_negotiated_len = selected_len; + s->s3->next_proto_neg_seen = 1; + + return 1; +} +#endif + +int tls_parse_server_alpn(SSL *s, PACKET *pkt, int *al) +{ + size_t len; + + /* We must have requested it. */ + if (!s->s3->alpn_sent) { + *al = SSL_AD_UNSUPPORTED_EXTENSION; + return 0; + } + /*- + * The extension data consists of: + * uint16 list_length + * uint8 proto_length; + * uint8 proto[proto_length]; + */ + if (!PACKET_get_net_2_len(pkt, &len) + || PACKET_remaining(pkt) != len || !PACKET_get_1_len(pkt, &len) + || PACKET_remaining(pkt) != len) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = OPENSSL_malloc(len); + if (s->s3->alpn_selected == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + if (!PACKET_copy_bytes(pkt, s->s3->alpn_selected, len)) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + s->s3->alpn_selected_len = len; + + return 1; +} + +#ifndef OPENSSL_NO_SRTP +int tls_parse_server_use_srtp(SSL *s, PACKET *pkt, int *al) +{ + unsigned int id, ct, mki; + int i; + STACK_OF(SRTP_PROTECTION_PROFILE) *clnt; + SRTP_PROTECTION_PROFILE *prof; + + if (!PACKET_get_net_2(pkt, &ct) + || ct != 2 || !PACKET_get_net_2(pkt, &id) + || !PACKET_get_1(pkt, &mki) + || PACKET_remaining(pkt) != 0) { + SSLerr(SSL_F_TLS_PARSE_SERVER_USE_SRTP, + SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + if (mki != 0) { + /* Must be no MKI, since we never offer one */ + SSLerr(SSL_F_TLS_PARSE_SERVER_USE_SRTP, SSL_R_BAD_SRTP_MKI_VALUE); + *al = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + clnt = SSL_get_srtp_profiles(s); + + /* Throw an error if the server gave us an unsolicited extension */ + if (clnt == NULL) { + SSLerr(SSL_F_TLS_PARSE_SERVER_USE_SRTP, SSL_R_NO_SRTP_PROFILES); + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + /* + * Check to see if the server gave us something we support (and + * presumably offered) + */ + for (i = 0; i < sk_SRTP_PROTECTION_PROFILE_num(clnt); i++) { + prof = sk_SRTP_PROTECTION_PROFILE_value(clnt, i); + + if (prof->id == id) { + s->srtp_profile = prof; + *al = 0; + return 1; + } + } + + SSLerr(SSL_F_TLS_PARSE_SERVER_USE_SRTP, + SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + *al = SSL_AD_DECODE_ERROR; + return 0; +} +#endif + +int tls_parse_server_etm(SSL *s, PACKET *pkt, int *al) +{ + /* Ignore if inappropriate ciphersuite */ + if (!(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC) + && s->s3->tmp.new_cipher->algorithm_mac != SSL_AEAD + && s->s3->tmp.new_cipher->algorithm_enc != SSL_RC4) + s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC; + + return 1; +} + +int tls_parse_server_ems(SSL *s, PACKET *pkt, int *al) +{ + s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS; + if (!s->hit) + s->session->flags |= SSL_SESS_FLAG_EXTMS; + + return 1; +} + +int tls_parse_server_key_share(SSL *s, PACKET *pkt, int *al) +{ + unsigned int group_id; + PACKET encoded_pt; + EVP_PKEY *ckey = s->s3->tmp.pkey, *skey = NULL; + + /* Sanity check */ + if (ckey == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PARSE_SERVER_KEY_SHARE, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (!PACKET_get_net_2(pkt, &group_id)) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PARSE_SERVER_KEY_SHARE, SSL_R_LENGTH_MISMATCH); + return 0; + } + + if (group_id != s->s3->group_id) { + /* + * This isn't for the group that we sent in the original + * key_share! + */ + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PARSE_SERVER_KEY_SHARE, SSL_R_BAD_KEY_SHARE); + return 0; + } + + if (!PACKET_as_length_prefixed_2(pkt, &encoded_pt) + || PACKET_remaining(&encoded_pt) == 0) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PARSE_SERVER_KEY_SHARE, SSL_R_LENGTH_MISMATCH); + return 0; + } + + skey = ssl_generate_pkey(ckey); + if (skey == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PARSE_SERVER_KEY_SHARE, ERR_R_MALLOC_FAILURE); + return 0; + } + if (!EVP_PKEY_set1_tls_encodedpoint(skey, PACKET_data(&encoded_pt), + PACKET_remaining(&encoded_pt))) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PARSE_SERVER_KEY_SHARE, SSL_R_BAD_ECPOINT); + return 0; + } + + if (ssl_derive(s, ckey, skey, 1) == 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PARSE_SERVER_KEY_SHARE, ERR_R_INTERNAL_ERROR); + EVP_PKEY_free(skey); + return 0; + } + EVP_PKEY_free(skey); + + return 1; +} + +static int ssl_scan_serverhello_tlsext(SSL *s, PACKET *pkt, int *al) +{ + size_t num_extensions = 0; + RAW_EXTENSION *extensions = NULL; + PACKET extpkt; + +#ifndef OPENSSL_NO_NEXTPROTONEG + s->s3->next_proto_neg_seen = 0; +#endif + s->tlsext_ticket_expected = 0; + + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = NULL; + + s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC; + + s->s3->flags &= ~TLS1_FLAGS_RECEIVED_EXTMS; + + if (!PACKET_as_length_prefixed_2(pkt, &extpkt)) { + /* Extensions block may be completely absent in SSLv3 */ + if (s->version != SSL3_VERSION || PACKET_remaining(pkt) != 0) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, SSL_R_BAD_LENGTH); + return 0; + } + PACKET_null_init(&extpkt); + } + + /* + * TODO(TLS1.3): We give multiple contexts for now until we're ready to + * give something more specific + */ + + if (!tls_collect_extensions(s, &extpkt, EXT_TLS1_2_SERVER_HELLO + | EXT_TLS1_3_SERVER_HELLO + | EXT_TLS1_3_ENCRYPTED_EXTENSIONS + | EXT_TLS1_3_CERTIFICATE, + &extensions, &num_extensions, al)) + return 0; + + /* + * Determine if we need to see RI. Strictly speaking if we want to avoid + * an attack we should *always* see RI even on initial server hello + * because the client doesn't see any renegotiation during an attack. + * However this would mean we could not connect to any server which + * doesn't support RI so for the immediate future tolerate RI absence + */ + if (!(s->options & SSL_OP_LEGACY_SERVER_CONNECT) + && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) + && tls_get_extension_by_type(extensions, num_extensions, + TLSEXT_TYPE_renegotiate) == NULL) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + return 0; + } + + if (!tls_parse_all_extensions(s, EXT_TLS1_2_SERVER_HELLO + | EXT_TLS1_3_SERVER_HELLO + | EXT_TLS1_3_ENCRYPTED_EXTENSIONS + | EXT_TLS1_3_CERTIFICATE, + extensions, num_extensions, al)) + return 0; + + if (s->hit) { + /* + * Check extended master secret extension is consistent with + * original session. + */ + if (!(s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) != + !(s->session->flags & SSL_SESS_FLAG_EXTMS)) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, SSL_R_INCONSISTENT_EXTMS); + return 0; + } + } + + return 1; +} + +static int ssl_check_serverhello_tlsext(SSL *s) +{ + int ret = SSL_TLSEXT_ERR_NOACK; + int al = SSL_AD_UNRECOGNIZED_NAME; + +#ifndef OPENSSL_NO_EC + /* + * If we are client and using an elliptic curve cryptography cipher + * suite, then if server returns an EC point formats lists extension it + * must contain uncompressed. + */ + unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey; + unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth; + if ((s->tlsext_ecpointformatlist != NULL) + && (s->tlsext_ecpointformatlist_length > 0) + && (s->session->tlsext_ecpointformatlist != NULL) + && (s->session->tlsext_ecpointformatlist_length > 0) + && ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA))) { + /* we are using an ECC cipher */ + size_t i; + unsigned char *list; + int found_uncompressed = 0; + list = s->session->tlsext_ecpointformatlist; + for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++) { + if (*(list++) == TLSEXT_ECPOINTFORMAT_uncompressed) { + found_uncompressed = 1; + break; + } + } + if (!found_uncompressed) { + SSLerr(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT, + SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST); + return -1; + } + } + ret = SSL_TLSEXT_ERR_OK; +#endif /* OPENSSL_NO_EC */ + + if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) + ret = + s->ctx->tlsext_servername_callback(s, &al, + s->ctx->tlsext_servername_arg); + else if (s->initial_ctx != NULL + && s->initial_ctx->tlsext_servername_callback != 0) + ret = + s->initial_ctx->tlsext_servername_callback(s, &al, + s-> + initial_ctx->tlsext_servername_arg); + + /* + * Ensure we get sensible values passed to tlsext_status_cb in the event + * that we don't receive a status message + */ + OPENSSL_free(s->tlsext_ocsp_resp); + s->tlsext_ocsp_resp = NULL; + s->tlsext_ocsp_resplen = 0; + + switch (ret) { + case SSL_TLSEXT_ERR_ALERT_FATAL: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + return -1; + + case SSL_TLSEXT_ERR_ALERT_WARNING: + ssl3_send_alert(s, SSL3_AL_WARNING, al); + return 1; + + case SSL_TLSEXT_ERR_NOACK: + s->servername_done = 0; + default: + return 1; + } +} + +int ssl_parse_serverhello_tlsext(SSL *s, PACKET *pkt) +{ + int al = -1; + if (s->version < SSL3_VERSION) + return 1; + if (ssl_scan_serverhello_tlsext(s, pkt, &al) <= 0) { + ssl3_send_alert(s, SSL3_AL_FATAL, al); + return 0; + } + + if (ssl_check_serverhello_tlsext(s) <= 0) { + SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT, SSL_R_SERVERHELLO_TLSEXT); + return 0; + } + return 1; +} diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 7a69f68046..e090421dde 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -648,6 +648,138 @@ int tls_parse_client_ems(SSL *s, PACKET *pkt, int *al) return 1; } +#ifndef OPENSSL_NO_EC +/*- + * ssl_check_for_safari attempts to fingerprint Safari using OS X + * SecureTransport using the TLS extension block in |hello|. + * Safari, since 10.6, sends exactly these extensions, in this order: + * SNI, + * elliptic_curves + * ec_point_formats + * + * We wish to fingerprint Safari because they broke ECDHE-ECDSA support in 10.8, + * but they advertise support. So enabling ECDHE-ECDSA ciphers breaks them. + * 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 CLIENTHELLO_MSG *hello) +{ + unsigned int type; + PACKET sni, tmppkt; + size_t ext_len; + + static const unsigned char kSafariExtensionsBlock[] = { + 0x00, 0x0a, /* elliptic_curves extension */ + 0x00, 0x08, /* 8 bytes */ + 0x00, 0x06, /* 6 bytes of curve ids */ + 0x00, 0x17, /* P-256 */ + 0x00, 0x18, /* P-384 */ + 0x00, 0x19, /* P-521 */ + + 0x00, 0x0b, /* ec_point_formats */ + 0x00, 0x02, /* 2 bytes */ + 0x01, /* 1 point format */ + 0x00, /* uncompressed */ + /* The following is only present in TLS 1.2 */ + 0x00, 0x0d, /* signature_algorithms */ + 0x00, 0x0c, /* 12 bytes */ + 0x00, 0x0a, /* 10 bytes */ + 0x05, 0x01, /* SHA-384/RSA */ + 0x04, 0x01, /* SHA-256/RSA */ + 0x02, 0x01, /* SHA-1/RSA */ + 0x04, 0x03, /* SHA-256/ECDSA */ + 0x02, 0x03, /* SHA-1/ECDSA */ + }; + + /* Length of the common prefix (first two extensions). */ + static const size_t kSafariCommonExtensionsLength = 18; + + tmppkt = hello->extensions; + + if (!PACKET_forward(&tmppkt, 2) + || !PACKET_get_net_2(&tmppkt, &type) + || !PACKET_get_length_prefixed_2(&tmppkt, &sni)) { + return; + } + + if (type != TLSEXT_TYPE_server_name) + return; + + ext_len = TLS1_get_client_version(s) >= TLS1_2_VERSION ? + sizeof(kSafariExtensionsBlock) : kSafariCommonExtensionsLength; + + s->s3->is_probably_safari = PACKET_equal(&tmppkt, kSafariExtensionsBlock, + ext_len); +} +#endif /* !OPENSSL_NO_EC */ + +/* + * Process all remaining ClientHello extensions that we collected earlier and + * haven't already processed. + * + * Behaviour upon resumption is extension-specific. If the extension has no + * effect during resumption, it is parsed (to verify its format) but otherwise + * ignored. Returns 1 on success and 0 on failure. Upon failure, sets |al| to + * the appropriate alert. + */ +int tls_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al) +{ + /* Reset various flags that might get set by extensions during parsing */ + s->servername_done = 0; + s->tlsext_status_type = -1; +#ifndef OPENSSL_NO_NEXTPROTONEG + s->s3->next_proto_neg_seen = 0; +#endif + + OPENSSL_free(s->s3->alpn_selected); + s->s3->alpn_selected = NULL; + s->s3->alpn_selected_len = 0; + OPENSSL_free(s->s3->alpn_proposed); + s->s3->alpn_proposed = NULL; + s->s3->alpn_proposed_len = 0; + +#ifndef OPENSSL_NO_EC + if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG) + ssl_check_for_safari(s, hello); +#endif /* !OPENSSL_NO_EC */ + + /* Clear any signature algorithms extension received */ + OPENSSL_free(s->s3->tmp.peer_sigalgs); + s->s3->tmp.peer_sigalgs = NULL; + s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC; + +#ifndef OPENSSL_NO_SRP + OPENSSL_free(s->srp_ctx.login); + s->srp_ctx.login = NULL; +#endif + + s->srtp_profile = NULL; + + /* + * We process the supported_groups extension first so that is done before + * we get to key_share which needs to use the information in it. + */ + if (!tls_parse_extension(s, TLSEXT_TYPE_supported_groups, EXT_CLIENT_HELLO, + hello->pre_proc_exts, hello->num_extensions, al)) { + return 0; + } + + /* Need RI if renegotiating */ + if (s->renegotiate + && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) + && tls_get_extension_by_type(hello->pre_proc_exts, + hello->num_extensions, + TLSEXT_TYPE_renegotiate) == NULL) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_SCAN_CLIENTHELLO_TLSEXT, + SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); + return 0; + } + + return tls_parse_all_extensions(s, EXT_CLIENT_HELLO, hello->pre_proc_exts, + hello->num_extensions, al); +} + /* * Process the ALPN extension in a ClientHello. * al: a pointer to the alert value to send in the event of a failure. diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h index 53fd0f0be9..88c40f546b 100644 --- a/ssl/statem/statem_locl.h +++ b/ssl/statem/statem_locl.h @@ -180,6 +180,8 @@ int tls_parse_client_etm(SSL *s, PACKET *pkt, int *al); int tls_parse_client_key_share(SSL *s, PACKET *pkt, int *al); int tls_parse_client_ems(SSL *s, PACKET *pkt, int *al); +int tls_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al); + int tls_construct_server_renegotiate(SSL *s, WPACKET *pkt, int *al); int tls_construct_server_server_name(SSL *s, WPACKET *pkt, int *al); int tls_construct_server_ec_pt_formats(SSL *s, WPACKET *pkt, int *al); @@ -191,10 +193,32 @@ int tls_construct_server_use_srtp(SSL *s, WPACKET *pkt, int *al); int tls_construct_server_etm(SSL *s, WPACKET *pkt, int *al); int tls_construct_server_ems(SSL *s, WPACKET *pkt, int *al); int tls_construct_server_key_share(SSL *s, WPACKET *pkt, int *al); - /* * Not in public headers as this is not an official extension. Only used when * SSL_OP_CRYPTOPRO_TLSEXT_BUG is set. */ #define TLSEXT_TYPE_cryptopro_bug 0xfde8 int tls_construct_server_cryptopro_bug(SSL *s, WPACKET *pkt, int *al); + +/* Client Extension processing */ +int tls_parse_server_renegotiate(SSL *s, PACKET *pkt, int *al); +int tls_parse_server_server_name(SSL *s, PACKET *pkt, int *al); +#ifndef OPENSSL_NO_EC +int tls_parse_server_ec_pt_formats(SSL *s, PACKET *pkt, int *al); +#endif +int tls_parse_server_session_ticket(SSL *s, PACKET *pkt, int *al); +int tls_parse_server_status_request(SSL *s, PACKET *pkt, int *al); +#ifndef OPENSSL_NO_CT +int tls_parse_server_sct(SSL *s, PACKET *pkt, int *al); +#endif +#ifndef OPENSSL_NO_NEXTPROTONEG +int tls_parse_server_npn(SSL *s, PACKET *pkt, int *al); +#endif +int tls_parse_server_alpn(SSL *s, PACKET *pkt, int *al); +#ifndef OPENSSL_NO_SRTP +int tls_parse_server_use_srtp(SSL *s, PACKET *pkt, int *al); +#endif +int tls_parse_server_etm(SSL *s, PACKET *pkt, int *al); +int tls_parse_server_ems(SSL *s, PACKET *pkt, int *al); +int tls_parse_server_key_share(SSL *s, PACKET *pkt, int *al); +int ssl_parse_serverhello_tlsext(SSL *s, PACKET *pkt); diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index cc4b8c3153..14fa0ed028 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -1062,138 +1062,6 @@ int dtls_construct_hello_verify_request(SSL *s, WPACKET *pkt) return 1; } -#ifndef OPENSSL_NO_EC -/*- - * ssl_check_for_safari attempts to fingerprint Safari using OS X - * SecureTransport using the TLS extension block in |hello|. - * Safari, since 10.6, sends exactly these extensions, in this order: - * SNI, - * elliptic_curves - * ec_point_formats - * - * We wish to fingerprint Safari because they broke ECDHE-ECDSA support in 10.8, - * but they advertise support. So enabling ECDHE-ECDSA ciphers breaks them. - * 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 CLIENTHELLO_MSG *hello) -{ - unsigned int type; - PACKET sni, tmppkt; - size_t ext_len; - - static const unsigned char kSafariExtensionsBlock[] = { - 0x00, 0x0a, /* elliptic_curves extension */ - 0x00, 0x08, /* 8 bytes */ - 0x00, 0x06, /* 6 bytes of curve ids */ - 0x00, 0x17, /* P-256 */ - 0x00, 0x18, /* P-384 */ - 0x00, 0x19, /* P-521 */ - - 0x00, 0x0b, /* ec_point_formats */ - 0x00, 0x02, /* 2 bytes */ - 0x01, /* 1 point format */ - 0x00, /* uncompressed */ - /* The following is only present in TLS 1.2 */ - 0x00, 0x0d, /* signature_algorithms */ - 0x00, 0x0c, /* 12 bytes */ - 0x00, 0x0a, /* 10 bytes */ - 0x05, 0x01, /* SHA-384/RSA */ - 0x04, 0x01, /* SHA-256/RSA */ - 0x02, 0x01, /* SHA-1/RSA */ - 0x04, 0x03, /* SHA-256/ECDSA */ - 0x02, 0x03, /* SHA-1/ECDSA */ - }; - - /* Length of the common prefix (first two extensions). */ - static const size_t kSafariCommonExtensionsLength = 18; - - tmppkt = hello->extensions; - - if (!PACKET_forward(&tmppkt, 2) - || !PACKET_get_net_2(&tmppkt, &type) - || !PACKET_get_length_prefixed_2(&tmppkt, &sni)) { - return; - } - - if (type != TLSEXT_TYPE_server_name) - return; - - ext_len = TLS1_get_client_version(s) >= TLS1_2_VERSION ? - sizeof(kSafariExtensionsBlock) : kSafariCommonExtensionsLength; - - s->s3->is_probably_safari = PACKET_equal(&tmppkt, kSafariExtensionsBlock, - ext_len); -} -#endif /* !OPENSSL_NO_EC */ - -/* - * Process all remaining ClientHello extensions that we collected earlier and - * haven't already processed. - * - * Behaviour upon resumption is extension-specific. If the extension has no - * effect during resumption, it is parsed (to verify its format) but otherwise - * ignored. Returns 1 on success and 0 on failure. Upon failure, sets |al| to - * the appropriate alert. - */ -static int tls_scan_clienthello_tlsext(SSL *s, CLIENTHELLO_MSG *hello, int *al) -{ - /* Reset various flags that might get set by extensions during parsing */ - s->servername_done = 0; - s->tlsext_status_type = -1; -#ifndef OPENSSL_NO_NEXTPROTONEG - s->s3->next_proto_neg_seen = 0; -#endif - - OPENSSL_free(s->s3->alpn_selected); - s->s3->alpn_selected = NULL; - s->s3->alpn_selected_len = 0; - OPENSSL_free(s->s3->alpn_proposed); - s->s3->alpn_proposed = NULL; - s->s3->alpn_proposed_len = 0; - -#ifndef OPENSSL_NO_EC - if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG) - ssl_check_for_safari(s, hello); -#endif /* !OPENSSL_NO_EC */ - - /* Clear any signature algorithms extension received */ - OPENSSL_free(s->s3->tmp.peer_sigalgs); - s->s3->tmp.peer_sigalgs = NULL; - s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC; - -#ifndef OPENSSL_NO_SRP - OPENSSL_free(s->srp_ctx.login); - s->srp_ctx.login = NULL; -#endif - - s->srtp_profile = NULL; - - /* - * We process the supported_groups extension first so that is done before - * we get to key_share which needs to use the information in it. - */ - if (!tls_parse_extension(s, TLSEXT_TYPE_supported_groups, EXT_CLIENT_HELLO, - hello->pre_proc_exts, hello->num_extensions, al)) { - return 0; - } - - /* Need RI if renegotiating */ - if (s->renegotiate - && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) - && tls_get_extension_by_type(hello->pre_proc_exts, - hello->num_extensions, - TLSEXT_TYPE_renegotiate) == NULL) { - *al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_TLS_SCAN_CLIENTHELLO_TLSEXT, - SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); - return 0; - } - - return tls_parse_all_extensions(s, EXT_CLIENT_HELLO, hello->pre_proc_exts, - hello->num_extensions, al); -} - /* * Check the results of extension parsing. Currently just calls the servername * callback. Returns 1 for success or 0 for failure. @@ -1986,7 +1854,9 @@ int tls_construct_server_hello(SSL *s, WPACKET *pkt) */ || !tls_construct_extensions(s, pkt, EXT_TLS1_2_SERVER_HELLO - | EXT_TLS1_3_SERVER_HELLO, &al)) { + | EXT_TLS1_3_SERVER_HELLO + | EXT_TLS1_3_ENCRYPTED_EXTENSIONS + | EXT_TLS1_3_CERTIFICATE, &al)) { SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR); goto err; } diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index e8019c0471..e682912b5d 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -23,7 +23,6 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *tick, size_t ticklen, const unsigned char *sess_id, size_t sesslen, SSL_SESSION **psess); -static int ssl_check_serverhello_tlsext(SSL *s); SSL3_ENC_METHOD const TLSv1_enc_data = { tls1_enc, @@ -946,81 +945,6 @@ int tls_use_ticket(SSL *s) return ssl_security(s, SSL_SECOP_TICKET, 0, 0, NULL); } -static int compare_uint(const void *p1, const void *p2) -{ - unsigned int u1 = *((const unsigned int *)p1); - unsigned int u2 = *((const unsigned int *)p2); - if (u1 < u2) - return -1; - else if (u1 > u2) - return 1; - else - return 0; -} - -/* - * 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 does an initial scan over the extensions block to filter those - * out. It returns 1 if all extensions are unique, and 0 if the extensions - * contain duplicates, could not be successfully parsed, or an internal error - * occurred. - */ -static int tls1_check_duplicate_extensions(const PACKET *packet) -{ - PACKET extensions = *packet; - size_t num_extensions = 0, i = 0; - unsigned int *extension_types = NULL; - int ret = 0; - - /* 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)) { - goto done; - } - num_extensions++; - } - - if (num_extensions <= 1) - return 1; - - extension_types = OPENSSL_malloc(sizeof(unsigned int) * num_extensions); - if (extension_types == NULL) { - SSLerr(SSL_F_TLS1_CHECK_DUPLICATE_EXTENSIONS, ERR_R_MALLOC_FAILURE); - goto done; - } - - /* Second pass: gather the extension types. */ - extensions = *packet; - for (i = 0; i < num_extensions; i++) { - PACKET extension; - if (!PACKET_get_net_2(&extensions, &extension_types[i]) || - !PACKET_get_length_prefixed_2(&extensions, &extension)) { - /* This should not happen. */ - SSLerr(SSL_F_TLS1_CHECK_DUPLICATE_EXTENSIONS, ERR_R_INTERNAL_ERROR); - goto done; - } - } - - if (PACKET_remaining(&extensions) != 0) { - SSLerr(SSL_F_TLS1_CHECK_DUPLICATE_EXTENSIONS, ERR_R_INTERNAL_ERROR); - goto done; - } - /* Sort the extensions and make sure there are no duplicates. */ - qsort(extension_types, num_extensions, sizeof(unsigned int), compare_uint); - for (i = 1; i < num_extensions; i++) { - if (extension_types[i - 1] == extension_types[i]) - goto done; - } - ret = 1; - done: - OPENSSL_free(extension_types); - return ret; -} - int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al) { #ifndef OPENSSL_NO_EC @@ -1512,366 +1436,6 @@ int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al) return 1; } -#ifndef OPENSSL_NO_NEXTPROTONEG -/* - * ssl_next_proto_validate validates a Next Protocol Negotiation block. No - * elements of zero length are allowed and the set of elements must exactly - * fill the length of the block. - */ -static char ssl_next_proto_validate(PACKET *pkt) -{ - PACKET tmp_protocol; - - while (PACKET_remaining(pkt)) { - if (!PACKET_get_length_prefixed_1(pkt, &tmp_protocol) - || PACKET_remaining(&tmp_protocol) == 0) - return 0; - } - - return 1; -} -#endif - -static int ssl_scan_serverhello_tlsext(SSL *s, PACKET *pkt, int *al) -{ - unsigned int length, type, size; - int tlsext_servername = 0; - int renegotiate_seen = 0; - -#ifndef OPENSSL_NO_NEXTPROTONEG - s->s3->next_proto_neg_seen = 0; -#endif - s->tlsext_ticket_expected = 0; - - OPENSSL_free(s->s3->alpn_selected); - s->s3->alpn_selected = NULL; - - s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC; - - s->s3->flags &= ~TLS1_FLAGS_RECEIVED_EXTMS; - - if (!PACKET_get_net_2(pkt, &length)) - goto ri_check; - - if (PACKET_remaining(pkt) != length) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - if (!tls1_check_duplicate_extensions(pkt)) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - while (PACKET_get_net_2(pkt, &type) && PACKET_get_net_2(pkt, &size)) { - const unsigned char *data; - PACKET spkt; - - if (!PACKET_get_sub_packet(pkt, &spkt, size) - || !PACKET_peek_bytes(&spkt, &data, size)) - goto ri_check; - - if (s->tlsext_debug_cb) - s->tlsext_debug_cb(s, 1, type, data, size, s->tlsext_debug_arg); - - if (type == TLSEXT_TYPE_renegotiate) { - if (!ssl_parse_serverhello_renegotiate_ext(s, &spkt, al)) - return 0; - renegotiate_seen = 1; - } else if (s->version == SSL3_VERSION) { - } else if (type == TLSEXT_TYPE_server_name) { - if (s->tlsext_hostname == NULL || size > 0) { - *al = TLS1_AD_UNRECOGNIZED_NAME; - return 0; - } - tlsext_servername = 1; - } -#ifndef OPENSSL_NO_EC - else if (type == TLSEXT_TYPE_ec_point_formats) { - unsigned int ecpointformatlist_length; - if (!PACKET_get_1(&spkt, &ecpointformatlist_length) - || ecpointformatlist_length != size - 1) { - *al = TLS1_AD_DECODE_ERROR; - return 0; - } - if (!s->hit) { - s->session->tlsext_ecpointformatlist_length = 0; - OPENSSL_free(s->session->tlsext_ecpointformatlist); - if ((s->session->tlsext_ecpointformatlist = - OPENSSL_malloc(ecpointformatlist_length)) == NULL) { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - s->session->tlsext_ecpointformatlist_length = - ecpointformatlist_length; - if (!PACKET_copy_bytes(&spkt, - s->session->tlsext_ecpointformatlist, - ecpointformatlist_length)) { - *al = TLS1_AD_DECODE_ERROR; - return 0; - } - - } - } -#endif /* OPENSSL_NO_EC */ - - else if (type == TLSEXT_TYPE_session_ticket) { - if (s->tls_session_ticket_ext_cb && - !s->tls_session_ticket_ext_cb(s, data, size, - s->tls_session_ticket_ext_cb_arg)) - { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - if (!tls_use_ticket(s) || (size > 0)) { - *al = TLS1_AD_UNSUPPORTED_EXTENSION; - return 0; - } - s->tlsext_ticket_expected = 1; - } else if (type == TLSEXT_TYPE_status_request) { - /* - * MUST be empty and only sent if we've requested a status - * request message. - */ - if ((s->tlsext_status_type == -1) || (size > 0)) { - *al = TLS1_AD_UNSUPPORTED_EXTENSION; - return 0; - } - /* Set flag to expect CertificateStatus message */ - s->tlsext_status_expected = 1; - } -#ifndef OPENSSL_NO_CT - /* - * Only take it if we asked for it - i.e if there is no CT validation - * callback set, then a custom extension MAY be processing it, so we - * need to let control continue to flow to that. - */ - else if (type == TLSEXT_TYPE_signed_certificate_timestamp && - s->ct_validation_callback != NULL) { - /* Simply copy it off for later processing */ - if (s->tlsext_scts != NULL) { - OPENSSL_free(s->tlsext_scts); - s->tlsext_scts = NULL; - } - s->tlsext_scts_len = size; - if (size > 0) { - s->tlsext_scts = OPENSSL_malloc(size); - if (s->tlsext_scts == NULL) { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - memcpy(s->tlsext_scts, data, size); - } - } -#endif -#ifndef OPENSSL_NO_NEXTPROTONEG - else if (type == TLSEXT_TYPE_next_proto_neg && - s->s3->tmp.finish_md_len == 0) { - unsigned char *selected; - unsigned char selected_len; - /* We must have requested it. */ - if (s->ctx->next_proto_select_cb == NULL) { - *al = TLS1_AD_UNSUPPORTED_EXTENSION; - return 0; - } - /* The data must be valid */ - if (!ssl_next_proto_validate(&spkt)) { - *al = TLS1_AD_DECODE_ERROR; - return 0; - } - if (s->ctx->next_proto_select_cb(s, &selected, &selected_len, data, - size, - s-> - ctx->next_proto_select_cb_arg) != - SSL_TLSEXT_ERR_OK) { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - /* - * Could be non-NULL if server has sent multiple NPN extensions in - * a single Serverhello - */ - OPENSSL_free(s->next_proto_negotiated); - s->next_proto_negotiated = OPENSSL_malloc(selected_len); - if (s->next_proto_negotiated == NULL) { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - memcpy(s->next_proto_negotiated, selected, selected_len); - s->next_proto_negotiated_len = selected_len; - s->s3->next_proto_neg_seen = 1; - } -#endif - - else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation) { - unsigned len; - /* We must have requested it. */ - if (!s->s3->alpn_sent) { - *al = TLS1_AD_UNSUPPORTED_EXTENSION; - return 0; - } - /*- - * The extension data consists of: - * uint16 list_length - * uint8 proto_length; - * uint8 proto[proto_length]; - */ - if (!PACKET_get_net_2(&spkt, &len) - || PACKET_remaining(&spkt) != len || !PACKET_get_1(&spkt, &len) - || PACKET_remaining(&spkt) != len) { - *al = TLS1_AD_DECODE_ERROR; - return 0; - } - OPENSSL_free(s->s3->alpn_selected); - s->s3->alpn_selected = OPENSSL_malloc(len); - if (s->s3->alpn_selected == NULL) { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - if (!PACKET_copy_bytes(&spkt, s->s3->alpn_selected, len)) { - *al = TLS1_AD_DECODE_ERROR; - return 0; - } - s->s3->alpn_selected_len = len; - } -#ifndef OPENSSL_NO_SRTP - else if (SSL_IS_DTLS(s) && type == TLSEXT_TYPE_use_srtp) { - if (ssl_parse_serverhello_use_srtp_ext(s, &spkt, al)) - return 0; - } -#endif - else if (type == TLSEXT_TYPE_encrypt_then_mac) { - /* Ignore if inappropriate ciphersuite */ - if (!(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC) && - s->s3->tmp.new_cipher->algorithm_mac != SSL_AEAD - && s->s3->tmp.new_cipher->algorithm_enc != SSL_RC4) - s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC; - } else if (type == TLSEXT_TYPE_extended_master_secret && - (SSL_IS_DTLS(s) || !SSL_IS_TLS13(s))) { - s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS; - if (!s->hit) - s->session->flags |= SSL_SESS_FLAG_EXTMS; - } else if (type == TLSEXT_TYPE_key_share - && SSL_IS_TLS13(s)) { - unsigned int group_id; - PACKET encoded_pt; - EVP_PKEY *ckey = s->s3->tmp.pkey, *skey = NULL; - - /* Sanity check */ - if (ckey == NULL) { - *al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); - return 0; - } - - if (!PACKET_get_net_2(&spkt, &group_id)) { - *al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, - SSL_R_LENGTH_MISMATCH); - return 0; - } - - if (group_id != s->s3->group_id) { - /* - * This isn't for the group that we sent in the original - * key_share! - */ - *al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, - SSL_R_BAD_KEY_SHARE); - return 0; - } - - if (!PACKET_as_length_prefixed_2(&spkt, &encoded_pt) - || PACKET_remaining(&encoded_pt) == 0) { - *al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, - SSL_R_LENGTH_MISMATCH); - return 0; - } - - skey = ssl_generate_pkey(ckey); - if (skey == NULL) { - *al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, ERR_R_MALLOC_FAILURE); - return 0; - } - if (!EVP_PKEY_set1_tls_encodedpoint(skey, PACKET_data(&encoded_pt), - PACKET_remaining(&encoded_pt))) { - *al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, SSL_R_BAD_ECPOINT); - return 0; - } - - if (ssl_derive(s, ckey, skey, 1) == 0) { - *al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); - EVP_PKEY_free(skey); - return 0; - } - EVP_PKEY_free(skey); - /* - * If this extension type was not otherwise handled, but matches a - * custom_cli_ext_record, then send it to the c callback - */ - } else if (custom_ext_parse(s, 0, type, data, size, al) <= 0) - return 0; - } - - if (PACKET_remaining(pkt) != 0) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - if (!s->hit && tlsext_servername == 1) { - if (s->tlsext_hostname) { - if (s->session->tlsext_hostname == NULL) { - s->session->tlsext_hostname = - OPENSSL_strdup(s->tlsext_hostname); - if (!s->session->tlsext_hostname) { - *al = SSL_AD_UNRECOGNIZED_NAME; - return 0; - } - } else { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - } - } - - ri_check: - - /* - * Determine if we need to see RI. Strictly speaking if we want to avoid - * an attack we should *always* see RI even on initial server hello - * because the client doesn't see any renegotiation during an attack. - * However this would mean we could not connect to any server which - * doesn't support RI so for the immediate future tolerate RI absence - */ - if (!renegotiate_seen && !(s->options & SSL_OP_LEGACY_SERVER_CONNECT) - && !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) { - *al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, - SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED); - return 0; - } - - if (s->hit) { - /* - * Check extended master secret extension is consistent with - * original session. - */ - if (!(s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) != - !(s->session->flags & SSL_SESS_FLAG_EXTMS)) { - *al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, SSL_R_INCONSISTENT_EXTMS); - return 0; - } - } - - return 1; -} - int ssl_prepare_clienthello_tlsext(SSL *s) { s->s3->alpn_sent = 0; @@ -1940,96 +1504,6 @@ int tls1_set_server_sigalgs(SSL *s) return 0; } -int ssl_check_serverhello_tlsext(SSL *s) -{ - int ret = SSL_TLSEXT_ERR_NOACK; - int al = SSL_AD_UNRECOGNIZED_NAME; - -#ifndef OPENSSL_NO_EC - /* - * If we are client and using an elliptic curve cryptography cipher - * suite, then if server returns an EC point formats lists extension it - * must contain uncompressed. - */ - unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey; - unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth; - if ((s->tlsext_ecpointformatlist != NULL) - && (s->tlsext_ecpointformatlist_length > 0) - && (s->session->tlsext_ecpointformatlist != NULL) - && (s->session->tlsext_ecpointformatlist_length > 0) - && ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA))) { - /* we are using an ECC cipher */ - size_t i; - unsigned char *list; - int found_uncompressed = 0; - list = s->session->tlsext_ecpointformatlist; - for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++) { - if (*(list++) == TLSEXT_ECPOINTFORMAT_uncompressed) { - found_uncompressed = 1; - break; - } - } - if (!found_uncompressed) { - SSLerr(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT, - SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST); - return -1; - } - } - ret = SSL_TLSEXT_ERR_OK; -#endif /* OPENSSL_NO_EC */ - - if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0) - ret = - s->ctx->tlsext_servername_callback(s, &al, - s->ctx->tlsext_servername_arg); - else if (s->initial_ctx != NULL - && s->initial_ctx->tlsext_servername_callback != 0) - ret = - s->initial_ctx->tlsext_servername_callback(s, &al, - s-> - initial_ctx->tlsext_servername_arg); - - /* - * Ensure we get sensible values passed to tlsext_status_cb in the event - * that we don't receive a status message - */ - OPENSSL_free(s->tlsext_ocsp_resp); - s->tlsext_ocsp_resp = NULL; - s->tlsext_ocsp_resplen = 0; - - switch (ret) { - case SSL_TLSEXT_ERR_ALERT_FATAL: - ssl3_send_alert(s, SSL3_AL_FATAL, al); - return -1; - - case SSL_TLSEXT_ERR_ALERT_WARNING: - ssl3_send_alert(s, SSL3_AL_WARNING, al); - return 1; - - case SSL_TLSEXT_ERR_NOACK: - s->servername_done = 0; - default: - return 1; - } -} - -int ssl_parse_serverhello_tlsext(SSL *s, PACKET *pkt) -{ - int al = -1; - if (s->version < SSL3_VERSION) - return 1; - if (ssl_scan_serverhello_tlsext(s, pkt, &al) <= 0) { - ssl3_send_alert(s, SSL3_AL_FATAL, al); - return 0; - } - - if (ssl_check_serverhello_tlsext(s) <= 0) { - SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT, SSL_R_SERVERHELLO_TLSEXT); - return 0; - } - return 1; -} - /* * Given a list of extensions that we collected earlier, find one of a given * type and return it. diff --git a/ssl/t1_reneg.c b/ssl/t1_reneg.c deleted file mode 100644 index 4301a38be5..0000000000 --- a/ssl/t1_reneg.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. - * - * Licensed under the OpenSSL license (the "License"). You may not use - * this file except in compliance with the License. You can obtain a copy - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include -#include -#include "ssl_locl.h" - -/* - * Parse the server's renegotiation binding and abort if it's not right - */ -int ssl_parse_serverhello_renegotiate_ext(SSL *s, PACKET *pkt, int *al) -{ - size_t expected_len = s->s3->previous_client_finished_len - + s->s3->previous_server_finished_len; - size_t ilen; - const unsigned char *data; - - /* Check for logic errors */ - OPENSSL_assert(!expected_len || s->s3->previous_client_finished_len); - OPENSSL_assert(!expected_len || s->s3->previous_server_finished_len); - - /* Parse the length byte */ - if (!PACKET_get_1_len(pkt, &ilen)) { - SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT, - SSL_R_RENEGOTIATION_ENCODING_ERR); - *al = SSL_AD_ILLEGAL_PARAMETER; - return 0; - } - - /* Consistency check */ - if (PACKET_remaining(pkt) != ilen) { - SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT, - SSL_R_RENEGOTIATION_ENCODING_ERR); - *al = SSL_AD_ILLEGAL_PARAMETER; - return 0; - } - - /* Check that the extension matches */ - if (ilen != expected_len) { - SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT, - SSL_R_RENEGOTIATION_MISMATCH); - *al = SSL_AD_HANDSHAKE_FAILURE; - return 0; - } - - if (!PACKET_get_bytes(pkt, &data, s->s3->previous_client_finished_len) - || memcmp(data, s->s3->previous_client_finished, - s->s3->previous_client_finished_len) != 0) { - SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT, - SSL_R_RENEGOTIATION_MISMATCH); - *al = SSL_AD_HANDSHAKE_FAILURE; - return 0; - } - - if (!PACKET_get_bytes(pkt, &data, s->s3->previous_server_finished_len) - || memcmp(data, s->s3->previous_server_finished, - s->s3->previous_server_finished_len) != 0) { - SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_RENEGOTIATE_EXT, - SSL_R_RENEGOTIATION_MISMATCH); - *al = SSL_AD_ILLEGAL_PARAMETER; - return 0; - } - s->s3->send_connection_binding = 1; - - return 1; -}