Continue with a randomized premaster if decryption failed / version mismatches

This commit is contained in:
Martin Willi
2010-09-02 19:33:08 +02:00
parent 1dfd6d18ff
commit 60c4b3b545
+41 -9
View File
@@ -108,6 +108,11 @@ struct private_tls_server_t {
* Selected TLS cipher 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;
}
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;
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,
tls_reader_t *reader)
{
chunk_t encrypted, premaster;
chunk_t encrypted, decrypted;
char premaster[48];
rng_t *rng;
this->crypto->append_handshake(this->crypto,
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;
}
if (!this->private ||
!this->private->decrypt(this->private, ENCRYPT_RSA_PKCS1,
encrypted, &premaster))
htoun16(premaster, this->client_version);
/* pre-randomize premaster for failure cases */
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
if (!rng)
{
DBG1(DBG_TLS, "decrypting Client Key Exchange data failed");
this->alert->add(this->alert, TLS_FATAL, TLS_DECRYPT_ERROR);
DBG1(DBG_TLS, "creating RNG failed");
this->alert->add(this->alert, TLS_FATAL, TLS_INTERNAL_ERROR);
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->server_random));
chunk_clear(&premaster);
this->state = STATE_KEY_EXCHANGE_RECEIVED;
return NEED_MORE;