bumped versions
[gnutls.git] / lib / pkcs11_write.c
blobb5bf72712b6fdea29e9673dbf3d84acce5dba179
1 /*
2 * GnuTLS PKCS#11 support
3 * Copyright (C) 2010-2012 Free Software Foundation, Inc.
4 *
5 * Authors: Nikos Mavrogiannopoulos, Stef Walter
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 3 of the License, or (at your option) any later version.
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.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>
21 #include <gnutls_int.h>
22 #include <gnutls/pkcs11.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <gnutls_errors.h>
26 #include <gnutls_datum.h>
27 #include <pkcs11_int.h>
29 static const ck_bool_t tval = 1;
30 static const ck_bool_t fval = 0;
32 /**
33 * gnutls_pkcs11_copy_x509_crt:
34 * @token_url: A PKCS #11 URL specifying a token
35 * @crt: A certificate
36 * @label: A name to be used for the stored data
37 * @flags: One of GNUTLS_PKCS11_OBJ_FLAG_*
39 * This function will copy a certificate into a PKCS #11 token specified by
40 * a URL. The certificate can be marked as trusted or not.
42 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
43 * negative error value.
45 * Since: 2.12.0
46 **/
47 int
48 gnutls_pkcs11_copy_x509_crt (const char *token_url,
49 gnutls_x509_crt_t crt, const char *label,
50 unsigned int flags)
52 int ret;
53 struct p11_kit_uri *info = NULL;
54 ck_rv_t rv;
55 size_t der_size, id_size;
56 uint8_t *der = NULL;
57 uint8_t id[20];
58 struct ck_attribute a[16];
59 ck_object_class_t class = CKO_CERTIFICATE;
60 ck_certificate_type_t type = CKC_X_509;
61 ck_object_handle_t obj;
62 int a_val;
63 gnutls_datum_t subject = { NULL, 0 };
64 struct pkcs11_session_info sinfo;
66 memset(&sinfo, 0, sizeof(sinfo));
68 ret = pkcs11_url_to_info (token_url, &info);
69 if (ret < 0)
71 gnutls_assert ();
72 return ret;
75 ret =
76 pkcs11_open_session (&sinfo, NULL, info,
77 SESSION_WRITE | pkcs11_obj_flags_to_int (flags));
78 p11_kit_uri_free (info);
80 if (ret < 0)
82 gnutls_assert ();
83 return ret;
86 ret = gnutls_x509_crt_export (crt, GNUTLS_X509_FMT_DER, NULL, &der_size);
87 if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
89 gnutls_assert ();
90 goto cleanup;
93 der = gnutls_malloc (der_size);
94 if (der == NULL)
96 gnutls_assert ();
97 ret = GNUTLS_E_MEMORY_ERROR;
98 goto cleanup;
101 ret = gnutls_x509_crt_export (crt, GNUTLS_X509_FMT_DER, der, &der_size);
102 if (ret < 0)
104 gnutls_assert ();
105 goto cleanup;
108 id_size = sizeof (id);
109 ret = gnutls_x509_crt_get_key_id (crt, 0, id, &id_size);
110 if (ret < 0)
112 gnutls_assert ();
113 goto cleanup;
116 ret = gnutls_x509_crt_get_raw_dn (crt, &subject);
117 if (ret < 0)
119 gnutls_assert ();
120 goto cleanup;
123 /* FIXME: copy key usage flags */
125 a[0].type = CKA_CLASS;
126 a[0].value = &class;
127 a[0].value_len = sizeof (class);
128 a[1].type = CKA_ID;
129 a[1].value = id;
130 a[1].value_len = id_size;
131 a[2].type = CKA_VALUE;
132 a[2].value = der;
133 a[2].value_len = der_size;
134 a[3].type = CKA_TOKEN;
135 a[3].value = (void*)&tval;
136 a[3].value_len = sizeof (tval);
137 a[4].type = CKA_CERTIFICATE_TYPE;
138 a[4].value = &type;
139 a[4].value_len = sizeof (type);
141 a_val = 5;
143 a[a_val].type = CKA_SUBJECT;
144 a[a_val].value = subject.data;
145 a[a_val].value_len = subject.size;
146 a_val++;
148 if (label)
150 a[a_val].type = CKA_LABEL;
151 a[a_val].value = (void *) label;
152 a[a_val].value_len = strlen (label);
153 a_val++;
156 if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED)
158 a[a_val].type = CKA_TRUSTED;
159 a[a_val].value = (void*)&tval;
160 a[a_val].value_len = sizeof (tval);
161 a_val++;
163 a[a_val].type = CKA_PRIVATE;
164 a[a_val].value = (void*)&fval;
165 a[a_val].value_len = sizeof(fval);
166 a_val++;
168 else
170 if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_PRIVATE)
172 a[a_val].type = CKA_PRIVATE;
173 a[a_val].value = (void*)&tval;
174 a[a_val].value_len = sizeof(tval);
175 a_val++;
177 else if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE)
179 a[a_val].type = CKA_PRIVATE;
180 a[a_val].value = (void*)&fval;
181 a[a_val].value_len = sizeof(fval);
182 a_val++;
186 rv = pkcs11_create_object (sinfo.module, sinfo.pks, a, a_val, &obj);
187 if (rv != CKR_OK)
189 gnutls_assert ();
190 _gnutls_debug_log ("pkcs11: %s\n", pkcs11_strerror (rv));
191 ret = pkcs11_rv_to_err (rv);
192 goto cleanup;
195 /* generated!
198 ret = 0;
200 cleanup:
201 gnutls_free (der);
202 pkcs11_close_session (&sinfo);
203 _gnutls_free_datum(&subject);
204 return ret;
209 * gnutls_pkcs11_copy_x509_privkey:
210 * @token_url: A PKCS #11 URL specifying a token
211 * @key: A private key
212 * @label: A name to be used for the stored data
213 * @key_usage: One of GNUTLS_KEY_*
214 * @flags: One of GNUTLS_PKCS11_OBJ_* flags
216 * This function will copy a private key into a PKCS #11 token specified by
217 * a URL. It is highly recommended flags to contain %GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE
218 * unless there is a strong reason not to.
220 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
221 * negative error value.
223 * Since: 2.12.0
226 gnutls_pkcs11_copy_x509_privkey (const char *token_url,
227 gnutls_x509_privkey_t key,
228 const char *label,
229 unsigned int key_usage, unsigned int flags)
231 int ret;
232 struct p11_kit_uri *info = NULL;
233 ck_rv_t rv;
234 size_t id_size;
235 uint8_t id[20];
236 struct ck_attribute a[16];
237 ck_object_class_t class = CKO_PRIVATE_KEY;
238 ck_object_handle_t obj;
239 ck_key_type_t type;
240 int a_val;
241 gnutls_pk_algorithm_t pk;
242 gnutls_datum_t p, q, g, y, x;
243 gnutls_datum_t m, e, d, u, exp1, exp2;
244 struct pkcs11_session_info sinfo;
246 memset(&sinfo, 0, sizeof(sinfo));
248 memset(&p, 0, sizeof(p));
249 memset(&q, 0, sizeof(q));
250 memset(&g, 0, sizeof(g));
251 memset(&y, 0, sizeof(y));
252 memset(&x, 0, sizeof(x));
253 memset(&m, 0, sizeof(m));
254 memset(&e, 0, sizeof(e));
255 memset(&d, 0, sizeof(d));
256 memset(&u, 0, sizeof(u));
257 memset(&exp1, 0, sizeof(exp1));
258 memset(&exp2, 0, sizeof(exp2));
260 ret = pkcs11_url_to_info (token_url, &info);
261 if (ret < 0)
263 gnutls_assert ();
264 return ret;
267 id_size = sizeof (id);
268 ret = gnutls_x509_privkey_get_key_id (key, 0, id, &id_size);
269 if (ret < 0)
271 p11_kit_uri_free (info);
272 gnutls_assert ();
273 return ret;
276 ret =
277 pkcs11_open_session (&sinfo, NULL, info,
278 SESSION_WRITE | pkcs11_obj_flags_to_int (flags));
279 p11_kit_uri_free (info);
281 if (ret < 0)
283 gnutls_assert ();
284 return ret;
287 /* FIXME: copy key usage flags */
288 a_val = 0;
289 a[a_val].type = CKA_CLASS;
290 a[a_val].value = &class;
291 a[a_val].value_len = sizeof (class);
292 a_val++;
294 a[a_val].type = CKA_ID;
295 a[a_val].value = id;
296 a[a_val].value_len = id_size;
297 a_val++;
299 a[a_val].type = CKA_KEY_TYPE;
300 a[a_val].value = &type;
301 a[a_val].value_len = sizeof (type);
302 a_val++;
304 a[a_val].type = CKA_TOKEN;
305 a[a_val].value = (void*)&tval;
306 a[a_val].value_len = sizeof (tval);
307 a_val++;
309 /* a private key is set always as private unless
310 * requested otherwise
312 if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE)
314 a[a_val].type = CKA_PRIVATE;
315 a[a_val].value = (void*)&fval;
316 a[a_val].value_len = sizeof(fval);
317 a_val++;
319 else
321 a[a_val].type = CKA_PRIVATE;
322 a[a_val].value = (void*)&tval;
323 a[a_val].value_len = sizeof (tval);
324 a_val++;
327 if (label)
329 a[a_val].type = CKA_LABEL;
330 a[a_val].value = (void *) label;
331 a[a_val].value_len = strlen (label);
332 a_val++;
335 if (flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_SENSITIVE)
337 a[a_val].type = CKA_SENSITIVE;
338 a[a_val].value = (void*)&tval;
339 a[a_val].value_len = sizeof (tval);
340 a_val++;
342 else
344 a[a_val].type = CKA_SENSITIVE;
345 a[a_val].value = (void*)&fval;
346 a[a_val].value_len = sizeof (fval);
347 a_val++;
350 pk = gnutls_x509_privkey_get_pk_algorithm (key);
351 switch (pk)
353 case GNUTLS_PK_RSA:
356 ret =
357 gnutls_x509_privkey_export_rsa_raw2 (key, &m,
358 &e, &d, &p,
359 &q, &u, &exp1, &exp2);
360 if (ret < 0)
362 gnutls_assert ();
363 goto cleanup;
366 type = CKK_RSA;
368 a[a_val].type = CKA_MODULUS;
369 a[a_val].value = m.data;
370 a[a_val].value_len = m.size;
371 a_val++;
373 a[a_val].type = CKA_PUBLIC_EXPONENT;
374 a[a_val].value = e.data;
375 a[a_val].value_len = e.size;
376 a_val++;
378 a[a_val].type = CKA_PRIVATE_EXPONENT;
379 a[a_val].value = d.data;
380 a[a_val].value_len = d.size;
381 a_val++;
383 a[a_val].type = CKA_PRIME_1;
384 a[a_val].value = p.data;
385 a[a_val].value_len = p.size;
386 a_val++;
388 a[a_val].type = CKA_PRIME_2;
389 a[a_val].value = q.data;
390 a[a_val].value_len = q.size;
391 a_val++;
393 a[a_val].type = CKA_COEFFICIENT;
394 a[a_val].value = u.data;
395 a[a_val].value_len = u.size;
396 a_val++;
398 a[a_val].type = CKA_EXPONENT_1;
399 a[a_val].value = exp1.data;
400 a[a_val].value_len = exp1.size;
401 a_val++;
403 a[a_val].type = CKA_EXPONENT_2;
404 a[a_val].value = exp2.data;
405 a[a_val].value_len = exp2.size;
406 a_val++;
408 break;
410 case GNUTLS_PK_DSA:
412 ret = gnutls_x509_privkey_export_dsa_raw (key, &p, &q, &g, &y, &x);
413 if (ret < 0)
415 gnutls_assert ();
416 goto cleanup;
419 type = CKK_DSA;
421 a[a_val].type = CKA_PRIME;
422 a[a_val].value = p.data;
423 a[a_val].value_len = p.size;
424 a_val++;
426 a[a_val].type = CKA_SUBPRIME;
427 a[a_val].value = q.data;
428 a[a_val].value_len = q.size;
429 a_val++;
431 a[a_val].type = CKA_BASE;
432 a[a_val].value = g.data;
433 a[a_val].value_len = g.size;
434 a_val++;
436 a[a_val].type = CKA_VALUE;
437 a[a_val].value = x.data;
438 a[a_val].value_len = x.size;
439 a_val++;
441 break;
443 case GNUTLS_PK_EC:
445 ret = _gnutls_x509_write_ecc_params(&key->params, &p);
446 if (ret < 0)
448 gnutls_assert ();
449 goto cleanup;
452 ret = _gnutls_mpi_dprint_lz(&key->params.params[ECC_K], &x);
453 if (ret < 0)
455 gnutls_assert ();
456 goto cleanup;
459 type = CKK_ECDSA;
461 a[a_val].type = CKA_EC_PARAMS;
462 a[a_val].value = p.data;
463 a[a_val].value_len = p.size;
464 a_val++;
466 a[a_val].type = CKA_VALUE;
467 a[a_val].value = x.data;
468 a[a_val].value_len = x.size;
469 a_val++;
471 break;
473 default:
474 gnutls_assert ();
475 ret = GNUTLS_E_INVALID_REQUEST;
476 goto cleanup;
479 rv = pkcs11_create_object (sinfo.module, sinfo.pks, a, a_val, &obj);
480 if (rv != CKR_OK)
482 gnutls_assert ();
483 _gnutls_debug_log ("pkcs11: %s\n", pkcs11_strerror (rv));
484 ret = pkcs11_rv_to_err (rv);
485 goto cleanup;
488 ret = 0;
490 cleanup:
491 switch (pk)
493 case GNUTLS_PK_RSA:
495 gnutls_free (m.data);
496 gnutls_free (e.data);
497 gnutls_free (d.data);
498 gnutls_free (p.data);
499 gnutls_free (q.data);
500 gnutls_free (u.data);
501 gnutls_free (exp1.data);
502 gnutls_free (exp2.data);
503 break;
505 case GNUTLS_PK_DSA:
507 gnutls_free (p.data);
508 gnutls_free (q.data);
509 gnutls_free (g.data);
510 gnutls_free (y.data);
511 gnutls_free (x.data);
512 break;
514 case GNUTLS_PK_EC:
516 gnutls_free (p.data);
517 gnutls_free (x.data);
518 break;
520 default:
521 gnutls_assert ();
522 ret = GNUTLS_E_INVALID_REQUEST;
523 break;
526 if (sinfo.pks != 0)
527 pkcs11_close_session (&sinfo);
529 return ret;
533 struct delete_data_st
535 struct p11_kit_uri *info;
536 unsigned int deleted; /* how many */
539 static int
540 delete_obj_url (struct pkcs11_session_info * sinfo,
541 struct token_info *info,
542 struct ck_info *lib_info, void *input)
544 struct delete_data_st *find_data = input;
545 struct ck_attribute a[4];
546 struct ck_attribute *attr;
547 ck_object_class_t class;
548 ck_certificate_type_t type = (ck_certificate_type_t)-1;
549 ck_rv_t rv;
550 ck_object_handle_t obj;
551 unsigned long count, a_vals;
552 int found = 0, ret;
554 if (info == NULL)
555 { /* we don't support multiple calls */
556 gnutls_assert ();
557 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
560 /* do not bother reading the token if basic fields do not match
562 if (!p11_kit_uri_match_module_info (find_data->info, lib_info) ||
563 !p11_kit_uri_match_token_info (find_data->info, &info->tinfo))
565 gnutls_assert ();
566 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
569 /* Find objects with given class and type */
570 class = CKO_CERTIFICATE; /* default */
571 a_vals = 0;
573 attr = p11_kit_uri_get_attribute (find_data->info, CKA_CLASS);
574 if (attr != NULL)
576 if(attr->value && attr->value_len == sizeof (ck_object_class_t))
577 class = *((ck_object_class_t*)attr->value);
578 if (class == CKO_CERTIFICATE)
579 type = CKC_X_509;
582 a[a_vals].type = CKA_CLASS;
583 a[a_vals].value = &class;
584 a[a_vals].value_len = sizeof (class);
585 a_vals++;
587 attr = p11_kit_uri_get_attribute (find_data->info, CKA_ID);
588 if (attr != NULL)
590 memcpy (a + a_vals, attr, sizeof (struct ck_attribute));
591 a_vals++;
594 if (type != (ck_certificate_type_t)-1)
596 a[a_vals].type = CKA_CERTIFICATE_TYPE;
597 a[a_vals].value = &type;
598 a[a_vals].value_len = sizeof type;
599 a_vals++;
602 attr = p11_kit_uri_get_attribute (find_data->info, CKA_LABEL);
603 if (attr != NULL)
605 memcpy (a + a_vals, attr, sizeof (struct ck_attribute));
606 a_vals++;
609 rv = pkcs11_find_objects_init (sinfo->module, sinfo->pks, a, a_vals);
610 if (rv != CKR_OK)
612 gnutls_assert ();
613 _gnutls_debug_log ("pk11: FindObjectsInit failed.\n");
614 ret = pkcs11_rv_to_err (rv);
615 goto cleanup;
618 while (pkcs11_find_objects (sinfo->module, sinfo->pks, &obj, 1, &count) == CKR_OK && count == 1)
620 rv = pkcs11_destroy_object (sinfo->module, sinfo->pks, obj);
621 if (rv != CKR_OK)
623 _gnutls_debug_log
624 ("pkcs11: Cannot destroy object: %s\n", pkcs11_strerror (rv));
626 else
628 find_data->deleted++;
631 found = 1;
634 if (found == 0)
636 gnutls_assert ();
637 ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
639 else
641 ret = 0;
644 cleanup:
645 pkcs11_find_objects_final (sinfo);
647 return ret;
652 * gnutls_pkcs11_delete_url:
653 * @object_url: The URL of the object to delete.
654 * @flags: One of GNUTLS_PKCS11_OBJ_* flags
656 * This function will delete objects matching the given URL.
657 * Note that not all tokens support the delete operation.
659 * Returns: On success, the number of objects deleted is returned, otherwise a
660 * negative error value.
662 * Since: 2.12.0
665 gnutls_pkcs11_delete_url (const char *object_url, unsigned int flags)
667 int ret;
668 struct delete_data_st find_data;
670 memset (&find_data, 0, sizeof (find_data));
672 ret = pkcs11_url_to_info (object_url, &find_data.info);
673 if (ret < 0)
675 gnutls_assert ();
676 return ret;
679 ret =
680 _pkcs11_traverse_tokens (delete_obj_url, &find_data, find_data.info,
681 NULL, SESSION_WRITE | pkcs11_obj_flags_to_int (flags));
682 p11_kit_uri_free (find_data.info);
684 if (ret < 0)
686 gnutls_assert ();
687 return ret;
690 return find_data.deleted;
695 * gnutls_pkcs11_token_init:
696 * @token_url: A PKCS #11 URL specifying a token
697 * @so_pin: Security Officer's PIN
698 * @label: A name to be used for the token
700 * This function will initialize (format) a token. If the token is
701 * at a factory defaults state the security officer's PIN given will be
702 * set to be the default. Otherwise it should match the officer's PIN.
704 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
705 * negative error value.
708 gnutls_pkcs11_token_init (const char *token_url,
709 const char *so_pin, const char *label)
711 int ret;
712 struct p11_kit_uri *info = NULL;
713 ck_rv_t rv;
714 struct ck_function_list *module;
715 ck_slot_id_t slot;
716 char flabel[32];
718 ret = pkcs11_url_to_info (token_url, &info);
719 if (ret < 0)
721 gnutls_assert ();
722 return ret;
725 ret = pkcs11_find_slot (&module, &slot, info, NULL);
726 p11_kit_uri_free (info);
728 if (ret < 0)
730 gnutls_assert ();
731 return ret;
734 /* so it seems memset has other uses than zeroing! */
735 memset (flabel, ' ', sizeof (flabel));
736 if (label != NULL)
737 memcpy (flabel, label, strlen (label));
739 rv =
740 pkcs11_init_token (module, slot, (uint8_t*)so_pin, strlen (so_pin),
741 (uint8_t*)flabel);
742 if (rv != CKR_OK)
744 gnutls_assert ();
745 _gnutls_debug_log ("pkcs11: %s\n", pkcs11_strerror (rv));
746 return pkcs11_rv_to_err (rv);
749 return 0;
754 * gnutls_pkcs11_token_set_pin:
755 * @token_url: A PKCS #11 URL specifying a token
756 * @oldpin: old user's PIN
757 * @newpin: new user's PIN
758 * @flags: one of #gnutls_pin_flag_t.
760 * This function will modify or set a user's PIN for the given token.
761 * If it is called to set a user pin for first time the oldpin must
762 * be NULL.
764 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
765 * negative error value.
768 gnutls_pkcs11_token_set_pin (const char *token_url,
769 const char *oldpin,
770 const char *newpin, unsigned int flags)
772 int ret;
773 struct p11_kit_uri *info = NULL;
774 ck_rv_t rv;
775 unsigned int ses_flags;
776 struct pkcs11_session_info sinfo;
778 memset(&sinfo, 0, sizeof(sinfo));
780 ret = pkcs11_url_to_info (token_url, &info);
781 if (ret < 0)
783 gnutls_assert ();
784 return ret;
787 if (((flags & GNUTLS_PIN_USER) && oldpin == NULL) ||
788 (flags & GNUTLS_PIN_SO))
789 ses_flags = SESSION_WRITE | SESSION_LOGIN | SESSION_SO;
790 else
791 ses_flags = SESSION_WRITE | SESSION_LOGIN;
793 ret = pkcs11_open_session (&sinfo, NULL, info, ses_flags);
794 p11_kit_uri_free (info);
796 if (ret < 0)
798 gnutls_assert ();
799 return ret;
802 if (oldpin == NULL)
804 rv = pkcs11_init_pin (sinfo.module, sinfo.pks, (uint8_t *) newpin, strlen (newpin));
805 if (rv != CKR_OK)
807 gnutls_assert ();
808 _gnutls_debug_log ("pkcs11: %s\n", pkcs11_strerror (rv));
809 ret = pkcs11_rv_to_err (rv);
810 goto finish;
813 else
815 rv = pkcs11_set_pin (sinfo.module, sinfo.pks,
816 oldpin, strlen (oldpin),
817 newpin, strlen (newpin));
818 if (rv != CKR_OK)
820 gnutls_assert ();
821 _gnutls_debug_log ("pkcs11: %s\n", pkcs11_strerror (rv));
822 ret = pkcs11_rv_to_err (rv);
823 goto finish;
827 ret = 0;
829 finish:
830 pkcs11_close_session (&sinfo);
831 return ret;