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>
This commit is contained in:
Matt Caswell 2015-03-31 00:18:31 +01:00
parent 32ec41539b
commit 13c9bb3ece
15 changed files with 127 additions and 38 deletions

View File

@ -1261,7 +1261,7 @@ OCSP_RESPONSE *process_responder(OCSP_REQUEST *req,
BIO_set_conn_port(cbio, port);
if (use_ssl == 1) {
BIO *sbio;
ctx = SSL_CTX_new(SSLv23_client_method());
ctx = SSL_CTX_new(TLS_client_method());
if (ctx == NULL) {
BIO_printf(bio_err, "Error creating SSL context.\n");
goto end;

View File

@ -636,7 +636,7 @@ int s_client_main(int argc, char **argv)
SSL_CONF_CTX *cctx = NULL;
STACK_OF(OPENSSL_STRING) *ssl_args = NULL;
STACK_OF(X509_CRL) *crls = NULL;
const SSL_METHOD *meth = SSLv23_client_method();
const SSL_METHOD *meth = TLS_client_method();
char *CApath = NULL, *CAfile = NULL, *cbuf = NULL, *sbuf = NULL, *mbuf =
NULL;
char *cert_file = NULL, *key_file = NULL, *chain_file = NULL, *prog;

View File

@ -167,7 +167,7 @@ int s_time_main(int argc, char **argv)
int exitNow = 0; /* Set when it's time to exit main */
#endif
meth = SSLv23_client_method();
meth = TLS_client_method();
verify_depth = 0;
verify_error = X509_V_OK;

View File

@ -17,7 +17,7 @@ int main(int argc, char **argv)
ERR_load_SSL_strings();
SSL_library_init();
ctx = SSL_CTX_new(SSLv23_client_method());
ctx = SSL_CTX_new(TLS_client_method());
cctx = SSL_CONF_CTX_new();
SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT);
SSL_CONF_CTX_set_ssl_ctx(cctx, ctx);

View File

@ -37,7 +37,7 @@ int main(int argc, char **argv)
goto end;
}
ctx = SSL_CTX_new(SSLv23_client_method());
ctx = SSL_CTX_new(TLS_client_method());
cctx = SSL_CONF_CTX_new();
SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT);
SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE);

View File

@ -43,7 +43,7 @@ char *argv[];
/* Setup all the global SSL stuff */
OpenSSL_add_ssl_algorithms();
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
ssl_ctx = SSL_CTX_new(TLS_client_method());
/* Lets make a SSL structure */
ssl = SSL_new(ssl_ctx);

View File

@ -667,7 +667,7 @@ SSL_CTX *tls_create_ctx(struct tls_create_ctx_args a, void *apparg)
return NULL;
ret =
SSL_CTX_new((a.client_p ? SSLv23_client_method :
SSL_CTX_new((a.client_p ? TLS_client_method :
TLS_server_method) ());
if (ret == NULL)

View File

@ -38,7 +38,7 @@ void main ()
SSL_METHOD *meth;
SSLeay_add_ssl_algorithms();
meth = SSLv23_client_method();
meth = TLS_client_method();
SSL_load_error_strings();
ctx = SSL_CTX_new (meth); CHK_NULL(ctx);

View File

@ -1565,14 +1565,13 @@ __owur const SSL_METHOD *SSLv3_client_method(void); /* SSLv3 */
#ifdef OPENSSL_USE_DEPRECATED
#define SSLv23_method TLS_method
#define SSLv23_server_method TLS_server_method
#define SSLv23_client_method TLS_client_method
#endif
/* This next one will be deprecated in a subsequent commit */
__owur const SSL_METHOD *SSLv23_client_method(void); /* Negotiate highest available
* SSL/TLS version */
/* Negotiate highest available SSL/TLS version */
__owur const SSL_METHOD *TLS_method(void);
__owur const SSL_METHOD *TLS_server_method(void);
__owur const SSL_METHOD *TLS_client_method(void);
__owur const SSL_METHOD *TLSv1_method(void); /* TLSv1.0 */
__owur const SSL_METHOD *TLSv1_server_method(void); /* TLSv1.0 */

View File

@ -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.

View File

@ -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)

View File

@ -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)
{

View File

@ -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;

View File

@ -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)

View File

@ -95,7 +95,7 @@ SSL_use_certificate_ASN1 106 EXIST::FUNCTION:
SSL_use_certificate_file 107 EXIST::FUNCTION:STDIO
SSL_write 108 EXIST::FUNCTION:
SSLeay_add_ssl_algorithms 109 NOEXIST::FUNCTION:
SSLv23_client_method 110 EXIST::FUNCTION:RSA
SSLv23_client_method 110 NOEXIST::FUNCTION:
SSLv23_method 111 NOEXIST::FUNCTION:
SSLv23_server_method 112 NOEXIST::FUNCTION:
SSLv2_client_method 113 NOEXIST::FUNCTION:
@ -398,3 +398,4 @@ SSL_CIPHER_get_cipher_nid 432 EXIST::FUNCTION:
SSL_use_certificate_chain_file 433 EXIST::FUNCTION:STDIO
TLS_server_method 434 EXIST::FUNCTION:
TLS_method 435 EXIST::FUNCTION:
TLS_client_method 436 EXIST::FUNCTION: