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.
(cherry picked from commit c6913eeb76)

Conflicts:

	CHANGES
This commit is contained in:
Dr. Stephen Henson 2013-04-06 15:50:12 +01:00
parent b60b9e7afe
commit 65a87d3cc3
11 changed files with 146 additions and 11 deletions

View File

@ -912,6 +912,11 @@ static char *jpake_secret = NULL;
meth=TLSv1_client_method(); meth=TLSv1_client_method();
#endif #endif
#ifndef OPENSSL_NO_DTLS1 #ifndef OPENSSL_NO_DTLS1
else if (strcmp(*argv,"-dtls") == 0)
{
meth=DTLS_client_method();
socket_type=SOCK_DGRAM;
}
else if (strcmp(*argv,"-dtls1") == 0) else if (strcmp(*argv,"-dtls1") == 0)
{ {
meth=DTLSv1_client_method(); meth=DTLSv1_client_method();

View File

@ -1369,6 +1369,11 @@ int MAIN(int argc, char *argv[])
{ meth=TLSv1_2_server_method(); } { meth=TLSv1_2_server_method(); }
#endif #endif
#ifndef OPENSSL_NO_DTLS1 #ifndef OPENSSL_NO_DTLS1
else if (strcmp(*argv,"-dtls") == 0)
{
meth=DTLS_server_method();
socket_type = SOCK_DGRAM;
}
else if (strcmp(*argv,"-dtls1") == 0) else if (strcmp(*argv,"-dtls1") == 0)
{ {
meth=DTLSv1_server_method(); meth=DTLSv1_server_method();

View File

@ -155,6 +155,13 @@ IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
dtls1_get_client_method, dtls1_get_client_method,
DTLSv1_2_enc_data) 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) int dtls1_connect(SSL *s)
{ {
BUF_MEM *buf=NULL; BUF_MEM *buf=NULL;
@ -785,12 +792,14 @@ static int dtls1_get_hello_verify(SSL *s)
unsigned char *data; unsigned char *data;
unsigned int cookie_len; unsigned int cookie_len;
s->first_packet = 1;
n=s->method->ssl_get_message(s, n=s->method->ssl_get_message(s,
DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A, DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A,
DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B, DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B,
-1, -1,
s->max_cert_list, s->max_cert_list,
&ok); &ok);
s->first_packet = 0;
if (!ok) return((int)n); if (!ok) return((int)n);
@ -802,14 +811,16 @@ static int dtls1_get_hello_verify(SSL *s)
} }
data = (unsigned char *)s->init_msg; data = (unsigned char *)s->init_msg;
#if 0
if ((data[0] != (s->version>>8)) || (data[1] != (s->version&0xff))) 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); SSLerr(SSL_F_DTLS1_GET_HELLO_VERIFY,SSL_R_WRONG_SSL_VERSION);
s->version=(s->version&0xff00)|data[1]; s->version=(s->version&0xff00)|data[1];
al = SSL_AD_PROTOCOL_VERSION; al = SSL_AD_PROTOCOL_VERSION;
goto f_err; goto f_err;
} }
#endif
data+=2; data+=2;
cookie_len = *(data++); cookie_len = *(data++);

View File

@ -267,6 +267,8 @@ void dtls1_clear(SSL *s)
ssl3_clear(s); ssl3_clear(s);
if (s->options & SSL_OP_CISCO_ANYCONNECT) if (s->options & SSL_OP_CISCO_ANYCONNECT)
s->version=DTLS1_BAD_VER; s->version=DTLS1_BAD_VER;
else if (s->method->version == DTLS_ANY_VERSION)
s->version=DTLS1_2_VERSION;
else else
s->version=s->method->version; s->version=s->method->version;
} }
@ -522,5 +524,3 @@ static int dtls1_handshake_write(SSL *s)
{ {
return dtls1_do_write(s, SSL3_RT_HANDSHAKE); return dtls1_do_write(s, SSL3_RT_HANDSHAKE);
} }

View File

@ -86,3 +86,10 @@ IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
dtls1_get_method, dtls1_get_method,
DTLSv1_2_enc_data) DTLSv1_2_enc_data)
IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION,
DTLS_method,
dtls1_accept,
dtls1_connect,
dtls1_get_method,
DTLSv1_2_enc_data)

View File

@ -1552,9 +1552,22 @@ int do_dtls1_write(SSL *s, int type, const unsigned char *buf, unsigned int len,
*(p++)=type&0xff; *(p++)=type&0xff;
wr->type=type; wr->type=type;
/* Special case: for hello verify request, client version 1.0 and
*(p++)=(s->version>>8); * we haven't decided which version to use yet send back using
*(p++)=s->version&0xff; * 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 */ /* field where we are to write out packet epoch, seq num and len */
pseq=p; pseq=p;

View File

@ -153,6 +153,13 @@ IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION,
dtls1_get_server_method, dtls1_get_server_method,
DTLSv1_2_enc_data) 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) int dtls1_accept(SSL *s)
{ {
BUF_MEM *buf; BUF_MEM *buf;
@ -885,8 +892,9 @@ int dtls1_send_hello_verify_request(SSL *s)
buf = (unsigned char *)s->init_buf->data; buf = (unsigned char *)s->init_buf->data;
msg = p = &(buf[DTLS1_HM_HEADER_LENGTH]); msg = p = &(buf[DTLS1_HM_HEADER_LENGTH]);
*(p++) = s->version >> 8; /* Always use DTLS 1.0 version: see RFC 6347 */
*(p++) = s->version & 0xFF; *(p++) = DTLS1_VERSION >> 8;
*(p++) = DTLS1_VERSION & 0xFF;
if (s->ctx->app_gen_cookie_cb == NULL || if (s->ctx->app_gen_cookie_cb == NULL ||
s->ctx->app_gen_cookie_cb(s, s->d1->cookie, s->ctx->app_gen_cookie_cb(s, s->d1->cookie,

View File

@ -86,6 +86,8 @@ extern "C" {
#define DTLS1_VERSION 0xFEFF #define DTLS1_VERSION 0xFEFF
#define DTLS1_BAD_VER 0x0100 #define DTLS1_BAD_VER 0x0100
#define DTLS1_2_VERSION 0xFEFD #define DTLS1_2_VERSION 0xFEFD
/* Special value for method supporting multiple versions */
#define DTLS_ANY_VERSION 0x1FFFF
#if 0 #if 0
/* this alert description is not specified anywhere... */ /* this alert description is not specified anywhere... */

View File

@ -694,6 +694,36 @@ int ssl3_client_hello(SSL *s)
if (!ssl_get_new_session(s,0)) if (!ssl_get_new_session(s,0))
goto err; 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 */ /* else use the pre-loaded session */
p=s->s3->client_random; p=s->s3->client_random;
@ -721,6 +751,7 @@ int ssl3_client_hello(SSL *s)
Time=(unsigned long)time(NULL); /* Time */ Time=(unsigned long)time(NULL); /* Time */
l2n(Time,p); l2n(Time,p);
RAND_pseudo_bytes(p,sizeof(s->s3->client_random)-4); RAND_pseudo_bytes(p,sizeof(s->s3->client_random)-4);
} }
/* Do the message type and length last */ /* Do the message type and length last */
@ -873,6 +904,11 @@ int ssl3_get_server_hello(SSL *s)
#ifndef OPENSSL_NO_COMP #ifndef OPENSSL_NO_COMP
SSL_COMP *comp; SSL_COMP *comp;
#endif #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, n=s->method->ssl_get_message(s,
SSL3_ST_CR_SRVR_HELLO_A, SSL3_ST_CR_SRVR_HELLO_A,
@ -885,6 +921,7 @@ int ssl3_get_server_hello(SSL *s)
if (SSL_IS_DTLS(s)) if (SSL_IS_DTLS(s))
{ {
s->first_packet = 0;
if ( s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST) if ( s->s3->tmp.message_type == DTLS1_MT_HELLO_VERIFY_REQUEST)
{ {
if ( s->d1->send_cookie == 0) if ( s->d1->send_cookie == 0)
@ -909,6 +946,21 @@ int ssl3_get_server_hello(SSL *s)
} }
d=p=(unsigned char *)s->init_msg; 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))) if ((p[0] != (s->version>>8)) || (p[1] != (s->version&0xff)))
{ {

View File

@ -968,8 +968,9 @@ int ssl3_get_client_hello(SSL *s)
s->client_version=(((int)p[0])<<8)|(int)p[1]; s->client_version=(((int)p[0])<<8)|(int)p[1];
p+=2; p+=2;
if ((s->version == DTLS1_VERSION && s->client_version > s->version) || if ((SSL_IS_DTLS(s) && s->client_version > s->version
(s->version != DTLS1_VERSION && 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); SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER);
if ((s->client_version>>8) == SSL3_VERSION_MAJOR) if ((s->client_version>>8) == SSL3_VERSION_MAJOR)
@ -1087,6 +1088,30 @@ int ssl3_get_client_hello(SSL *s)
} }
p += cookie_len; 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); n2s(p,i);

View File

@ -668,6 +668,9 @@ struct ssl_session_st
#define SSL_OP_NO_TLSv1_2 0x08000000L #define SSL_OP_NO_TLSv1_2 0x08000000L
#define SSL_OP_NO_TLSv1_1 0x10000000L #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|\ #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) SSL_OP_NO_TLSv1|SSL_OP_NO_TLSv1_1|SSL_OP_NO_TLSv1_2)
@ -2209,6 +2212,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_server_method(void); /* DTLSv1.2 */
const SSL_METHOD *DTLSv1_2_client_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); STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s);
int SSL_do_handshake(SSL *s); int SSL_do_handshake(SSL *s);