diff options
Diffstat (limited to 'crypto/openssl/ssl/d1_pkt.c')
-rw-r--r-- | crypto/openssl/ssl/d1_pkt.c | 117 |
1 files changed, 68 insertions, 49 deletions
diff --git a/crypto/openssl/ssl/d1_pkt.c b/crypto/openssl/ssl/d1_pkt.c index 3f19077af111..9db44c95f9bd 100644 --- a/crypto/openssl/ssl/d1_pkt.c +++ b/crypto/openssl/ssl/d1_pkt.c @@ -139,7 +139,6 @@ static int dtls1_process_record(SSL *s); #if PQ_64BIT_IS_INTEGER static PQ_64BIT bytes_to_long_long(unsigned char *bytes, PQ_64BIT *num); #endif -static void dtls1_clear_timeouts(SSL *s); /* copy buffered record into SSL structure */ static int @@ -328,15 +327,13 @@ dtls1_get_buffered_record(SSL *s) static int dtls1_process_record(SSL *s) { - int al; - int clear=0; - int enc_err; + int i,al; + int enc_err; SSL_SESSION *sess; - SSL3_RECORD *rr; - unsigned int mac_size; + SSL3_RECORD *rr; + unsigned int mac_size, orig_len; unsigned char md[EVP_MAX_MD_SIZE]; - rr= &(s->s3->rrec); sess = s->session; @@ -365,15 +362,18 @@ dtls1_process_record(SSL *s) /* decrypt in place in 'rr->input' */ rr->data=rr->input; + 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) { - if (enc_err == 0) - /* SSLerr() and ssl3_send_alert() have been called */ - goto err; - - /* otherwise enc_err == -1 */ + /* For DTLS we simply ignore bad packets. */ + rr->length = 0; + s->packet_length = 0; goto err; } @@ -384,42 +384,64 @@ 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) && + (s->read_hash != NULL)) { + /* s->read_hash != NULL => mac_size != -1 */ + unsigned char *mac = NULL; + unsigned char mac_tmp[EVP_MAX_MD_SIZE]; mac_size=EVP_MD_size(s->read_hash); + OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE); - if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+mac_size) - { -#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); - goto f_err; -#else - goto err; -#endif - } - /* check the MAC for rr->input (it's in mac_size bytes at the tail) */ - if (rr->length < 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 (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 */ al=SSL_AD_DECODE_ERROR; SSLerr(SSL_F_DTLS1_PROCESS_RECORD,SSL_R_LENGTH_TOO_SHORT); goto f_err; -#else - goto err; -#endif } - rr->length-=mac_size; - s->method->ssl3_enc->mac(s,md,0); - if (memcmp(md,&(rr->data[rr->length]),mac_size) != 0) + + if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE) { - goto err; + /* 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; } + else + { + /* 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 || 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 (enc_err < 0) + { + /* decryption failed, silently discard message */ + rr->length = 0; + s->packet_length = 0; + goto err; } /* r->length is now just compressed */ @@ -615,10 +637,12 @@ again: /* If this record is from the next epoch (either HM or ALERT), * and a handshake is currently in progress, buffer it since it - * cannot be processed at this time. */ + * cannot be processed at this time. However, do not buffer + * anything while listening. + */ if (is_next_epoch) { - if (SSL_in_init(s) || s->in_handshake) + if ((SSL_in_init(s) || s->in_handshake) && !s->d1->listen) { dtls1_buffer_record(s, &(s->d1->unprocessed_rcds), &rr->seq_num); } @@ -634,7 +658,6 @@ again: goto again; /* get another record */ } - dtls1_clear_timeouts(s); /* done waiting */ return(1); } @@ -1103,6 +1126,9 @@ start: */ if (msg_hdr.type == SSL3_MT_FINISHED) { + if (dtls1_check_timeout_num(s) < 0) + return -1; + dtls1_retransmit_buffered_messages(s); rr->length = 0; goto start; @@ -1806,10 +1832,3 @@ bytes_to_long_long(unsigned char *bytes, PQ_64BIT *num) return _num; } #endif - - -static void -dtls1_clear_timeouts(SSL *s) - { - memset(&(s->d1->timeout), 0x00, sizeof(struct dtls1_timeout_st)); - } |