+ s2n(TLSEXT_TYPE_elliptic_curves, ret);
+ s2n(s->tlsext_ellipticcurvelist_length + 2, ret);
+
+ s2n(s->tlsext_ellipticcurvelist_length, ret);
+ memcpy(ret, s->tlsext_ellipticcurvelist,
+ s->tlsext_ellipticcurvelist_length);
+ ret += s->tlsext_ellipticcurvelist_length;
+ }
+# endif /* OPENSSL_NO_EC */
+
+ if (!(SSL_get_options(s) & SSL_OP_NO_TICKET)) {
+ int ticklen;
+ if (!s->new_session && s->session && s->session->tlsext_tick)
+ ticklen = s->session->tlsext_ticklen;
+ else if (s->session && s->tlsext_session_ticket &&
+ s->tlsext_session_ticket->data) {
+ ticklen = s->tlsext_session_ticket->length;
+ s->session->tlsext_tick = OPENSSL_malloc(ticklen);
+ if (!s->session->tlsext_tick)
+ return NULL;
+ memcpy(s->session->tlsext_tick,
+ s->tlsext_session_ticket->data, ticklen);
+ s->session->tlsext_ticklen = ticklen;
+ } else
+ ticklen = 0;
+ if (ticklen == 0 && s->tlsext_session_ticket &&
+ s->tlsext_session_ticket->data == NULL)
+ goto skip_ext;
+ /*
+ * Check for enough room 2 for extension type, 2 for len rest for
+ * ticket
+ */
+ if ((long)(limit - ret - 4 - ticklen) < 0)
+ return NULL;
+ s2n(TLSEXT_TYPE_session_ticket, ret);
+ s2n(ticklen, ret);
+ if (ticklen) {
+ memcpy(ret, s->session->tlsext_tick, ticklen);
+ ret += ticklen;
+ }
+ }
+ skip_ext:
+
+ if (TLS1_get_client_version(s) >= TLS1_2_VERSION) {
+ if ((size_t)(limit - ret) < sizeof(tls12_sigalgs) + 6)
+ return NULL;
+ s2n(TLSEXT_TYPE_signature_algorithms, ret);
+ s2n(sizeof(tls12_sigalgs) + 2, ret);
+ s2n(sizeof(tls12_sigalgs), ret);
+ memcpy(ret, tls12_sigalgs, sizeof(tls12_sigalgs));
+ ret += sizeof(tls12_sigalgs);
+ }
+# ifdef TLSEXT_TYPE_opaque_prf_input
+ if (s->s3->client_opaque_prf_input != NULL && s->version != DTLS1_VERSION) {
+ size_t col = s->s3->client_opaque_prf_input_len;
+
+ if ((long)(limit - ret - 6 - col < 0))
+ return NULL;
+ if (col > 0xFFFD) /* can't happen */
+ return NULL;
+
+ s2n(TLSEXT_TYPE_opaque_prf_input, ret);
+ s2n(col + 2, ret);
+ s2n(col, ret);
+ memcpy(ret, s->s3->client_opaque_prf_input, col);
+ ret += col;
+ }
+# endif
+
+ if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
+ s->version != DTLS1_VERSION) {
+ int i;
+ long extlen, idlen, itmp;
+ OCSP_RESPID *id;
+
+ idlen = 0;
+ for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) {
+ id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
+ itmp = i2d_OCSP_RESPID(id, NULL);
+ if (itmp <= 0)
+ return NULL;
+ idlen += itmp + 2;
+ }
+
+ if (s->tlsext_ocsp_exts) {
+ extlen = i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, NULL);
+ if (extlen < 0)
+ return NULL;
+ } else
+ extlen = 0;
+
+ if ((long)(limit - ret - 7 - extlen - idlen) < 0)
+ return NULL;
+ s2n(TLSEXT_TYPE_status_request, ret);
+ if (extlen + idlen > 0xFFF0)
+ return NULL;
+ s2n(extlen + idlen + 5, ret);
+ *(ret++) = TLSEXT_STATUSTYPE_ocsp;
+ s2n(idlen, ret);
+ for (i = 0; i < sk_OCSP_RESPID_num(s->tlsext_ocsp_ids); i++) {
+ /* save position of id len */
+ unsigned char *q = ret;
+ id = sk_OCSP_RESPID_value(s->tlsext_ocsp_ids, i);
+ /* skip over id len */
+ ret += 2;
+ itmp = i2d_OCSP_RESPID(id, &ret);
+ /* write id len */
+ s2n(itmp, q);
+ }
+ s2n(extlen, ret);
+ if (extlen > 0)
+ i2d_X509_EXTENSIONS(s->tlsext_ocsp_exts, &ret);
+ }
+# ifndef OPENSSL_NO_HEARTBEATS
+ /* Add Heartbeat extension */
+ if ((limit - ret - 4 - 1) < 0)
+ return NULL;
+ s2n(TLSEXT_TYPE_heartbeat, ret);
+ s2n(1, ret);
+ /*-
+ * Set mode:
+ * 1: peer may send requests
+ * 2: peer not allowed to send requests
+ */
+ if (s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_RECV_REQUESTS)
+ *(ret++) = SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
+ else
+ *(ret++) = SSL_TLSEXT_HB_ENABLED;
+# endif
+
+# ifndef OPENSSL_NO_NEXTPROTONEG
+ if (s->ctx->next_proto_select_cb && !s->s3->tmp.finish_md_len) {
+ /*
+ * The client advertises an emtpy extension to indicate its support
+ * for Next Protocol Negotiation
+ */
+ if (limit - ret - 4 < 0)
+ return NULL;
+ s2n(TLSEXT_TYPE_next_proto_neg, ret);
+ s2n(0, ret);
+ }
+# endif
+
+# ifndef OPENSSL_NO_SRTP
+ if (SSL_IS_DTLS(s) && SSL_get_srtp_profiles(s)) {
+ int el;
+
+ ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0);
+
+ if ((limit - ret - 4 - el) < 0)
+ return NULL;
+
+ s2n(TLSEXT_TYPE_use_srtp, ret);
+ s2n(el, ret);
+
+ if (ssl_add_clienthello_use_srtp_ext(s, ret, &el, el)) {
+ SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+ ret += el;
+ }
+# endif
+ /*
+ * Add padding to workaround bugs in F5 terminators. See
+ * https://tools.ietf.org/html/draft-agl-tls-padding-03 NB: because this
+ * code works out the length of all existing extensions it MUST always
+ * appear last.
+ */
+ if (s->options & SSL_OP_TLSEXT_PADDING) {
+ int hlen = ret - (unsigned char *)s->init_buf->data;
+ /*
+ * The code in s23_clnt.c to build ClientHello messages includes the
+ * 5-byte record header in the buffer, while the code in s3_clnt.c
+ * does not.
+ */
+ if (s->state == SSL23_ST_CW_CLNT_HELLO_A)
+ hlen -= 5;
+ if (hlen > 0xff && hlen < 0x200) {
+ hlen = 0x200 - hlen;
+ if (hlen >= 4)
+ hlen -= 4;
+ else
+ hlen = 0;
+
+ s2n(TLSEXT_TYPE_padding, ret);
+ s2n(hlen, ret);
+ memset(ret, 0, hlen);
+ ret += hlen;
+ }
+ }
+
+ if ((extdatalen = ret - orig - 2) == 0)
+ return orig;
+
+ s2n(extdatalen, orig);
+ return ret;
+}
+
+unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
+ unsigned char *limit)
+{
+ int extdatalen = 0;
+ unsigned char *orig = buf;
+ unsigned char *ret = buf;
+# ifndef OPENSSL_NO_NEXTPROTONEG
+ int next_proto_neg_seen;
+# endif
+
+ /*
+ * don't add extensions for SSLv3, unless doing secure renegotiation
+ */
+ if (s->version == SSL3_VERSION && !s->s3->send_connection_binding)
+ return orig;
+
+ ret += 2;
+ if (ret >= limit)
+ return NULL; /* this really never occurs, but ... */
+
+ if (!s->hit && s->servername_done == 1
+ && s->session->tlsext_hostname != NULL) {
+ if ((long)(limit - ret - 4) < 0)
+ return NULL;
+
+ s2n(TLSEXT_TYPE_server_name, ret);
+ s2n(0, ret);
+ }
+
+ if (s->s3->send_connection_binding) {
+ int el;
+
+ if (!ssl_add_serverhello_renegotiate_ext(s, 0, &el, 0)) {
+ SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ if ((limit - ret - 4 - el) < 0)
+ return NULL;
+
+ s2n(TLSEXT_TYPE_renegotiate, ret);
+ s2n(el, ret);
+
+ if (!ssl_add_serverhello_renegotiate_ext(s, ret, &el, el)) {
+ SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ ret += el;
+ }
+# ifndef OPENSSL_NO_EC
+ if (s->tlsext_ecpointformatlist != NULL) {
+ /*
+ * Add TLS extension ECPointFormats to the ServerHello message
+ */
+ long lenmax;
+
+ if ((lenmax = limit - ret - 5) < 0)
+ return NULL;
+ if (s->tlsext_ecpointformatlist_length > (unsigned long)lenmax)
+ return NULL;
+ if (s->tlsext_ecpointformatlist_length > 255) {
+ SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ s2n(TLSEXT_TYPE_ec_point_formats, ret);
+ s2n(s->tlsext_ecpointformatlist_length + 1, ret);
+ *(ret++) = (unsigned char)s->tlsext_ecpointformatlist_length;
+ memcpy(ret, s->tlsext_ecpointformatlist,
+ s->tlsext_ecpointformatlist_length);
+ ret += s->tlsext_ecpointformatlist_length;
+
+ }
+ /*
+ * Currently the server should not respond with a SupportedCurves
+ * extension
+ */
+# endif /* OPENSSL_NO_EC */
+
+ if (s->tlsext_ticket_expected && !(SSL_get_options(s) & SSL_OP_NO_TICKET)) {
+ if ((long)(limit - ret - 4) < 0)
+ return NULL;
+ s2n(TLSEXT_TYPE_session_ticket, ret);
+ s2n(0, ret);
+ }
+
+ if (s->tlsext_status_expected) {
+ if ((long)(limit - ret - 4) < 0)
+ return NULL;
+ s2n(TLSEXT_TYPE_status_request, ret);
+ s2n(0, ret);
+ }
+# ifdef TLSEXT_TYPE_opaque_prf_input
+ if (s->s3->server_opaque_prf_input != NULL && s->version != DTLS1_VERSION) {
+ size_t sol = s->s3->server_opaque_prf_input_len;
+
+ if ((long)(limit - ret - 6 - sol) < 0)
+ return NULL;
+ if (sol > 0xFFFD) /* can't happen */
+ return NULL;
+
+ s2n(TLSEXT_TYPE_opaque_prf_input, ret);
+ s2n(sol + 2, ret);
+ s2n(sol, ret);
+ memcpy(ret, s->s3->server_opaque_prf_input, sol);
+ ret += sol;
+ }
+# endif
+
+# ifndef OPENSSL_NO_SRTP
+ if (SSL_IS_DTLS(s) && s->srtp_profile) {
+ int el;
+
+ ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0);
+
+ if ((limit - ret - 4 - el) < 0)
+ return NULL;
+
+ s2n(TLSEXT_TYPE_use_srtp, ret);
+ s2n(el, ret);
+
+ if (ssl_add_serverhello_use_srtp_ext(s, ret, &el, el)) {
+ SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+ ret += el;
+ }
+# endif
+
+ if (((s->s3->tmp.new_cipher->id & 0xFFFF) == 0x80
+ || (s->s3->tmp.new_cipher->id & 0xFFFF) == 0x81)
+ && (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG)) {
+ const unsigned char cryptopro_ext[36] = {
+ 0xfd, 0xe8, /* 65000 */
+ 0x00, 0x20, /* 32 bytes length */
+ 0x30, 0x1e, 0x30, 0x08, 0x06, 0x06, 0x2a, 0x85,
+ 0x03, 0x02, 0x02, 0x09, 0x30, 0x08, 0x06, 0x06,
+ 0x2a, 0x85, 0x03, 0x02, 0x02, 0x16, 0x30, 0x08,
+ 0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x17
+ };
+ if (limit - ret < 36)
+ return NULL;
+ memcpy(ret, cryptopro_ext, 36);
+ ret += 36;
+
+ }
+# ifndef OPENSSL_NO_HEARTBEATS
+ /* Add Heartbeat extension if we've received one */
+ if (s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) {
+ if ((limit - ret - 4 - 1) < 0)
+ return NULL;
+ s2n(TLSEXT_TYPE_heartbeat, ret);
+ s2n(1, ret);
+ /*-
+ * Set mode:
+ * 1: peer may send requests
+ * 2: peer not allowed to send requests
+ */
+ if (s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_RECV_REQUESTS)
+ *(ret++) = SSL_TLSEXT_HB_DONT_SEND_REQUESTS;
+ else
+ *(ret++) = SSL_TLSEXT_HB_ENABLED;
+
+ }
+# endif
+
+# ifndef OPENSSL_NO_NEXTPROTONEG
+ next_proto_neg_seen = s->s3->next_proto_neg_seen;
+ s->s3->next_proto_neg_seen = 0;
+ if (next_proto_neg_seen && s->ctx->next_protos_advertised_cb) {
+ const unsigned char *npa;
+ unsigned int npalen;
+ int r;
+
+ r = s->ctx->next_protos_advertised_cb(s, &npa, &npalen,
+ s->
+ ctx->next_protos_advertised_cb_arg);
+ if (r == SSL_TLSEXT_ERR_OK) {
+ if ((long)(limit - ret - 4 - npalen) < 0)
+ return NULL;
+ s2n(TLSEXT_TYPE_next_proto_neg, ret);
+ s2n(npalen, ret);
+ memcpy(ret, npa, npalen);
+ ret += npalen;
+ s->s3->next_proto_neg_seen = 1;
+ }
+ }
+# endif
+
+ if ((extdatalen = ret - orig - 2) == 0)
+ return orig;
+
+ s2n(extdatalen, orig);
+ return ret;
+}
+
+# ifndef OPENSSL_NO_EC
+/*-
+ * ssl_check_for_safari attempts to fingerprint Safari using OS X
+ * SecureTransport using the TLS extension block in |d|, of length |n|.
+ * Safari, since 10.6, sends exactly these extensions, in this order:
+ * SNI,
+ * elliptic_curves
+ * ec_point_formats
+ *
+ * We wish to fingerprint Safari because they broke ECDHE-ECDSA support in 10.8,
+ * but they advertise support. So enabling ECDHE-ECDSA ciphers breaks them.
+ * Sadly we cannot differentiate 10.6, 10.7 and 10.8.4 (which work), from
+ * 10.8..10.8.3 (which don't work).
+ */
+static void ssl_check_for_safari(SSL *s, const unsigned char *data,
+ const unsigned char *d, int n)
+{
+ unsigned short type, size;
+ static const unsigned char kSafariExtensionsBlock[] = {
+ 0x00, 0x0a, /* elliptic_curves extension */
+ 0x00, 0x08, /* 8 bytes */
+ 0x00, 0x06, /* 6 bytes of curve ids */
+ 0x00, 0x17, /* P-256 */
+ 0x00, 0x18, /* P-384 */
+ 0x00, 0x19, /* P-521 */
+
+ 0x00, 0x0b, /* ec_point_formats */
+ 0x00, 0x02, /* 2 bytes */
+ 0x01, /* 1 point format */
+ 0x00, /* uncompressed */
+ };
+
+ /* The following is only present in TLS 1.2 */
+ static const unsigned char kSafariTLS12ExtensionsBlock[] = {
+ 0x00, 0x0d, /* signature_algorithms */
+ 0x00, 0x0c, /* 12 bytes */
+ 0x00, 0x0a, /* 10 bytes */
+ 0x05, 0x01, /* SHA-384/RSA */
+ 0x04, 0x01, /* SHA-256/RSA */
+ 0x02, 0x01, /* SHA-1/RSA */
+ 0x04, 0x03, /* SHA-256/ECDSA */
+ 0x02, 0x03, /* SHA-1/ECDSA */
+ };
+
+ if (data >= (d + n - 2))
+ return;
+ data += 2;
+
+ if (data > (d + n - 4))
+ return;
+ n2s(data, type);
+ n2s(data, size);
+
+ if (type != TLSEXT_TYPE_server_name)
+ return;
+
+ if (data + size > d + n)
+ return;
+ data += size;
+
+ if (TLS1_get_client_version(s) >= TLS1_2_VERSION) {
+ const size_t len1 = sizeof(kSafariExtensionsBlock);
+ const size_t len2 = sizeof(kSafariTLS12ExtensionsBlock);
+
+ if (data + len1 + len2 != d + n)
+ return;
+ if (memcmp(data, kSafariExtensionsBlock, len1) != 0)
+ return;
+ if (memcmp(data + len1, kSafariTLS12ExtensionsBlock, len2) != 0)
+ return;
+ } else {
+ const size_t len = sizeof(kSafariExtensionsBlock);
+
+ if (data + len != d + n)
+ return;
+ if (memcmp(data, kSafariExtensionsBlock, len) != 0)
+ return;
+ }
+
+ s->s3->is_probably_safari = 1;
+}
+# endif /* !OPENSSL_NO_EC */
+
+int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d,
+ int n, int *al)
+{
+ unsigned short type;
+ unsigned short size;
+ unsigned short len;
+ unsigned char *data = *p;
+ int renegotiate_seen = 0;
+ int sigalg_seen = 0;
+
+ s->servername_done = 0;
+ s->tlsext_status_type = -1;
+# ifndef OPENSSL_NO_NEXTPROTONEG
+ s->s3->next_proto_neg_seen = 0;
+# endif
+
+# ifndef OPENSSL_NO_HEARTBEATS
+ s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
+ SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
+# endif
+
+# ifndef OPENSSL_NO_EC
+ if (s->options & SSL_OP_SAFARI_ECDHE_ECDSA_BUG)
+ ssl_check_for_safari(s, data, d, n);
+# endif /* !OPENSSL_NO_EC */
+
+# ifndef OPENSSL_NO_SRP
+ if (s->srp_ctx.login != NULL) {
+ OPENSSL_free(s->srp_ctx.login);
+ s->srp_ctx.login = NULL;
+ }
+# endif
+
+ s->srtp_profile = NULL;
+
+ if (data >= (d + n - 2))
+ goto ri_check;
+ n2s(data, len);
+
+ if (data > (d + n - len))
+ goto ri_check;
+
+ while (data <= (d + n - 4)) {
+ n2s(data, type);
+ n2s(data, size);
+
+ if (data + size > (d + n))
+ goto ri_check;
+# if 0
+ fprintf(stderr, "Received extension type %d size %d\n", type, size);
+# endif
+ if (s->tlsext_debug_cb)
+ s->tlsext_debug_cb(s, 0, type, data, size, s->tlsext_debug_arg);
+/*-
+ * 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 (type == TLSEXT_TYPE_server_name) {
+ unsigned char *sdata;
+ int servname_type;
+ int dsize;
+
+ 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;
+ while (dsize > 3) {
+ servname_type = *(sdata++);
+ n2s(sdata, len);
+ dsize -= 3;
+
+ if (len > dsize) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (s->servername_done == 0)
+ switch (servname_type) {
+ case TLSEXT_NAMETYPE_host_name:
+ if (!s->hit) {
+ if (s->session->tlsext_hostname) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (len > TLSEXT_MAXLEN_host_name) {
+ *al = TLS1_AD_UNRECOGNIZED_NAME;
+ return 0;
+ }
+ if ((s->session->tlsext_hostname =
+ OPENSSL_malloc(len + 1)) == NULL) {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ memcpy(s->session->tlsext_hostname, sdata, len);
+ s->session->tlsext_hostname[len] = '\0';
+ if (strlen(s->session->tlsext_hostname) != len) {
+ OPENSSL_free(s->session->tlsext_hostname);
+ s->session->tlsext_hostname = NULL;
+ *al = TLS1_AD_UNRECOGNIZED_NAME;
+ return 0;
+ }
+ s->servername_done = 1;
+
+ } else
+ s->servername_done = s->session->tlsext_hostname
+ && strlen(s->session->tlsext_hostname) == len
+ && strncmp(s->session->tlsext_hostname,
+ (char *)sdata, len) == 0;
+
+ break;
+
+ default:
+ break;
+ }
+
+ 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) {
+ *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 */
+# ifdef TLSEXT_TYPE_opaque_prf_input
+ else if (type == TLSEXT_TYPE_opaque_prf_input &&
+ s->version != DTLS1_VERSION) {
+ unsigned char *sdata = data;
+
+ if (size < 2) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ n2s(sdata, s->s3->client_opaque_prf_input_len);
+ if (s->s3->client_opaque_prf_input_len != size - 2) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ if (s->s3->client_opaque_prf_input != NULL) {
+ /* shouldn't really happen */
+ OPENSSL_free(s->s3->client_opaque_prf_input);
+ }
+
+ /* dummy byte just to get non-NULL */
+ if (s->s3->client_opaque_prf_input_len == 0)
+ s->s3->client_opaque_prf_input = OPENSSL_malloc(1);
+ else
+ s->s3->client_opaque_prf_input =
+ BUF_memdup(sdata, s->s3->client_opaque_prf_input_len);
+ if (s->s3->client_opaque_prf_input == NULL) {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
+# endif
+ 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_renegotiate) {
+ if (!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
+ return 0;
+ renegotiate_seen = 1;
+ } else if (type == TLSEXT_TYPE_signature_algorithms) {
+ int dsize;
+ if (sigalg_seen || size < 2) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ sigalg_seen = 1;
+ n2s(data, dsize);
+ size -= 2;
+ if (dsize != size || dsize & 1) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ if (!tls1_process_sigalgs(s, data, dsize)) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ } else if (type == TLSEXT_TYPE_status_request &&
+ s->version != DTLS1_VERSION) {
+
+ 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) {
+ /*-
+ * 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
+
+ /* 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
+
+ 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_PARSE_CLIENTHELLO_TLSEXT,
+ SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+ 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
+
+int ssl_parse_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;
+
+# ifndef OPENSSL_NO_HEARTBEATS
+ s->tlsext_heartbeat &= ~(SSL_TLSEXT_HB_ENABLED |
+ SSL_TLSEXT_HB_DONT_SEND_REQUESTS);
+# 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_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 ||
+ ecpointformatlist_length < 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 ((SSL_get_options(s) & SSL_OP_NO_TICKET)
+ || (size > 0)) {
+ *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+ return 0;
+ }
+ s->tlsext_ticket_expected = 1;
+ }
+# ifdef TLSEXT_TYPE_opaque_prf_input
+ else if (type == TLSEXT_TYPE_opaque_prf_input &&
+ s->version != DTLS1_VERSION) {
+ unsigned char *sdata = data;
+
+ if (size < 2) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ n2s(sdata, s->s3->server_opaque_prf_input_len);
+ if (s->s3->server_opaque_prf_input_len != size - 2) {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ if (s->s3->server_opaque_prf_input != NULL) {
+ /* shouldn't really happen */
+ OPENSSL_free(s->s3->server_opaque_prf_input);
+ }
+ if (s->s3->server_opaque_prf_input_len == 0) {
+ /* dummy byte just to get non-NULL */
+ s->s3->server_opaque_prf_input = OPENSSL_malloc(1);
+ } else {
+ s->s3->server_opaque_prf_input =
+ BUF_memdup(sdata, s->s3->server_opaque_prf_input_len);
+ }
+
+ if (s->s3->server_opaque_prf_input == NULL) {
+ *al = TLS1_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ }
+# endif
+ else if (type == TLSEXT_TYPE_status_request &&
+ s->version != DTLS1_VERSION) {
+ /*
+ * 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_renegotiate) {
+ if (!ssl_parse_serverhello_renegotiate_ext(s, data, size, al))
+ return 0;
+ renegotiate_seen = 1;
+ }
+# 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
+
+ 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_PARSE_SERVERHELLO_TLSEXT,
+ SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+ return 0;
+ }
+
+ return 1;
+}