Merge branch 'stroke-purge-on-reread'
Remove all previously loaded certificates during "ipsec reread", finally allowing the removal of CA certificates from a running daemon. Fixes #842, #700, #305.
This commit is contained in:
@@ -210,15 +210,18 @@ flushes and rereads all secrets defined in \fIipsec.secrets\fP.
|
||||
.
|
||||
.TP
|
||||
.B "rereadcacerts"
|
||||
reads all certificate files contained in the \fI/etc/ipsec.d/cacerts\fP
|
||||
directory and adds them to the list of Certification Authority (CA)
|
||||
certificates.
|
||||
removes previously loaded CA certificates, reads all certificate files
|
||||
contained in the \fI/etc/ipsec.d/cacerts\fP directory and adds them to the list
|
||||
of Certification Authority (CA) certificates. This does not affect certificates
|
||||
explicitly defined in a
|
||||
.BR ipsec.conf (5)
|
||||
ca section, which may be separately updated using the \fBupdate\fP command.
|
||||
.
|
||||
.TP
|
||||
.B "rereadaacerts"
|
||||
reads all certificate files contained in the \fI/etc/ipsec.d/aacerts\fP
|
||||
directory and adds them to the list of Authorization Authority (AA)
|
||||
certificates.
|
||||
removes previously loaded AA certificates, reads all certificate files
|
||||
contained in the \fI/etc/ipsec.d/aacerts\fP directory and adds them to the list
|
||||
of Authorization Authority (AA) certificates.
|
||||
.
|
||||
.TP
|
||||
.B "rereadocspcerts"
|
||||
|
||||
@@ -119,6 +119,84 @@ static void ca_section_destroy(ca_section_t *this)
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data for the certificate enumerator
|
||||
*/
|
||||
typedef struct {
|
||||
private_stroke_ca_t *this;
|
||||
certificate_type_t cert;
|
||||
key_type_t key;
|
||||
identification_t *id;
|
||||
} cert_data_t;
|
||||
|
||||
/**
|
||||
* destroy cert_data
|
||||
*/
|
||||
static void cert_data_destroy(cert_data_t *data)
|
||||
{
|
||||
data->this->lock->unlock(data->this->lock);
|
||||
free(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* filter function for certs enumerator
|
||||
*/
|
||||
static bool certs_filter(cert_data_t *data, ca_section_t **in,
|
||||
certificate_t **out)
|
||||
{
|
||||
public_key_t *public;
|
||||
certificate_t *cert = (*in)->cert;
|
||||
|
||||
if (data->cert == CERT_ANY || data->cert == cert->get_type(cert))
|
||||
{
|
||||
public = cert->get_public_key(cert);
|
||||
if (public)
|
||||
{
|
||||
if (data->key == KEY_ANY || data->key == public->get_type(public))
|
||||
{
|
||||
if (data->id && public->has_fingerprint(public,
|
||||
data->id->get_encoding(data->id)))
|
||||
{
|
||||
public->destroy(public);
|
||||
*out = cert;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
public->destroy(public);
|
||||
}
|
||||
else if (data->key != KEY_ANY)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
if (data->id == NULL || cert->has_subject(cert, data->id))
|
||||
{
|
||||
*out = cert;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
|
||||
private_stroke_ca_t *this, certificate_type_t cert, key_type_t key,
|
||||
identification_t *id, bool trusted)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
cert_data_t *data;
|
||||
|
||||
INIT(data,
|
||||
.this = this,
|
||||
.cert = cert,
|
||||
.key = key,
|
||||
.id = id,
|
||||
);
|
||||
|
||||
this->lock->read_lock(this->lock);
|
||||
enumerator = this->sections->create_enumerator(this->sections);
|
||||
return enumerator_create_filter(enumerator, (void*)certs_filter, data,
|
||||
(void*)cert_data_destroy);
|
||||
}
|
||||
|
||||
/**
|
||||
* data to pass to create_inner_cdp
|
||||
*/
|
||||
@@ -438,7 +516,7 @@ stroke_ca_t *stroke_ca_create(stroke_cred_t *cred)
|
||||
.public = {
|
||||
.set = {
|
||||
.create_private_enumerator = (void*)return_null,
|
||||
.create_cert_enumerator = (void*)return_null,
|
||||
.create_cert_enumerator = _create_cert_enumerator,
|
||||
.create_shared_enumerator = (void*)return_null,
|
||||
.create_cdp_enumerator = _create_cdp_enumerator,
|
||||
.cache_cert = (void*)nop,
|
||||
@@ -456,4 +534,3 @@ stroke_ca_t *stroke_ca_create(stroke_cred_t *cred)
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
|
||||
|
||||
@@ -70,10 +70,20 @@ struct private_stroke_cred_t {
|
||||
char *secrets_file;
|
||||
|
||||
/**
|
||||
* credentials
|
||||
* credentials: end entity certs, attribute certs, CRLs, etc.
|
||||
*/
|
||||
mem_cred_t *creds;
|
||||
|
||||
/**
|
||||
* CA certificates
|
||||
*/
|
||||
mem_cred_t *cacerts;
|
||||
|
||||
/**
|
||||
* Attribute Authority certificates
|
||||
*/
|
||||
mem_cred_t *aacerts;
|
||||
|
||||
/**
|
||||
* ignore missing CA basic constraint (i.e. treat all certificates in
|
||||
* ipsec.conf ca sections and ipsec.d/cacerts as CA certificates)
|
||||
@@ -231,7 +241,7 @@ METHOD(stroke_cred_t, load_ca, certificate_t*,
|
||||
}
|
||||
DBG1(DBG_CFG, " loaded ca certificate \"%Y\" from '%s'",
|
||||
cert->get_subject(cert), filename);
|
||||
return this->creds->add_cert_ref(this->creds, TRUE, cert);
|
||||
return this->creds->get_cert_ref(this->creds, cert);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -373,134 +383,184 @@ METHOD(stroke_cred_t, load_pubkey, certificate_t*,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a CA certificate from disk
|
||||
*/
|
||||
static void load_x509_ca(private_stroke_cred_t *this, char *file)
|
||||
{
|
||||
certificate_t *cert;
|
||||
|
||||
if (this->force_ca_cert)
|
||||
{ /* treat certificate as CA cert even it has no CA basic constraint */
|
||||
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
|
||||
BUILD_FROM_FILE, file,
|
||||
BUILD_X509_FLAG, X509_CA, BUILD_END);
|
||||
}
|
||||
else
|
||||
{
|
||||
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
|
||||
BUILD_FROM_FILE, file, BUILD_END);
|
||||
}
|
||||
if (cert)
|
||||
{
|
||||
x509_t *x509 = (x509_t*)cert;
|
||||
|
||||
if (!(x509->get_flags(x509) & X509_CA))
|
||||
{
|
||||
DBG1(DBG_CFG, " ca certificate \"%Y\" lacks ca basic constraint, "
|
||||
"discarded", cert->get_subject(cert));
|
||||
cert->destroy(cert);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, " loaded ca certificate \"%Y\" from '%s'",
|
||||
cert->get_subject(cert), file);
|
||||
this->cacerts->add_cert(this->cacerts, TRUE, cert);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, " loading ca certificate from '%s' failed", file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load AA certificate with flags from disk
|
||||
*/
|
||||
static void load_x509_aa(private_stroke_cred_t *this, char *file)
|
||||
{
|
||||
certificate_t *cert;
|
||||
|
||||
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
|
||||
BUILD_FROM_FILE, file,
|
||||
BUILD_X509_FLAG, X509_AA, BUILD_END);
|
||||
if (cert)
|
||||
{
|
||||
DBG1(DBG_CFG, " loaded AA certificate \"%Y\" from '%s'",
|
||||
cert->get_subject(cert), file);
|
||||
this->aacerts->add_cert(this->aacerts, TRUE, cert);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, " loading AA certificate from '%s' failed", file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a certificate with flags from disk
|
||||
*/
|
||||
static void load_x509(private_stroke_cred_t *this, char *file, x509_flag_t flag)
|
||||
{
|
||||
certificate_t *cert;
|
||||
|
||||
/* for all other flags, we add them to the certificate. */
|
||||
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
|
||||
BUILD_FROM_FILE, file,
|
||||
BUILD_X509_FLAG, flag, BUILD_END);
|
||||
if (cert)
|
||||
{
|
||||
DBG1(DBG_CFG, " loaded certificate \"%Y\" from '%s'",
|
||||
cert->get_subject(cert), file);
|
||||
this->creds->add_cert(this->creds, TRUE, cert);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, " loading certificate from '%s' failed", file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a CRL from a file
|
||||
*/
|
||||
static void load_x509_crl(private_stroke_cred_t *this, char *file)
|
||||
{
|
||||
certificate_t *cert;
|
||||
|
||||
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
|
||||
BUILD_FROM_FILE, file, BUILD_END);
|
||||
if (cert)
|
||||
{
|
||||
this->creds->add_crl(this->creds, (crl_t*)cert);
|
||||
DBG1(DBG_CFG, " loaded crl from '%s'", file);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, " loading crl from '%s' failed", file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an attribute certificate from a file
|
||||
*/
|
||||
static void load_x509_ac(private_stroke_cred_t *this, char *file)
|
||||
{
|
||||
certificate_t *cert;
|
||||
|
||||
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC,
|
||||
BUILD_FROM_FILE, file, BUILD_END);
|
||||
if (cert)
|
||||
{
|
||||
DBG1(DBG_CFG, " loaded attribute certificate from '%s'", file);
|
||||
this->creds->add_cert(this->creds, FALSE, cert);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, " loading attribute certificate from '%s' failed", file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* load trusted certificates from a directory
|
||||
*/
|
||||
static void load_certdir(private_stroke_cred_t *this, char *path,
|
||||
certificate_type_t type, x509_flag_t flag)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
struct stat st;
|
||||
char *file;
|
||||
|
||||
enumerator_t *enumerator = enumerator_create_directory(path);
|
||||
|
||||
if (!enumerator)
|
||||
enumerator = enumerator_create_directory(path);
|
||||
if (enumerator)
|
||||
{
|
||||
while (enumerator->enumerate(enumerator, NULL, &file, &st))
|
||||
{
|
||||
if (!S_ISREG(st.st_mode))
|
||||
{
|
||||
/* skip special file */
|
||||
continue;
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
case CERT_X509:
|
||||
if (flag & X509_CA)
|
||||
{
|
||||
load_x509_ca(this, file);
|
||||
}
|
||||
else if (flag & X509_AA)
|
||||
{
|
||||
load_x509_aa(this, file);
|
||||
}
|
||||
else
|
||||
{
|
||||
load_x509(this, file, flag);
|
||||
}
|
||||
break;
|
||||
case CERT_X509_CRL:
|
||||
load_x509_crl(this, file);
|
||||
break;
|
||||
case CERT_X509_AC:
|
||||
load_x509_ac(this, file);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, " reading directory failed");
|
||||
return;
|
||||
}
|
||||
|
||||
while (enumerator->enumerate(enumerator, NULL, &file, &st))
|
||||
{
|
||||
certificate_t *cert;
|
||||
|
||||
if (!S_ISREG(st.st_mode))
|
||||
{
|
||||
/* skip special file */
|
||||
continue;
|
||||
}
|
||||
switch (type)
|
||||
{
|
||||
case CERT_X509:
|
||||
if (flag & X509_CA)
|
||||
{
|
||||
if (this->force_ca_cert)
|
||||
{ /* treat this certificate as CA cert even it has no
|
||||
* CA basic constraint */
|
||||
cert = lib->creds->create(lib->creds,
|
||||
CRED_CERTIFICATE, CERT_X509,
|
||||
BUILD_FROM_FILE, file, BUILD_X509_FLAG,
|
||||
X509_CA, BUILD_END);
|
||||
}
|
||||
else
|
||||
{
|
||||
cert = lib->creds->create(lib->creds,
|
||||
CRED_CERTIFICATE, CERT_X509,
|
||||
BUILD_FROM_FILE, file, BUILD_END);
|
||||
}
|
||||
if (cert)
|
||||
{
|
||||
x509_t *x509 = (x509_t*)cert;
|
||||
|
||||
if (!(x509->get_flags(x509) & X509_CA))
|
||||
{
|
||||
DBG1(DBG_CFG, " ca certificate \"%Y\" lacks "
|
||||
"ca basic constraint, discarded",
|
||||
cert->get_subject(cert));
|
||||
cert->destroy(cert);
|
||||
cert = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, " loaded ca certificate \"%Y\" "
|
||||
"from '%s'", cert->get_subject(cert), file);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, " loading ca certificate from '%s' "
|
||||
"failed", file);
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* for all other flags, we add them to the certificate. */
|
||||
cert = lib->creds->create(lib->creds,
|
||||
CRED_CERTIFICATE, CERT_X509,
|
||||
BUILD_FROM_FILE, file,
|
||||
BUILD_X509_FLAG, flag, BUILD_END);
|
||||
if (cert)
|
||||
{
|
||||
DBG1(DBG_CFG, " loaded certificate \"%Y\" from '%s'",
|
||||
cert->get_subject(cert), file);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, " loading certificate from '%s' "
|
||||
"failed", file);
|
||||
}
|
||||
}
|
||||
if (cert)
|
||||
{
|
||||
this->creds->add_cert(this->creds, TRUE, cert);
|
||||
}
|
||||
break;
|
||||
case CERT_X509_CRL:
|
||||
cert = lib->creds->create(lib->creds,
|
||||
CRED_CERTIFICATE, CERT_X509_CRL,
|
||||
BUILD_FROM_FILE, file,
|
||||
BUILD_END);
|
||||
if (cert)
|
||||
{
|
||||
this->creds->add_crl(this->creds, (crl_t*)cert);
|
||||
DBG1(DBG_CFG, " loaded crl from '%s'", file);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, " loading crl from '%s' failed", file);
|
||||
}
|
||||
break;
|
||||
case CERT_X509_AC:
|
||||
cert = lib->creds->create(lib->creds,
|
||||
CRED_CERTIFICATE, CERT_X509_AC,
|
||||
BUILD_FROM_FILE, file,
|
||||
BUILD_END);
|
||||
if (cert)
|
||||
{
|
||||
this->creds->add_cert(this->creds, FALSE, cert);
|
||||
DBG1(DBG_CFG, " loaded attribute certificate from '%s'",
|
||||
file);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_CFG, " loading attribute certificate from '%s' "
|
||||
"failed", file);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
METHOD(stroke_cred_t, cache_cert, void,
|
||||
@@ -1321,6 +1381,8 @@ METHOD(stroke_cred_t, reread, void,
|
||||
{
|
||||
DBG1(DBG_CFG, "rereading ca certificates from '%s'",
|
||||
CA_CERTIFICATE_DIR);
|
||||
this->cacerts->clear(this->cacerts);
|
||||
lib->credmgr->flush_cache(lib->credmgr, CERT_X509);
|
||||
load_certdir(this, CA_CERTIFICATE_DIR, CERT_X509, X509_CA);
|
||||
}
|
||||
if (msg->reread.flags & REREAD_OCSPCERTS)
|
||||
@@ -1334,6 +1396,8 @@ METHOD(stroke_cred_t, reread, void,
|
||||
{
|
||||
DBG1(DBG_CFG, "rereading aa certificates from '%s'",
|
||||
AA_CERTIFICATE_DIR);
|
||||
this->aacerts->clear(this->aacerts);
|
||||
lib->credmgr->flush_cache(lib->credmgr, CERT_X509);
|
||||
load_certdir(this, AA_CERTIFICATE_DIR, CERT_X509, X509_AA);
|
||||
}
|
||||
if (msg->reread.flags & REREAD_ACERTS)
|
||||
@@ -1359,7 +1423,11 @@ METHOD(stroke_cred_t, add_shared, void,
|
||||
METHOD(stroke_cred_t, destroy, void,
|
||||
private_stroke_cred_t *this)
|
||||
{
|
||||
lib->credmgr->remove_set(lib->credmgr, &this->aacerts->set);
|
||||
lib->credmgr->remove_set(lib->credmgr, &this->cacerts->set);
|
||||
lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
|
||||
this->aacerts->destroy(this->aacerts);
|
||||
this->cacerts->destroy(this->cacerts);
|
||||
this->creds->destroy(this->creds);
|
||||
free(this);
|
||||
}
|
||||
@@ -1392,9 +1460,13 @@ stroke_cred_t *stroke_cred_create()
|
||||
"%s.plugins.stroke.secrets_file", SECRETS_FILE,
|
||||
lib->ns),
|
||||
.creds = mem_cred_create(),
|
||||
.cacerts = mem_cred_create(),
|
||||
.aacerts = mem_cred_create(),
|
||||
);
|
||||
|
||||
lib->credmgr->add_set(lib->credmgr, &this->creds->set);
|
||||
lib->credmgr->add_set(lib->credmgr, &this->cacerts->set);
|
||||
lib->credmgr->add_set(lib->credmgr, &this->aacerts->set);
|
||||
|
||||
this->force_ca_cert = lib->settings->get_bool(lib->settings,
|
||||
"%s.plugins.stroke.ignore_missing_ca_basic_constraint",
|
||||
|
||||
@@ -50,10 +50,13 @@ struct stroke_cred_t {
|
||||
void (*reread)(stroke_cred_t *this, stroke_msg_t *msg, FILE *prompt);
|
||||
|
||||
/**
|
||||
* Load a CA certificate, and serve it through the credential_set.
|
||||
* Load a CA certificate.
|
||||
*
|
||||
* This method does not add the loaded CA certificate to the internal
|
||||
* credentail set, but returns it only.
|
||||
*
|
||||
* @param filename file to load CA cert from
|
||||
* @return reference to loaded certificate, or NULL
|
||||
* @return loaded certificate, or NULL
|
||||
*/
|
||||
certificate_t* (*load_ca)(stroke_cred_t *this, char *filename);
|
||||
|
||||
|
||||
@@ -192,6 +192,24 @@ METHOD(mem_cred_t, add_cert_ref, certificate_t*,
|
||||
return add_cert_internal(this, trusted, cert);
|
||||
}
|
||||
|
||||
METHOD(mem_cred_t, get_cert_ref, certificate_t*,
|
||||
private_mem_cred_t *this, certificate_t *cert)
|
||||
{
|
||||
certificate_t *cached;
|
||||
|
||||
this->lock->write_lock(this->lock);
|
||||
if (this->untrusted->find_first(this->untrusted,
|
||||
(linked_list_match_t)certificate_equals,
|
||||
(void**)&cached, cert) == SUCCESS)
|
||||
{
|
||||
cert->destroy(cert);
|
||||
cert = cached->get_ref(cached);
|
||||
}
|
||||
this->lock->unlock(this->lock);
|
||||
|
||||
return cert;
|
||||
}
|
||||
|
||||
METHOD(mem_cred_t, add_crl, bool,
|
||||
private_mem_cred_t *this, crl_t *crl)
|
||||
{
|
||||
@@ -736,6 +754,7 @@ mem_cred_t *mem_cred_create()
|
||||
},
|
||||
.add_cert = _add_cert,
|
||||
.add_cert_ref = _add_cert_ref,
|
||||
.get_cert_ref = _get_cert_ref,
|
||||
.add_crl = _add_crl,
|
||||
.add_key = _add_key,
|
||||
.add_shared = _add_shared,
|
||||
|
||||
@@ -58,6 +58,18 @@ struct mem_cred_t {
|
||||
certificate_t *(*add_cert_ref)(mem_cred_t *this, bool trusted,
|
||||
certificate_t *cert);
|
||||
|
||||
/**
|
||||
* Get an existing reference to the same certificate.
|
||||
*
|
||||
* Searches for the same certficate in the set, and returns a reference
|
||||
* to it, destroying the passed certificate. If the passed certificate
|
||||
* is not found, it is just returned.
|
||||
*
|
||||
* @param cert certificate to look up
|
||||
* @return the same certificate, potentially different instance
|
||||
*/
|
||||
certificate_t* (*get_cert_ref)(mem_cred_t *this, certificate_t *cert);
|
||||
|
||||
/**
|
||||
* Add an X.509 CRL to the credential set.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user