critical keyUsage extension must be parsed
authorAndreas Steffen <andreas.steffen@strongswan.org>
Sun, 7 Mar 2010 19:51:34 +0000 (20:51 +0100)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Sun, 7 Mar 2010 19:51:34 +0000 (20:51 +0100)
ca.diff [new file with mode: 0644]
configure.in
src/libstrongswan/plugins/x509/x509_cert.c
strongswan-4.4.0dr1.tar.bz2 [new file with mode: 0644]

diff --git a/ca.diff b/ca.diff
new file mode 100644 (file)
index 0000000..a262ccf
--- /dev/null
+++ b/ca.diff
@@ -0,0 +1,542 @@
+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();
index 8124992..f500ebc 100644 (file)
@@ -16,7 +16,7 @@ dnl ===========================
 dnl  initialize & set some vars
 dnl ===========================
 
-AC_INIT(strongSwan,4.4.0)
+AC_INIT(strongSwan,4.4.0dr1)
 AM_INIT_AUTOMAKE(tar-ustar)
 AC_CONFIG_MACRO_DIR([m4/config])
 PKG_PROG_PKG_CONFIG
index 6989034..4c8456c 100644 (file)
@@ -974,6 +974,9 @@ static bool parse_certificate(private_x509_cert_t *this)
                                        case OID_AUTHORITY_INFO_ACCESS:
                                                parse_authorityInfoAccess(object, level, this);
                                                break;
+                                       case OID_KEY_USAGE:
+                                               /* TODO parse the flags */
+                                               break;
                                        case OID_EXTENDED_KEY_USAGE:
                                                parse_extendedKeyUsage(object, level, this);
                                                break;
diff --git a/strongswan-4.4.0dr1.tar.bz2 b/strongswan-4.4.0dr1.tar.bz2
new file mode 100644 (file)
index 0000000..25e14cc
Binary files /dev/null and b/strongswan-4.4.0dr1.tar.bz2 differ