4ee94362fed35c262246b51e79c108a0ec2ac7f5
[strongswan.git] / src / libcharon / plugins / nm / nm_creds.c
1 /*
2 * Copyright (C) 2008 Martin Willi
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 "nm_creds.h"
17
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21
22 #include <daemon.h>
23 #include <threading/rwlock.h>
24 #include <credentials/certificates/x509.h>
25
26 typedef struct private_nm_creds_t private_nm_creds_t;
27
28 /**
29 * private data of nm_creds
30 */
31 struct private_nm_creds_t {
32
33 /**
34 * public functions
35 */
36 nm_creds_t public;
37
38 /**
39 * List of trusted certificates, certificate_t*
40 */
41 linked_list_t *certs;
42
43 /**
44 * User name
45 */
46 identification_t *user;
47
48 /**
49 * User password
50 */
51 char *pass;
52
53 /**
54 * Private key decryption password
55 */
56 char *keypass;
57
58 /**
59 * users certificate
60 */
61 certificate_t *usercert;
62
63 /**
64 * users private key
65 */
66 private_key_t *key;
67
68 /**
69 * read/write lock
70 */
71 rwlock_t *lock;
72 };
73
74 /**
75 * Enumerator for user certificate
76 */
77 static enumerator_t *create_usercert_enumerator(private_nm_creds_t *this,
78 certificate_type_t cert, key_type_t key)
79 {
80 public_key_t *public;
81
82 if (cert != CERT_ANY && cert != this->usercert->get_type(this->usercert))
83 {
84 return NULL;
85 }
86 if (key != KEY_ANY)
87 {
88 public = this->usercert->get_public_key(this->usercert);
89 if (!public)
90 {
91 return NULL;
92 }
93 if (public->get_type(public) != key)
94 {
95 public->destroy(public);
96 return NULL;
97 }
98 public->destroy(public);
99 }
100 this->lock->read_lock(this->lock);
101 return enumerator_create_cleaner(
102 enumerator_create_single(this->usercert, NULL),
103 (void*)this->lock->unlock, this->lock);
104 }
105
106 /**
107 * CA certificate enumerator data
108 */
109 typedef struct {
110 /** ref to credential credential store */
111 private_nm_creds_t *this;
112 /** type of key we are looking for */
113 key_type_t key;
114 /** CA certificate ID */
115 identification_t *id;
116 } cert_data_t;
117
118 /**
119 * Destroy CA certificate enumerator data
120 */
121 static void cert_data_destroy(cert_data_t *data)
122 {
123 data->this->lock->unlock(data->this->lock);
124 free(data);
125 }
126
127 /**
128 * Filter function for certificates enumerator
129 */
130 static bool cert_filter(cert_data_t *data, certificate_t **in,
131 certificate_t **out)
132 {
133 certificate_t *cert = *in;
134 public_key_t *public;
135
136 public = cert->get_public_key(cert);
137 if (!public)
138 {
139 return FALSE;
140 }
141 if (data->key != KEY_ANY && public->get_type(public) != data->key)
142 {
143 public->destroy(public);
144 return FALSE;
145 }
146 if (data->id && data->id->get_type(data->id) == ID_KEY_ID &&
147 public->has_fingerprint(public, data->id->get_encoding(data->id)))
148 {
149 public->destroy(public);
150 *out = cert;
151 return TRUE;
152 }
153 public->destroy(public);
154 if (data->id && !cert->has_subject(cert, data->id))
155 {
156 return FALSE;
157 }
158 *out = cert;
159 return TRUE;
160 }
161
162 /**
163 * Create enumerator for trusted certificates
164 */
165 static enumerator_t *create_trusted_cert_enumerator(private_nm_creds_t *this,
166 key_type_t key, identification_t *id)
167 {
168 cert_data_t *data = malloc_thing(cert_data_t);
169
170 data->this = this;
171 data->id = id;
172 data->key = key;
173
174 this->lock->read_lock(this->lock);
175 return enumerator_create_filter(
176 this->certs->create_enumerator(this->certs),
177 (void*)cert_filter, data, (void*)cert_data_destroy);
178 }
179
180 /**
181 * Implements credential_set_t.create_cert_enumerator
182 */
183 static enumerator_t* create_cert_enumerator(private_nm_creds_t *this,
184 certificate_type_t cert, key_type_t key,
185 identification_t *id, bool trusted)
186 {
187 if (id && this->usercert &&
188 id->equals(id, this->usercert->get_subject(this->usercert)))
189 {
190 return create_usercert_enumerator(this, cert, key);
191 }
192 if (cert == CERT_X509 || cert == CERT_ANY)
193 {
194 return create_trusted_cert_enumerator(this, key, id);
195 }
196 return NULL;
197 }
198
199 /**
200 * Implements credential_set_t.create_cert_enumerator
201 */
202 static enumerator_t* create_private_enumerator(private_nm_creds_t *this,
203 key_type_t type, identification_t *id)
204 {
205 if (this->key == NULL)
206 {
207 return NULL;
208 }
209 if (type != KEY_ANY && type != this->key->get_type(this->key))
210 {
211 return NULL;
212 }
213 if (id && id->get_type(id) != ID_ANY)
214 {
215 if (id->get_type(id) != ID_KEY_ID ||
216 !this->key->has_fingerprint(this->key, id->get_encoding(id)))
217 {
218 return NULL;
219 }
220 }
221 this->lock->read_lock(this->lock);
222 return enumerator_create_cleaner(enumerator_create_single(this->key, NULL),
223 (void*)this->lock->unlock, this->lock);
224 }
225
226 /**
227 * shared key enumerator implementation
228 */
229 typedef struct {
230 enumerator_t public;
231 private_nm_creds_t *this;
232 shared_key_t *key;
233 bool done;
234 } shared_enumerator_t;
235
236 /**
237 * enumerate function for shared enumerator
238 */
239 static bool shared_enumerate(shared_enumerator_t *this, shared_key_t **key,
240 id_match_t *me, id_match_t *other)
241 {
242 if (this->done)
243 {
244 return FALSE;
245 }
246 *key = this->key;
247 if (me)
248 {
249 *me = ID_MATCH_PERFECT;
250 }
251 if (other)
252 {
253 *other = ID_MATCH_ANY;
254 }
255 this->done = TRUE;
256 return TRUE;
257 }
258
259 /**
260 * Destroy function for shared enumerator
261 */
262 static void shared_destroy(shared_enumerator_t *this)
263 {
264 this->key->destroy(this->key);
265 this->this->lock->unlock(this->this->lock);
266 free(this);
267 }
268 /**
269 * Implements credential_set_t.create_cert_enumerator
270 */
271 static enumerator_t* create_shared_enumerator(private_nm_creds_t *this,
272 shared_key_type_t type, identification_t *me,
273 identification_t *other)
274 {
275 shared_enumerator_t *enumerator;
276 chunk_t key;
277
278 switch (type)
279 {
280 case SHARED_EAP:
281 case SHARED_IKE:
282 if (!this->pass || !this->user)
283 {
284 return NULL;
285 }
286 if (me && !me->equals(me, this->user))
287 {
288 return NULL;
289 }
290 key = chunk_create(this->pass, strlen(this->pass));
291 break;
292 case SHARED_PRIVATE_KEY_PASS:
293 if (!this->keypass)
294 {
295 return NULL;
296 }
297 key = chunk_create(this->keypass, strlen(this->keypass));
298 break;
299 default:
300 return NULL;
301 }
302
303 enumerator = malloc_thing(shared_enumerator_t);
304 enumerator->public.enumerate = (void*)shared_enumerate;
305 enumerator->public.destroy = (void*)shared_destroy;
306 enumerator->this = this;
307 enumerator->done = FALSE;
308 this->lock->read_lock(this->lock);
309 enumerator->key = shared_key_create(type, chunk_clone(key));
310 return &enumerator->public;
311 }
312
313 /**
314 * Implementation of nm_creds_t.add_certificate
315 */
316 static void add_certificate(private_nm_creds_t *this, certificate_t *cert)
317 {
318 this->lock->write_lock(this->lock);
319 this->certs->insert_last(this->certs, cert);
320 this->lock->unlock(this->lock);
321 }
322
323 /**
324 * Load a certificate file
325 */
326 static void load_ca_file(private_nm_creds_t *this, char *file)
327 {
328 certificate_t *cert;
329
330 /* We add the CA constraint, as many CAs miss it */
331 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
332 BUILD_FROM_FILE, file, BUILD_END);
333 if (!cert)
334 {
335 DBG1(DBG_CFG, "loading CA certificate '%s' failed", file);
336 }
337 else
338 {
339 DBG2(DBG_CFG, "loaded CA certificate '%Y'", cert->get_subject(cert));
340 x509_t *x509 = (x509_t*)cert;
341 if (!(x509->get_flags(x509) & X509_SELF_SIGNED))
342 {
343 DBG1(DBG_CFG, "%Y is not self signed", cert->get_subject(cert));
344 }
345 this->certs->insert_last(this->certs, cert);
346 }
347 }
348
349 /**
350 * Implementation of nm_creds_t.load_ca_dir
351 */
352 static void load_ca_dir(private_nm_creds_t *this, char *dir)
353 {
354 enumerator_t *enumerator;
355 char *rel, *abs;
356 struct stat st;
357
358 enumerator = enumerator_create_directory(dir);
359 if (enumerator)
360 {
361 while (enumerator->enumerate(enumerator, &rel, &abs, &st))
362 {
363 /* skip '.', '..' and hidden files */
364 if (rel[0] != '.')
365 {
366 if (S_ISDIR(st.st_mode))
367 {
368 load_ca_dir(this, abs);
369 }
370 else if (S_ISREG(st.st_mode))
371 {
372 load_ca_file(this, abs);
373 }
374 }
375 }
376 enumerator->destroy(enumerator);
377 }
378 }
379
380 /**
381 * Implementation of nm_creds_t.set_password
382 */
383 static void set_username_password(private_nm_creds_t *this, identification_t *id,
384 char *password)
385 {
386 this->lock->write_lock(this->lock);
387 DESTROY_IF(this->user);
388 this->user = id->clone(id);
389 free(this->pass);
390 this->pass = password ? strdup(password) : NULL;
391 this->lock->unlock(this->lock);
392 }
393
394 /**
395 * Implementation of nm_creds_t.set_key_password
396 */
397 static void set_key_password(private_nm_creds_t *this, char *password)
398 {
399 this->lock->write_lock(this->lock);
400 free(this->keypass);
401 this->keypass = password ? strdup(password) : NULL;
402 this->lock->unlock(this->lock);
403 }
404
405 /**
406 * Implementation of nm_creds_t.set_cert_and_key
407 */
408 static void set_cert_and_key(private_nm_creds_t *this, certificate_t *cert,
409 private_key_t *key)
410 {
411 this->lock->write_lock(this->lock);
412 DESTROY_IF(this->key);
413 DESTROY_IF(this->usercert);
414 this->key = key;
415 this->usercert = cert;
416 this->lock->unlock(this->lock);
417 }
418
419 /**
420 * Implementation of nm_creds_t.clear
421 */
422 static void clear(private_nm_creds_t *this)
423 {
424 certificate_t *cert;
425
426 while (this->certs->remove_last(this->certs, (void**)&cert) == SUCCESS)
427 {
428 cert->destroy(cert);
429 }
430 DESTROY_IF(this->user);
431 free(this->pass);
432 DESTROY_IF(this->usercert);
433 DESTROY_IF(this->key);
434 this->key = NULL;
435 this->usercert = NULL;
436 this->pass = NULL;
437 this->user = NULL;
438 }
439
440 /**
441 * Implementation of nm_creds_t.destroy
442 */
443 static void destroy(private_nm_creds_t *this)
444 {
445 clear(this);
446 this->certs->destroy(this->certs);
447 this->lock->destroy(this->lock);
448 free(this);
449 }
450
451 /*
452 * see header file
453 */
454 nm_creds_t *nm_creds_create()
455 {
456 private_nm_creds_t *this = malloc_thing(private_nm_creds_t);
457
458 this->public.set.create_private_enumerator = (void*)create_private_enumerator;
459 this->public.set.create_cert_enumerator = (void*)create_cert_enumerator;
460 this->public.set.create_shared_enumerator = (void*)create_shared_enumerator;
461 this->public.set.create_cdp_enumerator = (void*)return_null;
462 this->public.set.cache_cert = (void*)nop;
463 this->public.add_certificate = (void(*)(nm_creds_t*, certificate_t *cert))add_certificate;
464 this->public.load_ca_dir = (void(*)(nm_creds_t*, char *dir))load_ca_dir;
465 this->public.set_username_password = (void(*)(nm_creds_t*, identification_t *id, char *password))set_username_password;
466 this->public.set_key_password = (void(*)(nm_creds_t*, char *password))set_key_password;
467 this->public.set_cert_and_key = (void(*)(nm_creds_t*, certificate_t *cert, private_key_t *key))set_cert_and_key;
468 this->public.clear = (void(*)(nm_creds_t*))clear;
469 this->public.destroy = (void(*)(nm_creds_t*))destroy;
470
471 this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
472
473 this->certs = linked_list_create();
474 this->user = NULL;
475 this->pass = NULL;
476 this->usercert = NULL;
477 this->key = NULL;
478
479 return &this->public;
480 }
481