mirror of https://github.com/openssl/openssl.git
				
				
				
			Dual DTLS version methods.
Add new methods DTLS_*_method() which support both DTLS 1.0 and DTLS 1.2 and pick the highest version the peer supports during negotiation. As with SSL/TLS options can change this behaviour specifically SSL_OP_NO_DTLSv1 and SSL_OP_NO_DTLSv1_2.
This commit is contained in:
		
							parent
							
								
									04638f2fc3
								
							
						
					
					
						commit
						c6913eeb76
					
				
							
								
								
									
										5
									
								
								CHANGES
								
								
								
								
							
							
						
						
									
										5
									
								
								CHANGES
								
								
								
								
							|  | @ -4,6 +4,11 @@ | |||
| 
 | ||||
|  Changes between 1.0.x and 1.1.0  [xx XXX xxxx] | ||||
| 
 | ||||
|   *) Support for DTLS 1.2. This adds two sets of DTLS methods: DTLS_*_method() | ||||
|      supports both DTLS 1.2 and 1.0 and should use whatever version the peer | ||||
|      supports and DTLSv1_2_*_method() which supports DTLS 1.2 only. | ||||
|      [Steve Henson] | ||||
| 
 | ||||
|   *) Make openssl verify return errors. | ||||
|      [Chris Palmer <palmer@google.com> and Ben Laurie] | ||||
| 
 | ||||
|  |  | |||
|  | @ -881,6 +881,11 @@ static char *jpake_secret = NULL; | |||
| 			meth=TLSv1_client_method(); | ||||
| #endif | ||||
| #ifndef OPENSSL_NO_DTLS1 | ||||
| 		else if	(strcmp(*argv,"-dtls") == 0) | ||||
| 			{ | ||||
| 			meth=DTLS_client_method(); | ||||
| 			socket_type=SOCK_DGRAM; | ||||
| 			} | ||||
| 		else if	(strcmp(*argv,"-dtls1") == 0) | ||||
| 			{ | ||||
| 			meth=DTLSv1_client_method(); | ||||
|  |  | |||
|  | @ -1362,6 +1362,11 @@ int MAIN(int argc, char *argv[]) | |||
| 			{ meth=TLSv1_2_server_method(); } | ||||
| #endif | ||||
| #ifndef OPENSSL_NO_DTLS1 | ||||
| 		else if	(strcmp(*argv,"-dtls") == 0) | ||||
| 			{  | ||||
| 			meth=DTLS_server_method(); | ||||
| 			socket_type = SOCK_DGRAM; | ||||
| 			} | ||||
| 		else if	(strcmp(*argv,"-dtls1") == 0) | ||||
| 			{  | ||||
| 			meth=DTLSv1_server_method(); | ||||
|  |  | |||
|  | @ -155,6 +155,13 @@ IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, | |||
| 			dtls1_get_client_method, | ||||
| 			DTLSv1_2_enc_data) | ||||
| 
 | ||||
| IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, | ||||
| 			DTLS_client_method, | ||||
| 			ssl_undefined_function, | ||||
| 			dtls1_connect, | ||||
| 			dtls1_get_client_method, | ||||
| 			DTLSv1_2_enc_data) | ||||
| 
 | ||||
| int dtls1_connect(SSL *s) | ||||
| 	{ | ||||
| 	BUF_MEM *buf=NULL; | ||||
|  | @ -785,12 +792,14 @@ static int dtls1_get_hello_verify(SSL *s) | |||
| 	unsigned char *data; | ||||
| 	unsigned int cookie_len; | ||||
| 
 | ||||
| 	s->first_packet = 1; | ||||
| 	n=s->method->ssl_get_message(s, | ||||
| 		DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A, | ||||
| 		DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B, | ||||
| 		-1, | ||||
| 		s->max_cert_list, | ||||
| 		&ok); | ||||
| 	s->first_packet = 0; | ||||
| 
 | ||||
| 	if (!ok) return((int)n); | ||||
| 
 | ||||
|  | @ -802,14 +811,16 @@ static int dtls1_get_hello_verify(SSL *s) | |||
| 		} | ||||
| 
 | ||||
| 	data = (unsigned char *)s->init_msg; | ||||
| 
 | ||||
| 	if ((data[0] != (s->version>>8)) || (data[1] != (s->version&0xff))) | ||||
| #if 0 | ||||
| 	if (s->method->version != DTLS_ANY_VERSION && | ||||
| 		((data[0] != (s->version>>8)) || (data[1] != (s->version&0xff)))) | ||||
| 		{ | ||||
| 		SSLerr(SSL_F_DTLS1_GET_HELLO_VERIFY,SSL_R_WRONG_SSL_VERSION); | ||||
| 		s->version=(s->version&0xff00)|data[1]; | ||||
| 		al = SSL_AD_PROTOCOL_VERSION; | ||||
| 		goto f_err; | ||||
| 		} | ||||
| #endif | ||||
| 	data+=2; | ||||
| 
 | ||||
| 	cookie_len = *(data++); | ||||
|  |  | |||
|  | @ -267,6 +267,8 @@ void dtls1_clear(SSL *s) | |||
| 	ssl3_clear(s); | ||||
| 	if (s->options & SSL_OP_CISCO_ANYCONNECT) | ||||
| 		s->version=DTLS1_BAD_VER; | ||||
| 	else if (s->method->version == DTLS_ANY_VERSION) | ||||
| 		s->version=DTLS1_2_VERSION; | ||||
| 	else | ||||
| 		s->version=s->method->version; | ||||
| 	} | ||||
|  | @ -526,5 +528,3 @@ static int dtls1_handshake_write(SSL *s) | |||
| 	{ | ||||
| 	return dtls1_do_write(s, SSL3_RT_HANDSHAKE); | ||||
| 	} | ||||
| 	 | ||||
| 	 | ||||
|  |  | |||
|  | @ -86,3 +86,10 @@ IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, | |||
| 			dtls1_get_method, | ||||
| 			DTLSv1_2_enc_data) | ||||
| 
 | ||||
| IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, | ||||
| 			DTLS_method, | ||||
| 			dtls1_accept, | ||||
| 			dtls1_connect, | ||||
| 			dtls1_get_method, | ||||
| 			DTLSv1_2_enc_data) | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										19
									
								
								ssl/d1_pkt.c
								
								
								
								
							
							
						
						
									
										19
									
								
								ssl/d1_pkt.c
								
								
								
								
							|  | @ -1546,9 +1546,22 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len, | |||
| 
 | ||||
| 	*(p++)=type&0xff; | ||||
| 	wr->type=type; | ||||
| 
 | ||||
| 	*(p++)=(s->version>>8); | ||||
| 	*(p++)=s->version&0xff; | ||||
| 	/* Special case: for hello verify request, client version 1.0 and
 | ||||
| 	 * we haven't decided which version to use yet send back using  | ||||
| 	 * version 1.0 header: otherwise some clients will ignore it. | ||||
| 	 */ | ||||
| 	if (s->state == DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B | ||||
| 			&& s->method->version == DTLS_ANY_VERSION | ||||
| 			&& s->client_version == DTLS1_VERSION) | ||||
| 		{ | ||||
| 		*(p++)=DTLS1_VERSION>>8; | ||||
| 		*(p++)=DTLS1_VERSION&0xff; | ||||
| 		} | ||||
| 	else | ||||
| 		{ | ||||
| 		*(p++)=s->version>>8; | ||||
| 		*(p++)=s->version&0xff; | ||||
| 		} | ||||
| 
 | ||||
| 	/* field where we are to write out packet epoch, seq num and len */ | ||||
| 	pseq=p;  | ||||
|  |  | |||
|  | @ -153,6 +153,13 @@ IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, | |||
| 			dtls1_get_server_method, | ||||
| 			DTLSv1_2_enc_data) | ||||
| 
 | ||||
| IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, | ||||
| 			DTLS_server_method, | ||||
| 			dtls1_accept, | ||||
| 			ssl_undefined_function, | ||||
| 			dtls1_get_server_method, | ||||
| 			DTLSv1_2_enc_data) | ||||
| 
 | ||||
| int dtls1_accept(SSL *s) | ||||
| 	{ | ||||
| 	BUF_MEM *buf; | ||||
|  | @ -884,8 +891,9 @@ int dtls1_send_hello_verify_request(SSL *s) | |||
| 		buf = (unsigned char *)s->init_buf->data; | ||||
| 
 | ||||
| 		msg = p = &(buf[DTLS1_HM_HEADER_LENGTH]); | ||||
| 		*(p++) = s->version >> 8; | ||||
| 		*(p++) = s->version & 0xFF; | ||||
| 		/* Always use DTLS 1.0 version: see RFC 6347 */ | ||||
| 		*(p++) = DTLS1_VERSION >> 8; | ||||
| 		*(p++) = DTLS1_VERSION & 0xFF; | ||||
| 
 | ||||
| 		if (s->ctx->app_gen_cookie_cb == NULL || | ||||
| 		     s->ctx->app_gen_cookie_cb(s, s->d1->cookie, | ||||
|  |  | |||
|  | @ -86,6 +86,8 @@ extern "C" { | |||
| #define DTLS1_VERSION			0xFEFF | ||||
| #define DTLS1_BAD_VER			0x0100 | ||||
| #define DTLS1_2_VERSION			0xFEFD | ||||
| /* Special value for method supporting multiple versions */ | ||||
| #define DTLS_ANY_VERSION		0x1FFFF | ||||
| 
 | ||||
| #if 0 | ||||
| /* this alert description is not specified anywhere... */ | ||||
|  |  | |||
|  | @ -694,6 +694,36 @@ int ssl3_client_hello(SSL *s) | |||
| 			if (!ssl_get_new_session(s,0)) | ||||
| 				goto err; | ||||
| 			} | ||||
| 		if (s->method->version == DTLS_ANY_VERSION) | ||||
| 			{ | ||||
| 			/* Determine which DTLS version to use */ | ||||
| 			int options = s->options; | ||||
| 			/* If DTLS 1.2 disabled correct the version number */ | ||||
| 			if (options & SSL_OP_NO_DTLSv1_2) | ||||
| 				{ | ||||
| 				/* Disabling all versions is silly: return an
 | ||||
| 				 * error. | ||||
| 				 */ | ||||
| 				if (options & SSL_OP_NO_DTLSv1) | ||||
| 					{ | ||||
| 					SSLerr(SSL_F_SSL3_CLIENT_HELLO,SSL_R_WRONG_SSL_VERSION); | ||||
| 					goto err; | ||||
| 					} | ||||
| 				/* Update method so we don't use any DTLS 1.2
 | ||||
| 				 * features. | ||||
| 				 */ | ||||
| 				s->method = DTLSv1_client_method(); | ||||
| 				s->version = DTLS1_VERSION; | ||||
| 				} | ||||
| 			else | ||||
| 				{ | ||||
| 				/* We only support one version: update method */ | ||||
| 				if (options & SSL_OP_NO_DTLSv1) | ||||
| 					s->method = DTLSv1_2_client_method(); | ||||
| 				s->version = DTLS1_2_VERSION; | ||||
| 				} | ||||
| 			s->client_version = s->version; | ||||
| 			} | ||||
| 		/* else use the pre-loaded session */ | ||||
| 
 | ||||
| 		p=s->s3->client_random; | ||||
|  | @ -721,6 +751,7 @@ int ssl3_client_hello(SSL *s) | |||
| 			Time=(unsigned long)time(NULL);	/* Time */ | ||||
| 			l2n(Time,p); | ||||
| 			RAND_pseudo_bytes(p,sizeof(s->s3->client_random)-4); | ||||
| 					 | ||||
| 			} | ||||
| 
 | ||||
| 		/* Do the message type and length last */ | ||||
|  | @ -873,6 +904,11 @@ int ssl3_get_server_hello(SSL *s) | |||
| #ifndef OPENSSL_NO_COMP | ||||
| 	SSL_COMP *comp; | ||||
| #endif | ||||
| 	/* Hello verify request and/or server hello version may not
 | ||||
| 	 * match so set first packet if we're negotiating version. | ||||
| 	 */ | ||||
| 	if (s->method->version == DTLS_ANY_VERSION) | ||||
| 		s->first_packet = 1; | ||||
| 
 | ||||
| 	n=s->method->ssl_get_message(s, | ||||
| 		SSL3_ST_CR_SRVR_HELLO_A, | ||||
|  | @ -885,6 +921,7 @@ int ssl3_get_server_hello(SSL *s) | |||
| 
 | ||||
| 	if (SSL_IS_DTLS(s)) | ||||
| 		{ | ||||
| 		s->first_packet = 0; | ||||
| 		if ( s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST) | ||||
| 			{ | ||||
| 			if ( s->d1->send_cookie == 0) | ||||
|  | @ -909,6 +946,21 @@ int ssl3_get_server_hello(SSL *s) | |||
| 		} | ||||
| 
 | ||||
| 	d=p=(unsigned char *)s->init_msg; | ||||
| 	if (s->method->version == DTLS_ANY_VERSION) | ||||
| 		{ | ||||
| 		/* Work out correct protocol version to use */ | ||||
| 		int hversion = (p[0] << 8)|p[1]; | ||||
| 		int options = s->options; | ||||
| 		if (hversion == DTLS1_2_VERSION | ||||
| 			&& !(options & SSL_OP_NO_DTLSv1_2)) | ||||
| 			s->method = DTLSv1_2_client_method(); | ||||
| 		else if (hversion == DTLS1_VERSION | ||||
| 			&& !(options & SSL_OP_NO_DTLSv1)) | ||||
| 			s->method = DTLSv1_client_method(); | ||||
| 		else | ||||
| 			SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,SSL_R_WRONG_SSL_VERSION); | ||||
| 		s->version = s->client_version = s->method->version; | ||||
| 		} | ||||
| 
 | ||||
| 	if ((p[0] != (s->version>>8)) || (p[1] != (s->version&0xff))) | ||||
| 		{ | ||||
|  |  | |||
|  | @ -967,8 +967,9 @@ int ssl3_get_client_hello(SSL *s) | |||
| 	s->client_version=(((int)p[0])<<8)|(int)p[1]; | ||||
| 	p+=2; | ||||
| 
 | ||||
| 	if ((s->version == DTLS1_VERSION && s->client_version > s->version) || | ||||
| 	    (s->version != DTLS1_VERSION && s->client_version < s->version)) | ||||
| 	if ((SSL_IS_DTLS(s) && s->client_version > s->version | ||||
| 			&& s->method->version != DTLS_ANY_VERSION) || | ||||
| 	    (!SSL_IS_DTLS(s) && s->client_version < s->version)) | ||||
| 		{ | ||||
| 		SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER); | ||||
| 		if ((s->client_version>>8) == SSL3_VERSION_MAJOR) | ||||
|  | @ -1086,6 +1087,30 @@ int ssl3_get_client_hello(SSL *s) | |||
| 			} | ||||
| 
 | ||||
| 		p += cookie_len; | ||||
| 		if (s->method->version == DTLS_ANY_VERSION) | ||||
| 			{ | ||||
| 			/* Select version to use */ | ||||
| 			if (s->client_version <= DTLS1_2_VERSION && | ||||
| 				!(s->options & SSL_OP_NO_DTLSv1_2)) | ||||
| 				{ | ||||
| 				s->version = DTLS1_2_VERSION; | ||||
| 				s->method = DTLSv1_2_server_method(); | ||||
| 				} | ||||
| 			else if (s->client_version <= DTLS1_VERSION && | ||||
| 				!(s->options & SSL_OP_NO_DTLSv1)) | ||||
| 				{ | ||||
| 				s->version = DTLS1_VERSION; | ||||
| 				s->method = DTLSv1_server_method(); | ||||
| 				} | ||||
| 			else | ||||
| 				{ | ||||
| 				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER); | ||||
| 				s->version = s->client_version; | ||||
| 				al = SSL_AD_PROTOCOL_VERSION; | ||||
| 				goto f_err; | ||||
| 				} | ||||
| 			s->session->ssl_version = s->version; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 	n2s(p,i); | ||||
|  |  | |||
|  | @ -617,6 +617,9 @@ struct ssl_session_st | |||
| #define SSL_OP_NO_TLSv1_2				0x08000000L | ||||
| #define SSL_OP_NO_TLSv1_1				0x10000000L | ||||
| 
 | ||||
| #define SSL_OP_NO_DTLSv1				0x04000000L | ||||
| #define SSL_OP_NO_DTLSv1_2				0x08000000L | ||||
| 
 | ||||
| #define SSL_OP_NO_SSL_MASK (SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|\ | ||||
| 	SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2) | ||||
| 
 | ||||
|  | @ -2115,6 +2118,10 @@ const SSL_METHOD *DTLSv1_2_method(void);	/* DTLSv1.2 */ | |||
| const SSL_METHOD *DTLSv1_2_server_method(void);	/* DTLSv1.2 */ | ||||
| const SSL_METHOD *DTLSv1_2_client_method(void);	/* DTLSv1.2 */ | ||||
| 
 | ||||
| const SSL_METHOD *DTLS_method(void);		/* DTLS 1.0 and 1.2 */ | ||||
| const SSL_METHOD *DTLS_server_method(void);	/* DTLS 1.0 and 1.2 */ | ||||
| const SSL_METHOD *DTLS_client_method(void);	/* DTLS 1.0 and 1.2 */ | ||||
| 
 | ||||
| STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s); | ||||
| 
 | ||||
| int SSL_do_handshake(SSL *s); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue