diff options
-rw-r--r-- | lib/libcrypto/asn1/a_verify.c | 6 | ||||
-rw-r--r-- | lib/libcrypto/bn/bn_word.c | 25 | ||||
-rw-r--r-- | lib/libcrypto/evp/e_aes_cbc_hmac_sha1.c | 216 | ||||
-rw-r--r-- | lib/libcrypto/ocsp/ocsp_vfy.c | 9 | ||||
-rw-r--r-- | lib/libcrypto/rsa/rsa_oaep.c | 2 | ||||
-rw-r--r-- | lib/libssl/d1_enc.c | 75 | ||||
-rw-r--r-- | lib/libssl/d1_pkt.c | 91 | ||||
-rw-r--r-- | lib/libssl/s3_both.c | 2 | ||||
-rw-r--r-- | lib/libssl/s3_pkt.c | 98 | ||||
-rw-r--r-- | lib/libssl/ssl_locl.h | 38 | ||||
-rw-r--r-- | lib/libssl/t1_enc.c | 157 | ||||
-rw-r--r-- | lib/libssl/t1_lib.c | 2 |
12 files changed, 462 insertions, 259 deletions
diff --git a/lib/libcrypto/asn1/a_verify.c b/lib/libcrypto/asn1/a_verify.c index 432722e4099..fc84cd3d191 100644 --- a/lib/libcrypto/asn1/a_verify.c +++ b/lib/libcrypto/asn1/a_verify.c @@ -140,6 +140,12 @@ int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, int mdnid, pknid; + if (!pkey) + { + ASN1err(ASN1_F_ASN1_ITEM_VERIFY, ERR_R_PASSED_NULL_PARAMETER); + return -1; + } + EVP_MD_CTX_init(&ctx); /* Convert signature OID into digest and public key OIDs */ diff --git a/lib/libcrypto/bn/bn_word.c b/lib/libcrypto/bn/bn_word.c index ee7b87c45cc..de83a15b99c 100644 --- a/lib/libcrypto/bn/bn_word.c +++ b/lib/libcrypto/bn/bn_word.c @@ -144,26 +144,17 @@ int BN_add_word(BIGNUM *a, BN_ULONG w) a->neg=!(a->neg); return(i); } - /* Only expand (and risk failing) if it's possibly necessary */ - if (((BN_ULONG)(a->d[a->top - 1] + 1) == 0) && - (bn_wexpand(a,a->top+1) == NULL)) - return(0); - i=0; - for (;;) + for (i=0;w!=0 && i<a->top;i++) { - if (i >= a->top) - l=w; - else - l=(a->d[i]+w)&BN_MASK2; - a->d[i]=l; - if (w > l) - w=1; - else - break; - i++; + a->d[i] = l = (a->d[i]+w)&BN_MASK2; + w = (w>l)?1:0; } - if (i >= a->top) + if (w && i==a->top) + { + if (bn_wexpand(a,a->top+1) == NULL) return 0; a->top++; + a->d[i]=w; + } bn_check_top(a); return(1); } diff --git a/lib/libcrypto/evp/e_aes_cbc_hmac_sha1.c b/lib/libcrypto/evp/e_aes_cbc_hmac_sha1.c index 710fb79baf4..483e04b605b 100644 --- a/lib/libcrypto/evp/e_aes_cbc_hmac_sha1.c +++ b/lib/libcrypto/evp/e_aes_cbc_hmac_sha1.c @@ -1,5 +1,5 @@ /* ==================================================================== - * Copyright (c) 2011 The OpenSSL Project. All rights reserved. + * Copyright (c) 2011-2013 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -90,6 +90,10 @@ typedef struct defined(_M_AMD64) || defined(_M_X64) || \ defined(__INTEL__) ) +#if defined(__GNUC__) && __GNUC__>=2 && !defined(PEDANTIC) +# define BSWAP(x) ({ unsigned int r=(x); asm ("bswapl %0":"=r"(r):"0"(r)); r; }) +#endif + extern unsigned int OPENSSL_ia32cap_P[2]; #define AESNI_CAPABLE (1<<(57-32)) @@ -167,6 +171,9 @@ static void sha1_update(SHA_CTX *c,const void *data,size_t len) SHA1_Update(c,ptr,res); } +#ifdef SHA1_Update +#undef SHA1_Update +#endif #define SHA1_Update sha1_update static int aesni_cbc_hmac_sha1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, @@ -184,6 +191,8 @@ static int aesni_cbc_hmac_sha1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, sha_off = SHA_CBLOCK-key->md.num; #endif + key->payload_length = NO_PAYLOAD_LENGTH; + if (len%AES_BLOCK_SIZE) return 0; if (ctx->encrypt) { @@ -234,47 +243,210 @@ static int aesni_cbc_hmac_sha1_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, &key->ks,ctx->iv,1); } } else { - unsigned char mac[SHA_DIGEST_LENGTH]; + union { unsigned int u[SHA_DIGEST_LENGTH/sizeof(unsigned int)]; + unsigned char c[32+SHA_DIGEST_LENGTH]; } mac, *pmac; + + /* arrange cache line alignment */ + pmac = (void *)(((size_t)mac.c+31)&((size_t)0-32)); /* decrypt HMAC|padding at once */ aesni_cbc_encrypt(in,out,len, &key->ks,ctx->iv,0); if (plen) { /* "TLS" mode of operation */ - /* figure out payload length */ - if (len<(size_t)(out[len-1]+1+SHA_DIGEST_LENGTH)) - return 0; - - len -= (out[len-1]+1+SHA_DIGEST_LENGTH); + size_t inp_len, mask, j, i; + unsigned int res, maxpad, pad, bitlen; + int ret = 1; + union { unsigned int u[SHA_LBLOCK]; + unsigned char c[SHA_CBLOCK]; } + *data = (void *)key->md.data; if ((key->aux.tls_aad[plen-4]<<8|key->aux.tls_aad[plen-3]) - >= TLS1_1_VERSION) { - len -= AES_BLOCK_SIZE; + >= TLS1_1_VERSION) iv = AES_BLOCK_SIZE; - } - key->aux.tls_aad[plen-2] = len>>8; - key->aux.tls_aad[plen-1] = len; + if (len<(iv+SHA_DIGEST_LENGTH+1)) + return 0; + + /* omit explicit iv */ + out += iv; + len -= iv; + + /* figure out payload length */ + pad = out[len-1]; + maxpad = len-(SHA_DIGEST_LENGTH+1); + maxpad |= (255-maxpad)>>(sizeof(maxpad)*8-8); + maxpad &= 255; + + inp_len = len - (SHA_DIGEST_LENGTH+pad+1); + mask = (0-((inp_len-len)>>(sizeof(inp_len)*8-1))); + inp_len &= mask; + ret &= (int)mask; + + key->aux.tls_aad[plen-2] = inp_len>>8; + key->aux.tls_aad[plen-1] = inp_len; - /* calculate HMAC and verify it */ + /* calculate HMAC */ key->md = key->head; SHA1_Update(&key->md,key->aux.tls_aad,plen); - SHA1_Update(&key->md,out+iv,len); - SHA1_Final(mac,&key->md); +#if 1 + len -= SHA_DIGEST_LENGTH; /* amend mac */ + if (len>=(256+SHA_CBLOCK)) { + j = (len-(256+SHA_CBLOCK))&(0-SHA_CBLOCK); + j += SHA_CBLOCK-key->md.num; + SHA1_Update(&key->md,out,j); + out += j; + len -= j; + inp_len -= j; + } + + /* but pretend as if we hashed padded payload */ + bitlen = key->md.Nl+(inp_len<<3); /* at most 18 bits */ +#ifdef BSWAP + bitlen = BSWAP(bitlen); +#else + mac.c[0] = 0; + mac.c[1] = (unsigned char)(bitlen>>16); + mac.c[2] = (unsigned char)(bitlen>>8); + mac.c[3] = (unsigned char)bitlen; + bitlen = mac.u[0]; +#endif + + pmac->u[0]=0; + pmac->u[1]=0; + pmac->u[2]=0; + pmac->u[3]=0; + pmac->u[4]=0; + + for (res=key->md.num, j=0;j<len;j++) { + size_t c = out[j]; + mask = (j-inp_len)>>(sizeof(j)*8-8); + c &= mask; + c |= 0x80&~mask&~((inp_len-j)>>(sizeof(j)*8-8)); + data->c[res++]=(unsigned char)c; + + if (res!=SHA_CBLOCK) continue; + + mask = 0-((inp_len+8-j)>>(sizeof(j)*8-1)); + data->u[SHA_LBLOCK-1] |= bitlen&mask; + sha1_block_data_order(&key->md,data,1); + mask &= 0-((j-inp_len-73)>>(sizeof(j)*8-1)); + pmac->u[0] |= key->md.h0 & mask; + pmac->u[1] |= key->md.h1 & mask; + pmac->u[2] |= key->md.h2 & mask; + pmac->u[3] |= key->md.h3 & mask; + pmac->u[4] |= key->md.h4 & mask; + res=0; + } + + for(i=res;i<SHA_CBLOCK;i++,j++) data->c[i]=0; + + if (res>SHA_CBLOCK-8) { + mask = 0-((inp_len+8-j)>>(sizeof(j)*8-1)); + data->u[SHA_LBLOCK-1] |= bitlen&mask; + sha1_block_data_order(&key->md,data,1); + mask &= 0-((j-inp_len-73)>>(sizeof(j)*8-1)); + pmac->u[0] |= key->md.h0 & mask; + pmac->u[1] |= key->md.h1 & mask; + pmac->u[2] |= key->md.h2 & mask; + pmac->u[3] |= key->md.h3 & mask; + pmac->u[4] |= key->md.h4 & mask; + + memset(data,0,SHA_CBLOCK); + j+=64; + } + data->u[SHA_LBLOCK-1] = bitlen; + sha1_block_data_order(&key->md,data,1); + mask = 0-((j-inp_len-73)>>(sizeof(j)*8-1)); + pmac->u[0] |= key->md.h0 & mask; + pmac->u[1] |= key->md.h1 & mask; + pmac->u[2] |= key->md.h2 & mask; + pmac->u[3] |= key->md.h3 & mask; + pmac->u[4] |= key->md.h4 & mask; + +#ifdef BSWAP + pmac->u[0] = BSWAP(pmac->u[0]); + pmac->u[1] = BSWAP(pmac->u[1]); + pmac->u[2] = BSWAP(pmac->u[2]); + pmac->u[3] = BSWAP(pmac->u[3]); + pmac->u[4] = BSWAP(pmac->u[4]); +#else + for (i=0;i<5;i++) { + res = pmac->u[i]; + pmac->c[4*i+0]=(unsigned char)(res>>24); + pmac->c[4*i+1]=(unsigned char)(res>>16); + pmac->c[4*i+2]=(unsigned char)(res>>8); + pmac->c[4*i+3]=(unsigned char)res; + } +#endif + len += SHA_DIGEST_LENGTH; +#else + SHA1_Update(&key->md,out,inp_len); + res = key->md.num; + SHA1_Final(pmac->c,&key->md); + + { + unsigned int inp_blocks, pad_blocks; + + /* but pretend as if we hashed padded payload */ + inp_blocks = 1+((SHA_CBLOCK-9-res)>>(sizeof(res)*8-1)); + res += (unsigned int)(len-inp_len); + pad_blocks = res / SHA_CBLOCK; + res %= SHA_CBLOCK; + pad_blocks += 1+((SHA_CBLOCK-9-res)>>(sizeof(res)*8-1)); + for (;inp_blocks<pad_blocks;inp_blocks++) + sha1_block_data_order(&key->md,data,1); + } +#endif key->md = key->tail; - SHA1_Update(&key->md,mac,SHA_DIGEST_LENGTH); - SHA1_Final(mac,&key->md); + SHA1_Update(&key->md,pmac->c,SHA_DIGEST_LENGTH); + SHA1_Final(pmac->c,&key->md); - if (memcmp(out+iv+len,mac,SHA_DIGEST_LENGTH)) - return 0; + /* verify HMAC */ + out += inp_len; + len -= inp_len; +#if 1 + { + unsigned char *p = out+len-1-maxpad-SHA_DIGEST_LENGTH; + size_t off = out-p; + unsigned int c, cmask; + + maxpad += SHA_DIGEST_LENGTH; + for (res=0,i=0,j=0;j<maxpad;j++) { + c = p[j]; + cmask = ((int)(j-off-SHA_DIGEST_LENGTH))>>(sizeof(int)*8-1); + res |= (c^pad)&~cmask; /* ... and padding */ + cmask &= ((int)(off-1-j))>>(sizeof(int)*8-1); + res |= (c^pmac->c[i])&cmask; + i += 1&cmask; + } + maxpad -= SHA_DIGEST_LENGTH; + + res = 0-((0-res)>>(sizeof(res)*8-1)); + ret &= (int)~res; + } +#else + for (res=0,i=0;i<SHA_DIGEST_LENGTH;i++) + res |= out[i]^pmac->c[i]; + res = 0-((0-res)>>(sizeof(res)*8-1)); + ret &= (int)~res; + + /* verify padding */ + pad = (pad&~res) | (maxpad&res); + out = out+len-1-pad; + for (res=0,i=0;i<pad;i++) + res |= out[i]^pad; + + res = (0-res)>>(sizeof(res)*8-1); + ret &= (int)~res; +#endif + return ret; } else { SHA1_Update(&key->md,out,len); } } - key->payload_length = NO_PAYLOAD_LENGTH; - return 1; } @@ -309,6 +481,8 @@ static int aesni_cbc_hmac_sha1_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void SHA1_Init(&key->tail); SHA1_Update(&key->tail,hmac_key,sizeof(hmac_key)); + OPENSSL_cleanse(hmac_key,sizeof(hmac_key)); + return 1; } case EVP_CTRL_AEAD_TLS1_AAD: diff --git a/lib/libcrypto/ocsp/ocsp_vfy.c b/lib/libcrypto/ocsp/ocsp_vfy.c index 415d67e61cf..91a45c91330 100644 --- a/lib/libcrypto/ocsp/ocsp_vfy.c +++ b/lib/libcrypto/ocsp/ocsp_vfy.c @@ -91,9 +91,12 @@ int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs, { EVP_PKEY *skey; skey = X509_get_pubkey(signer); - ret = OCSP_BASICRESP_verify(bs, skey, 0); - EVP_PKEY_free(skey); - if(ret <= 0) + if (skey) + { + ret = OCSP_BASICRESP_verify(bs, skey, 0); + EVP_PKEY_free(skey); + } + if(!skey || ret <= 0) { OCSPerr(OCSP_F_OCSP_BASIC_VERIFY, OCSP_R_SIGNATURE_FAILURE); goto end; diff --git a/lib/libcrypto/rsa/rsa_oaep.c b/lib/libcrypto/rsa/rsa_oaep.c index 553d212ebe9..e08ac151ffe 100644 --- a/lib/libcrypto/rsa/rsa_oaep.c +++ b/lib/libcrypto/rsa/rsa_oaep.c @@ -149,7 +149,7 @@ int RSA_padding_check_PKCS1_OAEP(unsigned char *to, int tlen, if (!EVP_Digest((void *)param, plen, phash, NULL, EVP_sha1(), NULL)) return -1; - if (memcmp(db, phash, SHA_DIGEST_LENGTH) != 0 || bad) + if (timingsafe_bcmp(db, phash, SHA_DIGEST_LENGTH) != 0 || bad) goto decoding_err; else { diff --git a/lib/libssl/d1_enc.c b/lib/libssl/d1_enc.c index cbff7495c50..712c4647f24 100644 --- a/lib/libssl/d1_enc.c +++ b/lib/libssl/d1_enc.c @@ -115,25 +115,41 @@ #include <stdio.h> #include "ssl_locl.h" +#ifndef OPENSSL_NO_COMP #include <openssl/comp.h> +#endif #include <openssl/evp.h> #include <openssl/hmac.h> #include <openssl/md5.h> #include <openssl/rand.h> +#ifdef KSSL_DEBUG +#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; 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 (s->write_hash != NULL) - n=EVP_MD_size(s->write_hash); + if (EVP_MD_CTX_md(s->write_hash)) + { + mac_size=EVP_MD_CTX_size(s->write_hash); + if (mac_size < 0) + return -1; + } ds=s->enc_write_ctx; rec= &(s->s3->wrec); if (s->enc_write_ctx == NULL) @@ -147,15 +163,18 @@ int dtls1_enc(SSL *s, int send) __FILE__, __LINE__); else if ( EVP_CIPHER_block_size(ds->cipher) > 1) { - if (!RAND_bytes(rec->input, EVP_CIPHER_block_size(ds->cipher))) + if (RAND_bytes(rec->input, EVP_CIPHER_block_size(ds->cipher)) <= 0) return -1; } } } else { - if (s->read_hash != NULL) - n=EVP_MD_size(s->read_hash); + if (EVP_MD_CTX_md(s->read_hash)) + { + mac_size=EVP_MD_CTX_size(s->read_hash); + OPENSSL_assert(mac_size >= 0); + } ds=s->enc_read_ctx; rec= &(s->s3->rrec); if (s->enc_read_ctx == NULL) @@ -219,11 +238,7 @@ int dtls1_enc(SSL *s, int send) if (!send) { if (l == 0 || l%bs != 0) - { - SSLerr(SSL_F_DTLS1_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); @@ -238,43 +253,7 @@ int dtls1_enc(SSL *s, int send) #endif /* KSSL_DEBUG */ 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 > (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); } diff --git a/lib/libssl/d1_pkt.c b/lib/libssl/d1_pkt.c index 987af608358..cfe45245534 100644 --- a/lib/libssl/d1_pkt.c +++ b/lib/libssl/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 int mac_size, orig_len; 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; @@ -416,12 +412,16 @@ dtls1_process_record(SSL *s) rr->data=rr->input; 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 @@ -431,45 +431,62 @@ 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); + + /* kludge: *_cbc_remove_padding passes padding length in rr->type */ + orig_len = rr->length+((unsigned int)rr->type>>8); + + /* 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 (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 && + 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, orig_len); 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 || memcmp(md, mac, mac_size) != 0) { - decryption_failed_or_bad_record_mac = 1; + /* In this case there's no padding, so |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 || timingsafe_bcmp(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/lib/libssl/s3_both.c b/lib/libssl/s3_both.c index b63460a56dd..6981852b5b1 100644 --- a/lib/libssl/s3_both.c +++ b/lib/libssl/s3_both.c @@ -263,7 +263,7 @@ int ssl3_get_finished(SSL *s, int a, int b) goto f_err; } - if (memcmp(p, s->s3->tmp.peer_finish_md, i) != 0) + if (timingsafe_bcmp(p, s->s3->tmp.peer_finish_md, i) != 0) { al=SSL_AD_DECRYPT_ERROR; SSLerr(SSL_F_SSL3_GET_FINISHED,SSL_R_DIGEST_CHECK_FAILED); diff --git a/lib/libssl/s3_pkt.c b/lib/libssl/s3_pkt.c index adf8c387cc0..a7d2defbea5 100644 --- a/lib/libssl/s3_pkt.c +++ b/lib/libssl/s3_pkt.c @@ -290,11 +290,8 @@ static int ssl3_get_record(SSL *s) unsigned char *p; unsigned char md[EVP_MAX_MD_SIZE]; short version; - int mac_size; - int clear=0; + unsigned mac_size, orig_len; size_t extra; - int decryption_failed_or_bad_record_mac = 0; - unsigned char *mac = NULL; rr= &(s->s3->rrec); sess=s->session; @@ -403,17 +400,15 @@ 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) + /* 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) { - 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; + al=SSL_AD_DECRYPTION_FAILED; + SSLerr(SSL_F_TLS1_ENC,SSL_R_BLOCK_CIPHER_PAD_IS_WRONG); + goto f_err; } #ifdef TLS_DEBUG @@ -423,53 +418,62 @@ 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); - OPENSSL_assert(mac_size >= 0); + OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE); - if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra+mac_size) + /* kludge: *_cbc_remove_padding passes padding length in rr->type */ + orig_len = rr->length+((unsigned int)rr->type>>8); + + /* 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 (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 && + 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, orig_len); 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 - } - i=s->method->ssl3_enc->mac(s,md,0); - if (i < 0 || mac == NULL || memcmp(md, mac, (size_t)mac_size) != 0) - { - decryption_failed_or_bad_record_mac = 1; + /* In this case there's no padding, so |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 || timingsafe_bcmp(md, mac, (size_t)mac_size) != 0) + 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 diff --git a/lib/libssl/ssl_locl.h b/lib/libssl/ssl_locl.h index d87fd51cfa8..7fc110df648 100644 --- a/lib/libssl/ssl_locl.h +++ b/lib/libssl/ssl_locl.h @@ -215,6 +215,15 @@ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ *((c)++)=(unsigned char)(((l) )&0xff)) +#define l2n8(l,c) (*((c)++)=(unsigned char)(((l)>>56)&0xff), \ + *((c)++)=(unsigned char)(((l)>>48)&0xff), \ + *((c)++)=(unsigned char)(((l)>>40)&0xff), \ + *((c)++)=(unsigned char)(((l)>>32)&0xff), \ + *((c)++)=(unsigned char)(((l)>>24)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16)&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ + *((c)++)=(unsigned char)(((l) )&0xff)) + #define n2l6(c,l) (l =((BN_ULLONG)(*((c)++)))<<40, \ l|=((BN_ULLONG)(*((c)++)))<<32, \ l|=((BN_ULLONG)(*((c)++)))<<24, \ @@ -1131,4 +1140,33 @@ int ssl_parse_clienthello_use_srtp_ext(SSL *s, unsigned char *d, int len,int *al int ssl_add_serverhello_use_srtp_ext(SSL *s, unsigned char *p, int *len, int maxlen); int ssl_parse_serverhello_use_srtp_ext(SSL *s, unsigned char *d, int len,int *al); +/* s3_cbc.c */ +void ssl3_cbc_copy_mac(unsigned char* out, + const SSL3_RECORD *rec, + unsigned md_size,unsigned orig_len); +int ssl3_cbc_remove_padding(const SSL* s, + SSL3_RECORD *rec, + unsigned block_size, + unsigned mac_size); +int tls1_cbc_remove_padding(const SSL* s, + SSL3_RECORD *rec, + unsigned block_size, + unsigned mac_size); +char ssl3_cbc_record_digest_supported(const EVP_MD_CTX *ctx); +void ssl3_cbc_digest_record( + const EVP_MD_CTX *ctx, + unsigned char* md_out, + size_t* md_out_size, + const unsigned char header[13], + const unsigned char *data, + size_t data_plus_mac_size, + size_t data_plus_mac_plus_padding_size, + const unsigned char *mac_secret, + unsigned mac_secret_length, + char is_sslv3); + +void tls_fips_digest_extra( + const EVP_CIPHER_CTX *cipher_ctx, EVP_MD_CTX *mac_ctx, + const unsigned char *data, size_t data_len, size_t orig_len); + #endif diff --git a/lib/libssl/t1_enc.c b/lib/libssl/t1_enc.c index f7bdeb3b9db..448eef274fa 100644 --- a/lib/libssl/t1_enc.c +++ b/lib/libssl/t1_enc.c @@ -667,12 +667,21 @@ err: return(ret); } +/* tls1_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 tls1_enc(SSL *s, int send) { SSL3_RECORD *rec; EVP_CIPHER_CTX *ds; unsigned long l; - int bs,i,ii,j,k,pad=0; + int bs,i,j,k,pad=0,ret,mac_size=0; const EVP_CIPHER *enc; if (send) @@ -729,11 +738,11 @@ int tls1_enc(SSL *s, int send) printf("tls1_enc(%d)\n", send); #endif /* KSSL_DEBUG */ - if ((s->session == NULL) || (ds == NULL) || - (enc == NULL)) + if ((s->session == NULL) || (ds == NULL) || (enc == NULL)) { memmove(rec->data,rec->input,rec->length); rec->input=rec->data; + ret = 1; } else { @@ -797,13 +806,13 @@ int tls1_enc(SSL *s, int send) #ifdef KSSL_DEBUG { - unsigned long ui; + unsigned long ui; printf("EVP_Cipher(ds=%p,rec->data=%p,rec->input=%p,l=%ld) ==>\n", - ds,rec->data,rec->input,l); + ds,rec->data,rec->input,l); printf("\tEVP_CIPHER_CTX: %d buf_len, %d key_len [%d %d], %d iv_len\n", - ds->buf_len, ds->cipher->key_len, - DES_KEY_SZ, DES_SCHEDULE_SZ, - ds->cipher->iv_len); + ds->buf_len, ds->cipher->key_len, + DES_KEY_SZ, DES_SCHEDULE_SZ, + ds->cipher->iv_len); printf("\t\tIV: "); for (i=0; i<ds->cipher->iv_len; i++) printf("%02X", ds->iv[i]); printf("\n"); @@ -816,13 +825,7 @@ int tls1_enc(SSL *s, int send) if (!send) { if (l == 0 || l%bs != 0) - { - if (s->version >= TLS1_1_VERSION) - return -1; - 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); @@ -839,68 +842,24 @@ int tls1_enc(SSL *s, int send) #ifdef KSSL_DEBUG { - unsigned long i; - printf("\trec->data="); + unsigned long i; + printf("\trec->data="); for (i=0; i<l; i++) - printf(" %02x", rec->data[i]); printf("\n"); - } + printf(" %02x", rec->data[i]); printf("\n"); + } #endif /* KSSL_DEBUG */ + ret = 1; + if (EVP_MD_CTX_md(s->read_hash) != NULL) + mac_size = EVP_MD_CTX_size(s->read_hash); if ((bs != 1) && !send) - { - ii=i=rec->data[l-1]; /* padding_length */ - i++; - /* NB: if compression is in operation the first packet - * may not be of even length so the padding bug check - * cannot be performed. This bug workaround has been - * around since SSLeay so hopefully it is either fixed - * now or no buggy implementation supports compression - * [steve] - */ - if ( (s->options&SSL_OP_TLS_BLOCK_PADDING_BUG) - && !s->expand) - { - /* 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 > (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; - if (s->version >= TLS1_1_VERSION - && EVP_CIPHER_CTX_mode(ds) == EVP_CIPH_CBC_MODE) - { - if (bs > (int)rec->length) - return -1; - rec->data += bs; /* skip the explicit IV */ - rec->input += bs; - rec->length -= bs; - } - } + ret = tls1_cbc_remove_padding(s, rec, bs, mac_size); if (pad && !send) rec->length -= pad; } - return(1); + return ret; } + int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *out) { unsigned int ret; @@ -990,10 +949,10 @@ int tls1_mac(SSL *ssl, unsigned char *md, int send) SSL3_RECORD *rec; unsigned char *seq; EVP_MD_CTX *hash; - size_t md_size; + size_t md_size, orig_len; int i; EVP_MD_CTX hmac, *mac_ctx; - unsigned char buf[5]; + unsigned char header[13]; int stream_mac = (send?(ssl->mac_flags & SSL_MAC_FLAG_WRITE_MAC_STREAM):(ssl->mac_flags&SSL_MAC_FLAG_READ_MAC_STREAM)); int t; @@ -1014,12 +973,6 @@ int tls1_mac(SSL *ssl, unsigned char *md, int send) OPENSSL_assert(t >= 0); md_size=t; - buf[0]=rec->type; - buf[1]=(unsigned char)(ssl->version>>8); - buf[2]=(unsigned char)(ssl->version); - buf[3]=rec->length>>8; - buf[4]=rec->length&0xff; - /* I should fix this up TLS TLS TLS TLS TLS XXXXXXXX */ if (stream_mac) { @@ -1038,17 +991,55 @@ int tls1_mac(SSL *ssl, unsigned char *md, int send) s2n(send?ssl->d1->w_epoch:ssl->d1->r_epoch, p); memcpy (p,&seq[2],6); - EVP_DigestSignUpdate(mac_ctx,dtlsseq,8); + memcpy(header, dtlsseq, 8); } else - EVP_DigestSignUpdate(mac_ctx,seq,8); + memcpy(header, seq, 8); - EVP_DigestSignUpdate(mac_ctx,buf,5); - EVP_DigestSignUpdate(mac_ctx,rec->input,rec->length); - t=EVP_DigestSignFinal(mac_ctx,md,&md_size); - OPENSSL_assert(t > 0); + /* kludge: tls1_cbc_remove_padding passes padding length in rec->type */ + orig_len = rec->length+md_size+((unsigned int)rec->type>>8); + rec->type &= 0xff; + + header[8]=rec->type; + header[9]=(unsigned char)(ssl->version>>8); + header[10]=(unsigned char)(ssl->version); + header[11]=(rec->length)>>8; + header[12]=(rec->length)&0xff; + + if (!send && + EVP_CIPHER_CTX_mode(ssl->enc_read_ctx) == EVP_CIPH_CBC_MODE && + ssl3_cbc_record_digest_supported(mac_ctx)) + { + /* 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. */ + ssl3_cbc_digest_record( + mac_ctx, + md, &md_size, + header, rec->input, + rec->length + md_size, orig_len, + ssl->s3->read_mac_secret, + ssl->s3->read_mac_secret_size, + 0 /* not SSLv3 */); + } + else + { + EVP_DigestSignUpdate(mac_ctx,header,sizeof(header)); + EVP_DigestSignUpdate(mac_ctx,rec->input,rec->length); + t=EVP_DigestSignFinal(mac_ctx,md,&md_size); + OPENSSL_assert(t > 0); +#ifdef OPENSSL_FIPS + if (!send && FIPS_mode()) + tls_fips_digest_extra( + ssl->enc_read_ctx, + mac_ctx, rec->input, + rec->length, orig_len); +#endif + } - if (!stream_mac) EVP_MD_CTX_cleanup(&hmac); + if (!stream_mac) + EVP_MD_CTX_cleanup(&hmac); #ifdef TLS_DEBUG printf("sec="); {unsigned int z; for (z=0; z<md_size; z++) printf("%02X ",mac_sec[z]); printf("\n"); } diff --git a/lib/libssl/t1_lib.c b/lib/libssl/t1_lib.c index 27c8e3460da..bfd47313650 100644 --- a/lib/libssl/t1_lib.c +++ b/lib/libssl/t1_lib.c @@ -2189,7 +2189,7 @@ static int tls_decrypt_ticket(SSL *s, const unsigned char *etick, int eticklen, HMAC_Update(&hctx, etick, eticklen); HMAC_Final(&hctx, tick_hmac, NULL); HMAC_CTX_cleanup(&hctx); - if (memcmp(tick_hmac, etick + eticklen, mlen)) + if (timingsafe_bcmp(tick_hmac, etick + eticklen, mlen)) return 2; /* Attempt to decrypt session data */ /* Move p after IV to start of encrypted ticket, update length */ |