Avoid memory leak when sending RADIUS accounting start message failed
[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", entry->label.len, entry->label.ptr);
113 /* trusted certificates are also returned as untrusted */
114 this->untrusted->insert_last(this->untrusted, cert);
115 if (entry->trusted)
116 {
117 this->trusted->insert_last(this->trusted, cert->get_ref(cert));
118 }
119 }
120 else
121 {
122 DBG1(DBG_CFG, " loading cert '%.*s' failed",
123 entry->label.len, entry->label.ptr);
124 }
125 free(entry->value.ptr);
126 free(entry->label.ptr);
127 free(entry);
128 }
129 raw->destroy(raw);
130 }
131
132 /**
133 * Load in the certificates from the token
134 */
135 static bool load_certificates(private_pkcs11_creds_t *this)
136 {
137 CK_SESSION_HANDLE session;
138 CK_RV rv;
139
140 rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION,
141 NULL, NULL, &session);
142 if (rv != CKR_OK)
143 {
144 DBG1(DBG_CFG, "opening session failed: %N", ck_rv_names, rv);
145 return FALSE;
146 }
147
148 find_certificates(this, session);
149
150 this->lib->f->C_CloseSession(session);
151 return TRUE;
152 }
153
154 /**
155 * filter function for certs enumerator
156 */
157 static bool certs_filter(identification_t *id,
158 certificate_t **in, certificate_t **out)
159 {
160 public_key_t *public;
161 certificate_t *cert = *in;
162
163 if (id == NULL || cert->has_subject(cert, id))
164 {
165 *out = *in;
166 return TRUE;
167 }
168 public = cert->get_public_key(cert);
169 if (public)
170 {
171 if (public->has_fingerprint(public, id->get_encoding(id)))
172 {
173 public->destroy(public);
174 *out = *in;
175 return TRUE;
176 }
177 public->destroy(public);
178 }
179 return FALSE;
180 }
181
182 METHOD(credential_set_t, create_cert_enumerator, enumerator_t*,
183 private_pkcs11_creds_t *this, certificate_type_t cert, key_type_t key,
184 identification_t *id, bool trusted)
185 {
186 enumerator_t *inner;
187
188 if (cert != CERT_X509 && cert != CERT_ANY)
189 {
190 return NULL;
191 }
192 if (trusted)
193 {
194 inner = this->trusted->create_enumerator(this->trusted);
195 }
196 else
197 {
198 inner = this->untrusted->create_enumerator(this->untrusted);
199 }
200 return enumerator_create_filter(inner, (void*)certs_filter, id, NULL);
201 }
202
203 METHOD(pkcs11_creds_t, get_library, pkcs11_library_t*,
204 private_pkcs11_creds_t *this)
205 {
206 return this->lib;
207 }
208
209 METHOD(pkcs11_creds_t, get_slot, CK_SLOT_ID,
210 private_pkcs11_creds_t *this)
211 {
212 return this->slot;
213 }
214
215 METHOD(pkcs11_creds_t, destroy, void,
216 private_pkcs11_creds_t *this)
217 {
218 this->trusted->destroy_offset(this->trusted,
219 offsetof(certificate_t, destroy));
220 this->untrusted->destroy_offset(this->untrusted,
221 offsetof(certificate_t, destroy));
222 free(this);
223 }
224
225 /**
226 * See header
227 */
228 pkcs11_creds_t *pkcs11_creds_create(pkcs11_library_t *p11, CK_SLOT_ID slot)
229 {
230 private_pkcs11_creds_t *this;
231
232 INIT(this,
233 .public = {
234 .set = {
235 .create_shared_enumerator = (void*)enumerator_create_empty,
236 .create_private_enumerator = (void*)enumerator_create_empty,
237 .create_cert_enumerator = _create_cert_enumerator,
238 .create_cdp_enumerator = (void*)enumerator_create_empty,
239 .cache_cert = (void*)nop,
240 },
241 .get_library = _get_library,
242 .get_slot = _get_slot,
243 .destroy = _destroy,
244 },
245 .lib = p11,
246 .slot = slot,
247 .trusted = linked_list_create(),
248 .untrusted = linked_list_create(),
249 );
250
251 if (!load_certificates(this))
252 {
253 destroy(this);
254 return NULL;
255 }
256
257 return &this->public;
258 }