diff options
author | Matt Caswell <matt@openssl.org> | 2016-11-25 12:34:29 +0000 |
---|---|---|
committer | Matt Caswell <matt@openssl.org> | 2016-12-08 17:18:25 +0000 |
commit | 6dd083fd6804a3ee6ac3adc019f81910f1c63f21 (patch) | |
tree | fc4c9bacf7a79bb56db98faf2a890136f7fca0af /ssl | |
parent | e56c33b98bd8d72307da7911de27b5d38191d239 (diff) |
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 <rsalz@openssl.org>
Reviewed-by: Richard Levitte <levitte@openssl.org>
Diffstat (limited to 'ssl')
-rw-r--r-- | ssl/build.info | 4 | ||||
-rw-r--r-- | ssl/d1_srtp.c | 57 | ||||
-rw-r--r-- | ssl/ssl_err.c | 5 | ||||
-rw-r--r-- | ssl/ssl_locl.h | 3 | ||||
-rw-r--r-- | ssl/statem/extensions.c | 64 | ||||
-rw-r--r-- | ssl/statem/extensions_clnt.c | 608 | ||||
-rw-r--r-- | ssl/statem/extensions_srvr.c | 132 | ||||
-rw-r--r-- | ssl/statem/statem_locl.h | 26 | ||||
-rw-r--r-- | ssl/statem/statem_srvr.c | 136 | ||||
-rw-r--r-- | ssl/t1_lib.c | 526 | ||||
-rw-r--r-- | ssl/t1_reneg.c | 72 |
11 files changed, 809 insertions, 824 deletions
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 <assert.h> +#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_don |