From 2bec193a1ba26f04f16169811c92df97ad3389dd Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 8 Aug 2012 12:35:49 +0200 Subject: [PATCH] CharonVpnService provides a function to get trusted certificates via JNI --- .../android/jni/libandroidbridge/charonservice.c | 48 +++++++++++++++++ .../android/jni/libandroidbridge/charonservice.h | 9 ++++ .../strongswan/android/logic/CharonVpnService.java | 61 ++++++++++++++++++++++ 3 files changed, 118 insertions(+) diff --git a/src/frontends/android/jni/libandroidbridge/charonservice.c b/src/frontends/android/jni/libandroidbridge/charonservice.c index 874258b..ac6df0d 100644 --- a/src/frontends/android/jni/libandroidbridge/charonservice.c +++ b/src/frontends/android/jni/libandroidbridge/charonservice.c @@ -142,6 +142,53 @@ failed: return FALSE; } +METHOD(charonservice_t, get_trusted_certificates, linked_list_t*, + private_charonservice_t *this) +{ + JNIEnv *env; + jmethodID method_id; + jobjectArray jcerts; + linked_list_t *list; + jsize i; + + androidjni_attach_thread(&env); + + method_id = (*env)->GetMethodID(env, + android_charonvpnservice_class, + "getTrustedCertificates", "(Ljava/lang/String;)[[B"); + if (!method_id) + { + goto failed; + } + jcerts = (*env)->CallObjectMethod(env, this->vpn_service, method_id, NULL); + if (!jcerts) + { + goto failed; + } + list = linked_list_create(); + for (i = 0; i < (*env)->GetArrayLength(env, jcerts); ++i) + { + chunk_t *ca_cert; + jbyteArray jcert; + + ca_cert = malloc_thing(chunk_t); + list->insert_last(list, ca_cert); + + jcert = (*env)->GetObjectArrayElement(env, jcerts, i); + *ca_cert = chunk_alloc((*env)->GetArrayLength(env, jcert)); + (*env)->GetByteArrayRegion(env, jcert, 0, ca_cert->len, ca_cert->ptr); + (*env)->DeleteLocalRef(env, jcert); + } + (*env)->DeleteLocalRef(env, jcerts); + androidjni_detach_thread(); + return list; + +failed: + androidjni_exception_occurred(env); + androidjni_detach_thread(); + return NULL; +} + /** * Initialize the charonservice object */ @@ -159,6 +206,7 @@ static void charonservice_init(JNIEnv *env, jobject service) .public = { .update_status = _update_status, .bypass_socket = _bypass_socket, + .get_trusted_certificates = _get_trusted_certificates, }, .vpn_service = (*env)->NewGlobalRef(env, service), ); diff --git a/src/frontends/android/jni/libandroidbridge/charonservice.h b/src/frontends/android/jni/libandroidbridge/charonservice.h index c537165..d0c0b71 100644 --- a/src/frontends/android/jni/libandroidbridge/charonservice.h +++ b/src/frontends/android/jni/libandroidbridge/charonservice.h @@ -29,6 +29,7 @@ #define CHARONSERVICE_H_ #include +#include typedef enum android_vpn_state_t android_vpn_state_t; typedef struct charonservice_t charonservice_t; @@ -71,6 +72,14 @@ struct charonservice_t { */ bool (*bypass_socket)(charonservice_t *this, int fd, int family); + /** + * Get a list of trusted certificates via JNI + * + * @return list of DER encoded certificates (as chunk_t*), + * NULL on failure + */ + linked_list_t *(*get_trusted_certificates)(charonservice_t *this); + }; /** diff --git a/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java b/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java index c3bb1ad..d66a551 100644 --- a/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java +++ b/src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java @@ -17,6 +17,10 @@ package org.strongswan.android.logic; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; + import org.strongswan.android.data.VpnProfile; import org.strongswan.android.data.VpnProfileDataSource; import org.strongswan.android.logic.VpnStateService.ErrorState; @@ -329,6 +333,63 @@ public class CharonVpnService extends VpnService implements Runnable } /** + * Function called via JNI to generate a list of DER encoded CA certificates + * as byte array. + * + * @param hash optional alias (only hash part), if given matching certificates are returned + * @return a list of DER encoded CA certificates + */ + private synchronized byte[][] getTrustedCertificates(String hash) + { + ArrayList certs = new ArrayList(); + TrustedCertificateManager certman = TrustedCertificateManager.getInstance(); + try + { + if (hash != null) + { + String alias = "user:" + hash + ".0"; + X509Certificate cert = certman.getCACertificateFromAlias(alias); + if (cert == null) + { + alias = "system:" + hash + ".0"; + cert = certman.getCACertificateFromAlias(alias); + } + if (cert == null) + { + return null; + } + certs.add(cert.getEncoded()); + } + else + { + String alias = this.mCurrentProfile.getCertificateAlias(); + if (alias != null) + { + X509Certificate cert = certman.getCACertificateFromAlias(alias); + if (cert == null) + { + return null; + } + certs.add(cert.getEncoded()); + } + else + { + for (X509Certificate cert : certman.getAllCACertificates().values()) + { + certs.add(cert.getEncoded()); + } + } + } + } + catch (CertificateEncodingException e) + { + e.printStackTrace(); + return null; + } + return certs.toArray(new byte[certs.size()][]); + } + + /** * Initialization of charon, provided by libandroidbridge.so */ public native void initializeCharon(); -- 2.7.4