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.
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 0a9bc1a..44ff247 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -694,6 +694,36 @@
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 @@
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 @@
#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 @@
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 @@
}
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)))
{