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