2 * @file local_credential_store.c
4 * @brief Implementation of local_credential_store_t.
9 * Copyright (C) 2006 Martin Willi
10 * Hochschule fuer Technik Rapperswil
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>.
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
27 #include "local_credential_store.h"
29 #include <utils/lexparser.h>
30 #include <utils/linked_list.h>
31 #include <utils/logger_manager.h>
32 #include <crypto/x509.h>
36 typedef struct key_entry_t key_entry_t
;
39 * Private key with an associated ID to find it
49 * Associated rsa private key
51 rsa_private_key_t
*key
;
55 typedef struct private_local_credential_store_t private_local_credential_store_t
;
58 * Private data of an local_credential_store_t object
60 struct private_local_credential_store_t
{
65 local_credential_store_t
public;
68 * list of key_entry_t's with private keys
70 linked_list_t
*private_keys
;
73 * list of x509 certificates with public keys
75 linked_list_t
*certificates
;
85 * Implementation of credential_store_t.get_shared_secret.
87 static status_t
get_shared_secret(private_local_credential_store_t
*this, identification_t
*identification
, chunk_t
*preshared_secret
)
93 * Implementation of credential_store_t.get_rsa_public_key.
95 static rsa_public_key_t
* get_rsa_public_key(private_local_credential_store_t
*this, identification_t
*identification
)
98 rsa_public_key_t
*found
= NULL
;
101 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "Looking for public key for %s",
102 identification
->get_string(identification
));
103 iterator
= this->certificates
->create_iterator(this->certificates
, TRUE
);
104 while (iterator
->has_next(iterator
))
106 iterator
->current(iterator
, (void**)¤t
);
107 identification_t
*stored
= current
->get_subject(current
);
108 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "there is one for %s",
109 stored
->get_string(stored
));
110 if (identification
->equals(identification
, stored
))
112 found
= current
->get_public_key(current
);
116 iterator
->destroy(iterator
);
121 * Implementation of credential_store_t.get_rsa_private_key.
123 static rsa_private_key_t
*get_rsa_private_key(private_local_credential_store_t
*this, identification_t
*identification
)
125 rsa_private_key_t
*found
= NULL
;
126 key_entry_t
*current
;
127 iterator_t
*iterator
;
129 iterator
= this->private_keys
->create_iterator(this->private_keys
, TRUE
);
130 while (iterator
->has_next(iterator
))
132 iterator
->current(iterator
, (void**)¤t
);
133 if (identification
->equals(identification
, current
->id
))
135 found
= current
->key
->clone(current
->key
);
139 iterator
->destroy(iterator
);
144 * Implements local_credential_store_t.load_certificates
146 static void load_certificates(private_local_credential_store_t
*this, const char *path
)
148 struct dirent
* entry
;
155 this->logger
->log(this->logger
, ERROR
, "error opening certificate directory \"%s\"", path
);
158 while ((entry
= readdir(dir
)) != NULL
)
162 snprintf(file
, sizeof(file
), "%s/%s", path
, entry
->d_name
);
164 if (stat(file
, &stb
) == -1)
168 /* try to parse all regular files */
169 if (stb
.st_mode
& S_IFREG
)
171 cert
= x509_create_from_file(file
);
174 this->certificates
->insert_last(this->certificates
, (void*)cert
);
178 this->logger
->log(this->logger
, ERROR
, "certificate \"%s\" invalid, skipped", file
);
186 * Query the ID for a private key, by doing a lookup in the certificates
188 static identification_t
*get_id_for_private_key(private_local_credential_store_t
*this, rsa_private_key_t
*private_key
)
190 iterator_t
*iterator
;
192 identification_t
*found
= NULL
;
193 rsa_public_key_t
*public_key
;
195 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "Getting ID for a private key...");
197 iterator
= this->certificates
->create_iterator(this->certificates
, TRUE
);
198 while (!found
&& iterator
->has_next(iterator
))
200 iterator
->current(iterator
, (void**)&cert
);
201 public_key
= cert
->get_public_key(cert
);
204 if (private_key
->belongs_to(private_key
, public_key
))
206 this->logger
->log(this->logger
, CONTROL
|LEVEL2
, "found a match");
207 found
= cert
->get_subject(cert
);
208 found
= found
->clone(found
);
212 this->logger
->log(this->logger
, CONTROL
|LEVEL3
, "this one did not match");
214 public_key
->destroy(public_key
);
217 iterator
->destroy(iterator
);
222 * Implements local_credential_store_t.load_private_keys
224 static void load_private_keys(private_local_credential_store_t
*this, const char *secretsfile
, const char *defaultpath
)
226 FILE *fd
= fopen(secretsfile
, "r");
232 chunk_t chunk
, src
, line
;
234 this->logger
->log(this->logger
, CONTROL
, "loading secrets from \"%s\"", secretsfile
);
236 fseek(fd
, 0, SEEK_END
);
237 chunk
.len
= ftell(fd
);
239 chunk
.ptr
= malloc(chunk
.len
);
240 bytes
= fread(chunk
.ptr
, 1, chunk
.len
, fd
);
245 while (fetchline(&src
, &line
))
251 if (!eat_whitespace(&line
))
255 if (!extract_token(&ids
, ':', &line
))
257 this->logger
->log(this->logger
, ERROR
, "line %d: missing ':' separator", line_nr
);
260 if (!eat_whitespace(&line
) || !extract_token(&token
, ' ', &line
))
262 this->logger
->log(this->logger
, ERROR
, "line %d: missing token", line_nr
);
265 if (match("RSA", &token
))
270 err_t ugh
= extract_value(&filename
, &line
);
274 this->logger
->log(this->logger
, ERROR
, "line %d: %s", line_nr
, ugh
);
277 if (filename
.len
== 0)
279 this->logger
->log(this->logger
, ERROR
,
280 "line %d: empty filename", line_nr
);
283 if (*filename
.ptr
== '/')
285 /* absolute path name */
286 snprintf(path
, sizeof(path
), "%.*s", filename
.len
, filename
.ptr
);
290 /* relative path name */
291 snprintf(path
, sizeof(path
), "%s/%.*s", defaultpath
, filename
.len
, filename
.ptr
);
294 rsa_private_key_t
*key
= rsa_private_key_create_from_file(path
, NULL
);
298 identification_t
*id
= get_id_for_private_key(this, key
);
302 this->logger
->log(this->logger
, ERROR
,
303 "no certificate found for private key \"%s\", skipped", path
);
307 entry
= malloc_thing(key_entry_t
);
310 this->private_keys
->insert_last(this->private_keys
, (void*)entry
);
313 else if (match("PSK", &token
))
317 else if (match("PIN", &token
))
323 this->logger
->log(this->logger
, ERROR
,
324 "line %d: token must be either RSA, PSK, or PIN",
334 this->logger
->log(this->logger
, ERROR
, "could not open file '%s'", secretsfile
);
339 * Implementation of credential_store_t.destroy.
341 static void destroy(private_local_credential_store_t
*this)
344 key_entry_t
*key_entry
;
346 while (this->certificates
->remove_last(this->certificates
, (void**)&certificate
) == SUCCESS
)
348 certificate
->destroy(certificate
);
350 this->certificates
->destroy(this->certificates
);
351 while (this->private_keys
->remove_last(this->private_keys
, (void**)&key_entry
) == SUCCESS
)
353 key_entry
->id
->destroy(key_entry
->id
);
354 key_entry
->key
->destroy(key_entry
->key
);
357 this->private_keys
->destroy(this->private_keys
);
362 * Described in header.
364 local_credential_store_t
* local_credential_store_create()
366 private_local_credential_store_t
*this = malloc_thing(private_local_credential_store_t
);
368 this->public.credential_store
.get_shared_secret
= (status_t(*)(credential_store_t
*,identification_t
*,chunk_t
*))get_shared_secret
;
369 this->public.credential_store
.get_rsa_private_key
= (rsa_private_key_t
*(*)(credential_store_t
*,identification_t
*))get_rsa_private_key
;
370 this->public.credential_store
.get_rsa_public_key
= (rsa_public_key_t
*(*)(credential_store_t
*,identification_t
*))get_rsa_public_key
;
371 this->public.load_certificates
= (void(*)(local_credential_store_t
*,const char*))load_certificates
;
372 this->public.load_private_keys
= (void(*)(local_credential_store_t
*,const char*, const char*))load_private_keys
;
373 this->public.credential_store
.destroy
= (void(*)(credential_store_t
*))destroy
;
375 /* private variables */
376 this->private_keys
= linked_list_create();
377 this->certificates
= linked_list_create();
378 this->logger
= logger_manager
->get_logger(logger_manager
, CONFIG
);
380 return (&this->public);