Pass the PKCS11 keyid as chunk, not as string
[strongswan.git] / src / libstrongswan / plugins / pkcs11 / pkcs11_private_key.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_private_key.h"
17
18 #include "pkcs11_library.h"
19 #include "pkcs11_manager.h"
20
21 #include <debug.h>
22 #include <threading/mutex.h>
23
24 typedef struct private_pkcs11_private_key_t private_pkcs11_private_key_t;
25
26 /**
27 * Private data of an pkcs11_private_key_t object.
28 */
29 struct private_pkcs11_private_key_t {
30
31 /**
32 * Public pkcs11_private_key_t interface.
33 */
34 pkcs11_private_key_t public;
35
36 /**
37 * PKCS#11 module
38 */
39 pkcs11_library_t *lib;
40
41 /**
42 * Token session
43 */
44 CK_SESSION_HANDLE session;
45
46 /**
47 * Mutex to lock session
48 */
49 mutex_t *mutex;
50
51 /**
52 * Key object on the token
53 */
54 CK_OBJECT_HANDLE object;
55
56 /**
57 * Associated public key
58 */
59 public_key_t *pubkey;
60
61 /**
62 * References to this key
63 */
64 refcount_t ref;
65 };
66
67 METHOD(private_key_t, get_type, key_type_t,
68 private_pkcs11_private_key_t *this)
69 {
70 return this->pubkey->get_type(this->pubkey);
71 }
72
73 METHOD(private_key_t, get_keysize, size_t,
74 private_pkcs11_private_key_t *this)
75 {
76 return this->pubkey->get_keysize(this->pubkey);
77 }
78
79 /**
80 * Get the Cryptoki mechanism for a signature scheme
81 */
82 static CK_MECHANISM_PTR scheme_to_mechanism(signature_scheme_t scheme)
83 {
84 static struct {
85 signature_scheme_t scheme;
86 CK_MECHANISM mechanism;
87 } mappings[] = {
88 {SIGN_RSA_EMSA_PKCS1_NULL, {CKM_RSA_PKCS, NULL, 0}},
89 {SIGN_RSA_EMSA_PKCS1_SHA1, {CKM_SHA1_RSA_PKCS, NULL, 0}},
90 {SIGN_RSA_EMSA_PKCS1_SHA256, {CKM_SHA256_RSA_PKCS, NULL, 0}},
91 {SIGN_RSA_EMSA_PKCS1_SHA384, {CKM_SHA384_RSA_PKCS, NULL, 0}},
92 {SIGN_RSA_EMSA_PKCS1_SHA512, {CKM_SHA512_RSA_PKCS, NULL, 0}},
93 {SIGN_RSA_EMSA_PKCS1_MD5, {CKM_MD5_RSA_PKCS, NULL, 0}},
94 };
95 int i;
96
97 for (i = 0; i < countof(mappings); i++)
98 {
99 if (mappings[i].scheme == scheme)
100 {
101 return &mappings[i].mechanism;
102 }
103 }
104 return NULL;
105 }
106
107 METHOD(private_key_t, sign, bool,
108 private_pkcs11_private_key_t *this, signature_scheme_t scheme,
109 chunk_t data, chunk_t *signature)
110 {
111 CK_MECHANISM_PTR mechanism;
112 CK_BYTE_PTR buf;
113 CK_ULONG len;
114 CK_RV rv;
115
116 mechanism = scheme_to_mechanism(scheme);
117 if (!mechanism)
118 {
119 DBG1(DBG_LIB, "signature scheme %N not supported",
120 signature_scheme_names, scheme);
121 return FALSE;
122 }
123 this->mutex->lock(this->mutex);
124 rv = this->lib->f->C_SignInit(this->session, mechanism, this->object);
125 if (rv != CKR_OK)
126 {
127 this->mutex->unlock(this->mutex);
128 DBG1(DBG_LIB, "C_SignInit() failed: %N", ck_rv_names, rv);
129 return FALSE;
130 }
131 buf = malloc(get_keysize(this));
132 rv = this->lib->f->C_Sign(this->session, data.ptr, data.len, buf, &len);
133 this->mutex->unlock(this->mutex);
134 if (rv != CKR_OK)
135 {
136 DBG1(DBG_LIB, "C_Sign() failed: %N", ck_rv_names, rv);
137 free(buf);
138 return FALSE;
139 }
140 *signature = chunk_create(buf, len);
141 return TRUE;
142 }
143
144 METHOD(private_key_t, decrypt, bool,
145 private_pkcs11_private_key_t *this, chunk_t crypto, chunk_t *plain)
146 {
147 return FALSE;
148 }
149
150 METHOD(private_key_t, get_public_key, public_key_t*,
151 private_pkcs11_private_key_t *this)
152 {
153 return this->pubkey->get_ref(this->pubkey);
154 }
155
156 METHOD(private_key_t, get_fingerprint, bool,
157 private_pkcs11_private_key_t *this, cred_encoding_type_t type,
158 chunk_t *fingerprint)
159 {
160 return this->pubkey->get_fingerprint(this->pubkey, type, fingerprint);
161 }
162
163 METHOD(private_key_t, get_encoding, bool,
164 private_pkcs11_private_key_t *this, cred_encoding_type_t type,
165 chunk_t *encoding)
166 {
167 return FALSE;
168 }
169
170 METHOD(private_key_t, get_ref, private_key_t*,
171 private_pkcs11_private_key_t *this)
172 {
173 ref_get(&this->ref);
174 return &this->public.key;
175 }
176
177 METHOD(private_key_t, destroy, void,
178 private_pkcs11_private_key_t *this)
179 {
180 if (ref_put(&this->ref))
181 {
182 if (this->pubkey)
183 {
184 this->pubkey->destroy(this->pubkey);
185 }
186 this->mutex->destroy(this->mutex);
187 this->lib->f->C_CloseSession(this->session);
188 free(this);
189 }
190 }
191
192 /**
193 * Find the PKCS#11 library by its friendly name
194 */
195 static pkcs11_library_t* find_lib(char *module)
196 {
197 pkcs11_manager_t *manager;
198 enumerator_t *enumerator;
199 pkcs11_library_t *p11, *found = NULL;
200 CK_SLOT_ID slot;
201
202 manager = pkcs11_manager_get();
203 if (!manager)
204 {
205 return NULL;
206 }
207 enumerator = manager->create_token_enumerator(manager);
208 while (enumerator->enumerate(enumerator, &p11, &slot))
209 {
210 if (streq(module, p11->get_name(p11)))
211 {
212 found = p11;
213 break;
214 }
215 }
216 enumerator->destroy(enumerator);
217 return found;
218 }
219
220 /**
221 * Find the key on the token
222 */
223 static bool find_key(private_pkcs11_private_key_t *this, chunk_t keyid)
224 {
225 CK_OBJECT_CLASS class = CKO_PRIVATE_KEY;
226 CK_ATTRIBUTE tmpl[] = {
227 {CKA_CLASS, &class, sizeof(class)},
228 {CKA_ID, keyid.ptr, keyid.len},
229 };
230 CK_OBJECT_HANDLE object;
231 CK_KEY_TYPE type;
232 CK_ATTRIBUTE attr[] = {
233 {CKA_KEY_TYPE, &type, sizeof(type)},
234 {CKA_MODULUS, NULL, 0},
235 {CKA_PUBLIC_EXPONENT, NULL, 0},
236 };
237 enumerator_t *enumerator;
238 chunk_t modulus, pubexp;
239
240 enumerator = this->lib->create_object_enumerator(this->lib,
241 this->session, tmpl, countof(tmpl), attr, countof(attr));
242 if (enumerator->enumerate(enumerator, &object))
243 {
244 switch (type)
245 {
246 case CKK_RSA:
247 if (attr[0].ulValueLen == -1 || attr[1].ulValueLen == -1)
248 {
249 DBG1(DBG_CFG, "reading modulus/exponent from PKCS#1 failed");
250 break;
251 }
252 modulus = chunk_create(attr[1].pValue, attr[1].ulValueLen);
253 pubexp = chunk_create(attr[2].pValue, attr[2].ulValueLen);
254 this->pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY,
255 KEY_RSA, BUILD_RSA_MODULUS, modulus,
256 BUILD_RSA_PUB_EXP, pubexp, BUILD_END);
257 if (!this->pubkey)
258 {
259 DBG1(DBG_CFG, "extracting public key from PKCS#11 RSA "
260 "private key failed");
261 }
262 this->object = object;
263 break;
264 default:
265 DBG1(DBG_CFG, "PKCS#11 key type %d not supported", type);
266 break;
267 }
268 }
269 enumerator->destroy(enumerator);
270 return this->pubkey != NULL;
271 }
272
273 /**
274 * See header.
275 */
276 pkcs11_private_key_t *pkcs11_private_key_connect(key_type_t type, va_list args)
277 {
278 private_pkcs11_private_key_t *this;
279 char *module = NULL;
280 chunk_t keyid, pin;
281 int slot = -1;
282 CK_RV rv;
283
284 keyid = pin = chunk_empty;
285 while (TRUE)
286 {
287 switch (va_arg(args, builder_part_t))
288 {
289 case BUILD_PKCS11_KEYID:
290 keyid = va_arg(args, chunk_t);
291 continue;
292 case BUILD_PASSPHRASE:
293 pin = va_arg(args, chunk_t);
294 continue;
295 case BUILD_PKCS11_SLOT:
296 slot = va_arg(args, int);
297 continue;
298 case BUILD_PKCS11_MODULE:
299 module = va_arg(args, char*);
300 continue;
301 case BUILD_END:
302 break;
303 default:
304 return NULL;
305 }
306 break;
307 }
308 if (!keyid.len || !pin.len || !module || slot == -1)
309 { /* we currently require all parameters, TODO: search for pubkeys */
310 return NULL;
311 }
312
313 INIT(this,
314 .public.key = {
315 .get_type = _get_type,
316 .sign = _sign,
317 .decrypt = _decrypt,
318 .get_keysize = _get_keysize,
319 .get_public_key = _get_public_key,
320 .equals = private_key_equals,
321 .belongs_to = private_key_belongs_to,
322 .get_fingerprint = _get_fingerprint,
323 .has_fingerprint = private_key_has_fingerprint,
324 .get_encoding = _get_encoding,
325 .get_ref = _get_ref,
326 .destroy = _destroy,
327 },
328 .ref = 1,
329 );
330
331 this->lib = find_lib(module);
332 if (!this->lib)
333 {
334 DBG1(DBG_CFG, "PKCS#11 module '%s' not found", module);
335 free(this);
336 return NULL;
337 }
338
339 rv = this->lib->f->C_OpenSession(slot, CKF_SERIAL_SESSION,
340 NULL, NULL, &this->session);
341 if (rv != CKR_OK)
342 {
343 DBG1(DBG_CFG, "opening private key session on '%s':%d failed: %N",
344 module, slot, ck_rv_names, rv);
345 free(this);
346 return NULL;
347 }
348
349 this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
350
351 rv = this->lib->f->C_Login(this->session, CKU_USER, pin.ptr, pin.len);
352 if (rv != CKR_OK)
353 {
354 DBG1(DBG_CFG, "login to '%s':%d failed: %N",
355 module, slot, ck_rv_names, rv);
356 destroy(this);
357 return NULL;
358 }
359
360 if (!find_key(this, keyid))
361 {
362 destroy(this);
363 return NULL;
364 }
365
366 return &this->public;
367 }