ike-sa: Add method to verify certificates in completed authentication rounds
This commit is contained in:
@@ -58,6 +58,7 @@
|
|||||||
#include <sa/ikev2/tasks/ike_auth_lifetime.h>
|
#include <sa/ikev2/tasks/ike_auth_lifetime.h>
|
||||||
#include <sa/ikev2/tasks/ike_reauth_complete.h>
|
#include <sa/ikev2/tasks/ike_reauth_complete.h>
|
||||||
#include <sa/ikev2/tasks/ike_redirect.h>
|
#include <sa/ikev2/tasks/ike_redirect.h>
|
||||||
|
#include <credentials/sets/auth_cfg_wrapper.h>
|
||||||
|
|
||||||
#ifdef ME
|
#ifdef ME
|
||||||
#include <sa/ikev2/tasks/ike_me.h>
|
#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);
|
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
|
* 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,
|
.set_peer_cfg = _set_peer_cfg,
|
||||||
.get_auth_cfg = _get_auth_cfg,
|
.get_auth_cfg = _get_auth_cfg,
|
||||||
.create_auth_cfg_enumerator = _create_auth_cfg_enumerator,
|
.create_auth_cfg_enumerator = _create_auth_cfg_enumerator,
|
||||||
|
.verify_peer_certificate = _verify_peer_certificate,
|
||||||
.add_auth_cfg = _add_auth_cfg,
|
.add_auth_cfg = _add_auth_cfg,
|
||||||
.get_proposal = _get_proposal,
|
.get_proposal = _get_proposal,
|
||||||
.set_proposal = _set_proposal,
|
.set_proposal = _set_proposal,
|
||||||
|
|||||||
@@ -521,6 +521,14 @@ struct ike_sa_t {
|
|||||||
*/
|
*/
|
||||||
enumerator_t* (*create_auth_cfg_enumerator)(ike_sa_t *this, bool local);
|
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.
|
* Get the selected proposal of this IKE_SA.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user