summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Laurie <ben@links.org>2013-01-28 17:34:33 +0000
committerBen Laurie <ben@links.org>2013-01-28 17:34:33 +0000
commit9f27de170d1b7bef3d46d41382dc4dafde8b3900 (patch)
tree1d224a7727fc7a834f632bbc790902caa32bdcd3
parent6cb19b7681f600b2f165e4adc57547b097b475fd (diff)
downloadopenssl-new-9f27de170d1b7bef3d46d41382dc4dafde8b3900.tar.gz
Update DTLS code to match CBC decoding in TLS.
This change updates the DTLS code to match the constant-time CBC behaviour in the TLS.
-rw-r--r--ssl/d1_enc.c13
-rw-r--r--ssl/d1_pkt.c86
-rw-r--r--ssl/s3_enc.c4
-rw-r--r--ssl/s3_pkt.c17
-rw-r--r--ssl/t1_enc.c4
5 files changed, 67 insertions, 57 deletions
diff --git a/ssl/d1_enc.c b/ssl/d1_enc.c
index da42348b3d..712c4647f2 100644
--- a/ssl/d1_enc.c
+++ b/ssl/d1_enc.c
@@ -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;
@@ -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);
@@ -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);
diff --git a/ssl/d1_pkt.c b/ssl/d1_pkt.c
index 4763d5cd1f..02c881ab31 100644
--- a/ssl/d1_pkt.c
+++ b/ssl/d1_pkt.c
@@ -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;
@@ -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
@@ -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;
diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c
index e963efd47f..a0eac77d7d 100644
--- a/ssl/s3_enc.c
+++ b/ssl/s3_enc.c
@@ -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 */
}
diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c
index dd98e698bf..dba6653589 100644
--- a/ssl/s3_pkt.c
+++ b/ssl/s3_pkt.c
@@ -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);
@@ -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
@@ -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);
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 67a1fea887..bb46f7f9ba 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -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);