Skip to content

Commit

Permalink
Update DTLS code to match CBC decoding in TLS.
Browse files Browse the repository at this point in the history
This change updates the DTLS code to match the constant-time CBC
behaviour in the TLS.
  • Loading branch information
benlaurie committed Jan 28, 2013
1 parent 6cb19b7 commit 9f27de1
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 57 deletions.
13 changes: 10 additions & 3 deletions ssl/d1_enc.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,14 @@
#include <openssl/des.h>
#endif

/* dtls1_enc encrypts/decrypts the record in |s->wrec| / |s->rrec|, respectively.
*
* Returns:
* 0: (in non-constant time) if the record is publically invalid (i.e. too
* short etc).
* 1: if the record's padding is valid / the encryption was successful.
* -1: if the record's padding/AEAD-authenticator is invalid or, if sending,
* an internal error occured. */
int dtls1_enc(SSL *s, int send)
{
SSL3_RECORD *rec;
Expand Down Expand Up @@ -165,8 +173,7 @@ int dtls1_enc(SSL *s, int send)
if (EVP_MD_CTX_md(s->read_hash))
{
mac_size=EVP_MD_CTX_size(s->read_hash);
if (mac_size < 0)
return -1;
OPENSSL_assert(mac_size >= 0);
}
ds=s->enc_read_ctx;
rec= &(s->s3->rrec);
Expand Down Expand Up @@ -231,7 +238,7 @@ int dtls1_enc(SSL *s, int send)
if (!send)
{
if (l == 0 || l%bs != 0)
return -1;
return 0;
}

EVP_Cipher(ds,rec->data,rec->input,l);
Expand Down
86 changes: 50 additions & 36 deletions ssl/d1_pkt.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,15 +376,11 @@ static int
dtls1_process_record(SSL *s)
{
int i,al;
int clear=0;
int enc_err;
SSL_SESSION *sess;
SSL3_RECORD *rr;
unsigned int mac_size;
unsigned char md[EVP_MAX_MD_SIZE];
int decryption_failed_or_bad_record_mac = 0;
unsigned char *mac = NULL;


rr= &(s->s3->rrec);
sess = s->session;
Expand Down Expand Up @@ -417,12 +413,16 @@ dtls1_process_record(SSL *s)
rr->orig_len=rr->length;

enc_err = s->method->ssl3_enc->enc(s,0);
if (enc_err <= 0)
/* enc_err is:
* 0: (in non-constant time) if the record is publically invalid.
* 1: if the padding is valid
* -1: if the padding is invalid */
if (enc_err == 0)
{
/* To minimize information leaked via timing, we will always
* perform all computations before discarding the message.
*/
decryption_failed_or_bad_record_mac = 1;
/* For DTLS we simply ignore bad packets. */
rr->length = 0;
s->packet_length = 0;
goto err;
}

#ifdef TLS_DEBUG
Expand All @@ -432,45 +432,59 @@ printf("\n");
#endif

/* r->length is now the compressed data plus mac */
if ( (sess == NULL) ||
(s->enc_read_ctx == NULL) ||
(s->read_hash == NULL))
clear=1;

if (!clear)
if ((sess != NULL) &&
(s->enc_read_ctx != NULL) &&
(EVP_MD_CTX_md(s->read_hash) != NULL))
{
/* !clear => s->read_hash != NULL => mac_size != -1 */
int t;
t=EVP_MD_CTX_size(s->read_hash);
OPENSSL_assert(t >= 0);
mac_size=t;

if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+mac_size)
/* s->read_hash != NULL => mac_size != -1 */
unsigned char *mac = NULL;
unsigned char mac_tmp[EVP_MAX_MD_SIZE];
mac_size=EVP_MD_CTX_size(s->read_hash);
OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);

/* orig_len is the length of the record before any padding was
* removed. This is public information, as is the MAC in use,
* therefore we can safely process the record in a different
* amount of time if it's too short to possibly contain a MAC.
*/
if (rr->orig_len < mac_size ||
/* CBC records must have a padding length byte too. */
(EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
rr->orig_len < mac_size+1))
{
#if 0 /* OK only for stream ciphers (then rr->length is visible from ciphertext anyway) */
al=SSL_AD_RECORD_OVERFLOW;
SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_PRE_MAC_LENGTH_TOO_LONG);
al=SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_LENGTH_TOO_SHORT);
goto f_err;
#else
decryption_failed_or_bad_record_mac = 1;
#endif
}
/* check the MAC for rr->input (it's in mac_size bytes at the tail) */
if (rr->length >= mac_size)

if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE)
{
/* We update the length so that the TLS header bytes
* can be constructed correctly but we need to extract
* the MAC in constant time from within the record,
* without leaking the contents of the padding bytes.
* */
mac = mac_tmp;
ssl3_cbc_copy_mac(mac_tmp, rr, mac_size);
rr->length -= mac_size;
mac = &rr->data[rr->length];
}
else
rr->length = 0;
i=s->method->ssl3_enc->mac(s,md,0);
if (i < 0 || mac == NULL || CRYPTO_memcmp(md,mac,mac_size) != 0)
{
decryption_failed_or_bad_record_mac = 1;
/* In this case there's no padding, so |rec->orig_len|
* equals |rec->length| and we checked that there's
* enough bytes for |mac_size| above. */
rr->length -= mac_size;
mac = &rr->data[rr->length];
}

i=s->method->ssl3_enc->mac(s,md,0 /* not send */);
if (i < 0 || mac == NULL || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0)
enc_err = -1;
if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+mac_size)
enc_err = -1;
}

if (decryption_failed_or_bad_record_mac)
if (enc_err < 0)
{
/* decryption failed, silently discard message */
rr->length = 0;
Expand Down
4 changes: 0 additions & 4 deletions ssl/s3_enc.c
Original file line number Diff line number Diff line change
Expand Up @@ -531,11 +531,7 @@ int ssl3_enc(SSL *s, int send)
if (!send)
{
if (l == 0 || l%bs != 0)
{
SSLerr(SSL_F_SSL3_ENC,SSL_R_BLOCK_CIPHER_PAD_IS_WRONG);
ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECRYPTION_FAILED);
return 0;
}
/* otherwise, rec->length >= bs */
}

Expand Down
17 changes: 7 additions & 10 deletions ssl/s3_pkt.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,6 @@ static int ssl3_get_record(SSL *s)
unsigned char md[EVP_MAX_MD_SIZE];
short version;
unsigned mac_size;
int clear=0;
size_t extra;

rr= &(s->s3->rrec);
Expand Down Expand Up @@ -408,8 +407,9 @@ fprintf(stderr, "Record type=%d, Length=%d\n", rr->type, rr->length);
* -1: if the padding is invalid */
if (enc_err == 0)
{
/* SSLerr() and ssl3_send_alert() have been called */
goto err;
al=SSL_AD_DECRYPTION_FAILED;
SSLerr(SSL_F_TLS1_ENC,SSL_R_BLOCK_CIPHER_PAD_IS_WRONG);
goto f_err;
}

#ifdef TLS_DEBUG
Expand All @@ -419,14 +419,11 @@ printf("\n");
#endif

/* r->length is now the compressed data plus mac */
if ( (sess == NULL) ||
(s->enc_read_ctx == NULL) ||
(EVP_MD_CTX_md(s->read_hash) == NULL))
clear=1;

if (!clear)
if ((sess != NULL) &&
(s->enc_read_ctx != NULL) &&
(EVP_MD_CTX_md(s->read_hash) != NULL))
{
/* !clear => s->read_hash != NULL => mac_size != -1 */
/* s->read_hash != NULL => mac_size != -1 */
unsigned char *mac = NULL;
unsigned char mac_tmp[EVP_MAX_MD_SIZE];
mac_size=EVP_MD_CTX_size(s->read_hash);
Expand Down
4 changes: 0 additions & 4 deletions ssl/t1_enc.c
Original file line number Diff line number Diff line change
Expand Up @@ -825,11 +825,7 @@ int tls1_enc(SSL *s, int send)
if (!send)
{
if (l == 0 || l%bs != 0)
{
SSLerr(SSL_F_TLS1_ENC,SSL_R_BLOCK_CIPHER_PAD_IS_WRONG);
ssl3_send_alert(s,SSL3_AL_FATAL,SSL_AD_DECRYPTION_FAILED);
return 0;
}
}

i = EVP_Cipher(ds,rec->data,rec->input,l);
Expand Down

0 comments on commit 9f27de1

Please sign in to comment.