gnutls_tpm2_ibm.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. /*
  2. * OpenConnect (SSL + DTLS) VPN client
  3. *
  4. * Copyright © 2018 David Woodhouse.
  5. * Copyright © 2017-2018 James Bottomley
  6. *
  7. * Authors: James Bottomley <James.Bottomley@hansenpartnership.com>
  8. * David Woodhouse <dwmw2@infradead.org>
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public License
  12. * version 2.1, as published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope that it will be useful, but
  15. * WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. */
  19. #include <config.h>
  20. #include "openconnect-internal.h"
  21. #include "gnutls.h"
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <errno.h>
  25. #define TSSINCLUDE(x) < HAVE_TSS2/x >
  26. #include TSSINCLUDE(tss.h)
  27. #include TSSINCLUDE(tssresponsecode.h)
  28. #include TSSINCLUDE(Unmarshal_fp.h)
  29. #include TSSINCLUDE(RSA_Decrypt_fp.h)
  30. #include TSSINCLUDE(Sign_fp.h)
  31. #define rc_is_key_auth_failed(rc) (((rc) & 0xff) == TPM_RC_BAD_AUTH)
  32. #define rc_is_parent_auth_failed(rc) (((rc) & 0xff) == TPM_RC_AUTH_FAIL)
  33. struct oc_tpm2_ctx {
  34. TPM2B_PUBLIC pub;
  35. TPM2B_PRIVATE priv;
  36. char *parent_pass, *key_pass;
  37. unsigned int need_userauth:1;
  38. unsigned int legacy_srk:1;
  39. unsigned int parent;
  40. };
  41. static void tpm2_error(struct openconnect_info *vpninfo, TPM_RC rc, const char *reason)
  42. {
  43. const char *msg = NULL, *submsg = NULL, *num = NULL;
  44. TSS_ResponseCode_toString(&msg, &submsg, &num, rc);
  45. vpn_progress(vpninfo, PRG_ERR,
  46. _("TPM2 operation %s failed (%d): %s%s%s\n"),
  47. reason, rc, msg, submsg, num);
  48. }
  49. static TPM_RC tpm2_readpublic(struct openconnect_info *vpninfo, TSS_CONTEXT *tssContext,
  50. TPM_HANDLE handle, TPMT_PUBLIC *pub)
  51. {
  52. ReadPublic_In rin;
  53. ReadPublic_Out rout;
  54. TPM_RC rc;
  55. rin.objectHandle = handle;
  56. rc = TSS_Execute (tssContext,
  57. (RESPONSE_PARAMETERS *)&rout,
  58. (COMMAND_PARAMETERS *)&rin,
  59. NULL,
  60. TPM_CC_ReadPublic,
  61. TPM_RH_NULL, NULL, 0);
  62. if (rc) {
  63. tpm2_error(vpninfo, rc, "TPM2_ReadPublic");
  64. return rc;
  65. }
  66. if (pub)
  67. *pub = rout.outPublic.publicArea;
  68. return rc;
  69. }
  70. static TPM_RC tpm2_get_session_handle(struct openconnect_info *vpninfo, TSS_CONTEXT *tssContext,
  71. TPM_HANDLE *handle, TPM_HANDLE bind, const char *auth,
  72. TPM_HANDLE salt_key)
  73. {
  74. TPM_RC rc;
  75. StartAuthSession_In in;
  76. StartAuthSession_Out out;
  77. StartAuthSession_Extra extra;
  78. memset(&in, 0, sizeof(in));
  79. memset(&extra, 0 , sizeof(extra));
  80. in.bind = bind;
  81. extra.bindPassword = auth;
  82. in.sessionType = TPM_SE_HMAC;
  83. in.authHash = TPM_ALG_SHA256;
  84. in.tpmKey = TPM_RH_NULL;
  85. in.symmetric.algorithm = TPM_ALG_AES;
  86. in.symmetric.keyBits.aes = 128;
  87. in.symmetric.mode.aes = TPM_ALG_CFB;
  88. if (salt_key) {
  89. /* For the TSS to use a key as salt, it must have
  90. * access to the public part. It does this by keeping
  91. * key files, but request the public part just to make
  92. * sure*/
  93. tpm2_readpublic(vpninfo, tssContext, salt_key, NULL);
  94. /* don't care what rout returns, the purpose of the
  95. * operation was to get the public key parameters into
  96. * the tss so it can construct the salt */
  97. in.tpmKey = salt_key;
  98. }
  99. rc = TSS_Execute(tssContext,
  100. (RESPONSE_PARAMETERS *)&out,
  101. (COMMAND_PARAMETERS *)&in,
  102. (EXTRA_PARAMETERS *)&extra,
  103. TPM_CC_StartAuthSession,
  104. TPM_RH_NULL, NULL, 0);
  105. if (rc) {
  106. tpm2_error(vpninfo, rc, "TPM2_StartAuthSession");
  107. return rc;
  108. }
  109. *handle = out.sessionHandle;
  110. return TPM_RC_SUCCESS;
  111. }
  112. static void tpm2_flush_handle(TSS_CONTEXT *tssContext, TPM_HANDLE h)
  113. {
  114. FlushContext_In in;
  115. if (!h)
  116. return;
  117. in.flushHandle = h;
  118. TSS_Execute(tssContext, NULL,
  119. (COMMAND_PARAMETERS *)&in,
  120. NULL,
  121. TPM_CC_FlushContext,
  122. TPM_RH_NULL, NULL, 0);
  123. }
  124. #define parent_is_generated(parent) ((parent) >> HR_SHIFT == TPM_HT_PERMANENT)
  125. #define parent_is_persistent(parent) ((parent) >> HR_SHIFT == TPM_HT_PERSISTENT)
  126. static TPM_RC tpm2_load_srk(struct openconnect_info *vpninfo, TSS_CONTEXT *tssContext,
  127. TPM_HANDLE *h, const char *auth, TPM_HANDLE hierarchy,
  128. int legacy_srk)
  129. {
  130. TPM_RC rc;
  131. CreatePrimary_In in;
  132. CreatePrimary_Out out;
  133. TPM_HANDLE session;
  134. /* SPS owner */
  135. in.primaryHandle = hierarchy;
  136. if (auth) {
  137. in.inSensitive.sensitive.userAuth.t.size = strlen(auth);
  138. memcpy(in.inSensitive.sensitive.userAuth.t.buffer, auth, strlen(auth));
  139. } else {
  140. in.inSensitive.sensitive.userAuth.t.size = 0;
  141. }
  142. /* no sensitive date for storage keys */
  143. in.inSensitive.sensitive.data.t.size = 0;
  144. /* no outside info */
  145. in.outsideInfo.t.size = 0;
  146. /* no PCR state */
  147. in.creationPCR.count = 0;
  148. /* public parameters for an RSA2048 key */
  149. in.inPublic.publicArea.type = TPM_ALG_ECC;
  150. in.inPublic.publicArea.nameAlg = TPM_ALG_SHA256;
  151. in.inPublic.publicArea.objectAttributes.val =
  152. TPMA_OBJECT_NODA |
  153. TPMA_OBJECT_SENSITIVEDATAORIGIN |
  154. TPMA_OBJECT_USERWITHAUTH |
  155. TPMA_OBJECT_DECRYPT |
  156. TPMA_OBJECT_RESTRICTED;
  157. if (!legacy_srk)
  158. in.inPublic.publicArea.objectAttributes.val |=
  159. TPMA_OBJECT_FIXEDPARENT | TPMA_OBJECT_FIXEDTPM;
  160. in.inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = TPM_ALG_AES;
  161. in.inPublic.publicArea.parameters.eccDetail.symmetric.keyBits.aes = 128;
  162. in.inPublic.publicArea.parameters.eccDetail.symmetric.mode.aes = TPM_ALG_CFB;
  163. in.inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_NULL;
  164. in.inPublic.publicArea.parameters.eccDetail.curveID = TPM_ECC_NIST_P256;
  165. in.inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
  166. in.inPublic.publicArea.unique.ecc.x.t.size = 0;
  167. in.inPublic.publicArea.unique.ecc.y.t.size = 0;
  168. in.inPublic.publicArea.authPolicy.t.size = 0;
  169. /* use a bound session here because we have no known key objects
  170. * to encrypt a salt to */
  171. rc = tpm2_get_session_handle(vpninfo, tssContext, &session, hierarchy, auth, 0);
  172. if (rc)
  173. return rc;
  174. rc = TSS_Execute(tssContext,
  175. (RESPONSE_PARAMETERS *)&out,
  176. (COMMAND_PARAMETERS *)&in,
  177. NULL,
  178. TPM_CC_CreatePrimary,
  179. session, auth, TPMA_SESSION_DECRYPT,
  180. TPM_RH_NULL, NULL, 0);
  181. if (rc) {
  182. tpm2_error(vpninfo, rc, "TSS_CreatePrimary");
  183. tpm2_flush_handle(tssContext, session);
  184. return rc;
  185. }
  186. *h = out.objectHandle;
  187. return 0;
  188. }
  189. static TPM_HANDLE tpm2_load_key(struct openconnect_info *vpninfo, struct cert_info *certinfo, TSS_CONTEXT **tsscp)
  190. {
  191. TSS_CONTEXT *tssContext;
  192. Load_In in;
  193. Load_Out out;
  194. TPM_HANDLE key = 0;
  195. TPM_RC rc;
  196. TPM_HANDLE session;
  197. char *pass = certinfo->tpm2->parent_pass;
  198. int need_pw = 0;
  199. certinfo->tpm2->parent_pass = NULL;
  200. rc = TSS_Create(&tssContext);
  201. if (rc) {
  202. tpm2_error(vpninfo, rc, "TSS_Create");
  203. return 0;
  204. }
  205. memset(&in, 0, sizeof(in));
  206. memset(&out, 0, sizeof(out));
  207. if (parent_is_persistent(certinfo->tpm2->parent)) {
  208. if (!pass) {
  209. TPMT_PUBLIC pub;
  210. rc = tpm2_readpublic(vpninfo, tssContext, certinfo->tpm2->parent, &pub);
  211. if (rc)
  212. goto out;
  213. if (!(pub.objectAttributes.val & TPMA_OBJECT_NODA))
  214. need_pw = 1;
  215. }
  216. in.parentHandle = certinfo->tpm2->parent;
  217. } else {
  218. reauth_srk:
  219. rc = tpm2_load_srk(vpninfo, tssContext, &in.parentHandle, pass, certinfo->tpm2->parent, certinfo->tpm2->legacy_srk);
  220. if (rc_is_key_auth_failed(rc)) {
  221. free_pass(&pass);
  222. if (!request_passphrase(vpninfo,
  223. certinfo_string(certinfo, "openconnect_tpm2_hierarchy",
  224. "openconnect_secondary_tpm2_hierarchy"),
  225. &pass,
  226. _("Enter TPM2 %s hierarchy password:"), "owner")) {
  227. goto reauth_srk;
  228. }
  229. }
  230. if (rc)
  231. goto out;
  232. }
  233. rc = tpm2_get_session_handle(vpninfo, tssContext, &session, 0, NULL, in.parentHandle);
  234. if (rc)
  235. goto out_flush_srk;
  236. memcpy(&in.inPublic, &certinfo->tpm2->pub, sizeof(in.inPublic));
  237. memcpy(&in.inPrivate, &certinfo->tpm2->priv, sizeof(in.inPrivate));
  238. if (need_pw && !pass) {
  239. reauth_parent:
  240. if (request_passphrase(vpninfo,
  241. certinfo_string(certinfo, "openconnect_tpm2_parent",
  242. "openconnect_secondary_tpm2_parent"),
  243. &pass,
  244. certinfo_string(certinfo, _("Enter TPM2 parent key password:"),
  245. _("Enter secondary TPM2 parent key password:")))) {
  246. tpm2_flush_handle(tssContext, session);
  247. goto out_flush_srk;
  248. }
  249. }
  250. rc = TSS_Execute(tssContext,
  251. (RESPONSE_PARAMETERS *)&out,
  252. (COMMAND_PARAMETERS *)&in,
  253. NULL,
  254. TPM_CC_Load,
  255. session, pass, 0,
  256. TPM_RH_NULL, NULL, 0);
  257. if (rc_is_parent_auth_failed(rc)) {
  258. free_pass(&pass);
  259. goto reauth_parent;
  260. }
  261. if (rc) {
  262. tpm2_error(vpninfo, rc, "TPM2_Load");
  263. tpm2_flush_handle(tssContext, session);
  264. }
  265. else
  266. key = out.objectHandle;
  267. out_flush_srk:
  268. if (parent_is_generated(certinfo->tpm2->parent))
  269. tpm2_flush_handle(tssContext, in.parentHandle);
  270. out:
  271. certinfo->tpm2->parent_pass = pass;
  272. if (!key)
  273. TSS_Delete(tssContext);
  274. else
  275. *tsscp = tssContext;
  276. return key;
  277. }
  278. static void tpm2_unload_key(TSS_CONTEXT *tssContext, TPM_HANDLE key)
  279. {
  280. tpm2_flush_handle(tssContext, key);
  281. TSS_Delete(tssContext);
  282. }
  283. int tpm2_rsa_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
  284. void *_certinfo, unsigned int flags,
  285. const gnutls_datum_t *data, gnutls_datum_t *sig)
  286. {
  287. struct cert_info *certinfo = _certinfo;
  288. struct openconnect_info *vpninfo = certinfo->vpninfo;
  289. TSS_CONTEXT *tssContext = NULL;
  290. RSA_Decrypt_In in;
  291. RSA_Decrypt_Out out;
  292. int ret = GNUTLS_E_PK_SIGN_FAILED;
  293. TPM_HANDLE authHandle;
  294. TPM_RC rc;
  295. char *pass = certinfo->tpm2->key_pass;
  296. certinfo->tpm2->key_pass = NULL;
  297. memset(&in, 0, sizeof(in));
  298. in.cipherText.t.size = certinfo->tpm2->pub.publicArea.unique.rsa.t.size;
  299. if (oc_pad_rsasig(vpninfo, algo, in.cipherText.t.buffer, in.cipherText.t.size, data,
  300. certinfo->tpm2->pub.publicArea.parameters.rsaDetail.keyBits))
  301. return GNUTLS_E_PK_SIGN_FAILED;
  302. in.inScheme.scheme = TPM_ALG_NULL;
  303. in.keyHandle = tpm2_load_key(vpninfo, certinfo, &tssContext);
  304. in.label.t.size = 0;
  305. if (!in.keyHandle)
  306. return GNUTLS_E_PK_SIGN_FAILED;
  307. rc = tpm2_get_session_handle(vpninfo, tssContext, &authHandle, 0, NULL, 0);
  308. if (rc)
  309. goto out;
  310. reauth:
  311. rc = TSS_Execute(tssContext,
  312. (RESPONSE_PARAMETERS *)&out,
  313. (COMMAND_PARAMETERS *)&in,
  314. NULL,
  315. TPM_CC_RSA_Decrypt,
  316. authHandle, pass, TPMA_SESSION_DECRYPT,
  317. TPM_RH_NULL, NULL, 0);
  318. if (rc_is_key_auth_failed(rc)) {
  319. free_pass(&pass);
  320. if (!request_passphrase(vpninfo,
  321. certinfo_string(certinfo, "openconnect_tpm2_key",
  322. "openconnect_secondary_tpm2_key"),
  323. &pass,
  324. certinfo_string(certinfo, _("Enter TPM2 key password:"),
  325. _("Enter secondary TPM2 key password:"))))
  326. goto reauth;
  327. }
  328. if (rc) {
  329. tpm2_error(vpninfo, rc, "TPM2_RSA_Decrypt");
  330. /* failure means auth handle is not flushed */
  331. tpm2_flush_handle(tssContext, authHandle);
  332. goto out;
  333. }
  334. certinfo->tpm2->key_pass = pass;
  335. sig->data = malloc(out.message.t.size);
  336. if (!sig->data)
  337. goto out;
  338. sig->size = out.message.t.size;
  339. memcpy(sig->data, out.message.t.buffer, out.message.t.size);
  340. ret = 0;
  341. out:
  342. tpm2_unload_key(tssContext, in.keyHandle);
  343. return ret;
  344. }
  345. int tpm2_ec_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
  346. void *_certinfo, unsigned int flags,
  347. const gnutls_datum_t *data, gnutls_datum_t *sig)
  348. {
  349. struct cert_info *certinfo = _certinfo;
  350. struct openconnect_info *vpninfo = certinfo->vpninfo;
  351. TSS_CONTEXT *tssContext = NULL;
  352. Sign_In in;
  353. Sign_Out out;
  354. int ret = GNUTLS_E_PK_SIGN_FAILED;
  355. TPM_HANDLE authHandle;
  356. TPM_RC rc;
  357. char *pass = certinfo->tpm2->key_pass;
  358. gnutls_datum_t sig_r, sig_s;
  359. certinfo->tpm2->key_pass = NULL;
  360. vpn_progress(vpninfo, PRG_DEBUG,
  361. _("TPM2 EC sign function called for %d bytes.\n"),
  362. data->size);
  363. memset(&in, 0, sizeof(in));
  364. /* FIPS-186-4 §6.4 says "When the length of the output of the hash
  365. * function is greater than the bit length of n, then the leftmost
  366. * n bits of the hash function output block shall be used in any
  367. * calculation using the hash function output during the generation
  368. * or verification of a digital signature."
  369. *
  370. * So GnuTLS is expected to *truncate* a larger hash to fit the
  371. * curve bit length, and then we lie to the TPM about which hash
  372. * it was because the TPM only really cares about the size of the
  373. * data anyway. */
  374. switch (data->size) {
  375. case SHA1_SIZE: in.inScheme.details.ecdsa.hashAlg = TPM_ALG_SHA1; break;
  376. case SHA256_SIZE: in.inScheme.details.ecdsa.hashAlg = TPM_ALG_SHA256; break;
  377. case SHA384_SIZE: in.inScheme.details.ecdsa.hashAlg = TPM_ALG_SHA384; break;
  378. #ifdef TPM_ALG_SHA512
  379. case SHA512_SIZE: in.inScheme.details.ecdsa.hashAlg = TPM_ALG_SHA512; break;
  380. #endif
  381. default:
  382. vpn_progress(vpninfo, PRG_ERR,
  383. _("Unknown TPM2 EC digest size %d for algo 0x%x\n"),
  384. data->size, algo);
  385. return GNUTLS_E_PK_SIGN_FAILED;
  386. }
  387. in.inScheme.scheme = TPM_ALG_ECDSA;
  388. in.digest.t.size = data->size;
  389. memcpy(in.digest.t.buffer, data->data, data->size);
  390. in.validation.tag = TPM_ST_HASHCHECK;
  391. in.validation.hierarchy = TPM_RH_NULL;
  392. in.validation.digest.t.size = 0;
  393. in.keyHandle = tpm2_load_key(vpninfo, certinfo, &tssContext);
  394. if (!in.keyHandle)
  395. return GNUTLS_E_PK_SIGN_FAILED;
  396. rc = tpm2_get_session_handle(vpninfo, tssContext, &authHandle, 0, NULL, 0);
  397. if (rc)
  398. goto out;
  399. reauth:
  400. rc = TSS_Execute(tssContext,
  401. (RESPONSE_PARAMETERS *)&out,
  402. (COMMAND_PARAMETERS *)&in,
  403. NULL,
  404. TPM_CC_Sign,
  405. authHandle, pass, TPMA_SESSION_DECRYPT,
  406. TPM_RH_NULL, NULL, 0);
  407. if (rc_is_key_auth_failed(rc)) {
  408. free_pass(&pass);
  409. if (!request_passphrase(vpninfo, "openconnect_tpm2_key",
  410. &pass, _("Enter TPM2 key password:")))
  411. goto reauth;
  412. }
  413. if (rc) {
  414. tpm2_error(vpninfo, rc, "TPM2_Sign");
  415. tpm2_flush_handle(tssContext, authHandle);
  416. goto out;
  417. }
  418. certinfo->tpm2->key_pass = pass;
  419. sig_r.data = out.signature.signature.ecdsa.signatureR.t.buffer;
  420. sig_r.size = out.signature.signature.ecdsa.signatureR.t.size;
  421. sig_s.data = out.signature.signature.ecdsa.signatureS.t.buffer;
  422. sig_s.size = out.signature.signature.ecdsa.signatureS.t.size;
  423. ret = gnutls_encode_rs_value(sig, &sig_r, &sig_s);
  424. out:
  425. tpm2_unload_key(tssContext, in.keyHandle);
  426. return ret;
  427. }
  428. int install_tpm2_key(struct openconnect_info *vpninfo, struct cert_info *certinfo,
  429. gnutls_privkey_t *pkey, gnutls_datum_t *pkey_sig,
  430. unsigned int parent, int emptyauth, int legacy,
  431. gnutls_datum_t *privdata, gnutls_datum_t *pubdata)
  432. {
  433. TPM_RC rc;
  434. BYTE *der;
  435. INT32 dersize;
  436. if (!parent_is_persistent(parent) &&
  437. parent != TPM_RH_OWNER && parent != TPM_RH_NULL &&
  438. parent != TPM_RH_ENDORSEMENT && parent != TPM_RH_PLATFORM) {
  439. vpn_progress(vpninfo, PRG_ERR,
  440. _("Invalid TPM2 parent handle 0x%08x\n"), parent);
  441. return -EINVAL;
  442. }
  443. certinfo->tpm2 = calloc(1, sizeof(*certinfo->tpm2));
  444. if (!certinfo->tpm2)
  445. return -ENOMEM;
  446. certinfo->tpm2->parent = parent;
  447. certinfo->tpm2->need_userauth = !emptyauth;
  448. certinfo->tpm2->legacy_srk = legacy;
  449. der = privdata->data;
  450. dersize = privdata->size;
  451. rc = TPM2B_PRIVATE_Unmarshal(&certinfo->tpm2->priv, &der, &dersize);
  452. if (rc) {
  453. vpn_progress(vpninfo, PRG_ERR,
  454. _("Failed to import TPM2 private key data: 0x%x\n"),
  455. rc);
  456. goto err_out;
  457. }
  458. der = pubdata->data;
  459. dersize = pubdata->size;
  460. rc = TPM2B_PUBLIC_Unmarshal(&certinfo->tpm2->pub, &der, &dersize, FALSE);
  461. if (rc) {
  462. vpn_progress(vpninfo, PRG_ERR,
  463. _("Failed to import TPM2 public key data: 0x%x\n"),
  464. rc);
  465. goto err_out;
  466. }
  467. switch(certinfo->tpm2->pub.publicArea.type) {
  468. case TPM_ALG_RSA: return GNUTLS_PK_RSA;
  469. case TPM_ALG_ECC: return GNUTLS_PK_ECC;
  470. }
  471. vpn_progress(vpninfo, PRG_ERR,
  472. _("Unsupported TPM2 key type %d\n"),
  473. certinfo->tpm2->pub.publicArea.type);
  474. err_out:
  475. release_tpm2_ctx(vpninfo, certinfo);
  476. return -EINVAL;
  477. }
  478. uint16_t tpm2_key_curve(struct openconnect_info *vpninfo, struct cert_info *certinfo)
  479. {
  480. return certinfo->tpm2->pub.publicArea.parameters.eccDetail.curveID;
  481. }
  482. int tpm2_rsa_key_bits(struct openconnect_info *vpninfo, struct cert_info *certinfo)
  483. {
  484. return certinfo->tpm2->pub.publicArea.parameters.rsaDetail.keyBits;
  485. }
  486. void release_tpm2_ctx(struct openconnect_info *vpninfo, struct cert_info *certinfo)
  487. {
  488. if (certinfo->tpm2) {
  489. free_pass(&certinfo->tpm2->parent_pass);
  490. free_pass(&certinfo->tpm2->key_pass);
  491. free(certinfo->tpm2);
  492. certinfo->tpm2 = NULL;
  493. }
  494. }