543 lines
14 KiB
Diff
543 lines
14 KiB
Diff
diff --git a/src/pluto/ca.c b/src/pluto/ca.c
|
|
index 2f59a90..d9db082 100644
|
|
--- a/src/pluto/ca.c
|
|
+++ b/src/pluto/ca.c
|
|
@@ -27,7 +27,6 @@
|
|
#include "constants.h"
|
|
#include "defs.h"
|
|
#include "log.h"
|
|
-#include "x509.h"
|
|
#include "ca.h"
|
|
#include "certs.h"
|
|
#include "whack.h"
|
|
@@ -36,13 +35,180 @@
|
|
|
|
/* chained list of X.509 authority certificates (ca, aa, and ocsp) */
|
|
|
|
-static x509cert_t *x509authcerts = NULL;
|
|
+static linked_list_t *authcerts = NULL;
|
|
|
|
/* chained list of X.509 certification authority information records */
|
|
|
|
static ca_info_t *ca_infos = NULL;
|
|
|
|
+/**
|
|
+ * Initialize the linked list of authority certificates
|
|
+ */
|
|
+void ca_initialize(void)
|
|
+{
|
|
+ authcerts = linked_list_create();
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Free the linked list of authority certificates
|
|
+ */
|
|
+void ca_finalize(void)
|
|
+{
|
|
+ lock_authcert_list("free_authcerts");
|
|
+ authcerts->destroy_offset(authcerts, offsetof(certificate_t, destroy));
|
|
+ unlock_authcert_list("free_authcerts");
|
|
+}
|
|
+
|
|
/*
|
|
+ * get a X.509 authority certificate with a given subject or keyid
|
|
+ */
|
|
+certificate_t* ca_get_cert(identification_t *subject, chunk_t keyid,
|
|
+ x509_flag_t auth_flags)
|
|
+{
|
|
+ enumerator_t *enumerator;
|
|
+ certificate_t *cert, *found = NULL;
|
|
+
|
|
+ enumerator = authcerts->create_enumerator(authcerts);
|
|
+ while (enumerator->enumerate(enumerator, &cert))
|
|
+ {
|
|
+ x509_t *x509 = (x509_t*)cert;
|
|
+
|
|
+ /* skip non-matching types of authority certificates */
|
|
+ if (!(x509->get_flags(x509) & auth_flags))
|
|
+ {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /* compare the keyid with the certificate's subjectKeyIdentifier */
|
|
+ if (keyid.ptr)
|
|
+ {
|
|
+ chunk_t subjectKeyId;
|
|
+
|
|
+ subjectKeyId = x509->get_subjectKeyIdentifier(x509);
|
|
+ if (subjectKeyId.ptr && !chunk_equals(keyid, subjectKeyId))
|
|
+ {
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* compare the subjectDistinguishedNames */
|
|
+ if (cert->has_subject(cert, subject))
|
|
+ {
|
|
+ found = cert;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ enumerator->destroy(enumerator);
|
|
+ return found;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Add an authority certificate to the chained list
|
|
+ */
|
|
+certificate_t* ca_add_cert(certificate_t *cert)
|
|
+{
|
|
+ identification_t *subject = cert->get_subject(cert);
|
|
+ x509_t *x509 = (x509_t*)cert;
|
|
+ x509_flag_t flags = x509->get_flags(x509);
|
|
+ chunk_t keyid = x509->get_subjectKeyIdentifier(x509);
|
|
+
|
|
+ certificate_t *old_cert;
|
|
+ enumerator_t *enumerator;
|
|
+ bool add = TRUE;
|
|
+
|
|
+ lock_authcert_list("add_authcert");
|
|
+
|
|
+ enumerator = acerts->create_enumerator(acerts);
|
|
+ while (enumerator->enumerate(enumerator, &cert_old))
|
|
+ {
|
|
+ x509_t *x509_old = (x509_t*)cert_old;
|
|
+
|
|
+ /* skip non-matching types of authority certificates */
|
|
+ if (!(x509_old->get_flags(x509_old) & flags))
|
|
+ {
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /* compare the keyid with the certificate's subjectKeyIdentifier */
|
|
+ if (keyid.ptr)
|
|
+ {
|
|
+ chunk_t subjectKeyId;
|
|
+
|
|
+ subjectKeyId = x509_old->get_subjectKeyIdentifier(x509_old);
|
|
+ if (subjectKeyId.ptr && !chunk_equals(keyid, subjectKeyId))
|
|
+ {
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* compare the subjectDistinguishedNames */
|
|
+ if (!cert_old->has_subject(cert_old, subject))
|
|
+ {
|
|
+ continue,
|
|
+ }
|
|
+
|
|
+ if (cert->equals(cert, cert_old))
|
|
+ {
|
|
+ DBG1(" authcert is already present and identical")
|
|
+
|
|
+ cert->destroy(cert);
|
|
+ cert = cert_old;
|
|
+ add = FALSE;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ authcerts->remove_at(authcerts, enumerator);
|
|
+ DBG1(" existing authcert replaced");
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ enumerator->destroy(enumerator);
|
|
+
|
|
+ if (add)
|
|
+ {
|
|
+ authcerts->insert_last(authcerts, cert);
|
|
+ }
|
|
+ unlock_authcert_list("add_authcert");
|
|
+
|
|
+ return cert;
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Loads authority certificates
|
|
+ */
|
|
+void ca_load_authcerts(char *type, char *path, x509_flag_t auth_flags)
|
|
+{
|
|
+ enumerator_t *enumerator;
|
|
+ struct stat st;
|
|
+ char *file;
|
|
+
|
|
+ DBG1("loading %s certificates from '%s'", type, path);
|
|
+
|
|
+ enumerator = enumerator_create_directory(path);
|
|
+ if (!enumerator)
|
|
+ {
|
|
+ DBG1(" reading directory '%s' failed");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ while (enumerator->enumerate(enumerator, NULL, &file, &st))
|
|
+ {
|
|
+ cert_t cert;
|
|
+
|
|
+ if (!S_ISREG(st.st_mode))
|
|
+ {
|
|
+ /* skip special file */
|
|
+ continue;
|
|
+ }
|
|
+ if (load_cert(file, type, auth_flags, &cert))
|
|
+ {
|
|
+ add_authcert(cert.u.x509, auth_flags);
|
|
+ }
|
|
+ }
|
|
+ enumerator->destroy(enumerator);
|
|
+}
|
|
+
|
|
+/**
|
|
* Checks if CA a is trusted by CA b
|
|
*/
|
|
bool trusted_ca(identification_t *a, identification_t *b, int *pathlen)
|
|
@@ -76,20 +242,18 @@ bool trusted_ca(identification_t *a, identification_t *b, int *pathlen)
|
|
|
|
while ((*pathlen)++ < MAX_CA_PATH_LEN)
|
|
{
|
|
- certificate_t *certificate;
|
|
+ certificate_t *cacert;
|
|
identification_t *issuer;
|
|
- x509cert_t *cacert;
|
|
|
|
- cacert = get_authcert(a, chunk_empty, X509_CA);
|
|
+ cacert = ca_get_cert(a, chunk_empty, X509_CA);
|
|
if (cacert == NULL)
|
|
{
|
|
break;
|
|
}
|
|
- certificate = cacert->cert;
|
|
|
|
/* is the certificate self-signed? */
|
|
{
|
|
- x509_t *x509 = (x509_t*)certificate;
|
|
+ x509_t *x509 = (x509_t*)cacert;
|
|
|
|
if (x509->get_flags(x509) & X509_SELF_SIGNED)
|
|
{
|
|
@@ -98,7 +262,7 @@ bool trusted_ca(identification_t *a, identification_t *b, int *pathlen)
|
|
}
|
|
|
|
/* does the issuer of CA a match CA b? */
|
|
- issuer = certificate->get_issuer(certificate);
|
|
+ issuer = cert->get_issuer(cert);
|
|
match = b->equals(b, issuer);
|
|
|
|
/* we have a match and exit the loop */
|
|
@@ -114,8 +278,8 @@ bool trusted_ca(identification_t *a, identification_t *b, int *pathlen)
|
|
return match;
|
|
}
|
|
|
|
-/*
|
|
- * does our CA match one of the requested CAs?
|
|
+/**
|
|
+ * Does our CA match one of the requested CAs?
|
|
*/
|
|
bool match_requested_ca(linked_list_t *requested_ca, identification_t *our_ca,
|
|
int *our_pathlen)
|
|
@@ -156,167 +320,6 @@ bool match_requested_ca(linked_list_t *requested_ca, identification_t *our_ca,
|
|
}
|
|
|
|
/*
|
|
- * free the first authority certificate in the chain
|
|
- */
|
|
-static void free_first_authcert(void)
|
|
-{
|
|
- x509cert_t *first = x509authcerts;
|
|
- x509authcerts = first->next;
|
|
- free_x509cert(first);
|
|
-}
|
|
-
|
|
-/*
|
|
- * free all CA certificates
|
|
- */
|
|
-void free_authcerts(void)
|
|
-{
|
|
- lock_authcert_list("free_authcerts");
|
|
-
|
|
- while (x509authcerts != NULL)
|
|
- free_first_authcert();
|
|
-
|
|
- unlock_authcert_list("free_authcerts");
|
|
-}
|
|
-
|
|
-/*
|
|
- * get a X.509 authority certificate with a given subject or keyid
|
|
- */
|
|
-x509cert_t* get_authcert(identification_t *subject, chunk_t keyid,
|
|
- x509_flag_t auth_flags)
|
|
-{
|
|
- x509cert_t *cert, *prev_cert = NULL;
|
|
-
|
|
- /* the authority certificate list is empty */
|
|
- if (x509authcerts == NULL)
|
|
- {
|
|
- return NULL;
|
|
- }
|
|
-
|
|
- for (cert = x509authcerts; cert != NULL; prev_cert = cert, cert = cert->next)
|
|
- {
|
|
- certificate_t *certificate = cert->cert;
|
|
- x509_t *x509 = (x509_t*)certificate;
|
|
-
|
|
- /* skip non-matching types of authority certificates */
|
|
- if (!(x509->get_flags(x509) & auth_flags))
|
|
- {
|
|
- continue;
|
|
- }
|
|
-
|
|
- /* compare the keyid with the certificate's subjectKeyIdentifier */
|
|
- if (keyid.ptr)
|
|
- {
|
|
- chunk_t subjectKeyId;
|
|
-
|
|
- subjectKeyId = x509->get_subjectKeyIdentifier(x509);
|
|
- if (subjectKeyId.ptr && !chunk_equals(keyid, subjectKeyId))
|
|
- {
|
|
- continue;
|
|
- }
|
|
- }
|
|
-
|
|
- /* compare the subjectDistinguishedNames */
|
|
- if (!certificate->has_subject(certificate, subject))
|
|
- {
|
|
- continue;
|
|
- }
|
|
-
|
|
- /* found the authcert */
|
|
- if (cert != x509authcerts)
|
|
- {
|
|
- /* bring the certificate up front */
|
|
- prev_cert->next = cert->next;
|
|
- cert->next = x509authcerts;
|
|
- x509authcerts = cert;
|
|
- }
|
|
- return cert;
|
|
- }
|
|
- return NULL;
|
|
-}
|
|
-
|
|
-/*
|
|
- * add an authority certificate to the chained list
|
|
- */
|
|
-x509cert_t* add_authcert(x509cert_t *cert, x509_flag_t auth_flags)
|
|
-{
|
|
- certificate_t *certificate = cert->cert;
|
|
- x509_t *x509 = (x509_t*)certificate;
|
|
- x509cert_t *old_cert;
|
|
-
|
|
- lock_authcert_list("add_authcert");
|
|
-
|
|
- old_cert = get_authcert(certificate->get_subject(certificate),
|
|
- x509->get_subjectKeyIdentifier(x509),
|
|
- auth_flags);
|
|
- if (old_cert)
|
|
- {
|
|
- if (certificate->equals(certificate, old_cert->cert))
|
|
- {
|
|
- DBG(DBG_CONTROL | DBG_PARSING ,
|
|
- DBG_log(" authcert is already present and identical")
|
|
- )
|
|
- unlock_authcert_list("add_authcert");
|
|
-
|
|
- free_x509cert(cert);
|
|
- return old_cert;
|
|
- }
|
|
- else
|
|
- {
|
|
- /* cert is already present but will be replaced by new cert */
|
|
- free_first_authcert();
|
|
- DBG(DBG_CONTROL | DBG_PARSING ,
|
|
- DBG_log(" existing authcert deleted")
|
|
- )
|
|
- }
|
|
- }
|
|
-
|
|
- /* add new authcert to chained list */
|
|
- cert->next = x509authcerts;
|
|
- x509authcerts = cert;
|
|
- share_x509cert(cert); /* set count to one */
|
|
- DBG(DBG_CONTROL | DBG_PARSING,
|
|
- DBG_log(" authcert inserted")
|
|
- )
|
|
- unlock_authcert_list("add_authcert");
|
|
- return cert;
|
|
-}
|
|
-
|
|
-/*
|
|
- * Loads authority certificates
|
|
- */
|
|
-void load_authcerts(char *type, char *path, x509_flag_t auth_flags)
|
|
-{
|
|
- enumerator_t *enumerator;
|
|
- struct stat st;
|
|
- char *file;
|
|
-
|
|
- DBG1("loading %s certificates from '%s'", type, path);
|
|
-
|
|
- enumerator = enumerator_create_directory(path);
|
|
- if (!enumerator)
|
|
- {
|
|
- DBG1(" reading directory '%s' failed");
|
|
- return;
|
|
- }
|
|
-
|
|
- while (enumerator->enumerate(enumerator, NULL, &file, &st))
|
|
- {
|
|
- cert_t cert;
|
|
-
|
|
- if (!S_ISREG(st.st_mode))
|
|
- {
|
|
- /* skip special file */
|
|
- continue;
|
|
- }
|
|
- if (load_cert(file, type, auth_flags, &cert))
|
|
- {
|
|
- add_authcert(cert.u.x509, auth_flags);
|
|
- }
|
|
- }
|
|
- enumerator->destroy(enumerator);
|
|
-}
|
|
-
|
|
-/*
|
|
* list all X.509 authcerts with given auth flags in a chained list
|
|
*/
|
|
void list_authcerts(const char *caption, x509_flag_t auth_flags, bool utc)
|
|
@@ -368,7 +371,7 @@ static const x509cert_t* get_alt_cacert(identification_t *subject, chunk_t keyid
|
|
/* establish trust into a candidate authcert by going up the trust chain.
|
|
* validity and revocation status are not checked.
|
|
*/
|
|
-bool trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chain)
|
|
+bool trust_authcert_candidate(certificate_t *cert, linked_list_t *alt_chain)
|
|
{
|
|
int pathlen;
|
|
|
|
@@ -448,8 +451,8 @@ bool trust_authcert_candidate(const x509cert_t *cert, const x509cert_t *alt_chai
|
|
return FALSE;
|
|
}
|
|
|
|
-/*
|
|
- * get a CA info record with a given authName or authKeyID
|
|
+/**
|
|
+ * Get a CA info record with a given authName or authKeyID
|
|
*/
|
|
ca_info_t* get_ca_info(identification_t *name, chunk_t keyid)
|
|
{
|
|
@@ -468,11 +471,10 @@ ca_info_t* get_ca_info(identification_t *name, chunk_t keyid)
|
|
}
|
|
|
|
|
|
-/*
|
|
- * free the dynamic memory used by a ca_info record
|
|
+/**
|
|
+ * Free the dynamic memory used by a ca_info record
|
|
*/
|
|
-static void
|
|
-free_ca_info(ca_info_t* ca_info)
|
|
+static void free_ca_info(ca_info_t* ca_info)
|
|
{
|
|
if (ca_info == NULL)
|
|
{
|
|
@@ -502,8 +504,8 @@ void free_ca_infos(void)
|
|
}
|
|
}
|
|
|
|
-/*
|
|
- * find a CA information record by name and optionally delete it
|
|
+/**
|
|
+ * Find a CA information record by name and optionally delete it
|
|
*/
|
|
bool find_ca_info_by_name(const char *name, bool delete)
|
|
{
|
|
@@ -531,7 +533,7 @@ bool find_ca_info_by_name(const char *name, bool delete)
|
|
return FALSE;
|
|
}
|
|
|
|
-/*
|
|
+/**
|
|
* Create an empty ca_info_t record
|
|
*/
|
|
ca_info_t* create_ca_info(void)
|
|
@@ -659,8 +661,8 @@ void add_ca_info(const whack_message_t *msg)
|
|
}
|
|
}
|
|
|
|
-/*
|
|
- * list all ca_info records in the chained list
|
|
+/**
|
|
+ * List all ca_info records in the chained list
|
|
*/
|
|
void list_ca_infos(bool utc)
|
|
{
|
|
diff --git a/src/pluto/ca.h b/src/pluto/ca.h
|
|
index 77dfe33..3b9e4c9 100644
|
|
--- a/src/pluto/ca.h
|
|
+++ b/src/pluto/ca.h
|
|
@@ -17,8 +17,8 @@
|
|
|
|
#include <utils/linked_list.h>
|
|
#include <utils/identification.h>
|
|
+#include <credentials/certificates/certificate.h>
|
|
|
|
-#include "x509.h"
|
|
#include "whack.h"
|
|
|
|
#define MAX_CA_PATH_LEN 7
|
|
@@ -39,17 +39,21 @@ struct ca_info {
|
|
bool strictcrlpolicy;
|
|
};
|
|
|
|
+extern void ca_initialize(void);
|
|
+extern void ca_finalize(void);
|
|
+extern void ca_load_certs(char *type, char *path, x509_flag_t auth_flags);
|
|
+extern void ca_list_certs(const char *caption, x509_flag_t auth_flags, bool utc);
|
|
+
|
|
+extern certificate_t* ca_add_cert(certificate_t *cert);
|
|
+
|
|
+extern certificate_t* ca_get_cert(identification_t *subject, chunk_t keyid,
|
|
+ x509_flag_t auth_flags)
|
|
+
|
|
extern bool trusted_ca(identification_t *a, identification_t *b, int *pathlen);
|
|
extern bool match_requested_ca(linked_list_t *requested_ca,
|
|
identification_t *our_ca, int *our_pathlen);
|
|
-extern x509cert_t* get_authcert(identification_t *subject, chunk_t keyid,
|
|
- x509_flag_t auth_flags);
|
|
-extern void load_authcerts(char *type, char *path, x509_flag_t auth_flags);
|
|
-extern x509cert_t* add_authcert(x509cert_t *cert, x509_flag_t auth_flags);
|
|
-extern void free_authcerts(void);
|
|
-extern void list_authcerts(const char *caption, x509_flag_t auth_flags, bool utc);
|
|
-extern bool trust_authcert_candidate(const x509cert_t *cert,
|
|
- const x509cert_t *alt_chain);
|
|
+extern bool trust_authcert_candidate(certificate_t *cert,
|
|
+ linked_list_t *alt_chain);
|
|
extern ca_info_t* get_ca_info(identification_t *name, chunk_t keyid);
|
|
extern bool find_ca_info_by_name(const char *name, bool delete);
|
|
extern void add_ca_info(const whack_message_t *msg);
|
|
diff --git a/src/pluto/plutomain.c b/src/pluto/plutomain.c
|
|
index 0471d26..a9e3aa0 100644
|
|
--- a/src/pluto/plutomain.c
|
|
+++ b/src/pluto/plutomain.c
|
|
@@ -675,6 +675,7 @@ int main(int argc, char **argv)
|
|
init_adns();
|
|
init_myid();
|
|
init_fetch();
|
|
+ ca_initialize();
|
|
ac_initialize();
|
|
|
|
/* drop unneeded capabilities and change UID/GID */
|
|
@@ -752,12 +753,12 @@ void exit_pluto(int status)
|
|
delete_every_connection();
|
|
free_crl_fetch(); /* free chain of crl fetch requests */
|
|
free_ocsp_fetch(); /* free chain of ocsp fetch requests */
|
|
- free_authcerts(); /* free chain of X.509 authority certificates */
|
|
free_crls(); /* free chain of X.509 CRLs */
|
|
free_ca_infos(); /* free chain of X.509 CA information records */
|
|
free_ocsp(); /* free ocsp cache */
|
|
free_ifaces();
|
|
ac_finalize(); /* free X.509 attribute certificates */
|
|
+ ca_finalize(); /* free X.509 authority certificates */
|
|
scx_finalize(); /* finalize and unload PKCS #11 module */
|
|
xauth_finalize(); /* finalize and unload XAUTH module */
|
|
stop_adns();
|