- /* If custom types were sent in ClientHello, add ServerHello responses */
- if (s->s3->tlsext_custom_types_count)
- {
- size_t i;
-
- for (i = 0; i < s->s3->tlsext_custom_types_count; i++)
- {
- size_t j;
- custom_srv_ext_record *record;
-
- for (j = 0; j < s->ctx->custom_srv_ext_records_count; j++)
- {
- record = &s->ctx->custom_srv_ext_records[j];
- if (s->s3->tlsext_custom_types[i] == record->ext_type)
- {
- const unsigned char *out = NULL;
- unsigned short outlen = 0;
- int cb_retval = 0;
-
- /* NULL callback or -1 omits extension */
- if (!record->fn2)
- break;
- cb_retval = record->fn2(s, record->ext_type,
- &out, &outlen,
- record->arg);
- if (cb_retval == 0)
- return NULL; /* error */
- if (cb_retval == -1)
- break; /* skip this extension */
- if (limit < ret + 4 + outlen)
- return NULL;
- s2n(record->ext_type, ret);
- s2n(outlen, ret);
- memcpy(ret, out, outlen);
- ret += outlen;
- break;
- }
- }
- }
- }
-
- if (s->s3->alpn_selected)
- {
- const unsigned char *selected = s->s3->alpn_selected;
- unsigned len = s->s3->alpn_selected_len;
-
- if ((long)(limit - ret - 4 - 2 - 1 - len) < 0)
- return NULL;
- s2n(TLSEXT_TYPE_application_layer_protocol_negotiation,ret);
- s2n(3 + len,ret);
- s2n(1 + len,ret);
- *ret++ = len;
- memcpy(ret, selected, len);
- ret += len;
- }
-
- if ((extdatalen = ret-p-2)== 0)
- return p;
-
- s2n(extdatalen,p);
- return ret;
- }
-
-/* tls1_alpn_handle_client_hello is called to process the ALPN extension in a
- * ClientHello.
- * data: the contents of the extension, not including the type and length.
- * data_len: the number of bytes in |data|
- * al: a pointer to the alert value to send in the event of a non-zero
- * return.
- *
- * returns: 0 on success. */
+ 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
+ custom_ext_init(&s->cert->cli_ext);
+ /* Add custom TLS Extensions to ClientHello */
+ if (!custom_ext_add(s, 0, &ret, limit, al))
+ return NULL;
+# ifdef TLSEXT_TYPE_encrypt_then_mac
+ s2n(TLSEXT_TYPE_encrypt_then_mac, ret);
+ s2n(0, ret);
+# endif
+ s2n(TLSEXT_TYPE_extended_master_secret, ret);
+ s2n(0, ret);
+
+ /*
+ * 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;
+ }
+ }
+
+ done:
+
+ 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 *al)
+{
+ int extdatalen = 0;
+ unsigned char *orig = buf;
+ unsigned char *ret = buf;
+# ifndef OPENSSL_NO_NEXTPROTONEG
+ int next_proto_neg_seen;
+# endif
+# ifndef OPENSSL_NO_EC
+ unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+ unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+ int using_ecc = (alg_k & (SSL_kECDHE | SSL_kECDHr | SSL_kECDHe))
+ || (alg_a & SSL_aECDSA);
+ using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
+# endif
+
+ ret += 2;
+ if (ret >= limit)
+ return NULL; /* this really never occurs, but ... */
+
+ 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;
+ }
+
+ /* Only add RI for SSLv3 */
+ if (s->version == SSL3_VERSION)
+ goto done;
+
+ 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);
+ }
+# ifndef OPENSSL_NO_EC
+ if (using_ecc) {
+ const unsigned char *plist;
+ size_t plistlen;
+ /*
+ * Add TLS extension ECPointFormats to the ServerHello message
+ */
+ long lenmax;
+
+ tls1_get_formatlist(s, &plist, &plistlen);
+
+ if ((lenmax = limit - ret - 5) < 0)
+ return NULL;
+ if (plistlen > (size_t)lenmax)
+ return NULL;
+ if (plistlen > 255) {
+ SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return NULL;
+ }
+
+ s2n(TLSEXT_TYPE_ec_point_formats, ret);
+ s2n(plistlen + 1, ret);
+ *(ret++) = (unsigned char)plistlen;
+ memcpy(ret, plist, plistlen);
+ ret += plistlen;
+
+ }
+ /*
+ * Currently the server should not respond with a SupportedCurves
+ * extension
+ */
+# endif /* OPENSSL_NO_EC */
+
+ if (s->tlsext_ticket_expected && tls_use_ticket(s)) {
+ 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);
+ }
+
+# ifndef OPENSSL_NO_SRTP
+ if (SSL_IS_DTLS(s) && s->srtp_profile) {
+ int el;
+
+ /* Returns 0 on success!! */
+ if (ssl_add_serverhello_use_srtp_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_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 (!custom_ext_add(s, 1, &ret, limit, al))
+ return NULL;
+# ifdef TLSEXT_TYPE_encrypt_then_mac
+ if (s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC) {
+ /*
+ * Don't use encrypt_then_mac if AEAD or RC4 might want to disable
+ * for other cases too.
+ */
+ 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;
+ else {
+ s2n(TLSEXT_TYPE_encrypt_then_mac, ret);
+ s2n(0, ret);
+ }
+ }
+# endif
+ if (!s->hit && s->session->flags & SSL_SESS_FLAG_EXTMS) {
+ s2n(TLSEXT_TYPE_extended_master_secret, ret);
+ s2n(0, ret);
+ }
+
+ if (s->s3->alpn_selected) {
+ const unsigned char *selected = s->s3->alpn_selected;
+ unsigned len = s->s3->alpn_selected_len;
+
+ if ((long)(limit - ret - 4 - 2 - 1 - len) < 0)
+ return NULL;
+ s2n(TLSEXT_TYPE_application_layer_protocol_negotiation, ret);
+ s2n(3 + len, ret);
+ s2n(1 + len, ret);
+ *ret++ = len;
+ memcpy(ret, selected, len);
+ ret += len;
+ }
+
+ done:
+
+ if ((extdatalen = ret - orig - 2) == 0)
+ return orig;
+
+ s2n(extdatalen, orig);
+ return ret;
+}
+
+/*
+ * tls1_alpn_handle_client_hello is called to process the ALPN extension in a
+ * ClientHello. data: the contents of the extension, not including the type
+ * and length. data_len: the number of bytes in |data| al: a pointer to the
+ * alert value to send in the event of a non-zero return. returns: 0 on
+ * success.
+ */