Tizen 2.0 Release
[external/libgnutls26.git] / lib / pkcs11_write.c
1 /*
2  * GnuTLS PKCS#11 support
3  * Copyright (C) 2010 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
31 /**
32  * gnutls_pkcs11_copy_x509_crt:
33  * @token_url: A PKCS #11 URL specifying a token
34  * @crt: A certificate
35  * @label: A name to be used for the stored data
36  * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_*
37  *
38  * This function will copy a certificate into a PKCS #11 token specified by
39  * a URL. The certificate can be marked as trusted or not.
40  *
41  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
42  *   negative error value.
43  **/
44 int
45 gnutls_pkcs11_copy_x509_crt (const char *token_url,
46                              gnutls_x509_crt_t crt, const char *label,
47                              unsigned int flags)
48 {
49   int ret;
50   struct ck_function_list *module;
51   ck_session_handle_t pks;
52   struct p11_kit_uri *info = NULL;
53   ck_rv_t rv;
54   size_t der_size, id_size;
55   opaque *der = NULL;
56   opaque id[20];
57   struct ck_attribute a[16];
58   ck_object_class_t class = CKO_CERTIFICATE;
59   ck_certificate_type_t type = CKC_X_509;
60   ck_object_handle_t obj;
61   ck_bool_t tval = 1;
62   ck_bool_t fval = 0;
63   int a_val;
64   gnutls_datum_t subject = { NULL, 0 };
65
66   ret = pkcs11_url_to_info (token_url, &info);
67   if (ret < 0)
68     {
69       gnutls_assert ();
70       return ret;
71     }
72
73   ret =
74     pkcs11_open_session (&module, &pks, info,
75                          SESSION_WRITE | pkcs11_obj_flags_to_int (flags));
76   p11_kit_uri_free (info);
77
78   if (ret < 0)
79     {
80       gnutls_assert ();
81       return ret;
82     }
83
84   ret = gnutls_x509_crt_export (crt, GNUTLS_X509_FMT_DER, NULL, &der_size);
85   if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
86     {
87       gnutls_assert ();
88       goto cleanup;
89     }
90
91   der = gnutls_malloc (der_size);
92   if (der == NULL)
93     {
94       gnutls_assert ();
95       ret = GNUTLS_E_MEMORY_ERROR;
96       goto cleanup;
97     }
98
99   ret = gnutls_x509_crt_export (crt, GNUTLS_X509_FMT_DER, der, &der_size);
100   if (ret < 0)
101     {
102       gnutls_assert ();
103       goto cleanup;
104     }
105
106   id_size = sizeof (id);
107   ret = gnutls_x509_crt_get_key_id (crt, 0, id, &id_size);
108   if (ret < 0)
109     {
110       gnutls_assert ();
111       goto cleanup;
112     }
113   
114   ret = gnutls_x509_crt_get_raw_dn (crt, &subject);
115   if (ret < 0)
116     {
117       gnutls_assert ();
118       goto cleanup;
119     }
120
121   /* FIXME: copy key usage flags */
122
123   a[0].type = CKA_CLASS;
124   a[0].value = &class;
125   a[0].value_len = sizeof (class);
126   a[1].type = CKA_ID;
127   a[1].value = id;
128   a[1].value_len = id_size;
129   a[2].type = CKA_VALUE;
130   a[2].value = der;
131   a[2].value_len = der_size;
132   a[3].type = CKA_TOKEN;
133   a[3].value = &tval;
134   a[3].value_len = sizeof (tval);
135   a[4].type = CKA_CERTIFICATE_TYPE;
136   a[4].value = &type;
137   a[4].value_len = sizeof (type);
138
139   a_val = 5;
140
141   a[a_val].type = CKA_SUBJECT;
142   a[a_val].value = subject.data;
143   a[a_val].value_len = subject.size;
144   a_val++;
145
146
147   if (label)
148     {
149       a[a_val].type = CKA_LABEL;
150       a[a_val].value = (void *) label;
151       a[a_val].value_len = strlen (label);
152       a_val++;
153     }
154
155   if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED)
156     {
157       a[a_val].type = CKA_TRUSTED;
158       a[a_val].value = &tval;
159       a[a_val].value_len = sizeof (tval);
160       a_val++;
161
162       a[a_val].type = CKA_PRIVATE;
163       a[a_val].value = &fval;
164       a[a_val].value_len = sizeof(fval);
165       a_val++;
166     }
167
168   rv = pkcs11_create_object (module, pks, a, a_val, &obj);
169   if (rv != CKR_OK)
170     {
171       gnutls_assert ();
172       _gnutls_debug_log ("pkcs11: %s\n", pkcs11_strerror (rv));
173       ret = pkcs11_rv_to_err (rv);
174       goto cleanup;
175     }
176
177   /* generated! 
178    */
179
180   ret = 0;
181
182 cleanup:
183   gnutls_free (der);
184   _gnutls_free_datum(&subject);
185   pkcs11_close_session (module, pks);
186
187   return ret;
188
189 }
190
191 /**
192  * gnutls_pkcs11_copy_x509_privkey:
193  * @token_url: A PKCS #11 URL specifying a token
194  * @key: A private key
195  * @label: A name to be used for the stored data
196  * @key_usage: One of GNUTLS_KEY_*
197  * @flags: One of GNUTLS_PKCS11_OBJ_* flags
198  *
199  * This function will copy a private key into a PKCS #11 token specified by
200  * a URL. It is highly recommended flags to contain %GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE
201  * unless there is a strong reason not to.
202  *
203  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
204  *   negative error value.
205  **/
206 int
207 gnutls_pkcs11_copy_x509_privkey (const char *token_url,
208                                  gnutls_x509_privkey_t key,
209                                  const char *label,
210                                  unsigned int key_usage, unsigned int flags)
211 {
212   int ret;
213   struct ck_function_list *module;
214   ck_session_handle_t pks = 0;
215   struct p11_kit_uri *info = NULL;
216   ck_rv_t rv;
217   size_t id_size;
218   opaque id[20];
219   struct ck_attribute a[16];
220   ck_object_class_t class = CKO_PRIVATE_KEY;
221   ck_object_handle_t obj;
222   ck_key_type_t type;
223   ck_bool_t tval = 1;
224   int a_val;
225   gnutls_pk_algorithm_t pk;
226   gnutls_datum_t p, q, g, y, x;
227   gnutls_datum_t m, e, d, u, exp1, exp2;
228
229
230   ret = pkcs11_url_to_info (token_url, &info);
231   if (ret < 0)
232     {
233       gnutls_assert ();
234       return ret;
235     }
236
237   id_size = sizeof (id);
238   ret = gnutls_x509_privkey_get_key_id (key, 0, id, &id_size);
239   if (ret < 0)
240     {
241       p11_kit_uri_free (info);
242       gnutls_assert ();
243       goto cleanup;
244     }
245
246   ret =
247     pkcs11_open_session (&module, &pks, info,
248                          SESSION_WRITE | pkcs11_obj_flags_to_int (flags));
249   p11_kit_uri_free (info);
250
251   if (ret < 0)
252     {
253       gnutls_assert ();
254       return ret;
255     }
256
257   /* FIXME: copy key usage flags */
258   a_val = 0;
259   a[a_val].type = CKA_CLASS;
260   a[a_val].value = &class;
261   a[a_val].value_len = sizeof (class);
262   a_val++;
263
264   a[a_val].type = CKA_ID;
265   a[a_val].value = id;
266   a[a_val].value_len = id_size;
267   a_val++;
268
269   a[a_val].type = CKA_KEY_TYPE;
270   a[a_val].value = &type;
271   a[a_val].value_len = sizeof (type);
272   a_val++;
273
274   a[a_val].type = CKA_TOKEN;
275   a[a_val].value = &tval;
276   a[a_val].value_len = sizeof (tval);
277   a_val++;
278
279   a[a_val].type = CKA_PRIVATE;
280   a[a_val].value = &tval;
281   a[a_val].value_len = sizeof (tval);
282   a_val++;
283
284   if (label)
285     {
286       a[a_val].type = CKA_LABEL;
287       a[a_val].value = (void *) label;
288       a[a_val].value_len = strlen (label);
289       a_val++;
290     }
291
292   if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE)
293     tval = 1;
294   else
295     tval = 0;
296
297   a[a_val].type = CKA_SENSITIVE;
298   a[a_val].value = &tval;
299   a[a_val].value_len = sizeof (tval);
300   a_val++;
301
302   pk = gnutls_x509_privkey_get_pk_algorithm (key);
303   switch (pk)
304     {
305     case GNUTLS_PK_RSA:
306       {
307
308         ret =
309           gnutls_x509_privkey_export_rsa_raw2 (key, &m,
310                                                &e, &d, &p,
311                                                &q, &u, &exp1, &exp2);
312         if (ret < 0)
313           {
314             gnutls_assert ();
315             goto cleanup;
316           }
317
318         type = CKK_RSA;
319
320         a[a_val].type = CKA_MODULUS;
321         a[a_val].value = m.data;
322         a[a_val].value_len = m.size;
323         a_val++;
324
325         a[a_val].type = CKA_PUBLIC_EXPONENT;
326         a[a_val].value = e.data;
327         a[a_val].value_len = e.size;
328         a_val++;
329
330         a[a_val].type = CKA_PRIVATE_EXPONENT;
331         a[a_val].value = d.data;
332         a[a_val].value_len = d.size;
333         a_val++;
334
335         a[a_val].type = CKA_PRIME_1;
336         a[a_val].value = p.data;
337         a[a_val].value_len = p.size;
338         a_val++;
339
340         a[a_val].type = CKA_PRIME_2;
341         a[a_val].value = q.data;
342         a[a_val].value_len = q.size;
343         a_val++;
344
345         a[a_val].type = CKA_COEFFICIENT;
346         a[a_val].value = u.data;
347         a[a_val].value_len = u.size;
348         a_val++;
349
350         a[a_val].type = CKA_EXPONENT_1;
351         a[a_val].value = exp1.data;
352         a[a_val].value_len = exp1.size;
353         a_val++;
354
355         a[a_val].type = CKA_EXPONENT_2;
356         a[a_val].value = exp2.data;
357         a[a_val].value_len = exp2.size;
358         a_val++;
359
360         break;
361       }
362     case GNUTLS_PK_DSA:
363       {
364         ret = gnutls_x509_privkey_export_dsa_raw (key, &p, &q, &g, &y, &x);
365         if (ret < 0)
366           {
367             gnutls_assert ();
368             goto cleanup;
369           }
370
371         type = CKK_DSA;
372
373         a[a_val].type = CKA_PRIME;
374         a[a_val].value = p.data;
375         a[a_val].value_len = p.size;
376         a_val++;
377
378         a[a_val].type = CKA_SUBPRIME;
379         a[a_val].value = q.data;
380         a[a_val].value_len = q.size;
381         a_val++;
382
383         a[a_val].type = CKA_BASE;
384         a[a_val].value = g.data;
385         a[a_val].value_len = g.size;
386         a_val++;
387
388         a[a_val].type = CKA_VALUE;
389         a[a_val].value = x.data;
390         a[a_val].value_len = x.size;
391         a_val++;
392
393         break;
394       }
395     default:
396       gnutls_assert ();
397       ret = GNUTLS_E_INVALID_REQUEST;
398       goto cleanup;
399     }
400
401   rv = pkcs11_create_object (module, pks, a, a_val, &obj);
402   if (rv != CKR_OK)
403     {
404       gnutls_assert ();
405       _gnutls_debug_log ("pkcs11: %s\n", pkcs11_strerror (rv));
406       ret = pkcs11_rv_to_err (rv);
407       goto cleanup;
408     }
409
410   /* generated! 
411    */
412
413   switch (pk)
414     {
415     case GNUTLS_PK_RSA:
416       {
417         gnutls_free (m.data);
418         gnutls_free (e.data);
419         gnutls_free (d.data);
420         gnutls_free (p.data);
421         gnutls_free (q.data);
422         gnutls_free (u.data);
423         gnutls_free (exp1.data);
424         gnutls_free (exp2.data);
425         break;
426       }
427     case GNUTLS_PK_DSA:
428       {
429         gnutls_free (p.data);
430         gnutls_free (q.data);
431         gnutls_free (g.data);
432         gnutls_free (y.data);
433         gnutls_free (x.data);
434         break;
435       }
436     default:
437       gnutls_assert ();
438       ret = GNUTLS_E_INVALID_REQUEST;
439       goto cleanup;
440     }
441
442   ret = 0;
443
444 cleanup:
445   if (pks != 0)
446     pkcs11_close_session (module, pks);
447
448   return ret;
449
450 }
451
452 struct delete_data_st
453 {
454   struct p11_kit_uri *info;
455   unsigned int deleted;         /* how many */
456 };
457
458 static int
459 delete_obj_url (struct ck_function_list *module,
460                 ck_session_handle_t pks,
461                 struct token_info *info,
462                 struct ck_info *lib_info, void *input)
463 {
464   struct delete_data_st *find_data = input;
465   struct ck_attribute a[4];
466   struct ck_attribute *attr;
467   ck_object_class_t class;
468   ck_certificate_type_t type = -1;
469   ck_rv_t rv;
470   ck_object_handle_t obj;
471   unsigned long count, a_vals;
472   int found = 0, ret;
473
474
475   if (info == NULL)
476     {                           /* we don't support multiple calls */
477       gnutls_assert ();
478       return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
479     }
480
481   /* do not bother reading the token if basic fields do not match
482    */
483   if (!p11_kit_uri_match_module_info (find_data->info, lib_info) ||
484       !p11_kit_uri_match_token_info (find_data->info, &info->tinfo))
485     {
486       gnutls_assert ();
487       return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
488     }
489
490   /* Find objects with given class and type */
491   class = CKO_CERTIFICATE;      /* default  */
492   a_vals = 0;
493
494   attr = p11_kit_uri_get_attribute (find_data->info, CKA_CLASS);
495   if (attr != NULL)
496     {
497       if(attr->value && attr->value_len == sizeof (ck_object_class_t))
498         class = *((ck_object_class_t*)attr->value);
499       if (class == CKO_CERTIFICATE)
500         type = CKC_X_509;
501     }
502
503   a[a_vals].type = CKA_CLASS;
504   a[a_vals].value = &class;
505   a[a_vals].value_len = sizeof (class);
506   a_vals++;
507
508   attr = p11_kit_uri_get_attribute (find_data->info, CKA_ID);
509   if (attr != NULL)
510     {
511       memcpy (a + a_vals, attr, sizeof (struct ck_attribute));
512       a_vals++;
513     }
514
515   if (type != -1)
516     {
517       a[a_vals].type = CKA_CERTIFICATE_TYPE;
518       a[a_vals].value = &type;
519       a[a_vals].value_len = sizeof type;
520       a_vals++;
521     }
522
523   attr = p11_kit_uri_get_attribute (find_data->info, CKA_LABEL);
524   if (attr != NULL)
525     {
526       memcpy (a + a_vals, attr, sizeof (struct ck_attribute));
527       a_vals++;
528     }
529
530   rv = pkcs11_find_objects_init (module, pks, a, a_vals);
531   if (rv != CKR_OK)
532     {
533       gnutls_assert ();
534       _gnutls_debug_log ("pk11: FindObjectsInit failed.\n");
535       ret = pkcs11_rv_to_err (rv);
536       goto cleanup;
537     }
538
539   while (pkcs11_find_objects (module, pks, &obj, 1, &count) == CKR_OK && count == 1)
540     {
541       rv = pkcs11_destroy_object (module, pks, obj);
542       if (rv != CKR_OK)
543         {
544           _gnutls_debug_log
545             ("pkcs11: Cannot destroy object: %s\n", pkcs11_strerror (rv));
546         }
547       else
548         {
549           find_data->deleted++;
550         }
551
552       found = 1;
553     }
554
555   if (found == 0)
556     {
557       gnutls_assert ();
558       ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
559     }
560   else
561     {
562       ret = 0;
563     }
564
565 cleanup:
566   pkcs11_find_objects_final (module, pks);
567
568   return ret;
569 }
570
571
572 /**
573  * gnutls_pkcs11_delete_url:
574  * @object_url: The URL of the object to delete.
575  * @flags: One of GNUTLS_PKCS11_OBJ_* flags
576  * 
577  * This function will delete objects matching the given URL.
578  *
579  * Returns: On success, the number of objects deleted is returned, otherwise a
580  *   negative error value.
581  **/
582 int
583 gnutls_pkcs11_delete_url (const char *object_url, unsigned int flags)
584 {
585   int ret;
586   struct delete_data_st find_data;
587
588   memset (&find_data, 0, sizeof (find_data));
589
590   ret = pkcs11_url_to_info (object_url, &find_data.info);
591   if (ret < 0)
592     {
593       gnutls_assert ();
594       return ret;
595     }
596
597   ret =
598     _pkcs11_traverse_tokens (delete_obj_url, &find_data, find_data.info,
599                              SESSION_WRITE | pkcs11_obj_flags_to_int (flags));
600   p11_kit_uri_free (find_data.info);
601
602   if (ret < 0)
603     {
604       gnutls_assert ();
605       return ret;
606     }
607
608   return find_data.deleted;
609
610 }
611
612 /**
613  * gnutls_pkcs11_token_init:
614  * @token_url: A PKCS #11 URL specifying a token
615  * @so_pin: Security Officer's PIN
616  * @label: A name to be used for the token
617  *
618  * This function will initialize (format) a token. If the token is
619  * at a factory defaults state the security officer's PIN given will be
620  * set to be the default. Otherwise it should match the officer's PIN.
621  *
622  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
623  *   negative error value.
624  **/
625 int
626 gnutls_pkcs11_token_init (const char *token_url,
627                           const char *so_pin, const char *label)
628 {
629   int ret;
630   struct p11_kit_uri *info = NULL;
631   ck_rv_t rv;
632   struct ck_function_list *module;
633   ck_slot_id_t slot;
634   char flabel[32];
635
636   ret = pkcs11_url_to_info (token_url, &info);
637   if (ret < 0)
638     {
639       gnutls_assert ();
640       return ret;
641     }
642
643   ret = pkcs11_find_slot (&module, &slot, info, NULL);
644   p11_kit_uri_free (info);
645
646   if (ret < 0)
647     {
648       gnutls_assert ();
649       return ret;
650     }
651
652   /* so it seems memset has other uses than zeroing! */
653   memset (flabel, ' ', sizeof (flabel));
654   if (label != NULL)
655     memcpy (flabel, label, strlen (label));
656
657   rv =
658     pkcs11_init_token (module, slot, (char *) so_pin, strlen (so_pin),
659                        flabel);
660   if (rv != CKR_OK)
661     {
662       gnutls_assert ();
663       _gnutls_debug_log ("pkcs11: %s\n", pkcs11_strerror (rv));
664       return pkcs11_rv_to_err (rv);
665     }
666
667   return 0;
668
669 }
670
671 /**
672  * gnutls_pkcs11_token_set_pin:
673  * @token_url: A PKCS #11 URL specifying a token
674  * @oldpin: old user's PIN
675  * @newpin: new user's PIN
676  * @flags: one of gnutls_pkcs11_pin_flag_t
677  *
678  * This function will modify or set a user's PIN for the given token. 
679  * If it is called to set a user pin for first time the oldpin must
680  * be NULL.
681  *
682  * Returns: On success, %GNUTLS_E_SUCCESS is returned, otherwise a
683  *   negative error value.
684  **/
685 int
686 gnutls_pkcs11_token_set_pin (const char *token_url,
687                              const char *oldpin,
688                              const char *newpin, unsigned int flags)
689 {
690   int ret;
691   struct ck_function_list *module;
692   ck_session_handle_t pks;
693   struct p11_kit_uri *info = NULL;
694   ck_rv_t rv;
695   unsigned int ses_flags;
696
697   ret = pkcs11_url_to_info (token_url, &info);
698   if (ret < 0)
699     {
700       gnutls_assert ();
701       return ret;
702     }
703
704   if (((flags & GNUTLS_PKCS11_PIN_USER) && oldpin == NULL) ||
705       (flags & GNUTLS_PKCS11_PIN_SO))
706     ses_flags = SESSION_WRITE | SESSION_LOGIN | SESSION_SO;
707   else
708     ses_flags = SESSION_WRITE | SESSION_LOGIN;
709
710   ret = pkcs11_open_session (&module, &pks, info, ses_flags);
711   p11_kit_uri_free (info);
712
713   if (ret < 0)
714     {
715       gnutls_assert ();
716       return ret;
717     }
718
719   if (oldpin == NULL)
720     {
721       rv = pkcs11_init_pin (module, pks, (char *) newpin, strlen (newpin));
722       if (rv != CKR_OK)
723         {
724           gnutls_assert ();
725           _gnutls_debug_log ("pkcs11: %s\n", pkcs11_strerror (rv));
726           ret = pkcs11_rv_to_err (rv);
727           goto finish;
728         }
729     }
730   else
731     {
732       rv = pkcs11_set_pin (module, pks,
733                            (char *) oldpin, strlen (oldpin),
734                            (char *) newpin, strlen (newpin));
735       if (rv != CKR_OK)
736         {
737           gnutls_assert ();
738           _gnutls_debug_log ("pkcs11: %s\n", pkcs11_strerror (rv));
739           ret = pkcs11_rv_to_err (rv);
740           goto finish;
741         }
742     }
743
744   ret = 0;
745
746 finish:
747   pkcs11_close_session (module, pks);
748   return ret;
749
750 }