2 * OpenConnect (SSL + DTLS) VPN client
4 * Copyright © 2012 Free Software Foundation.
5 * Copyright © 2008-2012 Intel Corporation.
7 * Author: David Woodhouse <dwmw2@infradead.org>
8 * Author: Nikos Mavrogiannopoulos
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.
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.
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/>
26 * TPM code based on client-tpm.c from
27 * Carolin Latze <latze@angry-red-pla.net> and Tobias Soder
31 #include <gnutls/gnutls.h>
32 #include <gnutls/abstract.h>
33 #include <gnutls/tpm.h>
34 #include <gnutls_int.h>
38 #include <gnutls_errors.h>
39 #include <pkcs11_int.h>
40 #include <x509/common.h>
46 #include <trousers/tss.h>
47 #include <trousers/trousers.h>
52 TSS_HPOLICY tpm_key_policy;
54 TSS_HPOLICY srk_policy;
57 struct tpm_key_list_st {
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,
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,
74 /* TPM URL format: (draft-mavrogiannopoulos-tpmuri-01)
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
83 static int tss_err_pwd(TSS_RESULT err, int pwd_error)
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));
89 switch (ERROR_LAYER(err)) {
91 switch (ERROR_CODE(err)) {
95 return GNUTLS_E_TPM_UNINITIALIZED;
97 return gnutls_assert_val(GNUTLS_E_TPM_ERROR);
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;
110 return gnutls_assert_val(GNUTLS_E_TPM_ERROR);
113 return gnutls_assert_val(GNUTLS_E_TPM_ERROR);
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)
120 static void tpm_deinit_fn(gnutls_privkey_t key, void *_s)
122 struct tpm_ctx_st *s = _s;
124 Tspi_Context_CloseObject(s->tpm_ctx, s->tpm_key_policy);
125 Tspi_Context_CloseObject(s->tpm_ctx, s->tpm_key);
127 tpm_close_session(s);
132 tpm_sign_fn(gnutls_privkey_t key, void *_s,
133 const gnutls_datum_t * data, gnutls_datum_t * sig)
135 struct tpm_ctx_st *s = _s;
139 _gnutls_debug_log("TPM sign function called for %u bytes.\n",
143 Tspi_Context_CreateObject(s->tpm_ctx,
144 TSS_OBJECT_TYPE_HASH, TSS_HASH_OTHER,
148 _gnutls_debug_log("Failed to create TPM hash object: %s\n",
149 Trspi_Error_String(err));
150 return GNUTLS_E_PK_SIGN_FAILED;
152 err = Tspi_Hash_SetHashValue(hash, data->size, data->data);
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;
161 err = Tspi_Hash_Sign(hash, s->tpm_key, &sig->size, &sig->data);
162 Tspi_Context_CloseObject(s->tpm_ctx, hash);
164 if (s->tpm_key_policy || err != TPM_E_AUTHFAIL)
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;
171 return GNUTLS_E_PK_SIGN_FAILED;
176 static const unsigned char nullpass[20];
177 static const gnutls_datum_t nulldata = { (void *) nullpass, 20 };
179 const TSS_UUID srk_uuid = TSS_UUID_SRK;
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)
185 unsigned int flags = 0;
191 flags |= GNUTLS_PIN_WRONG;
194 if (memcmp(uuid, &srk_uuid, sizeof(TSS_UUID)) == 0) {
197 ret = encode_tpmkey_url(&url, uuid, storage);
199 return gnutls_assert_val(ret);
203 ret = encode_tpmkey_url(&url, uuid, storage);
205 return gnutls_assert_val(ret);
210 if (pin_info && pin_info->cb)
212 pin_info->cb(pin_info->data, attempts, url, label,
213 flags, pin, pin_size);
214 else if (_gnutls_pin_func)
216 _gnutls_pin_func(_gnutls_pin_data, attempts, url,
217 label, flags, pin, pin_size);
219 ret = gnutls_assert_val(GNUTLS_E_TPM_KEY_PASSWORD_ERROR); /* doesn't really matter */
233 static TSS_RESULT myTspi_Policy_SetSecret(TSS_HPOLICY hPolicy,
234 UINT32 ulSecretLength,
237 if (rgbSecret == NULL) {
238 /* Well known NULL key */
239 return Tspi_Policy_SetSecret(hPolicy,
240 TSS_SECRET_MODE_SHA1,
243 } else { /* key is given */
245 return Tspi_Policy_SetSecret(hPolicy,
246 TSS_SECRET_MODE_PLAIN,
247 ulSecretLength, rgbSecret);
251 #define SAFE_LEN(x) (x==NULL?0:strlen(x))
253 static int tpm_open_session(struct tpm_ctx_st *s, const char *srk_password)
257 err = Tspi_Context_Create(&s->tpm_ctx);
263 err = Tspi_Context_Connect(s->tpm_ctx, NULL);
271 Tspi_Context_LoadKeyByUUID(s->tpm_ctx, TSS_PS_TYPE_SYSTEM,
280 Tspi_GetPolicyObject(s->srk, TSS_POLICY_USAGE, &s->srk_policy);
287 err = myTspi_Policy_SetSecret(s->srk_policy,
288 SAFE_LEN(srk_password),
289 (BYTE *) srk_password);
299 Tspi_Context_CloseObject(s->tpm_ctx, s->srk_policy);
302 Tspi_Context_CloseObject(s->tpm_ctx, s->srk);
305 Tspi_Context_Close(s->tpm_ctx);
311 static void tpm_close_session(struct tpm_ctx_st *s)
313 Tspi_Context_CloseObject(s->tpm_ctx, s->srk_policy);
315 Tspi_Context_CloseObject(s->tpm_ctx, s->srk);
317 Tspi_Context_Close(s->tpm_ctx);
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)
327 unsigned int attempts = 0;
328 char pin1[GNUTLS_PKCS11_MAX_PIN_LEN];
329 char pin2[GNUTLS_PKCS11_MAX_PIN_LEN];
334 import_tpm_key(pkey, fdata, format, uuid, storage,
335 srk_password, key_password);
340 if (ret == GNUTLS_E_TPM_SRK_PASSWORD_ERROR) {
342 tpm_pin(&pkey->pin, &srk_uuid, storage, pin1,
343 sizeof(pin1), attempts++);
346 return GNUTLS_E_TPM_SRK_PASSWORD_ERROR;
351 if (ret == GNUTLS_E_TPM_KEY_PASSWORD_ERROR) {
353 tpm_pin(&pkey->pin, uuid, storage, pin2,
354 sizeof(pin2), attempts++);
357 return GNUTLS_E_TPM_KEY_PASSWORD_ERROR;
362 while (ret == GNUTLS_E_TPM_KEY_PASSWORD_ERROR
363 || ret == GNUTLS_E_TPM_SRK_PASSWORD_ERROR);
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)
375 gnutls_datum_t asn1 = { NULL, 0 };
377 if (format == GNUTLS_TPMKEY_FMT_CTK_PEM) {
381 gnutls_pem_base64_decode_alloc("TSS KEY BLOB", fdata,
386 ("Error decoding TSS key blob: %s\n",
387 gnutls_strerror(ret));
392 _gnutls_x509_decode_string(ASN1_ETYPE_OCTET_STRING,
393 asn1.data, asn1.size, &td);
398 gnutls_free(asn1.data);
406 asn1.size = fdata->size;
407 asn1.data = gnutls_malloc(asn1.size);
408 if (asn1.data == NULL) {
410 return GNUTLS_E_MEMORY_ERROR;
415 Tspi_DecodeBER_TssBlob(fdata->size, fdata->data, &type,
426 /* ... we get it here instead. */
427 err = Tspi_Context_LoadKeyByBlob(tpm_ctx, srk,
428 asn1.size, asn1.data, tpm_key);
438 gnutls_free(asn1.data);
445 import_tpm_key(gnutls_privkey_t pkey,
446 const gnutls_datum_t * fdata,
447 gnutls_tpmkey_fmt_t format,
450 const char *srk_password, const char *key_password)
453 struct tpm_ctx_st *s;
454 gnutls_datum_t tmp_sig;
456 s = gnutls_malloc(sizeof(*s));
459 return GNUTLS_E_MEMORY_ERROR;
462 ret = tpm_open_session(s, srk_password);
470 load_key(s->tpm_ctx, s->srk, fdata, format,
478 Tspi_Context_LoadKeyByUUID(s->tpm_ctx, storage,
488 ret = GNUTLS_E_INVALID_REQUEST;
493 gnutls_privkey_import_ext2(pkey, GNUTLS_PK_RSA, s,
494 tpm_sign_fn, NULL, tpm_deinit_fn,
502 gnutls_privkey_sign_data(pkey, GNUTLS_DIG_SHA1, 0, &nulldata,
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,
518 Tspi_Policy_AssignToObject(s->tpm_key_policy,
527 err = myTspi_Policy_SetSecret(s->tpm_key_policy,
528 SAFE_LEN(key_password),
529 (void *) key_password);
533 ret = tss_err_key(err);
536 } else if (ret < 0) {
543 Tspi_Context_CloseObject(s->tpm_ctx, s->tpm_key_policy);
544 s->tpm_key_policy = 0;
546 Tspi_Context_CloseObject(s->tpm_ctx, s->tpm_key);
549 tpm_close_session(s);
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
564 * This function will import the given private key to the abstract
565 * #gnutls_privkey_t structure.
567 * With respect to passwords the same as in gnutls_privkey_import_tpm_url() apply.
569 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
570 * negative error value.
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)
582 if (flags & GNUTLS_PRIVKEY_DISABLE_CALLBACKS)
583 return import_tpm_key(pkey, fdata, format, NULL, 0,
584 srk_password, key_password);
586 return import_tpm_key_cb(pkey, fdata, format, NULL, 0,
587 srk_password, key_password);
590 struct tpmkey_url_st {
594 unsigned int uuid_set;
597 static void clear_tpmkey_url(struct tpmkey_url_st *s)
599 gnutls_free(s->filename);
600 memset(s, 0, sizeof(*s));
604 unescape_string(char *output, const char *input, size_t * size,
607 gnutls_buffer_st str;
612 _gnutls_buffer_init(&str);
614 /* find terminator */
615 p = strchr(input, terminator);
621 ret = _gnutls_buffer_append_data(&str, input, len);
627 ret = _gnutls_buffer_unescape(&str);
633 ret = _gnutls_buffer_append_data(&str, "", 1);
639 _gnutls_buffer_pop_data(&str, output, size);
641 _gnutls_buffer_clear(&str);
648 static int randomize_uuid(TSS_UUID * uuid)
650 uint8_t raw_uuid[16];
653 ret = _gnutls_rnd(GNUTLS_RND_NONCE, raw_uuid, sizeof(raw_uuid));
655 return gnutls_assert_val(ret);
657 /* mark it as random uuid */
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);
673 static int encode_tpmkey_url(char **url, const TSS_UUID * uuid,
676 size_t size = (UUID_SIZE * 2 + 4) * 2 + 32;
677 uint8_t u1[UUID_SIZE];
678 gnutls_buffer_st buf;
682 *url = gnutls_malloc(size);
684 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
686 _gnutls_buffer_init(&buf);
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);
695 ret = _gnutls_buffer_append_str(&buf, "tpmkey:uuid=");
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]);
726 _gnutls_buffer_append_printf(&buf, ";storage=%s",
728 TSS_PS_TYPE_USER) ? "user" :
735 ret = _gnutls_buffer_to_datum(&buf, &dret);
741 *url = (char *) dret.data;
745 _gnutls_buffer_clear(&buf);
749 static int decode_tpmkey_url(const char *url, struct tpmkey_url_st *s)
756 if (strstr(url, "tpmkey:") == NULL)
757 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
759 memset(s, 0, sizeof(*s));
761 p = strstr(url, "file=");
763 p += sizeof("file=") - 1;
765 s->filename = gnutls_malloc(size + 1);
766 if (s->filename == NULL)
767 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
769 ret = unescape_string(s->filename, p, &size, ';');
774 s->filename[size] = 0;
775 } else if ((p = strstr(url, "uuid=")) != NULL) {
777 uint8_t raw_uuid[16];
779 p += sizeof("uuid=") - 1;
782 for (j = i = 0; i < size; i++) {
783 if (j == sizeof(tmp_uuid) - 1) {
787 tmp_uuid[j++] = p[i];
791 size = sizeof(raw_uuid);
793 _gnutls_hex2bin(tmp_uuid, strlen(tmp_uuid), raw_uuid,
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);
808 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
811 if (strstr(url, "storage=user") != NULL)
812 s->storage = TSS_PS_TYPE_USER;
814 s->storage = TSS_PS_TYPE_SYSTEM;
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
831 * This function will import the given private key to the abstract
832 * #gnutls_privkey_t structure.
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
842 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
843 * negative error value.
849 gnutls_privkey_import_tpm_url(gnutls_privkey_t pkey,
851 const char *srk_password,
852 const char *key_password, unsigned int flags)
854 struct tpmkey_url_st durl;
855 gnutls_datum_t fdata = { NULL, 0 };
858 ret = decode_tpmkey_url(url, &durl);
860 return gnutls_assert_val(ret);
863 ret = gnutls_load_file(durl.filename, &fdata);
866 _gnutls_debug_log("Error loading %s\n",
872 gnutls_privkey_import_tpm_raw(pkey, &fdata,
873 GNUTLS_TPMKEY_FMT_CTK_PEM,
875 key_password, flags);
876 if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR)
878 gnutls_privkey_import_tpm_raw(pkey, &fdata,
879 GNUTLS_TPMKEY_FMT_RAW,
888 } else if (durl.uuid_set) {
889 if (flags & GNUTLS_PRIVKEY_DISABLE_CALLBACKS)
891 import_tpm_key(pkey, NULL, 0, &durl.uuid,
892 durl.storage, srk_password,
896 import_tpm_key_cb(pkey, NULL, 0, &durl.uuid,
897 durl.storage, srk_password,
907 gnutls_free(fdata.data);
908 clear_tpmkey_url(&durl);
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
916 static int read_pubkey(gnutls_pubkey_t pub, TSS_HKEY key_ctx,
925 /* read the public key */
927 tssret = Tspi_GetAttribData(key_ctx, TSS_TSPATTRIB_RSAKEY_INFO,
928 TSS_TSPATTRIB_KEYINFO_RSA_MODULUS,
929 &tint, (void *) &tdata);
932 return tss_err(tssret);
938 tssret = Tspi_GetAttribData(key_ctx, TSS_TSPATTRIB_RSAKEY_INFO,
939 TSS_TSPATTRIB_KEYINFO_RSA_EXPONENT,
940 &tint, (void *) &tdata);
943 Tspi_Context_FreeMemory(key_ctx, m.data);
944 return tss_err(tssret);
950 ret = gnutls_pubkey_import_rsa_raw(pub, &m, &e);
952 Tspi_Context_FreeMemory(key_ctx, m.data);
953 Tspi_Context_FreeMemory(key_ctx, e.data);
956 return gnutls_assert_val(ret);
959 *psize = e.size + m.size;
967 import_tpm_pubkey(gnutls_pubkey_t pkey,
968 const gnutls_datum_t * fdata,
969 gnutls_tpmkey_fmt_t format,
971 TSS_FLAG storage, const char *srk_password)
976 ret = tpm_open_session(&s, srk_password);
978 return gnutls_assert_val(ret);
982 load_key(s.tpm_ctx, s.srk, fdata, format, &s.tpm_key);
989 Tspi_Context_LoadKeyByUUID(s.tpm_ctx, storage,
998 ret = GNUTLS_E_INVALID_REQUEST;
1002 ret = read_pubkey(pkey, s.tpm_key, NULL);
1010 tpm_close_session(&s);
1015 import_tpm_pubkey_cb(gnutls_pubkey_t pkey,
1016 const gnutls_datum_t * fdata,
1017 gnutls_tpmkey_fmt_t format,
1019 TSS_FLAG storage, const char *srk_password)
1021 unsigned int attempts = 0;
1022 char pin1[GNUTLS_PKCS11_MAX_PIN_LEN];
1027 import_tpm_pubkey(pkey, fdata, format, uuid, storage,
1033 if (ret == GNUTLS_E_TPM_SRK_PASSWORD_ERROR) {
1035 tpm_pin(&pkey->pin, &srk_uuid, storage, pin1,
1036 sizeof(pin1), attempts++);
1039 return GNUTLS_E_TPM_SRK_PASSWORD_ERROR;
1041 srk_password = pin1;
1044 while (ret == GNUTLS_E_TPM_SRK_PASSWORD_ERROR);
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
1060 * This function will import the public key from the provided TPM key
1063 * With respect to passwords the same as in
1064 * gnutls_pubkey_import_tpm_url() apply.
1066 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1067 * negative error value.
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)
1077 if (flags & GNUTLS_PUBKEY_DISABLE_CALLBACKS)
1078 return import_tpm_pubkey_cb(pkey, fdata, format, NULL, 0,
1081 return import_tpm_pubkey(pkey, fdata, format, NULL, 0,
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
1092 * This function will import the given private key to the abstract
1093 * #gnutls_privkey_t structure.
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.
1101 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1102 * negative error value.
1108 gnutls_pubkey_import_tpm_url(gnutls_pubkey_t pkey,
1110 const char *srk_password, unsigned int flags)
1112 struct tpmkey_url_st durl;
1113 gnutls_datum_t fdata = { NULL, 0 };
1116 ret = decode_tpmkey_url(url, &durl);
1118 return gnutls_assert_val(ret);
1120 if (durl.filename) {
1122 ret = gnutls_load_file(durl.filename, &fdata);
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)
1134 gnutls_pubkey_import_tpm_raw(pkey, &fdata,
1135 GNUTLS_TPMKEY_FMT_RAW,
1142 } else if (durl.uuid_set) {
1143 if (flags & GNUTLS_PUBKEY_DISABLE_CALLBACKS)
1145 import_tpm_pubkey(pkey, NULL, 0, &durl.uuid,
1146 durl.storage, srk_password);
1149 import_tpm_pubkey_cb(pkey, NULL, 0, &durl.uuid,
1160 gnutls_free(fdata.data);
1161 clear_tpmkey_url(&durl);
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
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.
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.
1188 * Allowed flags are:
1190 * %GNUTLS_TPM_KEY_SIGNING: Generate a signing key instead of a legacy,
1192 * %GNUTLS_TPM_REGISTER_KEY: Register the generate key in TPM. In that
1193 * case @privkey would contain a URL with the UUID.
1195 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1196 * negative error value.
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)
1209 TSS_FLAG tpm_flags = TSS_KEY_VOLATILE;
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;
1223 if (flags & GNUTLS_TPM_KEY_SIGNING)
1224 tpm_flags |= TSS_KEY_TYPE_SIGNING;
1226 tpm_flags |= TSS_KEY_TYPE_LEGACY;
1228 if (flags & GNUTLS_TPM_KEY_USER)
1229 storage_type = TSS_PS_TYPE_USER;
1231 storage_type = TSS_PS_TYPE_SYSTEM;
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;
1244 tpm_flags |= TSS_KEY_SIZE_16384;
1246 ret = tpm_open_session(&s, srk_password);
1248 return gnutls_assert_val(ret);
1250 /* put some randomness into TPM.
1251 * Let's not trust it completely.
1253 tssret = Tspi_Context_GetTpmObject(s.tpm_ctx, &htpm);
1256 ret = tss_err(tssret);
1261 ret = _gnutls_rnd(GNUTLS_RND_RANDOM, buf, sizeof(buf));
1267 tssret = Tspi_TPM_StirRandom(htpm, sizeof(buf), buf);
1273 Tspi_Context_CreateObject(s.tpm_ctx, TSS_OBJECT_TYPE_RSAKEY,
1274 tpm_flags, &key_ctx);
1277 ret = tss_err(tssret);
1282 Tspi_SetAttribUint32(key_ctx, TSS_TSPATTRIB_KEY_INFO,
1283 TSS_TSPATTRIB_KEYINFO_SIGSCHEME,
1284 TSS_SS_RSASSAPKCS1V15_DER);
1287 ret = tss_err(tssret);
1291 /* set the password of the actual key */
1294 Tspi_GetPolicyObject(key_ctx, TSS_POLICY_USAGE,
1298 ret = tss_err(tssret);
1302 tssret = myTspi_Policy_SetSecret(key_policy,
1303 SAFE_LEN(key_password),
1304 (void *) key_password);
1307 ret = tss_err(tssret);
1312 tssret = Tspi_Key_CreateKey(key_ctx, s.srk, 0);
1315 ret = tss_err(tssret);
1319 if (flags & GNUTLS_TPM_REGISTER_KEY) {
1322 ret = randomize_uuid(&key_uuid);
1329 Tspi_Context_RegisterKey(s.tpm_ctx, key_ctx,
1330 storage_type, key_uuid,
1331 TSS_PS_TYPE_SYSTEM, srk_uuid);
1334 ret = tss_err(tssret);
1339 encode_tpmkey_url((char **) &privkey->data, &key_uuid,
1344 Tspi_Context_UnregisterKey(s.tpm_ctx, storage_type,
1349 privkey->size = strlen((char *) privkey->data);
1351 } else { /* get the key as blob */
1355 Tspi_GetAttribData(key_ctx, TSS_TSPATTRIB_KEY_BLOB,
1356 TSS_TSPATTRIB_KEYBLOB_BLOB, &tint,
1360 ret = tss_err(tssret);
1365 if (format == GNUTLS_TPMKEY_FMT_CTK_PEM) {
1367 _gnutls_x509_encode_string
1368 (ASN1_ETYPE_OCTET_STRING, tdata, tint,
1376 _gnutls_fbase64_encode("TSS KEY BLOB",
1378 tmpkey.size, privkey);
1386 tmpkey.size = tint + 32; /* spec says no more than 20 */
1387 tmpkey.data = gnutls_malloc(tmpkey.size);
1388 if (tmpkey.data == NULL) {
1390 ret = GNUTLS_E_MEMORY_ERROR;
1394 tint2 = tmpkey.size;
1396 Tspi_EncodeDER_TssBlob(tint, tdata,
1397 TSS_BLOB_TYPE_PRIVATEKEY,
1398 &tint2, tmpkey.data);
1401 ret = tss_err(tssret);
1405 tmpkey.size = tint2;
1407 privkey->data = tmpkey.data;
1408 privkey->size = tmpkey.size;
1413 /* read the public key */
1414 if (pubkey != NULL) {
1417 ret = gnutls_pubkey_init(&pub);
1420 goto privkey_cleanup;
1423 ret = read_pubkey(pub, key_ctx, &psize);
1426 goto privkey_cleanup;
1430 pubkey->data = gnutls_malloc(psize);
1431 if (pubkey->data == NULL) {
1433 ret = GNUTLS_E_MEMORY_ERROR;
1434 goto pubkey_cleanup;
1438 gnutls_pubkey_export(pub, pub_format, pubkey->data,
1442 goto pubkey_cleanup;
1444 pubkey->size = psize;
1446 gnutls_pubkey_deinit(pub);
1453 gnutls_pubkey_deinit(pub);
1455 gnutls_free(privkey->data);
1456 privkey->data = NULL;
1458 gnutls_free(tmpkey.data);
1461 Tspi_Context_CloseObject(s.tpm_ctx, key_ctx);
1463 tpm_close_session(&s);
1469 * gnutls_tpm_key_list_deinit:
1470 * @list: a list of the keys
1472 * This function will deinitialize the list of stored keys in the TPM.
1476 void gnutls_tpm_key_list_deinit(gnutls_tpm_key_list_t list)
1478 if (list->tpm_ctx != 0)
1479 Tspi_Context_Close(list->tpm_ctx);
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
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
1495 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1496 * negative error value.
1501 gnutls_tpm_key_list_get_url(gnutls_tpm_key_list_t list, unsigned int idx,
1502 char **url, unsigned int flags)
1504 if (idx >= list->size)
1507 (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
1509 return encode_tpmkey_url(url, &list->ki[idx].keyUUID,
1510 list->ki[idx].persistentStorageType);
1514 * gnutls_tpm_get_registered:
1515 * @list: a list to store the keys
1517 * This function will get a list of stored keys in the TPM. The uuid
1520 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1521 * negative error value.
1525 int gnutls_tpm_get_registered(gnutls_tpm_key_list_t * list)
1530 *list = gnutls_calloc(1, sizeof(struct tpm_key_list_st));
1532 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
1534 tssret = Tspi_Context_Create(&(*list)->tpm_ctx);
1537 ret = tss_err(tssret);
1541 tssret = Tspi_Context_Connect((*list)->tpm_ctx, NULL);
1544 ret = tss_err(tssret);
1549 Tspi_Context_GetRegisteredKeysByUUID2((*list)->tpm_ctx,
1550 TSS_PS_TYPE_SYSTEM, NULL,
1555 ret = tss_err(tssret);
1561 gnutls_tpm_key_list_deinit(*list);
1567 * gnutls_tpm_privkey_delete:
1568 * @url: the URL describing the key
1569 * @srk_password: a password for the SRK key
1571 * This function will unregister the private key from the TPM
1574 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1575 * negative error value.
1579 int gnutls_tpm_privkey_delete(const char *url, const char *srk_password)
1581 struct tpm_ctx_st s;
1582 struct tpmkey_url_st durl;
1587 ret = decode_tpmkey_url(url, &durl);
1589 return gnutls_assert_val(ret);
1591 if (durl.uuid_set == 0)
1592 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
1594 ret = tpm_open_session(&s, srk_password);
1596 return gnutls_assert_val(ret);
1599 Tspi_Context_UnregisterKey(s.tpm_ctx, durl.storage, durl.uuid,
1603 ret = tss_err(tssret);
1609 tpm_close_session(&s);
1612 #else /* HAVE_TROUSERS */
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)
1620 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
1624 gnutls_privkey_import_tpm_url(gnutls_privkey_t pkey,
1626 const char *srk_password,
1627 const char *key_password, unsigned int flags)
1629 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
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)
1638 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
1642 gnutls_pubkey_import_tpm_url(gnutls_pubkey_t pkey,
1644 const char *srk_password, unsigned int flags)
1646 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
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)
1658 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
1661 void gnutls_tpm_key_list_deinit(gnutls_tpm_key_list_t list)
1667 gnutls_tpm_key_list_get_url(gnutls_tpm_key_list_t list, unsigned int idx,
1668 char **url, unsigned int flags)
1670 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
1673 int gnutls_tpm_get_registered(gnutls_tpm_key_list_t * list)
1675 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
1678 int gnutls_tpm_privkey_delete(const char *url, const char *srk_password)
1680 return GNUTLS_E_UNIMPLEMENTED_FEATURE;
1682 #endif /* HAVE_TROUSERS */