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