diff options
author | Tobias Brunner <tobias@strongswan.org> | 2015-10-27 17:25:22 +0100 |
---|---|---|
committer | Tobias Brunner <tobias@strongswan.org> | 2016-03-10 11:07:14 +0100 |
commit | 1b9c1ae018aa176aaf9e1f11503b72cc622ba771 (patch) | |
tree | 66877eb13a7859ead856f61aad1c337ff4cfd045 | |
parent | ef9171ad1ee9145a7139c365524006abb930a41d (diff) | |
download | strongswan-1b9c1ae018aa176aaf9e1f11503b72cc622ba771.tar.bz2 strongswan-1b9c1ae018aa176aaf9e1f11503b72cc622ba771.tar.xz |
ike-sa: Add method to verify certificates in completed authentication rounds
-rw-r--r-- | src/libcharon/sa/ike_sa.c | 103 | ||||
-rw-r--r-- | src/libcharon/sa/ike_sa.h | 8 |
2 files changed, 111 insertions, 0 deletions
diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index b07ff0e74..3384c0278 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -58,6 +58,7 @@ #include <sa/ikev2/tasks/ike_auth_lifetime.h> #include <sa/ikev2/tasks/ike_reauth_complete.h> #include <sa/ikev2/tasks/ike_redirect.h> +#include <credentials/sets/auth_cfg_wrapper.h> #ifdef ME #include <sa/ikev2/tasks/ike_me.h> @@ -462,6 +463,107 @@ METHOD(ike_sa_t, create_auth_cfg_enumerator, enumerator_t*, return array_create_enumerator(this->other_auths); } +METHOD(ike_sa_t, verify_peer_certificate, bool, + private_ike_sa_t *this) +{ + enumerator_t *e1, *e2, *certs; + auth_cfg_t *cfg, *cfg_done; + certificate_t *peer, *cert; + public_key_t *key; + auth_cfg_t *auth; + auth_cfg_wrapper_t *wrapper; + time_t not_before, not_after; + bool valid = TRUE, found; + + if (this->state != IKE_ESTABLISHED) + { + DBG1(DBG_IKE, "unable to verify peer certificate in state %N", + ike_sa_state_names, this->state); + return FALSE; + } + + if (lib->settings->get_bool(lib->settings, + "%s.flush_auth_cfg", FALSE, lib->ns)) + { + DBG1(DBG_IKE, "unable to verify peer certificate as authentication " + "information has been flushed"); + return FALSE; + } + + e1 = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, FALSE); + e2 = array_create_enumerator(this->other_auths); + while (e1->enumerate(e1, &cfg)) + { + if (!e2->enumerate(e2, &cfg_done)) + { /* this should not happen as the authentication should never have + * succeeded */ + valid = FALSE; + break; + } + if ((uintptr_t)cfg_done->get(cfg_done, + AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_PUBKEY) + { + continue; + } + peer = cfg_done->get(cfg_done, AUTH_RULE_SUBJECT_CERT); + if (!peer) + { + DBG1(DBG_IKE, "no subject certificate found, skipping certificate " + "verification"); + continue; + } + if (!peer->get_validity(peer, NULL, ¬_before, ¬_after)) + { + /* FIXME: theoretically we could find a newer cert with the same + * identity and public key below...but it's not the cert used by + * the peer during the original authentication so... */ + DBG1(DBG_IKE, "peer certificate invalid (valid from %T to %T)", + ¬_before, FALSE, ¬_after, FALSE); + valid = FALSE; + break; + } + key = peer->get_public_key(peer); + if (!key) + { + DBG1(DBG_IKE, "unable to retrieve public key, skipping certificate " + "verification"); + continue; + } + DBG1(DBG_IKE, "verifying peer certificate"); + /* serve received certificates */ + wrapper = auth_cfg_wrapper_create(cfg_done); + lib->credmgr->add_local_set(lib->credmgr, &wrapper->set, FALSE); + certs = lib->credmgr->create_trusted_enumerator(lib->credmgr, + key->get_type(key), peer->get_subject(peer), TRUE); + key->destroy(key); + + found = FALSE; + while (certs->enumerate(certs, &cert, &auth)) + { + if (peer->equals(peer, cert)) + { + cfg_done->add(cfg_done, AUTH_RULE_CERT_VALIDATION_SUSPENDED, + FALSE); + cfg_done->merge(cfg_done, auth, FALSE); + valid = cfg_done->complies(cfg_done, cfg, TRUE); + found = TRUE; + break; + } + } + certs->destroy(certs); + lib->credmgr->remove_local_set(lib->credmgr, &wrapper->set); + wrapper->destroy(wrapper); + if (!found || !valid) + { + valid = FALSE; + break; + } + } + e1->destroy(e1); + e2->destroy(e2); + return valid; +} + /** * Flush the stored authentication round information */ @@ -2750,6 +2852,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, .set_peer_cfg = _set_peer_cfg, .get_auth_cfg = _get_auth_cfg, .create_auth_cfg_enumerator = _create_auth_cfg_enumerator, + .verify_peer_certificate = _verify_peer_certificate, .add_auth_cfg = _add_auth_cfg, .get_proposal = _get_proposal, .set_proposal = _set_proposal, diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index 158a690df..0f47ad31f 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -522,6 +522,14 @@ struct ike_sa_t { enumerator_t* (*create_auth_cfg_enumerator)(ike_sa_t *this, bool local); /** + * Verify the trustchains (validity, revocation) in completed public key + * auth rounds. + * + * @return TRUE if certificates were valid, FALSE otherwise + */ + bool (*verify_peer_certificate)(ike_sa_t *this); + + /** * Get the selected proposal of this IKE_SA. * * @return selected proposal |