systime-fix disables certificate lifetime validation if system time not synced

The system time can be periodically checked. If it gets valid, certificates get
rechecked with the current lifetime. If certificates are invalid, associated
IKE_SAs can be closed or reauthenticated.
This commit is contained in:
Martin Willi 2013-02-19 15:38:28 +01:00
parent 0ed31e7284
commit 295e42a47f
4 changed files with 326 additions and 0 deletions

View File

@ -9,6 +9,7 @@ plugin_LTLIBRARIES = libstrongswan-systime-fix.la
endif
libstrongswan_systime_fix_la_SOURCES = \
systime_fix_validator.h systime_fix_validator.c \
systime_fix_plugin.h systime_fix_plugin.c
libstrongswan_systime_fix_la_LDFLAGS = -module -avoid-version

View File

@ -14,8 +14,20 @@
*/
#include "systime_fix_plugin.h"
#include "systime_fix_validator.h"
#include <daemon.h>
#include <processing/jobs/callback_job.h>
#include <processing/jobs/delete_ike_sa_job.h>
#include <processing/jobs/rekey_ike_sa_job.h>
#include <time.h>
/**
* Defining _XOPEN_SOURCE is difficult with libstrongswan includes,
* declare function explicitly.
*/
char *strptime(const char *s, const char *format, struct tm *tm);
typedef struct private_systime_fix_plugin_t private_systime_fix_plugin_t;
@ -28,6 +40,26 @@ struct private_systime_fix_plugin_t {
* Implements plugin interface
*/
systime_fix_plugin_t public;
/**
* Certificate lifetime validator
*/
systime_fix_validator_t *validator;
/**
* Interval we check for a now-valid system time, in seconds. 0 if disabled
*/
u_int interval;
/**
* Timestamp where we start considering system time valid
*/
time_t threshold;
/**
* Do we trigger reauth or delete when finding expired certificates?
*/
bool reauth;
};
METHOD(plugin_t, get_name, char*,
@ -39,9 +71,155 @@ METHOD(plugin_t, get_name, char*,
METHOD(plugin_t, destroy, void,
private_systime_fix_plugin_t *this)
{
if (this->validator)
{
lib->credmgr->remove_validator(lib->credmgr, &this->validator->validator);
this->validator->destroy(this->validator);
}
free(this);
}
/**
* Check if all certificates associated to an IKE_SA have valid lifetimes
*/
static bool has_invalid_certs(ike_sa_t *ike_sa)
{
enumerator_t *cfgs, *items;
certificate_t *cert;
auth_rule_t type;
auth_cfg_t *auth;
time_t not_before, not_after;
bool valid = TRUE;
cfgs = ike_sa->create_auth_cfg_enumerator(ike_sa, FALSE);
while (valid && cfgs->enumerate(cfgs, &auth))
{
items = auth->create_enumerator(auth);
while (valid && items->enumerate(items, &type, &cert))
{
switch (type)
{
case AUTH_RULE_SUBJECT_CERT:
case AUTH_RULE_IM_CERT:
case AUTH_RULE_CA_CERT:
if (!cert->get_validity(cert, NULL, &not_before, &not_after))
{
DBG1(DBG_CFG, "certificate '%Y' invalid "
"(valid from %T to %T)", cert->get_subject(cert),
&not_before, FALSE, &not_after, FALSE);
valid = FALSE;
}
break;
default:
break;
}
}
items->destroy(items);
}
cfgs->destroy(cfgs);
if (valid)
{
DBG1(DBG_CFG, "all certificates have valid lifetimes");
}
return !valid;
}
/**
* Check system time, reevaluate certificates
*/
static job_requeue_t check_systime(private_systime_fix_plugin_t *this)
{
enumerator_t *enumerator;
ike_sa_t *ike_sa;
char *action;
job_t *job;
if (time(NULL) < this->threshold)
{
DBG2(DBG_CFG, "systime not valid, rechecking in %ds", this->interval);
lib->scheduler->schedule_job(lib->scheduler, (job_t*)
callback_job_create((callback_job_cb_t)check_systime, this,
NULL, NULL), this->interval);
return JOB_REQUEUE_NONE;
}
DBG1(DBG_CFG, "system time got valid, rechecking certificates");
enumerator = charon->ike_sa_manager->create_enumerator(
charon->ike_sa_manager, TRUE);
while (enumerator->enumerate(enumerator, &ike_sa))
{
if (has_invalid_certs(ike_sa))
{
if (this->reauth)
{
action = "reauthenticating";
job = &rekey_ike_sa_job_create(ike_sa->get_id(ike_sa),
TRUE)->job_interface;
}
else
{
action = "deleting";
job = &delete_ike_sa_job_create(ike_sa->get_id(ike_sa),
TRUE)->job_interface;
}
DBG1(DBG_CFG, "%s[%d] has certificates not valid, %s IKE_SA",
ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa),
action);
lib->processor->queue_job(lib->processor, job);
}
}
enumerator->destroy(enumerator);
return JOB_REQUEUE_NONE;
}
/**
* Load cert lifetime validator configuration
*/
static bool load_validator(private_systime_fix_plugin_t *this)
{
struct tm tm = {
.tm_mday = 1,
};
char *str, *fmt;
fmt = lib->settings->get_str(lib->settings,
"%s.plugins.%s.threshold_format", "%Y", charon->name, get_name(this));
str = lib->settings->get_str(lib->settings,
"%s.plugins.%s.threshold", NULL, charon->name, get_name(this));
if (!str)
{
DBG1(DBG_CFG, "no threshold configured for %s, disabled",
get_name(this));
return FALSE;
}
if (strptime(str, fmt, &tm) == NULL)
{
DBG1(DBG_CFG, "threshold for %s invalid, disabled", get_name(this));
return FALSE;
}
this->threshold = mktime(&tm);
if (this->threshold == -1)
{
DBG1(DBG_CFG, "converting threshold for %s failed, disabled",
get_name(this));
return FALSE;
}
if (time(NULL) >= this->threshold)
{
DBG1(DBG_CFG, "system time looks good, disabling %s", get_name(this));
return FALSE;
}
DBG1(DBG_CFG, "enabling %s, threshold: %s", get_name(this), asctime(&tm));
this->validator = systime_fix_validator_create(this->threshold);
lib->credmgr->add_validator(lib->credmgr, &this->validator->validator);
return TRUE;
}
/**
* Plugin constructor
*/
@ -57,7 +235,22 @@ plugin_t *systime_fix_plugin_create()
.destroy = _destroy,
},
},
.interval = lib->settings->get_int(lib->settings,
"%s.plugins.%s.interval", 0, charon->name, get_name(this)),
.reauth = lib->settings->get_bool(lib->settings,
"%s.plugins.%s.reauth", FALSE, charon->name, get_name(this)),
);
if (load_validator(this))
{
if (this->interval != 0)
{
DBG1(DBG_CFG, "starting systime check, interval: %ds",
this->interval);
lib->scheduler->schedule_job(lib->scheduler, (job_t*)
callback_job_create((callback_job_cb_t)check_systime, this,
NULL, NULL), this->interval);
}
}
return &this->public.plugin;
}

View File

@ -0,0 +1,83 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "systime_fix_validator.h"
#include <errno.h>
#include <time.h>
#include <daemon.h>
typedef struct private_systime_fix_validator_t private_systime_fix_validator_t;
/**
* Private data of an systime_fix_validator_t object.
*/
struct private_systime_fix_validator_t {
/**
* Public systime_fix_validator_t interface.
*/
systime_fix_validator_t public;
/**
* Timestamp where we start to consider system time valid
*/
time_t threshold;
};
METHOD(cert_validator_t, check_lifetime, status_t,
private_systime_fix_validator_t *this, certificate_t *cert,
int pathlen, bool anchor, auth_cfg_t *auth)
{
if (time(NULL) < this->threshold)
{
/* our system time seems to be invalid, accept certificate */
if (pathlen)
{ /* report only once per validated chain */
DBG1(DBG_CFG, "system time out of sync, skipping certificate "
"lifetime check");
}
return SUCCESS;
}
/* validate this certificate normally */
return NEED_MORE;
}
METHOD(systime_fix_validator_t, destroy, void,
private_systime_fix_validator_t *this)
{
free(this);
}
/**
* See header
*/
systime_fix_validator_t *systime_fix_validator_create(time_t threshold)
{
private_systime_fix_validator_t *this;
INIT(this,
.public = {
.validator = {
.check_lifetime = _check_lifetime,
},
.destroy = _destroy,
},
.threshold = threshold,
);
return &this->public;
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2013 Martin Willi
* Copyright (C) 2013 revosec AG
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup systime_fix_validator systime_fix_validator
* @{ @ingroup systime_fix
*/
#ifndef SYSTIME_FIX_VALIDATOR_H_
#define SYSTIME_FIX_VALIDATOR_H_
#include <credentials/cert_validator.h>
typedef struct systime_fix_validator_t systime_fix_validator_t;
/**
* Validator that accepts cert lifetimes if system time is out of sync.
*/
struct systime_fix_validator_t {
/**
* Implements cert_validator_t interface.
*/
cert_validator_t validator;
/**
* Destroy a systime_fix_validator_t.
*/
void (*destroy)(systime_fix_validator_t *this);
};
/**
* Create a systime_fix_validator instance.
*/
systime_fix_validator_t *systime_fix_validator_create();
#endif /** SYSTIME_FIX_VALIDATOR_H_ @}*/