]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
android: Cache CRLs in app directory
authorTobias Brunner <tobias@strongswan.org>
Mon, 21 Aug 2017 13:53:20 +0000 (15:53 +0200)
committerTobias Brunner <tobias@strongswan.org>
Mon, 4 Sep 2017 08:41:25 +0000 (10:41 +0200)
Fixes #2405.

src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_creds.c
src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_creds.h
src/frontends/android/app/src/main/jni/libandroidbridge/charonservice.c

index ddc032638e12eba74ac82a8a4237a7550bf3dfcf..0c460a9cf5d2816a0f57969a22207f898f1f5205 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2012 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2012-2017 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  * for more details.
  */
 
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <time.h>
+
 #include "android_creds.h"
 #include "../charonservice.h"
 
@@ -21,6 +26,8 @@
 #include <credentials/sets/mem_cred.h>
 #include <threading/rwlock.h>
 
+#define CRL_PREFIX "crl-"
+
 typedef struct private_android_creds_t private_android_creds_t;
 
 /**
@@ -47,6 +54,11 @@ struct private_android_creds_t {
         * TRUE if certificates have been loaded via JNI
         */
        bool loaded;
+
+       /**
+        * Directory for CRLs
+        */
+       char *crldir;
 };
 
 /**
@@ -86,15 +98,79 @@ static void load_trusted_certificates(private_android_creds_t *this)
        }
 }
 
+/**
+ * Load a CRL from a file
+ */
+static void load_crl(private_android_creds_t *this, char *file)
+{
+       certificate_t *cert;
+       time_t now, notAfter;
+
+       cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_CRL,
+                                                         BUILD_FROM_FILE, file, BUILD_END);
+       if (cert)
+       {
+               now = time(NULL);
+               if (cert->get_validity(cert, &now, NULL, &notAfter))
+               {
+                       DBG1(DBG_CFG, "loaded crl issued by '%Y'", cert->get_issuer(cert));
+                       this->creds->add_crl(this->creds, (crl_t*)cert);
+               }
+               else
+               {
+                       DBG1(DBG_CFG, "deleted crl issued by '%Y', expired (%V ago)",
+                                cert->get_issuer(cert), &now, &notAfter);
+                       unlink(file);
+               }
+       }
+       else
+       {
+               DBG1(DBG_CFG, "loading crl failed");
+               unlink(file);
+       }
+}
+
+/**
+ * Load cached CRLs
+ */
+static void load_crls(private_android_creds_t *this)
+{
+       enumerator_t *enumerator;
+       struct stat st;
+       char *rel, *abs;
+
+       enumerator = enumerator_create_directory(this->crldir);
+       if (enumerator)
+       {
+               while (enumerator->enumerate(enumerator, &rel, &abs, &st))
+               {
+                       if (S_ISREG(st.st_mode) && strpfx(rel, CRL_PREFIX))
+                       {
+                               load_crl(this, abs);
+                       }
+               }
+               enumerator->destroy(enumerator);
+       }
+       else
+       {
+               DBG1(DBG_CFG, "  reading directory '%s' failed", this->crldir);
+       }
+}
+
 METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
        private_android_creds_t *this, certificate_type_t cert, key_type_t key,
        identification_t *id, bool trusted)
 {
        enumerator_t *enumerator;
 
-       if (cert != CERT_ANY && cert != CERT_X509)
+       switch (cert)
        {
-               return NULL;
+               case CERT_ANY:
+               case CERT_X509:
+               case CERT_X509_CRL:
+                       break;
+               default:
+                       return NULL;
        }
        this->lock->read_lock(this->lock);
        if (!this->loaded)
@@ -104,6 +180,7 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
                /* check again after acquiring the write lock */
                if (!this->loaded)
                {
+                       load_crls(this);
                        load_trusted_certificates(this);
                        this->loaded = TRUE;
                }
@@ -116,6 +193,46 @@ METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
                                                                         this->lock);
 }
 
+METHOD(credential_set_t, cache_cert, void,
+       private_android_creds_t *this, certificate_t *cert)
+{
+       if (this->crldir && cert->get_type(cert) == CERT_X509_CRL)
+       {
+               /* CRLs get written to /<app>/<path>/crl-<authkeyId>[-delta] */
+               crl_t *crl = (crl_t*)cert;
+
+               cert->get_ref(cert);
+               if (this->creds->add_crl(this->creds, crl))
+               {
+                       char buf[BUF_LEN];
+                       chunk_t chunk, hex;
+                       bool is_delta_crl;
+
+                       is_delta_crl = crl->is_delta_crl(crl, NULL);
+                       chunk = crl->get_authKeyIdentifier(crl);
+                       hex = chunk_to_hex(chunk, NULL, FALSE);
+                       snprintf(buf, sizeof(buf), "%s/%s%s%s", this->crldir, CRL_PREFIX,
+                                        hex.ptr, is_delta_crl ? "-delta" : "");
+                       free(hex.ptr);
+
+                       if (cert->get_encoding(cert, CERT_ASN1_DER, &chunk))
+                       {
+                               if (chunk_write(chunk, buf, 022, TRUE))
+                               {
+                                       DBG1(DBG_CFG, "  written crl to file (%d bytes)",
+                                                chunk.len);
+                               }
+                               else
+                               {
+                                       DBG1(DBG_CFG, "  writing crl to file failed: %s",
+                                                strerror(errno));
+                               }
+                               free(chunk.ptr);
+                       }
+               }
+       }
+}
+
 METHOD(android_creds_t, add_username_password, void,
        private_android_creds_t *this, char *username, char *password)
 {
@@ -224,13 +341,14 @@ METHOD(android_creds_t, destroy, void,
        clear(this);
        this->creds->destroy(this->creds);
        this->lock->destroy(this->lock);
+       free(this->crldir);
        free(this);
 }
 
 /**
  * Described in header.
  */
-android_creds_t *android_creds_create()
+android_creds_t *android_creds_create(char *crldir)
 {
        private_android_creds_t *this;
 
@@ -241,7 +359,7 @@ android_creds_t *android_creds_create()
                                .create_shared_enumerator = _create_shared_enumerator,
                                .create_private_enumerator = _create_private_enumerator,
                                .create_cdp_enumerator = (void*)return_null,
-                               .cache_cert = (void*)nop,
+                               .cache_cert = _cache_cert,
                        },
                        .add_username_password = _add_username_password,
                        .load_user_certificate = _load_user_certificate,
@@ -250,6 +368,7 @@ android_creds_t *android_creds_create()
                },
                .creds = mem_cred_create(),
                .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+               .crldir = strdupnull(crldir),
        );
 
        return &this->public;
index 918708f145ce86997cebb0cfe72b4b6588185db9..869e0afead0b3e59d7da954238e3f611d95a3c1c 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Copyright (C) 2012 Tobias Brunner
- * Hochschule fuer Technik Rapperswil
+ * Copyright (C) 2012-2017 Tobias Brunner
+ * HSR Hochschule fuer Technik Rapperswil
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -67,8 +67,10 @@ struct android_creds_t {
 
 /**
  * Create an android_creds instance.
+ *
+ * @param crldir                               directory for cached CRLs
  */
-android_creds_t *android_creds_create();
+android_creds_t *android_creds_create(char *crldir);
 
 #endif /** ANDROID_CREDS_H_ @}*/
 
index 5eb1bd9c0dab26bfe1f2790b7923e7980c416a08..62427338ae7cc55cad2fb5d10e63e5f02bcab80b 100644 (file)
@@ -526,6 +526,7 @@ static void charonservice_init(JNIEnv *env, jobject service, jobject builder,
                PLUGIN_CALLBACK(charonservice_register, NULL),
                        PLUGIN_PROVIDE(CUSTOM, "android-backend"),
                                PLUGIN_DEPENDS(CUSTOM, "libcharon"),
+                               PLUGIN_DEPENDS(CERT_DECODE, CERT_X509_CRL),
                PLUGIN_REGISTER(FETCHER, android_fetcher_create),
                        PLUGIN_PROVIDE(FETCHER, "http://"),
                        PLUGIN_PROVIDE(FETCHER, "https://"),
@@ -544,7 +545,7 @@ static void charonservice_init(JNIEnv *env, jobject service, jobject builder,
                        .get_network_manager = _get_network_manager,
                },
                .attr = android_attr_create(),
-               .creds = android_creds_create(),
+               .creds = android_creds_create(appdir),
                .builder = vpnservice_builder_create(builder),
                .network_manager = network_manager_create(service),
                .sockets = linked_list_create(),