summaryrefslogtreecommitdiffstats
path: root/ssl
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2015-03-31 00:18:31 +0100
committerMatt Caswell <matt@openssl.org>2015-05-16 09:20:31 +0100
commit13c9bb3ecec5f847b4c5295249e039d386e2d10e (patch)
tree8a3c816a718d72049d44dc24b6c2239fe954eab0 /ssl
parent32ec41539b5b23bc42503589fcc5be65d648d1f5 (diff)
Client side version negotiation rewrite
Continuing from the previous commit this changes the way we do client side version negotiation. Similarly all of the s23* "up front" state machine code has been avoided and again things now work much the same way as they already did for DTLS, i.e. we just do most of the work in the ssl3_get_server_hello() function. Reviewed-by: Kurt Roeckx <kurt@openssl.org>
Diffstat (limited to 'ssl')
-rw-r--r--ssl/record/rec_layer_s3.c14
-rw-r--r--ssl/record/ssl3_record.c3
-rw-r--r--ssl/s23_clnt.c9
-rw-r--r--ssl/s3_clnt.c104
-rw-r--r--ssl/t1_clnt.c11
5 files changed, 115 insertions, 26 deletions
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index 97f6e900c5..c20af880e3 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -1124,6 +1124,20 @@ int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
goto f_err;
}
+ if(s->version == TLS_ANY_VERSION
+ && (s->server || rr->type != SSL3_RT_ALERT)) {
+ /*
+ * If we've got this far and still haven't decided on what version
+ * we're using then this must be a client side alert we're dealing with
+ * (we don't allow heartbeats yet). We shouldn't be receiving anything
+ * other than a ClientHello if we are a server.
+ */
+ s->version = rr->rec_version;
+ al = SSL_AD_UNEXPECTED_MESSAGE;
+ SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_UNEXPECTED_MESSAGE);
+ goto f_err;
+ }
+
/*
* In case of record types for which we have 'fragment' storage, fill
* that so that we can process the data at a fixed place.
diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c
index 190abd26e8..ff09f0b16a 100644
--- a/ssl/record/ssl3_record.c
+++ b/ssl/record/ssl3_record.c
@@ -263,7 +263,8 @@ int ssl3_get_record(SSL *s)
/* Lets check version */
if (!s->first_packet) {
- if (version != s->version) {
+ if (version != s->version
+ && s->method->version != TLS_ANY_VERSION) {
SSLerr(SSL_F_SSL3_GET_RECORD, SSL_R_WRONG_VERSION_NUMBER);
if ((s->version & 0xFF00) == (version & 0xFF00)
&& !s->enc_write_ctx && !s->write_hash)
diff --git a/ssl/s23_clnt.c b/ssl/s23_clnt.c
index 34343402c8..75a0582f95 100644
--- a/ssl/s23_clnt.c
+++ b/ssl/s23_clnt.c
@@ -116,9 +116,11 @@
#include <openssl/objects.h>
#include <openssl/evp.h>
-static const SSL_METHOD *ssl23_get_client_method(int ver);
+/*static const SSL_METHOD *ssl23_get_client_method(int ver);*/
static int ssl23_client_hello(SSL *s);
static int ssl23_get_server_hello(SSL *s);
+
+/*
static const SSL_METHOD *ssl23_get_client_method(int ver)
{
#ifndef OPENSSL_NO_SSL3
@@ -134,10 +136,7 @@ static const SSL_METHOD *ssl23_get_client_method(int ver)
else
return (NULL);
}
-
-IMPLEMENT_ssl23_meth_func(SSLv23_client_method,
- ssl_undefined_function,
- ssl23_connect, ssl23_get_client_method)
+*/
int ssl23_connect(SSL *s)
{
diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c
index 2228654f8e..1bc5bcd9b1 100644
--- a/ssl/s3_clnt.c
+++ b/ssl/s3_clnt.c
@@ -234,7 +234,8 @@ int ssl3_connect(SSL *s)
if (cb != NULL)
cb(s, SSL_CB_HANDSHAKE_START, 1);
- if ((s->version & 0xff00) != 0x0300) {
+ if ((s->version >> 8) != SSL3_VERSION_MAJOR
+ && s->version != TLS_ANY_VERSION) {
SSLerr(SSL_F_SSL3_CONNECT, ERR_R_INTERNAL_ERROR);
s->state = SSL_ST_ERR;
ret = -1;
@@ -679,27 +680,46 @@ int ssl3_client_hello(SSL *s)
int j;
SSL_COMP *comp;
#endif
+ unsigned long mask, options = s->options;
buf = (unsigned char *)s->init_buf->data;
if (s->state == SSL3_ST_CW_CLNT_HELLO_A) {
SSL_SESSION *sess = s->session;
- if ((sess == NULL) || (sess->ssl_version != s->version) ||
-#ifdef OPENSSL_NO_TLSEXT
- !sess->session_id_length ||
-#else
+
+ if (s->method->version == TLS_ANY_VERSION ) {
/*
- * In the case of EAP-FAST, we can have a pre-shared
- * "ticket" without a session ID.
+ * SSL_OP_NO_X disables all protocols above X *if* there are
+ * some protocols below X enabled. This is required in order
+ * to maintain "version capability" vector contiguous. So
+ * that if application wants to disable TLS1.0 in favour of
+ * TLS1>=1, it would be insufficient to pass SSL_NO_TLSv1, the
+ * answer is SSL_OP_NO_TLSv1|SSL_OP_NO_SSLv3.
*/
- (!sess->session_id_length && !sess->tlsext_tick) ||
+ mask = SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1
+#if !defined(OPENSSL_NO_SSL3)
+ | SSL_OP_NO_SSLv3
#endif
- (sess->not_resumable)) {
- if (!ssl_get_new_session(s, 0))
- goto err;
- }
- if (s->method->version == DTLS_ANY_VERSION) {
+ ;
+#if !defined(OPENSSL_NO_TLS1_2_CLIENT)
+ s->version = TLS1_2_VERSION;
+
+ if ((options & SSL_OP_NO_TLSv1_2) && (options & mask) != mask)
+ s->version = TLS1_1_VERSION;
+#else
+ s->version = TLS1_1_VERSION;
+#endif
+ mask &= ~SSL_OP_NO_TLSv1_1;
+ if ((options & SSL_OP_NO_TLSv1_1) && (options & mask) != mask)
+ s->version = TLS1_VERSION;
+ mask &= ~SSL_OP_NO_TLSv1;
+#if !defined(OPENSSL_NO_SSL3)
+ if ((options & SSL_OP_NO_TLSv1) && (options & mask) != mask)
+ s->version = SSL3_VERSION;
+ mask &= ~SSL_OP_NO_SSLv3;
+#endif
+ s->client_version = s->version;
+ } else 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) {
if (tls1_suiteb(s)) {
@@ -729,6 +749,21 @@ int ssl3_client_hello(SSL *s)
}
s->client_version = s->version;
}
+
+ if ((sess == NULL) || (sess->ssl_version != s->version) ||
+#ifdef OPENSSL_NO_TLSEXT
+ !sess->session_id_length ||
+#else
+ /*
+ * In the case of EAP-FAST, we can have a pre-shared
+ * "ticket" without a session ID.
+ */
+ (!sess->session_id_length && !sess->tlsext_tick) ||
+#endif
+ (sess->not_resumable)) {
+ if (!ssl_get_new_session(s, 0))
+ goto err;
+ }
/* else use the pre-loaded session */
p = s->s3->client_random;
@@ -934,7 +969,42 @@ int ssl3_get_server_hello(SSL *s)
}
d = p = (unsigned char *)s->init_msg;
- if (s->method->version == DTLS_ANY_VERSION) {
+
+ if (s->method->version == TLS_ANY_VERSION) {
+ int sversion = (p[0] << 8) | p[1];
+
+#if TLS_MAX_VERSION != TLS1_2_VERSION
+#error Code needs updating for new TLS version
+#endif
+#ifndef OPENSSL_NO_SSL3
+ if ((sversion == SSL3_VERSION) && !(s->options & SSL_OP_NO_SSLv3)) {
+ if (FIPS_mode()) {
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,
+ SSL_R_ONLY_TLS_ALLOWED_IN_FIPS_MODE);
+ goto err;
+ }
+ s->method = SSLv3_client_method();
+ } else
+#endif
+ if ((sversion == TLS1_VERSION) && !(s->options & SSL_OP_NO_TLSv1)) {
+ s->method = TLSv1_client_method();
+ } else if ((sversion == TLS1_1_VERSION) &&
+ !(s->options & SSL_OP_NO_TLSv1_1)) {
+ s->method = TLSv1_1_client_method();
+ } else if ((sversion == TLS1_2_VERSION) &&
+ !(s->options & SSL_OP_NO_TLSv1_2)) {
+ s->method = TLSv1_2_client_method();
+ } else {
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_UNSUPPORTED_PROTOCOL);
+ goto err;
+ }
+ s->session->ssl_version = s->version = s->method->version;
+
+ if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_VERSION_TOO_LOW);
+ goto err;
+ }
+ } else 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;
@@ -955,9 +1025,7 @@ int ssl3_get_server_hello(SSL *s)
goto f_err;
}
s->version = s->method->version;
- }
-
- if ((p[0] != (s->version >> 8)) || (p[1] != (s->version & 0xff))) {
+ } else if ((p[0] != (s->version >> 8)) || (p[1] != (s->version & 0xff))) {
SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, SSL_R_WRONG_SSL_VERSION);
s->version = (s->version & 0xff00) | p[1];
al = SSL_AD_PROTOCOL_VERSION;
diff --git a/ssl/t1_clnt.c b/ssl/t1_clnt.c
index 746b4e6b7a..7ead372bc3 100644
--- a/ssl/t1_clnt.c
+++ b/ssl/t1_clnt.c
@@ -66,6 +66,8 @@
static const SSL_METHOD *tls1_get_client_method(int ver);
static const SSL_METHOD *tls1_get_client_method(int ver)
{
+ if (ver == TLS_ANY_VERSION)
+ return TLS_server_method();
if (ver == TLS1_2_VERSION)
return TLSv1_2_client_method();
if (ver == TLS1_1_VERSION)
@@ -75,16 +77,21 @@ static const SSL_METHOD *tls1_get_client_method(int ver)
return NULL;
}
+IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, TLS_client_method,
+ ssl_undefined_function,
+ ssl3_connect,
+ tls1_get_client_method, TLSv1_2_enc_data)
+
IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_client_method,
ssl_undefined_function,
ssl3_connect,
tls1_get_client_method, TLSv1_2_enc_data)
- IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_client_method,
+IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_client_method,
ssl_undefined_function,
ssl3_connect,
tls1_get_client_method, TLSv1_1_enc_data)
- IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_client_method,
+IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_client_method,
ssl_undefined_function,
ssl3_connect, tls1_get_client_method, TLSv1_enc_data)