*/
#include <stdio.h>
+#include <assert.h>
#include <openssl/objects.h>
#include "ssl_locl.h"
#include <openssl/md5.h>
* Fill a ClientRandom or ServerRandom field of length len. Returns <= 0 on
* failure, 1 on success.
*/
-int ssl_fill_hello_random(SSL *s, int server, unsigned char *result, size_t len)
+int ssl_fill_hello_random(SSL *s, int server, unsigned char *result, size_t len,
+ DOWNGRADE dgrd)
{
- int send_time = 0;
+ int send_time = 0, ret;
if (len < 4)
return 0;
unsigned char *p = result;
l2n(Time, p);
/* TODO(size_t): Convert this */
- return RAND_bytes(p, (int)(len - 4));
- } else
- return RAND_bytes(result, (int)len);
+ ret = RAND_bytes(p, (int)(len - 4));
+ } else {
+ ret = RAND_bytes(result, (int)len);
+ }
+#ifndef OPENSSL_NO_TLS13DOWNGRADE
+ if (ret) {
+ static const unsigned char tls11downgrade[] = {
+ 0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x00
+ };
+ static const unsigned char tls12downgrade[] = {
+ 0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01
+ };
+
+ assert(sizeof(tls11downgrade) < len && sizeof(tls12downgrade) < len);
+ if (dgrd == DOWNGRADE_TO_1_2)
+ memcpy(result + len - sizeof(tls12downgrade), tls12downgrade,
+ sizeof(tls12downgrade));
+ else if (dgrd == DOWNGRADE_TO_1_1)
+ memcpy(result + len - sizeof(tls11downgrade), tls11downgrade,
+ sizeof(tls11downgrade));
+ }
+#endif
+ return ret;
}
int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen,
} SSL3_COMP;
# endif
+typedef enum downgrade_en {
+ DOWNGRADE_NONE,
+ DOWNGRADE_TO_1_2,
+ DOWNGRADE_TO_1_1
+} DOWNGRADE;
+
/*
* Extension index values NOTE: Any updates to these defines should be mirrored
* with equivalent updates to ext_defs in extensions.c
void ssl_sort_cipher_list(void);
void ssl_load_ciphers(void);
__owur int ssl_fill_hello_random(SSL *s, int server, unsigned char *field,
- size_t len);
+ size_t len, DOWNGRADE dgrd);
__owur int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen,
int free_pms);
__owur EVP_PKEY *ssl_generate_pkey(EVP_PKEY *pm);
__owur int ssl_set_client_hello_version(SSL *s);
__owur int ssl_check_version_downgrade(SSL *s);
__owur int ssl_set_version_bound(int method_version, int version, int *bound);
-__owur int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello);
+__owur int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello,
+ DOWNGRADE *dgrd);
__owur int ssl_choose_client_version(SSL *s, int version);
int ssl_get_client_min_max_version(const SSL *s, int *min_version,
int *max_version);
} else
i = 1;
- if (i && ssl_fill_hello_random(s, 0, p, sizeof(s->s3->client_random)) <= 0)
+ if (i && ssl_fill_hello_random(s, 0, p, sizeof(s->s3->client_random),
+ DOWNGRADE_NONE) <= 0)
return 0;
/*-
# error Code needs update for TLS_method() support beyond TLS1_3_VERSION.
#endif
+/* Must be in order high to low */
static const version_info tls_version_table[] = {
#ifndef OPENSSL_NO_TLS1_3
{TLS1_3_VERSION, tlsv1_3_client_method, tlsv1_3_server_method},
# error Code needs update for DTLS_method() support beyond DTLS1_2_VERSION.
#endif
+/* Must be in order high to low */
static const version_info dtls_version_table[] = {
#ifndef OPENSSL_NO_DTLS1_2
{DTLS1_2_VERSION, dtlsv1_2_client_method, dtlsv1_2_server_method},
return 1;
}
+static void check_for_downgrade(SSL *s, int vers, DOWNGRADE *dgrd)
+{
+ if (vers == TLS1_2_VERSION
+ && ssl_version_supported(s, TLS1_3_VERSION)) {
+ *dgrd = DOWNGRADE_TO_1_2;
+ } else if (!SSL_IS_DTLS(s) && vers < TLS1_2_VERSION
+ && (ssl_version_supported(s, TLS1_2_VERSION)
+ || ssl_version_supported(s, TLS1_3_VERSION))) {
+ *dgrd = DOWNGRADE_TO_1_1;
+ } else {
+ *dgrd = DOWNGRADE_NONE;
+ }
+}
+
/*
* ssl_choose_server_version - Choose server (D)TLS version. Called when the
* client HELLO is received to select the final server protocol version and
*
* Returns 0 on success or an SSL error reason number on failure.
*/
-int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello)
+int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello, DOWNGRADE *dgrd)
{
/*-
* With version-flexible methods we have an initial state with:
if (!SSL_IS_TLS13(s)) {
if (version_cmp(s, client_version, s->version) < 0)
return SSL_R_WRONG_SSL_VERSION;
+ *dgrd = DOWNGRADE_NONE;
/*
* If this SSL handle is not from a version flexible method we don't
* (and never did) check min/max FIPS or Suite B constraints. Hope
return SSL_R_UNSUPPORTED_PROTOCOL;
return 0;
}
+ check_for_downgrade(s, best_vers, dgrd);
s->version = best_vers;
s->method = best_method;
return 0;
continue;
method = vent->smeth();
if (ssl_method_error(s, method) == 0) {
+ check_for_downgrade(s, vent->version, dgrd);
s->version = vent->version;
s->method = method;
return 0;
STACK_OF(SSL_CIPHER) *ciphers = NULL;
STACK_OF(SSL_CIPHER) *scsvs = NULL;
CLIENTHELLO_MSG *clienthello = s->clienthello;
+ DOWNGRADE dgrd = DOWNGRADE_NONE;
*al = SSL_AD_INTERNAL_ERROR;
/* Finished parsing the ClientHello, now we can start processing it */
* versions are potentially compatible. Version negotiation comes later.
*/
if (!SSL_IS_DTLS(s)) {
- protverr = ssl_choose_server_version(s, clienthello);
+ protverr = ssl_choose_server_version(s, clienthello, &dgrd);
} else if (s->method->version != DTLS_ANY_VERSION &&
DTLS_VERSION_LT((int)clienthello->legacy_version, s->version)) {
protverr = SSL_R_VERSION_TOO_LOW;
s->d1->cookie_verified = 1;
}
if (s->method->version == DTLS_ANY_VERSION) {
- protverr = ssl_choose_server_version(s, clienthello);
+ protverr = ssl_choose_server_version(s, clienthello, &dgrd);
if (protverr != 0) {
SSLerr(SSL_F_TLS_EARLY_POST_PROCESS_CLIENT_HELLO, protverr);
s->version = s->client_version;
{
unsigned char *pos;
pos = s->s3->server_random;
- if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE) <= 0) {
+ if (ssl_fill_hello_random(s, 1, pos, SSL3_RANDOM_SIZE, dgrd) <= 0) {
goto err;
}
}