Use version in SSL_METHOD not SSL structure. When deciding whether to use TLS 1.2 PRF and record hash algorithms use the version number in the corresponding SSL_METHOD structure instead of the SSL structure. The SSL structure version is sometimes inaccurate. Note: OpenSSL 1.0.2 and later effectively do this already. (CVE-2013-6449) Also preventively check EVP errors for handshake digests. diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index bf832bb..c4ef273 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -4286,7 +4286,7 @@ need to go to SSL_ST_ACCEPT. long ssl_get_algorithm2(SSL *s) { long alg2 = s->s3->tmp.new_cipher->algorithm2; - if (TLS1_get_version(s) >= TLS1_2_VERSION && + if (s->method->version == TLS1_2_VERSION && alg2 == (SSL_HANDSHAKE_MAC_DEFAULT|TLS1_PRF)) return SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256; return alg2; diff --git a/ssl/s3_both.c b/ssl/s3_both.c index ead01c8..1e5dcab 100644 --- a/ssl/s3_both.c +++ b/ssl/s3_both.c @@ -161,6 +161,8 @@ int ssl3_send_finished(SSL *s, int a, int b, const char *sender, int slen) i=s->method->ssl3_enc->final_finish_mac(s, sender,slen,s->s3->tmp.finish_md); + if (i == 0) + return 0; s->s3->tmp.finish_md_len = i; memcpy(p, s->s3->tmp.finish_md, i); p+=i; diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c index 804291e..c4bc4e7 100644 --- a/ssl/s3_pkt.c +++ b/ssl/s3_pkt.c @@ -335,7 +335,7 @@ fprintf(stderr, "Record type=%d, Length=%d\n", rr->type, rr->length); if (version != s->version) { SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_WRONG_VERSION_NUMBER); - if ((s->version & 0xFF00) == (version & 0xFF00)) + if ((s->version & 0xFF00) == (version & 0xFF00) && !s->enc_write_ctx && !s->write_hash) /* Send back error using their minor version number :-) */ s->version = (unsigned short)version; al=SSL_AD_PROTOCOL_VERSION; @@ -1459,8 +1459,14 @@ int ssl3_do_change_cipher_spec(SSL *s) slen=s->method->ssl3_enc->client_finished_label_len; } - s->s3->tmp.peer_finish_md_len = s->method->ssl3_enc->final_finish_mac(s, + i = s->method->ssl3_enc->final_finish_mac(s, sender,slen,s->s3->tmp.peer_finish_md); + if (i == 0) + { + SSLerr(SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR); + return 0; + } + s->s3->tmp.peer_finish_md_len = i; return(1); } diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index e5a8b3f..52efed3 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -958,7 +958,8 @@ int ssl3_get_client_hello(SSL *s) (s->version != DTLS1_VERSION && s->client_version < s->version)) { SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO, SSL_R_WRONG_VERSION_NUMBER); - if ((s->client_version>>8) == SSL3_VERSION_MAJOR) + if ((s->client_version>>8) == SSL3_VERSION_MAJOR && + !s->enc_write_ctx && !s->write_hash) { /* similar to ssl3_get_record, send alert using remote version number */ s->version = s->client_version; diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index 809ad2e..72015f5 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -915,18 +915,19 @@ int tls1_final_finish_mac(SSL *s, if (mask & ssl_get_algorithm2(s)) { int hashsize = EVP_MD_size(md); - if (hashsize < 0 || hashsize > (int)(sizeof buf - (size_t)(q-buf))) + EVP_MD_CTX *hdgst = s->s3->handshake_dgst[idx]; + if (!hdgst || hashsize < 0 || hashsize > (int)(sizeof buf - (size_t)(q-buf))) { /* internal error: 'buf' is too small for this cipersuite! */ err = 1; } else { - EVP_MD_CTX_copy_ex(&ctx,s->s3->handshake_dgst[idx]); - EVP_DigestFinal_ex(&ctx,q,&i); - if (i != (unsigned int)hashsize) /* can't really happen */ + if (!EVP_MD_CTX_copy_ex(&ctx, hdgst) || + !EVP_DigestFinal_ex(&ctx,q,&i) || + (i != (unsigned int)hashsize)) err = 1; - q+=i; + q+=hashsize; } } } -- 1.8.3.1