Commit e130841b authored by Ben Laurie's avatar Ben Laurie
Browse files

Make CBC decoding constant time.

This patch makes the decoding of SSLv3 and TLS CBC records constant
time. Without this, a timing side-channel can be used to build a padding
oracle and mount Vaudenay's attack.

This patch also disables the stitched AESNI+SHA mode pending a similar
fix to that code.

In order to be easy to backport, this change is implemented in ssl/,
rather than as a generic AEAD mode. In the future this should be changed
around so that HMAC isn't in ssl/, but crypto/ as FIPS expects.
parent 2ee79888
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -195,11 +195,13 @@ void OpenSSL_add_all_ciphers(void)
	EVP_add_cipher(EVP_aes_256_xts());
	EVP_add_cipher_alias(SN_aes_256_cbc,"AES256");
	EVP_add_cipher_alias(SN_aes_256_cbc,"aes256");
#if 0  /* Disabled because of timing side-channel leaks. */
#if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_SHA1)
	EVP_add_cipher(EVP_aes_128_cbc_hmac_sha1());
	EVP_add_cipher(EVP_aes_256_cbc_hmac_sha1());
#endif
#endif
#endif

#ifndef OPENSSL_NO_CAMELLIA
	EVP_add_cipher(EVP_camellia_128_ecb());
+2 −2
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@ LIB=$(TOP)/libssl.a
SHARED_LIB= libssl$(SHLIB_EXT)
LIBSRC=	\
	s2_meth.c   s2_srvr.c s2_clnt.c  s2_lib.c  s2_enc.c s2_pkt.c \
	s3_meth.c   s3_srvr.c s3_clnt.c  s3_lib.c  s3_enc.c s3_pkt.c s3_both.c \
	s3_meth.c   s3_srvr.c s3_clnt.c  s3_lib.c  s3_enc.c s3_pkt.c s3_both.c s3_cbc.c \
	s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c          s23_pkt.c \
	t1_meth.c   t1_srvr.c t1_clnt.c  t1_lib.c  t1_enc.c \
	d1_meth.c   d1_srvr.c d1_clnt.c  d1_lib.c  d1_pkt.c \
@@ -33,7 +33,7 @@ LIBSRC= \
	bio_ssl.c ssl_err.c kssl.c tls_srp.c t1_reneg.c
LIBOBJ= \
	s2_meth.o  s2_srvr.o  s2_clnt.o  s2_lib.o  s2_enc.o s2_pkt.o \
	s3_meth.o  s3_srvr.o  s3_clnt.o  s3_lib.o  s3_enc.o s3_pkt.o s3_both.o \
	s3_meth.o  s3_srvr.o  s3_clnt.o  s3_lib.o  s3_enc.o s3_pkt.o s3_both.o s3_cbc.o \
	s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o          s23_pkt.o \
	t1_meth.o   t1_srvr.o t1_clnt.o  t1_lib.o  t1_enc.o \
	d1_meth.o   d1_srvr.o d1_clnt.o  d1_lib.o  d1_pkt.o \
+7 −42
Original line number Diff line number Diff line
@@ -131,15 +131,15 @@ int dtls1_enc(SSL *s, int send)
	SSL3_RECORD *rec;
	EVP_CIPHER_CTX *ds;
	unsigned long l;
	int bs,i,ii,j,k,n=0;
	int bs,i,j,k,mac_size=0;
	const EVP_CIPHER *enc;

	if (send)
		{
		if (EVP_MD_CTX_md(s->write_hash))
			{
			n=EVP_MD_CTX_size(s->write_hash);
			if (n < 0)
			mac_size=EVP_MD_CTX_size(s->write_hash);
			if (mac_size < 0)
				return -1;
			}
		ds=s->enc_write_ctx;
@@ -164,8 +164,8 @@ int dtls1_enc(SSL *s, int send)
		{
		if (EVP_MD_CTX_md(s->read_hash))
			{
			n=EVP_MD_CTX_size(s->read_hash);
			if (n < 0)
			mac_size=EVP_MD_CTX_size(s->read_hash);
			if (mac_size < 0)
				return -1;
			}
		ds=s->enc_read_ctx;
@@ -245,44 +245,9 @@ int dtls1_enc(SSL *s, int send)
                }
#endif	/* KSSL_DEBUG */

		rec->orig_len = rec->length;
		if ((bs != 1) && !send)
			{
			ii=i=rec->data[l-1]; /* padding_length */
			i++;
			if (s->options&SSL_OP_TLS_BLOCK_PADDING_BUG)
				{
				/* First packet is even in size, so check */
				if ((memcmp(s->s3->read_sequence,
					"\0\0\0\0\0\0\0\0",8) == 0) && !(ii & 1))
					s->s3->flags|=TLS1_FLAGS_TLS_PADDING_BUG;
				if (s->s3->flags & TLS1_FLAGS_TLS_PADDING_BUG)
					i--;
				}
			/* TLS 1.0 does not bound the number of padding bytes by the block size.
			 * All of them must have value 'padding_length'. */
			if (i + bs > (int)rec->length)
				{
				/* Incorrect padding. SSLerr() and ssl3_alert are done
				 * by caller: we don't want to reveal whether this is
				 * a decryption error or a MAC verification failure
				 * (see http://www.openssl.org/~bodo/tls-cbc.txt) 
				 */
				return -1;
				}
			for (j=(int)(l-i); j<(int)l; j++)
				{
				if (rec->data[j] != ii)
					{
					/* Incorrect padding */
					return -1;
					}
				}
			rec->length-=i;

			rec->data += bs;    /* skip the implicit IV */
			rec->input += bs;
			rec->length -= bs;
			}
			return tls1_cbc_remove_padding(s, rec, bs, mac_size);
		}
	return(1);
	}
+69 −39
Original line number Diff line number Diff line
@@ -471,7 +471,7 @@ int ssl3_enc(SSL *s, int send)
	SSL3_RECORD *rec;
	EVP_CIPHER_CTX *ds;
	unsigned long l;
	int bs,i;
	int bs,i,mac_size=0;
	const EVP_CIPHER *enc;

	if (send)
@@ -532,22 +532,12 @@ int ssl3_enc(SSL *s, int send)
		
		EVP_Cipher(ds,rec->data,rec->input,l);

		rec->orig_len = rec->length;

		if (EVP_MD_CTX_md(s->read_hash) != NULL)
			mac_size = EVP_MD_CTX_size(s->read_hash);
		if ((bs != 1) && !send)
			{
			i=rec->data[l-1]+1;
			/* SSL 3.0 bounds the number of padding bytes by the block size;
			 * padding bytes (except the last one) are arbitrary */
			if (i > bs)
				{
				/* Incorrect padding. SSLerr() and ssl3_alert are done
				 * by caller: we don't want to reveal whether this is
				 * a decryption error or a MAC verification failure
				 * (see http://www.openssl.org/~bodo/tls-cbc.txt) */
				return -1;
				}
			/* now i <= bs <= rec->length */
			rec->length-=i;
			}
			return ssl3_cbc_remove_padding(s, rec, bs, mac_size);
		}
	return(1);
	}
@@ -716,7 +706,7 @@ int n_ssl3_mac(SSL *ssl, unsigned char *md, int send)
	EVP_MD_CTX md_ctx;
	const EVP_MD_CTX *hash;
	unsigned char *p,rec_char;
	unsigned int md_size;
	size_t md_size;
	int npad;
	int t;

@@ -741,6 +731,44 @@ int n_ssl3_mac(SSL *ssl, unsigned char *md, int send)
	md_size=t;
	npad=(48/md_size)*md_size;

	if (!send &&
	    EVP_CIPHER_CTX_mode(ssl->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
	    ssl3_cbc_record_digest_supported(hash))
		{
		/* This is a CBC-encrypted record. We must avoid leaking any
		 * timing-side channel information about how many blocks of
		 * data we are hashing because that gives an attacker a
		 * timing-oracle. */

		/* npad is, at most, 48 bytes and that's with MD5:
		 *   16 + 48 + 8 (sequence bytes) + 1 + 2 = 75.
		 *
		 * With SHA-1 (the largest hash speced for SSLv3) the hash size
		 * goes up 4, but npad goes down by 8, resulting in a smaller
		 * total size. */
		unsigned char header[75];
		unsigned j = 0;
		memcpy(header+j, mac_sec, md_size);
		j += md_size;
		memcpy(header+j, ssl3_pad_1, npad);
		j += npad;
		memcpy(header+j, seq, 8);
		j += 8;
		header[j++] = rec->type;
		header[j++] = rec->length >> 8;
		header[j++] = rec->length & 0xff;

		ssl3_cbc_digest_record(
			hash,
			md, &md_size,
			header, rec->input,
			rec->length + md_size, rec->orig_len,
			mac_sec, md_size,
			1 /* is SSLv3 */);
		}
	else
		{
		unsigned int md_size_u;
		/* Chop the digest off the end :-) */
		EVP_MD_CTX_init(&md_ctx);

@@ -760,9 +788,11 @@ int n_ssl3_mac(SSL *ssl, unsigned char *md, int send)
		EVP_DigestUpdate(&md_ctx,mac_sec,md_size);
		EVP_DigestUpdate(&md_ctx,ssl3_pad_2,npad);
		EVP_DigestUpdate(&md_ctx,md,md_size);
	EVP_DigestFinal_ex( &md_ctx,md,&md_size);
		EVP_DigestFinal_ex( &md_ctx,md,&md_size_u);
		md_size = md_size_u;

		EVP_MD_CTX_cleanup(&md_ctx);
	}

	ssl3_record_sequence_update(seq);
	return(md_size);
+38 −38
Original line number Diff line number Diff line
@@ -290,11 +290,9 @@ static int ssl3_get_record(SSL *s)
	unsigned char *p;
	unsigned char md[EVP_MAX_MD_SIZE];
	short version;
	int mac_size;
	unsigned mac_size;
	int clear=0;
	size_t extra;
	int decryption_failed_or_bad_record_mac = 0;
	unsigned char *mac = NULL;

	rr= &(s->s3->rrec);
	sess=s->session;
@@ -403,17 +401,10 @@ fprintf(stderr, "Record type=%d, Length=%d\n", rr->type, rr->length);
	rr->data=rr->input;

	enc_err = s->method->ssl3_enc->enc(s,0);
	if (enc_err <= 0)
		{
	if (enc_err == 0)
		{
		/* SSLerr() and ssl3_send_alert() have been called */
		goto err;

		/* Otherwise enc_err == -1, which indicates bad padding
		 * (rec->length has not been changed in this case).
		 * To minimize information leaked via timing, we will perform
		 * the MAC computation anyway. */
		decryption_failed_or_bad_record_mac = 1;
		}

#ifdef TLS_DEBUG
@@ -431,45 +422,54 @@ printf("\n");
	if (!clear)
		{
		/* !clear => 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 >= 0);
		OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);

		if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra+mac_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_SSL3_GET_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 >= (unsigned int)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
			{
			/* record (minus padding) is too short to contain a MAC */
#if 0 /* OK only for stream ciphers */
			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;
			rr->length = 0;
#endif
			/* 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);

		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)
			{
			decryption_failed_or_bad_record_mac = 1;
			}
			enc_err = -1;
		if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra+mac_size)
			enc_err = -1;
		}

	if (decryption_failed_or_bad_record_mac)
	if (enc_err < 0)
		{
		/* A separate 'decryption_failed' alert was introduced with TLS 1.0,
		 * SSL 3.0 only has 'bad_record_mac'.  But unless a decryption
Loading