From: Matt Caswell Date: Thu, 24 Nov 2016 22:54:59 +0000 (+0000) Subject: Split extensions code into core extensions and server extensions code X-Git-Tag: OpenSSL_1_1_1-pre1~2911 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=25670f3e87d3a9e7ea8ffb2b717a288e2b3024f5;p=oweals%2Fopenssl.git Split extensions code into core extensions and server extensions code Later we will have client extensions code too. Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich Salz Reviewed-by: Rich Salz Reviewed-by: Richard Levitte --- diff --git a/ssl/build.info b/ssl/build.info index 931ad61b59..fb2265e145 100644 --- a/ssl/build.info +++ b/ssl/build.info @@ -2,7 +2,8 @@ LIBS=../libssl 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 s3_cbc.c s3_msg.c \ + statem/statem_lib.c statem/extensions.c statem/extensions_srvr.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 \ diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index c98a2055c2..8bea0746e1 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -8,33 +8,9 @@ */ #include -#include #include "../ssl_locl.h" #include "statem_locl.h" -static int tls_parse_clienthello_renegotiate(SSL *s, PACKET *pkt, int *al); -static int tls_parse_clienthello_server_name(SSL *s, PACKET *pkt, int *al); -#ifndef OPENSSL_NO_SRP -static int tls_parse_clienthello_srp(SSL *s, PACKET *pkt, int *al); -#endif -#ifndef OPENSSL_NO_EC -static int tls_parse_clienthello_ec_pt_formats(SSL *s, PACKET *pkt, int *al); -static int tls_parse_clienthello_supported_groups(SSL *s, PACKET *pkt, int *al); -#endif -static int tls_parse_clienthello_session_ticket(SSL *s, PACKET *pkt, int *al); -static int tls_parse_clienthello_sig_algs(SSL *s, PACKET *pkt, int *al); -static int tls_parse_clienthello_status_request(SSL *s, PACKET *pkt, int *al); -#ifndef OPENSSL_NO_NEXTPROTONEG -static int tls_parse_clienthello_npn(SSL *s, PACKET *pkt, int *al); -#endif -static int tls_parse_clienthello_alpn(SSL *s, PACKET *pkt, int *al); -#ifndef OPENSSL_NO_SRTP -static int tls_parse_clienthello_use_srtp(SSL *s, PACKET *pkt, int *al); -#endif -static int tls_parse_clienthello_etm(SSL *s, PACKET *pkt, int *al); -static int tls_parse_clienthello_key_share(SSL *s, PACKET *pkt, int *al); -static int tls_parse_clienthello_ems(SSL *s, PACKET *pkt, int *al); - typedef struct { /* The ID for the extension */ unsigned int type; @@ -535,640 +511,3 @@ int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context, return 1; } - -/* - * Parse the client's renegotiation binding and abort if it's not right - */ -static int tls_parse_clienthello_renegotiate(SSL *s, PACKET *pkt, int *al) -{ - unsigned int ilen; - const unsigned char *data; - - /* Parse the length byte */ - if (!PACKET_get_1(pkt, &ilen) - || !PACKET_get_bytes(pkt, &data, ilen)) { - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_RENEGOTIATE, - SSL_R_RENEGOTIATION_ENCODING_ERR); - *al = SSL_AD_ILLEGAL_PARAMETER; - return 0; - } - - /* Check that the extension matches */ - if (ilen != s->s3->previous_client_finished_len) { - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_RENEGOTIATE, - SSL_R_RENEGOTIATION_MISMATCH); - *al = SSL_AD_HANDSHAKE_FAILURE; - return 0; - } - - if (memcmp(data, s->s3->previous_client_finished, - s->s3->previous_client_finished_len)) { - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_RENEGOTIATE, - SSL_R_RENEGOTIATION_MISMATCH); - *al = SSL_AD_HANDSHAKE_FAILURE; - return 0; - } - - s->s3->send_connection_binding = 1; - - return 1; -} - -static int tls_parse_clienthello_server_name(SSL *s, PACKET *pkt, int *al) -{ - unsigned int servname_type; - PACKET sni, hostname; - - /*- - * The servername extension is treated as follows: - * - * - Only the hostname type is supported with a maximum length of 255. - * - The servername is rejected if too long or if it contains zeros, - * in which case an fatal alert is generated. - * - The servername field is maintained together with the session cache. - * - When a session is resumed, the servername call back invoked in order - * to allow the application to position itself to the right context. - * - The servername is acknowledged if it is new for a session or when - * it is identical to a previously used for the same session. - * Applications can control the behaviour. They can at any time - * set a 'desirable' servername for a new SSL object. This can be the - * case for example with HTTPS when a Host: header field is received and - * a renegotiation is requested. In this case, a possible servername - * presented in the new client hello is only acknowledged if it matches - * the value of the Host: field. - * - Applications must use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION - * if they provide for changing an explicit servername context for the - * session, i.e. when the session has been established with a servername - * extension. - * - On session reconnect, the servername extension may be absent. - * - */ - if (!PACKET_as_length_prefixed_2(pkt, &sni) - /* ServerNameList must be at least 1 byte long. */ - || PACKET_remaining(&sni) == 0) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - /* - * Although the server_name extension was intended to be - * extensible to new name types, RFC 4366 defined the - * syntax inextensibility and OpenSSL 1.0.x parses it as - * such. - * RFC 6066 corrected the mistake but adding new name types - * is nevertheless no longer feasible, so act as if no other - * SNI types can exist, to simplify parsing. - * - * Also note that the RFC permits only one SNI value per type, - * i.e., we can only have a single hostname. - */ - if (!PACKET_get_1(&sni, &servname_type) - || servname_type != TLSEXT_NAMETYPE_host_name - || !PACKET_as_length_prefixed_2(&sni, &hostname)) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - if (!s->hit) { - if (PACKET_remaining(&hostname) > TLSEXT_MAXLEN_host_name) { - *al = TLS1_AD_UNRECOGNIZED_NAME; - return 0; - } - - if (PACKET_contains_zero_byte(&hostname)) { - *al = TLS1_AD_UNRECOGNIZED_NAME; - return 0; - } - - if (!PACKET_strndup(&hostname, &s->session->tlsext_hostname)) { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - - s->servername_done = 1; - } else { - /* - * TODO(openssl-team): if the SNI doesn't match, we MUST - * fall back to a full handshake. - */ - s->servername_done = s->session->tlsext_hostname - && PACKET_equal(&hostname, s->session->tlsext_hostname, - strlen(s->session->tlsext_hostname)); - } - - return 1; -} - -#ifndef OPENSSL_NO_SRP -static int tls_parse_clienthello_srp(SSL *s, PACKET *pkt, int *al) -{ - PACKET srp_I; - - if (!PACKET_as_length_prefixed_1(pkt, &srp_I) - || PACKET_contains_zero_byte(&srp_I)) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - /* - * TODO(openssl-team): currently, we re-authenticate the user - * upon resumption. Instead, we MUST ignore the login. - */ - if (!PACKET_strndup(&srp_I, &s->srp_ctx.login)) { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - - return 1; -} -#endif - -#ifndef OPENSSL_NO_EC -static int tls_parse_clienthello_ec_pt_formats(SSL *s, PACKET *pkt, int *al) -{ - PACKET ec_point_format_list; - - if (!PACKET_as_length_prefixed_1(pkt, &ec_point_format_list) - || PACKET_remaining(&ec_point_format_list) == 0) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - if (!s->hit) { - if (!PACKET_memdup(&ec_point_format_list, - &s->session->tlsext_ecpointformatlist, - &s->session->tlsext_ecpointformatlist_length)) { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - } - - return 1; -} -#endif /* OPENSSL_NO_EC */ - -static int tls_parse_clienthello_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 = TLS1_AD_INTERNAL_ERROR; - return 0; - } - - return 1; -} - -static int tls_parse_clienthello_sig_algs(SSL *s, PACKET *pkt, int *al) -{ - PACKET supported_sig_algs; - - if (!PACKET_as_length_prefixed_2(pkt, &supported_sig_algs) - || (PACKET_remaining(&supported_sig_algs) % 2) != 0 - || PACKET_remaining(&supported_sig_algs) == 0) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - if (!s->hit && !tls1_save_sigalgs(s, PACKET_data(&supported_sig_algs), - PACKET_remaining(&supported_sig_algs))) { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - - return 1; -} - -static int tls_parse_clienthello_status_request(SSL *s, PACKET *pkt, int *al) -{ - if (!PACKET_get_1(pkt, (unsigned int *)&s->tlsext_status_type)) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } -#ifndef OPENSSL_NO_OCSP - if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) { - const unsigned char *ext_data; - PACKET responder_id_list, exts; - if (!PACKET_get_length_prefixed_2 (pkt, &responder_id_list)) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - /* - * We remove any OCSP_RESPIDs from a previous handshake - * to prevent unbounded memory growth - CVE-2016-6304 - */ - sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free); - if (PACKET_remaining(&responder_id_list) > 0) { - s->tlsext_ocsp_ids = sk_OCSP_RESPID_new_null(); - if (s->tlsext_ocsp_ids == NULL) { - *al = SSL_AD_INTERNAL_ERROR; - return 0; - } - } else { - s->tlsext_ocsp_ids = NULL; - } - - while (PACKET_remaining(&responder_id_list) > 0) { - OCSP_RESPID *id; - PACKET responder_id; - const unsigned char *id_data; - - if (!PACKET_get_length_prefixed_2(&responder_id_list, - &responder_id) - || PACKET_remaining(&responder_id) == 0) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - id_data = PACKET_data(&responder_id); - /* TODO(size_t): Convert d2i_* to size_t */ - id = d2i_OCSP_RESPID(NULL, &id_data, - (int)PACKET_remaining(&responder_id)); - if (id == NULL) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - if (id_data != PACKET_end(&responder_id)) { - OCSP_RESPID_free(id); - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - if (!sk_OCSP_RESPID_push(s->tlsext_ocsp_ids, id)) { - OCSP_RESPID_free(id); - *al = SSL_AD_INTERNAL_ERROR; - return 0; - } - } - - /* Read in request_extensions */ - if (!PACKET_as_length_prefixed_2(pkt, &exts)) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - if (PACKET_remaining(&exts) > 0) { - ext_data = PACKET_data(&exts); - sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts, - X509_EXTENSION_free); - s->tlsext_ocsp_exts = - d2i_X509_EXTENSIONS(NULL, &ext_data, - (int)PACKET_remaining(&exts)); - if (s->tlsext_ocsp_exts == NULL || ext_data != PACKET_end(&exts)) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - } - } else -#endif - { - /* - * We don't know what to do with any other type so ignore it. - */ - s->tlsext_status_type = -1; - } - - return 1; -} - -#ifndef OPENSSL_NO_NEXTPROTONEG -static int tls_parse_clienthello_npn(SSL *s, PACKET *pkt, int *al) -{ - if (s->s3->tmp.finish_md_len == 0) { - /*- - * We shouldn't accept this extension on a - * renegotiation. - * - * s->new_session will be set on renegotiation, but we - * probably shouldn't rely that it couldn't be set on - * the initial renegotiation too in certain cases (when - * there's some other reason to disallow resuming an - * earlier session -- the current code won't be doing - * anything like that, but this might change). - * - * A valid sign that there's been a previous handshake - * in this connection is if s->s3->tmp.finish_md_len > - * 0. (We are talking about a check that will happen - * in the Hello protocol round, well before a new - * Finished message could have been computed.) - */ - s->s3->next_proto_neg_seen = 1; - } - - return 1; -} -#endif - -/* - * Save the ALPN extension in a ClientHello. - * pkt: the contents of the ALPN extension, not including type and length. - * al: a pointer to the alert value to send in the event of a failure. - * returns: 1 on success, 0 on error. - */ -static int tls_parse_clienthello_alpn(SSL *s, PACKET *pkt, int *al) -{ - PACKET protocol_list, save_protocol_list, protocol; - - if (s->s3->tmp.finish_md_len != 0) - return 1; - - if (!PACKET_as_length_prefixed_2(pkt, &protocol_list) - || PACKET_remaining(&protocol_list) < 2) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - save_protocol_list = protocol_list; - do { - /* Protocol names can't be empty. */ - if (!PACKET_get_length_prefixed_1(&protocol_list, &protocol) - || PACKET_remaining(&protocol) == 0) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - } while (PACKET_remaining(&protocol_list) != 0); - - if (!PACKET_memdup(&save_protocol_list, - &s->s3->alpn_proposed, &s->s3->alpn_proposed_len)) { - *al = TLS1_AD_INTERNAL_ERROR; - return 0; - } - - return 1; -} - -#ifndef OPENSSL_NO_SRTP -static int tls_parse_clienthello_use_srtp(SSL *s, PACKET *pkt, int *al) -{ - SRTP_PROTECTION_PROFILE *sprof; - STACK_OF(SRTP_PROTECTION_PROFILE) *srvr; - unsigned int ct, mki_len, id; - int i, srtp_pref; - PACKET subpkt; - - /* Ignore this if we have no SRTP profiles */ - if (SSL_get_srtp_profiles(s) == NULL) - return 1; - - /* Pull off the length of the cipher suite list and check it is even */ - if (!PACKET_get_net_2(pkt, &ct) - || (ct & 1) != 0 || !PACKET_get_sub_packet(pkt, &subpkt, ct)) { - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_USE_SRTP, - SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - srvr = SSL_get_srtp_profiles(s); - s->srtp_profile = NULL; - /* Search all profiles for a match initially */ - srtp_pref = sk_SRTP_PROTECTION_PROFILE_num(srvr); - - while (PACKET_remaining(&subpkt)) { - if (!PACKET_get_net_2(&subpkt, &id)) { - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_USE_SRTP, - SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - /* - * Only look for match in profiles of higher preference than - * current match. - * If no profiles have been have been configured then this - * does nothing. - */ - for (i = 0; i < srtp_pref; i++) { - sprof = sk_SRTP_PROTECTION_PROFILE_value(srvr, i); - if (sprof->id == id) { - s->srtp_profile = sprof; - srtp_pref = i; - break; - } - } - } - - /* - * Now extract the MKI value as a sanity check, but discard it for now - */ - if (!PACKET_get_1(pkt, &mki_len)) { - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_USE_SRTP, - SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - if (!PACKET_forward(pkt, mki_len) - || PACKET_remaining(pkt)) { - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_USE_SRTP, SSL_R_BAD_SRTP_MKI_VALUE); - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - return 1; -} -#endif - -static int tls_parse_clienthello_etm(SSL *s, PACKET *pkt, int *al) -{ - if (!(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)) - s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC; - - return 1; -} - -/* - * Checks a list of |groups| to determine if the |group_id| is in it. If it is - * and |checkallow| is 1 then additionally check if the group is allowed to be - * used. Returns 1 if the group is in the list (and allowed if |checkallow| is - * 1) or 0 otherwise. - */ -static int check_in_list(SSL *s, unsigned int group_id, - const unsigned char *groups, size_t num_groups, - int checkallow) -{ - size_t i; - - if (groups == NULL || num_groups == 0) - return 0; - - for (i = 0; i < num_groups; i++, groups += 2) { - unsigned int share_id = (groups[0] << 8) | (groups[1]); - - if (group_id == share_id - && (!checkallow || tls_curve_allowed(s, groups, - SSL_SECOP_CURVE_CHECK))) { - break; - } - } - - /* If i == num_groups then not in the list */ - return i < num_groups; -} - -/* - * Process a key_share extension received in the ClientHello. |pkt| contains - * the raw PACKET data for the extension. Returns 1 on success or 0 on failure. - * If a failure occurs then |*al| is set to an appropriate alert value. - */ -static int tls_parse_clienthello_key_share(SSL *s, PACKET *pkt, int *al) -{ - unsigned int group_id; - PACKET key_share_list, encoded_pt; - const unsigned char *clntcurves, *srvrcurves; - size_t clnt_num_curves, srvr_num_curves; - int group_nid, found = 0; - unsigned int curve_flags; - - if (s->hit) - return 1; - - /* Sanity check */ - if (s->s3->peer_tmp != NULL) { - *al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, ERR_R_INTERNAL_ERROR); - return 0; - } - - if (!PACKET_as_length_prefixed_2(pkt, &key_share_list)) { - *al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, SSL_R_LENGTH_MISMATCH); - return 0; - } - - /* Get our list of supported curves */ - if (!tls1_get_curvelist(s, 0, &srvrcurves, &srvr_num_curves)) { - *al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, ERR_R_INTERNAL_ERROR); - return 0; - } - - /* Get the clients list of supported curves */ - if (!tls1_get_curvelist(s, 1, &clntcurves, &clnt_num_curves)) { - *al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, ERR_R_INTERNAL_ERROR); - return 0; - } - - while (PACKET_remaining(&key_share_list) > 0) { - if (!PACKET_get_net_2(&key_share_list, &group_id) - || !PACKET_get_length_prefixed_2(&key_share_list, &encoded_pt) - || PACKET_remaining(&encoded_pt) == 0) { - *al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, - SSL_R_LENGTH_MISMATCH); - return 0; - } - - /* - * If we already found a suitable key_share we loop through the - * rest to verify the structure, but don't process them. - */ - if (found) - continue; - - /* Check if this share is in supported_groups sent from client */ - if (!check_in_list(s, group_id, clntcurves, clnt_num_curves, 0)) { - *al = SSL_AD_HANDSHAKE_FAILURE; - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, SSL_R_BAD_KEY_SHARE); - return 0; - } - - /* Check if this share is for a group we can use */ - if (!check_in_list(s, group_id, srvrcurves, srvr_num_curves, 1)) { - /* Share not suitable */ - continue; - } - - group_nid = tls1_ec_curve_id2nid(group_id, &curve_flags); - - if (group_nid == 0) { - *al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, - SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS); - return 0; - } - - if ((curve_flags & TLS_CURVE_TYPE) == TLS_CURVE_CUSTOM) { - /* Can happen for some curves, e.g. X25519 */ - EVP_PKEY *key = EVP_PKEY_new(); - - if (key == NULL || !EVP_PKEY_set_type(key, group_nid)) { - *al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, ERR_R_EVP_LIB); - EVP_PKEY_free(key); - return 0; - } - s->s3->peer_tmp = key; - } else { - /* Set up EVP_PKEY with named curve as parameters */ - EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); - if (pctx == NULL - || EVP_PKEY_paramgen_init(pctx) <= 0 - || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, - group_nid) <= 0 - || EVP_PKEY_paramgen(pctx, &s->s3->peer_tmp) <= 0) { - *al = SSL_AD_INTERNAL_ERROR; - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, ERR_R_EVP_LIB); - EVP_PKEY_CTX_free(pctx); - return 0; - } - EVP_PKEY_CTX_free(pctx); - pctx = NULL; - } - s->s3->group_id = group_id; - - if (!EVP_PKEY_set1_tls_encodedpoint(s->s3->peer_tmp, - PACKET_data(&encoded_pt), - PACKET_remaining(&encoded_pt))) { - *al = SSL_AD_DECODE_ERROR; - SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, SSL_R_BAD_ECPOINT); - return 0; - } - - found = 1; - } - - return 1; -} - -#ifndef OPENSSL_NO_EC -static int tls_parse_clienthello_supported_groups(SSL *s, PACKET *pkt, int *al) -{ - PACKET supported_groups_list; - - /* Each group is 2 bytes and we must have at least 1. */ - if (!PACKET_as_length_prefixed_2(pkt, &supported_groups_list) - || PACKET_remaining(&supported_groups_list) == 0 - || (PACKET_remaining(&supported_groups_list) % 2) != 0) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - if (!s->hit - && !PACKET_memdup(&supported_groups_list, - &s->session->tlsext_supportedgroupslist, - &s->session->tlsext_supportedgroupslist_length)) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - return 1; -} -#endif - -static int tls_parse_clienthello_ems(SSL *s, PACKET *pkt, int *al) -{ - /* The extension must always be empty */ - if (PACKET_remaining(pkt) != 0) { - *al = SSL_AD_DECODE_ERROR; - return 0; - } - - s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS; - - return 1; -} diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c new file mode 100644 index 0000000000..38a6bef862 --- /dev/null +++ b/ssl/statem/extensions_srvr.c @@ -0,0 +1,649 @@ +/* + * 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 client's renegotiation binding and abort if it's not right + */ +int tls_parse_clienthello_renegotiate(SSL *s, PACKET *pkt, int *al) +{ + unsigned int ilen; + const unsigned char *data; + + /* Parse the length byte */ + if (!PACKET_get_1(pkt, &ilen) + || !PACKET_get_bytes(pkt, &data, ilen)) { + SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_RENEGOTIATE, + SSL_R_RENEGOTIATION_ENCODING_ERR); + *al = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + /* Check that the extension matches */ + if (ilen != s->s3->previous_client_finished_len) { + SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_RENEGOTIATE, + SSL_R_RENEGOTIATION_MISMATCH); + *al = SSL_AD_HANDSHAKE_FAILURE; + return 0; + } + + if (memcmp(data, s->s3->previous_client_finished, + s->s3->previous_client_finished_len)) { + SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_RENEGOTIATE, + SSL_R_RENEGOTIATION_MISMATCH); + *al = SSL_AD_HANDSHAKE_FAILURE; + return 0; + } + + s->s3->send_connection_binding = 1; + + return 1; +} + +int tls_parse_clienthello_server_name(SSL *s, PACKET *pkt, int *al) +{ + unsigned int servname_type; + PACKET sni, hostname; + + /*- + * The servername extension is treated as follows: + * + * - Only the hostname type is supported with a maximum length of 255. + * - The servername is rejected if too long or if it contains zeros, + * in which case an fatal alert is generated. + * - The servername field is maintained together with the session cache. + * - When a session is resumed, the servername call back invoked in order + * to allow the application to position itself to the right context. + * - The servername is acknowledged if it is new for a session or when + * it is identical to a previously used for the same session. + * Applications can control the behaviour. They can at any time + * set a 'desirable' servername for a new SSL object. This can be the + * case for example with HTTPS when a Host: header field is received and + * a renegotiation is requested. In this case, a possible servername + * presented in the new client hello is only acknowledged if it matches + * the value of the Host: field. + * - Applications must use SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION + * if they provide for changing an explicit servername context for the + * session, i.e. when the session has been established with a servername + * extension. + * - On session reconnect, the servername extension may be absent. + * + */ + if (!PACKET_as_length_prefixed_2(pkt, &sni) + /* ServerNameList must be at least 1 byte long. */ + || PACKET_remaining(&sni) == 0) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + /* + * Although the server_name extension was intended to be + * extensible to new name types, RFC 4366 defined the + * syntax inextensibility and OpenSSL 1.0.x parses it as + * such. + * RFC 6066 corrected the mistake but adding new name types + * is nevertheless no longer feasible, so act as if no other + * SNI types can exist, to simplify parsing. + * + * Also note that the RFC permits only one SNI value per type, + * i.e., we can only have a single hostname. + */ + if (!PACKET_get_1(&sni, &servname_type) + || servname_type != TLSEXT_NAMETYPE_host_name + || !PACKET_as_length_prefixed_2(&sni, &hostname)) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + if (!s->hit) { + if (PACKET_remaining(&hostname) > TLSEXT_MAXLEN_host_name) { + *al = TLS1_AD_UNRECOGNIZED_NAME; + return 0; + } + + if (PACKET_contains_zero_byte(&hostname)) { + *al = TLS1_AD_UNRECOGNIZED_NAME; + return 0; + } + + if (!PACKET_strndup(&hostname, &s->session->tlsext_hostname)) { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + + s->servername_done = 1; + } else { + /* + * TODO(openssl-team): if the SNI doesn't match, we MUST + * fall back to a full handshake. + */ + s->servername_done = s->session->tlsext_hostname + && PACKET_equal(&hostname, s->session->tlsext_hostname, + strlen(s->session->tlsext_hostname)); + } + + return 1; +} + +#ifndef OPENSSL_NO_SRP +int tls_parse_clienthello_srp(SSL *s, PACKET *pkt, int *al) +{ + PACKET srp_I; + + if (!PACKET_as_length_prefixed_1(pkt, &srp_I) + || PACKET_contains_zero_byte(&srp_I)) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + /* + * TODO(openssl-team): currently, we re-authenticate the user + * upon resumption. Instead, we MUST ignore the login. + */ + if (!PACKET_strndup(&srp_I, &s->srp_ctx.login)) { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + + return 1; +} +#endif + +#ifndef OPENSSL_NO_EC +int tls_parse_clienthello_ec_pt_formats(SSL *s, PACKET *pkt, int *al) +{ + PACKET ec_point_format_list; + + if (!PACKET_as_length_prefixed_1(pkt, &ec_point_format_list) + || PACKET_remaining(&ec_point_format_list) == 0) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + if (!s->hit) { + if (!PACKET_memdup(&ec_point_format_list, + &s->session->tlsext_ecpointformatlist, + &s->session->tlsext_ecpointformatlist_length)) { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + } + + return 1; +} +#endif /* OPENSSL_NO_EC */ + +int tls_parse_clienthello_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 = TLS1_AD_INTERNAL_ERROR; + return 0; + } + + return 1; +} + +int tls_parse_clienthello_sig_algs(SSL *s, PACKET *pkt, int *al) +{ + PACKET supported_sig_algs; + + if (!PACKET_as_length_prefixed_2(pkt, &supported_sig_algs) + || (PACKET_remaining(&supported_sig_algs) % 2) != 0 + || PACKET_remaining(&supported_sig_algs) == 0) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + if (!s->hit && !tls1_save_sigalgs(s, PACKET_data(&supported_sig_algs), + PACKET_remaining(&supported_sig_algs))) { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + + return 1; +} + +int tls_parse_clienthello_status_request(SSL *s, PACKET *pkt, int *al) +{ + if (!PACKET_get_1(pkt, (unsigned int *)&s->tlsext_status_type)) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } +#ifndef OPENSSL_NO_OCSP + if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) { + const unsigned char *ext_data; + PACKET responder_id_list, exts; + if (!PACKET_get_length_prefixed_2 (pkt, &responder_id_list)) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + /* + * We remove any OCSP_RESPIDs from a previous handshake + * to prevent unbounded memory growth - CVE-2016-6304 + */ + sk_OCSP_RESPID_pop_free(s->tlsext_ocsp_ids, OCSP_RESPID_free); + if (PACKET_remaining(&responder_id_list) > 0) { + s->tlsext_ocsp_ids = sk_OCSP_RESPID_new_null(); + if (s->tlsext_ocsp_ids == NULL) { + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + } else { + s->tlsext_ocsp_ids = NULL; + } + + while (PACKET_remaining(&responder_id_list) > 0) { + OCSP_RESPID *id; + PACKET responder_id; + const unsigned char *id_data; + + if (!PACKET_get_length_prefixed_2(&responder_id_list, + &responder_id) + || PACKET_remaining(&responder_id) == 0) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + id_data = PACKET_data(&responder_id); + /* TODO(size_t): Convert d2i_* to size_t */ + id = d2i_OCSP_RESPID(NULL, &id_data, + (int)PACKET_remaining(&responder_id)); + if (id == NULL) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + if (id_data != PACKET_end(&responder_id)) { + OCSP_RESPID_free(id); + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + if (!sk_OCSP_RESPID_push(s->tlsext_ocsp_ids, id)) { + OCSP_RESPID_free(id); + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + } + + /* Read in request_extensions */ + if (!PACKET_as_length_prefixed_2(pkt, &exts)) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + if (PACKET_remaining(&exts) > 0) { + ext_data = PACKET_data(&exts); + sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts, + X509_EXTENSION_free); + s->tlsext_ocsp_exts = + d2i_X509_EXTENSIONS(NULL, &ext_data, + (int)PACKET_remaining(&exts)); + if (s->tlsext_ocsp_exts == NULL || ext_data != PACKET_end(&exts)) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + } + } else +#endif + { + /* + * We don't know what to do with any other type so ignore it. + */ + s->tlsext_status_type = -1; + } + + return 1; +} + +#ifndef OPENSSL_NO_NEXTPROTONEG +int tls_parse_clienthello_npn(SSL *s, PACKET *pkt, int *al) +{ + if (s->s3->tmp.finish_md_len == 0) { + /*- + * We shouldn't accept this extension on a + * renegotiation. + * + * s->new_session will be set on renegotiation, but we + * probably shouldn't rely that it couldn't be set on + * the initial renegotiation too in certain cases (when + * there's some other reason to disallow resuming an + * earlier session -- the current code won't be doing + * anything like that, but this might change). + * + * A valid sign that there's been a previous handshake + * in this connection is if s->s3->tmp.finish_md_len > + * 0. (We are talking about a check that will happen + * in the Hello protocol round, well before a new + * Finished message could have been computed.) + */ + s->s3->next_proto_neg_seen = 1; + } + + return 1; +} +#endif + +/* + * Save the ALPN extension in a ClientHello. + * pkt: the contents of the ALPN extension, not including type and length. + * al: a pointer to the alert value to send in the event of a failure. + * returns: 1 on success, 0 on error. + */ +int tls_parse_clienthello_alpn(SSL *s, PACKET *pkt, int *al) +{ + PACKET protocol_list, save_protocol_list, protocol; + + if (s->s3->tmp.finish_md_len != 0) + return 1; + + if (!PACKET_as_length_prefixed_2(pkt, &protocol_list) + || PACKET_remaining(&protocol_list) < 2) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + save_protocol_list = protocol_list; + do { + /* Protocol names can't be empty. */ + if (!PACKET_get_length_prefixed_1(&protocol_list, &protocol) + || PACKET_remaining(&protocol) == 0) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + } while (PACKET_remaining(&protocol_list) != 0); + + if (!PACKET_memdup(&save_protocol_list, + &s->s3->alpn_proposed, &s->s3->alpn_proposed_len)) { + *al = TLS1_AD_INTERNAL_ERROR; + return 0; + } + + return 1; +} + +#ifndef OPENSSL_NO_SRTP +int tls_parse_clienthello_use_srtp(SSL *s, PACKET *pkt, int *al) +{ + SRTP_PROTECTION_PROFILE *sprof; + STACK_OF(SRTP_PROTECTION_PROFILE) *srvr; + unsigned int ct, mki_len, id; + int i, srtp_pref; + PACKET subpkt; + + /* Ignore this if we have no SRTP profiles */ + if (SSL_get_srtp_profiles(s) == NULL) + return 1; + + /* Pull off the length of the cipher suite list and check it is even */ + if (!PACKET_get_net_2(pkt, &ct) + || (ct & 1) != 0 || !PACKET_get_sub_packet(pkt, &subpkt, ct)) { + SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_USE_SRTP, + SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + srvr = SSL_get_srtp_profiles(s); + s->srtp_profile = NULL; + /* Search all profiles for a match initially */ + srtp_pref = sk_SRTP_PROTECTION_PROFILE_num(srvr); + + while (PACKET_remaining(&subpkt)) { + if (!PACKET_get_net_2(&subpkt, &id)) { + SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_USE_SRTP, + SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + /* + * Only look for match in profiles of higher preference than + * current match. + * If no profiles have been have been configured then this + * does nothing. + */ + for (i = 0; i < srtp_pref; i++) { + sprof = sk_SRTP_PROTECTION_PROFILE_value(srvr, i); + if (sprof->id == id) { + s->srtp_profile = sprof; + srtp_pref = i; + break; + } + } + } + + /* + * Now extract the MKI value as a sanity check, but discard it for now + */ + if (!PACKET_get_1(pkt, &mki_len)) { + SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_USE_SRTP, + SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST); + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + if (!PACKET_forward(pkt, mki_len) + || PACKET_remaining(pkt)) { + SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_USE_SRTP, SSL_R_BAD_SRTP_MKI_VALUE); + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + return 1; +} +#endif + +int tls_parse_clienthello_etm(SSL *s, PACKET *pkt, int *al) +{ + if (!(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)) + s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC; + + return 1; +} + +/* + * Checks a list of |groups| to determine if the |group_id| is in it. If it is + * and |checkallow| is 1 then additionally check if the group is allowed to be + * used. Returns 1 if the group is in the list (and allowed if |checkallow| is + * 1) or 0 otherwise. + */ +static int check_in_list(SSL *s, unsigned int group_id, + const unsigned char *groups, size_t num_groups, + int checkallow) +{ + size_t i; + + if (groups == NULL || num_groups == 0) + return 0; + + for (i = 0; i < num_groups; i++, groups += 2) { + unsigned int share_id = (groups[0] << 8) | (groups[1]); + + if (group_id == share_id + && (!checkallow || tls_curve_allowed(s, groups, + SSL_SECOP_CURVE_CHECK))) { + break; + } + } + + /* If i == num_groups then not in the list */ + return i < num_groups; +} + +/* + * Process a key_share extension received in the ClientHello. |pkt| contains + * the raw PACKET data for the extension. Returns 1 on success or 0 on failure. + * If a failure occurs then |*al| is set to an appropriate alert value. + */ +int tls_parse_clienthello_key_share(SSL *s, PACKET *pkt, int *al) +{ + unsigned int group_id; + PACKET key_share_list, encoded_pt; + const unsigned char *clntcurves, *srvrcurves; + size_t clnt_num_curves, srvr_num_curves; + int group_nid, found = 0; + unsigned int curve_flags; + + if (s->hit) + return 1; + + /* Sanity check */ + if (s->s3->peer_tmp != NULL) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (!PACKET_as_length_prefixed_2(pkt, &key_share_list)) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, SSL_R_LENGTH_MISMATCH); + return 0; + } + + /* Get our list of supported curves */ + if (!tls1_get_curvelist(s, 0, &srvrcurves, &srvr_num_curves)) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, ERR_R_INTERNAL_ERROR); + return 0; + } + + /* Get the clients list of supported curves */ + if (!tls1_get_curvelist(s, 1, &clntcurves, &clnt_num_curves)) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, ERR_R_INTERNAL_ERROR); + return 0; + } + + while (PACKET_remaining(&key_share_list) > 0) { + if (!PACKET_get_net_2(&key_share_list, &group_id) + || !PACKET_get_length_prefixed_2(&key_share_list, &encoded_pt) + || PACKET_remaining(&encoded_pt) == 0) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, + SSL_R_LENGTH_MISMATCH); + return 0; + } + + /* + * If we already found a suitable key_share we loop through the + * rest to verify the structure, but don't process them. + */ + if (found) + continue; + + /* Check if this share is in supported_groups sent from client */ + if (!check_in_list(s, group_id, clntcurves, clnt_num_curves, 0)) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, SSL_R_BAD_KEY_SHARE); + return 0; + } + + /* Check if this share is for a group we can use */ + if (!check_in_list(s, group_id, srvrcurves, srvr_num_curves, 1)) { + /* Share not suitable */ + continue; + } + + group_nid = tls1_ec_curve_id2nid(group_id, &curve_flags); + + if (group_nid == 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, + SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS); + return 0; + } + + if ((curve_flags & TLS_CURVE_TYPE) == TLS_CURVE_CUSTOM) { + /* Can happen for some curves, e.g. X25519 */ + EVP_PKEY *key = EVP_PKEY_new(); + + if (key == NULL || !EVP_PKEY_set_type(key, group_nid)) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, ERR_R_EVP_LIB); + EVP_PKEY_free(key); + return 0; + } + s->s3->peer_tmp = key; + } else { + /* Set up EVP_PKEY with named curve as parameters */ + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); + if (pctx == NULL + || EVP_PKEY_paramgen_init(pctx) <= 0 + || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, + group_nid) <= 0 + || EVP_PKEY_paramgen(pctx, &s->s3->peer_tmp) <= 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, ERR_R_EVP_LIB); + EVP_PKEY_CTX_free(pctx); + return 0; + } + EVP_PKEY_CTX_free(pctx); + pctx = NULL; + } + s->s3->group_id = group_id; + + if (!EVP_PKEY_set1_tls_encodedpoint(s->s3->peer_tmp, + PACKET_data(&encoded_pt), + PACKET_remaining(&encoded_pt))) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE, SSL_R_BAD_ECPOINT); + return 0; + } + + found = 1; + } + + return 1; +} + +#ifndef OPENSSL_NO_EC +int tls_parse_clienthello_supported_groups(SSL *s, PACKET *pkt, int *al) +{ + PACKET supported_groups_list; + + /* Each group is 2 bytes and we must have at least 1. */ + if (!PACKET_as_length_prefixed_2(pkt, &supported_groups_list) + || PACKET_remaining(&supported_groups_list) == 0 + || (PACKET_remaining(&supported_groups_list) % 2) != 0) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + if (!s->hit + && !PACKET_memdup(&supported_groups_list, + &s->session->tlsext_supportedgroupslist, + &s->session->tlsext_supportedgroupslist_length)) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + return 1; +} +#endif + +int tls_parse_clienthello_ems(SSL *s, PACKET *pkt, int *al) +{ + /* The extension must always be empty */ + if (PACKET_remaining(pkt) != 0) { + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS; + + return 1; +} diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h index 481336d47e..c884eab676 100644 --- a/ssl/statem/statem_locl.h +++ b/ssl/statem/statem_locl.h @@ -155,3 +155,27 @@ __owur int tls_parse_extension(SSL *s, int type, int context, RAW_EXTENSION *ext size_t numexts, int *al); __owur int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context, int *al); + +/* Server Extension processing */ +int tls_parse_clienthello_renegotiate(SSL *s, PACKET *pkt, int *al); +int tls_parse_clienthello_server_name(SSL *s, PACKET *pkt, int *al); +#ifndef OPENSSL_NO_SRP +int tls_parse_clienthello_srp(SSL *s, PACKET *pkt, int *al); +#endif +#ifndef OPENSSL_NO_EC +int tls_parse_clienthello_ec_pt_formats(SSL *s, PACKET *pkt, int *al); +int tls_parse_clienthello_supported_groups(SSL *s, PACKET *pkt, int *al); +#endif +int tls_parse_clienthello_session_ticket(SSL *s, PACKET *pkt, int *al); +int tls_parse_clienthello_sig_algs(SSL *s, PACKET *pkt, int *al); +int tls_parse_clienthello_status_request(SSL *s, PACKET *pkt, int *al); +#ifndef OPENSSL_NO_NEXTPROTONEG +int tls_parse_clienthello_npn(SSL *s, PACKET *pkt, int *al); +#endif +int tls_parse_clienthello_alpn(SSL *s, PACKET *pkt, int *al); +#ifndef OPENSSL_NO_SRTP +int tls_parse_clienthello_use_srtp(SSL *s, PACKET *pkt, int *al); +#endif +int tls_parse_clienthello_etm(SSL *s, PACKET *pkt, int *al); +int tls_parse_clienthello_key_share(SSL *s, PACKET *pkt, int *al); +int tls_parse_clienthello_ems(SSL *s, PACKET *pkt, int *al);