diff --git a/openssl-1.0.1e-cve-2015-1789.patch b/openssl-1.0.1e-cve-2015-1789.patch new file mode 100644 index 0000000..8633a76 --- /dev/null +++ b/openssl-1.0.1e-cve-2015-1789.patch @@ -0,0 +1,103 @@ +diff -up openssl-1.0.1e/crypto/x509/x509_vfy.c.oob-read openssl-1.0.1e/crypto/x509/x509_vfy.c +--- openssl-1.0.1e/crypto/x509/x509_vfy.c.oob-read 2015-05-25 12:03:41.000000000 +0200 ++++ openssl-1.0.1e/crypto/x509/x509_vfy.c 2015-06-09 15:01:51.688640453 +0200 +@@ -1702,49 +1702,92 @@ int X509_cmp_time(const ASN1_TIME *ctm, + ASN1_TIME atm; + long offset; + char buff1[24],buff2[24],*p; +- int i,j; ++ int i, j, remaining; + + p=buff1; +- i=ctm->length; ++ remaining=ctm->length; + str=(char *)ctm->data; ++ /* ++ * Note that the following (historical) code allows much more slack in the ++ * time format than RFC5280. In RFC5280, the representation is fixed: ++ * UTCTime: YYMMDDHHMMSSZ ++ * GeneralizedTime: YYYYMMDDHHMMSSZ ++ */ + if (ctm->type == V_ASN1_UTCTIME) + { +- if ((i < 11) || (i > 17)) return 0; ++ /* YYMMDDHHMM[SS]Z or YYMMDDHHMM[SS](+-)hhmm */ ++ int min_length = sizeof("YYMMDDHHMMZ") - 1; ++ int max_length = sizeof("YYMMDDHHMMSS+hhmm") - 1; ++ if (remaining < min_length || remaining > max_length) ++ return 0; + memcpy(p,str,10); + p+=10; + str+=10; ++ remaining -= 10; + } + else + { +- if (i < 13) return 0; ++ /* YYYYMMDDHHMM[SS[.fff]]Z or YYYYMMDDHHMM[SS[.f[f[f]]]](+-)hhmm */ ++ int min_length = sizeof("YYYYMMDDHHMMZ") - 1; ++ int max_length = sizeof("YYYYMMDDHHMMSS.fff+hhmm") - 1; ++ if (remaining < min_length || remaining > max_length) ++ return 0; + memcpy(p,str,12); + p+=12; + str+=12; ++ remaining -= 12; + } + + if ((*str == 'Z') || (*str == '-') || (*str == '+')) + { *(p++)='0'; *(p++)='0'; } + else + { ++ /* SS (seconds) */ ++ if (remaining < 2) ++ return 0; + *(p++)= *(str++); + *(p++)= *(str++); +- /* Skip any fractional seconds... */ +- if (*str == '.') ++ remaining -= 2; ++ /* ++ * Skip any (up to three) fractional seconds... ++ * TODO(emilia): in RFC5280, fractional seconds are forbidden. ++ * Can we just kill them altogether? ++ */ ++ if (remaining && *str == '.') + { + str++; +- while ((*str >= '0') && (*str <= '9')) str++; ++ remaining--; ++ for (i = 0; i < 3 && remaining; i++, str++, remaining--) ++ { ++ if (*str < '0' || *str > '9') ++ break; ++ } + } + + } + *(p++)='Z'; + *(p++)='\0'; + ++ /* We now need either a terminating 'Z' or an offset. */ ++ if (!remaining) ++ return 0; + if (*str == 'Z') ++ { ++ if (remaining != 1) ++ return 0; + offset=0; ++ } + else + { ++ /* (+-)HHMM */ + if ((*str != '+') && (*str != '-')) + return 0; ++ /* Historical behaviour: the (+-)hhmm offset is forbidden in RFC5280. */ ++ if (remaining != 5) ++ return 0; ++ if (str[1] < '0' || str[1] > '9' || str[2] < '0' || str[2] > '9' || ++ str[3] < '0' || str[3] > '9' || str[4] < '0' || str[4] > '9') ++ return 0; + offset=((str[1]-'0')*10+(str[2]-'0'))*60; + offset+=(str[3]-'0')*10+(str[4]-'0'); + if (*str == '-') diff --git a/openssl-1.0.1e-cve-2015-1790.patch b/openssl-1.0.1e-cve-2015-1790.patch new file mode 100644 index 0000000..3b30240 --- /dev/null +++ b/openssl-1.0.1e-cve-2015-1790.patch @@ -0,0 +1,55 @@ +diff -up openssl-1.0.1e/crypto/pkcs7/pk7_doit.c.missing-content openssl-1.0.1e/crypto/pkcs7/pk7_doit.c +--- openssl-1.0.1e/crypto/pkcs7/pk7_doit.c.missing-content 2015-05-25 12:03:41.000000000 +0200 ++++ openssl-1.0.1e/crypto/pkcs7/pk7_doit.c 2015-06-09 15:21:21.377951520 +0200 +@@ -472,6 +472,12 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKE + switch (i) + { + case NID_pkcs7_signed: ++ /* ++ * p7->d.sign->contents is a PKCS7 structure consisting of a contentType ++ * field and optional content. ++ * data_body is NULL if that structure has no (=detached) content ++ * or if the contentType is wrong (i.e., not "data"). ++ */ + data_body=PKCS7_get_octet_string(p7->d.sign->contents); + if (!PKCS7_is_detached(p7) && data_body == NULL) + { +@@ -484,6 +490,7 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKE + case NID_pkcs7_signedAndEnveloped: + rsk=p7->d.signed_and_enveloped->recipientinfo; + md_sk=p7->d.signed_and_enveloped->md_algs; ++ /* data_body is NULL if the optional EncryptedContent is missing. */ + data_body=p7->d.signed_and_enveloped->enc_data->enc_data; + enc_alg=p7->d.signed_and_enveloped->enc_data->algorithm; + evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm); +@@ -496,6 +503,7 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKE + case NID_pkcs7_enveloped: + rsk=p7->d.enveloped->recipientinfo; + enc_alg=p7->d.enveloped->enc_data->algorithm; ++ /* data_body is NULL if the optional EncryptedContent is missing. */ + data_body=p7->d.enveloped->enc_data->enc_data; + evp_cipher=EVP_get_cipherbyobj(enc_alg->algorithm); + if (evp_cipher == NULL) +@@ -509,6 +517,13 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKE + goto err; + } + ++ /* Detached content must be supplied via in_bio instead. */ ++ if (data_body == NULL && in_bio == NULL) ++ { ++ PKCS7err(PKCS7_F_PKCS7_DATADECODE, PKCS7_R_NO_CONTENT); ++ goto err; ++ } ++ + /* We will be checking the signature */ + if (md_sk != NULL) + { +@@ -665,7 +680,7 @@ BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKE + } + + #if 1 +- if (PKCS7_is_detached(p7) || (in_bio != NULL)) ++ if (in_bio != NULL) + { + bio=in_bio; + } diff --git a/openssl-1.0.1e-cve-2015-1792.patch b/openssl-1.0.1e-cve-2015-1792.patch new file mode 100644 index 0000000..5f2b0cd --- /dev/null +++ b/openssl-1.0.1e-cve-2015-1792.patch @@ -0,0 +1,12 @@ +diff -up openssl-1.0.1e/crypto/cms/cms_smime.c.unknown-hash openssl-1.0.1e/crypto/cms/cms_smime.c +--- openssl-1.0.1e/crypto/cms/cms_smime.c.unknown-hash 2013-02-11 16:26:04.000000000 +0100 ++++ openssl-1.0.1e/crypto/cms/cms_smime.c 2015-06-09 16:07:16.001516190 +0200 +@@ -141,7 +141,7 @@ static void do_free_upto(BIO *f, BIO *up + BIO_free(f); + f = tbio; + } +- while (f != upto); ++ while (f && f != upto); + } + else + BIO_free_all(f); diff --git a/openssl-1.0.1k-cve-2015-0209.patch b/openssl-1.0.1k-cve-2015-0209.patch index 994f963..2d291b2 100644 --- a/openssl-1.0.1k-cve-2015-0209.patch +++ b/openssl-1.0.1k-cve-2015-0209.patch @@ -1,3 +1,34 @@ +diff -up openssl-1.0.1e/crypto/asn1/x_x509.c.use-after-free openssl-1.0.1e/crypto/asn1/x_x509.c +--- openssl-1.0.1e/crypto/asn1/x_x509.c.use-after-free 2013-02-11 16:26:04.000000000 +0100 ++++ openssl-1.0.1e/crypto/asn1/x_x509.c 2015-06-11 11:14:52.581856349 +0200 +@@ -170,8 +170,14 @@ X509 *d2i_X509_AUX(X509 **a, const unsig + { + const unsigned char *q; + X509 *ret; ++ int freeret = 0; ++ + /* Save start position */ + q = *pp; ++ ++ if(!a || *a == NULL) { ++ freeret = 1; ++ } + ret = d2i_X509(a, pp, length); + /* If certificate unreadable then forget it */ + if(!ret) return NULL; +@@ -181,7 +187,11 @@ X509 *d2i_X509_AUX(X509 **a, const unsig + if(!d2i_X509_CERT_AUX(&ret->aux, pp, length)) goto err; + return ret; + err: +- X509_free(ret); ++ if(freeret) { ++ X509_free(ret); ++ if (a) ++ *a = NULL; ++ } + return NULL; + } + diff -up openssl-1.0.1k/crypto/ec/ec_asn1.c.use-after-free openssl-1.0.1k/crypto/ec/ec_asn1.c --- openssl-1.0.1k/crypto/ec/ec_asn1.c.use-after-free 2014-10-15 15:49:54.000000000 +0200 +++ openssl-1.0.1k/crypto/ec/ec_asn1.c 2015-03-19 17:28:03.349627040 +0100 @@ -25,3 +56,27 @@ diff -up openssl-1.0.1k/crypto/ec/ec_asn1.c.use-after-free openssl-1.0.1k/crypto EC_KEY_free(ret); ret = NULL; } +@@ -1377,8 +1377,6 @@ EC_KEY *d2i_ECParameters(EC_KEY **a, con + ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_MALLOC_FAILURE); + return NULL; + } +- if (a) +- *a = ret; + } + else + ret = *a; +@@ -1386,9 +1384,14 @@ EC_KEY *d2i_ECParameters(EC_KEY **a, con + if (!d2i_ECPKParameters(&ret->group, in, len)) + { + ECerr(EC_F_D2I_ECPARAMETERS, ERR_R_EC_LIB); ++ if (a == NULL || *a != ret) ++ EC_KEY_free(ret); + return NULL; + } + ++ if (a) ++ *a = ret; ++ + return ret; + } + diff --git a/openssl-1.0.1k-cve-2015-1791.patch b/openssl-1.0.1k-cve-2015-1791.patch new file mode 100644 index 0000000..3125f84 --- /dev/null +++ b/openssl-1.0.1k-cve-2015-1791.patch @@ -0,0 +1,231 @@ +diff -up openssl-1.0.1k/ssl/ssl_err.c.ticket-race openssl-1.0.1k/ssl/ssl_err.c +--- openssl-1.0.1k/ssl/ssl_err.c.ticket-race 2015-06-15 17:06:22.699702477 +0200 ++++ openssl-1.0.1k/ssl/ssl_err.c 2015-06-15 17:06:22.704702592 +0200 +@@ -245,6 +245,7 @@ static ERR_STRING_DATA SSL_str_functs[]= + {ERR_FUNC(SSL_F_SSL_READ), "SSL_read"}, + {ERR_FUNC(SSL_F_SSL_RSA_PRIVATE_DECRYPT), "SSL_RSA_PRIVATE_DECRYPT"}, + {ERR_FUNC(SSL_F_SSL_RSA_PUBLIC_ENCRYPT), "SSL_RSA_PUBLIC_ENCRYPT"}, ++{ERR_FUNC(SSL_F_SSL_SESSION_DUP), "ssl_session_dup"}, + {ERR_FUNC(SSL_F_SSL_SESSION_NEW), "SSL_SESSION_new"}, + {ERR_FUNC(SSL_F_SSL_SESSION_PRINT_FP), "SSL_SESSION_print_fp"}, + {ERR_FUNC(SSL_F_SSL_SESSION_SET1_ID_CONTEXT), "SSL_SESSION_set1_id_context"}, +diff -up openssl-1.0.1k/ssl/ssl.h.ticket-race openssl-1.0.1k/ssl/ssl.h +--- openssl-1.0.1k/ssl/ssl.h.ticket-race 2015-06-15 17:06:22.700702500 +0200 ++++ openssl-1.0.1k/ssl/ssl.h 2015-06-15 17:06:22.704702592 +0200 +@@ -2203,6 +2203,7 @@ void ERR_load_SSL_strings(void); + #define SSL_F_SSL_READ 223 + #define SSL_F_SSL_RSA_PRIVATE_DECRYPT 187 + #define SSL_F_SSL_RSA_PUBLIC_ENCRYPT 188 ++#define SSL_F_SSL_SESSION_DUP 348 + #define SSL_F_SSL_SESSION_NEW 189 + #define SSL_F_SSL_SESSION_PRINT_FP 190 + #define SSL_F_SSL_SESSION_SET1_ID_CONTEXT 312 +diff -up openssl-1.0.1k/ssl/ssl_locl.h.ticket-race openssl-1.0.1k/ssl/ssl_locl.h +--- openssl-1.0.1k/ssl/ssl_locl.h.ticket-race 2015-06-15 17:06:22.543698865 +0200 ++++ openssl-1.0.1k/ssl/ssl_locl.h 2015-06-15 17:06:22.705702616 +0200 +@@ -831,6 +831,7 @@ void ssl_sess_cert_free(SESS_CERT *sc); + int ssl_set_peer_cert_type(SESS_CERT *c, int type); + int ssl_get_new_session(SSL *s, int session); + int ssl_get_prev_session(SSL *s, unsigned char *session,int len, const unsigned char *limit); ++SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket); + int ssl_cipher_id_cmp(const SSL_CIPHER *a,const SSL_CIPHER *b); + DECLARE_OBJ_BSEARCH_GLOBAL_CMP_FN(SSL_CIPHER, SSL_CIPHER, + ssl_cipher_id); +diff -up openssl-1.0.1k/ssl/ssl_sess.c.ticket-race openssl-1.0.1k/ssl/ssl_sess.c +--- openssl-1.0.1k/ssl/ssl_sess.c.ticket-race 2015-01-08 15:00:56.000000000 +0100 ++++ openssl-1.0.1k/ssl/ssl_sess.c 2015-06-15 17:06:22.705702616 +0200 +@@ -224,6 +224,146 @@ SSL_SESSION *SSL_SESSION_new(void) + return(ss); + } + ++/* ++ * Create a new SSL_SESSION and duplicate the contents of |src| into it. If ++ * ticket == 0 then no ticket information is duplicated, otherwise it is. ++ */ ++SSL_SESSION *ssl_session_dup(SSL_SESSION *src, int ticket) ++{ ++ SSL_SESSION *dest; ++ ++ dest = OPENSSL_malloc(sizeof(*src)); ++ if (dest == NULL) ++ { ++ goto err; ++ } ++ memcpy(dest, src, sizeof(*dest)); ++ ++ /* ++ * Set the various pointers to NULL so that we can call SSL_SESSION_free in ++ * the case of an error whilst halfway through constructing dest ++ */ ++#ifndef OPENSSL_NO_PSK ++ dest->psk_identity_hint = NULL; ++ dest->psk_identity = NULL; ++#endif ++ dest->ciphers = NULL; ++#ifndef OPENSSL_NO_TLSEXT ++ dest->tlsext_hostname = NULL; ++# ifndef OPENSSL_NO_EC ++ dest->tlsext_ecpointformatlist = NULL; ++ dest->tlsext_ellipticcurvelist = NULL; ++# endif ++#endif ++ dest->tlsext_tick = NULL; ++#ifndef OPENSSL_NO_SRP ++ dest->srp_username = NULL; ++#endif ++ memset(&dest->ex_data, 0, sizeof(dest->ex_data)); ++ ++ /* We deliberately don't copy the prev and next pointers */ ++ dest->prev = NULL; ++ dest->next = NULL; ++ ++ dest->references = 1; ++ ++ if (src->sess_cert != NULL) ++ CRYPTO_add(&src->sess_cert->references, 1, CRYPTO_LOCK_SSL_SESS_CERT); ++ ++ if (src->peer != NULL) ++ CRYPTO_add(&src->peer->references, 1, CRYPTO_LOCK_X509); ++ ++#ifndef OPENSSL_NO_PSK ++ if (src->psk_identity_hint) ++ { ++ dest->psk_identity_hint = BUF_strdup(src->psk_identity_hint); ++ if (dest->psk_identity_hint == NULL) ++ { ++ goto err; ++ } ++ } ++ if (src->psk_identity) ++ { ++ dest->psk_identity = BUF_strdup(src->psk_identity); ++ if (dest->psk_identity == NULL) ++ { ++ goto err; ++ } ++ } ++#endif ++ ++ if(src->ciphers != NULL) ++ { ++ dest->ciphers = sk_SSL_CIPHER_dup(src->ciphers); ++ if (dest->ciphers == NULL) ++ goto err; ++ } ++ ++ if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ++ &dest->ex_data, &src->ex_data)) ++ { ++ goto err; ++ } ++ ++#ifndef OPENSSL_NO_TLSEXT ++ if (src->tlsext_hostname) ++ { ++ dest->tlsext_hostname = BUF_strdup(src->tlsext_hostname); ++ if (dest->tlsext_hostname == NULL) ++ { ++ goto err; ++ } ++ } ++# ifndef OPENSSL_NO_EC ++ if (src->tlsext_ecpointformatlist) ++ { ++ dest->tlsext_ecpointformatlist = ++ BUF_memdup(src->tlsext_ecpointformatlist, ++ src->tlsext_ecpointformatlist_length); ++ if (dest->tlsext_ecpointformatlist == NULL) ++ goto err; ++ } ++ if (src->tlsext_ellipticcurvelist) ++ { ++ dest->tlsext_ellipticcurvelist = ++ BUF_memdup(src->tlsext_ellipticcurvelist, ++ src->tlsext_ellipticcurvelist_length); ++ if (dest->tlsext_ellipticcurvelist == NULL) ++ goto err; ++ } ++# endif ++#endif ++ ++ if (ticket != 0) ++ { ++ dest->tlsext_tick = BUF_memdup(src->tlsext_tick, src->tlsext_ticklen); ++ if(dest->tlsext_tick == NULL) ++ goto err; ++ } ++ else ++ { ++ dest->tlsext_tick_lifetime_hint = 0; ++ dest->tlsext_ticklen = 0; ++ } ++ ++#ifndef OPENSSL_NO_SRP ++ if (src->srp_username) ++ { ++ dest->srp_username = BUF_strdup(src->srp_username); ++ if (dest->srp_username == NULL) ++ { ++ goto err; ++ } ++ } ++#endif ++ ++ return dest; ++err: ++ SSLerr(SSL_F_SSL_SESSION_DUP, ERR_R_MALLOC_FAILURE); ++ SSL_SESSION_free(dest); ++ return NULL; ++} ++ + const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s, unsigned int *len) + { + if(len) +diff -up openssl-1.0.1k/ssl/s3_clnt.c.ticket-race openssl-1.0.1k/ssl/s3_clnt.c +--- openssl-1.0.1k/ssl/s3_clnt.c.ticket-race 2015-06-15 17:06:22.700702500 +0200 ++++ openssl-1.0.1k/ssl/s3_clnt.c 2015-06-15 17:06:37.434043557 +0200 +@@ -2191,6 +2191,44 @@ int ssl3_get_new_session_ticket(SSL *s) + } + + p=d=(unsigned char *)s->init_msg; ++ ++ if (s->session->session_id_length > 0) ++ { ++ int i = s->session_ctx->session_cache_mode; ++ SSL_SESSION *new_sess; ++ /* ++ * We reused an existing session, so we need to replace it with a new ++ * one ++ */ ++ if (i & SSL_SESS_CACHE_CLIENT) ++ { ++ /* ++ * Remove the old session from the cache ++ */ ++ if (i & SSL_SESS_CACHE_NO_INTERNAL_STORE) ++ { ++ if (s->session_ctx->remove_session_cb != NULL) ++ s->session_ctx->remove_session_cb(s->session_ctx, ++ s->session); ++ } ++ else ++ { ++ /* We carry on if this fails */ ++ SSL_CTX_remove_session(s->session_ctx, s->session); ++ } ++ } ++ ++ if ((new_sess = ssl_session_dup(s->session, 0)) == 0) ++ { ++ al = SSL_AD_INTERNAL_ERROR; ++ SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE); ++ goto f_err; ++ } ++ ++ SSL_SESSION_free(s->session); ++ s->session = new_sess; ++ } ++ + n2l(p, s->session->tlsext_tick_lifetime_hint); + n2s(p, ticklen); + /* ticket_lifetime_hint + ticket_length + ticket */ diff --git a/openssl.spec b/openssl.spec index 19b650a..73667c8 100644 --- a/openssl.spec +++ b/openssl.spec @@ -23,7 +23,7 @@ Summary: Utilities from the general purpose cryptography library with TLS implementation Name: openssl Version: 1.0.1k -Release: 9%{?dist} +Release: 10%{?dist} Epoch: 1 # We have to remove certain patented algorithms from the openssl source # tarball with the hobble-openssl script which is included below. @@ -98,6 +98,10 @@ Patch105: openssl-1.0.1k-cve-2015-0289.patch Patch106: openssl-1.0.1e-cve-2015-0293.patch Patch107: openssl-1.0.1k-alt-chains.patch Patch108: openssl-1.0.1k-cve-2015-4000.patch +Patch109: openssl-1.0.1e-cve-2015-1789.patch +Patch110: openssl-1.0.1e-cve-2015-1790.patch +Patch111: openssl-1.0.1k-cve-2015-1791.patch +Patch112: openssl-1.0.1e-cve-2015-1792.patch License: OpenSSL Group: System Environment/Libraries @@ -229,6 +233,10 @@ cp %{SOURCE12} %{SOURCE13} crypto/ec/ %patch106 -p1 -b .ssl2-assert %patch107 -p1 -b .alt-chains %patch108 -p1 -b .logjam +%patch109 -p1 -b .oob-read +%patch110 -p1 -b .missing-content +%patch111 -p1 -b .ticket-race +%patch112 -p1 -b .unknown-hash sed -i 's/SHLIB_VERSION_NUMBER "1.0.0"/SHLIB_VERSION_NUMBER "%{version}"/' crypto/opensslv.h @@ -496,6 +504,13 @@ rm -rf $RPM_BUILD_ROOT/%{_libdir}/fipscanister.* %postun libs -p /sbin/ldconfig %changelog +* Mon Jun 15 2015 Tomáš Mráz 1.0.1k-10 +- fix CVE-2015-1789 - out-of-bounds read in X509_cmp_time +- fix CVE-2015-1790 - PKCS7 crash with missing EncryptedContent +- fix CVE-2015-1791 - race condition handling NewSessionTicket +- fix CVE-2015-1792 - CMS verify infinite loop with unknown hash function +- add missing parts of CVE-2015-0209 fix for corectness although unexploitable + * Fri May 29 2015 Tomáš Mráz 1.0.1k-9 - fix CVE-2015-4000 - prevent the logjam attack on client - restrict the DH key size to at least 768 bits (limit will be increased in future)