Annotation of embedaddon/strongswan/src/charon-nm/nm/nm_creds.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2008 Martin Willi
3: * HSR 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: CALLBACK(cert_data_destroy, void,
124: cert_data_t *data)
125: {
126: data->this->lock->unlock(data->this->lock);
127: free(data);
128: }
129:
130: CALLBACK(cert_filter, bool,
131: cert_data_t *data, enumerator_t *orig, va_list args)
132: {
133: certificate_t *cert, **out;
134: public_key_t *public;
135:
136: VA_ARGS_VGET(args, out);
137:
138: while (orig->enumerate(orig, &cert))
139: {
140: public = cert->get_public_key(cert);
141: if (!public)
142: {
143: continue;
144: }
145: if (data->key != KEY_ANY && public->get_type(public) != data->key)
146: {
147: public->destroy(public);
148: continue;
149: }
150: if (data->id && data->id->get_type(data->id) == ID_KEY_ID &&
151: public->has_fingerprint(public, data->id->get_encoding(data->id)))
152: {
153: public->destroy(public);
154: *out = cert;
155: return TRUE;
156: }
157: public->destroy(public);
158: if (data->id && !cert->has_subject(cert, data->id))
159: {
160: continue;
161: }
162: *out = cert;
163: return TRUE;
164: }
165: return FALSE;
166: }
167:
168: /**
169: * Create enumerator for trusted certificates
170: */
171: static enumerator_t *create_trusted_cert_enumerator(private_nm_creds_t *this,
172: key_type_t key, identification_t *id)
173: {
174: cert_data_t *data;
175:
176: INIT(data,
177: .this = this,
178: .id = id,
179: .key = key,
180: );
181:
182: this->lock->read_lock(this->lock);
183: return enumerator_create_filter(
184: this->certs->create_enumerator(this->certs),
185: cert_filter, data, cert_data_destroy);
186: }
187:
188: METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
189: private_nm_creds_t *this, 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: METHOD(credential_set_t, create_private_enumerator, enumerator_t*,
205: private_nm_creds_t *this, key_type_t type, identification_t *id)
206: {
207: if (this->key == NULL)
208: {
209: return NULL;
210: }
211: if (type != KEY_ANY && type != this->key->get_type(this->key))
212: {
213: return NULL;
214: }
215: if (id && id->get_type(id) != ID_ANY)
216: {
217: if (id->get_type(id) != ID_KEY_ID ||
218: !this->key->has_fingerprint(this->key, id->get_encoding(id)))
219: {
220: return NULL;
221: }
222: }
223: this->lock->read_lock(this->lock);
224: return enumerator_create_cleaner(enumerator_create_single(this->key, NULL),
225: (void*)this->lock->unlock, this->lock);
226: }
227:
228: /**
229: * shared key enumerator implementation
230: */
231: typedef struct {
232: enumerator_t public;
233: private_nm_creds_t *this;
234: shared_key_t *key;
235: bool done;
236: } shared_enumerator_t;
237:
238: METHOD(enumerator_t, shared_enumerate, bool,
239: shared_enumerator_t *this, va_list args)
240: {
241: shared_key_t **key;
242: id_match_t *me, *other;
243:
244: VA_ARGS_VGET(args, key, me, other);
245:
246: if (this->done)
247: {
248: return FALSE;
249: }
250: *key = this->key;
251: if (me)
252: {
253: *me = ID_MATCH_PERFECT;
254: }
255: if (other)
256: {
257: *other = ID_MATCH_ANY;
258: }
259: this->done = TRUE;
260: return TRUE;
261: }
262:
263: METHOD(enumerator_t, shared_destroy, void,
264: shared_enumerator_t *this)
265: {
266: this->key->destroy(this->key);
267: this->this->lock->unlock(this->this->lock);
268: free(this);
269: }
270:
271: METHOD(credential_set_t, create_shared_enumerator, enumerator_t*,
272: private_nm_creds_t *this, shared_key_type_t type, identification_t *me,
273: identification_t *other)
274: {
275: shared_enumerator_t *enumerator;
276: chunk_t key;
277:
278: this->lock->read_lock(this->lock);
279:
280: switch (type)
281: {
282: case SHARED_EAP:
283: case SHARED_IKE:
284: if (!this->pass || !this->user)
285: {
286: goto no_secret;
287: }
288: if (me && !me->matches(me, this->user))
289: {
290: goto no_secret;
291: }
292: key = chunk_create(this->pass, strlen(this->pass));
293: break;
294: case SHARED_PRIVATE_KEY_PASS:
295: if (!this->keypass)
296: {
297: goto no_secret;
298: }
299: key = chunk_create(this->keypass, strlen(this->keypass));
300: break;
301: case SHARED_PIN:
302: if (!this->keypass || !me ||
303: !chunk_equals(me->get_encoding(me), this->keyid))
304: {
305: goto no_secret;
306: }
307: key = chunk_create(this->keypass, strlen(this->keypass));
308: break;
309: default:
310: goto no_secret;
311: }
312:
313: INIT(enumerator,
314: .public = {
315: .enumerate = enumerator_enumerate_default,
316: .venumerate = _shared_enumerate,
317: .destroy = _shared_destroy,
318: },
319: .this = this,
320: );
321: enumerator->key = shared_key_create(type, chunk_clone(key));
322: return &enumerator->public;
323:
324: no_secret:
325: this->lock->unlock(this->lock);
326: return NULL;
327: }
328:
329: METHOD(nm_creds_t, add_certificate, void,
330: private_nm_creds_t *this, certificate_t *cert)
331: {
332: this->lock->write_lock(this->lock);
333: this->certs->insert_last(this->certs, cert);
334: this->lock->unlock(this->lock);
335: }
336:
337: /**
338: * Load a certificate file
339: */
340: static void load_ca_file(private_nm_creds_t *this, char *file)
341: {
342: certificate_t *cert;
343:
344: /* We add the CA constraint, as many CAs miss it */
345: cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
346: BUILD_FROM_FILE, file, BUILD_END);
347: if (!cert)
348: {
349: DBG1(DBG_CFG, "loading CA certificate '%s' failed", file);
350: }
351: else
352: {
353: DBG2(DBG_CFG, "loaded CA certificate '%Y'", cert->get_subject(cert));
354: x509_t *x509 = (x509_t*)cert;
355: if (!(x509->get_flags(x509) & X509_SELF_SIGNED))
356: {
357: DBG1(DBG_CFG, "%Y is not self signed", cert->get_subject(cert));
358: }
359: this->certs->insert_last(this->certs, cert);
360: }
361: }
362:
363: METHOD(nm_creds_t, load_ca_dir, void,
364: private_nm_creds_t *this, char *dir)
365: {
366: enumerator_t *enumerator;
367: char *rel, *abs;
368: struct stat st;
369:
370: enumerator = enumerator_create_directory(dir);
371: if (enumerator)
372: {
373: while (enumerator->enumerate(enumerator, &rel, &abs, &st))
374: {
375: /* skip '.', '..' and hidden files */
376: if (rel[0] != '.')
377: {
378: if (S_ISDIR(st.st_mode))
379: {
380: load_ca_dir(this, abs);
381: }
382: else if (S_ISREG(st.st_mode))
383: {
384: load_ca_file(this, abs);
385: }
386: }
387: }
388: enumerator->destroy(enumerator);
389: }
390: }
391:
392: METHOD(nm_creds_t, set_username_password, void,
393: private_nm_creds_t *this, identification_t *id, char *password)
394: {
395: this->lock->write_lock(this->lock);
396: DESTROY_IF(this->user);
397: this->user = id->clone(id);
398: free(this->pass);
399: this->pass = strdupnull(password);
400: this->lock->unlock(this->lock);
401: }
402:
403: METHOD(nm_creds_t, set_key_password, void,
404: private_nm_creds_t *this, char *password)
405: {
406: this->lock->write_lock(this->lock);
407: free(this->keypass);
408: this->keypass = strdupnull(password);
409: this->lock->unlock(this->lock);
410: }
411:
412: METHOD(nm_creds_t, set_pin, void,
413: private_nm_creds_t *this, chunk_t keyid, char *pin)
414: {
415: this->lock->write_lock(this->lock);
416: free(this->keypass);
417: free(this->keyid.ptr);
418: this->keypass = strdupnull(pin);
419: this->keyid = chunk_clone(keyid);
420: this->lock->unlock(this->lock);
421: }
422:
423: METHOD(nm_creds_t, set_cert_and_key, void,
424: private_nm_creds_t *this, certificate_t *cert, private_key_t *key)
425: {
426: this->lock->write_lock(this->lock);
427: DESTROY_IF(this->key);
428: DESTROY_IF(this->usercert);
429: this->key = key;
430: this->usercert = cert;
431: this->lock->unlock(this->lock);
432: }
433:
434: METHOD(nm_creds_t, clear, void,
435: private_nm_creds_t *this)
436: {
437: certificate_t *cert;
438:
439: while (this->certs->remove_last(this->certs, (void**)&cert) == SUCCESS)
440: {
441: cert->destroy(cert);
442: }
443: DESTROY_IF(this->user);
444: free(this->pass);
445: free(this->keypass);
446: free(this->keyid.ptr);
447: DESTROY_IF(this->usercert);
448: DESTROY_IF(this->key);
449: this->key = NULL;
450: this->usercert = NULL;
451: this->pass = NULL;
452: this->user = NULL;
453: this->keypass = NULL;
454: this->keyid = chunk_empty;
455: }
456:
457: METHOD(nm_creds_t, destroy, void,
458: private_nm_creds_t *this)
459: {
460: clear(this);
461: this->certs->destroy(this->certs);
462: this->lock->destroy(this->lock);
463: free(this);
464: }
465:
466: /*
467: * see header file
468: */
469: nm_creds_t *nm_creds_create()
470: {
471: private_nm_creds_t *this;
472:
473: INIT(this,
474: .public = {
475: .set = {
476: .create_private_enumerator = _create_private_enumerator,
477: .create_cert_enumerator = _create_cert_enumerator,
478: .create_shared_enumerator = _create_shared_enumerator,
479: .create_cdp_enumerator = (void*)return_null,
480: .cache_cert = (void*)nop,
481: },
482: .add_certificate = _add_certificate,
483: .load_ca_dir = _load_ca_dir,
484: .set_username_password = _set_username_password,
485: .set_key_password = _set_key_password,
486: .set_pin = _set_pin,
487: .set_cert_and_key = _set_cert_and_key,
488: .clear = _clear,
489: .destroy = _destroy,
490: },
491: .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
492: .certs = linked_list_create(),
493: );
494: return &this->public;
495: }
496:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>