summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDr. Stephen Henson <steve@openssl.org>2013-04-06 15:50:12 +0100
committerDr. Stephen Henson <steve@openssl.org>2013-04-09 14:02:48 +0100
commitc6913eeb762edffddecaaba5c84909d7a7962927 (patch)
treea57c3c33e23b846852f00ec4681c6fdeccf8ea85
parent04638f2fc335a6dc2af8e5d556d36e29c261dcd2 (diff)
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.
-rw-r--r--CHANGES5
-rw-r--r--apps/s_client.c5
-rw-r--r--apps/s_server.c5
-rw-r--r--ssl/d1_clnt.c15
-rw-r--r--ssl/d1_lib.c4
-rw-r--r--ssl/d1_meth.c7
-rw-r--r--ssl/d1_pkt.c19
-rw-r--r--ssl/d1_srvr.c12
-rw-r--r--ssl/dtls1.h2
-rw-r--r--ssl/s3_clnt.c52
-rw-r--r--ssl/s3_srvr.c29
-rw-r--r--ssl/ssl.h7
12 files changed, 151 insertions, 11 deletions
diff --git a/CHANGES b/CHANGES
index e770a240b7..63a85fbc1d 100644
--- a/CHANGES
+++ b/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]
diff --git a/apps/s_client.c b/apps/s_client.c
index d09d6951a4..45f6ced044 100644
--- a/apps/s_client.c
+++ b/apps/s_client.c
@@ -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();
diff --git a/apps/s_server.c b/apps/s_server.c
index 3eaee82c78..657b042d07 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -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();
diff --git a/ssl/d1_clnt.c b/ssl/d1_clnt.c
index ec7ef0d817..40acbb756b 100644
--- a/ssl/d1_clnt.c
+++ b/ssl/d1_clnt.c
@@ -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++);
diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c
index b70bce68ad..2b066e0165 100644
--- a/ssl/d1_lib.c
+++ b/ssl/d1_lib.c
@@ -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);
}
-
-
diff --git a/ssl/d1_meth.c b/ssl/d1_meth.c
index 64a22d6b09..ac86dec40d 100644
--- a/ssl/d1_meth.c
+++ b/ssl/d1_meth.c
@@ -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)
+
diff --git a/ssl/d1_pkt.c b/ssl/d1_pkt.c
index 995e6576e0..9b600fdf53 100644
--- a/ssl/d1_pkt.c
+++ b/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;
diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c
index f18fb38a12..27f31b6762 100644
--- a/ssl/d1_srvr.c
+++ b/ssl/d1_srvr.c
@@ -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,
diff --git a/ssl/dtls1.h b/ssl/dtls1.h
index 715749ae27..c6edbe39f9 100644
--- a/ssl/dtls1.h
+++ b/ssl/dtls1.h
@@ -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... */
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 0a9bc1a99a..44ff247db2 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -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)))
{
diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c
index 0c322cb2b1..200f4951fb 100644
--- a/ssl/s3_srvr.c
+++ b/ssl/s3_srvr.c
@@ -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);
diff --git a/ssl/ssl.h b/ssl/ssl.h
index 7072c2fbf3..cba5f4d748 100644
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -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);