3cab10a190d635a446d268a4ce399d1c7ee0880a
[strongswan.git] / src / libstrongswan / credentials / credential_factory.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 <stdint.h>
17 #include <pthread.h>
18
19 #include "credential_factory.h"
20
21 #include <debug.h>
22 #include <utils/linked_list.h>
23 #include <utils/mutex.h>
24 #include <credentials/certificates/x509.h>
25
26 ENUM(credential_type_names, CRED_PRIVATE_KEY, CRED_CERTIFICATE,
27 "CRED_PRIVATE_KEY",
28 "CRED_PUBLIC_KEY",
29 "CRED_CERTIFICATE",
30 "CRED_PLUTO_CERT",
31 );
32
33 typedef struct private_credential_factory_t private_credential_factory_t;
34
35 /**
36 * private data of credential_factory
37 */
38 struct private_credential_factory_t {
39
40 /**
41 * public functions
42 */
43 credential_factory_t public;
44
45 /**
46 * list with entry_t
47 */
48 linked_list_t *constructors;
49
50 /**
51 * Thread specific recursiveness counter
52 */
53 pthread_key_t recursive;
54
55 /**
56 * lock access to builders
57 */
58 rwlock_t *lock;
59 };
60
61 typedef struct entry_t entry_t;
62 struct entry_t {
63 /** kind of credential builder */
64 credential_type_t type;
65 /** subtype of credential, e.g. certificate_type_t */
66 int subtype;
67 /** builder construction function */
68 builder_constructor_t constructor;
69 };
70
71 /**
72 * type/subtype filter function for builder_enumerator
73 */
74 static bool builder_filter(entry_t *data, entry_t **in, builder_t **out)
75 {
76 builder_t *builder;
77
78 if (data->type == (*in)->type &&
79 data->subtype == (*in)->subtype)
80 {
81 builder = (*in)->constructor(data->subtype);
82 if (builder)
83 {
84 *out = builder;
85 return TRUE;
86 }
87 }
88 return FALSE;
89 }
90
91 /**
92 * Implementation of credential_factory_t.create_builder_enumerator.
93 */
94 static enumerator_t* create_builder_enumerator(
95 private_credential_factory_t *this, credential_type_t type, int subtype)
96 {
97 entry_t *data = malloc_thing(entry_t);
98
99 data->type = type;
100 data->subtype = subtype;
101
102 this->lock->read_lock(this->lock);
103 return enumerator_create_cleaner(
104 enumerator_create_filter(
105 this->constructors->create_enumerator(this->constructors),
106 (void*)builder_filter, data, free),
107 (void*)this->lock->unlock, this->lock);
108 }
109
110 /**
111 * Implementation of credential_factory_t.add_builder_constructor.
112 */
113 static void add_builder(private_credential_factory_t *this,
114 credential_type_t type, int subtype,
115 builder_constructor_t constructor)
116 {
117 entry_t *entry = malloc_thing(entry_t);
118
119 entry->type = type;
120 entry->subtype = subtype;
121 entry->constructor = constructor;
122 this->lock->write_lock(this->lock);
123 this->constructors->insert_last(this->constructors, entry);
124 this->lock->unlock(this->lock);
125 }
126
127 /**
128 * Implementation of credential_factory_t.remove_builder.
129 */
130 static void remove_builder(private_credential_factory_t *this,
131 builder_constructor_t constructor)
132 {
133 enumerator_t *enumerator;
134 entry_t *entry;
135
136 this->lock->write_lock(this->lock);
137 enumerator = this->constructors->create_enumerator(this->constructors);
138 while (enumerator->enumerate(enumerator, &entry))
139 {
140 if (entry->constructor == constructor)
141 {
142 this->constructors->remove_at(this->constructors, enumerator);
143 free(entry);
144 }
145 }
146 enumerator->destroy(enumerator);
147 this->lock->unlock(this->lock);
148 }
149
150 /**
151 * Implementation of credential_factory_t.create.
152 */
153 static void* create(private_credential_factory_t *this, credential_type_t type,
154 int subtype, ...)
155 {
156 enumerator_t *enumerator;
157 builder_t *builder;
158 builder_part_t part;
159 va_list args;
160 void* construct = NULL, *fn, *data;
161 int failures = 0;
162 uintptr_t level;
163
164 level = (uintptr_t)pthread_getspecific(this->recursive);
165 pthread_setspecific(this->recursive, (void*)level + 1);
166
167 enumerator = create_builder_enumerator(this, type, subtype);
168 while (enumerator->enumerate(enumerator, &builder))
169 {
170 va_start(args, subtype);
171 while (TRUE)
172 {
173 part = va_arg(args, builder_part_t);
174 switch (part)
175 {
176 case BUILD_END:
177 break;
178 case BUILD_BLOB_PEM:
179 case BUILD_BLOB_ASN1_DER:
180 case BUILD_BLOB_PGP:
181 case BUILD_BLOB_DNSKEY:
182 case BUILD_PASSPHRASE:
183 case BUILD_SERIAL:
184 case BUILD_RSA_MODULUS:
185 case BUILD_RSA_PUB_EXP:
186 case BUILD_RSA_PRIV_EXP:
187 case BUILD_RSA_PRIME1:
188 case BUILD_RSA_PRIME2:
189 case BUILD_RSA_EXP1:
190 case BUILD_RSA_EXP2:
191 case BUILD_RSA_COEFF:
192 builder->add(builder, part, va_arg(args, chunk_t));
193 continue;
194 case BUILD_X509_FLAG:
195 builder->add(builder, part, va_arg(args, x509_flag_t));
196 continue;
197 case BUILD_KEY_SIZE:
198 case BUILD_FROM_FD:
199 builder->add(builder, part, va_arg(args, u_int));
200 continue;
201 case BUILD_NOT_BEFORE_TIME:
202 case BUILD_NOT_AFTER_TIME:
203 builder->add(builder, part, va_arg(args, time_t));
204 continue;
205 case BUILD_FROM_FILE:
206 case BUILD_AGENT_SOCKET:
207 case BUILD_SIGNING_KEY:
208 case BUILD_PUBLIC_KEY:
209 case BUILD_SUBJECT:
210 case BUILD_SUBJECT_ALTNAME:
211 case BUILD_ISSUER:
212 case BUILD_ISSUER_ALTNAME:
213 case BUILD_SIGNING_CERT:
214 case BUILD_CA_CERT:
215 case BUILD_CERT:
216 case BUILD_IETF_GROUP_ATTR:
217 case BUILD_SMARTCARD_KEYID:
218 case BUILD_SMARTCARD_PIN:
219 builder->add(builder, part, va_arg(args, void*));
220 continue;
221 case BUILD_PASSPHRASE_CALLBACK:
222 fn = va_arg(args, void*);
223 data = va_arg(args, void*);
224 builder->add(builder, part, fn, data);
225 continue;
226 /* no default to get a compiler warning */
227 }
228 break;
229 }
230 va_end(args);
231
232 construct = builder->build(builder);
233 if (construct)
234 {
235 break;
236 }
237 failures++;
238 }
239 enumerator->destroy(enumerator);
240 if (!construct && !level)
241 {
242 enum_name_t *names = key_type_names;
243
244 if (type == CRED_CERTIFICATE)
245 {
246 names = certificate_type_names;
247 }
248 DBG1("building %N - %N failed, tried %d builders",
249 credential_type_names, type, names, subtype, failures);
250 }
251 pthread_setspecific(this->recursive, (void*)level);
252 return construct;
253 }
254
255 /**
256 * Implementation of credential_factory_t.destroy
257 */
258 static void destroy(private_credential_factory_t *this)
259 {
260 this->constructors->destroy_function(this->constructors, free);
261 pthread_key_delete(this->recursive);
262 this->lock->destroy(this->lock);
263 free(this);
264 }
265
266 /*
267 * see header file
268 */
269 credential_factory_t *credential_factory_create()
270 {
271 private_credential_factory_t *this = malloc_thing(private_credential_factory_t);
272
273 this->public.create = (void*(*)(credential_factory_t*, credential_type_t type, int subtype, ...))create;
274 this->public.create_builder_enumerator = (enumerator_t*(*)(credential_factory_t*, credential_type_t type, int subtype))create_builder_enumerator;
275 this->public.add_builder = (void(*)(credential_factory_t*,credential_type_t type, int subtype, builder_constructor_t constructor))add_builder;
276 this->public.remove_builder = (void(*)(credential_factory_t*,builder_constructor_t constructor))remove_builder;
277 this->public.destroy = (void(*)(credential_factory_t*))destroy;
278
279 this->constructors = linked_list_create();
280 pthread_key_create(&this->recursive, NULL);
281 this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
282
283 return &this->public;
284 }
285