new functions to add certificates and retrieve private and public keys
[strongswan.git] / src / charon / config / credentials / local_credential_store.c
1 /**
2 * @file local_credential_store.c
3 *
4 * @brief Implementation of local_credential_store_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include <sys/stat.h>
24 #include <dirent.h>
25 #include <string.h>
26
27 #include "local_credential_store.h"
28
29 #include <utils/lexparser.h>
30 #include <utils/linked_list.h>
31 #include <utils/logger_manager.h>
32 #include <crypto/x509.h>
33
34 #define PATH_BUF 256
35
36 typedef struct private_local_credential_store_t private_local_credential_store_t;
37
38 /**
39 * Private data of an local_credential_store_t object
40 */
41 struct private_local_credential_store_t {
42
43 /**
44 * Public part
45 */
46 local_credential_store_t public;
47
48 /**
49 * list of key_entry_t's with private keys
50 */
51 linked_list_t *private_keys;
52
53 /**
54 * list of X.509 certificates with public keys
55 */
56 linked_list_t *certs;
57
58 /**
59 * list of X.509 CA certificates with public keys
60 */
61 linked_list_t *ca_certs;
62 /**
63 * Assigned logger
64 */
65 logger_t *logger;
66 };
67
68
69 /**
70 * Implementation of credential_store_t.get_shared_secret.
71 */
72 static status_t get_shared_secret(private_local_credential_store_t *this, identification_t *id, chunk_t *secret)
73 {
74 return FAILED;
75 }
76
77 /**
78 * Implementation of credential_store_t.get_rsa_public_key.
79 */
80 static rsa_public_key_t * get_rsa_public_key(private_local_credential_store_t *this, identification_t *id)
81 {
82 rsa_public_key_t *found = NULL;
83
84 iterator_t *iterator = this->certs->create_iterator(this->certs, TRUE);
85
86 while (iterator->has_next(iterator))
87 {
88 x509_t *cert;
89
90 iterator->current(iterator, (void**)&cert);
91
92 if (id->equals(id, cert->get_subject(cert)) || cert->equals_subjectAltName(cert, id))
93 {
94 found = cert->get_public_key(cert);
95 break;
96 }
97 }
98 iterator->destroy(iterator);
99 return found;
100 }
101
102 /**
103 * Implementation of credential_store_t.get_rsa_private_key.
104 */
105 static rsa_private_key_t* get_rsa_private_key(private_local_credential_store_t *this, rsa_public_key_t *pubkey)
106 {
107 rsa_private_key_t *found = NULL;
108 rsa_private_key_t *current;
109
110 iterator_t *iterator = this->private_keys->create_iterator(this->private_keys, TRUE);
111
112 while (iterator->has_next(iterator))
113 {
114 iterator->current(iterator, (void**)&current);
115
116 if (current->belongs_to(current, pubkey))
117 {
118 found = current->clone(current);
119 break;
120 }
121 }
122 iterator->destroy(iterator);
123 return found;
124 }
125
126 /**
127 * Implementation of credential_store_t.has_rsa_private_key.
128 */
129 static bool has_rsa_private_key(private_local_credential_store_t *this, rsa_public_key_t *pubkey)
130 {
131 bool found = FALSE;
132 rsa_private_key_t *current;
133
134 iterator_t *iterator = this->private_keys->create_iterator(this->private_keys, TRUE);
135
136 while (iterator->has_next(iterator))
137 {
138 iterator->current(iterator, (void**)&current);
139
140 if (current->belongs_to(current, pubkey))
141 {
142 found = TRUE;
143 break;
144 }
145 }
146 iterator->destroy(iterator);
147 return found;
148 }
149
150 /**
151 * Implements credential_store_t.add_certificate
152 */
153 static void add_certificate(private_local_credential_store_t *this, x509_t *cert)
154 {
155 bool found = FALSE;
156
157 iterator_t *iterator = this->certs->create_iterator(this->certs, TRUE);
158
159 while (iterator->has_next(iterator))
160 {
161 x509_t *current_cert;
162
163 iterator->current(iterator, (void**)&current_cert);
164 if (cert->equals(cert, current_cert))
165 {
166 found = TRUE;
167 break;
168 }
169 }
170 iterator->destroy(iterator);
171
172 if (found)
173 {
174 cert->destroy(cert);
175 }
176 else
177 {
178 this->certs->insert_last(this->certs, (void*)cert);
179 }
180 }
181
182 /**
183 * Implements credential_store_t.log_certificates
184 */
185 static void log_certificates(private_local_credential_store_t *this, logger_t *logger, bool utc)
186 {
187 iterator_t *iterator = this->certs->create_iterator(this->certs, TRUE);
188
189 if (iterator->get_count(iterator))
190 {
191 logger->log(logger, CONTROL, "");
192 logger->log(logger, CONTROL, "List of X.509 End Entity Certificates:");
193 logger->log(logger, CONTROL, "");
194 }
195
196 while (iterator->has_next(iterator))
197 {
198 x509_t *cert;
199 rsa_private_key_t *key;
200 bool has_key;
201
202 iterator->current(iterator, (void**)&cert);
203 has_key = has_rsa_private_key(this, cert->get_public_key(cert));
204 cert->log_certificate(cert, logger, utc, has_key);
205 }
206 iterator->destroy(iterator);
207 }
208
209 /**
210 * Implements credential_store_t.log_ca_certificates
211 */
212 static void log_ca_certificates(private_local_credential_store_t *this, logger_t *logger, bool utc)
213 {
214 iterator_t *iterator = this->ca_certs->create_iterator(this->ca_certs, TRUE);
215
216 if (iterator->get_count(iterator))
217 {
218 logger->log(logger, CONTROL, "");
219 logger->log(logger, CONTROL, "List of X.509 CA Certificates:");
220 logger->log(logger, CONTROL, "");
221 }
222
223 while (iterator->has_next(iterator))
224 {
225 x509_t *cert;
226
227 iterator->current(iterator, (void**)&cert);
228 cert->log_certificate(cert, logger, utc, FALSE);
229 }
230 iterator->destroy(iterator);
231 }
232 /**
233 * Implements local_credential_store_t.load_ca_certificates
234 */
235 static void load_ca_certificates(private_local_credential_store_t *this, const char *path)
236 {
237 struct dirent* entry;
238 struct stat stb;
239 DIR* dir;
240 x509_t *cert;
241
242 this->logger->log(this->logger, CONTROL, "loading ca certificates from '%s/'", path);
243
244 dir = opendir(path);
245 if (dir == NULL)
246 {
247 this->logger->log(this->logger, ERROR, "error opening ca certs directory %s'", path);
248 return;
249 }
250
251 while ((entry = readdir(dir)) != NULL)
252 {
253 char file[PATH_BUF];
254
255 snprintf(file, sizeof(file), "%s/%s", path, entry->d_name);
256
257 if (stat(file, &stb) == -1)
258 {
259 continue;
260 }
261 /* try to parse all regular files */
262 if (stb.st_mode & S_IFREG)
263 {
264 cert = x509_create_from_file(file, "ca certificate");
265 if (cert)
266 {
267 this->ca_certs->insert_last(this->ca_certs, (void*)cert);
268 }
269 else
270 {
271 this->logger->log(this->logger, ERROR, "certificate \"%s\" invalid, skipped", file);
272 }
273 }
274 }
275 closedir(dir);
276 }
277
278 /**
279 * Implements local_credential_store_t.load_private_keys
280 */
281 static void load_private_keys(private_local_credential_store_t *this, const char *secretsfile, const char *defaultpath)
282 {
283 FILE *fd = fopen(secretsfile, "r");
284
285 if (fd)
286 {
287 int bytes;
288 int line_nr = 0;
289 chunk_t chunk, src, line;
290
291 this->logger->log(this->logger, CONTROL, "loading secrets from \"%s\"", secretsfile);
292
293 fseek(fd, 0, SEEK_END);
294 chunk.len = ftell(fd);
295 rewind(fd);
296 chunk.ptr = malloc(chunk.len);
297 bytes = fread(chunk.ptr, 1, chunk.len, fd);
298 fclose(fd);
299
300 src = chunk;
301
302 while (fetchline(&src, &line))
303 {
304 chunk_t ids, token;
305
306 line_nr++;
307
308 if (!eat_whitespace(&line))
309 {
310 continue;
311 }
312 if (!extract_token(&ids, ':', &line))
313 {
314 this->logger->log(this->logger, ERROR, "line %d: missing ':' separator", line_nr);
315 goto error;
316 }
317 if (!eat_whitespace(&line) || !extract_token(&token, ' ', &line))
318 {
319 this->logger->log(this->logger, ERROR, "line %d: missing token", line_nr);
320 goto error;
321 }
322 if (match("RSA", &token))
323 {
324 char path[PATH_BUF];
325 chunk_t filename;
326
327 err_t ugh = extract_value(&filename, &line);
328
329 if (ugh != NULL)
330 {
331 this->logger->log(this->logger, ERROR, "line %d: %s", line_nr, ugh);
332 goto error;
333 }
334 if (filename.len == 0)
335 {
336 this->logger->log(this->logger, ERROR,
337 "line %d: empty filename", line_nr);
338 goto error;
339 }
340 if (*filename.ptr == '/')
341 {
342 /* absolute path name */
343 snprintf(path, sizeof(path), "%.*s", filename.len, filename.ptr);
344 }
345 else
346 {
347 /* relative path name */
348 snprintf(path, sizeof(path), "%s/%.*s", defaultpath, filename.len, filename.ptr);
349 }
350
351 rsa_private_key_t *key = rsa_private_key_create_from_file(path, NULL);
352 if (key)
353 {
354 this->private_keys->insert_last(this->private_keys, (void*)key);
355 }
356 }
357 else if (match("PSK", &token))
358 {
359
360 }
361 else if (match("PIN", &token))
362 {
363
364 }
365 else
366 {
367 this->logger->log(this->logger, ERROR,
368 "line %d: token must be either RSA, PSK, or PIN",
369 line_nr, token.len);
370 goto error;
371 }
372 }
373 error:
374 free(chunk.ptr);
375 }
376 else
377 {
378 this->logger->log(this->logger, ERROR, "could not open file '%s'", secretsfile);
379 }
380 }
381
382 /**
383 * Implementation of credential_store_t.destroy.
384 */
385 static void destroy(private_local_credential_store_t *this)
386 {
387 x509_t *cert;
388 rsa_private_key_t *key;
389
390 /* destroy cert list */
391 while (this->certs->remove_last(this->certs, (void**)&cert) == SUCCESS)
392 {
393 cert->destroy(cert);
394 }
395 this->certs->destroy(this->certs);
396
397 /* destroy ca cert list */
398 while (this->ca_certs->remove_last(this->ca_certs, (void**)&cert) == SUCCESS)
399 {
400 cert->destroy(cert);
401 }
402 this->ca_certs->destroy(this->ca_certs);
403
404 /* destroy private key list */
405 while (this->private_keys->remove_last(this->private_keys, (void**)&key) == SUCCESS)
406 {
407 key->destroy(key);
408 }
409 this->private_keys->destroy(this->private_keys);
410
411 free(this);
412 }
413
414 /**
415 * Described in header.
416 */
417 local_credential_store_t * local_credential_store_create(void)
418 {
419 private_local_credential_store_t *this = malloc_thing(private_local_credential_store_t);
420
421 this->public.credential_store.get_shared_secret = (status_t(*)(credential_store_t*,identification_t*,chunk_t*))get_shared_secret;
422 this->public.credential_store.get_rsa_private_key = (rsa_private_key_t*(*)(credential_store_t*,rsa_public_key_t*))get_rsa_private_key;
423 this->public.credential_store.has_rsa_private_key = (bool(*)(credential_store_t*,rsa_public_key_t*))has_rsa_private_key;
424 this->public.credential_store.get_rsa_public_key = (rsa_public_key_t*(*)(credential_store_t*,identification_t*))get_rsa_public_key;
425 this->public.credential_store.add_certificate = (void(*)(credential_store_t*,x509_t*))add_certificate;
426 this->public.credential_store.log_certificates = (void(*)(credential_store_t*,logger_t*,bool))log_certificates;
427 this->public.credential_store.log_ca_certificates = (void(*)(credential_store_t*,logger_t*,bool))log_ca_certificates;
428 this->public.load_ca_certificates = (void(*)(local_credential_store_t*,const char*))load_ca_certificates;
429 this->public.load_private_keys = (void(*)(local_credential_store_t*,const char*, const char*))load_private_keys;
430 this->public.credential_store.destroy = (void(*)(credential_store_t*))destroy;
431
432 /* private variables */
433 this->private_keys = linked_list_create();
434 this->certs = linked_list_create();
435 this->ca_certs = linked_list_create();
436 this->logger = logger_manager->get_logger(logger_manager, CONFIG);
437
438 return (&this->public);
439 }