Make sure first argument is an int when using %.*s to print e.g. chunks
[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
18 #include <debug.h>
19 #include <utils/linked_list.h>
20
21 typedef struct private_pkcs11_creds_t private_pkcs11_creds_t;
22
23 /**
24 * Private data of an pkcs11_creds_t object.
25 */
26 struct private_pkcs11_creds_t {
27
28 /**
29 * Public pkcs11_creds_t interface.
30 */
31 pkcs11_creds_t public;
32
33 /**
34 * PKCS# library
35 */
36 pkcs11_library_t *lib;
37
38 /**
39 * Token slot
40 */
41 CK_SLOT_ID slot;
42
43 /**
44 * List of trusted certificates
45 */
46 linked_list_t *trusted;
47
48 /**
49 * List of untrusted certificates
50 */
51 linked_list_t *untrusted;
52 };
53
54 /**
55 * Find certificates, optionally trusted
56 */
57 static void find_certificates(private_pkcs11_creds_t *this,
58 CK_SESSION_HANDLE session)
59 {
60 CK_OBJECT_CLASS class = CKO_CERTIFICATE;
61 CK_CERTIFICATE_TYPE type = CKC_X_509;
62 CK_BBOOL trusted = TRUE;
63 CK_ATTRIBUTE tmpl[] = {
64 {CKA_CLASS, &class, sizeof(class)},
65 {CKA_CERTIFICATE_TYPE, &type, sizeof(type)},
66 };
67 CK_OBJECT_HANDLE object;
68 CK_ATTRIBUTE attr[] = {
69 {CKA_VALUE, NULL, 0},
70 {CKA_LABEL, NULL, 0},
71 {CKA_TRUSTED, &trusted, sizeof(trusted)}
72 };
73 enumerator_t *enumerator;
74 linked_list_t *raw;
75 certificate_t *cert;
76 struct {
77 chunk_t value;
78 chunk_t label;
79 bool trusted;
80 } *entry;
81 int count = countof(attr);
82
83 /* store result in a temporary list, avoid recursive operation */
84 raw = linked_list_create();
85 /* do not use trusted argument if not supported */
86 if (!(this->lib->get_features(this->lib) & PKCS11_TRUSTED_CERTS))
87 {
88 count--;
89 }
90 enumerator = this->lib->create_object_enumerator(this->lib,
91 session, tmpl, countof(tmpl), attr, count);
92 while (enumerator->enumerate(enumerator, &object))
93 {
94 entry = malloc(sizeof(*entry));
95 entry->value = chunk_clone(
96 chunk_create(attr[0].pValue, attr[0].ulValueLen));
97 entry->label = chunk_clone(
98 chunk_create(attr[1].pValue, attr[1].ulValueLen));
99 entry->trusted = trusted;
100 raw->insert_last(raw, entry);
101 }
102 enumerator->destroy(enumerator);
103
104 while (raw->remove_first(raw, (void**)&entry) == SUCCESS)
105 {
106 cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509,
107 BUILD_BLOB_ASN1_DER, entry->value,
108 BUILD_END);
109 if (cert)
110 {
111 DBG1(DBG_CFG, " loaded %strusted cert '%.*s'",
112 entry->trusted ? "" : "un", (int)entry->label.len,
113 entry->label.ptr);
114 /* trusted certificates are also returned as untrusted */
115 this->untrusted->insert_last(this->untrusted, cert);
116 if (entry->trusted)
117 {
118 this->trusted->insert_last(this->trusted, cert->get_ref(cert));
119 }
120 }
121 else
122 {
123 DBG1(DBG_CFG, " loading cert '%.*s' failed",
124 (int)entry->label.len, entry->label.ptr);
125 }
126 free(entry->value.ptr);
127 free(entry->label.ptr);
128 free(entry);
129 }
130 raw->destroy(raw);
131 }
132
133 /**
134 * Load in the certificates from the token
135 */
136 static bool load_certificates(private_pkcs11_creds_t *this)
137 {
138 CK_SESSION_HANDLE session;
139 CK_RV rv;
140
141 rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION,
142 NULL, NULL, &session);
143 if (rv != CKR_OK)
144 {
145 DBG1(DBG_CFG, "opening session failed: %N", ck_rv_names, rv);
146 return FALSE;
147 }
148
149 find_certificates(this, session);
150
151 this->lib->f->C_CloseSession(session);
152 return TRUE;
153 }
154
155 /**
156 * filter function for certs enumerator
157 */
158 static bool certs_filter(identification_t *id,
159 certificate_t **in, certificate_t **out)
160 {
161 public_key_t *public;
162 certificate_t *cert = *in;
163
164 if (id == NULL || cert->has_subject(cert, id))
165 {
166 *out = *in;
167 return TRUE;
168 }
169 public = cert->get_public_key(cert);
170 if (public)
171 {
172 if (public->has_fingerprint(public, id->get_encoding(id)))
173 {
174 public->destroy(public);
175 *out = *in;
176 return TRUE;
177 }
178 public->destroy(public);
179 }
180 return FALSE;
181 }
182
183 METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
184 private_pkcs11_creds_t *this, certificate_type_t cert, key_type_t key,
185 identification_t *id, bool trusted)
186 {
187 enumerator_t *inner;
188
189 if (cert != CERT_X509 && cert != CERT_ANY)
190 {
191 return NULL;
192 }
193 if (trusted)
194 {
195 inner = this->trusted->create_enumerator(this->trusted);
196 }
197 else
198 {
199 inner = this->untrusted->create_enumerator(this->untrusted);
200 }
201 return enumerator_create_filter(inner, (void*)certs_filter, id, NULL);
202 }
203
204 METHOD(pkcs11_creds_t, get_library, pkcs11_library_t*,
205 private_pkcs11_creds_t *this)
206 {
207 return this->lib;
208 }
209
210 METHOD(pkcs11_creds_t, get_slot, CK_SLOT_ID,
211 private_pkcs11_creds_t *this)
212 {
213 return this->slot;
214 }
215
216 METHOD(pkcs11_creds_t, destroy, void,
217 private_pkcs11_creds_t *this)
218 {
219 this->trusted->destroy_offset(this->trusted,
220 offsetof(certificate_t, destroy));
221 this->untrusted->destroy_offset(this->untrusted,
222 offsetof(certificate_t, destroy));
223 free(this);
224 }
225
226 /**
227 * See header
228 */
229 pkcs11_creds_t *pkcs11_creds_create(pkcs11_library_t *p11, CK_SLOT_ID slot)
230 {
231 private_pkcs11_creds_t *this;
232
233 INIT(this,
234 .public = {
235 .set = {
236 .create_shared_enumerator = (void*)enumerator_create_empty,
237 .create_private_enumerator = (void*)enumerator_create_empty,
238 .create_cert_enumerator = _create_cert_enumerator,
239 .create_cdp_enumerator = (void*)enumerator_create_empty,
240 .cache_cert = (void*)nop,
241 },
242 .get_library = _get_library,
243 .get_slot = _get_slot,
244 .destroy = _destroy,
245 },
246 .lib = p11,
247 .slot = slot,
248 .trusted = linked_list_create(),
249 .untrusted = linked_list_create(),
250 );
251
252 if (!load_certificates(this))
253 {
254 destroy(this);
255 return NULL;
256 }
257
258 return &this->public;
259 }