+/* 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 ||
+ 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)
+ {
+ *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)
+ {
+ 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);
+ if (s->s3->client_opaque_prf_input_len == 0)
+ s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
+ 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 (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_process_sigalgs(s, data, dsize))
+ {
+ *al = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+ /* If sigalgs received and no shared algorithms fatal
+ * error.
+ */
+ if (s->cert->peer_sigalgs && !s->cert->shared_sigalgs)
+ {
+ SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT,
+ SSL_R_NO_SHARED_SIGATURE_ALGORITHMS);
+ *al = SSL_AD_ILLEGAL_PARAMETER;
+ 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 */
+ else if (type == TLSEXT_TYPE_use_srtp)
+ {
+ if(ssl_parse_clienthello_use_srtp_ext(s, data, size,
+ al))
+ return 0;
+ }
+ /* 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 && s->ctx->custom_srv_ext_records_count)
+ {
+ custom_srv_ext_record *record;
+
+ for (i=0; i < s->ctx->custom_srv_ext_records_count; i++)
+ {
+ record = &s->ctx->custom_srv_ext_records[i];
+ if (type == record->ext_type)
+ {
+ if (record->fn1 && !record->fn1(s, type, data, size, al, record->arg))
+ return 0;
+ }
+ }
+ }
+#ifdef TLSEXT_TYPE_encrypt_then_mac
+ else if (type == TLSEXT_TYPE_encrypt_then_mac)
+ s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC;
+#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_SCAN_CLIENTHELLO_TLSEXT,
+ SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+ return 0;
+ }
+ /* If no signature algorithms extension set default values */
+ if (!s->cert->peer_sigalgs)
+ ssl_cert_set_default_md(s->cert);
+
+ return 1;
+ }
+
+int ssl_parse_clienthello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n)
+ {
+ int al = -1;
+ 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
+
+ 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_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;
+ }
+ 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;
+ }
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ else if (type == TLSEXT_TYPE_opaque_prf_input)
+ {
+ 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)
+ s->s3->server_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
+ 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)
+ {
+ /* 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;
+ }
+
+ 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
+ else if (type == TLSEXT_TYPE_use_srtp)
+ {
+ if(ssl_parse_serverhello_use_srtp_ext(s, data, size,
+ al))
+ return 0;
+ }
+ /* If this extension type was not otherwise handled, but
+ * matches a custom_cli_ext_record, then send it to the c
+ * callback */
+ else if (s->ctx->custom_cli_ext_records_count)
+ {
+ size_t i;
+ custom_cli_ext_record* record;
+
+ for (i = 0; i < s->ctx->custom_cli_ext_records_count; i++)
+ {
+ record = &s->ctx->custom_cli_ext_records[i];
+ if (record->ext_type == type)
+ {
+ if (record->fn2 && !record->fn2(s, type, data, size, al, record->arg))
+ return 0;
+ break;
+ }
+ }
+ }
+#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->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC;
+ }
+#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_SCAN_SERVERHELLO_TLSEXT,
+ SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+ return 0;
+ }
+
+ return 1;
+ }
+
+
+int ssl_prepare_clienthello_tlsext(SSL *s)
+ {
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ {
+ int r = 1;
+
+ if (s->ctx->tlsext_opaque_prf_input_callback != 0)
+ {
+ r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg);
+ if (!r)
+ return -1;
+ }
+
+ if (s->tlsext_opaque_prf_input != NULL)
+ {
+ if (s->s3->client_opaque_prf_input != NULL) /* shouldn't really happen */
+ OPENSSL_free(s->s3->client_opaque_prf_input);
+
+ if (s->tlsext_opaque_prf_input_len == 0)
+ s->s3->client_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
+ else
+ s->s3->client_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len);
+ if (s->s3->client_opaque_prf_input == NULL)
+ {
+ SSLerr(SSL_F_SSL_PREPARE_CLIENTHELLO_TLSEXT,ERR_R_MALLOC_FAILURE);
+ return -1;
+ }
+ s->s3->client_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
+ }
+
+ if (r == 2)
+ /* at callback's request, insist on receiving an appropriate server opaque PRF input */
+ s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
+ }
+#endif
+
+ return 1;
+ }
+
+int ssl_prepare_serverhello_tlsext(SSL *s)
+ {
+ return 1;
+ }
+
+static int ssl_check_clienthello_tlsext_early(SSL *s)
+ {
+ int ret=SSL_TLSEXT_ERR_NOACK;
+ int al = SSL_AD_UNRECOGNIZED_NAME;
+
+#ifndef OPENSSL_NO_EC
+ /* The handling of the ECPointFormats extension is done elsewhere, namely in
+ * ssl3_choose_cipher in s3_lib.c.
+ */
+ /* The handling of the EllipticCurves extension is done elsewhere, namely in
+ * ssl3_choose_cipher in s3_lib.c.
+ */
+#endif
+
+ if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0)
+ ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
+ else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)
+ ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ {
+ /* This sort of belongs into ssl_prepare_serverhello_tlsext(),
+ * but we might be sending an alert in response to the client hello,
+ * so this has to happen here in
+ * ssl_check_clienthello_tlsext_early(). */
+
+ int r = 1;
+
+ if (s->ctx->tlsext_opaque_prf_input_callback != 0)
+ {
+ r = s->ctx->tlsext_opaque_prf_input_callback(s, NULL, 0, s->ctx->tlsext_opaque_prf_input_callback_arg);
+ if (!r)
+ {
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_INTERNAL_ERROR;
+ goto err;
+ }
+ }
+
+ if (s->s3->server_opaque_prf_input != NULL) /* shouldn't really happen */
+ OPENSSL_free(s->s3->server_opaque_prf_input);
+ s->s3->server_opaque_prf_input = NULL;
+
+ if (s->tlsext_opaque_prf_input != NULL)
+ {
+ if (s->s3->client_opaque_prf_input != NULL &&
+ s->s3->client_opaque_prf_input_len == s->tlsext_opaque_prf_input_len)
+ {
+ /* can only use this extension if we have a server opaque PRF input
+ * of the same length as the client opaque PRF input! */
+
+ if (s->tlsext_opaque_prf_input_len == 0)
+ s->s3->server_opaque_prf_input = OPENSSL_malloc(1); /* dummy byte just to get non-NULL */
+ else
+ s->s3->server_opaque_prf_input = BUF_memdup(s->tlsext_opaque_prf_input, s->tlsext_opaque_prf_input_len);
+ if (s->s3->server_opaque_prf_input == NULL)
+ {
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_INTERNAL_ERROR;
+ goto err;
+ }
+ s->s3->server_opaque_prf_input_len = s->tlsext_opaque_prf_input_len;
+ }
+ }
+
+ if (r == 2 && s->s3->server_opaque_prf_input == NULL)
+ {
+ /* The callback wants to enforce use of the extension,
+ * but we can't do that with the client opaque PRF input;
+ * abort the handshake.
+ */
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ }
+ }
+
+ err:
+#endif
+ switch (ret)
+ {
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return -1;
+
+ case SSL_TLSEXT_ERR_ALERT_WARNING:
+ ssl3_send_alert(s,SSL3_AL_WARNING,al);
+ return 1;
+
+ case SSL_TLSEXT_ERR_NOACK:
+ s->servername_done=0;
+ default:
+ return 1;
+ }
+ }
+
+int ssl_check_clienthello_tlsext_late(SSL *s)
+ {
+ int ret = SSL_TLSEXT_ERR_OK;
+ int al;
+
+ /* If status request then ask callback what to do.
+ * Note: this must be called after servername callbacks in case
+ * the certificate has changed, and must be called after the cipher
+ * has been chosen because this may influence which certificate is sent
+ */
+ if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb)
+ {
+ int r;
+ CERT_PKEY *certpkey;
+ certpkey = ssl_get_server_send_pkey(s);
+ /* If no certificate can't return certificate status */
+ if (certpkey == NULL)
+ {
+ s->tlsext_status_expected = 0;
+ return 1;
+ }
+ /* Set current certificate to one we will use so
+ * SSL_get_certificate et al can pick it up.
+ */
+ s->cert->key = certpkey;
+ r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+ switch (r)
+ {
+ /* We don't want to send a status request response */
+ case SSL_TLSEXT_ERR_NOACK:
+ s->tlsext_status_expected = 0;
+ break;
+ /* status request response should be sent */
+ case SSL_TLSEXT_ERR_OK:
+ if (s->tlsext_ocsp_resp)
+ s->tlsext_status_expected = 1;
+ else
+ s->tlsext_status_expected = 0;
+ break;
+ /* something bad happened */
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_INTERNAL_ERROR;
+ goto err;
+ }
+ }
+ else
+ s->tlsext_status_expected = 0;
+
+ err:
+ switch (ret)
+ {
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ return -1;
+
+ case SSL_TLSEXT_ERR_ALERT_WARNING:
+ ssl3_send_alert(s, SSL3_AL_WARNING, al);
+ return 1;
+
+ default:
+ return 1;
+ }
+ }
+
+int ssl_check_serverhello_tlsext(SSL *s)
+ {
+ int ret=SSL_TLSEXT_ERR_NOACK;
+ int al = SSL_AD_UNRECOGNIZED_NAME;
+
+#ifndef OPENSSL_NO_EC
+ /* If we are client and using an elliptic curve cryptography cipher
+ * suite, then if server returns an EC point formats lists extension
+ * it must contain uncompressed.
+ */
+ unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
+ unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
+ if ((s->tlsext_ecpointformatlist != NULL) && (s->tlsext_ecpointformatlist_length > 0) &&
+ (s->session->tlsext_ecpointformatlist != NULL) && (s->session->tlsext_ecpointformatlist_length > 0) &&
+ ((alg_k & (SSL_kECDHE|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA)))
+ {
+ /* we are using an ECC cipher */
+ size_t i;
+ unsigned char *list;
+ int found_uncompressed = 0;
+ list = s->session->tlsext_ecpointformatlist;
+ for (i = 0; i < s->session->tlsext_ecpointformatlist_length; i++)
+ {
+ if (*(list++) == TLSEXT_ECPOINTFORMAT_uncompressed)
+ {
+ found_uncompressed = 1;
+ break;
+ }
+ }
+ if (!found_uncompressed)
+ {
+ SSLerr(SSL_F_SSL_CHECK_SERVERHELLO_TLSEXT,SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST);
+ return -1;
+ }
+ }
+ ret = SSL_TLSEXT_ERR_OK;
+#endif /* OPENSSL_NO_EC */
+
+ if (s->ctx != NULL && s->ctx->tlsext_servername_callback != 0)
+ ret = s->ctx->tlsext_servername_callback(s, &al, s->ctx->tlsext_servername_arg);
+ else if (s->initial_ctx != NULL && s->initial_ctx->tlsext_servername_callback != 0)
+ ret = s->initial_ctx->tlsext_servername_callback(s, &al, s->initial_ctx->tlsext_servername_arg);
+
+#ifdef TLSEXT_TYPE_opaque_prf_input
+ if (s->s3->server_opaque_prf_input_len > 0)
+ {
+ /* This case may indicate that we, as a client, want to insist on using opaque PRF inputs.
+ * So first verify that we really have a value from the server too. */
+
+ if (s->s3->server_opaque_prf_input == NULL)
+ {
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ }
+
+ /* Anytime the server *has* sent an opaque PRF input, we need to check
+ * that we have a client opaque PRF input of the same size. */
+ if (s->s3->client_opaque_prf_input == NULL ||
+ s->s3->client_opaque_prf_input_len != s->s3->server_opaque_prf_input_len)
+ {
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ }
+ }
+#endif
+
+ /* If we've requested certificate status and we wont get one
+ * tell the callback
+ */
+ if ((s->tlsext_status_type != -1) && !(s->tlsext_status_expected)
+ && s->ctx && s->ctx->tlsext_status_cb)
+ {
+ int r;
+ /* Set resp to NULL, resplen to -1 so callback knows
+ * there is no response.
+ */
+ if (s->tlsext_ocsp_resp)
+ {
+ OPENSSL_free(s->tlsext_ocsp_resp);
+ s->tlsext_ocsp_resp = NULL;
+ }
+ s->tlsext_ocsp_resplen = -1;
+ r = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
+ if (r == 0)
+ {
+ al = SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+ if (r < 0)
+ {
+ al = SSL_AD_INTERNAL_ERROR;
+ ret = SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+ }
+
+ switch (ret)
+ {
+ case SSL_TLSEXT_ERR_ALERT_FATAL:
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return -1;
+
+ case SSL_TLSEXT_ERR_ALERT_WARNING:
+ ssl3_send_alert(s,SSL3_AL_WARNING,al);
+ return 1;
+
+ case SSL_TLSEXT_ERR_NOACK:
+ s->servername_done=0;
+ default:
+ return 1;
+ }
+ }
+
+int ssl_parse_serverhello_tlsext(SSL *s, unsigned char **p, unsigned char *d, int n)
+ {
+ int al = -1;
+ if (s->version < SSL3_VERSION)
+ return 1;
+ if (ssl_scan_serverhello_tlsext(s, p, d, n, &al) <= 0)
+ {
+ ssl3_send_alert(s,SSL3_AL_FATAL,al);
+ return 0;
+ }
+
+ if (ssl_check_serverhello_tlsext(s) <= 0)
+ {
+ SSLerr(SSL_F_SSL_PARSE_SERVERHELLO_TLSEXT,SSL_R_SERVERHELLO_TLSEXT);
+ return 0;
+ }
+ return 1;
+}
+
+/* Since the server cache lookup is done early on in the processing of the
+ * ClientHello, and other operations depend on the result, we need to handle
+ * any TLS session ticket extension at the same time.
+ *
+ * session_id: points at the session ID in the ClientHello. This code will
+ * read past the end of this in order to parse out the session ticket
+ * extension, if any.
+ * len: the length of the session ID.
+ * limit: a pointer to the first byte after the ClientHello.
+ * ret: (output) on return, if a ticket was decrypted, then this is set to
+ * point to the resulting session.
+ *
+ * If s->tls_session_secret_cb is set then we are expecting a pre-shared key
+ * ciphersuite, in which case we have no use for session tickets and one will
+ * never be decrypted, nor will s->tlsext_ticket_expected be set to 1.
+ *
+ * Returns:
+ * -1: fatal error, either from parsing or decrypting the ticket.
+ * 0: no ticket was found (or was ignored, based on settings).
+ * 1: a zero length extension was found, indicating that the client supports
+ * session tickets but doesn't currently have one to offer.
+ * 2: either s->tls_session_secret_cb was set, or a ticket was offered but
+ * couldn't be decrypted because of a non-fatal error.
+ * 3: a ticket was successfully decrypted and *ret was set.
+ *
+ * Side effects:
+ * Sets s->tlsext_ticket_expected to 1 if the server will have to issue
+ * a new session ticket to the client because the client indicated support
+ * (and s->tls_session_secret_cb is NULL) but the client either doesn't have
+ * a session ticket or we couldn't use the one it gave us, or if
+ * s->ctx->tlsext_ticket_key_cb asked to renew the client's ticket.
+ * Otherwise, s->tlsext_ticket_expected is set to 0.
+ */
+int tls1_process_ticket(SSL *s, unsigned char *session_id, int len,
+ const unsigned char *limit, SSL_SESSION **ret)
+ {
+ /* Point after session ID in client hello */
+ const unsigned char *p = session_id + len;
+ unsigned short i;
+
+ *ret = NULL;
+ s->tlsext_ticket_expected = 0;
+
+ /* If tickets disabled behave as if no ticket present
+ * to permit stateful resumption.
+ */
+ if (!tls_use_ticket(s))
+ return 0;
+ if ((s->version <= SSL3_VERSION) || !limit)
+ return 0;
+ if (p >= limit)
+ return -1;
+ /* Skip past DTLS cookie */
+ if (SSL_IS_DTLS(s))
+ {
+ i = *(p++);
+ p+= i;
+ if (p >= limit)
+ return -1;
+ }
+ /* Skip past cipher list */
+ n2s(p, i);
+ p+= i;
+ if (p >= limit)
+ return -1;
+ /* Skip past compression algorithm list */
+ i = *(p++);
+ p += i;
+ if (p > limit)
+ return -1;
+ /* Now at start of extensions */
+ if ((p + 2) >= limit)
+ return 0;
+ n2s(p, i);
+ while ((p + 4) <= limit)
+ {
+ unsigned short type, size;
+ n2s(p, type);
+ n2s(p, size);
+ if (p + size > limit)
+ return 0;
+ if (type == TLSEXT_TYPE_session_ticket)
+ {
+ int r;
+ if (size == 0)
+ {
+ /* The client will accept a ticket but doesn't
+ * currently have one. */
+ s->tlsext_ticket_expected = 1;
+ return 1;
+ }
+ if (s->tls_session_secret_cb)
+ {
+ /* Indicate that the ticket couldn't be
+ * decrypted rather than generating the session
+ * from ticket now, trigger abbreviated
+ * handshake based on external mechanism to
+ * calculate the master secret later. */
+ return 2;
+ }
+ r = tls_decrypt_ticket(s, p, size, session_id, len, ret);
+ switch (r)
+ {
+ case 2: /* ticket couldn't be decrypted */
+ s->tlsext_ticket_expected = 1;
+ return 2;
+ case 3: /* ticket was decrypted */
+ return r;
+ case 4: /* ticket decrypted but need to renew */
+ s->tlsext_ticket_expected = 1;
+ return 3;
+ default: /* fatal error */
+ return -1;
+ }
+ }
+ p += size;
+ }
+ return 0;
+ }
+
+/* tls_decrypt_ticket attempts to decrypt a session ticket.
+ *
+ * etick: points to the body of the session ticket extension.
+ * eticklen: the length of the session tickets extenion.
+ * sess_id: points at the session ID.
+ * sesslen: the length of the session ID.
+ * psess: (output) on return, if a ticket was decrypted, then this is set to
+ * point to the resulting session.
+ *
+ * Returns:
+ * -1: fatal error, either from parsing or decrypting the ticket.
+ * 2: the ticket couldn't be decrypted.
+ * 3: a ticket was successfully decrypted and *psess was set.
+ * 4: same as 3, but the ticket needs to be renewed.
+ */
+static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen,
+ const unsigned char *sess_id, int sesslen,
+ SSL_SESSION **psess)
+ {
+ SSL_SESSION *sess;
+ unsigned char *sdec;
+ const unsigned char *p;
+ int slen, mlen, renew_ticket = 0;
+ unsigned char tick_hmac[EVP_MAX_MD_SIZE];
+ HMAC_CTX hctx;
+ EVP_CIPHER_CTX ctx;
+ SSL_CTX *tctx = s->initial_ctx;
+ /* Need at least keyname + iv + some encrypted data */
+ if (eticklen < 48)
+ return 2;
+ /* Initialize session ticket encryption and HMAC contexts */
+ HMAC_CTX_init(&hctx);
+ EVP_CIPHER_CTX_init(&ctx);
+ if (tctx->tlsext_ticket_key_cb)
+ {
+ unsigned char *nctick = (unsigned char *)etick;
+ int rv = tctx->tlsext_ticket_key_cb(s, nctick, nctick + 16,
+ &ctx, &hctx, 0);
+ if (rv < 0)
+ return -1;
+ if (rv == 0)
+ return 2;
+ if (rv == 2)
+ renew_ticket = 1;
+ }
+ else
+ {
+ /* Check key name matches */
+ if (memcmp(etick, tctx->tlsext_tick_key_name, 16))
+ return 2;
+ HMAC_Init_ex(&hctx, tctx->tlsext_tick_hmac_key, 16,
+ tlsext_tick_md(), NULL);
+ EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL,
+ tctx->tlsext_tick_aes_key, etick + 16);
+ }
+ /* Attempt to process session ticket, first conduct sanity and
+ * integrity checks on ticket.
+ */
+ mlen = HMAC_size(&hctx);
+ if (mlen < 0)
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ return -1;
+ }
+ eticklen -= mlen;
+ /* Check HMAC of encrypted ticket */
+ HMAC_Update(&hctx, etick, eticklen);
+ HMAC_Final(&hctx, tick_hmac, NULL);
+ HMAC_CTX_cleanup(&hctx);
+ if (CRYPTO_memcmp(tick_hmac, etick + eticklen, mlen))
+ return 2;
+ /* Attempt to decrypt session data */
+ /* Move p after IV to start of encrypted ticket, update length */
+ p = etick + 16 + EVP_CIPHER_CTX_iv_length(&ctx);
+ eticklen -= 16 + EVP_CIPHER_CTX_iv_length(&ctx);
+ sdec = OPENSSL_malloc(eticklen);
+ if (!sdec)
+ {
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ return -1;
+ }
+ EVP_DecryptUpdate(&ctx, sdec, &slen, p, eticklen);
+ if (EVP_DecryptFinal(&ctx, sdec + slen, &mlen) <= 0)
+ return 2;
+ slen += mlen;
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ p = sdec;
+
+ sess = d2i_SSL_SESSION(NULL, &p, slen);
+ OPENSSL_free(sdec);
+ if (sess)
+ {
+ /* The session ID, if non-empty, is used by some clients to
+ * detect that the ticket has been accepted. So we copy it to
+ * the session structure. If it is empty set length to zero
+ * as required by standard.
+ */
+ if (sesslen)
+ memcpy(sess->session_id, sess_id, sesslen);
+ sess->session_id_length = sesslen;
+ *psess = sess;
+ if (renew_ticket)
+ return 4;
+ else
+ return 3;
+ }
+ ERR_clear_error();
+ /* For session parse failure, indicate that we need to send a new
+ * ticket. */
+ return 2;
+ }
+
+/* Tables to translate from NIDs to TLS v1.2 ids */
+
+typedef struct
+ {
+ int nid;
+ int id;
+ } tls12_lookup;
+
+static tls12_lookup tls12_md[] = {
+ {NID_md5, TLSEXT_hash_md5},
+ {NID_sha1, TLSEXT_hash_sha1},
+ {NID_sha224, TLSEXT_hash_sha224},
+ {NID_sha256, TLSEXT_hash_sha256},
+ {NID_sha384, TLSEXT_hash_sha384},
+ {NID_sha512, TLSEXT_hash_sha512}
+};
+
+static tls12_lookup tls12_sig[] = {
+ {EVP_PKEY_RSA, TLSEXT_signature_rsa},
+ {EVP_PKEY_DSA, TLSEXT_signature_dsa},
+ {EVP_PKEY_EC, TLSEXT_signature_ecdsa}
+};
+
+static int tls12_find_id(int nid, tls12_lookup *table, size_t tlen)
+ {
+ size_t i;
+ for (i = 0; i < tlen; i++)
+ {
+ if (table[i].nid == nid)
+ return table[i].id;
+ }
+ return -1;
+ }
+
+static int tls12_find_nid(int id, tls12_lookup *table, size_t tlen)
+ {
+ size_t i;
+ for (i = 0; i < tlen; i++)
+ {
+ if ((table[i].id) == id)
+ return table[i].nid;
+ }
+ return NID_undef;
+ }
+
+int tls12_get_sigandhash(unsigned char *p, const EVP_PKEY *pk, const EVP_MD *md)
+ {
+ int sig_id, md_id;
+ if (!md)
+ return 0;
+ md_id = tls12_find_id(EVP_MD_type(md), tls12_md,
+ sizeof(tls12_md)/sizeof(tls12_lookup));
+ if (md_id == -1)
+ return 0;
+ sig_id = tls12_get_sigid(pk);
+ if (sig_id == -1)
+ return 0;
+ p[0] = (unsigned char)md_id;
+ p[1] = (unsigned char)sig_id;
+ return 1;
+ }
+
+int tls12_get_sigid(const EVP_PKEY *pk)
+ {
+ return tls12_find_id(pk->type, tls12_sig,
+ sizeof(tls12_sig)/sizeof(tls12_lookup));
+ }
+
+typedef struct
+ {
+ int nid;
+ int secbits;
+ const EVP_MD *(*mfunc)(void);
+ } tls12_hash_info;
+
+static const tls12_hash_info tls12_md_info[] = {
+#ifdef OPENSSL_NO_MD5
+ {NID_md5, 64, 0},
+#else
+ {NID_md5, 64, EVP_md5},
+#endif
+#ifdef OPENSSL_NO_SHA
+ {NID_sha1, 80, 0},
+#else
+ {NID_sha1, 80, EVP_sha1},
+#endif
+#ifdef OPENSSL_NO_SHA256
+ {NID_sha224, 112, 0},
+ {NID_sha256, 128, 0},
+#else
+ {NID_sha224, 112, EVP_sha224},
+ {NID_sha256, 128, EVP_sha256},
+#endif
+#ifdef OPENSSL_NO_SHA512
+ {NID_sha384, 192, 0},
+ {NID_sha512, 256, 0}
+#else
+ {NID_sha384, 192, EVP_sha384},
+ {NID_sha512, 256, EVP_sha512}
+#endif
+};
+
+static const tls12_hash_info *tls12_get_hash_info(unsigned char hash_alg)
+ {
+ if (hash_alg == 0)
+ return NULL;
+ if (hash_alg > sizeof(tls12_md_info)/sizeof(tls12_md_info[0]))
+ return NULL;
+ return tls12_md_info + hash_alg - 1;
+ }
+
+const EVP_MD *tls12_get_hash(unsigned char hash_alg)
+ {
+ const tls12_hash_info *inf;
+#ifndef OPENSSL_FIPS
+ if (hash_alg == TLSEXT_hash_md5 && FIPS_mode())
+ return NULL;
+#endif
+ inf = tls12_get_hash_info(hash_alg);
+ if (!inf || !inf->mfunc)
+ return NULL;
+ return inf->mfunc();
+ }
+
+static int tls12_get_pkey_idx(unsigned char sig_alg)
+ {
+ switch(sig_alg)
+ {
+#ifndef OPENSSL_NO_RSA
+ case TLSEXT_signature_rsa:
+ return SSL_PKEY_RSA_SIGN;
+#endif
+#ifndef OPENSSL_NO_DSA
+ case TLSEXT_signature_dsa:
+ return SSL_PKEY_DSA_SIGN;
+#endif
+#ifndef OPENSSL_NO_ECDSA
+ case TLSEXT_signature_ecdsa:
+ return SSL_PKEY_ECC;
+#endif
+ }
+ return -1;
+ }
+
+/* Convert TLS 1.2 signature algorithm extension values into NIDs */
+static void tls1_lookup_sigalg(int *phash_nid, int *psign_nid,
+ int *psignhash_nid, const unsigned char *data)
+ {
+ int sign_nid = 0, hash_nid = 0;
+ if (!phash_nid && !psign_nid && !psignhash_nid)
+ return;
+ if (phash_nid || psignhash_nid)
+ {
+ hash_nid = tls12_find_nid(data[0], tls12_md,
+ sizeof(tls12_md)/sizeof(tls12_lookup));
+ if (phash_nid)
+ *phash_nid = hash_nid;
+ }
+ if (psign_nid || psignhash_nid)
+ {
+ sign_nid = tls12_find_nid(data[1], tls12_sig,
+ sizeof(tls12_sig)/sizeof(tls12_lookup));
+ if (psign_nid)
+ *psign_nid = sign_nid;
+ }
+ if (psignhash_nid)
+ {
+ if (sign_nid && hash_nid)
+ OBJ_find_sigid_by_algs(psignhash_nid,
+ hash_nid, sign_nid);
+ else
+ *psignhash_nid = NID_undef;
+ }
+ }
+/* Check to see if a signature algorithm is allowed */
+static int tls12_sigalg_allowed(SSL *s, int op, const unsigned char *ptmp)
+ {
+ /* See if we have an entry in the hash table and it is enabled */
+ const tls12_hash_info *hinf = tls12_get_hash_info(ptmp[0]);
+ if (!hinf || !hinf->mfunc)
+ return 0;
+ /* See if public key algorithm allowed */
+ if (tls12_get_pkey_idx(ptmp[1]) == -1)
+ return 0;
+ /* Finally see if security callback allows it */
+ return ssl_security(s, op, hinf->secbits, hinf->nid, (void *)ptmp);
+ }
+
+/* Get a mask of disabled public key algorithms based on supported
+ * signature algorithms. For example if no signature algorithm supports RSA
+ * then RSA is disabled.
+ */
+
+void ssl_set_sig_mask(unsigned long *pmask_a, SSL *s, int op)
+ {
+ const unsigned char *sigalgs;
+ size_t i, sigalgslen;
+ int have_rsa = 0, have_dsa = 0, have_ecdsa = 0;
+ /* Now go through all signature algorithms seeing if we support
+ * any for RSA, DSA, ECDSA. Do this for all versions not just
+ * TLS 1.2. To keep down calls to security callback only check
+ * if we have to.
+ */
+ sigalgslen = tls12_get_psigalgs(s, &sigalgs);
+ for (i = 0; i < sigalgslen; i += 2, sigalgs += 2)
+ {
+ switch(sigalgs[1])
+ {
+#ifndef OPENSSL_NO_RSA
+ case TLSEXT_signature_rsa:
+ if (!have_rsa && tls12_sigalg_allowed(s, op, sigalgs))
+ have_rsa = 1;
+ break;
+#endif
+#ifndef OPENSSL_NO_DSA
+ case TLSEXT_signature_dsa:
+ if (!have_dsa && tls12_sigalg_allowed(s, op, sigalgs))
+ have_dsa = 1;
+ break;
+#endif
+#ifndef OPENSSL_NO_ECDSA
+ case TLSEXT_signature_ecdsa:
+ if (!have_ecdsa && tls12_sigalg_allowed(s, op, sigalgs))
+ have_ecdsa = 1;
+ break;
+#endif
+ }
+ }
+ if (!have_rsa)
+ *pmask_a |= SSL_aRSA;
+ if (!have_dsa)
+ *pmask_a |= SSL_aDSS;
+ if (!have_ecdsa)
+ *pmask_a |= SSL_aECDSA;
+ }
+
+size_t tls12_copy_sigalgs(SSL *s, unsigned char *out,
+ const unsigned char *psig, size_t psiglen)
+ {
+ unsigned char *tmpout = out;
+ size_t i;
+ for (i = 0; i < psiglen; i += 2, psig += 2)
+ {
+ if (tls12_sigalg_allowed(s, SSL_SECOP_SIGALG_SUPPORTED, psig))
+ {
+ *tmpout++ = psig[0];
+ *tmpout++ = psig[1];
+ }
+ }
+ return tmpout - out;
+ }
+
+/* Given preference and allowed sigalgs set shared sigalgs */
+static int tls12_shared_sigalgs(SSL *s, TLS_SIGALGS *shsig,
+ const unsigned char *pref, size_t preflen,
+ const unsigned char *allow, size_t allowlen)
+ {
+ const unsigned char *ptmp, *atmp;
+ size_t i, j, nmatch = 0;
+ for (i = 0, ptmp = pref; i < preflen; i+=2, ptmp+=2)
+ {
+ /* Skip disabled hashes or signature algorithms */
+ if (!tls12_sigalg_allowed(s, SSL_SECOP_SIGALG_SHARED, ptmp))
+ continue;
+ for (j = 0, atmp = allow; j < allowlen; j+=2, atmp+=2)
+ {
+ if (ptmp[0] == atmp[0] && ptmp[1] == atmp[1])
+ {
+ nmatch++;
+ if (shsig)
+ {
+ shsig->rhash = ptmp[0];
+ shsig->rsign = ptmp[1];
+ tls1_lookup_sigalg(&shsig->hash_nid,
+ &shsig->sign_nid,
+ &shsig->signandhash_nid,
+ ptmp);
+ shsig++;
+ }
+ break;
+ }
+ }
+ }
+ return nmatch;
+ }
+
+/* Set shared signature algorithms for SSL structures */
+static int tls1_set_shared_sigalgs(SSL *s)
+ {
+ const unsigned char *pref, *allow, *conf;
+ size_t preflen, allowlen, conflen;
+ size_t nmatch;
+ TLS_SIGALGS *salgs = NULL;
+ CERT *c = s->cert;
+ unsigned int is_suiteb = tls1_suiteb(s);
+ if (c->shared_sigalgs)
+ {
+ OPENSSL_free(c->shared_sigalgs);
+ c->shared_sigalgs = NULL;
+ }
+ /* If client use client signature algorithms if not NULL */
+ if (!s->server && c->client_sigalgs && !is_suiteb)
+ {
+ conf = c->client_sigalgs;
+ conflen = c->client_sigalgslen;
+ }
+ else if (c->conf_sigalgs && !is_suiteb)
+ {
+ conf = c->conf_sigalgs;
+ conflen = c->conf_sigalgslen;
+ }
+ else
+ conflen = tls12_get_psigalgs(s, &conf);
+ if(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE || is_suiteb)
+ {
+ pref = conf;
+ preflen = conflen;
+ allow = c->peer_sigalgs;
+ allowlen = c->peer_sigalgslen;
+ }
+ else
+ {
+ allow = conf;
+ allowlen = conflen;
+ pref = c->peer_sigalgs;
+ preflen = c->peer_sigalgslen;
+ }
+ nmatch = tls12_shared_sigalgs(s, NULL, pref, preflen, allow, allowlen);
+ if (!nmatch)
+ return 1;
+ salgs = OPENSSL_malloc(nmatch * sizeof(TLS_SIGALGS));
+ if (!salgs)
+ return 0;
+ nmatch = tls12_shared_sigalgs(s, salgs, pref, preflen, allow, allowlen);
+ c->shared_sigalgs = salgs;
+ c->shared_sigalgslen = nmatch;
+ return 1;
+ }
+
+
+/* Set preferred digest for each key type */
+
+int tls1_process_sigalgs(SSL *s, const unsigned char *data, int dsize)
+ {
+ int idx;
+ size_t i;
+ const EVP_MD *md;
+ CERT *c = s->cert;
+ TLS_SIGALGS *sigptr;
+ /* Extension ignored for inappropriate versions */
+ if (!SSL_USE_SIGALGS(s))
+ return 1;
+ /* Should never happen */
+ if (!c)
+ return 0;
+
+ if (c->peer_sigalgs)
+ OPENSSL_free(c->peer_sigalgs);
+ c->peer_sigalgs = OPENSSL_malloc(dsize);
+ if (!c->peer_sigalgs)
+ return 0;
+ c->peer_sigalgslen = dsize;
+ memcpy(c->peer_sigalgs, data, dsize);
+
+ tls1_set_shared_sigalgs(s);
+
+#ifdef OPENSSL_SSL_DEBUG_BROKEN_PROTOCOL
+ if (s->cert->cert_flags & SSL_CERT_FLAG_BROKEN_PROTOCOL)
+ {
+ /* Use first set signature preference to force message
+ * digest, ignoring any peer preferences.
+ */
+ const unsigned char *sigs = NULL;
+ if (s->server)
+ sigs = c->conf_sigalgs;
+ else
+ sigs = c->client_sigalgs;
+ if (sigs)
+ {
+ idx = tls12_get_pkey_idx(sigs[1]);
+ md = tls12_get_hash(sigs[0]);
+ c->pkeys[idx].digest = md;
+ c->pkeys[idx].valid_flags = CERT_PKEY_EXPLICIT_SIGN;
+ if (idx == SSL_PKEY_RSA_SIGN)
+ {
+ c->pkeys[SSL_PKEY_RSA_ENC].valid_flags = CERT_PKEY_EXPLICIT_SIGN;
+ c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
+ }
+ }
+ }
+#endif
+
+ for (i = 0, sigptr = c->shared_sigalgs;
+ i < c->shared_sigalgslen; i++, sigptr++)
+ {
+ idx = tls12_get_pkey_idx(sigptr->rsign);
+ if (idx > 0 && c->pkeys[idx].digest == NULL)
+ {
+ md = tls12_get_hash(sigptr->rhash);
+ c->pkeys[idx].digest = md;
+ c->pkeys[idx].valid_flags = CERT_PKEY_EXPLICIT_SIGN;
+ if (idx == SSL_PKEY_RSA_SIGN)
+ {
+ c->pkeys[SSL_PKEY_RSA_ENC].valid_flags = CERT_PKEY_EXPLICIT_SIGN;
+ c->pkeys[SSL_PKEY_RSA_ENC].digest = md;
+ }
+ }
+
+ }
+ /* In strict mode leave unset digests as NULL to indicate we can't
+ * use the certificate for signing.
+ */
+ if (!(s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT))
+ {
+ /* Set any remaining keys to default values. NOTE: if alg is
+ * not supported it stays as NULL.
+ */
+#ifndef OPENSSL_NO_DSA
+ if (!c->pkeys[SSL_PKEY_DSA_SIGN].digest)
+ c->pkeys[SSL_PKEY_DSA_SIGN].digest = EVP_sha1();
+#endif
+#ifndef OPENSSL_NO_RSA
+ if (!c->pkeys[SSL_PKEY_RSA_SIGN].digest)
+ {
+ c->pkeys[SSL_PKEY_RSA_SIGN].digest = EVP_sha1();
+ c->pkeys[SSL_PKEY_RSA_ENC].digest = EVP_sha1();
+ }
+#endif
+#ifndef OPENSSL_NO_ECDSA
+ if (!c->pkeys[SSL_PKEY_ECC].digest)
+ c->pkeys[SSL_PKEY_ECC].digest = EVP_sha1();
+#endif
+ }
+ return 1;
+ }
+
+
+int SSL_get_sigalgs(SSL *s, int idx,
+ int *psign, int *phash, int *psignhash,
+ unsigned char *rsig, unsigned char *rhash)
+ {
+ const unsigned char *psig = s->cert->peer_sigalgs;
+ if (psig == NULL)
+ return 0;
+ if (idx >= 0)
+ {
+ idx <<= 1;
+ if (idx >= (int)s->cert->peer_sigalgslen)
+ return 0;
+ psig += idx;
+ if (rhash)
+ *rhash = psig[0];
+ if (rsig)
+ *rsig = psig[1];
+ tls1_lookup_sigalg(phash, psign, psignhash, psig);
+ }
+ return s->cert->peer_sigalgslen / 2;
+ }
+
+int SSL_get_shared_sigalgs(SSL *s, int idx,
+ int *psign, int *phash, int *psignhash,
+ unsigned char *rsig, unsigned char *rhash)
+ {
+ TLS_SIGALGS *shsigalgs = s->cert->shared_sigalgs;
+ if (!shsigalgs || idx >= (int)s->cert->shared_sigalgslen)
+ return 0;
+ shsigalgs += idx;
+ if (phash)
+ *phash = shsigalgs->hash_nid;
+ if (psign)
+ *psign = shsigalgs->sign_nid;
+ if (psignhash)
+ *psignhash = shsigalgs->signandhash_nid;
+ if (rsig)
+ *rsig = shsigalgs->rsign;
+ if (rhash)
+ *rhash = shsigalgs->rhash;
+ return s->cert->shared_sigalgslen;
+ }
+
+
+#ifndef OPENSSL_NO_HEARTBEATS
+int
+tls1_process_heartbeat(SSL *s)
+ {
+ unsigned char *p = &s->s3->rrec.data[0], *pl;
+ unsigned short hbtype;
+ unsigned int payload;
+ unsigned int padding = 16; /* Use minimum padding */
+
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
+ &s->s3->rrec.data[0], s->s3->rrec.length,
+ s, s->msg_callback_arg);
+
+ /* Read type and payload length first */
+ if (1 + 2 + 16 > s->s3->rrec.length)
+ return 0; /* silently discard */
+ hbtype = *p++;
+ n2s(p, payload);
+ if (1 + 2 + payload + 16 > s->s3->rrec.length)
+ return 0; /* silently discard per RFC 6520 sec. 4 */
+ pl = p;
+
+ if (hbtype == TLS1_HB_REQUEST)
+ {
+ unsigned char *buffer, *bp;
+ int r;
+
+ /* Allocate memory for the response, size is 1 bytes
+ * message type, plus 2 bytes payload length, plus
+ * payload, plus padding
+ */
+ buffer = OPENSSL_malloc(1 + 2 + payload + padding);
+ bp = buffer;
+
+ /* Enter response type, length and copy payload */
+ *bp++ = TLS1_HB_RESPONSE;
+ s2n(payload, bp);
+ memcpy(bp, pl, payload);
+ bp += payload;
+ /* Random padding */
+ RAND_pseudo_bytes(bp, padding);
+
+ r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);
+
+ if (r >= 0 && s->msg_callback)
+ s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+ buffer, 3 + payload + padding,
+ s, s->msg_callback_arg);
+
+ OPENSSL_free(buffer);
+
+ if (r < 0)
+ return r;
+ }
+ else if (hbtype == TLS1_HB_RESPONSE)
+ {
+ unsigned int seq;
+
+ /* We only send sequence numbers (2 bytes unsigned int),
+ * and 16 random bytes, so we just try to read the
+ * sequence number */
+ n2s(pl, seq);
+
+ if (payload == 18 && seq == s->tlsext_hb_seq)
+ {
+ s->tlsext_hb_seq++;
+ s->tlsext_hb_pending = 0;
+ }
+ }
+
+ return 0;
+ }
+
+int
+tls1_heartbeat(SSL *s)
+ {
+ unsigned char *buf, *p;
+ int ret;
+ unsigned int payload = 18; /* Sequence number + random bytes */
+ unsigned int padding = 16; /* Use minimum padding */
+
+ /* Only send if peer supports and accepts HB requests... */
+ if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) ||
+ s->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS)
+ {
+ SSLerr(SSL_F_TLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT);
+ return -1;
+ }
+
+ /* ...and there is none in flight yet... */
+ if (s->tlsext_hb_pending)
+ {
+ SSLerr(SSL_F_TLS1_HEARTBEAT,SSL_R_TLS_HEARTBEAT_PENDING);
+ return -1;
+ }
+
+ /* ...and no handshake in progress. */
+ if (SSL_in_init(s) || s->in_handshake)
+ {
+ SSLerr(SSL_F_TLS1_HEARTBEAT,SSL_R_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ /* Check if padding is too long, payload and padding
+ * must not exceed 2^14 - 3 = 16381 bytes in total.
+ */
+ OPENSSL_assert(payload + padding <= 16381);
+
+ /* Create HeartBeat message, we just use a sequence number
+ * as payload to distuingish different messages and add
+ * some random stuff.
+ * - Message Type, 1 byte
+ * - Payload Length, 2 bytes (unsigned int)
+ * - Payload, the sequence number (2 bytes uint)
+ * - Payload, random bytes (16 bytes uint)
+ * - Padding
+ */
+ buf = OPENSSL_malloc(1 + 2 + payload + padding);
+ p = buf;
+ /* Message Type */
+ *p++ = TLS1_HB_REQUEST;
+ /* Payload length (18 bytes here) */
+ s2n(payload, p);
+ /* Sequence number */
+ s2n(s->tlsext_hb_seq, p);
+ /* 16 random bytes */
+ RAND_pseudo_bytes(p, 16);
+ p += 16;
+ /* Random padding */
+ RAND_pseudo_bytes(p, padding);
+
+ ret = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding);
+ if (ret >= 0)
+ {
+ if (s->msg_callback)
+ s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
+ buf, 3 + payload + padding,
+ s, s->msg_callback_arg);
+
+ s->tlsext_hb_pending = 1;
+ }
+
+ OPENSSL_free(buf);
+
+ return ret;
+ }
+#endif
+
+#define MAX_SIGALGLEN (TLSEXT_hash_num * TLSEXT_signature_num * 2)
+
+typedef struct
+ {
+ size_t sigalgcnt;
+ int sigalgs[MAX_SIGALGLEN];
+ } sig_cb_st;
+
+static int sig_cb(const char *elem, int len, void *arg)
+ {
+ sig_cb_st *sarg = arg;
+ size_t i;
+ char etmp[20], *p;
+ int sig_alg, hash_alg;
+ if (sarg->sigalgcnt == MAX_SIGALGLEN)
+ return 0;
+ if (len > (int)(sizeof(etmp) - 1))
+ return 0;
+ memcpy(etmp, elem, len);
+ etmp[len] = 0;
+ p = strchr(etmp, '+');
+ if (!p)
+ return 0;
+ *p = 0;
+ p++;
+ if (!*p)
+ return 0;
+
+ if (!strcmp(etmp, "RSA"))
+ sig_alg = EVP_PKEY_RSA;
+ else if (!strcmp(etmp, "DSA"))
+ sig_alg = EVP_PKEY_DSA;
+ else if (!strcmp(etmp, "ECDSA"))
+ sig_alg = EVP_PKEY_EC;
+ else return 0;
+
+ hash_alg = OBJ_sn2nid(p);
+ if (hash_alg == NID_undef)
+ hash_alg = OBJ_ln2nid(p);
+ if (hash_alg == NID_undef)
+ return 0;
+
+ for (i = 0; i < sarg->sigalgcnt; i+=2)
+ {
+ if (sarg->sigalgs[i] == sig_alg
+ && sarg->sigalgs[i + 1] == hash_alg)
+ return 0;
+ }
+ sarg->sigalgs[sarg->sigalgcnt++] = hash_alg;
+ sarg->sigalgs[sarg->sigalgcnt++] = sig_alg;
+ return 1;
+ }
+
+/* Set suppored signature algorithms based on a colon separated list
+ * of the form sig+hash e.g. RSA+SHA512:DSA+SHA512 */
+int tls1_set_sigalgs_list(CERT *c, const char *str, int client)
+ {
+ sig_cb_st sig;
+ sig.sigalgcnt = 0;
+ if (!CONF_parse_list(str, ':', 1, sig_cb, &sig))
+ return 0;
+ if (c == NULL)
+ return 1;
+ return tls1_set_sigalgs(c, sig.sigalgs, sig.sigalgcnt, client);
+ }