Skip to content

Commit

Permalink
This change alters the processing of invalid, RSA pre-master secrets so
Browse files Browse the repository at this point in the history
that bad encryptions are treated like random session keys in constant
time.
  • Loading branch information
Adam Langley authored and benlaurie committed Jun 13, 2013
1 parent 7e25d81 commit adb46db
Showing 1 changed file with 89 additions and 45 deletions.
134 changes: 89 additions & 45 deletions ssl/s3_srvr.c
Expand Up @@ -2195,6 +2195,10 @@ int ssl3_get_client_key_exchange(SSL *s)
#ifndef OPENSSL_NO_RSA
if (alg_k & SSL_kRSA)
{
unsigned char rand_premaster_secret[SSL_MAX_MASTER_KEY_LENGTH];
int decrypt_len, decrypt_good_mask;
unsigned char version_good;

/* FIX THIS UP EAY EAY EAY EAY */
if (s->s3->tmp.use_rsa_tmp)
{
Expand Down Expand Up @@ -2242,54 +2246,94 @@ int ssl3_get_client_key_exchange(SSL *s)
n=i;
}

i=RSA_private_decrypt((int)n,p,p,rsa,RSA_PKCS1_PADDING);

al = -1;

if (i != SSL_MAX_MASTER_KEY_LENGTH)
{
al=SSL_AD_DECODE_ERROR;
/* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_RSA_DECRYPT); */
}

if ((al == -1) && !((p[0] == (s->client_version>>8)) && (p[1] == (s->client_version & 0xff))))
{
/* The premaster secret must contain the same version number as the
* ClientHello to detect version rollback attacks (strangely, the
* protocol does not offer such protection for DH ciphersuites).
* However, buggy clients exist that send the negotiated protocol
* version instead if the server does not support the requested
* protocol version.
* If SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients. */
if (!((s->options & SSL_OP_TLS_ROLLBACK_BUG) &&
(p[0] == (s->version>>8)) && (p[1] == (s->version & 0xff))))
{
al=SSL_AD_DECODE_ERROR;
/* SSLerr(SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE,SSL_R_BAD_PROTOCOL_VERSION_NUMBER); */
/* We must not leak whether a decryption failure occurs because
* of Bleichenbacher's attack on PKCS #1 v1.5 RSA padding (see
* RFC 2246, section 7.4.7.1). The code follows that advice of
* the TLS RFC and generates a random premaster secret for the
* case that the decrypt fails. See
* https://tools.ietf.org/html/rfc5246#section-7.4.7.1 */

/* The Klima-Pokorny-Rosa extension of Bleichenbacher's attack
* (http://eprint.iacr.org/2003/052/) exploits the version
* number check as a "bad version oracle" -- an alert would
* reveal that the plaintext corresponding to some ciphertext
* made up by the adversary is properly formatted except
* that the version number is wrong. To avoid such attacks,
* we should treat this just like any other decryption error. */
}
/* should be RAND_bytes, but we cannot work around a failure. */
if (RAND_pseudo_bytes(rand_premaster_secret,
sizeof(rand_premaster_secret)) <= 0)
goto err;
decrypt_len = RSA_private_decrypt((int)n,p,p,rsa,RSA_PKCS1_PADDING);
ERR_clear_error();

/* decrypt_len should be SSL_MAX_MASTER_KEY_LENGTH.
* decrypt_good_mask will be zero if so and non-zero otherwise. */
decrypt_good_mask = decrypt_len ^ SSL_MAX_MASTER_KEY_LENGTH;

/* If the version in the decrypted pre-master secret is correct
* then version_good will be zero. The Klima-Pokorny-Rosa
* extension of Bleichenbacher's attack
* (http://eprint.iacr.org/2003/052/) exploits the version
* number check as a "bad version oracle". Thus version checks
* are done in constant time and are treated like any other
* decryption error. */
version_good = p[0] ^ (s->client_version>>8);
version_good |= p[1] ^ (s->client_version&0xff);

/* The premaster secret must contain the same version number as
* the ClientHello to detect version rollback attacks
* (strangely, the protocol does not offer such protection for
* DH ciphersuites). However, buggy clients exist that send the
* negotiated protocol version instead if the server does not
* support the requested protocol version. If
* SSL_OP_TLS_ROLLBACK_BUG is set, tolerate such clients. */
if (s->options & SSL_OP_TLS_ROLLBACK_BUG)
{
unsigned char workaround_mask = version_good;
unsigned char workaround;

/* workaround_mask will be 0xff if version_good is
* non-zero (i.e. the version match failed). Otherwise
* it'll be 0x00. */
workaround_mask |= workaround_mask >> 4;
workaround_mask |= workaround_mask >> 2;
workaround_mask |= workaround_mask >> 1;
workaround_mask = ~((workaround_mask & 1) - 1);

workaround = p[0] ^ (s->version>>8);
workaround |= p[1] ^ (s->version&0xff);

/* If workaround_mask is 0xff (i.e. there was a version
* mismatch) then we copy the value of workaround over
* version_good. */
version_good = (workaround & workaround_mask) |
(version_good & ~workaround_mask);
}

/* If any bits in version_good are set then they'll poision
* decrypt_good_mask and cause rand_premaster_secret to be
* used. */
decrypt_good_mask |= version_good;

/* decrypt_good_mask will be zero iff decrypt_len ==
* SSL_MAX_MASTER_KEY_LENGTH and the version check passed. We
* fold the bottom 32 bits of it with an OR so that the LSB
* will be zero iff everything is good. This assumes that we'll
* never decrypt a value > 2**31 bytes, which seems safe. */
decrypt_good_mask |= decrypt_good_mask >> 16;
decrypt_good_mask |= decrypt_good_mask >> 8;
decrypt_good_mask |= decrypt_good_mask >> 4;
decrypt_good_mask |= decrypt_good_mask >> 2;
decrypt_good_mask |= decrypt_good_mask >> 1;
/* Now select only the LSB and subtract one. If decrypt_len ==
* SSL_MAX_MASTER_KEY_LENGTH and the version check passed then
* decrypt_good_mask will be all ones. Otherwise it'll be all
* zeros. */
decrypt_good_mask &= 1;
decrypt_good_mask--;

/* Now copy rand_premaster_secret over p using
* decrypt_good_mask. */
for (i = 0; i < (int) sizeof(rand_premaster_secret); i++)
{
p[i] = (p[i] & decrypt_good_mask) |
(rand_premaster_secret[i] & ~decrypt_good_mask);
}

if (al != -1)
{
/* Some decryption failure -- use random value instead as countermeasure
* against Bleichenbacher's attack on PKCS #1 v1.5 RSA padding
* (see RFC 2246, section 7.4.7.1). */
ERR_clear_error();
i = SSL_MAX_MASTER_KEY_LENGTH;
p[0] = s->client_version >> 8;
p[1] = s->client_version & 0xff;
if (RAND_pseudo_bytes(p+2, i-2) <= 0) /* should be RAND_bytes, but we cannot work around a failure */
goto err;
}

s->session->master_key_length=
s->method->ssl3_enc->generate_master_secret(s,
s->session->master_key,
Expand Down

0 comments on commit adb46db

Please sign in to comment.