Commit b23da291 authored by Ben Laurie's avatar Ben Laurie Committed by Dr. Stephen Henson
Browse files

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.
(cherry picked from commit 9f27de17)
parent 610dfc3e
Loading
Loading
Loading
Loading
+10 −3
Original line number Diff line number Diff line
@@ -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);
+50 −36
Original line number Diff line number Diff line
@@ -368,15 +368,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;
@@ -409,12 +405,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
@@ -424,45 +424,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;
+0 −4
Original line number Diff line number Diff line
@@ -530,11 +530,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 */
			}
		
+7 −10
Original line number Diff line number Diff line
@@ -290,7 +290,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);
@@ -407,8 +406,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
@@ -418,14 +418,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);
+0 −4
Original line number Diff line number Diff line
@@ -737,12 +737,8 @@ 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;
			}
			}
		
		EVP_Cipher(ds,rec->data,rec->input,l);