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 };
371 if (format
== GNUTLS_TPMKEY_FMT_CTK_PEM
)
375 ret
= gnutls_pem_base64_decode_alloc ("TSS KEY BLOB", fdata
, &asn1
);
379 _gnutls_debug_log ("Error decoding TSS key blob: %s\n",
380 gnutls_strerror (ret
));
384 ret
= _gnutls_x509_decode_string(NULL
, asn1
.data
, asn1
.size
, &td
);
390 gnutls_free(asn1
.data
);
399 asn1
.size
= fdata
->size
;
400 asn1
.data
= gnutls_malloc(asn1
.size
);
401 if (asn1
.data
== NULL
)
404 return GNUTLS_E_MEMORY_ERROR
;
408 err
= Tspi_DecodeBER_TssBlob(fdata
->size
, fdata
->data
, &type
,
420 /* ... we get it here instead. */
421 err
= Tspi_Context_LoadKeyByBlob (tpm_ctx
, srk
,
422 asn1
.size
, asn1
.data
, tpm_key
);
433 gnutls_free (asn1
.data
);
440 import_tpm_key (gnutls_privkey_t pkey
,
441 const gnutls_datum_t
* fdata
,
442 gnutls_tpmkey_fmt_t format
,
445 const char *srk_password
,
446 const char *key_password
)
449 struct tpm_ctx_st
*s
;
450 gnutls_datum_t tmp_sig
;
452 s
= gnutls_malloc (sizeof (*s
));
456 return GNUTLS_E_MEMORY_ERROR
;
459 ret
= tpm_open_session(s
, srk_password
);
468 ret
= load_key(s
->tpm_ctx
, s
->srk
, fdata
, format
, &s
->tpm_key
);
478 Tspi_Context_LoadKeyByUUID (s
->tpm_ctx
, storage
,
491 ret
= GNUTLS_E_INVALID_REQUEST
;
496 gnutls_privkey_import_ext2 (pkey
, GNUTLS_PK_RSA
, s
,
497 tpm_sign_fn
, NULL
, tpm_deinit_fn
, 0);
505 gnutls_privkey_sign_data (pkey
, GNUTLS_DIG_SHA1
, 0, &nulldata
, &tmp_sig
);
506 if (ret
== GNUTLS_E_TPM_KEY_PASSWORD_ERROR
)
508 if (!s
->tpm_key_policy
)
510 err
= Tspi_Context_CreateObject (s
->tpm_ctx
,
511 TSS_OBJECT_TYPE_POLICY
,
521 err
= Tspi_Policy_AssignToObject (s
->tpm_key_policy
, s
->tpm_key
);
530 err
= myTspi_Policy_SetSecret (s
->tpm_key_policy
,
531 SAFE_LEN(key_password
), (void *) key_password
);
536 ret
= tss_err_key(err
);
548 Tspi_Context_CloseObject (s
->tpm_ctx
, s
->tpm_key_policy
);
549 s
->tpm_key_policy
= 0;
551 Tspi_Context_CloseObject (s
->tpm_ctx
, s
->tpm_key
);
554 tpm_close_session(s
);
561 * gnutls_privkey_import_tpm_raw:
562 * @pkey: The private key
563 * @fdata: The TPM key to be imported
564 * @format: The format of the private key
565 * @srk_password: The password for the SRK key (optional)
566 * @key_password: A password for the key (optional)
567 * @flags: should be zero
569 * This function will import the given private key to the abstract
570 * #gnutls_privkey_t structure.
572 * With respect to passwords the same as in gnutls_privkey_import_tpm_url() apply.
574 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
575 * negative error value.
581 gnutls_privkey_import_tpm_raw (gnutls_privkey_t pkey
,
582 const gnutls_datum_t
* fdata
,
583 gnutls_tpmkey_fmt_t format
,
584 const char *srk_password
,
585 const char *key_password
,
588 if (flags
& GNUTLS_PRIVKEY_DISABLE_CALLBACKS
)
589 return import_tpm_key(pkey
, fdata
, format
, NULL
, 0, srk_password
, key_password
);
591 return import_tpm_key_cb(pkey
, fdata
, format
, NULL
, 0, srk_password
, key_password
);
599 unsigned int uuid_set
;
602 static void clear_tpmkey_url(struct tpmkey_url_st
*s
)
604 gnutls_free(s
->filename
);
605 memset(s
, 0, sizeof(*s
));
609 unescape_string (char *output
, const char *input
, size_t * size
,
612 gnutls_buffer_st str
;
617 _gnutls_buffer_init (&str
);
619 /* find terminator */
620 p
= strchr (input
, terminator
);
624 len
= strlen (input
);
626 ret
= _gnutls_buffer_append_data (&str
, input
, len
);
633 ret
= _gnutls_buffer_unescape (&str
);
640 ret
= _gnutls_buffer_append_data (&str
, "", 1);
647 _gnutls_buffer_pop_data (&str
, output
, size
);
649 _gnutls_buffer_clear (&str
);
656 static int randomize_uuid(TSS_UUID
* uuid
)
658 uint8_t raw_uuid
[16];
661 ret
= _gnutls_rnd (GNUTLS_RND_NONCE
, raw_uuid
, sizeof(raw_uuid
));
663 return gnutls_assert_val(ret
);
665 /* mark it as random uuid */
671 memcpy(&uuid
->ulTimeLow
, raw_uuid
, 4);
672 memcpy(&uuid
->usTimeMid
, &raw_uuid
[4], 2);
673 memcpy(&uuid
->usTimeHigh
, &raw_uuid
[6], 2);
674 uuid
->bClockSeqHigh
= raw_uuid
[8];
675 uuid
->bClockSeqLow
= raw_uuid
[9];
676 memcpy(&uuid
->rgbNode
, &raw_uuid
[10], 6);
681 static int encode_tpmkey_url(char** url
, const TSS_UUID
* uuid
, TSS_FLAG storage
)
683 size_t size
= (UUID_SIZE
*2+4)*2+32;
684 uint8_t u1
[UUID_SIZE
];
685 gnutls_buffer_st buf
;
689 *url
= gnutls_malloc(size
);
691 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR
);
693 _gnutls_buffer_init(&buf
);
695 memcpy(u1
, &uuid
->ulTimeLow
, 4);
696 memcpy(&u1
[4], &uuid
->usTimeMid
, 2);
697 memcpy(&u1
[6], &uuid
->usTimeHigh
, 2);
698 u1
[8] = uuid
->bClockSeqHigh
;
699 u1
[9] = uuid
->bClockSeqLow
;
700 memcpy(&u1
[10], uuid
->rgbNode
, 6);
702 ret
= _gnutls_buffer_append_str(&buf
, "tpmkey:uuid=");
709 ret
= _gnutls_buffer_append_printf(&buf
, "%.2x%.2x%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x",
710 (unsigned int)u1
[0], (unsigned int)u1
[1], (unsigned int)u1
[2], (unsigned int)u1
[3],
711 (unsigned int)u1
[4], (unsigned int)u1
[5], (unsigned int)u1
[6], (unsigned int)u1
[7],
712 (unsigned int)u1
[8], (unsigned int)u1
[9], (unsigned int)u1
[10], (unsigned int)u1
[11],
713 (unsigned int)u1
[12], (unsigned int)u1
[13], (unsigned int)u1
[14], (unsigned int)u1
[15]);
720 ret
= _gnutls_buffer_append_printf(&buf
, ";storage=%s", (storage
==TSS_PS_TYPE_USER
)?"user":"system");
727 ret
= _gnutls_buffer_to_datum(&buf
, &dret
);
734 *url
= (char*)dret
.data
;
738 _gnutls_buffer_clear(&buf
);
742 static int decode_tpmkey_url(const char* url
, struct tpmkey_url_st
*s
)
749 if (strstr (url
, "tpmkey:") == NULL
)
750 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR
);
752 memset(s
, 0, sizeof(*s
));
754 p
= strstr(url
, "file=");
757 p
+= sizeof ("file=") - 1;
759 s
->filename
= gnutls_malloc(size
+1);
760 if (s
->filename
== NULL
)
761 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR
);
763 ret
= unescape_string (s
->filename
, p
, &size
, ';');
769 s
->filename
[size
] = 0;
771 else if ((p
= strstr(url
, "uuid=")) != NULL
)
774 uint8_t raw_uuid
[16];
776 p
+= sizeof ("uuid=") - 1;
779 for (j
=i
=0;i
<size
;i
++)
781 if (j
==sizeof(tmp_uuid
)-1)
785 if (isalnum(p
[i
])) tmp_uuid
[j
++]=p
[i
];
789 size
= sizeof(raw_uuid
);
790 ret
= _gnutls_hex2bin(tmp_uuid
, strlen(tmp_uuid
), raw_uuid
, &size
);
797 memcpy(&s
->uuid
.ulTimeLow
, raw_uuid
, 4);
798 memcpy(&s
->uuid
.usTimeMid
, &raw_uuid
[4], 2);
799 memcpy(&s
->uuid
.usTimeHigh
, &raw_uuid
[6], 2);
800 s
->uuid
.bClockSeqHigh
= raw_uuid
[8];
801 s
->uuid
.bClockSeqLow
= raw_uuid
[9];
802 memcpy(&s
->uuid
.rgbNode
, &raw_uuid
[10], 6);
807 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR
);
810 if ((p
= strstr(url
, "storage=user")) != NULL
)
811 s
->storage
= TSS_PS_TYPE_USER
;
813 s
->storage
= TSS_PS_TYPE_SYSTEM
;
823 * gnutls_privkey_import_tpm_url:
824 * @pkey: The private key
825 * @url: The URL of the TPM key to be imported
826 * @srk_password: The password for the SRK key (optional)
827 * @key_password: A password for the key (optional)
828 * @flags: One of the GNUTLS_PRIVKEY_* flags
830 * This function will import the given private key to the abstract
831 * #gnutls_privkey_t structure.
833 * Note that unless %GNUTLS_PRIVKEY_DISABLE_CALLBACKS
834 * is specified, if incorrect (or NULL) passwords are given
835 * the PKCS11 callback functions will be used to obtain the
836 * correct passwords. Otherwise if the SRK password is wrong
837 * %GNUTLS_E_TPM_SRK_PASSWORD_ERROR is returned and if the key password
838 * is wrong or not provided then %GNUTLS_E_TPM_KEY_PASSWORD_ERROR
841 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
842 * negative error value.
848 gnutls_privkey_import_tpm_url (gnutls_privkey_t pkey
,
850 const char *srk_password
,
851 const char *key_password
,
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
);
864 ret
= gnutls_load_file(durl
.filename
, &fdata
);
868 _gnutls_debug_log("Error loading %s\n", durl
.filename
);
872 ret
= gnutls_privkey_import_tpm_raw (pkey
, &fdata
, GNUTLS_TPMKEY_FMT_CTK_PEM
,
873 srk_password
, key_password
, flags
);
874 if (ret
== GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR
)
875 ret
= gnutls_privkey_import_tpm_raw (pkey
, &fdata
, GNUTLS_TPMKEY_FMT_DER
,
876 srk_password
, key_password
, flags
);
884 else if (durl
.uuid_set
)
886 if (flags
& GNUTLS_PRIVKEY_DISABLE_CALLBACKS
)
887 ret
= import_tpm_key (pkey
, NULL
, 0, &durl
.uuid
, durl
.storage
, srk_password
, key_password
);
889 ret
= import_tpm_key_cb (pkey
, NULL
, 0, &durl
.uuid
, durl
.storage
, srk_password
, key_password
);
899 gnutls_free(fdata
.data
);
900 clear_tpmkey_url(&durl
);
905 /* reads the RSA public key from the given TSS key.
906 * If psize is non-null it contains the total size of the parameters
908 static int read_pubkey(gnutls_pubkey_t pub
, TSS_HKEY key_ctx
, size_t *psize
)
916 /* read the public key */
918 tssret
= Tspi_GetAttribData(key_ctx
, TSS_TSPATTRIB_RSAKEY_INFO
,
919 TSS_TSPATTRIB_KEYINFO_RSA_MODULUS
, &tint
, (void*)&tdata
);
923 return tss_err(tssret
);
929 tssret
= Tspi_GetAttribData(key_ctx
, TSS_TSPATTRIB_RSAKEY_INFO
,
930 TSS_TSPATTRIB_KEYINFO_RSA_EXPONENT
, &tint
, (void*)&tdata
);
934 Tspi_Context_FreeMemory(key_ctx
, m
.data
);
935 return tss_err(tssret
);
941 ret
= gnutls_pubkey_import_rsa_raw(pub
, &m
, &e
);
943 Tspi_Context_FreeMemory(key_ctx
, m
.data
);
944 Tspi_Context_FreeMemory(key_ctx
, e
.data
);
947 return gnutls_assert_val(ret
);
950 *psize
= e
.size
+ m
.size
;
958 import_tpm_pubkey (gnutls_pubkey_t pkey
,
959 const gnutls_datum_t
* fdata
,
960 gnutls_tpmkey_fmt_t format
,
963 const char *srk_password
)
968 ret
= tpm_open_session(&s
, srk_password
);
970 return gnutls_assert_val(ret
);
974 ret
= load_key(s
.tpm_ctx
, s
.srk
, fdata
, format
, &s
.tpm_key
);
984 Tspi_Context_LoadKeyByUUID (s
.tpm_ctx
, storage
,
996 ret
= GNUTLS_E_INVALID_REQUEST
;
1000 ret
= read_pubkey(pkey
, s
.tpm_key
, NULL
);
1009 tpm_close_session(&s
);
1014 import_tpm_pubkey_cb (gnutls_pubkey_t pkey
,
1015 const gnutls_datum_t
* fdata
,
1016 gnutls_tpmkey_fmt_t format
,
1019 const char *srk_password
)
1021 unsigned int attempts
= 0;
1022 char pin1
[GNUTLS_PKCS11_MAX_PIN_LEN
];
1027 ret
= import_tpm_pubkey(pkey
, fdata
, format
, uuid
, storage
, srk_password
);
1032 if (ret
== GNUTLS_E_TPM_SRK_PASSWORD_ERROR
)
1034 ret
= tpm_pin(&pkey
->pin
, &srk_uuid
, storage
, pin1
, sizeof(pin1
), attempts
++);
1038 return GNUTLS_E_TPM_SRK_PASSWORD_ERROR
;
1040 srk_password
= pin1
;
1043 while(ret
== GNUTLS_E_TPM_SRK_PASSWORD_ERROR
);
1052 * gnutls_pubkey_import_tpm_raw:
1053 * @pkey: The public key
1054 * @fdata: The TPM key to be imported
1055 * @format: The format of the private key
1056 * @srk_password: The password for the SRK key (optional)
1057 * @flags: One of the GNUTLS_PUBKEY_* flags
1059 * This function will import the public key from the provided TPM key
1062 * With respect to passwords the same as in
1063 * gnutls_pubkey_import_tpm_url() apply.
1065 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1066 * negative error value.
1071 gnutls_pubkey_import_tpm_raw (gnutls_pubkey_t pkey
,
1072 const gnutls_datum_t
* fdata
,
1073 gnutls_tpmkey_fmt_t format
,
1074 const char *srk_password
,
1077 if (flags
& GNUTLS_PUBKEY_DISABLE_CALLBACKS
)
1078 return import_tpm_pubkey_cb(pkey
, fdata
, format
, NULL
, 0, srk_password
);
1080 return import_tpm_pubkey(pkey
, fdata
, format
, NULL
, 0, srk_password
);
1084 * gnutls_pubkey_import_tpm_url:
1085 * @pkey: The public key
1086 * @url: The URL of the TPM key to be imported
1087 * @srk_password: The password for the SRK key (optional)
1088 * @flags: should be zero
1090 * This function will import the given private key to the abstract
1091 * #gnutls_privkey_t structure.
1093 * Note that unless %GNUTLS_PUBKEY_DISABLE_CALLBACKS
1094 * is specified, if incorrect (or NULL) passwords are given
1095 * the PKCS11 callback functions will be used to obtain the
1096 * correct passwords. Otherwise if the SRK password is wrong
1097 * %GNUTLS_E_TPM_SRK_PASSWORD_ERROR is returned.
1099 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1100 * negative error value.
1106 gnutls_pubkey_import_tpm_url (gnutls_pubkey_t pkey
,
1108 const char *srk_password
,
1111 struct tpmkey_url_st durl
;
1112 gnutls_datum_t fdata
= { NULL
, 0 };
1115 ret
= decode_tpmkey_url(url
, &durl
);
1117 return gnutls_assert_val(ret
);
1122 ret
= gnutls_load_file(durl
.filename
, &fdata
);
1129 ret
= gnutls_pubkey_import_tpm_raw (pkey
, &fdata
, GNUTLS_TPMKEY_FMT_CTK_PEM
,
1130 srk_password
, flags
);
1131 if (ret
== GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR
)
1132 ret
= gnutls_pubkey_import_tpm_raw (pkey
, &fdata
, GNUTLS_TPMKEY_FMT_DER
,
1133 srk_password
, flags
);
1140 else if (durl
.uuid_set
)
1142 if (flags
& GNUTLS_PUBKEY_DISABLE_CALLBACKS
)
1143 ret
= import_tpm_pubkey (pkey
, NULL
, 0, &durl
.uuid
, durl
.storage
, srk_password
);
1145 ret
= import_tpm_pubkey_cb (pkey
, NULL
, 0, &durl
.uuid
, durl
.storage
, srk_password
);
1155 gnutls_free(fdata
.data
);
1156 clear_tpmkey_url(&durl
);
1162 * gnutls_tpm_privkey_generate:
1163 * @pk: the public key algorithm
1164 * @bits: the security bits
1165 * @srk_password: a password to protect the exported key (optional)
1166 * @key_password: the password for the TPM (optional)
1167 * @format: the format of the private key
1168 * @pub_format: the format of the public key
1169 * @privkey: the generated key
1170 * @pubkey: the corresponding public key (may be null)
1171 * @flags: should be a list of GNUTLS_TPM_* flags
1173 * This function will generate a private key in the TPM
1174 * chip. The private key will be generated within the chip
1175 * and will be exported in a wrapped with TPM's master key
1176 * form. Furthermore the wrapped key can be protected with
1177 * the provided @password.
1179 * Note that bits in TPM is quantized value. If the input value
1180 * is not one of the allowed values, then it will be quantized to
1181 * one of 512, 1024, 2048, 4096, 8192 and 16384.
1183 * Allowed flags are:
1185 * %GNUTLS_TPM_KEY_SIGNING: Generate a signing key instead of a legacy,
1187 * %GNUTLS_TPM_REGISTER_KEY: Register the generate key in TPM. In that
1188 * case @privkey would contain a URL with the UUID.
1190 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1191 * negative error value.
1196 gnutls_tpm_privkey_generate (gnutls_pk_algorithm_t pk
, unsigned int bits
,
1197 const char* srk_password
,
1198 const char* key_password
,
1199 gnutls_tpmkey_fmt_t format
,
1200 gnutls_x509_crt_fmt_t pub_format
,
1201 gnutls_datum_t
* privkey
,
1202 gnutls_datum_t
* pubkey
,
1205 TSS_FLAG tpm_flags
= TSS_KEY_VOLATILE
;
1211 gnutls_datum_t tmpkey
= {NULL
, 0};
1212 TSS_HPOLICY key_policy
;
1213 gnutls_pubkey_t pub
;
1214 struct tpm_ctx_st s
;
1215 TSS_FLAG storage_type
;
1219 if (flags
& GNUTLS_TPM_KEY_SIGNING
)
1220 tpm_flags
|= TSS_KEY_TYPE_SIGNING
;
1222 tpm_flags
|= TSS_KEY_TYPE_LEGACY
;
1224 if (flags
& GNUTLS_TPM_KEY_USER
)
1225 storage_type
= TSS_PS_TYPE_USER
;
1227 storage_type
= TSS_PS_TYPE_SYSTEM
;
1230 tpm_flags
|= TSS_KEY_SIZE_512
;
1231 else if (bits
<= 1024)
1232 tpm_flags
|= TSS_KEY_SIZE_1024
;
1233 else if (bits
<= 2048)
1234 tpm_flags
|= TSS_KEY_SIZE_2048
;
1235 else if (bits
<= 4096)
1236 tpm_flags
|= TSS_KEY_SIZE_4096
;
1237 else if (bits
<= 8192)
1238 tpm_flags
|= TSS_KEY_SIZE_8192
;
1240 tpm_flags
|= TSS_KEY_SIZE_16384
;
1242 ret
= tpm_open_session(&s
, srk_password
);
1244 return gnutls_assert_val(ret
);
1246 /* put some randomness into TPM.
1247 * Let's not trust it completely.
1249 tssret
= Tspi_Context_GetTpmObject(s
.tpm_ctx
, &htpm
);
1253 ret
= tss_err(tssret
);
1258 ret
= _gnutls_rnd(GNUTLS_RND_RANDOM
, buf
, sizeof(buf
));
1265 tssret
= Tspi_TPM_StirRandom(htpm
, sizeof(buf
), buf
);
1271 tssret
= Tspi_Context_CreateObject(s
.tpm_ctx
, TSS_OBJECT_TYPE_RSAKEY
, tpm_flags
, &key_ctx
);
1275 ret
= tss_err(tssret
);
1279 tssret
= Tspi_SetAttribUint32(key_ctx
, TSS_TSPATTRIB_KEY_INFO
, TSS_TSPATTRIB_KEYINFO_SIGSCHEME
,
1280 TSS_SS_RSASSAPKCS1V15_DER
);
1284 ret
= tss_err(tssret
);
1288 /* set the password of the actual key */
1291 tssret
= Tspi_GetPolicyObject(key_ctx
, TSS_POLICY_USAGE
, &key_policy
);
1295 ret
= tss_err(tssret
);
1299 tssret
= myTspi_Policy_SetSecret(key_policy
,
1300 SAFE_LEN(key_password
), (void*)key_password
);
1304 ret
= tss_err(tssret
);
1309 tssret
= Tspi_Key_CreateKey(key_ctx
, s
.srk
, 0);
1313 ret
= tss_err(tssret
);
1317 if (flags
& GNUTLS_TPM_REGISTER_KEY
)
1321 ret
= randomize_uuid(&key_uuid
);
1328 tssret
= Tspi_Context_RegisterKey(s
.tpm_ctx
, key_ctx
, storage_type
,
1329 key_uuid
, TSS_PS_TYPE_SYSTEM
, srk_uuid
);
1333 ret
= tss_err(tssret
);
1337 ret
= encode_tpmkey_url((char**)&privkey
->data
, &key_uuid
, storage_type
);
1342 Tspi_Context_UnregisterKey(s
.tpm_ctx
, storage_type
, key_uuid
, &tkey
);
1346 privkey
->size
= strlen((char*)privkey
->data
);
1349 else /* get the key as blob */
1352 tssret
= Tspi_GetAttribData(key_ctx
, TSS_TSPATTRIB_KEY_BLOB
,
1353 TSS_TSPATTRIB_KEYBLOB_BLOB
, &tint
, (void*)&tdata
);
1357 ret
= tss_err(tssret
);
1362 if (format
== GNUTLS_TPMKEY_FMT_CTK_PEM
)
1364 ret
= _gnutls_x509_encode_string(NULL
, tdata
, tint
, &tmpkey
);
1371 ret
= _gnutls_fbase64_encode ("TSS KEY BLOB", tmpkey
.data
, tmpkey
.size
, privkey
);
1382 tmpkey
.size
= tint
+ 32; /* spec says no more than 20 */
1383 tmpkey
.data
= gnutls_malloc(tmpkey
.size
);
1384 if (tmpkey
.data
== NULL
)
1387 ret
= GNUTLS_E_MEMORY_ERROR
;
1391 tint2
= tmpkey
.size
;
1392 tssret
= Tspi_EncodeDER_TssBlob(tint
, tdata
, TSS_BLOB_TYPE_PRIVATEKEY
,
1393 &tint2
, tmpkey
.data
);
1397 ret
= tss_err(tssret
);
1401 tmpkey
.size
= tint2
;
1403 privkey
->data
= tmpkey
.data
;
1404 privkey
->size
= tmpkey
.size
;
1409 /* read the public key */
1414 ret
= gnutls_pubkey_init(&pub
);
1418 goto privkey_cleanup
;
1421 ret
= read_pubkey(pub
, key_ctx
, &psize
);
1425 goto privkey_cleanup
;
1429 pubkey
->data
= gnutls_malloc(psize
);
1430 if (pubkey
->data
== NULL
)
1433 ret
= GNUTLS_E_MEMORY_ERROR
;
1434 goto pubkey_cleanup
;
1437 ret
= gnutls_pubkey_export(pub
, pub_format
, pubkey
->data
, &psize
);
1441 goto pubkey_cleanup
;
1443 pubkey
->size
= psize
;
1445 gnutls_pubkey_deinit(pub
);
1452 gnutls_pubkey_deinit(pub
);
1454 gnutls_free(privkey
->data
);
1455 privkey
->data
= NULL
;
1457 gnutls_free(tmpkey
.data
);
1460 Tspi_Context_CloseObject(s
.tpm_ctx
, key_ctx
);
1462 tpm_close_session(&s
);
1468 * gnutls_tpm_key_list_deinit:
1469 * @list: a list of the keys
1471 * This function will deinitialize the list of stored keys in the TPM.
1476 gnutls_tpm_key_list_deinit (gnutls_tpm_key_list_t list
)
1478 if (list
->tpm_ctx
!= 0) Tspi_Context_Close (list
->tpm_ctx
);
1483 * gnutls_tpm_key_list_get_url:
1484 * @list: a list of the keys
1485 * @idx: The index of the key (starting from zero)
1486 * @url: The URL to be returned
1487 * @flags: should be zero
1489 * This function will return for each given index a URL of
1490 * the corresponding key.
1491 * If the provided index is out of bounds then %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
1494 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1495 * negative error value.
1500 gnutls_tpm_key_list_get_url (gnutls_tpm_key_list_t list
, unsigned int idx
, char** url
, unsigned int flags
)
1502 if (idx
>= list
->size
)
1503 return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
);
1505 return encode_tpmkey_url(url
, &list
->ki
[idx
].keyUUID
, list
->ki
[idx
].persistentStorageType
);
1509 * gnutls_tpm_get_registered:
1510 * @list: a list to store the keys
1512 * This function will get a list of stored keys in the TPM. The uuid
1515 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1516 * negative error value.
1521 gnutls_tpm_get_registered (gnutls_tpm_key_list_t
*list
)
1526 *list
= gnutls_calloc(1, sizeof(struct tpm_key_list_st
));
1528 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR
);
1530 tssret
= Tspi_Context_Create (&(*list
)->tpm_ctx
);
1534 ret
= tss_err(tssret
);
1538 tssret
= Tspi_Context_Connect ((*list
)->tpm_ctx
, NULL
);
1542 ret
= tss_err(tssret
);
1547 Tspi_Context_GetRegisteredKeysByUUID2((*list
)->tpm_ctx
, TSS_PS_TYPE_SYSTEM
,
1548 NULL
, &(*list
)->size
, &(*list
)->ki
);
1552 ret
= tss_err(tssret
);
1558 gnutls_tpm_key_list_deinit(*list
);
1564 * gnutls_tpm_privkey_delete:
1565 * @url: the URL describing the key
1566 * @srk_password: a password for the SRK key
1568 * This function will unregister the private key from the TPM
1571 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
1572 * negative error value.
1577 gnutls_tpm_privkey_delete (const char* url
, const char* srk_password
)
1579 struct tpm_ctx_st s
;
1580 struct tpmkey_url_st durl
;
1585 ret
= decode_tpmkey_url(url
, &durl
);
1587 return gnutls_assert_val(ret
);
1589 if (durl
.uuid_set
== 0)
1590 return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST
);
1592 ret
= tpm_open_session(&s
, srk_password
);
1594 return gnutls_assert_val(ret
);
1596 tssret
= Tspi_Context_UnregisterKey(s
.tpm_ctx
, durl
.storage
, durl
.uuid
, &tkey
);
1600 ret
= tss_err(tssret
);
1606 tpm_close_session(&s
);