From: Tobias Brunner Date: Mon, 21 Aug 2017 13:53:20 +0000 (+0200) Subject: android: Cache CRLs in app directory X-Git-Tag: 5.6.1dr2~10^2~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0bebbae9e3834442ce5b5fbc30f9cafb9784ae9e;p=thirdparty%2Fstrongswan.git android: Cache CRLs in app directory Fixes #2405. --- diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_creds.c b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_creds.c index ddc032638e..0c460a9cf5 100644 --- a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_creds.c +++ b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_creds.c @@ -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 @@ -13,6 +13,11 @@ * for more details. */ +#include +#include +#include +#include + #include "android_creds.h" #include "../charonservice.h" @@ -21,6 +26,8 @@ #include #include +#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, ¬After)) + { + 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, ¬After); + 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 ///crl-[-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; diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_creds.h b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_creds.h index 918708f145..869e0afead 100644 --- a/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_creds.h +++ b/src/frontends/android/app/src/main/jni/libandroidbridge/backend/android_creds.h @@ -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_ @}*/ diff --git a/src/frontends/android/app/src/main/jni/libandroidbridge/charonservice.c b/src/frontends/android/app/src/main/jni/libandroidbridge/charonservice.c index 5eb1bd9c0d..62427338ae 100644 --- a/src/frontends/android/app/src/main/jni/libandroidbridge/charonservice.c +++ b/src/frontends/android/app/src/main/jni/libandroidbridge/charonservice.c @@ -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(),