1/*
2 * OpenConnect (SSL + DTLS) VPN client
3 *
4 * Copyright © 2012 Free Software Foundation.
5 * Copyright © 2008-2012 Intel Corporation.
6 *
7 * Author: David Woodhouse <dwmw2@infradead.org>
8 * Author: Nikos Mavrogiannopoulos
9 *
10 * GnuTLS is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1 of
13 * the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>
22 *
23 */
24
25/*
26 * TPM code based on client-tpm.c from
27 * Carolin Latze <latze@angry-red-pla.net> and Tobias Soder
28 */
29
30#include <gnutls/gnutls.h>
31#include <gnutls/abstract.h>
32#include <gnutls/tpm.h>
33#include <gnutls_int.h>
34
35#ifdef HAVE_TROUSERS
36
37#include <gnutls_errors.h>
38#include <pkcs11_int.h>
39#include <x509/common.h>
40#include <x509_b64.h>
41#include <random.h>
42#include <pin.h>
43#include <c-ctype.h>
44
45#include <trousers/tss.h>
46#include <trousers/trousers.h>
47
48struct tpm_ctx_st
49{
50 TSS_HCONTEXT tpm_ctx;
51 TSS_HKEY tpm_key;
52 TSS_HPOLICY tpm_key_policy;
53 TSS_HKEY srk;
54 TSS_HPOLICY srk_policy;
55};
56
57struct tpm_key_list_st
58{
59 UINT32 size;
60 TSS_KM_KEYINFO2 * ki;
61 TSS_HCONTEXT tpm_ctx;
62};
63
64static void tpm_close_session(struct tpm_ctx_st *s);
65static int import_tpm_key (gnutls_privkey_t pkey,
66 const gnutls_datum_t * fdata,
67 gnutls_tpmkey_fmt_t format,
68 TSS_UUID *uuid,
69 TSS_FLAG storage_type,
70 const char *srk_password,
71 const char *key_password);
72static int encode_tpmkey_url(char** url, const TSS_UUID* uuid, TSS_FLAG storage);
73
74/* TPM URL format: (draft-mavrogiannopoulos-tpmuri-01)
75 *
76 * tpmkey:file=/path/to/file
77 * tpmkey:uuid=7f468c16-cb7f-11e1-824d-b3a4f4b20343;storage=user
78 * tpmkey:uuid=7f468c16-cb7f-11e1-824d-b3a4f4b20343;storage=system
79 *
80 */
81
82
83static int tss_err_pwd(TSS_RESULT err, int pwd_error)
84{
85 _gnutls_debug_log("TPM (%s) error: %s (%x)\n", Trspi_Error_Layer(err), Trspi_Error_String(err), (unsigned int)Trspi_Error_Code(err));
86
87 switch(ERROR_LAYER(err))
88 {
89 case TSS_LAYER_TPM:
90 switch(ERROR_CODE(err))
91 {
92 case TPM_E_AUTHFAIL:
93 return pwd_error;
94 case TPM_E_NOSRK:
95 return GNUTLS_E_TPM_UNINITIALIZED;
96 default:
97 return gnutls_assert_val(GNUTLS_E_TPM_ERROR);
98 }
99 case TSS_LAYER_TCS:
100 case TSS_LAYER_TSP:
101 switch(ERROR_CODE(err))
102 {
103 case TSS_E_COMM_FAILURE:
104 case TSS_E_NO_CONNECTION:
105 case TSS_E_CONNECTION_FAILED:
106 case TSS_E_CONNECTION_BROKEN:
107 return GNUTLS_E_TPM_SESSION_ERROR;
108 case TSS_E_PS_KEY_NOTFOUND:
109 return GNUTLS_E_TPM_KEY_NOT_FOUND;
110 default:
111 return gnutls_assert_val(GNUTLS_E_TPM_ERROR);
112 }
113 default:
114 return gnutls_assert_val(GNUTLS_E_TPM_ERROR);
115 }
116}
117
118#define tss_err(x) tss_err_pwd(x, GNUTLS_E_TPM_SRK_PASSWORD_ERROR)
119#define tss_err_key(x) tss_err_pwd(x, GNUTLS_E_TPM_KEY_PASSWORD_ERROR)
120
121static void
122tpm_deinit_fn (gnutls_privkey_t key, void *_s)
123{
124 struct tpm_ctx_st *s = _s;
125
126 Tspi_Context_CloseObject (s->tpm_ctx, s->tpm_key_policy);
127 Tspi_Context_CloseObject (s->tpm_ctx, s->tpm_key);
128
129 tpm_close_session(s);
130 gnutls_free (s);
131}
132
133static int
134tpm_sign_fn (gnutls_privkey_t key, void *_s,
135 const gnutls_datum_t * data, gnutls_datum_t * sig)
136{
137 struct tpm_ctx_st *s = _s;
138 TSS_HHASH hash;
139 int err;
140
141 _gnutls_debug_log ("TPM sign function called for %u bytes.\n",
142 data->size);
143
144 err =
145 Tspi_Context_CreateObject (s->tpm_ctx,
146 TSS_OBJECT_TYPE_HASH, TSS_HASH_OTHER,
147 &hash);
148 if (err)
149 {
150 gnutls_assert ();
151 _gnutls_debug_log ("Failed to create TPM hash object: %s\n",
152 Trspi_Error_String (err));
153 return GNUTLS_E_PK_SIGN_FAILED;
154 }
155 err = Tspi_Hash_SetHashValue (hash, data->size, data->data);
156 if (err)
157 {
158 gnutls_assert ();
159 _gnutls_debug_log ("Failed to set value in TPM hash object: %s\n",
160 Trspi_Error_String (err));
161 Tspi_Context_CloseObject (s->tpm_ctx, hash);
162 return GNUTLS_E_PK_SIGN_FAILED;
163 }
164 err = Tspi_Hash_Sign (hash, s->tpm_key, &sig->size, &sig->data);
165 Tspi_Context_CloseObject (s->tpm_ctx, hash);
166 if (err)
167 {
168 if (s->tpm_key_policy || err != TPM_E_AUTHFAIL)
169 _gnutls_debug_log ("TPM hash signature failed: %s\n",
170 Trspi_Error_String (err));
171 if (err == TPM_E_AUTHFAIL)
172 return GNUTLS_E_TPM_KEY_PASSWORD_ERROR;
173 else
174 return GNUTLS_E_PK_SIGN_FAILED;
175 }
176 return 0;
177}
178
179static const unsigned char nullpass[20];
180static const gnutls_datum_t nulldata = {(void*)nullpass, 20};
181const TSS_UUID srk_uuid = TSS_UUID_SRK;
182
183static int tpm_pin(struct pin_info_st* pin_info, const TSS_UUID* uuid, TSS_FLAG storage,
184 char* pin, unsigned int pin_size, unsigned int attempts)
185{
186unsigned int flags = 0;
187const char* label;
188char* url = NULL;
189int ret;
190
191 if (attempts > 0)
192 flags |= GNUTLS_PIN_WRONG;
193
194 if (uuid)
195 {
196 if (memcmp(uuid, &srk_uuid, sizeof(TSS_UUID)) == 0)
197 {
198 label = "SRK";
199
200 ret = encode_tpmkey_url(&url, uuid, storage);
201 if (ret < 0)
202 return gnutls_assert_val(ret);
203 }
204 else
205 {
206 label = "TPM";
207
208 ret = encode_tpmkey_url(&url, uuid, storage);
209 if (ret < 0)
210 return gnutls_assert_val(ret);
211 }
212 }
213 else
214 label = "unknown";
215
216 if (pin_info && pin_info->cb)
217 ret = pin_info->cb(pin_info->data, attempts, url, label, flags, pin, pin_size);
218 else if (_gnutls_pin_func)
219 ret = _gnutls_pin_func(_gnutls_pin_data, attempts, url, label, flags, pin, pin_size);
220 else
221 ret = gnutls_assert_val(GNUTLS_E_TPM_KEY_PASSWORD_ERROR); /* doesn't really matter */
222
223 if (ret < 0)
224 {
225 gnutls_assert();
226 goto cleanup;
227 }
228
229 ret = 0;
230cleanup:
231 gnutls_free(url);
232 return ret;
233}
234
235
236static TSS_RESULT myTspi_Policy_SetSecret(TSS_HPOLICY hPolicy,
237 UINT32 ulSecretLength, BYTE* rgbSecret)
238{
239 if (rgbSecret == NULL)
240 {
241 /* Well known NULL key */
242 return Tspi_Policy_SetSecret (hPolicy,
243 TSS_SECRET_MODE_SHA1,
244 sizeof (nullpass), (BYTE *) nullpass);
245 }
246 else /* key is given */
247 {
248 return Tspi_Policy_SetSecret (hPolicy, TSS_SECRET_MODE_PLAIN,
249 ulSecretLength, rgbSecret);
250 }
251}
252
253#define SAFE_LEN(x) (x==NULL?0:strlen(x))
254
255static int tpm_open_session(struct tpm_ctx_st *s, const char* srk_password)
256{
257int err, ret;
258
259 err = Tspi_Context_Create (&s->tpm_ctx);
260 if (err)
261 {
262 gnutls_assert ();
263 return tss_err(err);
264 }
265
266 err = Tspi_Context_Connect (s->tpm_ctx, NULL);
267 if (err)
268 {
269 gnutls_assert ();
270 ret = tss_err(err);
271 goto out_tspi_ctx;
272 }
273
274 err =
275 Tspi_Context_LoadKeyByUUID (s->tpm_ctx, TSS_PS_TYPE_SYSTEM,
276 srk_uuid, &s->srk);
277 if (err)
278 {
279 gnutls_assert ();
280 ret = tss_err(err);
281 goto out_tspi_ctx;
282 }
283
284 err = Tspi_GetPolicyObject (s->srk, TSS_POLICY_USAGE, &s->srk_policy);
285 if (err)
286 {
287 gnutls_assert ();
288 ret = tss_err(err);
289 goto out_srk;
290 }
291
292 err = myTspi_Policy_SetSecret (s->srk_policy,
293 SAFE_LEN (srk_password), (BYTE *) srk_password);
294 if (err)
295 {
296 gnutls_assert ();
297 ret = tss_err(err);
298 goto out_srkpol;
299 }
300
301 return 0;
302
303out_srkpol:
304 Tspi_Context_CloseObject (s->tpm_ctx, s->srk_policy);
305 s->srk_policy = 0;
306out_srk:
307 Tspi_Context_CloseObject (s->tpm_ctx, s->srk);
308 s->srk = 0;
309out_tspi_ctx:
310 Tspi_Context_Close (s->tpm_ctx);
311 s->tpm_ctx = 0;
312 return ret;
313
314}
315
316static void tpm_close_session(struct tpm_ctx_st *s)
317{
318 Tspi_Context_CloseObject (s->tpm_ctx, s->srk_policy);
319 s->srk_policy = 0;
320 Tspi_Context_CloseObject (s->tpm_ctx, s->srk);
321 s->srk = 0;
322 Tspi_Context_Close (s->tpm_ctx);
323 s->tpm_ctx = 0;
324}
325
326static int
327import_tpm_key_cb (gnutls_privkey_t pkey, const gnutls_datum_t * fdata,
328 gnutls_tpmkey_fmt_t format, TSS_UUID *uuid,
329 TSS_FLAG storage, const char *srk_password,
330 const char *key_password)
331{
332unsigned int attempts = 0;
333char pin1[GNUTLS_PKCS11_MAX_PIN_LEN];
334char pin2[GNUTLS_PKCS11_MAX_PIN_LEN];
335int ret, ret2;
336
337 do
338 {
339 ret = import_tpm_key(pkey, fdata, format, uuid, storage, srk_password, key_password);
340
341 if (attempts > 3)
342 break;
343
344 if (ret == GNUTLS_E_TPM_SRK_PASSWORD_ERROR)
345 {
346 ret2 = tpm_pin(&pkey->pin, &srk_uuid, storage, pin1, sizeof(pin1), attempts++);
347 if (ret2 < 0)
348 {
349 gnutls_assert();
350 return GNUTLS_E_TPM_SRK_PASSWORD_ERROR;
351 }
352 srk_password = pin1;
353 }
354
355 if (ret == GNUTLS_E_TPM_KEY_PASSWORD_ERROR)
356 {
357 ret2 = tpm_pin(&pkey->pin, uuid, storage, pin2, sizeof(pin2), attempts++);
358 if (ret2 < 0)
359 {
360 gnutls_assert();
361 return GNUTLS_E_TPM_KEY_PASSWORD_ERROR;
362 }
363 key_password = pin2;
364 }
365 }
366 while(ret == GNUTLS_E_TPM_KEY_PASSWORD_ERROR || ret == GNUTLS_E_TPM_SRK_PASSWORD_ERROR);
367
368 if (ret < 0)
369 gnutls_assert();
370 return ret;
371}
372
373static int load_key(TSS_HCONTEXT tpm_ctx, TSS_HKEY srk,
374 const gnutls_datum_t * fdata, gnutls_tpmkey_fmt_t format,
375 TSS_HKEY* tpm_key)
376{
377int ret, err;
378gnutls_datum_t asn1 = { NULL, 0 };
379
380 if (format == GNUTLS_TPMKEY_FMT_CTK_PEM)
381 {
382 gnutls_datum_t td;
383
384 ret = gnutls_pem_base64_decode_alloc ("TSS KEY BLOB", fdata, &asn1);
385 if (ret)
386 {
387 gnutls_assert ();
388 _gnutls_debug_log ("Error decoding TSS key blob: %s\n",
389 gnutls_strerror (ret));
390 return ret;
391 }
392
393 ret = _gnutls_x509_decode_string(ASN1_ETYPE_OCTET_STRING, asn1.data, asn1.size, &td);
394 if (ret < 0)
395 {
396 gnutls_assert();
397 goto cleanup;
398 }
399 gnutls_free(asn1.data);
400 asn1.data = td.data;
401 asn1.size = td.size;
402 }
403 else /* DER */
404 {
405 UINT32 tint2;
406 UINT32 type;
407
408 asn1.size = fdata->size;
409 asn1.data = gnutls_malloc(asn1.size);
410 if (asn1.data == NULL)
411 {
412 gnutls_assert();
413 return GNUTLS_E_MEMORY_ERROR;
414 }
415
416 tint2 = asn1.size;
417 err = Tspi_DecodeBER_TssBlob(fdata->size, fdata->data, &type,
418 &tint2, asn1.data);
419 if (err != 0)
420 {
421 gnutls_assert();
422 ret = tss_err(err);
423 goto cleanup;
424 }
425
426 asn1.size = tint2;
427 }
428
429 /* ... we get it here instead. */
430 err = Tspi_Context_LoadKeyByBlob (tpm_ctx, srk,
431 asn1.size, asn1.data, tpm_key);
432 if (err != 0)
433 {
434 gnutls_assert ();
435 ret = tss_err(err);
436 goto cleanup;
437 }
438
439 ret = 0;
440
441cleanup:
442 gnutls_free (asn1.data);
443
444 return ret;
445}
446
447
448static int
449import_tpm_key (gnutls_privkey_t pkey,
450 const gnutls_datum_t * fdata,
451 gnutls_tpmkey_fmt_t format,
452 TSS_UUID *uuid,
453 TSS_FLAG storage,
454 const char *srk_password,
455 const char *key_password)
456{
457 int err, ret;
458 struct tpm_ctx_st *s;
459 gnutls_datum_t tmp_sig;
460
461 s = gnutls_malloc (sizeof (*s));
462 if (s == NULL)
463 {
464 gnutls_assert ();
465 return GNUTLS_E_MEMORY_ERROR;
466 }
467
468 ret = tpm_open_session(s, srk_password);
469 if (ret < 0)
470 {
471 gnutls_assert();
472 goto out_ctx;
473 }
474
475 if (fdata != NULL)
476 {
477 ret = load_key(s->tpm_ctx, s->srk, fdata, format, &s->tpm_key);
478 if (ret < 0)
479 {
480 gnutls_assert();
481 goto out_session;
482 }
483 }
484 else if (uuid)
485 {
486 err =
487 Tspi_Context_LoadKeyByUUID (s->tpm_ctx, storage,
488 *uuid, &s->tpm_key);
489
490 if (err)
491 {
492 gnutls_assert ();
493 ret = tss_err(err);
494 goto out_session;
495 }
496 }
497 else
498 {
499 gnutls_assert();
500 ret = GNUTLS_E_INVALID_REQUEST;
501 goto out_session;
502 }
503
504 ret =
505 gnutls_privkey_import_ext2 (pkey, GNUTLS_PK_RSA, s,
506 tpm_sign_fn, NULL, tpm_deinit_fn, 0);
507 if (ret < 0)
508 {
509 gnutls_assert ();
510 goto out_session;
511 }
512
513 ret =
514 gnutls_privkey_sign_data (pkey, GNUTLS_DIG_SHA1, 0, &nulldata, &tmp_sig);
515 if (ret == GNUTLS_E_TPM_KEY_PASSWORD_ERROR)
516 {
517 if (!s->tpm_key_policy)
518 {
519 err = Tspi_Context_CreateObject (s->tpm_ctx,
520 TSS_OBJECT_TYPE_POLICY,
521 TSS_POLICY_USAGE,
522 &s->tpm_key_policy);
523 if (err)
524 {
525 gnutls_assert ();
526 ret = tss_err(err);
527 goto out_key;
528 }
529
530 err = Tspi_Policy_AssignToObject (s->tpm_key_policy, s->tpm_key);
531 if (err)
532 {
533 gnutls_assert ();
534 ret = tss_err(err);
535 goto out_key_policy;
536 }
537 }
538
539 err = myTspi_Policy_SetSecret (s->tpm_key_policy,
540 SAFE_LEN(key_password), (void *) key_password);
541
542 if (err)
543 {
544 gnutls_assert ();
545 ret = tss_err_key(err);
546 goto out_key_policy;
547 }
548 }
549 else if (ret < 0)
550 {
551 gnutls_assert ();
552 goto out_session;
553 }
554
555 return 0;
556out_key_policy:
557 Tspi_Context_CloseObject (s->tpm_ctx, s->tpm_key_policy);
558 s->tpm_key_policy = 0;
559out_key:
560 Tspi_Context_CloseObject (s->tpm_ctx, s->tpm_key);
561 s->tpm_key = 0;
562out_session:
563 tpm_close_session(s);
564out_ctx:
565 gnutls_free (s);
566 return ret;
567}
568
569/**
570 * gnutls_privkey_import_tpm_raw:
571 * @pkey: The private key
572 * @fdata: The TPM key to be imported
573 * @format: The format of the private key
574 * @srk_password: The password for the SRK key (optional)
575 * @key_password: A password for the key (optional)
576 * @flags: should be zero
577 *
578 * This function will import the given private key to the abstract
579 * #gnutls_privkey_t structure.
580 *
581 * With respect to passwords the same as in gnutls_privkey_import_tpm_url() apply.
582 *
583 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
584 * negative error value.
585 *
586 * Since: 3.1.0
587 *
588 **/
589int
590gnutls_privkey_import_tpm_raw (gnutls_privkey_t pkey,
591 const gnutls_datum_t * fdata,
592 gnutls_tpmkey_fmt_t format,
593 const char *srk_password,
594 const char *key_password,
595 unsigned int flags)
596{
597 if (flags & GNUTLS_PRIVKEY_DISABLE_CALLBACKS)
598 return import_tpm_key(pkey, fdata, format, NULL, 0, srk_password, key_password);
599 else
600 return import_tpm_key_cb(pkey, fdata, format, NULL, 0, srk_password, key_password);
601}
602
603struct tpmkey_url_st
604{
605 char* filename;
606 TSS_UUID uuid;
607 TSS_FLAG storage;
608 unsigned int uuid_set;
609};
610
611static void clear_tpmkey_url(struct tpmkey_url_st *s)
612{
613 gnutls_free(s->filename);
614 memset(s, 0, sizeof(*s));
615}
616
617static int
618unescape_string (char *output, const char *input, size_t * size,
619 char terminator)
620{
621 gnutls_buffer_st str;
622 int ret = 0;
623 char *p;
624 int len;
625
626 _gnutls_buffer_init (&str);
627
628 /* find terminator */
629 p = strchr (input, terminator);
630 if (p != NULL)
631 len = p - input;
632 else
633 len = strlen (input);
634
635 ret = _gnutls_buffer_append_data (&str, input, len);
636 if (ret < 0)
637 {
638 gnutls_assert ();
639 return ret;
640 }
641
642 ret = _gnutls_buffer_unescape (&str);
643 if (ret < 0)
644 {
645 gnutls_assert ();
646 return ret;
647 }
648
649 ret = _gnutls_buffer_append_data (&str, "", 1);
650 if (ret < 0)
651 {
652 gnutls_assert ();
653 return ret;
654 }
655
656 _gnutls_buffer_pop_data (&str, output, size);
657
658 _gnutls_buffer_clear (&str);
659
660 return ret;
661}
662
663#define UUID_SIZE 16
664
665static int randomize_uuid(TSS_UUID* uuid)
666{
667 uint8_t raw_uuid[16];
668 int ret;
669
670 ret = _gnutls_rnd (GNUTLS_RND_NONCE, raw_uuid, sizeof(raw_uuid));
671 if (ret < 0)
672 return gnutls_assert_val(ret);
673
674 /* mark it as random uuid */
675 raw_uuid[6] &= 0x0f;
676 raw_uuid[6] |= 0x40;
677 raw_uuid[8] &= 0x0f;
678 raw_uuid[8] |= 0x80;
679
680 memcpy(&uuid->ulTimeLow, raw_uuid, 4);
681 memcpy(&uuid->usTimeMid, &raw_uuid[4], 2);
682 memcpy(&uuid->usTimeHigh, &raw_uuid[6], 2);
683 uuid->bClockSeqHigh = raw_uuid[8];
684 uuid->bClockSeqLow = raw_uuid[9];
685 memcpy(&uuid->rgbNode, &raw_uuid[10], 6);
686
687 return 0;
688}
689
690static int encode_tpmkey_url(char** url, const TSS_UUID* uuid, TSS_FLAG storage)
691{
692size_t size = (UUID_SIZE*2+4)*2+32;
693uint8_t u1[UUID_SIZE];
694gnutls_buffer_st buf;
695gnutls_datum_t dret;
696int ret;
697
698 *url = gnutls_malloc(size);
699 if (*url == NULL)
700 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
701
702 _gnutls_buffer_init(&buf);
703
704 memcpy(u1, &uuid->ulTimeLow, 4);
705 memcpy(&u1[4], &uuid->usTimeMid, 2);
706 memcpy(&u1[6], &uuid->usTimeHigh, 2);
707 u1[8] = uuid->bClockSeqHigh;
708 u1[9] = uuid->bClockSeqLow;
709 memcpy(&u1[10], uuid->rgbNode, 6);
710
711 ret = _gnutls_buffer_append_str(&buf, "tpmkey:uuid=");
712 if (ret < 0)
713 {
714 gnutls_assert();
715 goto cleanup;
716 }
717
718 ret = _gnutls_buffer_append_printf(&buf, "%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x",
719 (unsigned int)u1[0], (unsigned int)u1[1], (unsigned int)u1[2], (unsigned int)u1[3],
720 (unsigned int)u1[4], (unsigned int)u1[5], (unsigned int)u1[6], (unsigned int)u1[7],
721 (unsigned int)u1[8], (unsigned int)u1[9], (unsigned int)u1[10], (unsigned int)u1[11],
722 (unsigned int)u1[12], (unsigned int)u1[13], (unsigned int)u1[14], (unsigned int)u1[15]);
723 if (ret < 0)
724 {
725 gnutls_assert();
726 goto cleanup;
727 }
728
729 ret = _gnutls_buffer_append_printf(&buf, ";storage=%s", (storage==TSS_PS_TYPE_USER)?"user":"system");
730 if (ret < 0)
731 {
732 gnutls_assert();
733 goto cleanup;
734 }
735
736 ret = _gnutls_buffer_to_datum(&buf, &dret);
737 if (ret < 0)
738 {
739 gnutls_assert();
740 goto cleanup;
741 }
742
743 *url = (char*)dret.data;
744
745 return 0;
746cleanup:
747 _gnutls_buffer_clear(&buf);
748 return ret;
749}
750
751static int decode_tpmkey_url(const char* url, struct tpmkey_url_st *s)
752{
753 char* p;
754 size_t size;
755 int ret;
756 unsigned int i, j;
757
758 if (strstr (url, "tpmkey:") == NULL)
759 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
760
761 memset(s, 0, sizeof(*s));
762
763 p = strstr(url, "file=");
764 if (p != NULL)
765 {
766 p += sizeof ("file=") - 1;
767 size = strlen(p);
768 s->filename = gnutls_malloc(size+1);
769 if (s->filename == NULL)
770 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
771
772 ret = unescape_string (s->filename, p, &size, ';');
773 if (ret < 0)
774 {
775 gnutls_assert();
776 goto cleanup;
777 }
778 s->filename[size] = 0;
779 }
780 else if ((p = strstr(url, "uuid=")) != NULL)
781 {
782 char tmp_uuid[33];
783 uint8_t raw_uuid[16];
784
785 p += sizeof ("uuid=") - 1;
786 size = strlen(p);
787
788 for (j=i=0;i<size;i++)
789 {
790 if (j==sizeof(tmp_uuid)-1)
791 {
792 break;
793 }
794 if (c_isalnum(p[i])) tmp_uuid[j++]=p[i];
795 }
796 tmp_uuid[j] = 0;
797
798 size = sizeof(raw_uuid);
799 ret = _gnutls_hex2bin(tmp_uuid, strlen(tmp_uuid), raw_uuid, &size);
800 if (ret < 0)
801 {
802 gnutls_assert();
803 goto cleanup;
804 }
805
806 memcpy(&s->uuid.ulTimeLow, raw_uuid, 4);
807 memcpy(&s->uuid.usTimeMid, &raw_uuid[4], 2);
808 memcpy(&s->uuid.usTimeHigh, &raw_uuid[6], 2);
809 s->uuid.bClockSeqHigh = raw_uuid[8];
810 s->uuid.bClockSeqLow = raw_uuid[9];
811 memcpy(&s->uuid.rgbNode, &raw_uuid[10], 6);
812 s->uuid_set = 1;
813 }
814 else
815 {
816 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
817 }
818
819 if ((p = strstr(url, "storage=user")) != NULL)
820 s->storage = TSS_PS_TYPE_USER;
821 else
822 s->storage = TSS_PS_TYPE_SYSTEM;
823
824 return 0;
825
826cleanup:
827 clear_tpmkey_url(s);
828 return ret;
829}
830
831/**
832 * gnutls_privkey_import_tpm_url:
833 * @pkey: The private key
834 * @url: The URL of the TPM key to be imported
835 * @srk_password: The password for the SRK key (optional)
836 * @key_password: A password for the key (optional)
837 * @flags: One of the GNUTLS_PRIVKEY_* flags
838 *
839 * This function will import the given private key to the abstract
840 * #gnutls_privkey_t structure.
841 *
842 * Note that unless %GNUTLS_PRIVKEY_DISABLE_CALLBACKS
843 * is specified, if incorrect (or NULL) passwords are given
844 * the PKCS11 callback functions will be used to obtain the
845 * correct passwords. Otherwise if the SRK password is wrong
846 * %GNUTLS_E_TPM_SRK_PASSWORD_ERROR is returned and if the key password
847 * is wrong or not provided then %GNUTLS_E_TPM_KEY_PASSWORD_ERROR
848 * is returned.
849 *
850 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
851 * negative error value.
852 *
853 * Since: 3.1.0
854 *
855 **/
856int
857gnutls_privkey_import_tpm_url (gnutls_privkey_t pkey,
858 const char* url,
859 const char *srk_password,
860 const char *key_password,
861 unsigned int flags)
862{
863struct tpmkey_url_st durl;
864gnutls_datum_t fdata = { NULL, 0 };
865int ret;
866
867 ret = decode_tpmkey_url(url, &durl);
868 if (ret < 0)
869 return gnutls_assert_val(ret);
870
871 if (durl.filename)
872 {
873 ret = gnutls_load_file(durl.filename, &fdata);
874 if (ret < 0)
875 {
876 gnutls_assert();
877 _gnutls_debug_log("Error loading %s\n", durl.filename);
878 goto cleanup;
879 }
880
881 ret = gnutls_privkey_import_tpm_raw (pkey, &fdata, GNUTLS_TPMKEY_FMT_CTK_PEM,
882 srk_password, key_password, flags);
883 if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
884 ret = gnutls_privkey_import_tpm_raw (pkey, &fdata, GNUTLS_TPMKEY_FMT_RAW,
885 srk_password, key_password, flags);
886
887 if (ret < 0)
888 {
889 gnutls_assert();
890 goto cleanup;
891 }
892 }
893 else if (durl.uuid_set)
894 {
895 if (flags & GNUTLS_PRIVKEY_DISABLE_CALLBACKS)
896 ret = import_tpm_key (pkey, NULL, 0, &durl.uuid, durl.storage, srk_password, key_password);
897 else
898 ret = import_tpm_key_cb (pkey, NULL, 0, &durl.uuid, durl.storage, srk_password, key_password);
899 if (ret < 0)
900 {
901 gnutls_assert();
902 goto cleanup;
903 }
904 }
905
906 ret = 0;
907cleanup:
908 gnutls_free(fdata.data);
909 clear_tpmkey_url(&durl);
910 return ret;
911}
912
913
914/* reads the RSA public key from the given TSS key.
915 * If psize is non-null it contains the total size of the parameters
916 * in bytes */
917static int read_pubkey(gnutls_pubkey_t pub, TSS_HKEY key_ctx, size_t *psize)
918{
919void* tdata;
920UINT32 tint;
921TSS_RESULT tssret;
922gnutls_datum_t m, e;
923int ret;
924
925 /* read the public key */
926
927 tssret = Tspi_GetAttribData(key_ctx, TSS_TSPATTRIB_RSAKEY_INFO,
928 TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, &tint, (void*)&tdata);
929 if (tssret != 0)
930 {
931 gnutls_assert();
932 return tss_err(tssret);
933 }
934
935 m.data = tdata;
936 m.size = tint;
937
938 tssret = Tspi_GetAttribData(key_ctx, TSS_TSPATTRIB_RSAKEY_INFO,
939 TSS_TSPATTRIB_KEYINFO_RSA_EXPONENT, &tint, (void*)&tdata);
940 if (tssret != 0)
941 {
942 gnutls_assert();
943 Tspi_Context_FreeMemory(key_ctx, m.data);
944 return tss_err(tssret);
945 }
946
947 e.data = tdata;
948 e.size = tint;
949
950 ret = gnutls_pubkey_import_rsa_raw(pub, &m, &e);
951
952 Tspi_Context_FreeMemory(key_ctx, m.data);
953 Tspi_Context_FreeMemory(key_ctx, e.data);
954
955 if (ret < 0)
956 return gnutls_assert_val(ret);
957
958 if (psize)
959 *psize = e.size + m.size;
960
961 return 0;
962}
963
964
965
966static int
967import_tpm_pubkey (gnutls_pubkey_t pkey,
968 const gnutls_datum_t * fdata,
969 gnutls_tpmkey_fmt_t format,
970 TSS_UUID *uuid,
971 TSS_FLAG storage,
972 const char *srk_password)
973{
974int err, ret;
975struct tpm_ctx_st s;
976
977 ret = tpm_open_session(&s, srk_password);
978 if (ret < 0)
979 return gnutls_assert_val(ret);
980
981 if (fdata != NULL)
982 {
983 ret = load_key(s.tpm_ctx, s.srk, fdata, format, &s.tpm_key);
984 if (ret < 0)
985 {
986 gnutls_assert();
987 goto out_session;
988 }
989 }
990 else if (uuid)
991 {
992 err =
993 Tspi_Context_LoadKeyByUUID (s.tpm_ctx, storage,
994 *uuid, &s.tpm_key);
995 if (err)
996 {
997 gnutls_assert ();
998 ret = tss_err(err);
999 goto out_session;
1000 }
1001 }
1002 else
1003 {
1004 gnutls_assert();
1005 ret = GNUTLS_E_INVALID_REQUEST;
1006 goto out_session;
1007 }
1008
1009 ret = read_pubkey(pkey, s.tpm_key, NULL);
1010 if (ret < 0)
1011 {
1012 gnutls_assert();
1013 goto out_session;
1014 }
1015
1016 ret = 0;
1017out_session:
1018 tpm_close_session(&s);
1019 return ret;
1020}
1021
1022static int
1023import_tpm_pubkey_cb (gnutls_pubkey_t pkey,
1024 const gnutls_datum_t * fdata,
1025 gnutls_tpmkey_fmt_t format,
1026 TSS_UUID *uuid,
1027 TSS_FLAG storage,
1028 const char *srk_password)
1029{
1030unsigned int attempts = 0;
1031char pin1[GNUTLS_PKCS11_MAX_PIN_LEN];
1032int ret;
1033
1034 do
1035 {
1036 ret = import_tpm_pubkey(pkey, fdata, format, uuid, storage, srk_password);
1037
1038 if (attempts > 3)
1039 break;
1040
1041 if (ret == GNUTLS_E_TPM_SRK_PASSWORD_ERROR)
1042 {
1043 ret = tpm_pin(&pkey->pin, &srk_uuid, storage, pin1, sizeof(pin1), attempts++);
1044 if (ret < 0)
1045 {
1046 gnutls_assert();
1047 return GNUTLS_E_TPM_SRK_PASSWORD_ERROR;
1048 }
1049 srk_password = pin1;
1050 }
1051 }
1052 while(ret == GNUTLS_E_TPM_SRK_PASSWORD_ERROR);
1053
1054 if (ret < 0)
1055 gnutls_assert();
1056 return ret;
1057}
1058
1059
1060/**
1061 * gnutls_pubkey_import_tpm_raw:
1062 * @pkey: The public key
1063 * @fdata: The TPM key to be imported
1064 * @format: The format of the private key
1065 * @srk_password: The password for the SRK key (optional)
1066 * @flags: One of the GNUTLS_PUBKEY_* flags
1067 *
1068 * This function will import the public key from the provided TPM key
1069 * structure.
1070 *
1071 * With respect to passwords the same as in
1072 * gnutls_pubkey_import_tpm_url() apply.
1073 *
1074 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1075 * negative error value.
1076 *
1077 * Since: 3.1.0
1078 **/
1079int
1080gnutls_pubkey_import_tpm_raw (gnutls_pubkey_t pkey,
1081 const gnutls_datum_t * fdata,
1082 gnutls_tpmkey_fmt_t format,
1083 const char *srk_password,
1084 unsigned int flags)
1085{
1086 if (flags & GNUTLS_PUBKEY_DISABLE_CALLBACKS)
1087 return import_tpm_pubkey_cb(pkey, fdata, format, NULL, 0, srk_password);
1088 else
1089 return import_tpm_pubkey(pkey, fdata, format, NULL, 0, srk_password);
1090}
1091
1092/**
1093 * gnutls_pubkey_import_tpm_url:
1094 * @pkey: The public key
1095 * @url: The URL of the TPM key to be imported
1096 * @srk_password: The password for the SRK key (optional)
1097 * @flags: should be zero
1098 *
1099 * This function will import the given private key to the abstract
1100 * #gnutls_privkey_t structure.
1101 *
1102 * Note that unless %GNUTLS_PUBKEY_DISABLE_CALLBACKS
1103 * is specified, if incorrect (or NULL) passwords are given
1104 * the PKCS11 callback functions will be used to obtain the
1105 * correct passwords. Otherwise if the SRK password is wrong
1106 * %GNUTLS_E_TPM_SRK_PASSWORD_ERROR is returned.
1107 *
1108 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1109 * negative error value.
1110 *
1111 * Since: 3.1.0
1112 *
1113 **/
1114int
1115gnutls_pubkey_import_tpm_url (gnutls_pubkey_t pkey,
1116 const char* url,
1117 const char *srk_password,
1118 unsigned int flags)
1119{
1120struct tpmkey_url_st durl;
1121gnutls_datum_t fdata = { NULL, 0 };
1122int ret;
1123
1124 ret = decode_tpmkey_url(url, &durl);
1125 if (ret < 0)
1126 return gnutls_assert_val(ret);
1127
1128 if (durl.filename)
1129 {
1130
1131 ret = gnutls_load_file(durl.filename, &fdata);
1132 if (ret < 0)
1133 {
1134 gnutls_assert();
1135 goto cleanup;
1136 }
1137
1138 ret = gnutls_pubkey_import_tpm_raw (pkey, &fdata, GNUTLS_TPMKEY_FMT_CTK_PEM,
1139 srk_password, flags);
1140 if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
1141 ret = gnutls_pubkey_import_tpm_raw (pkey, &fdata, GNUTLS_TPMKEY_FMT_RAW,
1142 srk_password, flags);
1143 if (ret < 0)
1144 {
1145 gnutls_assert();
1146 goto cleanup;
1147 }
1148 }
1149 else if (durl.uuid_set)
1150 {
1151 if (flags & GNUTLS_PUBKEY_DISABLE_CALLBACKS)
1152 ret = import_tpm_pubkey (pkey, NULL, 0, &durl.uuid, durl.storage, srk_password);
1153 else
1154 ret = import_tpm_pubkey_cb (pkey, NULL, 0, &durl.uuid, durl.storage, srk_password);
1155 if (ret < 0)
1156 {
1157 gnutls_assert();
1158 goto cleanup;
1159 }
1160 }
1161
1162 ret = 0;
1163cleanup:
1164 gnutls_free(fdata.data);
1165 clear_tpmkey_url(&durl);
1166 return ret;
1167}
1168
1169
1170/**
1171 * gnutls_tpm_privkey_generate:
1172 * @pk: the public key algorithm
1173 * @bits: the security bits
1174 * @srk_password: a password to protect the exported key (optional)
1175 * @key_password: the password for the TPM (optional)
1176 * @format: the format of the private key
1177 * @pub_format: the format of the public key
1178 * @privkey: the generated key
1179 * @pubkey: the corresponding public key (may be null)
1180 * @flags: should be a list of GNUTLS_TPM_* flags
1181 *
1182 * This function will generate a private key in the TPM
1183 * chip. The private key will be generated within the chip
1184 * and will be exported in a wrapped with TPM's master key
1185 * form. Furthermore the wrapped key can be protected with
1186 * the provided @password.
1187 *
1188 * Note that bits in TPM is quantized value. If the input value
1189 * is not one of the allowed values, then it will be quantized to
1190 * one of 512, 1024, 2048, 4096, 8192 and 16384.
1191 *
1192 * Allowed flags are:
1193 *
1194 * %GNUTLS_TPM_KEY_SIGNING: Generate a signing key instead of a legacy,
1195
1196 * %GNUTLS_TPM_REGISTER_KEY: Register the generate key in TPM. In that
1197 * case @privkey would contain a URL with the UUID.
1198 *
1199 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1200 * negative error value.
1201 *
1202 * Since: 3.1.0
1203 **/
1204int
1205gnutls_tpm_privkey_generate (gnutls_pk_algorithm_t pk, unsigned int bits,
1206 const char* srk_password,
1207 const char* key_password,
1208 gnutls_tpmkey_fmt_t format,
1209 gnutls_x509_crt_fmt_t pub_format,
1210 gnutls_datum_t* privkey,
1211 gnutls_datum_t* pubkey,
1212 unsigned int flags)
1213{
1214TSS_FLAG tpm_flags = TSS_KEY_VOLATILE;
1215TSS_HKEY key_ctx;
1216TSS_RESULT tssret;
1217int ret;
1218void* tdata;
1219UINT32 tint;
1220gnutls_datum_t tmpkey = {NULL, 0};
1221TSS_HPOLICY key_policy;
1222gnutls_pubkey_t pub;
1223struct tpm_ctx_st s;
1224TSS_FLAG storage_type;
1225TSS_HTPM htpm;
1226uint8_t buf[32];
1227
1228 if (flags & GNUTLS_TPM_KEY_SIGNING)
1229 tpm_flags |= TSS_KEY_TYPE_SIGNING;
1230 else
1231 tpm_flags |= TSS_KEY_TYPE_LEGACY;
1232
1233 if (flags & GNUTLS_TPM_KEY_USER)
1234 storage_type = TSS_PS_TYPE_USER;
1235 else
1236 storage_type = TSS_PS_TYPE_SYSTEM;
1237
1238 if (bits <= 512)
1239 tpm_flags |= TSS_KEY_SIZE_512;
1240 else if (bits <= 1024)
1241 tpm_flags |= TSS_KEY_SIZE_1024;
1242 else if (bits <= 2048)
1243 tpm_flags |= TSS_KEY_SIZE_2048;
1244 else if (bits <= 4096)
1245 tpm_flags |= TSS_KEY_SIZE_4096;
1246 else if (bits <= 8192)
1247 tpm_flags |= TSS_KEY_SIZE_8192;
1248 else
1249 tpm_flags |= TSS_KEY_SIZE_16384;
1250
1251 ret = tpm_open_session(&s, srk_password);
1252 if (ret < 0)
1253 return gnutls_assert_val(ret);
1254
1255 /* put some randomness into TPM.
1256 * Let's not trust it completely.
1257 */
1258 tssret = Tspi_Context_GetTpmObject(s.tpm_ctx, &htpm);
1259 if (tssret != 0)
1260 {
1261 gnutls_assert();
1262 ret = tss_err(tssret);
1263 goto err_cc;
1264 }
1265
1266
1267 ret = _gnutls_rnd(GNUTLS_RND_RANDOM, buf, sizeof(buf));
1268 if (ret < 0)
1269 {
1270 gnutls_assert();
1271 goto err_cc;
1272 }
1273
1274 tssret = Tspi_TPM_StirRandom(htpm, sizeof(buf), buf);
1275 if (tssret)
1276 {
1277 gnutls_assert();
1278 }
1279
1280 tssret = Tspi_Context_CreateObject(s.tpm_ctx, TSS_OBJECT_TYPE_RSAKEY, tpm_flags, &key_ctx);
1281 if (tssret != 0)
1282 {
1283 gnutls_assert();
1284 ret = tss_err(tssret);
1285 goto err_cc;
1286 }
1287
1288 tssret = Tspi_SetAttribUint32(key_ctx, TSS_TSPATTRIB_KEY_INFO, TSS_TSPATTRIB_KEYINFO_SIGSCHEME,
1289 TSS_SS_RSASSAPKCS1V15_DER);
1290 if (tssret != 0)
1291 {
1292 gnutls_assert();
1293 ret = tss_err(tssret);
1294 goto err_sa;
1295 }
1296
1297 /* set the password of the actual key */
1298 if (key_password)
1299 {
1300 tssret = Tspi_GetPolicyObject(key_ctx, TSS_POLICY_USAGE, &key_policy);
1301 if (tssret != 0)
1302 {
1303 gnutls_assert();
1304 ret = tss_err(tssret);
1305 goto err_sa;
1306 }
1307
1308 tssret = myTspi_Policy_SetSecret(key_policy,
1309 SAFE_LEN(key_password), (void*)key_password);
1310 if (tssret != 0)
1311 {
1312 gnutls_assert();
1313 ret = tss_err(tssret);
1314 goto err_sa;
1315 }
1316 }
1317
1318 tssret = Tspi_Key_CreateKey(key_ctx, s.srk, 0);
1319 if (tssret != 0)
1320 {
1321 gnutls_assert();
1322 ret = tss_err(tssret);
1323 goto err_sa;
1324 }
1325
1326 if (flags & GNUTLS_TPM_REGISTER_KEY)
1327 {
1328 TSS_UUID key_uuid;
1329
1330 ret = randomize_uuid(&key_uuid);
1331 if (ret < 0)
1332 {
1333 gnutls_assert();
1334 goto err_sa;
1335 }
1336
1337 tssret = Tspi_Context_RegisterKey(s.tpm_ctx, key_ctx, storage_type,
1338 key_uuid, TSS_PS_TYPE_SYSTEM, srk_uuid);
1339 if (tssret != 0)
1340 {
1341 gnutls_assert();
1342 ret = tss_err(tssret);
1343 goto err_sa;
1344 }
1345
1346 ret = encode_tpmkey_url((char**)&privkey->data, &key_uuid, storage_type);
1347 if (ret < 0)
1348 {
1349 TSS_HKEY tkey;
1350
1351 Tspi_Context_UnregisterKey(s.tpm_ctx, storage_type, key_uuid, &tkey);
1352 gnutls_assert();
1353 goto err_sa;
1354 }
1355 privkey->size = strlen((char*)privkey->data);
1356
1357 }
1358 else /* get the key as blob */
1359 {
1360
1361 tssret = Tspi_GetAttribData(key_ctx, TSS_TSPATTRIB_KEY_BLOB,
1362 TSS_TSPATTRIB_KEYBLOB_BLOB, &tint, (void*)&tdata);
1363 if (tssret != 0)
1364 {
1365 gnutls_assert();
1366 ret = tss_err(tssret);
1367 goto err_sa;
1368 }
1369
1370
1371 if (format == GNUTLS_TPMKEY_FMT_CTK_PEM)
1372 {
1373 ret = _gnutls_x509_encode_string(ASN1_ETYPE_OCTET_STRING, tdata, tint, &tmpkey);
1374 if (ret < 0)
1375 {
1376 gnutls_assert();
1377 goto cleanup;
1378 }
1379
1380 ret = _gnutls_fbase64_encode ("TSS KEY BLOB", tmpkey.data, tmpkey.size, privkey);
1381 if (ret < 0)
1382 {
1383 gnutls_assert();
1384 goto cleanup;
1385 }
1386 }
1387 else
1388 {
1389 UINT32 tint2;
1390
1391 tmpkey.size = tint + 32; /* spec says no more than 20 */
1392 tmpkey.data = gnutls_malloc(tmpkey.size);
1393 if (tmpkey.data == NULL)
1394 {
1395 gnutls_assert();
1396 ret = GNUTLS_E_MEMORY_ERROR;
1397 goto cleanup;
1398 }
1399
1400 tint2 = tmpkey.size;
1401 tssret = Tspi_EncodeDER_TssBlob(tint, tdata, TSS_BLOB_TYPE_PRIVATEKEY,
1402 &tint2, tmpkey.data);
1403 if (tssret != 0)
1404 {
1405 gnutls_assert();
1406 ret = tss_err(tssret);
1407 goto cleanup;
1408 }
1409
1410 tmpkey.size = tint2;
1411
1412 privkey->data = tmpkey.data;
1413 privkey->size = tmpkey.size;
1414 tmpkey.data = NULL;
1415 }
1416 }
1417
1418 /* read the public key */
1419 if (pubkey != NULL)
1420 {
1421 size_t psize;
1422
1423 ret = gnutls_pubkey_init(&pub);
1424 if (ret < 0)
1425 {
1426 gnutls_assert();
1427 goto privkey_cleanup;
1428 }
1429
1430 ret = read_pubkey(pub, key_ctx, &psize);
1431 if (ret < 0)
1432 {
1433 gnutls_assert();
1434 goto privkey_cleanup;
1435 }
1436 psize+=512;
1437
1438 pubkey->data = gnutls_malloc(psize);
1439 if (pubkey->data == NULL)
1440 {
1441 gnutls_assert();
1442 ret = GNUTLS_E_MEMORY_ERROR;
1443 goto pubkey_cleanup;
1444 }
1445
1446 ret = gnutls_pubkey_export(pub, pub_format, pubkey->data, &psize);
1447 if (ret < 0)
1448 {
1449 gnutls_assert();
1450 goto pubkey_cleanup;
1451 }
1452 pubkey->size = psize;
1453
1454 gnutls_pubkey_deinit(pub);
1455 }
1456
1457 ret = 0;
1458 goto cleanup;
1459
1460pubkey_cleanup:
1461 gnutls_pubkey_deinit(pub);
1462privkey_cleanup:
1463 gnutls_free(privkey->data);
1464 privkey->data = NULL;
1465cleanup:
1466 gnutls_free(tmpkey.data);
1467 tmpkey.data = NULL;
1468err_sa:
1469 Tspi_Context_CloseObject(s.tpm_ctx, key_ctx);
1470err_cc:
1471 tpm_close_session(&s);
1472 return ret;
1473}
1474
1475
1476/**
1477 * gnutls_tpm_key_list_deinit:
1478 * @list: a list of the keys
1479 *
1480 * This function will deinitialize the list of stored keys in the TPM.
1481 *
1482 * Since: 3.1.0
1483 **/
1484void
1485gnutls_tpm_key_list_deinit (gnutls_tpm_key_list_t list)
1486{
1487 if (list->tpm_ctx != 0) Tspi_Context_Close (list->tpm_ctx);
1488 gnutls_free(list);
1489}
1490
1491/**
1492 * gnutls_tpm_key_list_get_url:
1493 * @list: a list of the keys
1494 * @idx: The index of the key (starting from zero)
1495 * @url: The URL to be returned
1496 * @flags: should be zero
1497 *
1498 * This function will return for each given index a URL of
1499 * the corresponding key.
1500 * If the provided index is out of bounds then %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
1501 * is returned.
1502 *
1503 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1504 * negative error value.
1505 *
1506 * Since: 3.1.0
1507 **/
1508int
1509gnutls_tpm_key_list_get_url (gnutls_tpm_key_list_t list, unsigned int idx, char** url, unsigned int flags)
1510{
1511 if (idx >= list->size)
1512 return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
1513
1514 return encode_tpmkey_url(url, &list->ki[idx].keyUUID, list->ki[idx].persistentStorageType);
1515}
1516
1517/**
1518 * gnutls_tpm_get_registered:
1519 * @list: a list to store the keys
1520 *
1521 * This function will get a list of stored keys in the TPM. The uuid
1522 * of those keys
1523 *
1524 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1525 * negative error value.
1526 *
1527 * Since: 3.1.0
1528 **/
1529int
1530gnutls_tpm_get_registered (gnutls_tpm_key_list_t *list)
1531{
1532TSS_RESULT tssret;
1533int ret;
1534
1535 *list = gnutls_calloc(1, sizeof(struct tpm_key_list_st));
1536 if (*list == NULL)
1537 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
1538
1539 tssret = Tspi_Context_Create (&(*list)->tpm_ctx);
1540 if (tssret)
1541 {
1542 gnutls_assert ();
1543 ret = tss_err(tssret);
1544 goto cleanup;
1545 }
1546
1547 tssret = Tspi_Context_Connect ((*list)->tpm_ctx, NULL);
1548 if (tssret)
1549 {
1550 gnutls_assert ();
1551 ret = tss_err(tssret);
1552 goto cleanup;
1553 }
1554
1555 tssret =
1556 Tspi_Context_GetRegisteredKeysByUUID2((*list)->tpm_ctx, TSS_PS_TYPE_SYSTEM,
1557 NULL, &(*list)->size, &(*list)->ki);
1558 if (tssret)
1559 {
1560 gnutls_assert ();
1561 ret = tss_err(tssret);
1562 goto cleanup;
1563 }
1564 return 0;
1565
1566cleanup:
1567 gnutls_tpm_key_list_deinit(*list);
1568
1569 return ret;
1570}
1571
1572/**
1573 * gnutls_tpm_privkey_delete:
1574 * @url: the URL describing the key
1575 * @srk_password: a password for the SRK key
1576 *
1577 * This function will unregister the private key from the TPM
1578 * chip.
1579 *
1580 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1581 * negative error value.
1582 *
1583 * Since: 3.1.0
1584 **/
1585int
1586gnutls_tpm_privkey_delete (const char* url, const char* srk_password)
1587{
1588struct tpm_ctx_st s;
1589struct tpmkey_url_st durl;
1590TSS_RESULT tssret;
1591TSS_HKEY tkey;
1592int ret;
1593
1594 ret = decode_tpmkey_url(url, &durl);
1595 if (ret < 0)
1596 return gnutls_assert_val(ret);
1597
1598 if (durl.uuid_set == 0)
1599 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
1600
1601 ret = tpm_open_session(&s, srk_password);
1602 if (ret < 0)
1603 return gnutls_assert_val(ret);
1604
1605 tssret = Tspi_Context_UnregisterKey(s.tpm_ctx, durl.storage, durl.uuid, &tkey);
1606 if (tssret != 0)
1607 {
1608 gnutls_assert();
1609 ret = tss_err(tssret);
1610 goto err_cc;
1611 }
1612
1613 ret = 0;
1614err_cc:
1615 tpm_close_session(&s);
1616 return ret;
1617}
1618#else /* HAVE_TROUSERS */
1619int
1620gnutls_privkey_import_tpm_raw (gnutls_privkey_t pkey,
1621 const gnutls_datum_t * fdata,
1622 gnutls_tpmkey_fmt_t format,
1623 const char *srk_password,
1624 const char *key_password,
1625 unsigned int flags)
1626{
1627 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
1628}
1629
1630int
1631gnutls_privkey_import_tpm_url (gnutls_privkey_t pkey,
1632 const char* url,
1633 const char *srk_password,
1634 const char *key_password,
1635 unsigned int flags)
1636{
1637 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
1638}
1639
1640int
1641gnutls_pubkey_import_tpm_raw (gnutls_pubkey_t pkey,
1642 const gnutls_datum_t * fdata,
1643 gnutls_tpmkey_fmt_t format,
1644 const char *srk_password,
1645 unsigned int flags)
1646{
1647 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
1648}
1649
1650int
1651gnutls_pubkey_import_tpm_url (gnutls_pubkey_t pkey,
1652 const char* url,
1653 const char *srk_password,
1654 unsigned int flags)
1655{
1656 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
1657}
1658
1659int
1660gnutls_tpm_privkey_generate (gnutls_pk_algorithm_t pk, unsigned int bits,
1661 const char* srk_password,
1662 const char* key_password,
1663 gnutls_tpmkey_fmt_t format,
1664 gnutls_x509_crt_fmt_t pub_format,
1665 gnutls_datum_t* privkey,
1666 gnutls_datum_t* pubkey,
1667 unsigned int flags)
1668{
1669 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
1670}
1671
1672void
1673gnutls_tpm_key_list_deinit (gnutls_tpm_key_list_t list)
1674{
1675 return;
1676}
1677
1678int
1679gnutls_tpm_key_list_get_url (gnutls_tpm_key_list_t list, unsigned int idx, char** url, unsigned int flags)
1680{
1681 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
1682}
1683
1684int
1685gnutls_tpm_get_registered (gnutls_tpm_key_list_t *list)
1686{
1687 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
1688}
1689
1690int
1691gnutls_tpm_privkey_delete (const char* url, const char* srk_password)
1692{
1693 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
1694}
1695#endif /* HAVE_TROUSERS */
1696
1697