2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
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>.
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
16 #include "pkcs11_private_key.h"
18 #include "pkcs11_library.h"
19 #include "pkcs11_manager.h"
22 #include <threading/mutex.h>
24 typedef struct private_pkcs11_private_key_t private_pkcs11_private_key_t
;
27 * Private data of an pkcs11_private_key_t object.
29 struct private_pkcs11_private_key_t
{
32 * Public pkcs11_private_key_t interface.
34 pkcs11_private_key_t
public;
39 pkcs11_library_t
*lib
;
44 CK_SESSION_HANDLE session
;
47 * Mutex to lock session
52 * Key object on the token
54 CK_OBJECT_HANDLE object
;
57 * Associated public key
62 * References to this key
67 METHOD(private_key_t
, get_type
, key_type_t
,
68 private_pkcs11_private_key_t
*this)
70 return this->pubkey
->get_type(this->pubkey
);
73 METHOD(private_key_t
, get_keysize
, size_t,
74 private_pkcs11_private_key_t
*this)
76 return this->pubkey
->get_keysize(this->pubkey
);
80 * Get the Cryptoki mechanism for a signature scheme
82 static CK_MECHANISM_PTR
scheme_to_mechanism(signature_scheme_t scheme
)
85 signature_scheme_t scheme
;
86 CK_MECHANISM mechanism
;
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}},
97 for (i
= 0; i
< countof(mappings
); i
++)
99 if (mappings
[i
].scheme
== scheme
)
101 return &mappings
[i
].mechanism
;
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
)
111 CK_MECHANISM_PTR mechanism
;
116 mechanism
= scheme_to_mechanism(scheme
);
119 DBG1(DBG_LIB
, "signature scheme %N not supported",
120 signature_scheme_names
, scheme
);
123 this->mutex
->lock(this->mutex
);
124 rv
= this->lib
->f
->C_SignInit(this->session
, mechanism
, this->object
);
127 this->mutex
->unlock(this->mutex
);
128 DBG1(DBG_LIB
, "C_SignInit() failed: %N", ck_rv_names
, rv
);
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
);
136 DBG1(DBG_LIB
, "C_Sign() failed: %N", ck_rv_names
, rv
);
140 *signature
= chunk_create(buf
, len
);
144 METHOD(private_key_t
, decrypt
, bool,
145 private_pkcs11_private_key_t
*this, chunk_t crypto
, chunk_t
*plain
)
150 METHOD(private_key_t
, get_public_key
, public_key_t
*,
151 private_pkcs11_private_key_t
*this)
153 return this->pubkey
->get_ref(this->pubkey
);
156 METHOD(private_key_t
, get_fingerprint
, bool,
157 private_pkcs11_private_key_t
*this, cred_encoding_type_t type
,
158 chunk_t
*fingerprint
)
160 return this->pubkey
->get_fingerprint(this->pubkey
, type
, fingerprint
);
163 METHOD(private_key_t
, get_encoding
, bool,
164 private_pkcs11_private_key_t
*this, cred_encoding_type_t type
,
170 METHOD(private_key_t
, get_ref
, private_key_t
*,
171 private_pkcs11_private_key_t
*this)
174 return &this->public.key
;
177 METHOD(private_key_t
, destroy
, void,
178 private_pkcs11_private_key_t
*this)
180 if (ref_put(&this->ref
))
184 this->pubkey
->destroy(this->pubkey
);
186 this->mutex
->destroy(this->mutex
);
187 this->lib
->f
->C_CloseSession(this->session
);
193 * Find the PKCS#11 library by its friendly name
195 static pkcs11_library_t
* find_lib(char *module
)
197 pkcs11_manager_t
*manager
;
198 enumerator_t
*enumerator
;
199 pkcs11_library_t
*p11
, *found
= NULL
;
202 manager
= pkcs11_manager_get();
207 enumerator
= manager
->create_token_enumerator(manager
);
208 while (enumerator
->enumerate(enumerator
, &p11
, &slot
))
210 if (streq(module
, p11
->get_name(p11
)))
216 enumerator
->destroy(enumerator
);
221 * Find the key on the token
223 static bool find_key(private_pkcs11_private_key_t
*this, chunk_t keyid
)
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
},
230 CK_OBJECT_HANDLE object
;
232 CK_ATTRIBUTE attr
[] = {
233 {CKA_KEY_TYPE
, &type
, sizeof(type
)},
234 {CKA_MODULUS
, NULL
, 0},
235 {CKA_PUBLIC_EXPONENT
, NULL
, 0},
237 enumerator_t
*enumerator
;
238 chunk_t modulus
, pubexp
;
240 enumerator
= this->lib
->create_object_enumerator(this->lib
,
241 this->session
, tmpl
, countof(tmpl
), attr
, countof(attr
));
242 if (enumerator
->enumerate(enumerator
, &object
))
247 if (attr
[0].ulValueLen
== -1 || attr
[1].ulValueLen
== -1)
249 DBG1(DBG_CFG
, "reading modulus/exponent from PKCS#1 failed");
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
);
259 DBG1(DBG_CFG
, "extracting public key from PKCS#11 RSA "
260 "private key failed");
262 this->object
= object
;
265 DBG1(DBG_CFG
, "PKCS#11 key type %d not supported", type
);
269 enumerator
->destroy(enumerator
);
270 return this->pubkey
!= NULL
;
276 pkcs11_private_key_t
*pkcs11_private_key_connect(key_type_t type
, va_list args
)
278 private_pkcs11_private_key_t
*this;
279 char *keyid
= NULL
, *pin
= NULL
, *module
= NULL
;
286 switch (va_arg(args
, builder_part_t
))
288 case BUILD_PKCS11_KEYID
:
289 keyid
= va_arg(args
, char*);
291 case BUILD_PKCS11_PIN
:
292 pin
= va_arg(args
, char*);
294 case BUILD_PKCS11_SLOT
:
295 slot
= va_arg(args
, int);
297 case BUILD_PKCS11_MODULE
:
298 module
= va_arg(args
, char*);
307 if (!keyid
|| !pin
|| !module
|| slot
== -1)
308 { /* we currently require all parameters, TODO: search for pubkeys */
314 .get_type
= _get_type
,
317 .get_keysize
= _get_keysize
,
318 .get_public_key
= _get_public_key
,
319 .equals
= private_key_equals
,
320 .belongs_to
= private_key_belongs_to
,
321 .get_fingerprint
= _get_fingerprint
,
322 .has_fingerprint
= private_key_has_fingerprint
,
323 .get_encoding
= _get_encoding
,
330 this->lib
= find_lib(module
);
333 DBG1(DBG_CFG
, "PKCS#11 module '%s' not found", module
);
338 rv
= this->lib
->f
->C_OpenSession(slot
, CKF_SERIAL_SESSION
,
339 NULL
, NULL
, &this->session
);
342 DBG1(DBG_CFG
, "opening private key session on '%s':%d failed: %N",
343 module
, slot
, ck_rv_names
, rv
);
348 this->mutex
= mutex_create(MUTEX_TYPE_DEFAULT
);
350 rv
= this->lib
->f
->C_Login(this->session
, CKU_USER
, pin
, strlen(pin
));
353 DBG1(DBG_CFG
, "login to '%s':%d failed: %N",
354 module
, slot
, ck_rv_names
, rv
);
359 chunk
= chunk_from_hex(chunk_create(keyid
, strlen(keyid
)), NULL
);
360 if (!find_key(this, chunk
))
368 return &this->public;