Commit message: Prevent use of RSA+MD5 in TLS 1.2 by default.

Removing RSA+MD5 from the default signature algorithm list
prevents its use by default.

If a broken implementation attempts to use RSA+MD5 anyway the sanity
checking of signature algorithms will cause a fatal alert.
CVE: CVE-2015-7575
CWE: CWE-19
Vulnerability description: Mozilla Network Security Services (NSS) before 3.20.2, as used in Mozilla Firefox before 43.0.2 and Firefox ESR 38.x before 38.5.2, does not reject MD5 signatures in Server Key Exchange messages in TLS 1.2 Handshake Protocol traffic, which makes it easier for man-in-the-middle attackers to spoof servers by triggering a collision.

Project: openssl

unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
	{
	int extdatalen=0;
	unsigned char *ret = p;
#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_kEECDH|SSL_kECDHr|SSL_kECDHe)) || (alg_a & SSL_aECDSA);
	using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
#endif
	/* don't add extensions for SSLv3, unless doing secure renegotiation */
	if (s->version == SSL3_VERSION && !s->s3->send_connection_binding)
		return p;
	
	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 - p - 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 (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
		&& !(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)
		{
		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

        if(s->srtp_profile)
                {
                int el;

                ssl_add_serverhello_use_srtp_ext(s, 0, &el, 0);
                
                if((limit - p - 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;
                }

	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)
		{
		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 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;
					}
				}
			}
		}
#ifdef TLSEXT_TYPE_encrypt_then_mac
	if (s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC)
		{
		/* Don't use encrypt_then_mac if AEAD: might want
		 * to disable for other ciphersuites too.
		 */
		if (s->s3->tmp.new_cipher->algorithm_mac == SSL_AEAD)
			s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC;
		else
			{
			s2n(TLSEXT_TYPE_encrypt_then_mac,ret);
			s2n(0,ret);
			}
		}
#endif

	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;
	}

Project: openssl

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 ((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)
			{
			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;
	}

Project: openssl

unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *p, unsigned char *limit)
	{
	int extdatalen=0;
	unsigned char *ret = p;
#ifndef OPENSSL_NO_EC
	/* See if we support any ECC ciphersuites */
	int using_ecc = 0;
	if (s->version >= TLS1_VERSION || SSL_IS_DTLS(s))
		{
		int i;
		unsigned long alg_k, alg_a;
		STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(s);

		for (i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++)
			{
			SSL_CIPHER *c = sk_SSL_CIPHER_value(cipher_stack, i);

			alg_k = c->algorithm_mkey;
			alg_a = c->algorithm_auth;
			if ((alg_k & (SSL_kEECDH|SSL_kECDHr|SSL_kECDHe)
				|| (alg_a & SSL_aECDSA)))
				{
				using_ecc = 1;
				break;
				}
			}
		}
#endif

	/* don't add extensions for SSLv3 unless doing secure renegotiation */
	if (s->client_version == SSL3_VERSION
					&& !s->s3->send_connection_binding)
		return p;

	ret+=2;

	if (ret>=limit) return NULL; /* this really never occurs, but ... */

 	if (s->tlsext_hostname != NULL)
		{ 
		/* Add TLS extension servername to the Client Hello message */
		unsigned long size_str;
		long lenmax; 

		/* check for enough space.
		   4 for the servername type and entension length
		   2 for servernamelist length
		   1 for the hostname type
		   2 for hostname length
		   + hostname length 
		*/
		   
		if ((lenmax = limit - ret - 9) < 0 
		    || (size_str = strlen(s->tlsext_hostname)) > (unsigned long)lenmax) 
			return NULL;
			
		/* extension type and length */
		s2n(TLSEXT_TYPE_server_name,ret); 
		s2n(size_str+5,ret);
		
		/* length of servername list */
		s2n(size_str+3,ret);
	
		/* hostname type, length and hostname */
		*(ret++) = (unsigned char) TLSEXT_NAMETYPE_host_name;
		s2n(size_str,ret);
		memcpy(ret, s->tlsext_hostname, size_str);
		ret+=size_str;
		}

        /* Add RI if renegotiating */
        if (s->renegotiate)
          {
          int el;
          
          if(!ssl_add_clienthello_renegotiate_ext(s, 0, &el, 0))
              {
              SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
              return NULL;
              }

          if((limit - p - 4 - el) < 0) return NULL;
          
          s2n(TLSEXT_TYPE_renegotiate,ret);
          s2n(el,ret);

          if(!ssl_add_clienthello_renegotiate_ext(s, ret, &el, el))
              {
              SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
              return NULL;
              }

          ret += el;
        }

#ifndef OPENSSL_NO_SRP
	/* Add SRP username if there is one */
	if (s->srp_ctx.login != NULL)
		{ /* Add TLS extension SRP username to the Client Hello message */

		int login_len = strlen(s->srp_ctx.login);	
		if (login_len > 255 || login_len == 0)
			{
			SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
			return NULL;
			} 

		/* check for enough space.
		   4 for the srp type type and entension length
		   1 for the srp user identity
		   + srp user identity length 
		*/
		if ((limit - ret - 5 - login_len) < 0) return NULL; 

		/* fill in the extension */
		s2n(TLSEXT_TYPE_srp,ret);
		s2n(login_len+1,ret);
		(*ret++) = (unsigned char) login_len;
		memcpy(ret, s->srp_ctx.login, login_len);
		ret+=login_len;
		}
#endif

#ifndef OPENSSL_NO_EC
	if (using_ecc)
		{
		/* Add TLS extension ECPointFormats to the ClientHello message */
		long lenmax; 
		const unsigned char *plist;
		size_t plistlen;

		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_CLIENTHELLO_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;

		/* Add TLS extension EllipticCurves to the ClientHello message */
		plist = s->tlsext_ellipticcurvelist;
		tls1_get_curvelist(s, 0, &plist, &plistlen);

		if ((lenmax = limit - ret - 6) < 0) return NULL; 
		if (plistlen > (size_t)lenmax) return NULL;
		if (plistlen > 65532)
			{
			SSLerr(SSL_F_SSL_ADD_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
			return NULL;
			}
		
		s2n(TLSEXT_TYPE_elliptic_curves,ret);
		s2n(plistlen + 2, ret);

		/* NB: draft-ietf-tls-ecc-12.txt uses a one-byte prefix for
		 * elliptic_curve_list, but the examples use two bytes.
		 * http://www1.ietf.org/mail-archive/web/tls/current/msg00538.html
		 * resolves this to two bytes.
		 */
		s2n(plistlen, ret);
		memcpy(ret, plist, plistlen);
		ret+=plistlen;
		}
#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 (SSL_USE_SIGALGS(s))
		{
		size_t salglen;
		const unsigned char *salg;
		salglen = tls12_get_psigalgs(s, &salg);
		if ((size_t)(limit - ret) < salglen + 6)
			return NULL; 
		s2n(TLSEXT_TYPE_signature_algorithms,ret);
		s2n(salglen + 2, ret);
		s2n(salglen, ret);
		memcpy(ret, salg, salglen);
		ret += salglen;
		}

#ifdef TLSEXT_TYPE_opaque_prf_input
	if (s->s3->client_opaque_prf_input != NULL)
		{
		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)
		{
		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 */
	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

	if (s->alpn_client_proto_list && !s->s3->tmp.finish_md_len)
		{
		if ((size_t)(limit - ret) < 6 + s->alpn_client_proto_list_len)
			return NULL;
		s2n(TLSEXT_TYPE_application_layer_protocol_negotiation,ret);
		s2n(2 + s->alpn_client_proto_list_len,ret);
		s2n(s->alpn_client_proto_list_len,ret);
		memcpy(ret, s->alpn_client_proto_list,
		       s->alpn_client_proto_list_len);
		ret += s->alpn_client_proto_list_len;
		}

        if(SSL_get_srtp_profiles(s))
                {
                int el;

                ssl_add_clienthello_use_srtp_ext(s, 0, &el, 0);
                
                if((limit - p - 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;
                }

	/* Add custom TLS Extensions to ClientHello */
	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++)
			{
			const unsigned char* out = NULL;
			unsigned short outlen = 0;

			record = &s->ctx->custom_cli_ext_records[i];
			/* NULL callback sends empty extension */ 
			/* -1 from callback omits extension */
			if (record->fn1)
				{
				int cb_retval = 0;
				cb_retval = record->fn1(s, record->ext_type,
							&out, &outlen,
							record->arg);
				if (cb_retval == 0)
					return NULL; /* error */
				if (cb_retval == -1)
					continue; /* skip this extension */
				}
			if (limit < ret + 4 + outlen)
				return NULL;
			s2n(record->ext_type, ret);
			s2n(outlen, ret);
			memcpy(ret, out, outlen);
			ret += outlen;
			}
		}
#ifdef TLSEXT_TYPE_encrypt_then_mac
	s2n(TLSEXT_TYPE_encrypt_then_mac,ret);
	s2n(0,ret);
#endif

	if ((extdatalen = ret-p-2) == 0)
		return p;

	s2n(extdatalen,p);
	return ret;
	}

Project: openssl

static int ssl_scan_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;
	size_t i;

	s->servername_done = 0;
	s->tlsext_status_type = -1;
#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;
		}

	/* Clear observed custom extensions */
	s->s3->tlsext_custom_types_count = 0;
	if (s->s3->tlsext_custom_types != NULL)
		{
		OPENSSL_free(s->s3->tlsext_custom_types);
		s->s3->tlsext_custom_types = NULL;
		}		

#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 */

	/* Clear any signature algorithms extension received */
	if (s->cert->peer_sigalgs)
		{
		OPENSSL_free(s->cert->peer_sigalgs);
		s->cert->peer_sigalgs = NULL;
		}
	/* Clear any shared sigtnature algorithms */
	if (s->cert->shared_sigalgs)
		{
		OPENSSL_free(s->cert->shared_sigalgs);
		s->cert->shared_sigalgs = NULL;
		}
	/* Clear certificate digests and validity flags */
	for (i = 0; i < SSL_PKEY_NUM; i++)
		{
		s->cert->pkeys[i].digest = NULL;
		s->cert->pkeys[i].valid_flags = 0;
		}

#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,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 || 
				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
		         && s->ctx->tlsext_status_cb)
			{
		
			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;
			/* ALPN takes precedence over NPN. */
			s->s3->next_proto_neg_seen = 0;
			}

		/* 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)
					{
					size_t j;

					/* Error on duplicate TLS Extensions */
					for (j = 0; j < s->s3->tlsext_custom_types_count; j++)
						{
						if (type == s->s3->tlsext_custom_types[j])
							{
							*al = TLS1_AD_DECODE_ERROR;
							return 0;
							}
						}

					/* NULL callback still notes the extension */ 
					if (record->fn1 && !record->fn1(s, type, data, size, al, record->arg))
						return 0;
						
					/* Add the (non-duplicated) entry */
					s->s3->tlsext_custom_types_count++;
					s->s3->tlsext_custom_types = OPENSSL_realloc(
							s->s3->tlsext_custom_types,
							s->s3->tlsext_custom_types_count * 2);
					if (s->s3->tlsext_custom_types == NULL)
						{
						s->s3->tlsext_custom_types = 0;
						*al = TLS1_AD_INTERNAL_ERROR;
						return 0;
						}
					s->s3->tlsext_custom_types[
							s->s3->tlsext_custom_types_count - 1] = type;
					}						
				}
			}
#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;
	}

Project: openssl

int tls12_check_peer_sigalg(const EVP_MD **pmd, SSL *s,
				const unsigned char *sig, EVP_PKEY *pkey)
	{
	const unsigned char *sent_sigs;
	size_t sent_sigslen, i;
	int sigalg = tls12_get_sigid(pkey);
	/* Should never happen */
	if (sigalg == -1)
		return -1;
	/* Check key type is consistent with signature */
	if (sigalg != (int)sig[1])
		{
		SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_WRONG_SIGNATURE_TYPE);
		return 0;
		}
#ifndef OPENSSL_NO_EC
	if (pkey->type == EVP_PKEY_EC)
		{
		unsigned char curve_id[2], comp_id;
		/* Check compression and curve matches extensions */
		if (!tls1_set_ec_id(curve_id, &comp_id, pkey->pkey.ec))
			return 0;
		if (!s->server && !tls1_check_ec_key(s, curve_id, &comp_id))
			{
			SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_WRONG_CURVE);
			return 0;
			}
		/* If Suite B only P-384+SHA384 or P-256+SHA-256 allowed */
		if (tls1_suiteb(s))
			{
			if (curve_id[0])
				return 0;
			if (curve_id[1] == TLSEXT_curve_P_256)
				{
				if (sig[0] != TLSEXT_hash_sha256)
					{
					SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,
						SSL_R_ILLEGAL_SUITEB_DIGEST);
					return 0;
					}
				}
			else if (curve_id[1] == TLSEXT_curve_P_384)
				{
				if (sig[0] != TLSEXT_hash_sha384)
					{
					SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,
						SSL_R_ILLEGAL_SUITEB_DIGEST);
					return 0;
					}
				}
			else
				return 0;
			}
		}
	else if (tls1_suiteb(s))
		return 0;
#endif

	/* Check signature matches a type we sent */
	sent_sigslen = tls12_get_psigalgs(s, &sent_sigs);
	for (i = 0; i < sent_sigslen; i+=2, sent_sigs+=2)
		{
		if (sig[0] == sent_sigs[0] && sig[1] == sent_sigs[1])
			break;
		}
	/* Allow fallback to SHA1 if not strict mode */
	if (i == sent_sigslen && (sig[0] != TLSEXT_hash_sha1 || s->cert->cert_flags & SSL_CERT_FLAGS_CHECK_TLS_STRICT))
		{
		SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_WRONG_SIGNATURE_TYPE);
		return 0;
		}
	*pmd = tls12_get_hash(sig[0]);
	if (*pmd == NULL)
		{
		SSLerr(SSL_F_TLS12_CHECK_PEER_SIGALG,SSL_R_UNKNOWN_DIGEST);
		return 0;
		}
	/* Store the digest used so applications can retrieve it if they
	 * wish.
	 */
	if (s->session && s->session->sess_cert)
		s->session->sess_cert->peer_key->digest = *pmd;
	return 1;
	}

Project: openssl

void ssl_set_client_disabled(SSL *s)
	{
	CERT *c = s->cert;
	const unsigned char *sigalgs;
	size_t i, sigalgslen;
	int have_rsa = 0, have_dsa = 0, have_ecdsa = 0;
	c->mask_a = 0;
	c->mask_k = 0;
	/* Don't allow TLS 1.2 only ciphers if we don't suppport them */
	if (!SSL_CLIENT_USE_TLS1_2_CIPHERS(s))
		c->mask_ssl = SSL_TLSV1_2;
	else
		c->mask_ssl = 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.
	 */
	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:
			have_rsa = 1;
			break;
#endif
#ifndef OPENSSL_NO_DSA
		case TLSEXT_signature_dsa:
			have_dsa = 1;
			break;
#endif
#ifndef OPENSSL_NO_ECDSA
		case TLSEXT_signature_ecdsa:
			have_ecdsa = 1;
			break;
#endif
			}
		}
	/* Disable auth and static DH if we don't include any appropriate
	 * signature algorithms.
	 */
	if (!have_rsa)
		{
		c->mask_a |= SSL_aRSA;
		c->mask_k |= SSL_kDHr|SSL_kECDHr;
		}
	if (!have_dsa)
		{
		c->mask_a |= SSL_aDSS;
		c->mask_k |= SSL_kDHd;
		}
	if (!have_ecdsa)
		{
		c->mask_a |= SSL_aECDSA;
		c->mask_k |= SSL_kECDHe;
		}
#ifndef OPENSSL_NO_KRB5
	if (!kssl_tgt_is_available(s->kssl_ctx))
		{
		c->mask_a |= SSL_aKRB5;
		c->mask_k |= SSL_kKRB5;
		}
#endif
#ifndef OPENSSL_NO_PSK
	/* with PSK there must be client callback set */
	if (!s->psk_client_callback)
		{
		c->mask_a |= SSL_aPSK;
		c->mask_k |= SSL_kPSK;
		}
#endif /* OPENSSL_NO_PSK */
	c->valid = 1;
	}

Project: openssl

static int tls1_check_ec_key(SSL *s,
			unsigned char *curve_id, unsigned char *comp_id)
	{
	const unsigned char *p;
	size_t plen, i;
	int j;
	/* If point formats extension present check it, otherwise everything
	 * is supported (see RFC4492).
	 */
	if (comp_id && s->session->tlsext_ecpointformatlist)
		{
		p = s->session->tlsext_ecpointformatlist;
		plen = s->session->tlsext_ecpointformatlist_length;
		for (i = 0; i < plen; i++, p++)
			{
			if (*comp_id == *p)
				break;
			}
		if (i == plen)
			return 0;
		}
	if (!curve_id)
		return 1;
	/* Check curve is consistent with client and server preferences */
	for (j = 0; j <= 1; j++)
		{
		tls1_get_curvelist(s, j, &p, &plen);
		for (i = 0; i < plen; i+=2, p+=2)
			{
			if (p[0] == curve_id[0] && p[1] == curve_id[1])
				break;
			}
		if (i == plen)
			return 0;
		/* For clients can only check sent curve list */
		if (!s->server)
			return 1;
		}
	return 1;
	}

Project: openssl

int tls1_shared_curve(SSL *s, int nmatch)
	{
	const unsigned char *pref, *supp;
	size_t preflen, supplen, i, j;
	int k;
	/* Can't do anything on client side */
	if (s->server == 0)
		return -1;
	if (nmatch == -2)
		{
		if (tls1_suiteb(s))
			{
			/* For Suite B ciphersuite determines curve: we 
			 * already know these are acceptable due to previous
			 * checks.
			 */
			unsigned long cid = s->s3->tmp.new_cipher->id;
			if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
				return NID_X9_62_prime256v1; /* P-256 */
			if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
				return NID_secp384r1; /* P-384 */
			/* Should never happen */
			return NID_undef;
			}
		/* If not Suite B just return first preference shared curve */
		nmatch = 0;
		}
	tls1_get_curvelist(s, !!(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE),
				&supp, &supplen);
	tls1_get_curvelist(s, !(s->options & SSL_OP_CIPHER_SERVER_PREFERENCE),
				&pref, &preflen);
	preflen /= 2;
	supplen /= 2;
	k = 0;
	for (i = 0; i < preflen; i++, pref+=2)
		{
		const unsigned char *tsupp = supp;
		for (j = 0; j < supplen; j++, tsupp+=2)
			{
			if (pref[0] == tsupp[0] && pref[1] == tsupp[1])
				{
				if (nmatch == k)
					{
					int id = (pref[0] << 8) | pref[1];
					return tls1_ec_curve_id2nid(id);
					}
				k++;
				}
			}
		}
	if (nmatch == -1)
		return k;
	return 0;
	}

Project: openssl

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 (SSL_get_options(s) & SSL_OP_NO_TICKET)
		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;
	}

Project: openssl

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 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_do_shared_sigalgs(NULL, pref, preflen, allow, allowlen);
	if (!nmatch)
		return 1;
	salgs = OPENSSL_malloc(nmatch * sizeof(TLS_SIGALGS));
	if (!salgs)
		return 0;
	nmatch = tls12_do_shared_sigalgs(salgs, pref, preflen, allow, allowlen);
	c->shared_sigalgs = salgs;
	c->shared_sigalgslen = nmatch;
	return 1;
	}

Project: openssl

int tls1_check_curve(SSL *s, const unsigned char *p, size_t len)
	{
	const unsigned char *curves;
	size_t curveslen, i;
	unsigned int suiteb_flags = tls1_suiteb(s);
	if (len != 3 || p[0] != NAMED_CURVE_TYPE)
		return 0;
	/* Check curve matches Suite B preferences */
	if (suiteb_flags)
		{
		unsigned long cid = s->s3->tmp.new_cipher->id;
		if (p[1])
			return 0;
		if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256)
			{
			if (p[2] != TLSEXT_curve_P_256)
				return 0;
			}
		else if (cid == TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
			{
			if (p[2] != TLSEXT_curve_P_384)
				return 0;
			}
		else	/* Should never happen */
			return 0;
		}
	tls1_get_curvelist(s, 0, &curves, &curveslen);
	for (i = 0; i < curveslen; i += 2, curves += 2)
		{
		if (p[1] == curves[0] && p[2] == curves[1])
			return 1;
		}
	return 0;
	}

Project: openssl

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;

	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;
	}