LCOV - code coverage report
Current view: top level - builds/gnutls/coverage/gnutls-git/lib - tpm.c (source / functions) Hit Total Coverage
Test: GnuTLS-3.6.14 Code Coverage Lines: 564 873 64.6 %
Date: 2020-10-30 04:50:48 Functions: 29 29 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14