Tizen 2.0 Release
[external/libgnutls26.git] / lib / pkcs11_privkey.c
1 /*
2  * GnuTLS PKCS#11 support
3  * Copyright (C) 2010,2011 Free Software Foundation
4  * 
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the Free
19  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20  * MA 02111-1307, USA
21 */
22
23 #include <gnutls_int.h>
24 #include <gnutls/pkcs11.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <gnutls_errors.h>
28 #include <gnutls_datum.h>
29 #include <pkcs11_int.h>
30 #include <gnutls_sig.h>
31 #include <p11-kit/uri.h>
32
33 struct gnutls_pkcs11_privkey_st
34 {
35   gnutls_pk_algorithm_t pk_algorithm;
36   unsigned int flags;
37   struct p11_kit_uri *info;
38   gnutls_pkcs11_pin_callback_t pin_func;
39   void *pin_data;
40 };
41
42 /**
43  * gnutls_pkcs11_privkey_init:
44  * @key: The structure to be initialized
45  *
46  * This function will initialize an private key structure.
47  *
48  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
49  *   negative error value.
50  **/
51 int
52 gnutls_pkcs11_privkey_init (gnutls_pkcs11_privkey_t * key)
53 {
54   *key = gnutls_calloc (1, sizeof (struct gnutls_pkcs11_privkey_st));
55   if (*key == NULL)
56     {
57       gnutls_assert ();
58       return GNUTLS_E_MEMORY_ERROR;
59     }
60
61   (*key)->info = p11_kit_uri_new ();
62   if ((*key)->info == NULL)
63     {
64       free (*key);
65       gnutls_assert ();
66       return GNUTLS_E_MEMORY_ERROR;
67     }
68
69   return 0;
70 }
71
72 /**
73  * gnutls_pkcs11_privkey_deinit:
74  * @key: The structure to be initialized
75  *
76  * This function will deinitialize a private key structure.
77  **/
78 void
79 gnutls_pkcs11_privkey_deinit (gnutls_pkcs11_privkey_t key)
80 {
81   p11_kit_uri_free (key->info);
82   gnutls_free (key);
83 }
84
85 /**
86  * gnutls_pkcs11_privkey_get_pk_algorithm:
87  * @key: should contain a #gnutls_pkcs11_privkey_t structure
88  *
89  * This function will return the public key algorithm of a private
90  * key.
91  *
92  * Returns: a member of the #gnutls_pk_algorithm_t enumeration on
93  *   success, or a negative value on error.
94  **/
95 int
96 gnutls_pkcs11_privkey_get_pk_algorithm (gnutls_pkcs11_privkey_t key,
97                                         unsigned int *bits)
98 {
99   if (bits)
100     *bits = 0;                  /* FIXME */
101   return key->pk_algorithm;
102 }
103
104 /**
105  * gnutls_pkcs11_privkey_get_info:
106  * @pkey: should contain a #gnutls_pkcs11_privkey_t structure
107  * @itype: Denotes the type of information requested
108  * @output: where output will be stored
109  * @output_size: contains the maximum size of the output and will be overwritten with actual
110  *
111  * This function will return information about the PKCS 11 private key such
112  * as the label, id as well as token information where the key is stored. When
113  * output is text it returns null terminated string although #output_size contains
114  * the size of the actual data only.
115  *
116  * Returns: zero on success or a negative value on error.
117  **/
118 int
119 gnutls_pkcs11_privkey_get_info (gnutls_pkcs11_privkey_t pkey,
120                                 gnutls_pkcs11_obj_info_t itype,
121                                 void *output, size_t * output_size)
122 {
123   return pkcs11_get_info (pkey->info, itype, output, output_size);
124 }
125
126
127 #define FIND_OBJECT(module, pks, obj, key) \
128         do { \
129                 int retries = 0; \
130                 int rret; \
131                 ret = pkcs11_find_object (&module, &pks, &obj, key->info, \
132                         SESSION_LOGIN); \
133                 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { \
134                         if (token_func) \
135                           { \
136                             rret = pkcs11_call_token_func (key->info, retries++); \
137                             if (rret == 0) continue; \
138                           } \
139                         gnutls_assert(); \
140                         return ret; \
141                 } else if (ret < 0) { \
142                         return ret; \
143                 } \
144         } while (0);
145
146 /*-
147  * _gnutls_pkcs11_privkey_sign_hash:
148  * @key: Holds the key
149  * @hash: holds the data to be signed (should be output of a hash)
150  * @signature: will contain the signature allocated with gnutls_malloc()
151  *
152  * This function will sign the given data using a signature algorithm
153  * supported by the private key. It is assumed that the given data
154  * are the output of a hash function.
155  *
156  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
157  *   negative error value.
158  -*/
159 int
160 _gnutls_pkcs11_privkey_sign_hash (gnutls_pkcs11_privkey_t key,
161                                   const gnutls_datum_t * hash,
162                                   gnutls_datum_t * signature)
163 {
164   ck_rv_t rv;
165   int ret;
166   struct ck_mechanism mech;
167   unsigned long siglen;
168   struct ck_function_list *module;
169   ck_session_handle_t pks;
170   ck_object_handle_t obj;
171
172   FIND_OBJECT (module, pks, obj, key);
173
174   mech.mechanism =
175     key->pk_algorithm == GNUTLS_PK_DSA ? CKM_DSA : CKM_RSA_PKCS;
176   mech.parameter = NULL;
177   mech.parameter_len = 0;
178
179   /* Initialize signing operation; using the private key discovered
180    * earlier. */
181   rv = pkcs11_sign_init (module, pks, &mech, obj);
182   if (rv != CKR_OK)
183     {
184       gnutls_assert ();
185       ret = pkcs11_rv_to_err (rv);
186       goto cleanup;
187     }
188
189   /* Work out how long the signature must be: */
190   rv = pkcs11_sign (module, pks, hash->data, hash->size, NULL, &siglen);
191   if (rv != CKR_OK)
192     {
193       gnutls_assert ();
194       ret = pkcs11_rv_to_err (rv);
195       goto cleanup;
196     }
197
198   signature->data = gnutls_malloc (siglen);
199   signature->size = siglen;
200
201   rv = pkcs11_sign (module, pks, hash->data, hash->size, signature->data, &siglen);
202   if (rv != CKR_OK)
203     {
204       gnutls_free (signature->data);
205       gnutls_assert ();
206       ret = pkcs11_rv_to_err (rv);
207       goto cleanup;
208     }
209
210   signature->size = siglen;
211
212   ret = 0;
213
214 cleanup:
215   pkcs11_close_session (module, pks);
216
217   return ret;
218 }
219
220 /**
221  * gnutls_pkcs11_privkey_import_url:
222  * @pkey: The structure to store the parsed key
223  * @url: a PKCS 11 url identifying the key
224  * @flags: sequence of GNUTLS_PKCS_PRIVKEY_*
225  *
226  * This function will "import" a PKCS 11 URL identifying a private
227  * key to the #gnutls_pkcs11_privkey_t structure. In reality since
228  * in most cases keys cannot be exported, the private key structure
229  * is being associated with the available operations on the token.
230  *
231  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
232  *   negative error value.
233  **/
234 int
235 gnutls_pkcs11_privkey_import_url (gnutls_pkcs11_privkey_t pkey,
236                                   const char *url, unsigned int flags)
237 {
238   int ret;
239   struct ck_function_list *module;
240   struct ck_attribute *attr;
241   ck_session_handle_t pks;
242   ck_object_handle_t obj;
243   struct ck_attribute a[4];
244   ck_key_type_t key_type;
245
246   ret = pkcs11_url_to_info (url, &pkey->info);
247   if (ret < 0)
248     {
249       gnutls_assert ();
250       return ret;
251     }
252
253   pkey->flags = flags;
254
255   attr = p11_kit_uri_get_attribute (pkey->info, CKA_CLASS);
256   if (!attr || attr->value_len != sizeof (ck_object_class_t) ||
257       *(ck_object_class_t*)attr->value != CKO_PRIVATE_KEY)
258     {
259       gnutls_assert ();
260       return GNUTLS_E_INVALID_REQUEST;
261     }
262
263   attr = p11_kit_uri_get_attribute (pkey->info, CKA_ID);
264   if (!attr || !attr->value_len)
265     {
266       gnutls_assert ();
267       return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
268     }
269
270   FIND_OBJECT (module, pks, obj, pkey);
271   a[0].type = CKA_KEY_TYPE;
272   a[0].value = &key_type;
273   a[0].value_len = sizeof (key_type);
274
275   if (pkcs11_get_attribute_value (module, pks, obj, a, 1) == CKR_OK)
276     {
277       switch (key_type)
278         {
279         case CKK_RSA:
280           pkey->pk_algorithm = GNUTLS_PK_RSA;
281           break;
282         case CKK_DSA:
283           pkey->pk_algorithm = GNUTLS_PK_DSA;
284           break;
285         default:
286           _gnutls_debug_log("Cannot determine PKCS #11 key algorithm\n");
287           ret = GNUTLS_E_UNKNOWN_ALGORITHM;
288           goto cleanup;
289         }
290     }
291
292   ret = 0;
293
294 cleanup:
295   pkcs11_close_session (module, pks);
296
297   return ret;
298 }
299
300 /*-
301  * _gnutls_pkcs11_privkey_decrypt_data:
302  * @key: Holds the key
303  * @flags: should be 0 for now
304  * @ciphertext: holds the data to be signed
305  * @plaintext: will contain the plaintext, allocated with gnutls_malloc()
306  *
307  * This function will decrypt the given data using the public key algorithm
308  * supported by the private key. 
309  *
310  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
311  *   negative error value.
312  -*/
313 int
314 _gnutls_pkcs11_privkey_decrypt_data (gnutls_pkcs11_privkey_t key,
315                                     unsigned int flags,
316                                     const gnutls_datum_t * ciphertext,
317                                     gnutls_datum_t * plaintext)
318 {
319   ck_rv_t rv;
320   int ret;
321   struct ck_mechanism mech;
322   unsigned long siglen;
323   struct ck_function_list *module;
324   ck_session_handle_t pks;
325   ck_object_handle_t obj;
326
327   FIND_OBJECT (module, pks, obj, key);
328
329   mech.mechanism =
330     key->pk_algorithm == GNUTLS_PK_DSA ? CKM_DSA : CKM_RSA_PKCS;
331   mech.parameter = NULL;
332   mech.parameter_len = 0;
333
334   /* Initialize signing operation; using the private key discovered
335    * earlier. */
336   rv = pkcs11_decrypt_init (module, pks, &mech, obj);
337   if (rv != CKR_OK)
338     {
339       gnutls_assert ();
340       ret = pkcs11_rv_to_err (rv);
341       goto cleanup;
342     }
343
344   /* Work out how long the plaintext must be: */
345   rv = pkcs11_decrypt (module, pks, ciphertext->data, ciphertext->size,
346                          NULL, &siglen);
347   if (rv != CKR_OK)
348     {
349       gnutls_assert ();
350       ret = pkcs11_rv_to_err (rv);
351       goto cleanup;
352     }
353
354   plaintext->data = gnutls_malloc (siglen);
355   plaintext->size = siglen;
356
357   rv = pkcs11_decrypt (module, pks, ciphertext->data, ciphertext->size,
358                          plaintext->data, &siglen);
359   if (rv != CKR_OK)
360     {
361       gnutls_free (plaintext->data);
362       gnutls_assert ();
363       ret = pkcs11_rv_to_err (rv);
364       goto cleanup;
365     }
366
367   plaintext->size = siglen;
368
369   ret = 0;
370
371 cleanup:
372   pkcs11_close_session (module, pks);
373
374   return ret;
375 }
376
377 /**
378  * gnutls_pkcs11_privkey_export_url:
379  * @key: Holds the PKCS 11 key
380  * @detailed: non zero if a detailed URL is required
381  * @url: will contain an allocated url
382  *
383  * This function will export a URL identifying the given key.
384  *
385  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
386  *   negative error value.
387  **/
388 int
389 gnutls_pkcs11_privkey_export_url (gnutls_pkcs11_privkey_t key,
390                                   gnutls_pkcs11_url_type_t detailed,
391                                   char **url)
392 {
393   int ret;
394
395   ret = pkcs11_info_to_url (key->info, detailed, url);
396   if (ret < 0)
397     {
398       gnutls_assert ();
399       return ret;
400     }
401
402   return 0;
403 }