Added an Android specific credential set that provides CA certificates via JNI
authorTobias Brunner <tobias@strongswan.org>
Wed, 8 Aug 2012 10:52:05 +0000 (12:52 +0200)
committerTobias Brunner <tobias@strongswan.org>
Mon, 13 Aug 2012 09:00:28 +0000 (11:00 +0200)
src/frontends/android/jni/libandroidbridge/Android.mk
src/frontends/android/jni/libandroidbridge/backend/android_creds.c [new file with mode: 0644]
src/frontends/android/jni/libandroidbridge/backend/android_creds.h [new file with mode: 0644]
src/frontends/android/jni/libandroidbridge/charonservice.c
src/frontends/android/jni/libandroidbridge/charonservice.h

index 95cc2b7..a56aa3b 100644 (file)
@@ -4,6 +4,7 @@ include $(CLEAR_VARS)
 # copy-n-paste from Makefile.am
 LOCAL_SRC_FILES := \
 android_jni.c android_jni.h \
+backend/android_creds.c backend/android_creds.h \
 charonservice.c charonservice.h \
 kernel/android_ipsec.c kernel/android_ipsec.h \
 kernel/android_net.c kernel/android_net.h
diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_creds.c b/src/frontends/android/jni/libandroidbridge/backend/android_creds.c
new file mode 100644 (file)
index 0000000..ee9549d
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * 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
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "android_creds.h"
+#include "../charonservice.h"
+
+#include <daemon.h>
+#include <library.h>
+#include <credentials/sets/mem_cred.h>
+#include <threading/rwlock.h>
+
+typedef struct private_android_creds_t private_android_creds_t;
+
+/**
+ * Private data of an android_creds_t object
+ */
+struct private_android_creds_t {
+
+       /**
+        * Public interface
+        */
+       android_creds_t public;
+
+       /**
+        * Credential set storing trusted certificates
+        */
+       mem_cred_t *creds;
+
+       /**
+        * read/write lock to make sure certificates are only loaded once
+        */
+       rwlock_t *lock;
+
+       /**
+        * TRUE if certificates have been loaded via JNI
+        */
+       bool loaded;
+};
+
+/**
+ * Load trusted certificates via charonservice (JNI).
+ */
+static void load_trusted_certificates(private_android_creds_t *this)
+{
+       linked_list_t *certs;
+       certificate_t *cert;
+       chunk_t *current;
+
+       certs = charonservice->get_trusted_certificates(charonservice);
+       if (certs)
+       {
+               while (certs->remove_first(certs, (void**)&current) == SUCCESS)
+               {
+                       cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
+                                                                         BUILD_BLOB_ASN1_DER, *current, BUILD_END);
+                       if (cert)
+                       {
+                               DBG2(DBG_CFG, "loaded CA certificate '%Y'",
+                                        cert->get_subject(cert));
+                               this->creds->add_cert(this->creds, TRUE, cert);
+                       }
+                       chunk_free(current);
+                       free(current);
+               }
+               certs->destroy(certs);
+       }
+}
+
+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 (!trusted || (cert != CERT_ANY && cert != CERT_X509))
+       {
+               return NULL;
+       }
+       this->lock->read_lock(this->lock);
+       if (!this->loaded)
+       {
+               this->lock->unlock(this->lock);
+               this->lock->write_lock(this->lock);
+               /* check again after acquiring the write lock */
+               if (!this->loaded)
+               {
+                       load_trusted_certificates(this);
+                       this->loaded = TRUE;
+               }
+               this->lock->unlock(this->lock);
+               this->lock->read_lock(this->lock);
+       }
+       enumerator = this->creds->set.create_cert_enumerator(&this->creds->set,
+                                                                                                       cert, key, id, trusted);
+       return enumerator_create_cleaner(enumerator, (void*)this->lock->unlock,
+                                                                        this->lock);
+}
+
+METHOD(android_creds_t, clear, void,
+       private_android_creds_t *this)
+{
+       this->lock->write_lock(this->lock);
+       this->creds->clear(this->creds);
+       this->loaded = FALSE;
+       this->lock->unlock(this->lock);
+}
+
+METHOD(android_creds_t, destroy, void,
+       private_android_creds_t *this)
+{
+       clear(this);
+       this->creds->destroy(this->creds);
+       this->lock->destroy(this->lock);
+       free(this);
+}
+
+/**
+ * Described in header.
+ */
+android_creds_t *android_creds_create()
+{
+       private_android_creds_t *this;
+
+       INIT(this,
+               .public = {
+                       .set = {
+                               .create_cert_enumerator = _create_cert_enumerator,
+                               .create_shared_enumerator = (void*)return_null,
+                               .create_private_enumerator = (void*)return_null,
+                               .create_cdp_enumerator = (void*)return_null,
+                               .cache_cert = (void*)nop,
+                       },
+                       .clear = _clear,
+                       .destroy = _destroy,
+               },
+               .creds = mem_cred_create(),
+               .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
+       );
+
+       return &this->public;
+}
diff --git a/src/frontends/android/jni/libandroidbridge/backend/android_creds.h b/src/frontends/android/jni/libandroidbridge/backend/android_creds.h
new file mode 100644 (file)
index 0000000..4b19b1b
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 Tobias Brunner
+ * 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
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup android_creds android_creds
+ * @{ @ingroup android_backend
+ */
+
+#ifndef ANDROID_CREDS_H_
+#define ANDROID_CREDS_H_
+
+#include <library.h>
+#include <credentials/credential_set.h>
+
+typedef struct android_creds_t android_creds_t;
+
+/**
+ * Android credential set that provides CA certificates via JNI.
+ */
+struct android_creds_t {
+
+       /**
+        * Implements credential_set_t
+        */
+       credential_set_t set;
+
+       /**
+        * Clear the cached CA certificates.
+        */
+       void (*clear)(android_creds_t *this);
+
+       /**
+        * Destroy a android_creds instance.
+        */
+       void (*destroy)(android_creds_t *this);
+
+};
+
+/**
+ * Create an android_creds instance.
+ */
+android_creds_t *android_creds_create();
+
+#endif /** ANDROID_CREDS_H_ @}*/
+
index ac6df0d..72feb9e 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "charonservice.h"
 #include "android_jni.h"
+#include "backend/android_creds.h"
 #include "kernel/android_ipsec.h"
 #include "kernel/android_net.h"
 
@@ -45,6 +46,11 @@ struct private_charonservice_t {
        charonservice_t public;
 
        /**
+        * android_creds instance
+        */
+       android_creds_t *creds;
+
+       /**
         * CharonVpnService reference
         */
        jobject vpn_service;
@@ -190,6 +196,24 @@ failed:
 }
 
 /**
+ * Initialize/deinitialize Android backend
+ */
+static bool charonservice_register(void *plugin, plugin_feature_t *feature,
+                                                                  bool reg, void *data)
+{
+       private_charonservice_t *this = (private_charonservice_t*)charonservice;
+       if (reg)
+       {
+               lib->credmgr->add_set(lib->credmgr, &this->creds->set);
+       }
+       else
+       {
+               lib->credmgr->remove_set(lib->credmgr, &this->creds->set);
+       }
+       return TRUE;
+}
+
+/**
  * Initialize the charonservice object
  */
 static void charonservice_init(JNIEnv *env, jobject service)
@@ -200,6 +224,9 @@ static void charonservice_init(JNIEnv *env, jobject service)
                        PLUGIN_PROVIDE(CUSTOM, "kernel-net"),
                PLUGIN_CALLBACK(kernel_ipsec_register, kernel_android_ipsec_create),
                        PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"),
+               PLUGIN_CALLBACK((plugin_feature_callback_t)charonservice_register, NULL),
+                       PLUGIN_PROVIDE(CUSTOM, "Android backend"),
+                               PLUGIN_DEPENDS(CUSTOM, "libcharon"),
        };
 
        INIT(this,
@@ -208,6 +235,7 @@ static void charonservice_init(JNIEnv *env, jobject service)
                        .bypass_socket = _bypass_socket,
                        .get_trusted_certificates = _get_trusted_certificates,
                },
+               .creds = android_creds_create(),
                .vpn_service = (*env)->NewGlobalRef(env, service),
        );
        charonservice = &this->public;
@@ -226,6 +254,7 @@ static void charonservice_deinit(JNIEnv *env)
 {
        private_charonservice_t *this = (private_charonservice_t*)charonservice;
 
+       this->creds->destroy(this->creds);
        (*env)->DeleteGlobalRef(env, this->vpn_service);
        free(this);
        charonservice = NULL;
index d0c0b71..e538a22 100644 (file)
@@ -18,6 +18,9 @@
 /**
  * @defgroup libandroidbridge libandroidbridge
  *
+ * @defgroup android_backend backend
+ * @ingroup libandroidbridge
+ *
  * @defgroup android_kernel kernel
  * @ingroup libandroidbridge
  *