Factor out remaining version-related functions.

Now SSLv23 and DTLS_ANY_VERSION share version-related helper functions.
ssl3_get_method is temporary until the method switch is no longer necessary.

Put them all together so there's one place to refactor them when we add a new
version or implement min_version/max_version controls.

Change-Id: Ic28a145cad22db08a87fdb854480b22886c451c6
Reviewed-on: https://boringssl-review.googlesource.com/2580
Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
David Benjamin
2014-12-13 22:35:52 +00:00
committed by Adam Langley
parent 69b9e597ae
commit ceb6f2880f
6 changed files with 178 additions and 155 deletions
+5 -27
View File
@@ -447,37 +447,15 @@ static int ssl23_get_server_hello(SSL *s)
((p[0] == SSL3_RT_HANDSHAKE && p[5] == SSL3_MT_SERVER_HELLO) ||
(p[0] == SSL3_RT_ALERT && p[3] == 0 && p[4] == 2)))
{
/* we have sslv3 or tls1 (server hello or alert) */
if ((p[2] == SSL3_VERSION_MINOR) &&
!(s->options & SSL_OP_NO_SSLv3))
{
s->version=SSL3_VERSION;
s->method=SSLv3_client_method();
}
else if ((p[2] == TLS1_VERSION_MINOR) &&
!(s->options & SSL_OP_NO_TLSv1))
{
s->version=TLS1_VERSION;
s->method=TLSv1_client_method();
}
else if ((p[2] == TLS1_1_VERSION_MINOR) &&
!(s->options & SSL_OP_NO_TLSv1_1))
{
s->version=TLS1_1_VERSION;
s->method=TLSv1_1_client_method();
}
else if ((p[2] == TLS1_2_VERSION_MINOR) &&
!(s->options & SSL_OP_NO_TLSv1_2))
{
s->version=TLS1_2_VERSION;
s->method=TLSv1_2_client_method();
}
else
uint16_t version = (p[1] << 8) | p[2];
if (!ssl3_is_version_enabled(s, version))
{
OPENSSL_PUT_ERROR(SSL, ssl23_get_server_hello, SSL_R_UNSUPPORTED_PROTOCOL);
goto err;
}
s->version = version;
s->method = ssl3_get_method(version);
assert(s->method != NULL);
if (p[0] == SSL3_RT_ALERT && p[5] != SSL3_AL_WARNING)
{
+8 -47
View File
@@ -121,20 +121,6 @@
static int ssl23_get_client_hello(SSL *s);
static int ssl23_get_v2_client_hello(SSL *s);
static const SSL_METHOD *ssl23_get_server_method(int ver)
{
if (ver == SSL3_VERSION)
return(SSLv3_server_method());
else if (ver == TLS1_VERSION)
return(TLSv1_server_method());
else if (ver == TLS1_1_VERSION)
return(TLSv1_1_server_method());
else if (ver == TLS1_2_VERSION)
return(TLSv1_2_server_method());
else
return(NULL);
}
int ssl23_accept(SSL *s)
{
BUF_MEM *buf;
@@ -213,7 +199,7 @@ int ssl23_accept(SSL *s)
}
s->state = SSL3_ST_SR_CLNT_HELLO_A;
s->method = ssl23_get_server_method(s->version);
s->method = ssl3_get_method(s->version);
assert(s->method != NULL);
s->handshake_func = s->method->ssl_accept;
s->init_num = 0;
@@ -246,35 +232,6 @@ end:
return(ret);
}
/* ssl23_get_mutual_version determines the highest supported version for a
* client which reports a highest version of |client_version|. On success, it
* returns 1 and sets |*out_version| to the negotiated version. Otherwise, it
* returns 0. */
static int ssl23_get_mutual_version(SSL *s, int *out_version, uint16_t client_version)
{
if (client_version >= TLS1_2_VERSION && !(s->options & SSL_OP_NO_TLSv1_2))
{
*out_version = TLS1_2_VERSION;
return 1;
}
if (client_version >= TLS1_1_VERSION && !(s->options & SSL_OP_NO_TLSv1_1))
{
*out_version = TLS1_1_VERSION;
return 1;
}
if (client_version >= TLS1_VERSION && !(s->options & SSL_OP_NO_TLSv1))
{
*out_version = TLS1_VERSION;
return 1;
}
if (client_version >= SSL3_VERSION && !(s->options & SSL_OP_NO_SSLv3))
{
*out_version = SSL3_VERSION;
return 1;
}
return 0;
}
static int ssl23_get_client_hello(SSL *s)
{
uint8_t *p;
@@ -336,11 +293,13 @@ static int ssl23_get_client_hello(SSL *s)
/* This is a V2ClientHello. Determine the version to
* use. */
uint16_t client_version = (p[3] << 8) | p[4];
if (!ssl23_get_mutual_version(s, &s->version, client_version))
uint16_t version = ssl3_get_mutual_version(s, client_version);
if (version == 0)
{
OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_UNSUPPORTED_PROTOCOL);
goto err;
}
s->version = version;
/* Parse the entire V2ClientHello. */
s->state = SSL23_ST_SR_V2_CLNT_HELLO;
}
@@ -355,7 +314,7 @@ static int ssl23_get_client_hello(SSL *s)
* this, so we simply reject such connections to avoid
* protocol version downgrade attacks. */
uint16_t record_length = (p[3] << 8) | p[4];
uint16_t client_version;
uint16_t client_version, version;
if (record_length < 6)
{
OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_RECORD_TOO_SMALL);
@@ -363,11 +322,13 @@ static int ssl23_get_client_hello(SSL *s)
}
client_version = (p[9] << 8) | p[10];
if (!ssl23_get_mutual_version(s, &s->version, client_version))
version = ssl3_get_mutual_version(s, client_version);
if (version == 0)
{
OPENSSL_PUT_ERROR(SSL, ssl23_get_client_hello, SSL_R_UNSUPPORTED_PROTOCOL);
goto err;
}
s->version = version;
/* Reset the record-layer state for SSL3. */
assert(s->rstate == SSL_ST_READ_HEADER);
+4 -53
View File
@@ -580,49 +580,6 @@ end:
return(ret);
}
uint16_t ssl3_get_max_client_version(SSL *s)
{
unsigned long options = s->options;
uint16_t version = 0;
/* OpenSSL's API for controlling versions entails blacklisting
* individual protocols. This has two problems. First, on the client,
* the protocol can only express a contiguous range of versions. Second,
* a library consumer trying to set a maximum version cannot disable
* protocol versions that get added in a future version of the library.
*
* To account for both of these, OpenSSL interprets the client-side
* bitmask as a min/max range by picking the lowest contiguous non-empty
* range of enabled protocols. Note that this means it is impossible to
* set a maximum version of TLS 1.2 in a future-proof way.
*
* By this scheme, the maximum version is the lowest version V such that
* V is enabled and V+1 is disabled or unimplemented.
*
* TODO(davidben): Deprecate this API in favor of more sensible
* min_version/max_version settings. */
if (SSL_IS_DTLS(s))
{
if (!(options & SSL_OP_NO_DTLSv1_2))
version = DTLS1_2_VERSION;
if (!(options & SSL_OP_NO_DTLSv1) && (options & SSL_OP_NO_DTLSv1_2))
version = DTLS1_VERSION;
}
else
{
if (!(options & SSL_OP_NO_TLSv1_2))
version = TLS1_2_VERSION;
if (!(options & SSL_OP_NO_TLSv1_1) && (options & SSL_OP_NO_TLSv1_2))
version = TLS1_1_VERSION;
if (!(options & SSL_OP_NO_TLSv1) && (options & SSL_OP_NO_TLSv1_1))
version = TLS1_VERSION;
if (!(options & SSL_OP_NO_SSLv3) && (options & SSL_OP_NO_TLSv1))
version = SSL3_VERSION;
}
return version;
}
int ssl3_send_client_hello(SSL *s)
{
unsigned char *buf;
@@ -816,22 +773,16 @@ int ssl3_get_server_hello(SSL *s)
if (s->method->version == DTLS_ANY_VERSION)
{
/* Work out correct protocol version to use */
int options = s->options;
if (server_version == DTLS1_2_VERSION
&& !(options & SSL_OP_NO_DTLSv1_2))
s->method = DTLSv1_2_client_method();
else if (server_version == DTLS1_VERSION
&& !(options & SSL_OP_NO_DTLSv1))
s->method = DTLSv1_client_method();
else
if (!ssl3_is_version_enabled(s, server_version))
{
OPENSSL_PUT_ERROR(SSL, ssl3_get_server_hello, SSL_R_WRONG_SSL_VERSION);
s->version = server_version;
al = SSL_AD_PROTOCOL_VERSION;
goto f_err;
}
s->version = s->method->version;
s->version = server_version;
s->method = ssl3_get_method(server_version);
assert(s->method != NULL);
}
if (server_version != s->version)
+5 -13
View File
@@ -854,25 +854,17 @@ int ssl3_get_client_hello(SSL *s)
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
uint16_t version = ssl3_get_mutual_version(s, client_version);
if (version == 0)
{
OPENSSL_PUT_ERROR(SSL, ssl3_get_client_hello, SSL_R_WRONG_VERSION_NUMBER);
s->version = s->client_version;
al = SSL_AD_PROTOCOL_VERSION;
goto f_err;
}
s->version = version;
s->method = ssl3_get_method(version);
assert(s->method != NULL);
}
}
+132 -7
View File
@@ -1498,7 +1498,9 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs)
/* Check for FALLBACK_SCSV. */
if (s->s3 && cipher_suite == (SSL3_CK_FALLBACK_SCSV & 0xffff))
{
if (s->version < ssl_get_max_version(s))
uint16_t max_version = ssl3_get_max_server_version(s);
if (SSL_IS_DTLS(s) ? (uint16_t)s->version > max_version
: (uint16_t)s->version < max_version)
{
OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_INAPPROPRIATE_FALLBACK);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_INAPPROPRIATE_FALLBACK);
@@ -3046,13 +3048,37 @@ int ssl3_can_cutthrough(const SSL *s)
return 1;
}
/* ssl_get_max_version returns the maximum SSL/TLS version number supported by
* |s|, or zero if all versions are disabled. */
int ssl_get_max_version(const SSL *s)
const SSL_METHOD *ssl3_get_method(uint16_t version)
{
/* Only one version supported for DTLS. */
if (s->version == DTLS1_VERSION)
return DTLS1_VERSION;
switch (version)
{
case SSL3_VERSION:
return SSLv3_method();
case TLS1_VERSION:
return TLSv1_method();
case TLS1_1_VERSION:
return TLSv1_1_method();
case TLS1_2_VERSION:
return TLSv1_2_method();
case DTLS1_VERSION:
return DTLSv1_method();
case DTLS1_2_VERSION:
return DTLSv1_2_method();
default:
return NULL;
}
}
uint16_t ssl3_get_max_server_version(const SSL *s)
{
if (SSL_IS_DTLS(s))
{
if (!(s->options & SSL_OP_NO_DTLSv1_2))
return DTLS1_2_VERSION;
if (!(s->options & SSL_OP_NO_DTLSv1))
return DTLS1_VERSION;
return 0;
}
if (!(s->options & SSL_OP_NO_TLSv1_2))
return TLS1_2_VERSION;
@@ -3065,6 +3091,105 @@ int ssl_get_max_version(const SSL *s)
return 0;
}
uint16_t ssl3_get_mutual_version(SSL *s, uint16_t client_version)
{
if (SSL_IS_DTLS(s))
{
if (client_version <= DTLS1_2_VERSION && !(s->options & SSL_OP_NO_DTLSv1_2))
return DTLS1_2_VERSION;
if (client_version <= DTLS1_VERSION && !(s->options & SSL_OP_NO_DTLSv1))
return DTLS1_VERSION;
return 0;
}
else
{
if (client_version >= TLS1_2_VERSION && !(s->options & SSL_OP_NO_TLSv1_2))
return TLS1_2_VERSION;
if (client_version >= TLS1_1_VERSION && !(s->options & SSL_OP_NO_TLSv1_1))
return TLS1_1_VERSION;
if (client_version >= TLS1_VERSION && !(s->options & SSL_OP_NO_TLSv1))
return TLS1_VERSION;
if (client_version >= SSL3_VERSION && !(s->options & SSL_OP_NO_SSLv3))
return SSL3_VERSION;
return 0;
}
}
uint16_t ssl3_get_max_client_version(SSL *s)
{
unsigned long options = s->options;
uint16_t version = 0;
/* OpenSSL's API for controlling versions entails blacklisting
* individual protocols. This has two problems. First, on the client,
* the protocol can only express a contiguous range of versions. Second,
* a library consumer trying to set a maximum version cannot disable
* protocol versions that get added in a future version of the library.
*
* To account for both of these, OpenSSL interprets the client-side
* bitmask as a min/max range by picking the lowest contiguous non-empty
* range of enabled protocols. Note that this means it is impossible to
* set a maximum version of TLS 1.2 in a future-proof way.
*
* By this scheme, the maximum version is the lowest version V such that
* V is enabled and V+1 is disabled or unimplemented.
*
* TODO(davidben): Deprecate this API in favor of more sensible
* min_version/max_version settings. */
if (SSL_IS_DTLS(s))
{
if (!(options & SSL_OP_NO_DTLSv1_2))
version = DTLS1_2_VERSION;
if (!(options & SSL_OP_NO_DTLSv1) && (options & SSL_OP_NO_DTLSv1_2))
version = DTLS1_VERSION;
}
else
{
if (!(options & SSL_OP_NO_TLSv1_2))
version = TLS1_2_VERSION;
if (!(options & SSL_OP_NO_TLSv1_1) && (options & SSL_OP_NO_TLSv1_2))
version = TLS1_1_VERSION;
if (!(options & SSL_OP_NO_TLSv1) && (options & SSL_OP_NO_TLSv1_1))
version = TLS1_VERSION;
if (!(options & SSL_OP_NO_SSLv3) && (options & SSL_OP_NO_TLSv1))
version = SSL3_VERSION;
}
return version;
}
int ssl3_is_version_enabled(SSL *s, uint16_t version)
{
if (SSL_IS_DTLS(s))
{
switch (version)
{
case DTLS1_VERSION:
return !(s->options & SSL_OP_NO_DTLSv1);
case DTLS1_2_VERSION:
return !(s->options & SSL_OP_NO_DTLSv1_2);
default:
return 0;
}
}
else
{
switch (version)
{
case SSL3_VERSION:
return !(s->options & SSL_OP_NO_SSLv3);
case TLS1_VERSION:
return !(s->options & SSL_OP_NO_TLSv1);
case TLS1_1_VERSION:
return !(s->options & SSL_OP_NO_TLSv1_1);
case TLS1_2_VERSION:
return !(s->options & SSL_OP_NO_TLSv1_2);
default:
return 0;
}
}
}
/* Allocates new EVP_MD_CTX and sets pointer to it into given pointer
* vairable, freeing EVP_MD_CTX previously stored in that variable, if
* any. If EVP_MD pointer is passed, initializes ctx with this md
+24 -8
View File
@@ -929,13 +929,6 @@ unsigned int dtls1_min_mtu(void);
void dtls1_hm_fragment_free(hm_fragment *frag);
/* some client-only functions */
/* ssl3_get_max_client_version returns the maximum protocol version configured
* for the client. It is guaranteed that the set of allowed versions at or below
* this maximum version is contiguous. If all versions are disabled, it returns
* zero. */
uint16_t ssl3_get_max_client_version(SSL *s);
int ssl3_send_client_hello(SSL *s);
int ssl3_get_server_hello(SSL *s);
int ssl3_get_certificate_request(SSL *s);
@@ -1078,7 +1071,30 @@ int ssl_ctx_log_master_secret(SSL_CTX *ctx,
const uint8_t *master, size_t master_len);
int ssl3_can_cutthrough(const SSL *s);
int ssl_get_max_version(const SSL *s);
/* ssl3_get_method returns the version-locked SSL_METHOD corresponding
* to |version|. */
const SSL_METHOD *ssl3_get_method(uint16_t version);
/* ssl3_get_max_server_version returns the maximum SSL/TLS version number
* supported by |s| as a server, or zero if all versions are disabled. */
uint16_t ssl3_get_max_server_version(const SSL *s);
/* ssl3_get_mutual_version selects the protocol version on |s| for a client
* which advertises |client_version|. If no suitable version exists, it returns
* zero. */
uint16_t ssl3_get_mutual_version(SSL *s, uint16_t client_version);
/* ssl3_get_max_client_version returns the maximum protocol version configured
* for the client. It is guaranteed that the set of allowed versions at or below
* this maximum version is contiguous. If all versions are disabled, it returns
* zero. */
uint16_t ssl3_get_max_client_version(SSL *s);
/* ssl3_is_version_enabled returns one if |version| is an enabled protocol
* version for |s| and zero otherwise. */
int ssl3_is_version_enabled(SSL *s, uint16_t version);
EVP_MD_CTX* ssl_replace_hash(EVP_MD_CTX **hash,const EVP_MD *md) ;
void ssl_clear_hash_ctx(EVP_MD_CTX **hash);
int ssl_add_serverhello_renegotiate_ext(SSL *s, unsigned char *p, int *len,