Adding an Android specific credential set.
[strongswan.git] / src / libcharon / plugins / android / android_creds.c
1 /*
2 * Copyright (C) 2010 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <keystore_get.h>
17
18 #include "android_creds.h"
19
20 #include <daemon.h>
21 #include <threading/rwlock.h>
22
23 typedef struct private_android_creds_t private_android_creds_t;
24
25 /**
26 * Private data of an android_creds_t object
27 */
28 struct private_android_creds_t {
29
30 /**
31 * Public interface
32 */
33 android_creds_t public;
34
35 /**
36 * List of trusted certificates, certificate_t*
37 */
38 linked_list_t *certs;
39
40 /**
41 * User name (ID)
42 */
43 identification_t *user;
44
45 /**
46 * User password
47 */
48 char *pass;
49
50 /**
51 * read/write lock
52 */
53 rwlock_t *lock;
54
55 };
56
57 /**
58 * Certificate enumerator data
59 */
60 typedef struct {
61 private_android_creds_t *this;
62 key_type_t key;
63 identification_t *id;
64 } cert_data_t;
65
66 /**
67 * Filter function for certificates enumerator
68 */
69 static bool cert_filter(cert_data_t *data, certificate_t **in,
70 certificate_t **out)
71 {
72 certificate_t *cert = *in;
73 public_key_t *public;
74
75 public = cert->get_public_key(cert);
76 if (!public)
77 {
78 return FALSE;
79 }
80 if (data->key != KEY_ANY && public->get_type(public) != data->key)
81 {
82 public->destroy(public);
83 return FALSE;
84 }
85 if (data->id && data->id->get_type(data->id) == ID_KEY_ID &&
86 public->has_fingerprint(public, data->id->get_encoding(data->id)))
87 {
88 public->destroy(public);
89 *out = cert;
90 return TRUE;
91 }
92 public->destroy(public);
93 if (data->id && !cert->has_subject(cert, data->id))
94 {
95 return FALSE;
96 }
97 *out = cert;
98 return TRUE;
99 }
100
101 /**
102 * Destroy certificate enumerator data
103 */
104 static void cert_data_destroy(cert_data_t *this)
105 {
106 this->this->lock->unlock(this->this->lock);
107 free(this);
108 }
109
110 METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
111 private_android_creds_t *this, certificate_type_t cert, key_type_t key,
112 identification_t *id, bool trusted)
113 {
114 if (cert == CERT_X509 || cert == CERT_ANY)
115 {
116 cert_data_t *data;
117 this->lock->read_lock(this->lock);
118 INIT(data, .this = this, .id = id, .key = key);
119 return enumerator_create_filter(
120 this->certs->create_enumerator(this->certs),
121 (void*)cert_filter, data, (void*)cert_data_destroy);
122 }
123 return NULL;
124 }
125
126 /**
127 * Shared key enumerator implementation
128 */
129 typedef struct {
130 enumerator_t public;
131 private_android_creds_t *this;
132 shared_key_t *key;
133 bool done;
134 } shared_enumerator_t;
135
136 METHOD(enumerator_t, shared_enumerate, bool,
137 shared_enumerator_t *this, shared_key_t **key, id_match_t *me,
138 id_match_t *other)
139 {
140 if (this->done)
141 {
142 return FALSE;
143 }
144 *key = this->key;
145 *me = ID_MATCH_PERFECT;
146 *other = ID_MATCH_ANY;
147 this->done = TRUE;
148 return TRUE;
149 }
150
151 METHOD(enumerator_t, shared_destroy, void,
152 shared_enumerator_t *this)
153 {
154 this->key->destroy(this->key);
155 this->this->lock->unlock(this->this->lock);
156 free(this);
157 }
158
159 METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
160 private_android_creds_t *this, shared_key_type_t type,
161 identification_t *me, identification_t *other)
162 {
163 shared_enumerator_t *enumerator;
164
165 this->lock->read_lock(this->lock);
166
167 if (!this->user || !this->pass)
168 {
169 this->lock->unlock(this->lock);
170 return NULL;
171 }
172 if (type != SHARED_EAP && type != SHARED_IKE)
173 {
174 this->lock->unlock(this->lock);
175 return NULL;
176 }
177 if (me && !me->equals(me, this->user))
178 {
179 this->lock->unlock(this->lock);
180 return NULL;
181 }
182
183 INIT(enumerator,
184 .public = {
185 .enumerate = (void*)_shared_enumerate,
186 .destroy = _shared_destroy,
187 },
188 .this = this,
189 .done = FALSE,
190 .key = shared_key_create(type, chunk_clone(chunk_create(this->pass,
191 strlen(this->pass)))),
192 );
193 return &enumerator->public;
194 }
195
196 METHOD(android_creds_t, add_certificate, bool,
197 private_android_creds_t *this, char *name)
198 {
199 certificate_t *cert = NULL;
200 bool status = FALSE;
201 chunk_t chunk;
202 this->lock->write_lock(this->lock);
203 chunk.ptr = keystore_get(name, &chunk.len);
204 if (chunk.ptr)
205 {
206 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
207 BUILD_BLOB_PEM, chunk, BUILD_END);
208 if (cert)
209 {
210 this->certs->insert_last(this->certs, cert);
211 status = TRUE;
212 }
213 free(chunk.ptr);
214 }
215 this->lock->unlock(this->lock);
216 return status;
217 }
218
219 METHOD(android_creds_t, set_username_password, void,
220 private_android_creds_t *this, identification_t *id, char *password)
221 {
222 this->lock->write_lock(this->lock);
223 DESTROY_IF(this->user);
224 this->user = id->clone(id);
225 free(this->pass);
226 this->pass = password ? strdup(password) : NULL;
227 this->lock->unlock(this->lock);
228 }
229
230 METHOD(android_creds_t, clear, void,
231 private_android_creds_t *this)
232 {
233 certificate_t *cert;
234 this->lock->write_lock(this->lock);
235 while (this->certs->remove_last(this->certs, (void**)&cert) == SUCCESS)
236 {
237 cert->destroy(cert);
238 }
239 DESTROY_IF(this->user);
240 free(this->pass);
241 this->user = NULL;
242 this->pass = NULL;
243 this->lock->unlock(this->lock);
244 }
245
246 METHOD(android_creds_t, destroy, void,
247 private_android_creds_t *this)
248 {
249 clear(this);
250 this->certs->destroy(this->certs);
251 this->lock->destroy(this->lock);
252 free(this);
253 }
254
255 /**
256 * Described in header.
257 */
258 android_creds_t *android_creds_create()
259 {
260 private_android_creds_t *this;
261
262 INIT(this,
263 .public = {
264 .set = {
265 .create_cert_enumerator = _create_cert_enumerator,
266 .create_shared_enumerator = _create_shared_enumerator,
267 .create_private_enumerator = (void*)return_null,
268 .create_cdp_enumerator = (void*)return_null,
269 .cache_cert = (void*)nop,
270 },
271 .add_certificate = _add_certificate,
272 .set_username_password = _set_username_password,
273 .clear = _clear,
274 .destroy = _destroy,
275 },
276 .certs = linked_list_create(),
277 .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
278 );
279
280 return &this->public;
281 }
282