removed unused gmp.h to build libstrongswan without libgmp
[strongswan.git] / src / libstrongswan / plugins / x509 / x509_cert.c
index e85076d..f427734 100644 (file)
@@ -23,7 +23,6 @@
 
 #include "x509_cert.h"
 
-#include <gmp.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <string.h>
@@ -66,9 +65,9 @@ struct private_x509_cert_t {
        x509_cert_t public;
 
        /**
-        * DER encoded X.509 certificate
+        * X.509 certificate encoding in ASN.1 DER format
         */
-       chunk_t certificate;
+       chunk_t encoding;
 
        /**
         * X.509 certificate body over which signature is computed
@@ -498,7 +497,7 @@ static identification_t *parse_generalName(chunk_t blob, int level0)
 /**
  * extracts one or several GNs and puts them into a chained list
  */
-void parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list)
+void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, linked_list_t *list)
 {
        asn1_ctx_t ctx;
        chunk_t object;
@@ -581,7 +580,7 @@ identification_t* x509_parse_authorityKeyIdentifier(chunk_t blob, int level0,
                        }
                        case AUTH_KEY_ID_CERT_ISSUER:
                        {
-                               /* TODO: parse_generalNames(object, level+1, TRUE); */
+                               /* TODO: x509_parse_generalNames(object, level+1, TRUE); */
                                break;
                        }
                        case AUTH_KEY_ID_CERT_SERIAL:
@@ -708,7 +707,7 @@ static void parse_crlDistributionPoints(chunk_t blob, int level0,
                }
                if (objectID == CRL_DIST_POINTS_FULLNAME)
                {       /* append extracted generalNames to existing chained list */
-                       parse_generalNames(object, level+1, TRUE, list);
+                       x509_parse_generalNames(object, level+1, TRUE, list);
        
                        while (list->remove_last(list, (void**)&id) == SUCCESS)
                        {
@@ -735,11 +734,11 @@ static bool parse_certificate(private_x509_cert_t *this)
        u_int level;
        int objectID = 0;
        int extn_oid = OID_UNKNOWN;
-       int key_alg = 0;
-       int sig_alg = 0;
+       int key_alg = OID_UNKNOWN;
+       int sig_alg = OID_UNKNOWN;
        chunk_t subjectPublicKey = chunk_empty;
        
-       asn1_init(&ctx, this->certificate, 0, FALSE, FALSE);
+       asn1_init(&ctx, this->encoding, 0, FALSE, FALSE);
        while (objectID < X509_OBJ_ROOF)
        {
                if (!extract_object(certObjects, &objectID, &object, &level, &ctx))
@@ -817,7 +816,7 @@ static bool parse_certificate(private_x509_cert_t *this)
                                                this->subjectKeyID = parse_keyIdentifier(object, level, FALSE);
                                                break;
                                        case OID_SUBJECT_ALT_NAME:
-                                               parse_generalNames(object, level, FALSE, this->subjectAltNames);
+                                               x509_parse_generalNames(object, level, FALSE, this->subjectAltNames);
                                                break;
                                        case OID_BASIC_CONSTRAINTS:
                                                if (parse_basicConstraints(object, level))
@@ -932,35 +931,35 @@ static id_match_t has_issuer(private_x509_cert_t *this, identification_t *issuer
 /**
  * Implementation of certificate_t.issued_by
  */
-static bool issued_by(private_x509_cert_t *this, certificate_t *issuer,
-                                         bool sigcheck)
+static bool issued_by(private_x509_cert_t *this, certificate_t *issuer)
 {
        public_key_t *key;
        signature_scheme_t scheme;
        bool valid;
        x509_t *x509 = (x509_t*)issuer;
        
-       if (&this->public.interface.interface == issuer &&
-               (this->flags & X509_SELF_SIGNED))
+       if (&this->public.interface.interface == issuer)
        {
-               return TRUE;
+               if (this->flags & X509_SELF_SIGNED)
+               {
+                       return TRUE;
+               }
        }
-       if (issuer->get_type(issuer) != CERT_X509)
+       else
        {
-               return FALSE;
+               if (issuer->get_type(issuer) != CERT_X509)
+               {
+                       return FALSE;
+               }
+               if (!(x509->get_flags(x509) & X509_CA))
+               {
+                       return FALSE;
+               }
        }
        if (!this->issuer->equals(this->issuer, issuer->get_subject(issuer)))
        {
                return FALSE;
        }
-       if (!(x509->get_flags(x509) & X509_CA))
-       {
-               return FALSE;
-       }
-       if (!sigcheck)
-       {
-               return TRUE;
-       }
        /* TODO: generic OID to scheme mapper? */
        switch (this->algorithm)
        {
@@ -1035,23 +1034,40 @@ static bool get_validity(private_x509_cert_t *this, time_t *when,
        {
                t = time(NULL);
        }
-       if (not_after)
-       {
-               *not_after = this->notAfter;
-       }
        if (not_before)
        {
                *not_before = this->notBefore;
        }
+       if (not_after)
+       {
+               *not_after = this->notAfter;
+       }
        return (t >= this->notBefore && t <= this->notAfter);
 }
+
+/**
+ * Implementation of certificate_t.is_newer.
+ */
+static bool is_newer(certificate_t *this, certificate_t *that)
+{
+       time_t this_update, that_update, now = time(NULL);
+       bool new;
+
+       this->get_validity(this, &now, &this_update, NULL);
+       that->get_validity(that, &now, &that_update, NULL);
+       new = this_update > that_update;
+       DBG1("  certificate from %#T is %s - existing certificate from %#T %s",
+                               &this_update, FALSE, new ? "newer":"not newer",
+                               &that_update, FALSE, new ? "replaced":"retained");
+       return new;
+}
        
 /**
  * Implementation of certificate_t.get_encoding.
  */
 static chunk_t get_encoding(private_x509_cert_t *this)
 {
-       return chunk_clone(this->certificate);
+       return chunk_clone(this->encoding);
 }
 
 /**
@@ -1135,15 +1151,15 @@ static void destroy(private_x509_cert_t *this)
                DESTROY_IF(this->subject);
                DESTROY_IF(this->public_key);
                DESTROY_IF(this->authKeyIdentifier);
-               chunk_free(&this->certificate);
+               chunk_free(&this->encoding);
                free(this);
        }
 }
 
 /**
- * load x509 certificate from a chunk
+ * create an empty but initialized X.509 certificate
  */
-static private_x509_cert_t *load(chunk_t chunk)
+static private_x509_cert_t* create_empty(void)
 {
        private_x509_cert_t *this = malloc_thing(private_x509_cert_t);
        
@@ -1152,9 +1168,10 @@ static private_x509_cert_t *load(chunk_t chunk)
        this->public.interface.interface.get_issuer = (identification_t* (*)(certificate_t *this))get_issuer;
        this->public.interface.interface.has_subject = (id_match_t (*)(certificate_t*, identification_t *subject))has_subject;
        this->public.interface.interface.has_issuer = (id_match_t (*)(certificate_t*, identification_t *issuer))has_issuer;
-       this->public.interface.interface.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer,bool))issued_by;
+       this->public.interface.interface.issued_by = (bool (*)(certificate_t *this, certificate_t *issuer))issued_by;
        this->public.interface.interface.get_public_key = (public_key_t* (*)(certificate_t *this))get_public_key;
        this->public.interface.interface.get_validity = (bool (*)(certificate_t*, time_t *when, time_t *, time_t*))get_validity;
+       this->public.interface.interface.is_newer = (bool (*)(certificate_t*,certificate_t*))is_newer;
        this->public.interface.interface.get_encoding = (chunk_t (*)(certificate_t*))get_encoding;
        this->public.interface.interface.equals = (bool (*)(certificate_t*, certificate_t *other))equals;
        this->public.interface.interface.get_ref = (certificate_t* (*)(certificate_t *this))get_ref;
@@ -1166,7 +1183,7 @@ static private_x509_cert_t *load(chunk_t chunk)
        this->public.interface.create_crl_uri_enumerator = (enumerator_t* (*)(x509_t*))create_crl_uri_enumerator;
        this->public.interface.create_ocsp_uri_enumerator = (enumerator_t* (*)(x509_t*))create_ocsp_uri_enumerator;
 
-       this->certificate = chunk;
+       this->encoding = chunk_empty;
        this->public_key = NULL;
        this->subject = NULL;
        this->issuer = NULL;
@@ -1178,19 +1195,58 @@ static private_x509_cert_t *load(chunk_t chunk)
        this->authKeySerialNumber = chunk_empty;
        this->flags = 0;
        this->ref = 1;
-       
+
+       return this;
+}
+
+/**
+ * create an X.509 certificate from a chunk
+ */
+static private_x509_cert_t *create_from_chunk(chunk_t chunk)
+{
+       private_x509_cert_t *this = create_empty();
+
+       this->encoding = chunk;
        if (!parse_certificate(this))
        {
                destroy(this);
                return NULL;
        }
-       if (issued_by(this, &this->public.interface.interface, FALSE))
+
+       /* check if the certificate is self-signed */
+       if (issued_by(this, &this->public.interface.interface))
        {
                this->flags |= X509_SELF_SIGNED;
        }
        return this;
 }
 
+/**
+ * create an X.509 certificate from a file
+ */
+static private_x509_cert_t *create_from_file(char *path)
+{
+       bool pgp = FALSE;
+       chunk_t chunk;
+       private_x509_cert_t *this;
+       
+       if (!pem_asn1_load_file(path, NULL, &chunk, &pgp))
+       {
+               return NULL;
+       }
+
+       this = create_from_chunk(chunk);
+
+       if (this == NULL)
+       {
+               DBG1("  could not parse loaded certificate file '%s'",path);
+               return NULL;
+       }
+       DBG1("  loaded certificate file '%s'",  path);
+       return this;
+
+}
+
 typedef struct private_builder_t private_builder_t;
 /**
  * Builder implementation for certificate loading
@@ -1207,14 +1263,24 @@ struct private_builder_t {
 /**
  * Implementation of builder_t.build
  */
-static x509_cert_t *build(private_builder_t *this)
+static private_x509_cert_t *build(private_builder_t *this)
 {
-       private_x509_cert_t *cert;
-       
-       cert = this->cert;
-       cert->flags |= this->flags;
+       private_x509_cert_t *cert = this->cert;
+       x509_flag_t flags = this->flags;
+
        free(this);
-       return &cert->public;
+       if (cert == NULL)
+       {
+               return NULL;
+       }
+       if ((flags & X509_CA) && !(cert->flags & X509_CA))
+       {
+               DBG1("  ca certificate must have ca basic constraint set, discarded");
+               destroy(cert);
+               return NULL;
+       }
+       cert->flags |= flags;
+       return cert;
 }
 
 /**
@@ -1227,20 +1293,15 @@ static void add(private_builder_t *this, builder_part_t part, ...)
        va_start(args, part);
        switch (part)
        {
+               case BUILD_FROM_FILE:
+                       this->cert = create_from_file(va_arg(args, char*));
+                       break;
                case BUILD_BLOB_ASN1_DER:
-               {
-                       if (this->cert)
-                       {
-                               destroy(this->cert);
-                       }
-                       this->cert = load(va_arg(args, chunk_t));
+                       this->cert = create_from_chunk(va_arg(args, chunk_t));
                        break;
-               }
                case BUILD_X509_FLAG:
-               {
                        this->flags = va_arg(args, x509_flag_t);
                        break;
-               }
                default:
                        DBG1("ignoring unsupported build part %N", builder_part_names, part);
                        break;