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 3 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
30 #include <gnutls/gnutls.h>
31 #include <gnutls/abstract.h>
32 #include <gnutls/tpm.h>
34 #include <gnutls_int.h>
35 #include <gnutls_errors.h>
36 #include <pkcs11_int.h>
37 #include <x509/common.h>
42 #include <trousers/tss.h>
43 #include <trousers/trousers.h>
49 TSS_HPOLICY tpm_key_policy
;
51 TSS_HPOLICY srk_policy
;
54 struct tpm_key_list_st
61 static void tpm_close_session(struct tpm_ctx_st
*s
);
62 static int import_tpm_key (gnutls_privkey_t pkey
,
63 const gnutls_datum_t
* fdata
,
64 gnutls_tpmkey_fmt_t format
,
66 TSS_FLAG storage_type
,
67 const char *srk_password
,
68 const char *key_password
);
69 static int encode_tpmkey_url(char** url
, const TSS_UUID
* uuid
, TSS_FLAG storage
);
73 * tpmkey:file=/path/to/file
74 * tpmkey:uuid=7f468c16-cb7f-11e1-824d-b3a4f4b20343;storage=user
75 * tpmkey:uuid=7f468c16-cb7f-11e1-824d-b3a4f4b20343;storage=system
80 static int tss_err_pwd(TSS_RESULT err
, int pwd_error
)
82 _gnutls_debug_log("TPM (%s) error: %s (%x)\n", Trspi_Error_Layer(err
), Trspi_Error_String(err
), (unsigned int)Trspi_Error_Code(err
));
84 switch(ERROR_LAYER(err
))
87 switch(ERROR_CODE(err
))
92 return GNUTLS_E_TPM_UNINITIALIZED
;
94 return gnutls_assert_val(GNUTLS_E_TPM_ERROR
);
98 switch(ERROR_CODE(err
))
100 case TSS_E_COMM_FAILURE
:
101 case TSS_E_NO_CONNECTION
:
102 case TSS_E_CONNECTION_FAILED
:
103 case TSS_E_CONNECTION_BROKEN
:
104 return GNUTLS_E_TPM_SESSION_ERROR
;
105 case TSS_E_PS_KEY_NOTFOUND
:
106 return GNUTLS_E_TPM_KEY_NOT_FOUND
;
108 return gnutls_assert_val(GNUTLS_E_TPM_ERROR
);
111 return gnutls_assert_val(GNUTLS_E_TPM_ERROR
);
115 #define tss_err(x) tss_err_pwd(x, GNUTLS_E_TPM_SRK_PASSWORD_ERROR)
116 #define tss_err_key(x) tss_err_pwd(x, GNUTLS_E_TPM_KEY_PASSWORD_ERROR)
119 tpm_deinit_fn (gnutls_privkey_t key
, void *_s
)
121 struct tpm_ctx_st
*s
= _s
;
123 Tspi_Context_CloseObject (s
->tpm_ctx
, s
->tpm_key_policy
);
124 Tspi_Context_CloseObject (s
->tpm_ctx
, s
->tpm_key
);
126 tpm_close_session(s
);
131 tpm_sign_fn (gnutls_privkey_t key
, void *_s
,
132 const gnutls_datum_t
* data
, gnutls_datum_t
* sig
)
134 struct tpm_ctx_st
*s
= _s
;
138 _gnutls_debug_log ("TPM sign function called for %u bytes.\n",
142 Tspi_Context_CreateObject (s
->tpm_ctx
,
143 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 _gnutls_debug_log ("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
);
165 if (s
->tpm_key_policy
|| err
!= TPM_E_AUTHFAIL
)
166 _gnutls_debug_log ("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};
178 const TSS_UUID srk_uuid
= TSS_UUID_SRK
;
180 static int tpm_pin(struct pin_info_st
* pin_info
, const TSS_UUID
* uuid
, TSS_FLAG storage
,
181 char* pin
, unsigned int pin_size
, unsigned int attempts
)
183 unsigned int flags
= 0;
189 flags
|= GNUTLS_PIN_WRONG
;
193 if (memcmp(uuid
, &srk_uuid
, sizeof(TSS_UUID
)) == 0)
197 ret
= encode_tpmkey_url(&url
, uuid
, storage
);
199 return gnutls_assert_val(ret
);
207 if (pin_info
&& pin_info
->cb
)
208 ret
= pin_info
->cb(pin_info
->data
, attempts
, "TPM", label
, flags
, pin
, pin_size
);
209 else if (_gnutls_pin_func
)
210 ret
= _gnutls_pin_func(_gnutls_pin_data
, attempts
, "TPM", label
, flags
, pin
, pin_size
);
212 ret
= gnutls_assert_val(GNUTLS_E_TPM_KEY_PASSWORD_ERROR
); /* doesn't really matter */
227 static TSS_RESULT
myTspi_Policy_SetSecret(TSS_HPOLICY hPolicy
,
228 UINT32 ulSecretLength
, BYTE
* rgbSecret
)
230 if (rgbSecret
== NULL
)
232 /* Well known NULL key */
233 return Tspi_Policy_SetSecret (hPolicy
,
234 TSS_SECRET_MODE_SHA1
,
235 sizeof (nullpass
), (BYTE
*) nullpass
);
237 else /* key is given */
239 return Tspi_Policy_SetSecret (hPolicy
, TSS_SECRET_MODE_PLAIN
,
240 ulSecretLength
, rgbSecret
);
244 #define SAFE_LEN(x) (x==NULL?0:strlen(x))
246 static int tpm_open_session(struct tpm_ctx_st
*s
, const char* srk_password
)
250 err
= Tspi_Context_Create (&s
->tpm_ctx
);
257 err
= Tspi_Context_Connect (s
->tpm_ctx
, NULL
);
266 Tspi_Context_LoadKeyByUUID (s
->tpm_ctx
, TSS_PS_TYPE_SYSTEM
,
275 err
= Tspi_GetPolicyObject (s
->srk
, TSS_POLICY_USAGE
, &s
->srk_policy
);
283 err
= myTspi_Policy_SetSecret (s
->srk_policy
,
284 SAFE_LEN (srk_password
), (BYTE
*) srk_password
);
295 Tspi_Context_CloseObject (s
->tpm_ctx
, s
->srk_policy
);
298 Tspi_Context_CloseObject (s
->tpm_ctx
, s
->srk
);
301 Tspi_Context_Close (s
->tpm_ctx
);
307 static void tpm_close_session(struct tpm_ctx_st
*s
)
309 Tspi_Context_CloseObject (s
->tpm_ctx
, s
->srk_policy
);
311 Tspi_Context_CloseObject (s
->tpm_ctx
, s
->srk
);
313 Tspi_Context_Close (s
->tpm_ctx
);
318 import_tpm_key_cb (gnutls_privkey_t pkey
, const gnutls_datum_t
* fdata
,
319 gnutls_tpmkey_fmt_t format
, TSS_UUID
*uuid
,
320 TSS_FLAG storage
, const char *srk_password
,
321 const char *key_password
)
323 unsigned int attempts
= 0;
324 char pin1
[GNUTLS_PKCS11_MAX_PIN_LEN
];
325 char pin2
[GNUTLS_PKCS11_MAX_PIN_LEN
];
330 ret
= import_tpm_key(pkey
, fdata
, format
, uuid
, storage
, srk_password
, key_password
);
335 if (ret
== GNUTLS_E_TPM_SRK_PASSWORD_ERROR
)
337 ret2
= tpm_pin(&pkey
->pin
, &srk_uuid
, storage
, pin1
, sizeof(pin1
), attempts
++);
341 return GNUTLS_E_TPM_SRK_PASSWORD_ERROR
;
346 if (ret
== GNUTLS_E_TPM_KEY_PASSWORD_ERROR
)
348 ret2
= tpm_pin(&pkey
->pin
, uuid
, storage
, pin2
, sizeof(pin2
), attempts
++);
352 return GNUTLS_E_TPM_KEY_PASSWORD_ERROR
;
357 while(ret
== GNUTLS_E_TPM_KEY_PASSWORD_ERROR
|| ret
== GNUTLS_E_TPM_SRK_PASSWORD_ERROR
);
364 static int load_key(TSS_HCONTEXT tpm_ctx
, TSS_HKEY srk
,
365 const gnutls_datum_t
* fdata
, gnutls_tpmkey_fmt_t format
,
369 gnutls_datum_t asn1
= { NULL
, 0 };
372 if (format
== GNUTLS_TPMKEY_FMT_CTK_PEM
)
374 ret
= gnutls_pem_base64_decode_alloc ("TSS KEY BLOB", fdata
, &asn1
);
378 _gnutls_debug_log ("Error decoding TSS key blob: %s\n",
379 gnutls_strerror (ret
));
384 ret
= _gnutls_x509_decode_octet_string(NULL
, asn1
.data
, asn1
.size
, asn1
.data
, &slen
);
397 asn1
.size
= fdata
->size
;
398 asn1
.data
= gnutls_malloc(asn1
.size
);
399 if (asn1
.data
== NULL
)
402 return GNUTLS_E_MEMORY_ERROR
;
406 err
= Tspi_DecodeBER_TssBlob(fdata
->size
, fdata
->data
, &type
,
418 /* ... we get it here instead. */
419 err
= Tspi_Context_LoadKeyByBlob (tpm_ctx
, srk
,
420 asn1
.size
, asn1
.data
, tpm_key
);
431 gnutls_free (asn1
.data
);
438 import_tpm_key (gnutls_privkey_t pkey
,
439 const gnutls_datum_t
* fdata
,
440 gnutls_tpmkey_fmt_t format
,
443 const char *srk_password
,
444 const char *key_password
)
447 struct tpm_ctx_st
*s
;
448 gnutls_datum_t tmp_sig
;
450 s
= gnutls_malloc (sizeof (*s
));
454 return GNUTLS_E_MEMORY_ERROR
;
457 ret
= tpm_open_session(s
, srk_password
);
466 ret
= load_key(s
->tpm_ctx
, s
->srk
, fdata
, format
, &s
->tpm_key
);
476 Tspi_Context_LoadKeyByUUID (s
->tpm_ctx
, storage
,
489 ret
= GNUTLS_E_INVALID_REQUEST
;
494 gnutls_privkey_import_ext2 (pkey
, GNUTLS_PK_RSA
, s
,
495 tpm_sign_fn
, NULL
, tpm_deinit_fn
, 0);
503 gnutls_privkey_sign_data (pkey
, GNUTLS_DIG_SHA1
, 0, &nulldata
, &tmp_sig
);
504 if (ret
== GNUTLS_E_TPM_KEY_PASSWORD_ERROR
)
506 if (!s
->tpm_key_policy
)
508 err
= Tspi_Context_CreateObject (s
->tpm_ctx
,
509 TSS_OBJECT_TYPE_POLICY
,
519 err
= Tspi_Policy_AssignToObject (s
->tpm_key_policy
, s
->tpm_key
);
528 err
= myTspi_Policy_SetSecret (s
->tpm_key_policy
,
529 SAFE_LEN(key_password
), (void *) key_password
);
534 ret
= tss_err_key(err
);
546 Tspi_Context_CloseObject (s
->tpm_ctx
, s
->tpm_key_policy
);
547 s
->tpm_key_policy
= 0;
549 Tspi_Context_CloseObject (s
->tpm_ctx
, s
->tpm_key
);
552 tpm_close_session(s
);
559 * gnutls_privkey_import_tpm_raw:
560 * @pkey: The private key
561 * @fdata: The TPM key to be imported
562 * @format: The format of the private key
563 * @srk_password: The password for the SRK key (optional)
564 * @key_password: A password for the key (optional)
565 * @flags: should be zero
567 * This function will import the given private key to the abstract
568 * #gnutls_privkey_t structure.
570 * With respect to passwords the same as in gnutls_privkey_import_tpm_url() apply.
572 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
573 * negative error value.
579 gnutls_privkey_import_tpm_raw (gnutls_privkey_t pkey
,
580 const gnutls_datum_t
* fdata
,
581 gnutls_tpmkey_fmt_t format
,
582 const char *srk_password
,
583 const char *key_password
,
586 if (flags
& GNUTLS_PRIVKEY_DISABLE_CALLBACKS
)
587 return import_tpm_key(pkey
, fdata
, format
, NULL
, 0, srk_password
, key_password
);
589 return import_tpm_key_cb(pkey
, fdata
, format
, NULL
, 0, srk_password
, key_password
);
597 unsigned int uuid_set
;
600 static void clear_tpmkey_url(struct tpmkey_url_st
*s
)
602 gnutls_free(s
->filename
);
603 memset(s
, 0, sizeof(*s
));
607 unescape_string (char *output
, const char *input
, size_t * size
,
610 gnutls_buffer_st str
;
615 _gnutls_buffer_init (&str
);
617 /* find terminator */
618 p
= strchr (input
, terminator
);
622 len
= strlen (input
);
624 ret
= _gnutls_buffer_append_data (&str
, input
, len
);
631 ret
= _gnutls_buffer_unescape (&str
);
638 ret
= _gnutls_buffer_append_data (&str
, "", 1);
645 _gnutls_buffer_pop_data (&str
, output
, size
);
647 _gnutls_buffer_clear (&str
);
654 static int randomize_uuid(TSS_UUID
* uuid
)
656 uint8_t raw_uuid
[16];
659 ret
= _gnutls_rnd (GNUTLS_RND_NONCE
, raw_uuid
, sizeof(raw_uuid
));
661 return gnutls_assert_val(ret
);
663 /* mark it as random uuid */
669 memcpy(&uuid
->ulTimeLow
, raw_uuid
, 4);
670 memcpy(&uuid
->usTimeMid
, &raw_uuid
[4], 2);
671 memcpy(&uuid
->usTimeHigh
, &raw_uuid
[6], 2);
672 uuid
->bClockSeqHigh
= raw_uuid
[8];
673 uuid
->bClockSeqLow
= raw_uuid
[9];
674 memcpy(&uuid
->rgbNode
, &raw_uuid
[10], 6);
679 static int encode_tpmkey_url(char** url
, const TSS_UUID
* uuid
, TSS_FLAG storage
)
681 size_t size
= (UUID_SIZE
*2+4)*2+32;
682 uint8_t u1
[UUID_SIZE
];
683 gnutls_buffer_st buf
;
687 *url
= gnutls_malloc(size
);
689 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR
);
691 _gnutls_buffer_init(&buf
);
693 memcpy(u1
, &uuid
->ulTimeLow
, 4);
694 memcpy(&u1
[4], &uuid
->usTimeMid
, 2);
695 memcpy(&u1
[6], &uuid
->usTimeHigh
, 2);
696 u1
[8] = uuid
->bClockSeqHigh
;
697 u1
[9] = uuid
->bClockSeqLow
;
698 memcpy(&u1
[10], uuid
->rgbNode
, 6);
700 ret
= _gnutls_buffer_append_str(&buf
, "tpmkey:uuid=");
707 ret
= _gnutls_buffer_append_printf(&buf
, "%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x",
708 (unsigned int)u1
[0], (unsigned int)u1
[1], (unsigned int)u1
[2], (unsigned int)u1
[3],
709 (unsigned int)u1
[4], (unsigned int)u1
[5], (unsigned int)u1
[6], (unsigned int)u1
[7],
710 (unsigned int)u1
[8], (unsigned int)u1
[9], (unsigned int)u1
[10], (unsigned int)u1
[11],
711 (unsigned int)u1
[12], (unsigned int)u1
[13], (unsigned int)u1
[14], (unsigned int)u1
[15]);
718 ret
= _gnutls_buffer_append_printf(&buf
, ";storage=%s", (storage
==TSS_PS_TYPE_USER
)?"user":"system");
725 ret
= _gnutls_buffer_to_datum(&buf
, &dret
);
732 *url
= (char*)dret
.data
;
736 _gnutls_buffer_clear(&buf
);
740 static int decode_tpmkey_url(const char* url
, struct tpmkey_url_st
*s
)
747 if (strstr (url
, "tpmkey:") == NULL
)
748 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR
);
750 memset(s
, 0, sizeof(*s
));
752 p
= strstr(url
, "file=");
755 p
+= sizeof ("file=") - 1;
757 s
->filename
= gnutls_malloc(size
+1);
758 if (s
->filename
== NULL
)
759 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR
);
761 ret
= unescape_string (s
->filename
, p
, &size
, ';');
767 s
->filename
[size
] = 0;
769 else if ((p
= strstr(url
, "uuid=")) != NULL
)
772 uint8_t raw_uuid
[16];
774 p
+= sizeof ("uuid=") - 1;
777 for (j
=i
=0;i
<size
;i
++)
779 if (j
==sizeof(tmp_uuid
)-1)
783 if (isalnum(p
[i
])) tmp_uuid
[j
++]=p
[i
];
787 size
= sizeof(raw_uuid
);
788 ret
= _gnutls_hex2bin(tmp_uuid
, strlen(tmp_uuid
), raw_uuid
, &size
);
795 memcpy(&s
->uuid
.ulTimeLow
, raw_uuid
, 4);
796 memcpy(&s
->uuid
.usTimeMid
, &raw_uuid
[4], 2);
797 memcpy(&s
->uuid
.usTimeHigh
, &raw_uuid
[6], 2);
798 s
->uuid
.bClockSeqHigh
= raw_uuid
[8];
799 s
->uuid
.bClockSeqLow
= raw_uuid
[9];
800 memcpy(&s
->uuid
.rgbNode
, &raw_uuid
[10], 6);
805 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR
);
808 if ((p
= strstr(url
, "storage=user")) != NULL
)
809 s
->storage
= TSS_PS_TYPE_USER
;
811 s
->storage
= TSS_PS_TYPE_SYSTEM
;
821 * gnutls_privkey_import_tpm_url:
822 * @pkey: The private key
823 * @url: The URL of the TPM key to be imported
824 * @srk_password: The password for the SRK key (optional)
825 * @key_password: A password for the key (optional)
826 * @flags: One of the GNUTLS_PRIVKEY_* flags
828 * This function will import the given private key to the abstract
829 * #gnutls_privkey_t structure.
831 * Note that unless %GNUTLS_PRIVKEY_DISABLE_CALLBACKS
832 * is specified, if incorrect (or NULL) passwords are given
833 * the PKCS11 callback functions will be used to obtain the
834 * correct passwords. Otherwise if the SRK password is wrong
835 * %GNUTLS_E_TPM_SRK_PASSWORD_ERROR is returned and if the key password
836 * is wrong or not provided then %GNUTLS_E_TPM_KEY_PASSWORD_ERROR
839 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
840 * negative error value.
846 gnutls_privkey_import_tpm_url (gnutls_privkey_t pkey
,
848 const char *srk_password
,
849 const char *key_password
,
852 struct tpmkey_url_st durl
;
853 gnutls_datum_t fdata
= { NULL
, 0 };
856 ret
= decode_tpmkey_url(url
, &durl
);
858 return gnutls_assert_val(ret
);
862 ret
= gnutls_load_file(durl
.filename
, &fdata
);
866 _gnutls_debug_log("Error loading %s\n", durl
.filename
);
870 ret
= gnutls_privkey_import_tpm_raw (pkey
, &fdata
, GNUTLS_TPMKEY_FMT_CTK_PEM
,
871 srk_password
, key_password
, flags
);
872 if (ret
== GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR
)
873 ret
= gnutls_privkey_import_tpm_raw (pkey
, &fdata
, GNUTLS_TPMKEY_FMT_DER
,
874 srk_password
, key_password
, flags
);
882 else if (durl
.uuid_set
)
884 if (flags
& GNUTLS_PRIVKEY_DISABLE_CALLBACKS
)
885 ret
= import_tpm_key (pkey
, NULL
, 0, &durl
.uuid
, durl
.storage
, srk_password
, key_password
);
887 ret
= import_tpm_key_cb (pkey
, NULL
, 0, &durl
.uuid
, durl
.storage
, srk_password
, key_password
);
897 gnutls_free(fdata
.data
);
898 clear_tpmkey_url(&durl
);
903 /* reads the RSA public key from the given TSS key.
904 * If psize is non-null it contains the total size of the parameters
906 static int read_pubkey(gnutls_pubkey_t pub
, TSS_HKEY key_ctx
, size_t *psize
)
914 /* read the public key */
916 tssret
= Tspi_GetAttribData(key_ctx
, TSS_TSPATTRIB_RSAKEY_INFO
,
917 TSS_TSPATTRIB_KEYINFO_RSA_MODULUS
, &tint
, (void*)&tdata
);
921 return tss_err(tssret
);
927 tssret
= Tspi_GetAttribData(key_ctx
, TSS_TSPATTRIB_RSAKEY_INFO
,
928 TSS_TSPATTRIB_KEYINFO_RSA_EXPONENT
, &tint
, (void*)&tdata
);
932 Tspi_Context_FreeMemory(key_ctx
, m
.data
);
933 return tss_err(tssret
);
939 ret
= gnutls_pubkey_import_rsa_raw(pub
, &m
, &e
);
941 Tspi_Context_FreeMemory(key_ctx
, m
.data
);
942 Tspi_Context_FreeMemory(key_ctx
, e
.data
);
945 return gnutls_assert_val(ret
);
948 *psize
= e
.size
+ m
.size
;
956 import_tpm_pubkey (gnutls_pubkey_t pkey
,
957 const gnutls_datum_t
* fdata
,
958 gnutls_tpmkey_fmt_t format
,
961 const char *srk_password
)
966 ret
= tpm_open_session(&s
, srk_password
);
968 return gnutls_assert_val(ret
);
972 ret
= load_key(s
.tpm_ctx
, s
.srk
, fdata
, format
, &s
.tpm_key
);
982 Tspi_Context_LoadKeyByUUID (s
.tpm_ctx
, storage
,
994 ret
= GNUTLS_E_INVALID_REQUEST
;
998 ret
= read_pubkey(pkey
, s
.tpm_key
, NULL
);
1007 tpm_close_session(&s
);
1012 import_tpm_pubkey_cb (gnutls_pubkey_t pkey
,
1013 const gnutls_datum_t
* fdata
,
1014 gnutls_tpmkey_fmt_t format
,
1017 const char *srk_password
)
1019 unsigned int attempts
= 0;
1020 char pin1
[GNUTLS_PKCS11_MAX_PIN_LEN
];
1025 ret
= import_tpm_pubkey(pkey
, fdata
, format
, uuid
, storage
, srk_password
);
1030 if (ret
== GNUTLS_E_TPM_SRK_PASSWORD_ERROR
)
1032 ret
= tpm_pin(&pkey
->pin
, &srk_uuid
, storage
, pin1
, sizeof(pin1
), attempts
++);
1036 return GNUTLS_E_TPM_SRK_PASSWORD_ERROR
;
1038 srk_password
= pin1
;
1041 while(ret
== GNUTLS_E_TPM_SRK_PASSWORD_ERROR
);
1050 * gnutls_pubkey_import_tpm_raw:
1051 * @pkey: The public key
1052 * @fdata: The TPM key to be imported
1053 * @format: The format of the private key
1054 * @srk_password: The password for the SRK key (optional)
1055 * @flags: One of the GNUTLS_PUBKEY_* flags
1057 * This function will import the public key from the provided TPM key
1060 * With respect to passwords the same as in
1061 * gnutls_pubkey_import_tpm_url() apply.
1063 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1064 * negative error value.
1069 gnutls_pubkey_import_tpm_raw (gnutls_pubkey_t pkey
,
1070 const gnutls_datum_t
* fdata
,
1071 gnutls_tpmkey_fmt_t format
,
1072 const char *srk_password
,
1075 if (flags
& GNUTLS_PUBKEY_DISABLE_CALLBACKS
)
1076 return import_tpm_pubkey_cb(pkey
, fdata
, format
, NULL
, 0, srk_password
);
1078 return import_tpm_pubkey(pkey
, fdata
, format
, NULL
, 0, srk_password
);
1082 * gnutls_pubkey_import_tpm_url:
1083 * @pkey: The public key
1084 * @url: The URL of the TPM key to be imported
1085 * @srk_password: The password for the SRK key (optional)
1086 * @flags: should be zero
1088 * This function will import the given private key to the abstract
1089 * #gnutls_privkey_t structure.
1091 * Note that unless %GNUTLS_PUBKEY_DISABLE_CALLBACKS
1092 * is specified, if incorrect (or NULL) passwords are given
1093 * the PKCS11 callback functions will be used to obtain the
1094 * correct passwords. Otherwise if the SRK password is wrong
1095 * %GNUTLS_E_TPM_SRK_PASSWORD_ERROR is returned.
1097 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1098 * negative error value.
1104 gnutls_pubkey_import_tpm_url (gnutls_pubkey_t pkey
,
1106 const char *srk_password
,
1109 struct tpmkey_url_st durl
;
1110 gnutls_datum_t fdata
= { NULL
, 0 };
1113 ret
= decode_tpmkey_url(url
, &durl
);
1115 return gnutls_assert_val(ret
);
1120 ret
= gnutls_load_file(durl
.filename
, &fdata
);
1127 ret
= gnutls_pubkey_import_tpm_raw (pkey
, &fdata
, GNUTLS_TPMKEY_FMT_CTK_PEM
,
1128 srk_password
, flags
);
1129 if (ret
== GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR
)
1130 ret
= gnutls_pubkey_import_tpm_raw (pkey
, &fdata
, GNUTLS_TPMKEY_FMT_DER
,
1131 srk_password
, flags
);
1138 else if (durl
.uuid_set
)
1140 if (flags
& GNUTLS_PUBKEY_DISABLE_CALLBACKS
)
1141 ret
= import_tpm_pubkey (pkey
, NULL
, 0, &durl
.uuid
, durl
.storage
, srk_password
);
1143 ret
= import_tpm_pubkey_cb (pkey
, NULL
, 0, &durl
.uuid
, durl
.storage
, srk_password
);
1153 gnutls_free(fdata
.data
);
1154 clear_tpmkey_url(&durl
);
1160 * gnutls_tpm_privkey_generate:
1161 * @pk: the public key algorithm
1162 * @bits: the security bits
1163 * @srk_password: a password to protect the exported key (optional)
1164 * @key_password: the password for the TPM (optional)
1165 * @format: the format of the private key
1166 * @pub_format: the format of the public key
1167 * @privkey: the generated key
1168 * @pubkey: the corresponding public key (may be null)
1169 * @flags: should be a list of GNUTLS_TPM_* flags
1171 * This function will generate a private key in the TPM
1172 * chip. The private key will be generated within the chip
1173 * and will be exported in a wrapped with TPM's master key
1174 * form. Furthermore the wrapped key can be protected with
1175 * the provided @password.
1177 * Note that bits in TPM is quantized value. If the input value
1178 * is not one of the allowed values, then it will be quantized to
1179 * one of 512, 1024, 2048, 4096, 8192 and 16384.
1181 * Allowed flags are:
1183 * %GNUTLS_TPM_KEY_SIGNING: Generate a signing key instead of a legacy,
1185 * %GNUTLS_TPM_REGISTER_KEY: Register the generate key in TPM. In that
1186 * case @privkey would contain a URL with the UUID.
1188 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1189 * negative error value.
1194 gnutls_tpm_privkey_generate (gnutls_pk_algorithm_t pk
, unsigned int bits
,
1195 const char* srk_password
,
1196 const char* key_password
,
1197 gnutls_tpmkey_fmt_t format
,
1198 gnutls_x509_crt_fmt_t pub_format
,
1199 gnutls_datum_t
* privkey
,
1200 gnutls_datum_t
* pubkey
,
1203 TSS_FLAG tpm_flags
= TSS_KEY_VOLATILE
;
1209 gnutls_datum_t tmpkey
= {NULL
, 0};
1210 TSS_HPOLICY key_policy
;
1211 gnutls_pubkey_t pub
;
1212 struct tpm_ctx_st s
;
1213 TSS_FLAG storage_type
;
1217 if (flags
& GNUTLS_TPM_KEY_SIGNING
)
1218 tpm_flags
|= TSS_KEY_TYPE_SIGNING
;
1220 tpm_flags
|= TSS_KEY_TYPE_LEGACY
;
1222 if (flags
& GNUTLS_TPM_KEY_USER
)
1223 storage_type
= TSS_PS_TYPE_USER
;
1225 storage_type
= TSS_PS_TYPE_SYSTEM
;
1228 tpm_flags
|= TSS_KEY_SIZE_512
;
1229 else if (bits
<= 1024)
1230 tpm_flags
|= TSS_KEY_SIZE_1024
;
1231 else if (bits
<= 2048)
1232 tpm_flags
|= TSS_KEY_SIZE_2048
;
1233 else if (bits
<= 4096)
1234 tpm_flags
|= TSS_KEY_SIZE_4096
;
1235 else if (bits
<= 8192)
1236 tpm_flags
|= TSS_KEY_SIZE_8192
;
1238 tpm_flags
|= TSS_KEY_SIZE_16384
;
1240 ret
= tpm_open_session(&s
, srk_password
);
1242 return gnutls_assert_val(ret
);
1244 /* put some randomness into TPM.
1245 * Let's not trust it completely.
1247 tssret
= Tspi_Context_GetTpmObject(s
.tpm_ctx
, &htpm
);
1251 ret
= tss_err(tssret
);
1256 ret
= _gnutls_rnd(GNUTLS_RND_RANDOM
, buf
, sizeof(buf
));
1263 tssret
= Tspi_TPM_StirRandom(htpm
, sizeof(buf
), buf
);
1269 tssret
= Tspi_Context_CreateObject(s
.tpm_ctx
, TSS_OBJECT_TYPE_RSAKEY
, tpm_flags
, &key_ctx
);
1273 ret
= tss_err(tssret
);
1277 tssret
= Tspi_SetAttribUint32(key_ctx
, TSS_TSPATTRIB_KEY_INFO
, TSS_TSPATTRIB_KEYINFO_SIGSCHEME
,
1278 TSS_SS_RSASSAPKCS1V15_DER
);
1282 ret
= tss_err(tssret
);
1286 /* set the password of the actual key */
1289 tssret
= Tspi_GetPolicyObject(key_ctx
, TSS_POLICY_USAGE
, &key_policy
);
1293 ret
= tss_err(tssret
);
1297 tssret
= myTspi_Policy_SetSecret(key_policy
,
1298 SAFE_LEN(key_password
), (void*)key_password
);
1302 ret
= tss_err(tssret
);
1307 tssret
= Tspi_Key_CreateKey(key_ctx
, s
.srk
, 0);
1311 ret
= tss_err(tssret
);
1315 if (flags
& GNUTLS_TPM_REGISTER_KEY
)
1319 ret
= randomize_uuid(&key_uuid
);
1326 tssret
= Tspi_Context_RegisterKey(s
.tpm_ctx
, key_ctx
, storage_type
,
1327 key_uuid
, TSS_PS_TYPE_SYSTEM
, srk_uuid
);
1331 ret
= tss_err(tssret
);
1335 ret
= encode_tpmkey_url((char**)&privkey
->data
, &key_uuid
, storage_type
);
1340 Tspi_Context_UnregisterKey(s
.tpm_ctx
, storage_type
, key_uuid
, &tkey
);
1344 privkey
->size
= strlen((char*)privkey
->data
);
1347 else /* get the key as blob */
1350 tssret
= Tspi_GetAttribData(key_ctx
, TSS_TSPATTRIB_KEY_BLOB
,
1351 TSS_TSPATTRIB_KEYBLOB_BLOB
, &tint
, (void*)&tdata
);
1355 ret
= tss_err(tssret
);
1360 if (format
== GNUTLS_TPMKEY_FMT_CTK_PEM
)
1362 ret
= _gnutls_x509_encode_octet_string(tdata
, tint
, &tmpkey
);
1369 ret
= _gnutls_fbase64_encode ("TSS KEY BLOB", tmpkey
.data
, tmpkey
.size
, privkey
);
1380 tmpkey
.size
= tint
+ 32; /* spec says no more than 20 */
1381 tmpkey
.data
= gnutls_malloc(tmpkey
.size
);
1382 if (tmpkey
.data
== NULL
)
1385 ret
= GNUTLS_E_MEMORY_ERROR
;
1389 tint2
= tmpkey
.size
;
1390 tssret
= Tspi_EncodeDER_TssBlob(tint
, tdata
, TSS_BLOB_TYPE_PRIVATEKEY
,
1391 &tint2
, tmpkey
.data
);
1395 ret
= tss_err(tssret
);
1399 tmpkey
.size
= tint2
;
1401 privkey
->data
= tmpkey
.data
;
1402 privkey
->size
= tmpkey
.size
;
1407 /* read the public key */
1412 ret
= gnutls_pubkey_init(&pub
);
1416 goto privkey_cleanup
;
1419 ret
= read_pubkey(pub
, key_ctx
, &psize
);
1423 goto privkey_cleanup
;
1427 pubkey
->data
= gnutls_malloc(psize
);
1428 if (pubkey
->data
== NULL
)
1431 ret
= GNUTLS_E_MEMORY_ERROR
;
1432 goto pubkey_cleanup
;
1435 ret
= gnutls_pubkey_export(pub
, pub_format
, pubkey
->data
, &psize
);
1439 goto pubkey_cleanup
;
1441 pubkey
->size
= psize
;
1443 gnutls_pubkey_deinit(pub
);
1450 gnutls_pubkey_deinit(pub
);
1452 gnutls_free(privkey
->data
);
1453 privkey
->data
= NULL
;
1455 gnutls_free(tmpkey
.data
);
1458 Tspi_Context_CloseObject(s
.tpm_ctx
, key_ctx
);
1460 tpm_close_session(&s
);
1466 * gnutls_tpm_key_list_deinit:
1467 * @list: a list of the keys
1469 * This function will deinitialize the list of stored keys in the TPM.
1474 gnutls_tpm_key_list_deinit (gnutls_tpm_key_list_t list
)
1476 if (list
->tpm_ctx
!= 0) Tspi_Context_Close (list
->tpm_ctx
);
1481 * gnutls_tpm_key_list_get_url:
1482 * @list: a list of the keys
1483 * @idx: The index of the key (starting from zero)
1484 * @url: The URL to be returned
1485 * @flags: should be zero
1487 * This function will return for each given index a URL of
1488 * the corresponding key.
1489 * If the provided index is out of bounds then %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
1492 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1493 * negative error value.
1498 gnutls_tpm_key_list_get_url (gnutls_tpm_key_list_t list
, unsigned int idx
, char** url
, unsigned int flags
)
1500 if (idx
>= list
->size
)
1501 return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
);
1503 return encode_tpmkey_url(url
, &list
->ki
[idx
].keyUUID
, list
->ki
[idx
].persistentStorageType
);
1507 * gnutls_tpm_get_registered:
1508 * @list: a list to store the keys
1510 * This function will get a list of stored keys in the TPM. The uuid
1513 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1514 * negative error value.
1519 gnutls_tpm_get_registered (gnutls_tpm_key_list_t
*list
)
1524 *list
= gnutls_calloc(1, sizeof(struct tpm_key_list_st
));
1526 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR
);
1528 tssret
= Tspi_Context_Create (&(*list
)->tpm_ctx
);
1532 ret
= tss_err(tssret
);
1536 tssret
= Tspi_Context_Connect ((*list
)->tpm_ctx
, NULL
);
1540 ret
= tss_err(tssret
);
1545 Tspi_Context_GetRegisteredKeysByUUID2((*list
)->tpm_ctx
, TSS_PS_TYPE_SYSTEM
,
1546 NULL
, &(*list
)->size
, &(*list
)->ki
);
1550 ret
= tss_err(tssret
);
1556 gnutls_tpm_key_list_deinit(*list
);
1562 * gnutls_tpm_privkey_delete:
1563 * @url: the URL describing the key
1564 * @srk_password: a password for the SRK key
1566 * This function will unregister the private key from the TPM
1569 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1570 * negative error value.
1575 gnutls_tpm_privkey_delete (const char* url
, const char* srk_password
)
1577 struct tpm_ctx_st s
;
1578 struct tpmkey_url_st durl
;
1583 ret
= decode_tpmkey_url(url
, &durl
);
1585 return gnutls_assert_val(ret
);
1587 if (durl
.uuid_set
== 0)
1588 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
1590 ret
= tpm_open_session(&s
, srk_password
);
1592 return gnutls_assert_val(ret
);
1594 tssret
= Tspi_Context_UnregisterKey(s
.tpm_ctx
, durl
.storage
, durl
.uuid
, &tkey
);
1598 ret
= tss_err(tssret
);
1604 tpm_close_session(&s
);