diff --git a/CVE-2022-40617.patch b/CVE-2022-40617.patch new file mode 100644 index 0000000000000000000000000000000000000000..8ee729cfcaeba81418880f991bde8735b86d10bc --- /dev/null +++ b/CVE-2022-40617.patch @@ -0,0 +1,204 @@ +From 66d3b2e0e596a6eac1ebcd15c83a8d9368fe7b34 Mon Sep 17 00:00:00 2001 +From: Tobias Brunner +Date: Fri, 22 Jul 2022 15:37:43 +0200 +Subject: [PATCH] credential-manager: Do online revocation checks only after + basic trust chain validation + +This avoids querying URLs of potentially untrusted certificates, e.g. if +an attacker sends a specially crafted end-entity and intermediate CA +certificate with a CDP that points to a server that completes the +TCP handshake but then does not send any further data, which will block +the fetcher thread (depending on the plugin) for as long as the default +timeout for TCP. Doing that multiple times will block all worker threads, +leading to a DoS attack. + +The logging during the certificate verification obviously changes. The +following example shows the output of `pki --verify` for the current +strongswan.org certificate: + +new: + + using certificate "CN=www.strongswan.org" + using trusted intermediate ca certificate "C=US, O=Let's Encrypt, CN=R3" + using trusted ca certificate "C=US, O=Internet Security Research Group, CN=ISRG Root X1" + reached self-signed root ca with a path length of 1 +checking certificate status of "CN=www.strongswan.org" + requesting ocsp status from 'http://r3.o.lencr.org' ... + ocsp response correctly signed by "C=US, O=Let's Encrypt, CN=R3" + ocsp response is valid: until Jul 27 12:59:58 2022 +certificate status is good +checking certificate status of "C=US, O=Let's Encrypt, CN=R3" +ocsp response verification failed, no signer certificate 'C=US, O=Let's Encrypt, CN=R3' found + fetching crl from 'http://x1.c.lencr.org/' ... + using trusted certificate "C=US, O=Internet Security Research Group, CN=ISRG Root X1" + crl correctly signed by "C=US, O=Internet Security Research Group, CN=ISRG Root X1" + crl is valid: until Apr 18 01:59:59 2023 +certificate status is good +certificate trusted, lifetimes valid, certificate not revoked + +old: + + using certificate "CN=www.strongswan.org" + using trusted intermediate ca certificate "C=US, O=Let's Encrypt, CN=R3" +checking certificate status of "CN=www.strongswan.org" + requesting ocsp status from 'http://r3.o.lencr.org' ... + ocsp response correctly signed by "C=US, O=Let's Encrypt, CN=R3" + ocsp response is valid: until Jul 27 12:59:58 2022 +certificate status is good + using trusted ca certificate "C=US, O=Internet Security Research Group, CN=ISRG Root X1" +checking certificate status of "C=US, O=Let's Encrypt, CN=R3" +ocsp response verification failed, no signer certificate 'C=US, O=Let's Encrypt, CN=R3' found + fetching crl from 'http://x1.c.lencr.org/' ... + using trusted certificate "C=US, O=Internet Security Research Group, CN=ISRG Root X1" + crl correctly signed by "C=US, O=Internet Security Research Group, CN=ISRG Root X1" + crl is valid: until Apr 18 01:59:59 2023 +certificate status is good + reached self-signed root ca with a path length of 1 +certificate trusted, lifetimes valid, certificate not revoked + +Note that this also fixes an issue with the previous dual-use of the +`trusted` flag. It not only indicated whether the chain is trusted but +also whether the current issuer is the root anchor (the corresponding +flag in the `cert_validator_t` interface is called `anchor`). This was +a problem when building multi-level trust chains for pre-trusted +end-entity certificates (i.e. where `trusted` is TRUE from the start). +This caused the main loop to get aborted after the first intermediate CA +certificate and the mentioned `anchor` flag wasn't correct in any calls +to `cert_validator_t` implementations. + +Fixes: CVE-2022-40617 +--- + .../credentials/credential_manager.c | 54 +++++++++++++++---- + 1 file changed, 45 insertions(+), 9 deletions(-) + +diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c +index e93b5943a3a7..798785544e41 100644 +--- a/src/libstrongswan/credentials/credential_manager.c ++++ b/src/libstrongswan/credentials/credential_manager.c +@@ -556,7 +556,7 @@ static void cache_queue(private_credential_manager_t *this) + */ + static bool check_lifetime(private_credential_manager_t *this, + certificate_t *cert, char *label, +- int pathlen, bool trusted, auth_cfg_t *auth) ++ int pathlen, bool anchor, auth_cfg_t *auth) + { + time_t not_before, not_after; + cert_validator_t *validator; +@@ -571,7 +571,7 @@ static bool check_lifetime(private_credential_manager_t *this, + continue; + } + status = validator->check_lifetime(validator, cert, +- pathlen, trusted, auth); ++ pathlen, anchor, auth); + if (status != NEED_MORE) + { + break; +@@ -604,13 +604,13 @@ static bool check_lifetime(private_credential_manager_t *this, + */ + static bool check_certificate(private_credential_manager_t *this, + certificate_t *subject, certificate_t *issuer, bool online, +- int pathlen, bool trusted, auth_cfg_t *auth) ++ int pathlen, bool anchor, auth_cfg_t *auth) + { + cert_validator_t *validator; + enumerator_t *enumerator; + + if (!check_lifetime(this, subject, "subject", pathlen, FALSE, auth) || +- !check_lifetime(this, issuer, "issuer", pathlen + 1, trusted, auth)) ++ !check_lifetime(this, issuer, "issuer", pathlen + 1, anchor, auth)) + { + return FALSE; + } +@@ -623,7 +623,7 @@ static bool check_certificate(private_credential_manager_t *this, + continue; + } + if (!validator->validate(validator, subject, issuer, +- online, pathlen, trusted, auth)) ++ online, pathlen, anchor, auth)) + { + enumerator->destroy(enumerator); + return FALSE; +@@ -726,6 +726,7 @@ static bool verify_trust_chain(private_credential_manager_t *this, + auth_cfg_t *auth; + signature_params_t *scheme; + int pathlen; ++ bool is_anchor = FALSE; + + auth = auth_cfg_create(); + get_key_strength(subject, auth); +@@ -743,7 +744,7 @@ static bool verify_trust_chain(private_credential_manager_t *this, + auth->add(auth, AUTH_RULE_CA_CERT, issuer->get_ref(issuer)); + DBG1(DBG_CFG, " using trusted ca certificate \"%Y\"", + issuer->get_subject(issuer)); +- trusted = TRUE; ++ trusted = is_anchor = TRUE; + } + else + { +@@ -778,11 +779,18 @@ static bool verify_trust_chain(private_credential_manager_t *this, + DBG1(DBG_CFG, " issuer is \"%Y\"", + current->get_issuer(current)); + call_hook(this, CRED_HOOK_NO_ISSUER, current); ++ if (trusted) ++ { ++ DBG1(DBG_CFG, " reached end of incomplete trust chain for " ++ "trusted certificate \"%Y\"", ++ subject->get_subject(subject)); ++ } + break; + } + } +- if (!check_certificate(this, current, issuer, online, +- pathlen, trusted, auth)) ++ /* don't do online verification here */ ++ if (!check_certificate(this, current, issuer, FALSE, ++ pathlen, is_anchor, auth)) + { + trusted = FALSE; + issuer->destroy(issuer); +@@ -794,7 +802,7 @@ static bool verify_trust_chain(private_credential_manager_t *this, + } + current->destroy(current); + current = issuer; +- if (trusted) ++ if (is_anchor) + { + DBG1(DBG_CFG, " reached self-signed root ca with a " + "path length of %d", pathlen); +@@ -807,6 +815,34 @@ static bool verify_trust_chain(private_credential_manager_t *this, + DBG1(DBG_CFG, "maximum path length of %d exceeded", MAX_TRUST_PATH_LEN); + call_hook(this, CRED_HOOK_EXCEEDED_PATH_LEN, subject); + } ++ else if (trusted && online) ++ { ++ enumerator_t *enumerator; ++ auth_rule_t rule; ++ ++ /* do online revocation checks after basic validation of the chain */ ++ pathlen = 0; ++ current = subject; ++ enumerator = auth->create_enumerator(auth); ++ while (enumerator->enumerate(enumerator, &rule, &issuer)) ++ { ++ if (rule == AUTH_RULE_CA_CERT || rule == AUTH_RULE_IM_CERT) ++ { ++ if (!check_certificate(this, current, issuer, TRUE, pathlen++, ++ rule == AUTH_RULE_CA_CERT, auth)) ++ { ++ trusted = FALSE; ++ break; ++ } ++ else if (rule == AUTH_RULE_CA_CERT) ++ { ++ break; ++ } ++ current = issuer; ++ } ++ } ++ enumerator->destroy(enumerator); ++ } + if (trusted) + { + result->merge(result, auth, FALSE); +-- +2.25.1 \ No newline at end of file diff --git a/strongswan.spec b/strongswan.spec index fc33354291a718bb99df3f5865351f8c1ab3c3d4..612193864f62ec7984e8d90a8e230932b5372ee3 100644 --- a/strongswan.spec +++ b/strongswan.spec @@ -1,12 +1,13 @@ Name: strongswan Version: 5.9.7 -Release: 3 +Release: 4 Summary: An OpenSource IPsec-based VPN and TNC solution License: GPLv2+ URL: http://www.strongswan.org/ Source0: http://download.strongswan.org/strongswan-%{version}.tar.bz2 Patch0: remove-warning-no-format.patch +Patch1: CVE-2022-40617.patch BuildRequires: gcc chrpath autoconf automake libtool tpm2-abrmd BuildRequires: systemd-devel gmp-devel libcurl-devel NetworkManager-libnm-devel openldap-devel @@ -192,6 +193,9 @@ echo "%{_libdir}/strongswan" > %{buildroot}/etc/ld.so.conf.d/%{name}-%{_arch}.co %{_libexecdir}/strongswan/charon-nm %changelog +* Mon Oct 10 2022 openhosec - 5.9.7-4 +- Fix CVE-2022-40617 + * Tue Sep 13 2022 wangkai - 5.9.7-3 - Add Requires strongswan-tnc-imcvs and strongswan-libipsec