X-Git-Url: https://git.openssl.org/gitweb/?a=blobdiff_plain;f=ssl%2Fs3_pkt.c;h=33286b84d2dc4d6b37e212e78d5e5b581c02108b;hb=2911575c6e790541e495927a60121d7546a66962;hp=80562914f0b49cbd66f5aee3ce74f96ff5e4a9f5;hpb=cbd64894ec687c6f37d8e43c16dff78e63f6be87;p=openssl.git diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c index 80562914f0..33286b84d2 100644 --- a/ssl/s3_pkt.c +++ b/ssl/s3_pkt.c @@ -117,6 +117,10 @@ #include #include +#ifndef EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK +# define EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK 0 +#endif + static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, unsigned int len, int create_empty_fragment); static int ssl3_get_record(SSL *s); @@ -272,6 +276,12 @@ int ssl3_read_n(SSL *s, int n, int max, int extend) return(n); } +/* MAX_EMPTY_RECORDS defines the number of consecutive, empty records that will + * be processed per call to ssl3_get_record. Without this limit an attacker + * could send empty records at a faster rate than we can process and cause + * ssl3_get_record to loop forever. */ +#define MAX_EMPTY_RECORDS 32 + /* Call this to get a new input record. * It will return <= 0 if more data is needed, normally due to an error * or non-blocking IO. @@ -292,6 +302,7 @@ static int ssl3_get_record(SSL *s) short version; unsigned mac_size; size_t extra; + unsigned empty_record_count = 0; rr= &(s->s3->rrec); sess=s->session; @@ -401,6 +412,30 @@ fprintf(stderr, "Record type=%d, Length=%d\n", rr->type, rr->length); /* decrypt in place in 'rr->input' */ rr->data=rr->input; rr->orig_len=rr->length; + /* If in encrypt-then-mac mode calculate mac from encrypted record. + * All the details below are public so no timing details can leak. + */ + if (SSL_USE_ETM(s) && s->read_hash) + { + unsigned char *mac; + mac_size=EVP_MD_CTX_size(s->read_hash); + OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE); + if (rr->length < mac_size) + { + al=SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_LENGTH_TOO_SHORT); + goto f_err; + } + rr->length -= mac_size; + mac = rr->data + rr->length; + i=s->method->ssl3_enc->mac(s,md,0 /* not send */); + if (i < 0 || CRYPTO_memcmp(md, mac, (size_t)mac_size) != 0) + { + al=SSL_AD_BAD_RECORD_MAC; + SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); + goto f_err; + } + } enc_err = s->method->ssl3_enc->enc(s,0); /* enc_err is: @@ -423,7 +458,7 @@ printf("\n"); /* 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)) + (EVP_MD_CTX_md(s->read_hash) != NULL) && !SSL_USE_ETM(s)) { /* s->read_hash != NULL => mac_size != -1 */ unsigned char *mac = NULL; @@ -478,7 +513,7 @@ printf("\n"); /* A separate 'decryption_failed' alert was introduced with TLS 1.0, * SSL 3.0 only has 'bad_record_mac'. But unless a decryption * failure is directly visible from the ciphertext anyway, - * we should not reveal which kind of error occured -- this + * we should not reveal which kind of error occurred -- this * might become visible to an attacker (e.g. via a logfile) */ al=SSL_AD_BAD_RECORD_MAC; SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); @@ -522,7 +557,17 @@ printf("\n"); s->packet_length=0; /* just read a 0 length packet */ - if (rr->length == 0) goto again; + if (rr->length == 0) + { + empty_record_count++; + if (empty_record_count > MAX_EMPTY_RECORDS) + { + al=SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_TOO_MANY_EMPTY_FRAGMENTS); + goto f_err; + } + goto again; + } #if 0 fprintf(stderr, "Ultimate Record type=%d, Length=%d\n", rr->type, rr->length); @@ -683,6 +728,55 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, goto err; } +#if !defined(OPENSSL_NO_MULTIBLOCK) && EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK + if (type==SSL3_RT_APPLICATION_DATA && s->compress==NULL && + !SSL_USE_ETM(s) && SSL_USE_EXPLICIT_IV(s) && /*!SSL_IS_DTLS(s) &&*/ + EVP_CIPHER_flags(s->enc_write_ctx->cipher)&EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK) + do { + unsigned char aad[13]; + EVP_CTRL_TLS1_1_MULTIBLOCK_PARAM mb_param = {NULL,aad,sizeof(aad),0}; + int packlen; + + memcpy(aad,s->s3->write_sequence,8); + aad[8]=type; + aad[9]=(unsigned char)(s->version>>8); + aad[10]=(unsigned char)(s->version); + aad[11]=(unsigned char)(len>>8); + aad[12]=(unsigned char)len; + packlen = EVP_CIPHER_CTX_ctrl(s->enc_write_ctx, + EVP_CTRL_TLS1_1_MULTIBLOCK_AAD, + sizeof(mb_param),&mb_param); + + if (packlen==0 || packlen > wb->len) break; + + mb_param.out = wb->buf; + mb_param.inp = buf; + mb_param.len = len; + EVP_CIPHER_CTX_ctrl(s->enc_write_ctx, + EVP_CTRL_TLS1_1_MULTIBLOCK_ENCRYPT, + sizeof(mb_param),&mb_param); + + s->s3->write_sequence[7] += mb_param.interleave; + if (s->s3->write_sequence[7] < mb_param.interleave) + { + int j=6; + while (j>=0 && (++s->s3->write_sequence[j--])==0) ; + } + + wb->offset=0; + wb->left = packlen; + + /* memorize arguments so that ssl3_write_pending can detect bad write retries later */ + s->s3->wpend_tot=len; + s->s3->wpend_buf=buf; + s->s3->wpend_type=type; + s->s3->wpend_ret=len; + + /* we now just need to write the buffer */ + return ssl3_write_pending(s,type,buf,len); + } while (0); +#endif + /* 'create_empty_fragment' is true only when this function calls itself */ if (!clear && !create_empty_fragment && !s->s3->empty_fragment_done) { @@ -803,7 +897,7 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, * from wr->input. Length should be wr->length. * wr->data still points in the wb->buf */ - if (mac_size != 0) + if (!SSL_USE_ETM(s) && mac_size != 0) { if (s->method->ssl3_enc->mac(s,&(p[wr->length + eivlen]),1) < 0) goto err; @@ -823,6 +917,13 @@ static int do_ssl3_write(SSL *s, int type, const unsigned char *buf, /* ssl3_enc can only have an error on read */ s->method->ssl3_enc->enc(s,1); + if (SSL_USE_ETM(s) && mac_size != 0) + { + if (s->method->ssl3_enc->mac(s,p + wr->length,1) < 0) + goto err; + wr->length+=mac_size; + } + /* record length after mac and block padding */ s2n(wr->length,plen);