| /* |
| * 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 <openssl/ocsp.h> |
| #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; |
| } |