Skip to content

Commit

Permalink
Allow different protocol version when trying to reuse a session
Browse files Browse the repository at this point in the history
We now send the highest supported version by the client, even if the session
uses an older version.

This fixes 2 problems:
- When you try to reuse a session but the other side doesn't reuse it and
  uses a different protocol version the connection will fail.
- When you're trying to reuse a session with an old version you might be
  stuck trying to reuse the old version while both sides support a newer
  version

Signed-off-by: Kurt Roeckx <kurt@roeckx.be>
Reviewed-by: Viktor Dukhovni <viktor@openssl.org>

GH: #852, MR: #2452
  • Loading branch information
indutny authored and kroeckx committed Mar 27, 2016
1 parent ce84456 commit ccae4a1
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 167 deletions.
1 change: 1 addition & 0 deletions include/openssl/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -2511,6 +2511,7 @@ void ERR_load_SSL_strings(void);
# define SSL_R_SSL_SESSION_ID_CONFLICT 302
# define SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG 273
# define SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH 303
# define SSL_R_SSL_SESSION_VERSION_MISMATCH 210
# define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER 232
# define SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT 365
# define SSL_R_TLS_HEARTBEAT_PENDING 366
Expand Down
166 changes: 24 additions & 142 deletions ssl/methods.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,315 +116,197 @@
* TLS/SSLv3 methods
*/

static const SSL_METHOD *tls1_get_method(int ver)
{
if (ver == TLS_ANY_VERSION)
return TLS_method();
#ifndef OPENSSL_NO_TLS1_2
if (ver == TLS1_2_VERSION)
return tlsv1_2_method();
#endif
#ifndef OPENSSL_NO_TLS1_1
if (ver == TLS1_1_VERSION)
return tlsv1_1_method();
#endif
#ifndef OPENSSL_NO_TLS1
if (ver == TLS1_VERSION)
return tlsv1_method();
#endif
#ifndef OPENSSL_NO_SSL3
if (ver == SSL3_VERSION)
return (sslv3_method());
else
#endif
return NULL;
}

IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, 0, 0,
TLS_method,
ossl_statem_accept,
ossl_statem_connect, tls1_get_method, TLSv1_2_enc_data)
ossl_statem_connect, TLSv1_2_enc_data)

#ifndef OPENSSL_NO_TLS1_2_METHOD
IMPLEMENT_tls_meth_func(TLS1_2_VERSION, 0, SSL_OP_NO_TLSv1_2,
tlsv1_2_method,
ossl_statem_accept,
ossl_statem_connect, tls1_get_method, TLSv1_2_enc_data)
ossl_statem_connect, TLSv1_2_enc_data)
#endif

#ifndef OPENSSL_NO_TLS1_1_METHOD
IMPLEMENT_tls_meth_func(TLS1_1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1_1,
tlsv1_1_method,
ossl_statem_accept,
ossl_statem_connect, tls1_get_method, TLSv1_1_enc_data)
ossl_statem_connect, TLSv1_1_enc_data)
#endif

#ifndef OPENSSL_NO_TLS1_METHOD
IMPLEMENT_tls_meth_func(TLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1,
tlsv1_method,
ossl_statem_accept,
ossl_statem_connect, tls1_get_method, TLSv1_enc_data)
ossl_statem_connect, TLSv1_enc_data)
#endif

#ifndef OPENSSL_NO_SSL3_METHOD
IMPLEMENT_ssl3_meth_func(sslv3_method, ossl_statem_accept, ossl_statem_connect,
tls1_get_method)
IMPLEMENT_ssl3_meth_func(sslv3_method, ossl_statem_accept, ossl_statem_connect)
#endif


/*
* TLS/SSLv3 server methods
*/

static const SSL_METHOD *tls1_get_server_method(int ver)
{
if (ver == TLS_ANY_VERSION)
return TLS_server_method();
#ifndef OPENSSL_NO_TLS1_2
if (ver == TLS1_2_VERSION)
return tlsv1_2_server_method();
#endif
#ifndef OPENSSL_NO_TLS1_1
if (ver == TLS1_1_VERSION)
return tlsv1_1_server_method();
#endif
#ifndef OPENSSL_NO_TLS1
if (ver == TLS1_VERSION)
return tlsv1_server_method();
#endif
#ifndef OPENSSL_NO_SSL3
if (ver == SSL3_VERSION)
return (sslv3_server_method());
#endif
return NULL;
}

IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, 0, 0,
TLS_server_method,
ossl_statem_accept,
ssl_undefined_function,
tls1_get_server_method, TLSv1_2_enc_data)
TLSv1_2_enc_data)

#ifndef OPENSSL_NO_TLS1_2_METHOD
IMPLEMENT_tls_meth_func(TLS1_2_VERSION, 0, SSL_OP_NO_TLSv1_2,
tlsv1_2_server_method,
ossl_statem_accept,
ssl_undefined_function,
tls1_get_server_method, TLSv1_2_enc_data)
TLSv1_2_enc_data)
#endif

#ifndef OPENSSL_NO_TLS1_1_METHOD
IMPLEMENT_tls_meth_func(TLS1_1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1_1,
tlsv1_1_server_method,
ossl_statem_accept,
ssl_undefined_function,
tls1_get_server_method, TLSv1_1_enc_data)
TLSv1_1_enc_data)
#endif

#ifndef OPENSSL_NO_TLS1_METHOD
IMPLEMENT_tls_meth_func(TLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1,
tlsv1_server_method,
ossl_statem_accept,
ssl_undefined_function,
tls1_get_server_method, TLSv1_enc_data)
TLSv1_enc_data)
#endif

#ifndef OPENSSL_NO_SSL3_METHOD
IMPLEMENT_ssl3_meth_func(sslv3_server_method,
ossl_statem_accept,
ssl_undefined_function, tls1_get_server_method)
ssl_undefined_function)
#endif


/*
* TLS/SSLv3 client methods
*/

static const SSL_METHOD *tls1_get_client_method(int ver)
{
if (ver == TLS_ANY_VERSION)
return TLS_client_method();
#ifndef OPENSSL_NO_TLS1_2
if (ver == TLS1_2_VERSION)
return tlsv1_2_client_method();
#endif
#ifndef OPENSSL_NO_TLS1_1
if (ver == TLS1_1_VERSION)
return tlsv1_1_client_method();
#endif
#ifndef OPENSSL_NO_TLS1
if (ver == TLS1_VERSION)
return tlsv1_client_method();
#endif
#ifndef OPENSSL_NO_SSL3
if (ver == SSL3_VERSION)
return (sslv3_client_method());
#endif
return NULL;
}

IMPLEMENT_tls_meth_func(TLS_ANY_VERSION, 0, 0,
TLS_client_method,
ssl_undefined_function,
ossl_statem_connect,
tls1_get_client_method, TLSv1_2_enc_data)
TLSv1_2_enc_data)

#ifndef OPENSSL_NO_TLS1_2_METHOD
IMPLEMENT_tls_meth_func(TLS1_2_VERSION, 0, SSL_OP_NO_TLSv1_2,
tlsv1_2_client_method,
ssl_undefined_function,
ossl_statem_connect,
tls1_get_client_method, TLSv1_2_enc_data)
TLSv1_2_enc_data)
#endif

#ifndef OPENSSL_NO_TLS1_1_METHOD
IMPLEMENT_tls_meth_func(TLS1_1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1_1,
tlsv1_1_client_method,
ssl_undefined_function,
ossl_statem_connect,
tls1_get_client_method, TLSv1_1_enc_data)
TLSv1_1_enc_data)
#endif

#ifndef OPENSSL_NO_TLS1_METHOD
IMPLEMENT_tls_meth_func(TLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_TLSv1,
tlsv1_client_method,
ssl_undefined_function,
ossl_statem_connect,
tls1_get_client_method, TLSv1_enc_data)
TLSv1_enc_data)
#endif

#ifndef OPENSSL_NO_SSL3_METHOD
IMPLEMENT_ssl3_meth_func(sslv3_client_method,
ssl_undefined_function,
ossl_statem_connect, tls1_get_client_method)
ossl_statem_connect)
#endif


/*
* DTLS methods
*/
static const SSL_METHOD *dtls1_get_method(int ver)
{
if (ver == DTLS_ANY_VERSION)
return DTLS_method();
#ifndef OPENSSL_NO_DTLS1
else if (ver == DTLS1_VERSION)
return dtlsv1_method();
#endif
#ifndef OPENSSL_NO_DTLS1_2
else if (ver == DTLS1_2_VERSION)
return dtlsv1_2_method();
#endif
else
return NULL;
}

#ifndef OPENSSL_NO_DTLS1_METHOD
IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_DTLSv1,
dtlsv1_method,
ossl_statem_accept,
ossl_statem_connect,
dtls1_get_method, DTLSv1_enc_data)
DTLSv1_enc_data)
#endif

#ifndef OPENSSL_NO_DTLS1_2_METHOD
IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, 0, SSL_OP_NO_DTLSv1_2,
dtlsv1_2_method,
ossl_statem_accept,
ossl_statem_connect,
dtls1_get_method, DTLSv1_2_enc_data)
DTLSv1_2_enc_data)
#endif

IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, 0, 0,
DTLS_method,
ossl_statem_accept,
ossl_statem_connect,
dtls1_get_method, DTLSv1_2_enc_data)
DTLSv1_2_enc_data)

/*
* DTLS server methods
*/

static const SSL_METHOD *dtls1_get_server_method(int ver)
{
if (ver == DTLS_ANY_VERSION)
return DTLS_server_method();
#ifndef OPENSSL_NO_DTLS1
else if (ver == DTLS1_VERSION)
return dtlsv1_server_method();
#endif
#ifndef OPENSSL_NO_DTLS1_2
else if (ver == DTLS1_2_VERSION)
return dtlsv1_2_server_method();
#endif
else
return NULL;
}

#ifndef OPENSSL_NO_DTLS1_METHOD
IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_DTLSv1,
dtlsv1_server_method,
ossl_statem_accept,
ssl_undefined_function,
dtls1_get_server_method, DTLSv1_enc_data)
DTLSv1_enc_data)
#endif

#ifndef OPENSSL_NO_DTLS1_2_METHOD
IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, 0, SSL_OP_NO_DTLSv1_2,
dtlsv1_2_server_method,
ossl_statem_accept,
ssl_undefined_function,
dtls1_get_server_method, DTLSv1_2_enc_data)
DTLSv1_2_enc_data)
#endif

IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, 0, 0,
DTLS_server_method,
ossl_statem_accept,
ssl_undefined_function,
dtls1_get_server_method, DTLSv1_2_enc_data)
DTLSv1_2_enc_data)


/*
* DTLS client methods
*/

static const SSL_METHOD *dtls1_get_client_method(int ver)
{
if (ver == DTLS_ANY_VERSION)
return DTLS_client_method();
#ifndef OPENSSL_NO_DTLS1
else if (ver == DTLS1_VERSION || ver == DTLS1_BAD_VER)
return dtlsv1_client_method();
#endif
#ifndef OPENSSL_NO_DTLS1_2
else if (ver == DTLS1_2_VERSION)
return dtlsv1_2_client_method();
#endif
else
return NULL;
}

#ifndef OPENSSL_NO_DTLS1_METHOD
IMPLEMENT_dtls1_meth_func(DTLS1_VERSION, SSL_METHOD_NO_SUITEB, SSL_OP_NO_DTLSv1,
dtlsv1_client_method,
ssl_undefined_function,
ossl_statem_connect,
dtls1_get_client_method, DTLSv1_enc_data)
DTLSv1_enc_data)
#endif

#ifndef OPENSSL_NO_DTLS1_2_METHOD
IMPLEMENT_dtls1_meth_func(DTLS1_2_VERSION, 0, SSL_OP_NO_DTLSv1_2,
dtlsv1_2_client_method,
ssl_undefined_function,
ossl_statem_connect,
dtls1_get_client_method, DTLSv1_2_enc_data)
DTLSv1_2_enc_data)
#endif

IMPLEMENT_dtls1_meth_func(DTLS_ANY_VERSION, 0, 0,
DTLS_client_method,
ssl_undefined_function,
ossl_statem_connect,
dtls1_get_client_method, DTLSv1_2_enc_data)
DTLSv1_2_enc_data)

#if OPENSSL_API_COMPAT < 0x10100000L

Expand Down
2 changes: 2 additions & 0 deletions ssl/ssl_err.c
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,8 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
"ssl session id context too long"},
{ERR_REASON(SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH),
"ssl session id has bad length"},
{ERR_REASON(SSL_R_SSL_SESSION_VERSION_MISMATCH),
"ssl session version mismatch"},
{ERR_REASON(SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER),
"tls client cert req with anon cipher"},
{ERR_REASON(SSL_R_TLS_HEARTBEAT_PEER_DOESNT_ACCEPT),
Expand Down
Loading

0 comments on commit ccae4a1

Please sign in to comment.