diff options
Diffstat (limited to 'src/libstrongswan/credentials')
-rw-r--r-- | src/libstrongswan/credentials/auth_cfg.c | 56 | ||||
-rw-r--r-- | src/libstrongswan/credentials/cert_validator.h | 17 | ||||
-rw-r--r-- | src/libstrongswan/credentials/credential_manager.c | 116 |
3 files changed, 157 insertions, 32 deletions
diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c index a718de3dc..d2d0a7d72 100644 --- a/src/libstrongswan/credentials/auth_cfg.c +++ b/src/libstrongswan/credentials/auth_cfg.c @@ -76,7 +76,6 @@ static inline bool is_multi_value_rule(auth_rule_t type) case AUTH_RULE_AAA_IDENTITY: case AUTH_RULE_XAUTH_IDENTITY: case AUTH_RULE_XAUTH_BACKEND: - case AUTH_RULE_SUBJECT_CERT: case AUTH_HELPER_SUBJECT_CERT: case AUTH_HELPER_SUBJECT_HASH_URL: case AUTH_RULE_MAX: @@ -84,6 +83,7 @@ static inline bool is_multi_value_rule(auth_rule_t type) case AUTH_RULE_OCSP_VALIDATION: case AUTH_RULE_CRL_VALIDATION: case AUTH_RULE_GROUP: + case AUTH_RULE_SUBJECT_CERT: case AUTH_RULE_CA_CERT: case AUTH_RULE_IM_CERT: case AUTH_RULE_CERT_POLICY: @@ -503,8 +503,9 @@ METHOD(auth_cfg_t, complies, bool, private_auth_cfg_t *this, auth_cfg_t *constraints, bool log_error) { enumerator_t *e1, *e2; - bool success = TRUE, group_match = FALSE; + bool success = TRUE, group_match = FALSE, cert_match = FALSE; identification_t *require_group = NULL; + certificate_t *require_cert = NULL; signature_scheme_t scheme = SIGN_UNKNOWN; u_int strength = 0; auth_rule_t t1, t2; @@ -542,20 +543,21 @@ METHOD(auth_cfg_t, complies, bool, } case AUTH_RULE_SUBJECT_CERT: { - certificate_t *c1, *c2; + certificate_t *cert; - c1 = (certificate_t*)value; - c2 = get(this, AUTH_RULE_SUBJECT_CERT); - if (!c2 || !c1->equals(c1, c2)) + /* for certs, a match of a single cert is sufficient */ + require_cert = (certificate_t*)value; + + e2 = create_enumerator(this); + while (e2->enumerate(e2, &t2, &cert)) { - success = FALSE; - if (log_error) + if (t2 == AUTH_RULE_SUBJECT_CERT && + cert->equals(cert, require_cert)) { - DBG1(DBG_CFG, "constraint check failed: peer not " - "authenticated with peer cert '%Y'.", - c1->get_subject(c1)); + cert_match = TRUE; } } + e2->destroy(e2); break; } case AUTH_RULE_CRL_VALIDATION: @@ -828,6 +830,17 @@ METHOD(auth_cfg_t, complies, bool, } return FALSE; } + + if (require_cert && !cert_match) + { + if (log_error) + { + DBG1(DBG_CFG, "constraint check failed: peer not " + "authenticated with peer cert '%Y'.", + require_cert->get_subject(require_cert)); + } + return FALSE; + } return success; } @@ -999,14 +1012,15 @@ METHOD(auth_cfg_t, clone_, auth_cfg_t*, { enumerator_t *enumerator; auth_cfg_t *clone; - entry_t *entry; + auth_rule_t type; + void *value; clone = auth_cfg_create(); /* this enumerator skips duplicates for rules we expect only once */ - enumerator = this->entries->create_enumerator(this->entries); - while (enumerator->enumerate(enumerator, &entry)) + enumerator = create_enumerator(this); + while (enumerator->enumerate(enumerator, &type, &value)) { - switch (entry->type) + switch (type) { case AUTH_RULE_IDENTITY: case AUTH_RULE_EAP_IDENTITY: @@ -1014,8 +1028,8 @@ METHOD(auth_cfg_t, clone_, auth_cfg_t*, case AUTH_RULE_GROUP: case AUTH_RULE_XAUTH_IDENTITY: { - identification_t *id = (identification_t*)entry->value; - clone->add(clone, entry->type, id->clone(id)); + identification_t *id = (identification_t*)value; + clone->add(clone, type, id->clone(id)); break; } case AUTH_RULE_CA_CERT: @@ -1025,8 +1039,8 @@ METHOD(auth_cfg_t, clone_, auth_cfg_t*, case AUTH_HELPER_SUBJECT_CERT: case AUTH_HELPER_REVOCATION_CERT: { - certificate_t *cert = (certificate_t*)entry->value; - clone->add(clone, entry->type, cert->get_ref(cert)); + certificate_t *cert = (certificate_t*)value; + clone->add(clone, type, cert->get_ref(cert)); break; } case AUTH_RULE_XAUTH_BACKEND: @@ -1034,7 +1048,7 @@ METHOD(auth_cfg_t, clone_, auth_cfg_t*, case AUTH_HELPER_IM_HASH_URL: case AUTH_HELPER_SUBJECT_HASH_URL: { - clone->add(clone, entry->type, strdup(entry->value)); + clone->add(clone, type, strdup(value)); break; } case AUTH_RULE_IDENTITY_LOOSE: @@ -1046,7 +1060,7 @@ METHOD(auth_cfg_t, clone_, auth_cfg_t*, case AUTH_RULE_RSA_STRENGTH: case AUTH_RULE_ECDSA_STRENGTH: case AUTH_RULE_SIGNATURE_SCHEME: - clone->add(clone, entry->type, (uintptr_t)entry->value); + clone->add(clone, type, (uintptr_t)value); break; case AUTH_RULE_MAX: break; diff --git a/src/libstrongswan/credentials/cert_validator.h b/src/libstrongswan/credentials/cert_validator.h index 00e30d7a0..325fa0af3 100644 --- a/src/libstrongswan/credentials/cert_validator.h +++ b/src/libstrongswan/credentials/cert_validator.h @@ -35,6 +35,22 @@ typedef struct cert_validator_t cert_validator_t; struct cert_validator_t { /** + * Check the lifetime of a certificate. + * + * If this function returns SUCCESS or FAILED, the certificate lifetime is + * considered definitely (in-)valid, without asking other validators. + * If all registered validaters return NEED_MORE, the default + * lifetime check is performed. + * + * @param cert certificate to check lifetime + * @param pathlen the current length of the path bottom-up + * @param anchor is certificate trusted root anchor? + * @param auth container for resulting authentication info + * @return SUCCESS, FAILED or NEED_MORE to ask next validator + */ + status_t (*check_lifetime)(cert_validator_t *this, certificate_t *cert, + int pathlen, bool anchor, auth_cfg_t *auth); + /** * Validate a subject certificate in relation to its issuer. * * @param subject subject certificate to check @@ -43,6 +59,7 @@ struct cert_validator_t { * @param pathlen the current length of the path bottom-up * @param anchor is issuer trusted root anchor * @param auth container for resulting authentication info + * @return TRUE if subject certificate valid */ bool (*validate)(cert_validator_t *this, certificate_t *subject, certificate_t *issuer, bool online, u_int pathlen, diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c index 9e40c5a10..f4cd9b9e6 100644 --- a/src/libstrongswan/credentials/credential_manager.c +++ b/src/libstrongswan/credentials/credential_manager.c @@ -515,32 +515,74 @@ static void cache_queue(private_credential_manager_t *this) } /** + * Use validators to check the lifetime of certificates + */ +static bool check_lifetime(private_credential_manager_t *this, + certificate_t *cert, char *label, + int pathlen, bool trusted, auth_cfg_t *auth) +{ + time_t not_before, not_after; + cert_validator_t *validator; + enumerator_t *enumerator; + status_t status = NEED_MORE; + + enumerator = this->validators->create_enumerator(this->validators); + while (enumerator->enumerate(enumerator, &validator)) + { + if (!validator->check_lifetime) + { + continue; + } + status = validator->check_lifetime(validator, cert, + pathlen, trusted, auth); + if (status != NEED_MORE) + { + break; + } + } + enumerator->destroy(enumerator); + + switch (status) + { + case NEED_MORE: + if (!cert->get_validity(cert, NULL, ¬_before, ¬_after)) + { + DBG1(DBG_CFG, "%s certificate invalid (valid from %T to %T)", + label, ¬_before, FALSE, ¬_after, FALSE); + return FALSE; + } + return TRUE; + case SUCCESS: + return TRUE; + case FAILED: + default: + return FALSE; + } +} + +/** * check a certificate for its lifetime */ 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) { - time_t not_before, not_after; cert_validator_t *validator; enumerator_t *enumerator; - if (!subject->get_validity(subject, NULL, ¬_before, ¬_after)) + if (!check_lifetime(this, subject, "subject", pathlen, FALSE, auth) || + !check_lifetime(this, issuer, "issuer", pathlen + 1, trusted, auth)) { - DBG1(DBG_CFG, "subject certificate invalid (valid from %T to %T)", - ¬_before, FALSE, ¬_after, FALSE); - return FALSE; - } - if (!issuer->get_validity(issuer, NULL, ¬_before, ¬_after)) - { - DBG1(DBG_CFG, "issuer certificate invalid (valid from %T to %T)", - ¬_before, FALSE, ¬_after, FALSE); return FALSE; } enumerator = this->validators->create_enumerator(this->validators); while (enumerator->enumerate(enumerator, &validator)) { + if (!validator->validate) + { + continue; + } if (!validator->validate(validator, subject, issuer, online, pathlen, trusted, auth)) { @@ -1041,6 +1083,29 @@ static private_key_t *get_private_by_cert(private_credential_manager_t *this, return private; } +/** + * Move the actually used certificate to front, so it gets returned with get() + */ +static void prefer_cert(auth_cfg_t *auth, certificate_t *cert) +{ + enumerator_t *enumerator; + auth_rule_t rule; + certificate_t *current; + + enumerator = auth->create_enumerator(auth); + while (enumerator->enumerate(enumerator, &rule, ¤t)) + { + if (rule == AUTH_RULE_SUBJECT_CERT) + { + current->get_ref(current); + auth->replace(auth, enumerator, AUTH_RULE_SUBJECT_CERT, cert); + cert = current; + } + } + enumerator->destroy(enumerator); + auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert); +} + METHOD(credential_manager_t, get_private, private_key_t*, private_credential_manager_t *this, key_type_t type, identification_t *id, auth_cfg_t *auth) @@ -1049,6 +1114,7 @@ METHOD(credential_manager_t, get_private, private_key_t*, certificate_t *cert; private_key_t *private = NULL; auth_cfg_t *trustchain; + auth_rule_t rule; /* check if this is a lookup by key ID, and do it if so */ if (id && id->get_type(id) == ID_KEY_ID) @@ -1062,7 +1128,35 @@ METHOD(credential_manager_t, get_private, private_key_t*, if (auth) { - /* if a specific certificate is preferred, check for a matching key */ + /* try to find a trustchain with one of the configured subject certs */ + enumerator = auth->create_enumerator(auth); + while (enumerator->enumerate(enumerator, &rule, &cert)) + { + if (rule == AUTH_RULE_SUBJECT_CERT) + { + private = get_private_by_cert(this, cert, type); + if (private) + { + trustchain = build_trustchain(this, cert, auth); + if (trustchain) + { + auth->merge(auth, trustchain, FALSE); + prefer_cert(auth, cert->get_ref(cert)); + trustchain->destroy(trustchain); + break; + } + private->destroy(private); + private = NULL; + } + } + } + enumerator->destroy(enumerator); + if (private) + { + return private; + } + + /* if none yielded a trustchain, enforce the first configured cert */ cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); if (cert) { |