pkcs11: Avoid naming conflict with method parameter
[strongswan.git] / src / libstrongswan / plugins / pkcs11 / pkcs11_creds.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
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 "pkcs11_creds.h"
17 #include "pkcs11_manager.h"
18
19 #include <utils/debug.h>
20 #include <collections/linked_list.h>
21
22 typedef struct private_pkcs11_creds_t private_pkcs11_creds_t;
23
24 /**
25 * Private data of an pkcs11_creds_t object.
26 */
27 struct private_pkcs11_creds_t {
28
29 /**
30 * Public pkcs11_creds_t interface.
31 */
32 pkcs11_creds_t public;
33
34 /**
35 * PKCS# library
36 */
37 pkcs11_library_t *lib;
38
39 /**
40 * Token slot
41 */
42 CK_SLOT_ID slot;
43
44 /**
45 * List of trusted certificates
46 */
47 linked_list_t *trusted;
48
49 /**
50 * List of untrusted certificates
51 */
52 linked_list_t *untrusted;
53 };
54
55 /**
56 * Find certificates, optionally trusted
57 */
58 static void find_certificates(private_pkcs11_creds_t *this,
59 CK_SESSION_HANDLE session)
60 {
61 CK_OBJECT_CLASS class = CKO_CERTIFICATE;
62 CK_CERTIFICATE_TYPE type = CKC_X_509;
63 CK_BBOOL trusted = TRUE;
64 CK_ATTRIBUTE tmpl[] = {
65 {CKA_CLASS, &class, sizeof(class)},
66 {CKA_CERTIFICATE_TYPE, &type, sizeof(type)},
67 };
68 CK_OBJECT_HANDLE object;
69 CK_ATTRIBUTE attr[] = {
70 {CKA_VALUE, NULL, 0},
71 {CKA_LABEL, NULL, 0},
72 {CKA_TRUSTED, &trusted, sizeof(trusted)}
73 };
74 enumerator_t *enumerator;
75 linked_list_t *raw;
76 certificate_t *cert;
77 struct {
78 chunk_t value;
79 chunk_t label;
80 bool trusted;
81 } *entry;
82 int count = countof(attr);
83
84 /* store result in a temporary list, avoid recursive operation */
85 raw = linked_list_create();
86 /* do not use trusted argument if not supported */
87 if (!(this->lib->get_features(this->lib) & PKCS11_TRUSTED_CERTS))
88 {
89 count--;
90 }
91 enumerator = this->lib->create_object_enumerator(this->lib,
92 session, tmpl, countof(tmpl), attr, count);
93 while (enumerator->enumerate(enumerator, &object))
94 {
95 entry = malloc(sizeof(*entry));
96 entry->value = chunk_clone(
97 chunk_create(attr[0].pValue, attr[0].ulValueLen));
98 entry->label = chunk_clone(
99 chunk_create(attr[1].pValue, attr[1].ulValueLen));
100 entry->trusted = trusted;
101 raw->insert_last(raw, entry);
102 }
103 enumerator->destroy(enumerator);
104
105 while (raw->remove_first(raw, (void**)&entry) == SUCCESS)
106 {
107 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
108 BUILD_BLOB_ASN1_DER, entry->value,
109 BUILD_END);
110 if (cert)
111 {
112 DBG1(DBG_CFG, " loaded %strusted cert '%.*s'",
113 entry->trusted ? "" : "un", (int)entry->label.len,
114 entry->label.ptr);
115 /* trusted certificates are also returned as untrusted */
116 this->untrusted->insert_last(this->untrusted, cert);
117 if (entry->trusted)
118 {
119 this->trusted->insert_last(this->trusted, cert->get_ref(cert));
120 }
121 }
122 else
123 {
124 DBG1(DBG_CFG, " loading cert '%.*s' failed",
125 (int)entry->label.len, entry->label.ptr);
126 }
127 free(entry->value.ptr);
128 free(entry->label.ptr);
129 free(entry);
130 }
131 raw->destroy(raw);
132 }
133
134 /**
135 * Load in the certificates from the token
136 */
137 static bool load_certificates(private_pkcs11_creds_t *this)
138 {
139 CK_SESSION_HANDLE session;
140 CK_RV rv;
141
142 rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION,
143 NULL, NULL, &session);
144 if (rv != CKR_OK)
145 {
146 DBG1(DBG_CFG, "opening session failed: %N", ck_rv_names, rv);
147 return FALSE;
148 }
149
150 find_certificates(this, session);
151
152 this->lib->f->C_CloseSession(session);
153 return TRUE;
154 }
155
156 CALLBACK(certs_filter, bool,
157 identification_t *id, enumerator_t *orig, va_list args)
158 {
159 public_key_t *public;
160 certificate_t *cert, **out;
161
162 VA_ARGS_VGET(args, out);
163
164 while (orig->enumerate(orig, &cert))
165 {
166 if (id == NULL || cert->has_subject(cert, id))
167 {
168 *out = cert;
169 return TRUE;
170 }
171 public = cert->get_public_key(cert);
172 if (public)
173 {
174 if (public->has_fingerprint(public, id->get_encoding(id)))
175 {
176 public->destroy(public);
177 *out = cert;
178 return TRUE;
179 }
180 public->destroy(public);
181 }
182 }
183 return FALSE;
184 }
185
186 METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
187 private_pkcs11_creds_t *this, certificate_type_t cert, key_type_t key,
188 identification_t *id, bool trusted)
189 {
190 enumerator_t *inner;
191
192 if (cert != CERT_X509 && cert != CERT_ANY)
193 {
194 return NULL;
195 }
196 if (trusted)
197 {
198 inner = this->trusted->create_enumerator(this->trusted);
199 }
200 else
201 {
202 inner = this->untrusted->create_enumerator(this->untrusted);
203 }
204 return enumerator_create_filter(inner, certs_filter, id, NULL);
205 }
206
207 METHOD(pkcs11_creds_t, get_library, pkcs11_library_t*,
208 private_pkcs11_creds_t *this)
209 {
210 return this->lib;
211 }
212
213 METHOD(pkcs11_creds_t, get_slot, CK_SLOT_ID,
214 private_pkcs11_creds_t *this)
215 {
216 return this->slot;
217 }
218
219 METHOD(pkcs11_creds_t, destroy, void,
220 private_pkcs11_creds_t *this)
221 {
222 this->trusted->destroy_offset(this->trusted,
223 offsetof(certificate_t, destroy));
224 this->untrusted->destroy_offset(this->untrusted,
225 offsetof(certificate_t, destroy));
226 free(this);
227 }
228
229 /**
230 * See header
231 */
232 pkcs11_creds_t *pkcs11_creds_create(pkcs11_library_t *p11, CK_SLOT_ID slot)
233 {
234 private_pkcs11_creds_t *this;
235
236 INIT(this,
237 .public = {
238 .set = {
239 .create_shared_enumerator = (void*)enumerator_create_empty,
240 .create_private_enumerator = (void*)enumerator_create_empty,
241 .create_cert_enumerator = _create_cert_enumerator,
242 .create_cdp_enumerator = (void*)enumerator_create_empty,
243 .cache_cert = (void*)nop,
244 },
245 .get_library = _get_library,
246 .get_slot = _get_slot,
247 .destroy = _destroy,
248 },
249 .lib = p11,
250 .slot = slot,
251 .trusted = linked_list_create(),
252 .untrusted = linked_list_create(),
253 );
254
255 if (!load_certificates(this))
256 {
257 destroy(this);
258 return NULL;
259 }
260
261 return &this->public;
262 }
263
264 /**
265 * See header.
266 */
267 certificate_t *pkcs11_creds_load(certificate_type_t type, va_list args)
268 {
269 chunk_t keyid = chunk_empty, data = chunk_empty;
270 enumerator_t *enumerator, *certs;
271 pkcs11_manager_t *manager;
272 pkcs11_library_t *p11;
273 certificate_t *cert = NULL;
274 CK_SLOT_ID current, slot = -1;
275 char *module = NULL;
276
277 while (TRUE)
278 {
279 switch (va_arg(args, builder_part_t))
280 {
281 case BUILD_PKCS11_KEYID:
282 keyid = va_arg(args, chunk_t);
283 continue;
284 case BUILD_PKCS11_SLOT:
285 slot = va_arg(args, int);
286 continue;
287 case BUILD_PKCS11_MODULE:
288 module = va_arg(args, char*);
289 continue;
290 case BUILD_END:
291 break;
292 default:
293 return NULL;
294 }
295 break;
296 }
297 if (!keyid.len)
298 {
299 return NULL;
300 }
301
302 manager = lib->get(lib, "pkcs11-manager");
303 if (!manager)
304 {
305 return NULL;
306 }
307 enumerator = manager->create_token_enumerator(manager);
308 while (enumerator->enumerate(enumerator, &p11, &current))
309 {
310 CK_OBJECT_CLASS class = CKO_CERTIFICATE;
311 CK_CERTIFICATE_TYPE ck_type = CKC_X_509;
312 CK_ATTRIBUTE tmpl[] = {
313 {CKA_CLASS, &class, sizeof(class)},
314 {CKA_CERTIFICATE_TYPE, &ck_type, sizeof(ck_type)},
315 {CKA_ID, keyid.ptr, keyid.len},
316 };
317 CK_ATTRIBUTE attr[] = {
318 {CKA_VALUE, NULL, 0},
319 };
320 CK_OBJECT_HANDLE object;
321 CK_SESSION_HANDLE session;
322 CK_RV rv;
323
324 if (slot != -1 && slot != current)
325 {
326 continue;
327 }
328 if (module && !streq(module, p11->get_name(p11)))
329 {
330 continue;
331 }
332
333 rv = p11->f->C_OpenSession(current, CKF_SERIAL_SESSION, NULL, NULL,
334 &session);
335 if (rv != CKR_OK)
336 {
337 DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv);
338 continue;
339 }
340 certs = p11->create_object_enumerator(p11, session,
341 tmpl, countof(tmpl), attr, countof(attr));
342 if (certs->enumerate(certs, &object))
343 {
344 data = chunk_clone(chunk_create(attr[0].pValue, attr[0].ulValueLen));
345 }
346 certs->destroy(certs);
347 p11->f->C_CloseSession(session);
348
349 if (data.ptr)
350 {
351 break;
352 }
353 }
354 enumerator->destroy(enumerator);
355
356 if (data.ptr)
357 {
358 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
359 BUILD_BLOB_ASN1_DER, data, BUILD_END);
360 free(data.ptr);
361 if (!cert)
362 {
363 DBG1(DBG_CFG, "parsing PKCS#11 certificate %#B failed", &keyid);
364 }
365 }
366 else
367 {
368 DBG1(DBG_CFG, "PKCS#11 certificate %#B not found", &keyid);
369 }
370 return cert;
371 }