158 lines
5.3 KiB
Diff
158 lines
5.3 KiB
Diff
From 6a6c275534e31b41f6d203cfd92685b7526a45e8 Mon Sep 17 00:00:00 2001
|
|
From: Hitendra Prajapati <hprajapati@mvista.com>
|
|
Date: Fri, 11 Nov 2022 10:15:38 +0530
|
|
Subject: [PATCH] CVE-2022-40617
|
|
|
|
Upstream-Status: Backport [https://download.strongswan.org/security/CVE-2022-40617]
|
|
CVE: CVE-2022-40617
|
|
Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
|
|
|
|
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.
|
|
---
|
|
.../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 3be0190..f65372b 100644
|
|
--- a/src/libstrongswan/credentials/credential_manager.c
|
|
+++ b/src/libstrongswan/credentials/credential_manager.c
|
|
@@ -555,7 +555,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;
|
|
@@ -570,7 +570,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;
|
|
@@ -603,13 +603,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;
|
|
}
|
|
@@ -622,7 +622,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;
|
|
@@ -725,6 +725,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);
|
|
@@ -742,7 +743,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
|
|
{
|
|
@@ -777,11 +778,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);
|
|
@@ -793,7 +801,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);
|
|
@@ -806,6 +814,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
|
|
|