]>
Commit | Line | Data |
---|---|---|
ec249871 MW |
1 | /* |
2 | * Copyright (C) 2008 Martin Willi | |
ec249871 MW |
3 | * |
4 | * This program is free software; you can redistribute it and/or modify it | |
5 | * under the terms of the GNU General Public License as published by the | |
6 | * Free Software Foundation; either version 2 of the License, or (at your | |
7 | * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, but | |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
11 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 | * for more details. | |
ec249871 MW |
13 | */ |
14 | ||
ec249871 MW |
15 | #include "nm_creds.h" |
16 | ||
85af7a89 MW |
17 | #include <sys/types.h> |
18 | #include <sys/stat.h> | |
19 | #include <unistd.h> | |
20 | ||
ec249871 | 21 | #include <daemon.h> |
eba64cef | 22 | #include <threading/rwlock.h> |
85af7a89 | 23 | #include <credentials/certificates/x509.h> |
ec249871 MW |
24 | |
25 | typedef struct private_nm_creds_t private_nm_creds_t; | |
26 | ||
27 | /** | |
28 | * private data of nm_creds | |
29 | */ | |
30 | struct private_nm_creds_t { | |
31 | ||
32 | /** | |
33 | * public functions | |
34 | */ | |
35 | nm_creds_t public; | |
7daf5226 | 36 | |
ec249871 | 37 | /** |
85af7a89 | 38 | * List of trusted certificates, certificate_t* |
ec249871 | 39 | */ |
85af7a89 | 40 | linked_list_t *certs; |
7daf5226 | 41 | |
142eaea4 | 42 | /** |
7b3814f7 MW |
43 | * User name |
44 | */ | |
45 | identification_t *user; | |
7daf5226 | 46 | |
ec249871 MW |
47 | /** |
48 | * User password | |
49 | */ | |
50 | char *pass; | |
7daf5226 | 51 | |
15177f57 | 52 | /** |
8bec0f51 | 53 | * Private key decryption password / smartcard pin |
15177f57 MW |
54 | */ |
55 | char *keypass; | |
56 | ||
8bec0f51 MW |
57 | /** |
58 | * private key ID of smartcard key | |
59 | */ | |
60 | chunk_t keyid; | |
61 | ||
aff26a62 MW |
62 | /** |
63 | * users certificate | |
64 | */ | |
65 | certificate_t *usercert; | |
7daf5226 | 66 | |
aff26a62 MW |
67 | /** |
68 | * users private key | |
69 | */ | |
70 | private_key_t *key; | |
7daf5226 | 71 | |
ec249871 MW |
72 | /** |
73 | * read/write lock | |
74 | */ | |
27ed987e | 75 | rwlock_t *lock; |
ec249871 MW |
76 | }; |
77 | ||
aff26a62 | 78 | /** |
8dbf40d1 | 79 | * Enumerator for user certificate (lock has to be locked) |
aff26a62 MW |
80 | */ |
81 | static enumerator_t *create_usercert_enumerator(private_nm_creds_t *this, | |
82 | certificate_type_t cert, key_type_t key) | |
83 | { | |
aff26a62 MW |
84 | return enumerator_create_cleaner( |
85 | enumerator_create_single(this->usercert, NULL), | |
27ed987e | 86 | (void*)this->lock->unlock, this->lock); |
aff26a62 MW |
87 | } |
88 | ||
85af7a89 MW |
89 | /** |
90 | * CA certificate enumerator data | |
91 | */ | |
92 | typedef struct { | |
93 | /** ref to credential credential store */ | |
94 | private_nm_creds_t *this; | |
8dbf40d1 TB |
95 | /** certificate type we are looking for */ |
96 | certificate_type_t type; | |
85af7a89 MW |
97 | /** type of key we are looking for */ |
98 | key_type_t key; | |
99 | /** CA certificate ID */ | |
100 | identification_t *id; | |
101 | } cert_data_t; | |
102 | ||
525cc46c TB |
103 | CALLBACK(cert_data_destroy, void, |
104 | cert_data_t *data) | |
85af7a89 MW |
105 | { |
106 | data->this->lock->unlock(data->this->lock); | |
107 | free(data); | |
108 | } | |
109 | ||
525cc46c TB |
110 | CALLBACK(cert_filter, bool, |
111 | cert_data_t *data, enumerator_t *orig, va_list args) | |
85af7a89 | 112 | { |
525cc46c | 113 | certificate_t *cert, **out; |
85af7a89 | 114 | |
525cc46c TB |
115 | VA_ARGS_VGET(args, out); |
116 | ||
117 | while (orig->enumerate(orig, &cert)) | |
85af7a89 | 118 | { |
8dbf40d1 | 119 | if (certificate_matches(cert, data->type, data->key, data->id)) |
525cc46c | 120 | { |
525cc46c TB |
121 | *out = cert; |
122 | return TRUE; | |
123 | } | |
85af7a89 | 124 | } |
525cc46c | 125 | return FALSE; |
85af7a89 MW |
126 | } |
127 | ||
128 | /** | |
8dbf40d1 | 129 | * Create enumerator for trusted certificates (lock has to be locked) |
85af7a89 MW |
130 | */ |
131 | static enumerator_t *create_trusted_cert_enumerator(private_nm_creds_t *this, | |
8dbf40d1 TB |
132 | certificate_type_t type, key_type_t key, |
133 | identification_t *id) | |
85af7a89 | 134 | { |
65a07156 | 135 | cert_data_t *data; |
85af7a89 | 136 | |
65a07156 TB |
137 | INIT(data, |
138 | .this = this, | |
8dbf40d1 | 139 | .type = type, |
65a07156 | 140 | .key = key, |
8dbf40d1 | 141 | .id = id, |
65a07156 | 142 | ); |
85af7a89 | 143 | |
85af7a89 MW |
144 | return enumerator_create_filter( |
145 | this->certs->create_enumerator(this->certs), | |
525cc46c | 146 | cert_filter, data, cert_data_destroy); |
85af7a89 MW |
147 | } |
148 | ||
65a07156 TB |
149 | METHOD(credential_set_t, create_cert_enumerator, enumerator_t*, |
150 | private_nm_creds_t *this, certificate_type_t cert, key_type_t key, | |
151 | identification_t *id, bool trusted) | |
ec249871 | 152 | { |
8dbf40d1 TB |
153 | this->lock->read_lock(this->lock); |
154 | ||
aff26a62 | 155 | if (id && this->usercert && |
8dbf40d1 | 156 | certificate_matches(this->usercert, cert, key, id)) |
aff26a62 MW |
157 | { |
158 | return create_usercert_enumerator(this, cert, key); | |
159 | } | |
8dbf40d1 | 160 | return create_trusted_cert_enumerator(this, cert, key, id); |
ec249871 MW |
161 | } |
162 | ||
65a07156 TB |
163 | METHOD(credential_set_t, create_private_enumerator, enumerator_t*, |
164 | private_nm_creds_t *this, key_type_t type, identification_t *id) | |
aff26a62 MW |
165 | { |
166 | if (this->key == NULL) | |
167 | { | |
168 | return NULL; | |
169 | } | |
170 | if (type != KEY_ANY && type != this->key->get_type(this->key)) | |
171 | { | |
172 | return NULL; | |
173 | } | |
174 | if (id && id->get_type(id) != ID_ANY) | |
175 | { | |
87d20263 | 176 | if (id->get_type(id) != ID_KEY_ID || |
c84b139a | 177 | !this->key->has_fingerprint(this->key, id->get_encoding(id))) |
aff26a62 MW |
178 | { |
179 | return NULL; | |
180 | } | |
181 | } | |
27ed987e | 182 | this->lock->read_lock(this->lock); |
aff26a62 | 183 | return enumerator_create_cleaner(enumerator_create_single(this->key, NULL), |
27ed987e | 184 | (void*)this->lock->unlock, this->lock); |
aff26a62 MW |
185 | } |
186 | ||
142eaea4 MW |
187 | /** |
188 | * shared key enumerator implementation | |
189 | */ | |
190 | typedef struct { | |
191 | enumerator_t public; | |
192 | private_nm_creds_t *this; | |
193 | shared_key_t *key; | |
194 | bool done; | |
195 | } shared_enumerator_t; | |
196 | ||
65a07156 | 197 | METHOD(enumerator_t, shared_enumerate, bool, |
95a63bf2 | 198 | shared_enumerator_t *this, va_list args) |
142eaea4 | 199 | { |
95a63bf2 TB |
200 | shared_key_t **key; |
201 | id_match_t *me, *other; | |
202 | ||
203 | VA_ARGS_VGET(args, key, me, other); | |
204 | ||
142eaea4 MW |
205 | if (this->done) |
206 | { | |
207 | return FALSE; | |
208 | } | |
209 | *key = this->key; | |
15177f57 MW |
210 | if (me) |
211 | { | |
212 | *me = ID_MATCH_PERFECT; | |
213 | } | |
214 | if (other) | |
215 | { | |
216 | *other = ID_MATCH_ANY; | |
217 | } | |
142eaea4 MW |
218 | this->done = TRUE; |
219 | return TRUE; | |
220 | } | |
221 | ||
65a07156 TB |
222 | METHOD(enumerator_t, shared_destroy, void, |
223 | shared_enumerator_t *this) | |
142eaea4 MW |
224 | { |
225 | this->key->destroy(this->key); | |
27ed987e | 226 | this->this->lock->unlock(this->this->lock); |
142eaea4 MW |
227 | free(this); |
228 | } | |
65a07156 TB |
229 | |
230 | METHOD(credential_set_t, create_shared_enumerator, enumerator_t*, | |
231 | private_nm_creds_t *this, shared_key_type_t type, identification_t *me, | |
232 | identification_t *other) | |
ec249871 | 233 | { |
142eaea4 | 234 | shared_enumerator_t *enumerator; |
15177f57 | 235 | chunk_t key; |
ec249871 | 236 | |
8107d9f4 TB |
237 | this->lock->read_lock(this->lock); |
238 | ||
15177f57 | 239 | switch (type) |
142eaea4 | 240 | { |
15177f57 MW |
241 | case SHARED_EAP: |
242 | case SHARED_IKE: | |
243 | if (!this->pass || !this->user) | |
244 | { | |
8107d9f4 | 245 | goto no_secret; |
15177f57 | 246 | } |
ff8f6b15 | 247 | if (me && !me->matches(me, this->user)) |
15177f57 | 248 | { |
8107d9f4 | 249 | goto no_secret; |
15177f57 MW |
250 | } |
251 | key = chunk_create(this->pass, strlen(this->pass)); | |
252 | break; | |
253 | case SHARED_PRIVATE_KEY_PASS: | |
254 | if (!this->keypass) | |
255 | { | |
8107d9f4 | 256 | goto no_secret; |
15177f57 MW |
257 | } |
258 | key = chunk_create(this->keypass, strlen(this->keypass)); | |
259 | break; | |
8bec0f51 MW |
260 | case SHARED_PIN: |
261 | if (!this->keypass || !me || | |
262 | !chunk_equals(me->get_encoding(me), this->keyid)) | |
263 | { | |
8107d9f4 | 264 | goto no_secret; |
8bec0f51 MW |
265 | } |
266 | key = chunk_create(this->keypass, strlen(this->keypass)); | |
267 | break; | |
15177f57 | 268 | default: |
8107d9f4 | 269 | goto no_secret; |
142eaea4 | 270 | } |
7daf5226 | 271 | |
65a07156 TB |
272 | INIT(enumerator, |
273 | .public = { | |
95a63bf2 TB |
274 | .enumerate = enumerator_enumerate_default, |
275 | .venumerate = _shared_enumerate, | |
65a07156 TB |
276 | .destroy = _shared_destroy, |
277 | }, | |
278 | .this = this, | |
279 | ); | |
15177f57 | 280 | enumerator->key = shared_key_create(type, chunk_clone(key)); |
142eaea4 | 281 | return &enumerator->public; |
8107d9f4 TB |
282 | |
283 | no_secret: | |
284 | this->lock->unlock(this->lock); | |
285 | return NULL; | |
ec249871 MW |
286 | } |
287 | ||
65a07156 TB |
288 | METHOD(nm_creds_t, add_certificate, void, |
289 | private_nm_creds_t *this, certificate_t *cert) | |
ec249871 | 290 | { |
27ed987e | 291 | this->lock->write_lock(this->lock); |
85af7a89 | 292 | this->certs->insert_last(this->certs, cert); |
27ed987e | 293 | this->lock->unlock(this->lock); |
ec249871 MW |
294 | } |
295 | ||
85af7a89 MW |
296 | /** |
297 | * Load a certificate file | |
298 | */ | |
299 | static void load_ca_file(private_nm_creds_t *this, char *file) | |
300 | { | |
301 | certificate_t *cert; | |
302 | ||
303 | /* We add the CA constraint, as many CAs miss it */ | |
304 | cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, | |
305 | BUILD_FROM_FILE, file, BUILD_END); | |
306 | if (!cert) | |
307 | { | |
308 | DBG1(DBG_CFG, "loading CA certificate '%s' failed", file); | |
309 | } | |
310 | else | |
311 | { | |
312 | DBG2(DBG_CFG, "loaded CA certificate '%Y'", cert->get_subject(cert)); | |
313 | x509_t *x509 = (x509_t*)cert; | |
314 | if (!(x509->get_flags(x509) & X509_SELF_SIGNED)) | |
315 | { | |
316 | DBG1(DBG_CFG, "%Y is not self signed", cert->get_subject(cert)); | |
317 | } | |
318 | this->certs->insert_last(this->certs, cert); | |
319 | } | |
320 | } | |
321 | ||
65a07156 TB |
322 | METHOD(nm_creds_t, load_ca_dir, void, |
323 | private_nm_creds_t *this, char *dir) | |
85af7a89 MW |
324 | { |
325 | enumerator_t *enumerator; | |
326 | char *rel, *abs; | |
327 | struct stat st; | |
328 | ||
329 | enumerator = enumerator_create_directory(dir); | |
330 | if (enumerator) | |
331 | { | |
332 | while (enumerator->enumerate(enumerator, &rel, &abs, &st)) | |
333 | { | |
334 | /* skip '.', '..' and hidden files */ | |
335 | if (rel[0] != '.') | |
336 | { | |
337 | if (S_ISDIR(st.st_mode)) | |
338 | { | |
339 | load_ca_dir(this, abs); | |
340 | } | |
341 | else if (S_ISREG(st.st_mode)) | |
342 | { | |
343 | load_ca_file(this, abs); | |
344 | } | |
345 | } | |
346 | } | |
347 | enumerator->destroy(enumerator); | |
348 | } | |
349 | } | |
350 | ||
65a07156 TB |
351 | METHOD(nm_creds_t, set_username_password, void, |
352 | private_nm_creds_t *this, identification_t *id, char *password) | |
ec249871 | 353 | { |
27ed987e | 354 | this->lock->write_lock(this->lock); |
142eaea4 | 355 | DESTROY_IF(this->user); |
a44bb934 | 356 | this->user = id->clone(id); |
ec249871 | 357 | free(this->pass); |
1038d9fe | 358 | this->pass = strdupnull(password); |
27ed987e | 359 | this->lock->unlock(this->lock); |
ec249871 MW |
360 | } |
361 | ||
65a07156 TB |
362 | METHOD(nm_creds_t, set_key_password, void, |
363 | private_nm_creds_t *this, char *password) | |
15177f57 MW |
364 | { |
365 | this->lock->write_lock(this->lock); | |
366 | free(this->keypass); | |
1038d9fe | 367 | this->keypass = strdupnull(password); |
15177f57 MW |
368 | this->lock->unlock(this->lock); |
369 | } | |
370 | ||
65a07156 TB |
371 | METHOD(nm_creds_t, set_pin, void, |
372 | private_nm_creds_t *this, chunk_t keyid, char *pin) | |
8bec0f51 MW |
373 | { |
374 | this->lock->write_lock(this->lock); | |
375 | free(this->keypass); | |
376 | free(this->keyid.ptr); | |
1038d9fe | 377 | this->keypass = strdupnull(pin); |
8bec0f51 MW |
378 | this->keyid = chunk_clone(keyid); |
379 | this->lock->unlock(this->lock); | |
380 | } | |
381 | ||
65a07156 TB |
382 | METHOD(nm_creds_t, set_cert_and_key, void, |
383 | private_nm_creds_t *this, certificate_t *cert, private_key_t *key) | |
aff26a62 | 384 | { |
27ed987e | 385 | this->lock->write_lock(this->lock); |
aff26a62 MW |
386 | DESTROY_IF(this->key); |
387 | DESTROY_IF(this->usercert); | |
388 | this->key = key; | |
389 | this->usercert = cert; | |
27ed987e | 390 | this->lock->unlock(this->lock); |
7daf5226 | 391 | } |
aff26a62 | 392 | |
65a07156 TB |
393 | METHOD(nm_creds_t, clear, void, |
394 | private_nm_creds_t *this) | |
ec249871 | 395 | { |
85af7a89 MW |
396 | certificate_t *cert; |
397 | ||
398 | while (this->certs->remove_last(this->certs, (void**)&cert) == SUCCESS) | |
399 | { | |
400 | cert->destroy(cert); | |
401 | } | |
142eaea4 | 402 | DESTROY_IF(this->user); |
ec249871 | 403 | free(this->pass); |
8bec0f51 MW |
404 | free(this->keypass); |
405 | free(this->keyid.ptr); | |
aff26a62 MW |
406 | DESTROY_IF(this->usercert); |
407 | DESTROY_IF(this->key); | |
408 | this->key = NULL; | |
409 | this->usercert = NULL; | |
410 | this->pass = NULL; | |
aff26a62 | 411 | this->user = NULL; |
8bec0f51 MW |
412 | this->keypass = NULL; |
413 | this->keyid = chunk_empty; | |
aff26a62 MW |
414 | } |
415 | ||
65a07156 TB |
416 | METHOD(nm_creds_t, destroy, void, |
417 | private_nm_creds_t *this) | |
aff26a62 MW |
418 | { |
419 | clear(this); | |
85af7a89 | 420 | this->certs->destroy(this->certs); |
27ed987e | 421 | this->lock->destroy(this->lock); |
ec249871 MW |
422 | free(this); |
423 | } | |
424 | ||
425 | /* | |
426 | * see header file | |
427 | */ | |
428 | nm_creds_t *nm_creds_create() | |
429 | { | |
65a07156 | 430 | private_nm_creds_t *this; |
7daf5226 | 431 | |
65a07156 TB |
432 | INIT(this, |
433 | .public = { | |
434 | .set = { | |
435 | .create_private_enumerator = _create_private_enumerator, | |
436 | .create_cert_enumerator = _create_cert_enumerator, | |
437 | .create_shared_enumerator = _create_shared_enumerator, | |
438 | .create_cdp_enumerator = (void*)return_null, | |
439 | .cache_cert = (void*)nop, | |
440 | }, | |
441 | .add_certificate = _add_certificate, | |
442 | .load_ca_dir = _load_ca_dir, | |
443 | .set_username_password = _set_username_password, | |
444 | .set_key_password = _set_key_password, | |
445 | .set_pin = _set_pin, | |
446 | .set_cert_and_key = _set_cert_and_key, | |
447 | .clear = _clear, | |
448 | .destroy = _destroy, | |
449 | }, | |
450 | .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), | |
451 | .certs = linked_list_create(), | |
452 | ); | |
ec249871 MW |
453 | return &this->public; |
454 | } | |
455 |