/* * 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 . * * 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 #include #include #include 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 and user credentials */ 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**)¤t) == 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, add_username_password, void, private_android_creds_t *this, char *username, char *password) { shared_key_t *shared_key; identification_t *id; chunk_t secret; secret = chunk_create(password, strlen(password)); shared_key = shared_key_create(SHARED_EAP, chunk_clone(secret)); id = identification_create_from_string(username); this->creds->add_shared(this->creds, shared_key, id, NULL); } METHOD(credential_set_t, create_shared_enumerator, enumerator_t*, private_android_creds_t *this, shared_key_type_t type, identification_t *me, identification_t *other) { return this->creds->set.create_shared_enumerator(&this->creds->set, type, me, other); } 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 = _create_shared_enumerator, .create_private_enumerator = (void*)return_null, .create_cdp_enumerator = (void*)return_null, .cache_cert = (void*)nop, }, .add_username_password = _add_username_password, .clear = _clear, .destroy = _destroy, }, .creds = mem_cred_create(), .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), ); return &this->public; }