Merge branch 'vici-ca-certs'
These changes store all CA certificates in vici_authority_t, which avoids issues with unloading authority sections or clearing credentials. Closes strongswan/strongswan#172.
This commit is contained in:
@@ -175,46 +175,15 @@ CALLBACK(certs_filter, bool,
|
|||||||
cert_data_t *data, enumerator_t *orig, va_list args)
|
cert_data_t *data, enumerator_t *orig, va_list args)
|
||||||
{
|
{
|
||||||
ca_cert_t *cacert;
|
ca_cert_t *cacert;
|
||||||
public_key_t *public;
|
|
||||||
certificate_t **out;
|
certificate_t **out;
|
||||||
|
|
||||||
VA_ARGS_VGET(args, out);
|
VA_ARGS_VGET(args, out);
|
||||||
|
|
||||||
while (orig->enumerate(orig, &cacert))
|
while (orig->enumerate(orig, &cacert))
|
||||||
{
|
{
|
||||||
certificate_t *cert = cacert->cert;
|
if (certificate_matches(cacert->cert, data->cert, data->key, data->id))
|
||||||
|
|
||||||
if (data->cert != CERT_ANY && data->cert != cert->get_type(cert))
|
|
||||||
{
|
{
|
||||||
continue;
|
*out = cacert->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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
public->destroy(public);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
public->destroy(public);
|
|
||||||
}
|
|
||||||
else if (data->key != KEY_ANY)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!data->id || cert->has_subject(cert, data->id))
|
|
||||||
{
|
|
||||||
*out = cert;
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2016-2019 Tobias Brunner
|
* Copyright (C) 2016-2020 Tobias Brunner
|
||||||
* Copyright (C) 2015 Andreas Steffen
|
* Copyright (C) 2015 Andreas Steffen
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
@@ -44,15 +44,15 @@ struct private_vici_authority_t {
|
|||||||
vici_dispatcher_t *dispatcher;
|
vici_dispatcher_t *dispatcher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* credential backend managed by VICI used for our ca certificates
|
* List of certification authorities (authority_t*)
|
||||||
*/
|
|
||||||
vici_cred_t *cred;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of certification authorities
|
|
||||||
*/
|
*/
|
||||||
linked_list_t *authorities;
|
linked_list_t *authorities;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of CA certificates (ca_cert_t*)
|
||||||
|
*/
|
||||||
|
linked_list_t *certs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rwlock to lock access to certification authorities
|
* rwlock to lock access to certification authorities
|
||||||
*/
|
*/
|
||||||
@@ -109,10 +109,8 @@ static authority_t *authority_create(char *name)
|
|||||||
return authority;
|
return authority;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
CALLBACK(authority_destroy, void,
|
||||||
* destroy a certification authority
|
authority_t *this)
|
||||||
*/
|
|
||||||
static void authority_destroy(authority_t *this)
|
|
||||||
{
|
{
|
||||||
this->crl_uris->destroy_function(this->crl_uris, free);
|
this->crl_uris->destroy_function(this->crl_uris, free);
|
||||||
this->ocsp_uris->destroy_function(this->ocsp_uris, free);
|
this->ocsp_uris->destroy_function(this->ocsp_uris, free);
|
||||||
@@ -122,6 +120,108 @@ static void authority_destroy(authority_t *this)
|
|||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct ca_cert_t ca_cert_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loaded CA certificate.
|
||||||
|
*/
|
||||||
|
struct ca_cert_t {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to certificate.
|
||||||
|
*/
|
||||||
|
certificate_t *cert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of authority sections referring to this certificate.
|
||||||
|
*/
|
||||||
|
u_int count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TRUE if this certificate was (also) added externally.
|
||||||
|
*/
|
||||||
|
bool external;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy a CA certificate entry
|
||||||
|
*/
|
||||||
|
CALLBACK(ca_cert_destroy, void,
|
||||||
|
ca_cert_t *this)
|
||||||
|
{
|
||||||
|
this->cert->destroy(this->cert);
|
||||||
|
free(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
CALLBACK(match_cert, bool,
|
||||||
|
ca_cert_t *item, va_list args)
|
||||||
|
{
|
||||||
|
certificate_t *cert;
|
||||||
|
|
||||||
|
VA_ARGS_VGET(args, cert);
|
||||||
|
return cert->equals(cert, item->cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a CA certificate to the local store
|
||||||
|
*/
|
||||||
|
static certificate_t *add_cert_internal(private_vici_authority_t *this,
|
||||||
|
certificate_t *cert, bool external)
|
||||||
|
{
|
||||||
|
ca_cert_t *found;
|
||||||
|
|
||||||
|
if (this->certs->find_first(this->certs, match_cert, (void**)&found, cert))
|
||||||
|
{
|
||||||
|
cert->destroy(cert);
|
||||||
|
cert = found->cert->get_ref(found->cert);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
INIT(found,
|
||||||
|
.cert = cert->get_ref(cert)
|
||||||
|
);
|
||||||
|
this->certs->insert_first(this->certs, found);
|
||||||
|
}
|
||||||
|
if (external)
|
||||||
|
{
|
||||||
|
found->external = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
found->count++;
|
||||||
|
}
|
||||||
|
return cert;
|
||||||
|
}
|
||||||
|
|
||||||
|
CALLBACK(remove_external_certs, bool,
|
||||||
|
ca_cert_t *item, void *unused)
|
||||||
|
{
|
||||||
|
if (item->external)
|
||||||
|
{
|
||||||
|
item->external = FALSE;
|
||||||
|
|
||||||
|
if (!item->count)
|
||||||
|
{
|
||||||
|
ca_cert_destroy(item);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
CALLBACK2(remove_cert, bool,
|
||||||
|
ca_cert_t *item, certificate_t *cert)
|
||||||
|
{
|
||||||
|
if (cert == item->cert)
|
||||||
|
{
|
||||||
|
if (--item->count == 0 && !item->external)
|
||||||
|
{
|
||||||
|
ca_cert_destroy(item);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a (error) reply message
|
* Create a (error) reply message
|
||||||
@@ -379,7 +479,6 @@ CALLBACK(authority_sn, bool,
|
|||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
linked_list_t *authorities;
|
linked_list_t *authorities;
|
||||||
authority_t *authority;
|
authority_t *authority;
|
||||||
vici_cred_t *cred;
|
|
||||||
load_data_t *data;
|
load_data_t *data;
|
||||||
chunk_t handle;
|
chunk_t handle;
|
||||||
|
|
||||||
@@ -437,6 +536,9 @@ CALLBACK(authority_sn, bool,
|
|||||||
|
|
||||||
request->this->lock->write_lock(request->this->lock);
|
request->this->lock->write_lock(request->this->lock);
|
||||||
|
|
||||||
|
data->authority->cert = add_cert_internal(request->this,
|
||||||
|
data->authority->cert, FALSE);
|
||||||
|
|
||||||
authorities = request->this->authorities;
|
authorities = request->this->authorities;
|
||||||
enumerator = authorities->create_enumerator(authorities);
|
enumerator = authorities->create_enumerator(authorities);
|
||||||
while (enumerator->enumerate(enumerator, &authority))
|
while (enumerator->enumerate(enumerator, &authority))
|
||||||
@@ -452,11 +554,8 @@ CALLBACK(authority_sn, bool,
|
|||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
authorities->insert_last(authorities, data->authority);
|
authorities->insert_last(authorities, data->authority);
|
||||||
|
|
||||||
cred = request->this->cred;
|
|
||||||
data->authority->cert = cred->add_cert(cred, data->authority->cert);
|
|
||||||
data->authority = NULL;
|
|
||||||
|
|
||||||
request->this->lock->unlock(request->this->lock);
|
request->this->lock->unlock(request->this->lock);
|
||||||
|
data->authority = NULL;
|
||||||
free_load_data(data);
|
free_load_data(data);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@@ -501,6 +600,7 @@ CALLBACK(unload_authority, vici_message_t*,
|
|||||||
if (streq(authority->name, authority_name))
|
if (streq(authority->name, authority_name))
|
||||||
{
|
{
|
||||||
this->authorities->remove_at(this->authorities, enumerator);
|
this->authorities->remove_at(this->authorities, enumerator);
|
||||||
|
this->certs->remove(this->certs, authority->cert, remove_cert);
|
||||||
authority_destroy(authority);
|
authority_destroy(authority);
|
||||||
found = TRUE;
|
found = TRUE;
|
||||||
break;
|
break;
|
||||||
@@ -513,6 +613,7 @@ CALLBACK(unload_authority, vici_message_t*,
|
|||||||
{
|
{
|
||||||
return create_reply("unload: authority '%s' not found", authority_name);
|
return create_reply("unload: authority '%s' not found", authority_name);
|
||||||
}
|
}
|
||||||
|
lib->credmgr->flush_cache(lib->credmgr, CERT_ANY);
|
||||||
return create_reply(NULL);
|
return create_reply(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -627,27 +728,63 @@ static void manage_commands(private_vici_authority_t *this, bool reg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* data to pass to create_inner_cdp
|
* Data for the certificate and CDP enumerator
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
private_vici_authority_t *this;
|
private_vici_authority_t *this;
|
||||||
certificate_type_t type;
|
certificate_type_t type;
|
||||||
|
key_type_t key;
|
||||||
identification_t *id;
|
identification_t *id;
|
||||||
} cdp_data_t;
|
} cert_data_t;
|
||||||
|
|
||||||
/**
|
CALLBACK(cert_data_destroy, void,
|
||||||
* destroy cdp enumerator data and unlock list
|
cert_data_t *data)
|
||||||
*/
|
|
||||||
static void cdp_data_destroy(cdp_data_t *data)
|
|
||||||
{
|
{
|
||||||
data->this->lock->unlock(data->this->lock);
|
data->this->lock->unlock(data->this->lock);
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
CALLBACK(certs_filter, bool,
|
||||||
* inner enumerator constructor for CDP URIs
|
cert_data_t *data, enumerator_t *orig, va_list args)
|
||||||
*/
|
{
|
||||||
static enumerator_t *create_inner_cdp(authority_t *authority, cdp_data_t *data)
|
ca_cert_t *ca;
|
||||||
|
certificate_t **out;
|
||||||
|
|
||||||
|
VA_ARGS_VGET(args, out);
|
||||||
|
|
||||||
|
while (orig->enumerate(orig, &ca))
|
||||||
|
{
|
||||||
|
if (certificate_matches(ca->cert, data->type, data->key, data->id))
|
||||||
|
{
|
||||||
|
*out = ca->cert;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
|
||||||
|
private_vici_authority_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,
|
||||||
|
.type = cert,
|
||||||
|
.key = key,
|
||||||
|
.id = id,
|
||||||
|
);
|
||||||
|
|
||||||
|
this->lock->read_lock(this->lock);
|
||||||
|
enumerator = this->certs->create_enumerator(this->certs);
|
||||||
|
return enumerator_create_filter(enumerator, certs_filter, data,
|
||||||
|
cert_data_destroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
CALLBACK(create_inner_cdp, enumerator_t*,
|
||||||
|
authority_t *authority, cert_data_t *data)
|
||||||
{
|
{
|
||||||
public_key_t *public;
|
public_key_t *public;
|
||||||
enumerator_t *enumerator = NULL;
|
enumerator_t *enumerator = NULL;
|
||||||
@@ -671,7 +808,8 @@ static enumerator_t *create_inner_cdp(authority_t *authority, cdp_data_t *data)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (public->has_fingerprint(public, data->id->get_encoding(data->id)))
|
if (public->has_fingerprint(public,
|
||||||
|
data->id->get_encoding(data->id)))
|
||||||
{
|
{
|
||||||
enumerator = list->create_enumerator(list);
|
enumerator = list->create_enumerator(list);
|
||||||
}
|
}
|
||||||
@@ -681,11 +819,8 @@ static enumerator_t *create_inner_cdp(authority_t *authority, cdp_data_t *data)
|
|||||||
return enumerator;
|
return enumerator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
CALLBACK(create_inner_cdp_hashandurl, enumerator_t*,
|
||||||
* inner enumerator constructor for "Hash and URL"
|
authority_t *authority, cert_data_t *data)
|
||||||
*/
|
|
||||||
static enumerator_t *create_inner_cdp_hashandurl(authority_t *authority,
|
|
||||||
cdp_data_t *data)
|
|
||||||
{
|
{
|
||||||
enumerator_t *enumerator = NULL;
|
enumerator_t *enumerator = NULL;
|
||||||
|
|
||||||
@@ -694,7 +829,8 @@ static enumerator_t *create_inner_cdp_hashandurl(authority_t *authority,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authority->cert->has_subject(authority->cert, data->id) != ID_MATCH_NONE)
|
if (authority->cert->has_subject(authority->cert,
|
||||||
|
data->id) != ID_MATCH_NONE)
|
||||||
{
|
{
|
||||||
enumerator = enumerator_create_single(strdup(authority->cert_uri_base),
|
enumerator = enumerator_create_single(strdup(authority->cert_uri_base),
|
||||||
free);
|
free);
|
||||||
@@ -706,7 +842,7 @@ METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*,
|
|||||||
private_vici_authority_t *this, certificate_type_t type,
|
private_vici_authority_t *this, certificate_type_t type,
|
||||||
identification_t *id)
|
identification_t *id)
|
||||||
{
|
{
|
||||||
cdp_data_t *data;
|
cert_data_t *data;
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{ /* we serve CRLs, OCSP responders and URLs for "Hash and URL" */
|
{ /* we serve CRLs, OCSP responders and URLs for "Hash and URL" */
|
||||||
@@ -718,17 +854,35 @@ METHOD(credential_set_t, create_cdp_enumerator, enumerator_t*,
|
|||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
data = malloc_thing(cdp_data_t);
|
|
||||||
data->this = this;
|
INIT(data,
|
||||||
data->type = type;
|
.this = this,
|
||||||
data->id = id;
|
.type = type,
|
||||||
|
.id = id,
|
||||||
|
);
|
||||||
|
|
||||||
this->lock->read_lock(this->lock);
|
this->lock->read_lock(this->lock);
|
||||||
|
|
||||||
return enumerator_create_nested(
|
return enumerator_create_nested(
|
||||||
this->authorities->create_enumerator(this->authorities),
|
this->authorities->create_enumerator(this->authorities),
|
||||||
(type == CERT_X509) ? (void*)create_inner_cdp_hashandurl :
|
(type == CERT_X509) ? (void*)create_inner_cdp_hashandurl :
|
||||||
(void*)create_inner_cdp, data, (void*)cdp_data_destroy);
|
(void*)create_inner_cdp, data, cert_data_destroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(vici_authority_t, add_ca_cert, certificate_t*,
|
||||||
|
private_vici_authority_t *this, certificate_t *cert)
|
||||||
|
{
|
||||||
|
this->lock->write_lock(this->lock);
|
||||||
|
cert = add_cert_internal(this, cert, TRUE);
|
||||||
|
this->lock->unlock(this->lock);
|
||||||
|
return cert;
|
||||||
|
}
|
||||||
|
|
||||||
|
METHOD(vici_authority_t, clear_ca_certs, void,
|
||||||
|
private_vici_authority_t *this)
|
||||||
|
{
|
||||||
|
this->lock->write_lock(this->lock);
|
||||||
|
this->certs->remove(this->certs, NULL, remove_external_certs);
|
||||||
|
this->lock->unlock(this->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(vici_authority_t, destroy, void,
|
METHOD(vici_authority_t, destroy, void,
|
||||||
@@ -738,6 +892,7 @@ METHOD(vici_authority_t, destroy, void,
|
|||||||
|
|
||||||
this->authorities->destroy_function(this->authorities,
|
this->authorities->destroy_function(this->authorities,
|
||||||
(void*)authority_destroy);
|
(void*)authority_destroy);
|
||||||
|
this->certs->destroy_function(this->certs, ca_cert_destroy);
|
||||||
this->lock->destroy(this->lock);
|
this->lock->destroy(this->lock);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
@@ -745,8 +900,7 @@ METHOD(vici_authority_t, destroy, void,
|
|||||||
/**
|
/**
|
||||||
* See header
|
* See header
|
||||||
*/
|
*/
|
||||||
vici_authority_t *vici_authority_create(vici_dispatcher_t *dispatcher,
|
vici_authority_t *vici_authority_create(vici_dispatcher_t *dispatcher)
|
||||||
vici_cred_t *cred)
|
|
||||||
{
|
{
|
||||||
private_vici_authority_t *this;
|
private_vici_authority_t *this;
|
||||||
|
|
||||||
@@ -754,16 +908,18 @@ vici_authority_t *vici_authority_create(vici_dispatcher_t *dispatcher,
|
|||||||
.public = {
|
.public = {
|
||||||
.set = {
|
.set = {
|
||||||
.create_private_enumerator = (void*)return_null,
|
.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_shared_enumerator = (void*)return_null,
|
||||||
.create_cdp_enumerator = _create_cdp_enumerator,
|
.create_cdp_enumerator = _create_cdp_enumerator,
|
||||||
.cache_cert = (void*)nop,
|
.cache_cert = (void*)nop,
|
||||||
},
|
},
|
||||||
|
.add_ca_cert = _add_ca_cert,
|
||||||
|
.clear_ca_certs = _clear_ca_certs,
|
||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
.dispatcher = dispatcher,
|
.dispatcher = dispatcher,
|
||||||
.cred = cred,
|
|
||||||
.authorities = linked_list_create(),
|
.authorities = linked_list_create(),
|
||||||
|
.certs = linked_list_create(),
|
||||||
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
|
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2020 Tobias Brunner
|
||||||
* Copyright (C) 2015 Andreas Steffen
|
* Copyright (C) 2015 Andreas Steffen
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
@@ -22,7 +23,6 @@
|
|||||||
#define VICI_AUTHORITY_H_
|
#define VICI_AUTHORITY_H_
|
||||||
|
|
||||||
#include "vici_dispatcher.h"
|
#include "vici_dispatcher.h"
|
||||||
#include "vici_cred.h"
|
|
||||||
|
|
||||||
typedef struct vici_authority_t vici_authority_t;
|
typedef struct vici_authority_t vici_authority_t;
|
||||||
|
|
||||||
@@ -36,6 +36,20 @@ struct vici_authority_t {
|
|||||||
*/
|
*/
|
||||||
credential_set_t set;
|
credential_set_t set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a CA certificate and return a reference if it is already stored,
|
||||||
|
* otherwise returns the same certificate.
|
||||||
|
*
|
||||||
|
* @param cert certificate to check
|
||||||
|
* @return reference to stored CA certificate, or original
|
||||||
|
*/
|
||||||
|
certificate_t *(*add_ca_cert)(vici_authority_t *this, certificate_t *cert);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove CA certificates added via add_ca_cert().
|
||||||
|
*/
|
||||||
|
void (*clear_ca_certs)(vici_authority_t *this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy a vici_authority_t.
|
* Destroy a vici_authority_t.
|
||||||
*/
|
*/
|
||||||
@@ -46,10 +60,8 @@ struct vici_authority_t {
|
|||||||
* Create a vici_authority instance.
|
* Create a vici_authority instance.
|
||||||
*
|
*
|
||||||
* @param dispatcher dispatcher to receive requests from
|
* @param dispatcher dispatcher to receive requests from
|
||||||
* @param cred in-memory credential backend managed by VICI
|
|
||||||
* @return authority backend
|
* @return authority backend
|
||||||
*/
|
*/
|
||||||
vici_authority_t *vici_authority_create(vici_dispatcher_t *dispatcher,
|
vici_authority_t *vici_authority_create(vici_dispatcher_t *dispatcher);
|
||||||
vici_cred_t *cred);
|
|
||||||
|
|
||||||
#endif /** VICI_AUTHORITY_H_ @}*/
|
#endif /** VICI_AUTHORITY_H_ @}*/
|
||||||
|
|||||||
@@ -1444,10 +1444,19 @@ CALLBACK(parse_cert_policy, bool,
|
|||||||
*/
|
*/
|
||||||
static bool add_cert(auth_data_t *auth, auth_rule_t rule, certificate_t *cert)
|
static bool add_cert(auth_data_t *auth, auth_rule_t rule, certificate_t *cert)
|
||||||
{
|
{
|
||||||
|
vici_authority_t *authority;
|
||||||
vici_cred_t *cred;
|
vici_cred_t *cred;
|
||||||
|
|
||||||
cred = auth->request->this->cred;
|
if (rule == AUTH_RULE_CA_CERT)
|
||||||
cert = cred->add_cert(cred, cert);
|
{
|
||||||
|
authority = auth->request->this->authority;
|
||||||
|
cert = authority->add_ca_cert(authority, cert);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cred = auth->request->this->cred;
|
||||||
|
cert = cred->add_cert(cred, cert);
|
||||||
|
}
|
||||||
auth->cfg->add(auth->cfg, rule, cert);
|
auth->cfg->add(auth->cfg, rule, cert);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -1492,17 +1501,13 @@ CALLBACK(parse_cacerts, bool,
|
|||||||
CALLBACK(parse_pubkeys, bool,
|
CALLBACK(parse_pubkeys, bool,
|
||||||
auth_data_t *auth, chunk_t v)
|
auth_data_t *auth, chunk_t v)
|
||||||
{
|
{
|
||||||
vici_cred_t *cred;
|
|
||||||
certificate_t *cert;
|
certificate_t *cert;
|
||||||
|
|
||||||
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY,
|
cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY,
|
||||||
BUILD_BLOB_PEM, v, BUILD_END);
|
BUILD_BLOB_PEM, v, BUILD_END);
|
||||||
if (cert)
|
if (cert)
|
||||||
{
|
{
|
||||||
cred = auth->request->this->cred;
|
return add_cert(auth, AUTH_RULE_SUBJECT_CERT, cert);
|
||||||
cert = cred->add_cert(cred, cert);
|
|
||||||
auth->cfg->add(auth->cfg, AUTH_RULE_SUBJECT_CERT, cert);
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,11 @@ struct private_vici_cred_t {
|
|||||||
*/
|
*/
|
||||||
vici_dispatcher_t *dispatcher;
|
vici_dispatcher_t *dispatcher;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CA certificate store
|
||||||
|
*/
|
||||||
|
vici_authority_t *authority;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* credentials
|
* credentials
|
||||||
*/
|
*/
|
||||||
@@ -135,7 +140,6 @@ CALLBACK(load_cert, vici_message_t*,
|
|||||||
x509_flag_t ext_flag, flag = X509_NONE;
|
x509_flag_t ext_flag, flag = X509_NONE;
|
||||||
x509_t *x509;
|
x509_t *x509;
|
||||||
chunk_t data;
|
chunk_t data;
|
||||||
bool trusted = TRUE;
|
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
str = message->get_str(message, NULL, "type");
|
str = message->get_str(message, NULL, "type");
|
||||||
@@ -179,26 +183,31 @@ CALLBACK(load_cert, vici_message_t*,
|
|||||||
}
|
}
|
||||||
DBG1(DBG_CFG, "loaded certificate '%Y'", cert->get_subject(cert));
|
DBG1(DBG_CFG, "loaded certificate '%Y'", cert->get_subject(cert));
|
||||||
|
|
||||||
/* check if CA certificate has CA basic constraint set */
|
if (type == CERT_X509)
|
||||||
if (flag & X509_CA)
|
|
||||||
{
|
{
|
||||||
char err_msg[] = "ca certificate lacks CA basic constraint, rejected";
|
|
||||||
x509 = (x509_t*)cert;
|
x509 = (x509_t*)cert;
|
||||||
|
if (x509->get_flags(x509) & X509_CA)
|
||||||
if (!(x509->get_flags(x509) & X509_CA))
|
|
||||||
{
|
{
|
||||||
|
cert = this->authority->add_ca_cert(this->authority, cert);
|
||||||
cert->destroy(cert);
|
cert->destroy(cert);
|
||||||
DBG1(DBG_CFG, " %s", err_msg);
|
return create_reply(NULL);
|
||||||
return create_reply(err_msg);
|
}
|
||||||
|
else if (flag & X509_CA)
|
||||||
|
{
|
||||||
|
char msg[] = "ca certificate lacks CA basic constraint, rejected";
|
||||||
|
cert->destroy(cert);
|
||||||
|
DBG1(DBG_CFG, " %s", msg);
|
||||||
|
return create_reply(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == CERT_X509_CRL)
|
if (type == CERT_X509_CRL)
|
||||||
{
|
{
|
||||||
this->creds->add_crl(this->creds, (crl_t*)cert);
|
this->creds->add_crl(this->creds, (crl_t*)cert);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this->creds->add_cert(this->creds, trusted, cert);
|
this->creds->add_cert(this->creds, type != CERT_X509_AC, cert);
|
||||||
}
|
}
|
||||||
return create_reply(NULL);
|
return create_reply(NULL);
|
||||||
}
|
}
|
||||||
@@ -536,6 +545,7 @@ CALLBACK(clear_creds, vici_message_t*,
|
|||||||
private_vici_cred_t *this, char *name, u_int id, vici_message_t *message)
|
private_vici_cred_t *this, char *name, u_int id, vici_message_t *message)
|
||||||
{
|
{
|
||||||
this->creds->clear(this->creds);
|
this->creds->clear(this->creds);
|
||||||
|
this->authority->clear_ca_certs(this->authority);
|
||||||
lib->credmgr->flush_cache(lib->credmgr, CERT_ANY);
|
lib->credmgr->flush_cache(lib->credmgr, CERT_ANY);
|
||||||
|
|
||||||
return create_reply(NULL);
|
return create_reply(NULL);
|
||||||
@@ -604,7 +614,8 @@ METHOD(vici_cred_t, destroy, void,
|
|||||||
/**
|
/**
|
||||||
* See header
|
* See header
|
||||||
*/
|
*/
|
||||||
vici_cred_t *vici_cred_create(vici_dispatcher_t *dispatcher)
|
vici_cred_t *vici_cred_create(vici_dispatcher_t *dispatcher,
|
||||||
|
vici_authority_t *authority)
|
||||||
{
|
{
|
||||||
private_vici_cred_t *this;
|
private_vici_cred_t *this;
|
||||||
|
|
||||||
@@ -621,6 +632,7 @@ vici_cred_t *vici_cred_create(vici_dispatcher_t *dispatcher)
|
|||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
.dispatcher = dispatcher,
|
.dispatcher = dispatcher,
|
||||||
|
.authority = authority,
|
||||||
.creds = mem_cred_create(),
|
.creds = mem_cred_create(),
|
||||||
.pins = mem_cred_create(),
|
.pins = mem_cred_create(),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#define VICI_CRED_H_
|
#define VICI_CRED_H_
|
||||||
|
|
||||||
#include "vici_dispatcher.h"
|
#include "vici_dispatcher.h"
|
||||||
|
#include "vici_authority.h"
|
||||||
|
|
||||||
#include <credentials/credential_set.h>
|
#include <credentials/credential_set.h>
|
||||||
|
|
||||||
@@ -58,8 +59,10 @@ struct vici_cred_t {
|
|||||||
* Create a vici_cred instance.
|
* Create a vici_cred instance.
|
||||||
*
|
*
|
||||||
* @param dispatcher dispatcher to receive requests from
|
* @param dispatcher dispatcher to receive requests from
|
||||||
|
* @param authority CA certificate storage
|
||||||
* @return credential backend
|
* @return credential backend
|
||||||
*/
|
*/
|
||||||
vici_cred_t *vici_cred_create(vici_dispatcher_t *dispatcher);
|
vici_cred_t *vici_cred_create(vici_dispatcher_t *dispatcher,
|
||||||
|
vici_authority_t *authority);
|
||||||
|
|
||||||
#endif /** VICI_CRED_H_ @}*/
|
#endif /** VICI_CRED_H_ @}*/
|
||||||
|
|||||||
@@ -127,9 +127,8 @@ static bool register_vici(private_vici_plugin_t *this,
|
|||||||
{
|
{
|
||||||
this->query = vici_query_create(this->dispatcher);
|
this->query = vici_query_create(this->dispatcher);
|
||||||
this->control = vici_control_create(this->dispatcher);
|
this->control = vici_control_create(this->dispatcher);
|
||||||
this->cred = vici_cred_create(this->dispatcher);
|
this->authority = vici_authority_create(this->dispatcher);
|
||||||
this->authority = vici_authority_create(this->dispatcher,
|
this->cred = vici_cred_create(this->dispatcher, this->authority);
|
||||||
this->cred);
|
|
||||||
lib->credmgr->add_set(lib->credmgr, &this->cred->set);
|
lib->credmgr->add_set(lib->credmgr, &this->cred->set);
|
||||||
lib->credmgr->add_set(lib->credmgr, &this->authority->set);
|
lib->credmgr->add_set(lib->credmgr, &this->authority->set);
|
||||||
this->config = vici_config_create(this->dispatcher, this->authority,
|
this->config = vici_config_create(this->dispatcher, this->authority,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2020 Tobias Brunner
|
||||||
* Copyright (C) 2007 Martin Willi
|
* Copyright (C) 2007 Martin Willi
|
||||||
* Copyright (C) 2015 Andreas Steffen
|
* Copyright (C) 2015 Andreas Steffen
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
@@ -61,3 +62,40 @@ bool certificate_is_newer(certificate_t *this, certificate_t *other)
|
|||||||
type, &that_update, FALSE, newer ? "replaced" : "retained");
|
type, &that_update, FALSE, newer ? "replaced" : "retained");
|
||||||
return newer;
|
return newer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Described in header
|
||||||
|
*/
|
||||||
|
bool certificate_matches(certificate_t *cert, certificate_type_t type,
|
||||||
|
key_type_t key, identification_t *id)
|
||||||
|
{
|
||||||
|
public_key_t *public;
|
||||||
|
|
||||||
|
if (type != CERT_ANY && type != cert->get_type(cert))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
public = cert->get_public_key(cert);
|
||||||
|
if (public)
|
||||||
|
{
|
||||||
|
if (key == KEY_ANY || key == public->get_type(public))
|
||||||
|
{
|
||||||
|
if (id && public->has_fingerprint(public, id->get_encoding(id)))
|
||||||
|
{
|
||||||
|
public->destroy(public);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
public->destroy(public);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
public->destroy(public);
|
||||||
|
}
|
||||||
|
else if (key != KEY_ANY)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return !id || cert->has_subject(cert, id);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2020 Tobias Brunner
|
||||||
* Copyright (C) 2007-2008 Martin Willi
|
* Copyright (C) 2007-2008 Martin Willi
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
@@ -204,4 +205,18 @@ struct certificate_t {
|
|||||||
*/
|
*/
|
||||||
bool certificate_is_newer(certificate_t *cert, certificate_t *other);
|
bool certificate_is_newer(certificate_t *cert, certificate_t *other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given certificate matches the given type, key type and identity,
|
||||||
|
* all of which are optional.
|
||||||
|
*
|
||||||
|
* Note that the identity may also be a public key fingerprint.
|
||||||
|
*
|
||||||
|
* @param cert certificate
|
||||||
|
* @param type certificate type to match, or CERT_ANY
|
||||||
|
* @param key key type to match, or KEY_ANY
|
||||||
|
* @param id identity to match, or NULL
|
||||||
|
*/
|
||||||
|
bool certificate_matches(certificate_t *cert, certificate_type_t type,
|
||||||
|
key_type_t key, identification_t *id);
|
||||||
|
|
||||||
#endif /** CERTIFICATE_H_ @}*/
|
#endif /** CERTIFICATE_H_ @}*/
|
||||||
|
|||||||
@@ -84,42 +84,13 @@ CALLBACK(cert_data_destroy, void,
|
|||||||
CALLBACK(certs_filter, bool,
|
CALLBACK(certs_filter, bool,
|
||||||
cert_data_t *data, enumerator_t *orig, va_list args)
|
cert_data_t *data, enumerator_t *orig, va_list args)
|
||||||
{
|
{
|
||||||
public_key_t *public;
|
|
||||||
certificate_t *cert, **out;
|
certificate_t *cert, **out;
|
||||||
|
|
||||||
VA_ARGS_VGET(args, out);
|
VA_ARGS_VGET(args, out);
|
||||||
|
|
||||||
while (orig->enumerate(orig, &cert))
|
while (orig->enumerate(orig, &cert))
|
||||||
{
|
{
|
||||||
if (data->cert != CERT_ANY && data->cert != cert->get_type(cert))
|
if (certificate_matches(cert, data->cert, data->key, data->id))
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
public->destroy(public);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
public->destroy(public);
|
|
||||||
}
|
|
||||||
else if (data->key != KEY_ANY)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!data->id || cert->has_subject(cert, data->id))
|
|
||||||
{
|
{
|
||||||
*out = cert;
|
*out = cert;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|||||||
@@ -123,4 +123,15 @@
|
|||||||
static typeof(_cb_##name) *name = (typeof(_cb_##name)*)_cb_##name; \
|
static typeof(_cb_##name) *name = (typeof(_cb_##name)*)_cb_##name; \
|
||||||
static ret _cb_##name(param1, ##__VA_ARGS__)
|
static ret _cb_##name(param1, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as CALLBACK(), but for two void* arguments (e.g. for comparisons).
|
||||||
|
*/
|
||||||
|
#define CALLBACK2(name, ret, param1, param2, ...) \
|
||||||
|
static ret _cb_##name(union {void *_generic; param1;} \
|
||||||
|
__attribute__((transparent_union)), \
|
||||||
|
union {void *_generic; param2;} \
|
||||||
|
__attribute__((transparent_union)), ##__VA_ARGS__); \
|
||||||
|
static typeof(_cb_##name) *name = (typeof(_cb_##name)*)_cb_##name; \
|
||||||
|
static ret _cb_##name(param1, param2, ##__VA_ARGS__)
|
||||||
|
|
||||||
#endif /** OBJECT_H_ @} */
|
#endif /** OBJECT_H_ @} */
|
||||||
|
|||||||
Reference in New Issue
Block a user