Continue with a randomized premaster if decryption failed / version mismatches
This commit is contained in:
+41
-9
@@ -108,6 +108,11 @@ struct private_tls_server_t {
|
|||||||
* Selected TLS cipher suite
|
* Selected TLS cipher suite
|
||||||
*/
|
*/
|
||||||
tls_cipher_suite_t suite;
|
tls_cipher_suite_t suite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offered TLS version of the client
|
||||||
|
*/
|
||||||
|
tls_version_t client_version;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -161,7 +166,9 @@ static status_t process_client_hello(private_tls_server_t *this,
|
|||||||
return NEED_MORE;
|
return NEED_MORE;
|
||||||
}
|
}
|
||||||
DBG1(DBG_TLS, "negotiated TLS version %N with suite %N",
|
DBG1(DBG_TLS, "negotiated TLS version %N with suite %N",
|
||||||
tls_version_names, version, tls_cipher_suite_names, this->suite);
|
tls_version_names, this->tls->get_version(this->tls),
|
||||||
|
tls_cipher_suite_names, this->suite);
|
||||||
|
this->client_version = version;
|
||||||
this->state = STATE_HELLO_RECEIVED;
|
this->state = STATE_HELLO_RECEIVED;
|
||||||
return NEED_MORE;
|
return NEED_MORE;
|
||||||
}
|
}
|
||||||
@@ -232,7 +239,9 @@ static status_t process_certificate(private_tls_server_t *this,
|
|||||||
static status_t process_key_exchange(private_tls_server_t *this,
|
static status_t process_key_exchange(private_tls_server_t *this,
|
||||||
tls_reader_t *reader)
|
tls_reader_t *reader)
|
||||||
{
|
{
|
||||||
chunk_t encrypted, premaster;
|
chunk_t encrypted, decrypted;
|
||||||
|
char premaster[48];
|
||||||
|
rng_t *rng;
|
||||||
|
|
||||||
this->crypto->append_handshake(this->crypto,
|
this->crypto->append_handshake(this->crypto,
|
||||||
TLS_CLIENT_KEY_EXCHANGE, reader->peek(reader));
|
TLS_CLIENT_KEY_EXCHANGE, reader->peek(reader));
|
||||||
@@ -244,18 +253,41 @@ static status_t process_key_exchange(private_tls_server_t *this,
|
|||||||
return NEED_MORE;
|
return NEED_MORE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this->private ||
|
htoun16(premaster, this->client_version);
|
||||||
!this->private->decrypt(this->private, ENCRYPT_RSA_PKCS1,
|
/* pre-randomize premaster for failure cases */
|
||||||
encrypted, &premaster))
|
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||||
|
if (!rng)
|
||||||
{
|
{
|
||||||
DBG1(DBG_TLS, "decrypting Client Key Exchange data failed");
|
DBG1(DBG_TLS, "creating RNG failed");
|
||||||
this->alert->add(this->alert, TLS_FATAL, TLS_DECRYPT_ERROR);
|
this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
|
||||||
return NEED_MORE;
|
return NEED_MORE;
|
||||||
}
|
}
|
||||||
this->crypto->derive_secrets(this->crypto, premaster,
|
rng->get_bytes(rng, sizeof(premaster) - 2, premaster + 2);
|
||||||
|
rng->destroy(rng);
|
||||||
|
|
||||||
|
if (this->private &&
|
||||||
|
this->private->decrypt(this->private,
|
||||||
|
ENCRYPT_RSA_PKCS1, encrypted, &decrypted))
|
||||||
|
{
|
||||||
|
if (decrypted.len == sizeof(premaster) &&
|
||||||
|
untoh16(decrypted.ptr) == this->client_version)
|
||||||
|
{
|
||||||
|
memcpy(premaster + 2, decrypted.ptr + 2, sizeof(premaster) - 2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "decrypted premaster has invalid length/version");
|
||||||
|
}
|
||||||
|
chunk_clear(&decrypted);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG1(DBG_TLS, "decrypting Client Key Exchange failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->crypto->derive_secrets(this->crypto, chunk_from_thing(premaster),
|
||||||
chunk_from_thing(this->client_random),
|
chunk_from_thing(this->client_random),
|
||||||
chunk_from_thing(this->server_random));
|
chunk_from_thing(this->server_random));
|
||||||
chunk_clear(&premaster);
|
|
||||||
|
|
||||||
this->state = STATE_KEY_EXCHANGE_RECEIVED;
|
this->state = STATE_KEY_EXCHANGE_RECEIVED;
|
||||||
return NEED_MORE;
|
return NEED_MORE;
|
||||||
|
|||||||
Reference in New Issue
Block a user