+ dsize -= len;
+ }
+ if (dsize != 0) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ }
+# ifndef OPENSSL_NO_SRP
+ else if (type == TLSEXT_TYPE_srp) {
+ if (size <= 0 || ((len = data[0])) != (size - 1)) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (s->srp_ctx.login != NULL) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if ((s->srp_ctx.login = OPENSSL_malloc(len + 1)) == NULL)
+ return -1;
+ memcpy(s->srp_ctx.login, &data[1], len);
+ s->srp_ctx.login[len] = '\0';
+
+ if (strlen(s->srp_ctx.login) != len) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ }
+# endif
+
+# ifndef OPENSSL_NO_EC
+ else if (type == TLSEXT_TYPE_ec_point_formats) {
+ unsigned char *sdata = data;
+ int ecpointformatlist_length = *(sdata++);
+
+ if (ecpointformatlist_length != size - 1 ||
+ ecpointformatlist_length < 1) {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (!s->hit) {
+ if (s->session->tlsext_ecpointformatlist) {
+ OPENSSL_free(s->session->tlsext_ecpointformatlist);
+ s->session->tlsext_ecpointformatlist = NULL;
+ }
+ s->session->tlsext_ecpointformatlist_length = 0;
+ if ((s->session->tlsext_ecpointformatlist =
+ OPENSSL_malloc(ecpointformatlist_length)) == NULL) {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ s->session->tlsext_ecpointformatlist_length =
+ ecpointformatlist_length;
+ memcpy(s->session->tlsext_ecpointformatlist, sdata,
+ ecpointformatlist_length);
+ }
+# if 0
+ fprintf(stderr,
+ "ssl_parse_clienthello_tlsext s->session->tlsext_ecpointformatlist (length=%i) ",
+ s->session->tlsext_ecpointformatlist_length);
+ sdata = s->session->tlsext_ecpointformatlist;
+ for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+ fprintf(stderr, "%i ", *(sdata++));
+ fprintf(stderr, "\n");
+# endif
+ } else if (type == TLSEXT_TYPE_elliptic_curves) {
+ unsigned char *sdata = data;
+ int ellipticcurvelist_length = (*(sdata++) << 8);
+ ellipticcurvelist_length += (*(sdata++));
+
+ if (ellipticcurvelist_length != size - 2 ||
+ ellipticcurvelist_length < 1 ||
+ /* Each NamedCurve is 2 bytes. */
+ ellipticcurvelist_length & 1) {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (!s->hit) {
+ if (s->session->tlsext_ellipticcurvelist) {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ s->session->tlsext_ellipticcurvelist_length = 0;
+ if ((s->session->tlsext_ellipticcurvelist =
+ OPENSSL_malloc(ellipticcurvelist_length)) == NULL) {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ s->session->tlsext_ellipticcurvelist_length =
+ ellipticcurvelist_length;
+ memcpy(s->session->tlsext_ellipticcurvelist, sdata,
+ ellipticcurvelist_length);
+ }
+# if 0
+ fprintf(stderr,
+ "ssl_parse_clienthello_tlsext s->session->tlsext_ellipticcurvelist (length=%i) ",
+ s->session->tlsext_ellipticcurvelist_length);
+ sdata = s->session->tlsext_ellipticcurvelist;
+ for (i = 0; i < s->session->tlsext_ellipticcurvelist_length; i++)
+ fprintf(stderr, "%i ", *(sdata++));
+ fprintf(stderr, "\n");
+# endif
+ }
+# 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;
+ }
+ } else if (type == TLSEXT_TYPE_signature_algorithms) {
+ int dsize;
+ if (s->cert->peer_sigalgs || size < 2) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ n2s(data, dsize);
+ size -= 2;
+ if (dsize != size || dsize & 1 || !dsize) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (!tls1_save_sigalgs(s, data, dsize)) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ } else if (type == TLSEXT_TYPE_status_request) {
+
+ if (size < 5) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ s->tlsext_status_type = *data++;
+ size--;
+ if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp) {
+ const unsigned char *sdata;
+ int dsize;
+ /* Read in responder_id_list */
+ n2s(data, dsize);
+ size -= 2;
+ if (dsize > size) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ while (dsize > 0) {
+ OCSP_RESPID *id;
+ int idsize;
+ if (dsize < 4) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ n2s(data, idsize);
+ dsize -= 2 + idsize;
+ size -= 2 + idsize;
+ if (dsize < 0) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ sdata = data;
+ data += idsize;
+ id = d2i_OCSP_RESPID(NULL, &sdata, idsize);
+ if (!id) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (data != sdata) {
+ OCSP_RESPID_free(id);
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (!s->tlsext_ocsp_ids
+ && !(s->tlsext_ocsp_ids =
+ sk_OCSP_RESPID_new_null())) {
+ OCSP_RESPID_free(id);
+ *al = SSL_AD_INTERNAL_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 (size < 2) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ n2s(data, dsize);
+ size -= 2;
+ if (dsize != size) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ sdata = data;
+ if (dsize > 0) {
+ if (s->tlsext_ocsp_exts) {
+ sk_X509_EXTENSION_pop_free(s->tlsext_ocsp_exts,
+ X509_EXTENSION_free);
+ }
+
+ s->tlsext_ocsp_exts =
+ d2i_X509_EXTENSIONS(NULL, &sdata, dsize);
+ if (!s->tlsext_ocsp_exts || (data + dsize != sdata)) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ }
+ }
+ /*
+ * We don't know what to do with any other type * so ignore it.
+ */
+ else
+ s->tlsext_status_type = -1;
+ }
+# ifndef OPENSSL_NO_HEARTBEATS
+ else if (type == TLSEXT_TYPE_heartbeat) {
+ switch (data[0]) {
+ case 0x01: /* Client allows us to send HB requests */
+ s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
+ break;
+ case 0x02: /* Client doesn't accept HB requests */
+ s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
+ s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
+ break;
+ default:
+ *al = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+ }
+# endif
+# ifndef OPENSSL_NO_NEXTPROTONEG
+ else if (type == TLSEXT_TYPE_next_proto_neg &&
+ s->s3->tmp.finish_md_len == 0 &&
+ s->s3->alpn_selected == NULL) {
+ /*-
+ * 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 renegotation 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;
+ }
+# endif
+
+ else if (type == TLSEXT_TYPE_application_layer_protocol_negotiation &&
+ s->ctx->alpn_select_cb && s->s3->tmp.finish_md_len == 0) {
+ if (tls1_alpn_handle_client_hello(s, data, size, al) != 0)
+ return 0;
+# ifndef OPENSSL_NO_NEXTPROTONEG
+ /* ALPN takes precedence over NPN. */
+ s->s3->next_proto_neg_seen = 0;
+# endif
+ }
+
+ /* session ticket processed earlier */
+# ifndef OPENSSL_NO_SRTP
+ else if (SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s)
+ && type == TLSEXT_TYPE_use_srtp) {
+ if (ssl_parse_clienthello_use_srtp_ext(s, data, size, al))
+ return 0;
+ }
+# endif
+# ifdef TLSEXT_TYPE_encrypt_then_mac
+ else if (type == TLSEXT_TYPE_encrypt_then_mac)
+ s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC;
+# endif
+ /*
+ * If this ClientHello extension was unhandled and this is a
+ * nonresumed connection, check whether the extension is a custom
+ * TLS Extension (has a custom_srv_ext_record), and if so call the
+ * callback and record the extension number so that an appropriate
+ * ServerHello may be later returned.
+ */
+ else if (!s->hit) {
+ if (custom_ext_parse(s, 1, type, data, size, al) <= 0)
+ return 0;
+ }
+
+ data += size;
+ }
+
+ *p = data;
+
+ ri_check:
+
+ /* Need RI if renegotiating */
+
+ if (!renegotiate_seen && s->renegotiate &&
+ !(s->options & SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
+ *al = SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT,
+ SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+ return 0;
+ }
+
+ return 1;
+}
+
+int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
+ int n)
+{
+ int al = -1;
+ custom_ext_init(&s->cert->srv_ext);
+ if (ssl_scan_clienthello_tlsext(s, p, d, n, &al) <= 0) {
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ return 0;
+ }
+
+ if (ssl_check_clienthello_tlsext_early(s) <= 0) {
+ SSLerr(SSL_F_SSL_PARSE_CLIENTHELLO_TLSEXT, SSL_R_CLIENTHELLO_TLSEXT);
+ return 0;
+ }
+ 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(unsigned char *d, unsigned len)
+{
+ unsigned int off = 0;
+
+ while (off < len) {
+ if (d[off] == 0)
+ return 0;
+ off += d[off];
+ off++;
+ }
+
+ return off == len;
+}
+# endif
+
+static int ssl_scan_serverhello_tlsext(SSL *s, unsigned char **p,
+ unsigned char *d, int n, int *al)
+{
+ unsigned short length;
+ unsigned short type;
+ unsigned short size;
+ unsigned char *data = *p;
+ 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;
+
+ if (s->s3->alpn_selected) {
+ OPENSSL_free(s->s3->alpn_selected);
+ s->s3->alpn_selected = NULL;
+ }
+# ifndef OPENSSL_NO_HEARTBEATS
+ s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
+ SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
+# endif
+
+# ifdef TLSEXT_TYPE_encrypt_then_mac
+ s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC;
+# endif
+
+ if (data >= (d + n - 2))
+ goto ri_check;
+
+ n2s(data, length);
+ if (data + length != d + n) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ while (data <= (d + n - 4)) {
+ n2s(data, type);
+ n2s(data, size);
+
+ if (data + size > (d + n))
+ 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, data, size, 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 char *sdata = data;
+ int ecpointformatlist_length = *(sdata++);
+
+ if (ecpointformatlist_length != size - 1) {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (!s->hit) {
+ s->session->tlsext_ecpointformatlist_length = 0;
+ if (s->session->tlsext_ecpointformatlist != NULL)
+ 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;
+ memcpy(s->session->tlsext_ecpointformatlist, sdata,
+ ecpointformatlist_length);
+ }
+# if 0
+ fprintf(stderr,
+ "ssl_parse_serverhello_tlsext s->session->tlsext_ecpointformatlist ");
+ sdata = s->session->tlsext_ecpointformatlist;
+ for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+ fprintf(stderr, "%i ", *(sdata++));
+ fprintf(stderr, "\n");
+# endif
+ }
+# 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_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(data, size)) {
+ *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;
+ }
+ s->next_proto_negotiated = OPENSSL_malloc(selected_len);
+ if (!s->next_proto_negotiated) {
+ *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->alpn_client_proto_list == NULL) {
+ *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+ return 0;
+ }
+ if (size < 4) {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ /*-
+ * The extension data consists of:
+ * uint16 list_length
+ * uint8 proto_length;
+ * uint8 proto[proto_length];
+ */
+ len = data[0];
+ len <<= 8;
+ len |= data[1];
+ if (len != (unsigned)size - 2) {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ len = data[2];
+ if (len != (unsigned)size - 3) {
+ *al = TLS1_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (s->s3->alpn_selected)
+ OPENSSL_free(s->s3->alpn_selected);
+ s->s3->alpn_selected = OPENSSL_malloc(len);
+ if (!s->s3->alpn_selected) {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ memcpy(s->s3->alpn_selected, data + 3, len);
+ s->s3->alpn_selected_len = len;
+ }
+# ifndef OPENSSL_NO_HEARTBEATS
+ else if (type == TLSEXT_TYPE_heartbeat) {
+ switch (data[0]) {
+ case 0x01: /* Server allows us to send HB requests */
+ s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
+ break;
+ case 0x02: /* Server doesn't accept HB requests */
+ s->tlsext_heartbeat |= SSL_TLSEXT_HB_ENABLED;
+ s->tlsext_heartbeat |= SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
+ break;
+ default:
+ *al = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+ }
+# endif
+# ifndef OPENSSL_NO_SRTP
+ else if (SSL_IS_DTLS(s) && type == TLSEXT_TYPE_use_srtp) {
+ if (ssl_parse_serverhello_use_srtp_ext(s, data, size, al))
+ return 0;
+ }
+# endif
+# ifdef TLSEXT_TYPE_encrypt_then_mac
+ else if (type == TLSEXT_TYPE_encrypt_then_mac) {
+ /* Ignore if inappropriate ciphersuite */
+ if (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;
+ }
+# endif
+ /*
+ * 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;
+
+ data += size;
+ }
+
+ if (data != d + n) {
+ *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 = BUF_strdup(s->tlsext_hostname);
+ if (!s->session->tlsext_hostname) {
+ *al = SSL_AD_UNRECOGNIZED_NAME;
+ return 0;
+ }
+ } else {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ }
+ }
+
+ *p = data;
+
+ 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 on
+ * initial connect only.
+ */
+ 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;
+ }
+
+ return 1;
+}