X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=ssl%2Fs3_enc.c;h=e3cd4f062c5a53cabaeac6e0d11924246b393288;hp=dc3101ff14430f3cedb00df915c6472108760be9;hb=ec07246a0835a36af9d892f1e28b594018be6da1;hpb=b81fde02aa9c09b41ca83c59f885140d85cb9002 diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c index dc3101ff14..e3cd4f062c 100644 --- a/ssl/s3_enc.c +++ b/ssl/s3_enc.c @@ -466,12 +466,21 @@ void ssl3_cleanup_key_block(SSL *s) s->s3->tmp.key_block_length=0; } +/* ssl3_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 is invalid or, if sending, an internal error + * occured. + */ 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) @@ -512,6 +521,9 @@ int ssl3_enc(SSL *s, int send) /* we need to add 'i-1' padding bytes */ l+=i; + /* the last of these zero bytes will be overwritten + * with the padding length. */ + memset(&rec->input[rec->length], 0, i); rec->length+=i; rec->input[l-1]=(i-1); } @@ -519,32 +531,16 @@ 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 */ } EVP_Cipher(ds,rec->data,rec->input,l); + 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); } @@ -614,7 +610,6 @@ int ssl3_digest_cached_records(SSL *s) if ((mask & ssl_get_algorithm2(s)) && md) { s->s3->handshake_dgst[i]=EVP_MD_CTX_create(); - EVP_DigestInit_ex(s->s3->handshake_dgst[i],md,NULL); #ifdef OPENSSL_FIPS if (EVP_MD_nid(md) == NID_md5) { @@ -622,6 +617,7 @@ int ssl3_digest_cached_records(SSL *s) EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); } #endif + EVP_DigestInit_ex(s->s3->handshake_dgst[i],md,NULL); EVP_DigestUpdate(s->s3->handshake_dgst[i],hdata,hdatalen); } else @@ -713,7 +709,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, orig_len; int npad; int t; @@ -738,28 +734,72 @@ int n_ssl3_mac(SSL *ssl, unsigned char *md, int send) md_size=t; npad=(48/md_size)*md_size; - /* Chop the digest off the end :-) */ - EVP_MD_CTX_init(&md_ctx); - - EVP_MD_CTX_copy_ex( &md_ctx,hash); - EVP_DigestUpdate(&md_ctx,mac_sec,md_size); - EVP_DigestUpdate(&md_ctx,ssl3_pad_1,npad); - EVP_DigestUpdate(&md_ctx,seq,8); - rec_char=rec->type; - EVP_DigestUpdate(&md_ctx,&rec_char,1); - p=md; - s2n(rec->length,p); - EVP_DigestUpdate(&md_ctx,md,2); - EVP_DigestUpdate(&md_ctx,rec->input,rec->length); - EVP_DigestFinal_ex( &md_ctx,md,NULL); - - EVP_MD_CTX_copy_ex( &md_ctx,hash); - 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_MD_CTX_cleanup(&md_ctx); + /* kludge: ssl3_cbc_remove_padding passes padding length in rec->type */ + orig_len = rec->length+md_size+((unsigned int)rec->type>>8); + rec->type &= 0xff; + + 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, 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); + + EVP_MD_CTX_copy_ex( &md_ctx,hash); + EVP_DigestUpdate(&md_ctx,mac_sec,md_size); + EVP_DigestUpdate(&md_ctx,ssl3_pad_1,npad); + EVP_DigestUpdate(&md_ctx,seq,8); + rec_char=rec->type; + EVP_DigestUpdate(&md_ctx,&rec_char,1); + p=md; + s2n(rec->length,p); + EVP_DigestUpdate(&md_ctx,md,2); + EVP_DigestUpdate(&md_ctx,rec->input,rec->length); + EVP_DigestFinal_ex( &md_ctx,md,NULL); + + EVP_MD_CTX_copy_ex( &md_ctx,hash); + 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_u); + md_size = md_size_u; + + EVP_MD_CTX_cleanup(&md_ctx); + } ssl3_record_sequence_update(seq); return(md_size);