123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647 |
- /*
- * OpenConnect (SSL + DTLS) VPN client
- *
- * Copyright © 2018 David Woodhouse.
- *
- * Author: David Woodhouse <dwmw2@infradead.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * version 2.1, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- */
- /* Portions taken from tpm2-tss-engine, copyright as below: */
- /*******************************************************************************
- * Copyright 2017-2018, Fraunhofer SIT sponsored by Infineon Technologies AG
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * 3. Neither the name of tpm2-tss-engine nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
- * THE POSSIBILITY OF SUCH DAMAGE.
- ******************************************************************************/
- #include <config.h>
- #include "openconnect-internal.h"
- #include "gnutls.h"
- #include <tss2/tss2_mu.h>
- #include <tss2/tss2_esys.h>
- #include <tss2/tss2_tctildr.h>
- #include <errno.h>
- #include <stdio.h>
- #include <string.h>
- struct oc_tpm2_ctx {
- TSS2_TCTI_CONTEXT *tcti_ctx;
- TPM2B_PUBLIC pub;
- TPM2B_PRIVATE priv;
- TPM2B_DIGEST userauth;
- TPM2B_DIGEST ownerauth;
- unsigned int need_userauth:1;
- unsigned int need_ownerauth:1;
- unsigned int did_ownerauth:1;
- unsigned int legacy_srk:1;
- unsigned int parent;
- };
- static const TPM2B_PUBLIC primaryTemplate = {
- .publicArea = {
- .type = TPM2_ALG_ECC,
- .nameAlg = TPM2_ALG_SHA256,
- .objectAttributes = (TPMA_OBJECT_USERWITHAUTH |
- TPMA_OBJECT_RESTRICTED |
- TPMA_OBJECT_DECRYPT |
- TPMA_OBJECT_FIXEDTPM |
- TPMA_OBJECT_FIXEDPARENT |
- TPMA_OBJECT_NODA |
- TPMA_OBJECT_SENSITIVEDATAORIGIN),
- .authPolicy = {
- .size = 0,
- },
- .parameters.eccDetail = {
- .symmetric = {
- .algorithm = TPM2_ALG_AES,
- .keyBits.aes = 128,
- .mode.aes = TPM2_ALG_CFB,
- },
- .scheme = {
- .scheme = TPM2_ALG_NULL,
- .details = {}
- },
- .curveID = TPM2_ECC_NIST_P256,
- .kdf = {
- .scheme = TPM2_ALG_NULL,
- .details = {}
- },
- },
- .unique.ecc = {
- .x.size = 0,
- .y.size = 0
- }
- }
- };
- static const TPM2B_PUBLIC primaryTemplate_legacy = {
- .publicArea = {
- .type = TPM2_ALG_ECC,
- .nameAlg = TPM2_ALG_SHA256,
- .objectAttributes = (TPMA_OBJECT_USERWITHAUTH |
- TPMA_OBJECT_RESTRICTED |
- TPMA_OBJECT_DECRYPT |
- TPMA_OBJECT_NODA |
- TPMA_OBJECT_SENSITIVEDATAORIGIN),
- .authPolicy = {
- .size = 0,
- },
- .parameters.eccDetail = {
- .symmetric = {
- .algorithm = TPM2_ALG_AES,
- .keyBits.aes = 128,
- .mode.aes = TPM2_ALG_CFB,
- },
- .scheme = {
- .scheme = TPM2_ALG_NULL,
- .details = {}
- },
- .curveID = TPM2_ECC_NIST_P256,
- .kdf = {
- .scheme = TPM2_ALG_NULL,
- .details = {}
- },
- },
- .unique.ecc = {
- .x.size = 0,
- .y.size = 0
- }
- }
- };
- static const TPM2B_SENSITIVE_CREATE primarySensitive = {
- .sensitive = {
- .userAuth = {
- .size = 0,
- },
- .data = {
- .size = 0,
- }
- }
- };
- static const TPM2B_DATA allOutsideInfo = {
- .size = 0,
- };
- static const TPML_PCR_SELECTION allCreationPCR = {
- .count = 0,
- };
- #define rc_is_key_auth_failed(rc) (((rc) & 0xff) == TPM2_RC_BAD_AUTH)
- #define rc_is_parent_auth_failed(rc) (((rc) & 0xff) == TPM2_RC_AUTH_FAIL)
- static void install_tpm_passphrase(struct openconnect_info *vpninfo, TPM2B_DIGEST *auth, char *pass)
- {
- int pwlen = strlen(pass);
- if (pwlen > sizeof(auth->buffer) - 1) {
- vpn_progress(vpninfo, PRG_ERR,
- _("TPM2 password too long; truncating\n"));
- pwlen = sizeof(auth->buffer) - 1;
- }
- auth->size = pwlen;
- memcpy(auth->buffer, pass, pwlen);
- pass[pwlen] = 0;
- free_pass(&pass);
- }
- static int init_tpm2_primary(struct openconnect_info *vpninfo, struct cert_info *certinfo,
- ESYS_CONTEXT *ctx, ESYS_TR *primaryHandle)
- {
- TSS2_RC r;
- const char *hierarchy_name;
- ESYS_TR hierarchy;
- switch(certinfo->tpm2->parent) {
- case TPM2_RH_OWNER: hierarchy = ESYS_TR_RH_OWNER; hierarchy_name = _("owner"); break;
- case TPM2_RH_NULL: hierarchy = ESYS_TR_RH_NULL; hierarchy_name = _("null"); break;
- case TPM2_RH_ENDORSEMENT:hierarchy = ESYS_TR_RH_ENDORSEMENT; hierarchy_name = _("endorsement"); break;
- case TPM2_RH_PLATFORM: hierarchy = ESYS_TR_RH_PLATFORM; hierarchy_name = _("platform"); break;
- default: return -EINVAL;
- }
- vpn_progress(vpninfo, PRG_DEBUG, _("Creating primary key under %s hierarchy.\n"), hierarchy_name);
- reauth:
- if (certinfo->tpm2->need_ownerauth) {
- char *pass = NULL;
- if (request_passphrase(vpninfo,
- certinfo_string(certinfo, "openconnect_tpm2_hierarchy",
- "openconnect_secondary_tpm2_hierarchy"),
- &pass,
- _("Enter TPM2 %s hierarchy password:"), hierarchy_name))
- return -EPERM;
- install_tpm_passphrase(vpninfo, &certinfo->tpm2->ownerauth, pass);
- certinfo->tpm2->need_ownerauth = 0;
- }
- r = Esys_TR_SetAuth(ctx, hierarchy, &certinfo->tpm2->ownerauth);
- if (r) {
- vpn_progress(vpninfo, PRG_ERR,
- _("TPM2 Esys_TR_SetAuth failed: 0x%x\n"),
- r);
- return -EPERM;
- }
- r = Esys_CreatePrimary(ctx, hierarchy,
- ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
- &primarySensitive,
- certinfo->tpm2->legacy_srk ? &primaryTemplate_legacy : &primaryTemplate,
- &allOutsideInfo, &allCreationPCR,
- primaryHandle, NULL, NULL, NULL, NULL);
- if (rc_is_key_auth_failed(r)) {
- vpn_progress(vpninfo, PRG_DEBUG,
- _("TPM2 Esys_CreatePrimary owner auth failed\n"));
- certinfo->tpm2->need_ownerauth = 1;
- goto reauth;
- } else if (r) {
- vpn_progress(vpninfo, PRG_ERR,
- _("TPM2 Esys_CreatePrimary failed: 0x%x\n"),
- r);
- return -EIO;
- }
- return 0;
- }
- #define parent_is_generated(parent) ((parent) >> TPM2_HR_SHIFT == TPM2_HT_PERMANENT)
- #define parent_is_persistent(parent) ((parent) >> TPM2_HR_SHIFT == TPM2_HT_PERSISTENT)
- static int init_tpm2_key(ESYS_CONTEXT **ctx, ESYS_TR *keyHandle,
- struct openconnect_info *vpninfo, struct cert_info *certinfo)
- {
- ESYS_TR parentHandle = ESYS_TR_NONE;
- TSS2_RC r;
- *keyHandle = ESYS_TR_NONE;
- vpn_progress(vpninfo, PRG_DEBUG,
- _("Establishing connection with TPM.\n"));
- r = Esys_Initialize(ctx, certinfo->tpm2->tcti_ctx, NULL);
- if (r) {
- vpn_progress(vpninfo, PRG_ERR,
- _("TPM2 Esys_Initialize failed: 0x%x\n"),
- r);
- goto error;
- }
- r = Esys_Startup(*ctx, TPM2_SU_CLEAR);
- if (r == TPM2_RC_INITIALIZE) {
- vpn_progress(vpninfo, PRG_DEBUG,
- _("TPM2 was already started up thus false positive failing in tpm2tss log.\n"));
- } else if (r) {
- vpn_progress(vpninfo, PRG_ERR,
- _("TPM2 Esys_Startup failed: 0x%x\n"),
- r);
- goto error;
- }
- if (parent_is_generated(certinfo->tpm2->parent)) {
- if (init_tpm2_primary(vpninfo, certinfo, *ctx, &parentHandle))
- goto error;
- } else {
- r = Esys_TR_FromTPMPublic(*ctx, certinfo->tpm2->parent,
- ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE, &parentHandle);
- if (r) {
- vpn_progress(vpninfo, PRG_ERR,
- _("Esys_TR_FromTPMPublic failed for handle 0x%x: 0x%x\n"),
- certinfo->tpm2->parent, r);
- goto error;
- }
- /* If we don't already have a password (and haven't already authenticated
- * successfully), check the NODA flag on the parent and demand one if DA
- * protection is enabled (since that strongly implies there is a non-empty
- * password). */
- if (!certinfo->tpm2->did_ownerauth && !certinfo->tpm2->ownerauth.size) {
- TPM2B_PUBLIC *pub = NULL;
- r = Esys_ReadPublic(*ctx, parentHandle, ESYS_TR_NONE, ESYS_TR_NONE, ESYS_TR_NONE,
- &pub, NULL, NULL);
- if (!r && !(pub->publicArea.objectAttributes & TPMA_OBJECT_NODA))
- certinfo->tpm2->need_ownerauth = 1;
- Esys_Free(pub);
- }
- reauth:
- if (certinfo->tpm2->need_ownerauth) {
- char *pass = NULL;
- if (request_passphrase(vpninfo,
- certinfo_string(certinfo, "openconnect_tpm2_parent",
- "openconnect_secondary_tpm2_parent"),
- &pass,
- certinfo_string(certinfo, _("Enter TPM2 parent key password:"),
- _("Enter secondary TPM2 parent key password:"))))
- return -EPERM;
- install_tpm_passphrase(vpninfo, &certinfo->tpm2->ownerauth, pass);
- certinfo->tpm2->need_ownerauth = 0;
- }
- r = Esys_TR_SetAuth(*ctx, parentHandle, &certinfo->tpm2->ownerauth);
- if (r) {
- vpn_progress(vpninfo, PRG_ERR,
- _("TPM2 Esys_TR_SetAuth failed: 0x%x\n"),
- r);
- goto error;
- }
- }
- vpn_progress(vpninfo, PRG_DEBUG, _("Loading TPM2 key blob, parent %x.\n"), parentHandle);
- r = Esys_Load(*ctx, parentHandle,
- ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
- &certinfo->tpm2->priv, &certinfo->tpm2->pub,
- keyHandle);
- if (rc_is_parent_auth_failed(r)) {
- vpn_progress(vpninfo, PRG_DEBUG,
- _("TPM2 Esys_Load auth failed\n"));
- certinfo->tpm2->need_ownerauth = 1;
- goto reauth;
- }
- if (r) {
- vpn_progress(vpninfo, PRG_ERR,
- _("TPM2 Esys_Load failed: 0x%x\n"),
- r);
- goto error;
- }
- certinfo->tpm2->did_ownerauth = 1;
- if (parent_is_generated(certinfo->tpm2->parent)) {
- r = Esys_FlushContext(*ctx, parentHandle);
- if (r) {
- vpn_progress(vpninfo, PRG_ERR,
- _("TPM2 Esys_FlushContext for generated primary failed: 0x%x\n"),
- r);
- }
- /* But it's non-fatal. */
- }
- return 0;
- error:
- if (parent_is_generated(certinfo->tpm2->parent) && parentHandle != ESYS_TR_NONE)
- Esys_FlushContext(*ctx, parentHandle);
- if (*keyHandle != ESYS_TR_NONE)
- Esys_FlushContext(*ctx, *keyHandle);
- *keyHandle = ESYS_TR_NONE;
- Esys_Finalize(ctx);
- return -EIO;
- }
- static int auth_tpm2_key(struct openconnect_info *vpninfo, struct cert_info *certinfo,
- ESYS_CONTEXT *ctx, ESYS_TR key_handle)
- {
- TSS2_RC r;
- if (certinfo->tpm2->need_userauth) {
- char *pass = NULL;
- if (certinfo->password) {
- pass = certinfo->password;
- certinfo->password = NULL;
- } else {
- int err = request_passphrase(vpninfo,
- certinfo_string(certinfo, "openconnect_tpm2_key",
- "openconnect_secondary_tpm2_key"),
- &pass,
- certinfo_string(certinfo, _("Enter TPM2 key password:"),
- _("Enter secondary TPM2 key password:")));
- if (err)
- return err;
- }
- install_tpm_passphrase(vpninfo, &certinfo->tpm2->userauth, pass);
- certinfo->tpm2->need_userauth = 0;
- }
- r = Esys_TR_SetAuth(ctx, key_handle, &certinfo->tpm2->userauth);
- if (r) {
- vpn_progress(vpninfo, PRG_ERR,
- _("TPM2 Esys_TR_SetAuth failed: 0x%x\n"),
- r);
- return -EIO;
- }
- return 0;
- }
- int tpm2_rsa_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
- void *_certinfo, unsigned int flags,
- const gnutls_datum_t *data, gnutls_datum_t *sig)
- {
- struct cert_info *certinfo = _certinfo;
- struct openconnect_info *vpninfo = certinfo->vpninfo;
- int ret = GNUTLS_E_PK_SIGN_FAILED;
- ESYS_CONTEXT *ectx = NULL;
- TPM2B_PUBLIC_KEY_RSA digest, *tsig = NULL;
- TPM2B_DATA label = { .size = 0 };
- TPMT_RSA_DECRYPT inScheme = { .scheme = TPM2_ALG_NULL };
- ESYS_TR key_handle = ESYS_TR_NONE;
- TSS2_RC r;
- vpn_progress(vpninfo, PRG_DEBUG,
- _("TPM2 RSA sign function called for %d bytes, algo %s\n"),
- data->size, gnutls_sign_get_name(algo));
- digest.size = certinfo->tpm2->pub.publicArea.unique.rsa.size;
- if (oc_pad_rsasig(vpninfo, algo, digest.buffer, digest.size, data,
- certinfo->tpm2->pub.publicArea.parameters.rsaDetail.keyBits))
- return GNUTLS_E_PK_SIGN_FAILED;
- if (init_tpm2_key(&ectx, &key_handle, vpninfo, certinfo))
- goto out;
- reauth:
- if (auth_tpm2_key(vpninfo, certinfo, ectx, key_handle))
- goto out;
- r = Esys_RSA_Decrypt(ectx, key_handle,
- ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
- &digest, &inScheme, &label, &tsig);
- if (rc_is_key_auth_failed(r)) {
- vpn_progress(vpninfo, PRG_DEBUG,
- _("TPM2 Esys_RSA_Decrypt auth failed\n"));
- certinfo->tpm2->need_userauth = 1;
- goto reauth;
- }
- if (r) {
- vpn_progress(vpninfo, PRG_ERR,
- _("TPM2 failed to generate RSA signature: 0x%x\n"),
- r);
- goto out;
- }
- sig->data = malloc(tsig->size);
- if (!sig->data)
- goto out;
- memcpy(sig->data, tsig->buffer, tsig->size);
- sig->size = tsig->size;
- ret = 0;
- out:
- Esys_Free(tsig);
- if (key_handle != ESYS_TR_NONE)
- Esys_FlushContext(ectx, key_handle);
- if (ectx)
- Esys_Finalize(&ectx);
- return ret;
- }
- int tpm2_ec_sign_hash_fn(gnutls_privkey_t key, gnutls_sign_algorithm_t algo,
- void *_certinfo, unsigned int flags,
- const gnutls_datum_t *data, gnutls_datum_t *sig)
- {
- struct cert_info *certinfo = _certinfo;
- struct openconnect_info *vpninfo = certinfo->vpninfo;
- int ret = GNUTLS_E_PK_SIGN_FAILED;
- ESYS_CONTEXT *ectx = NULL;
- TPM2B_DIGEST digest;
- TPMT_SIGNATURE *tsig = NULL;
- ESYS_TR key_handle = ESYS_TR_NONE;
- TSS2_RC r;
- TPMT_TK_HASHCHECK validation = { .tag = TPM2_ST_HASHCHECK,
- .hierarchy = TPM2_RH_NULL,
- .digest.size = 0 };
- TPMT_SIG_SCHEME inScheme = { .scheme = TPM2_ALG_ECDSA };
- gnutls_datum_t sig_r, sig_s;
- vpn_progress(vpninfo, PRG_DEBUG,
- _("TPM2 EC sign function called for %d bytes.\n"),
- data->size);
- /* FIPS-186-4 §6.4 says "When the length of the output of the hash
- * function is greater than the bit length of n, then the leftmost
- * n bits of the hash function output block shall be used in any
- * calculation using the hash function output during the generation
- * or verification of a digital signature."
- *
- * So GnuTLS is expected to *truncate* a larger hash to fit the
- * curve bit length, and then we lie to the TPM about which hash
- * it was because the TPM only really cares about the size of the
- * data anyway. */
- switch (data->size) {
- case SHA1_SIZE: inScheme.details.ecdsa.hashAlg = TPM2_ALG_SHA1; break;
- case SHA256_SIZE: inScheme.details.ecdsa.hashAlg = TPM2_ALG_SHA256; break;
- case SHA384_SIZE: inScheme.details.ecdsa.hashAlg = TPM2_ALG_SHA384; break;
- case SHA512_SIZE: inScheme.details.ecdsa.hashAlg = TPM2_ALG_SHA512; break;
- default:
- vpn_progress(vpninfo, PRG_ERR,
- _("Unknown TPM2 EC digest size %d for algo 0x%x\n"),
- data->size, algo);
- return GNUTLS_E_PK_SIGN_FAILED;
- }
- memcpy(digest.buffer, data->data, data->size);
- digest.size = data->size;
- if (init_tpm2_key(&ectx, &key_handle, vpninfo, certinfo))
- goto out;
- reauth:
- if (auth_tpm2_key(vpninfo, certinfo, ectx, key_handle))
- goto out;
- r = Esys_Sign(ectx, key_handle,
- ESYS_TR_PASSWORD, ESYS_TR_NONE, ESYS_TR_NONE,
- &digest, &inScheme, &validation,
- &tsig);
- if (rc_is_key_auth_failed(r)) {
- vpn_progress(vpninfo, PRG_DEBUG,
- _("TPM2 Esys_Sign auth failed\n"));
- certinfo->tpm2->need_userauth = 1;
- goto reauth;
- }
- if (r) {
- vpn_progress(vpninfo, PRG_ERR,
- _("TPM2 failed to generate RSA signature: 0x%x\n"),
- r);
- goto out;
- }
- sig_r.data = tsig->signature.ecdsa.signatureR.buffer;
- sig_r.size = tsig->signature.ecdsa.signatureR.size;
- sig_s.data = tsig->signature.ecdsa.signatureS.buffer;
- sig_s.size = tsig->signature.ecdsa.signatureS.size;
- ret = gnutls_encode_rs_value(sig, &sig_r, &sig_s);
- out:
- Esys_Free(tsig);
- if (key_handle != ESYS_TR_NONE)
- Esys_FlushContext(ectx, key_handle);
- if (ectx)
- Esys_Finalize(&ectx);
- return ret;
- }
- int install_tpm2_key(struct openconnect_info *vpninfo, struct cert_info *certinfo,
- gnutls_privkey_t *pkey, gnutls_datum_t *pkey_sig,
- unsigned int parent, int emptyauth, int legacy,
- gnutls_datum_t *privdata, gnutls_datum_t *pubdata)
- {
- TSS2_RC r;
- if (!parent_is_persistent(parent) &&
- parent != TPM2_RH_OWNER && parent != TPM2_RH_NULL &&
- parent != TPM2_RH_ENDORSEMENT && parent != TPM2_RH_PLATFORM) {
- vpn_progress(vpninfo, PRG_ERR,
- _("Invalid TPM2 parent handle 0x%08x\n"), parent);
- return -EINVAL;
- }
- certinfo->tpm2 = calloc(1, sizeof(*certinfo->tpm2));
- if (!certinfo->tpm2)
- return -ENOMEM;
- certinfo->tpm2->parent = parent;
- /* This is the variable which the *IBM* TSS uses, to force it to use
- * the swtpm; it happens in the library automatically. To allow the
- * swtpm test to work on platforms where a real TPM is available,
- * emulate the same thing. Not really intended for production use. */
- const char *tpm_type = getenv("TPM_INTERFACE_TYPE");
- if (tpm_type && !strcmp(tpm_type, "socsim")) {
- vpn_progress(vpninfo, PRG_DEBUG,
- _("Using SWTPM due to TPM_INTERFACE_TYPE environment variable\n"));
- r = Tss2_TctiLdr_Initialize("swtpm", &certinfo->tpm2->tcti_ctx);
- if (r) {
- vpn_progress(vpninfo, PRG_ERR,
- _("TSS2_TctiLdr_Initialize failed for swtpm: 0x%x\n"),
- r);
- goto err_out;
- }
- }
- r = Tss2_MU_TPM2B_PRIVATE_Unmarshal(privdata->data, privdata->size, NULL,
- &certinfo->tpm2->priv);
- if (r) {
- vpn_progress(vpninfo, PRG_ERR,
- _("Failed to import TPM2 private key data: 0x%x\n"),
- r);
- goto err_out;
- }
- r = Tss2_MU_TPM2B_PUBLIC_Unmarshal(pubdata->data, pubdata->size, NULL,
- &certinfo->tpm2->pub);
- if (r) {
- vpn_progress(vpninfo, PRG_ERR,
- _("Failed to import TPM2 public key data: 0x%x\n"),
- r);
- goto err_out;
- }
- certinfo->tpm2->need_userauth = !emptyauth;
- certinfo->tpm2->legacy_srk = legacy;
- switch(certinfo->tpm2->pub.publicArea.type) {
- case TPM2_ALG_RSA: return GNUTLS_PK_RSA;
- case TPM2_ALG_ECC: return GNUTLS_PK_ECC;
- }
- vpn_progress(vpninfo, PRG_ERR,
- _("Unsupported TPM2 key type %d\n"),
- certinfo->tpm2->pub.publicArea.type);
- err_out:
- release_tpm2_ctx(vpninfo, certinfo);
- return -EINVAL;
- }
- uint16_t tpm2_key_curve(struct openconnect_info *vpninfo, struct cert_info *certinfo)
- {
- return certinfo->tpm2->pub.publicArea.parameters.eccDetail.curveID;
- }
- int tpm2_rsa_key_bits(struct openconnect_info *vpninfo, struct cert_info *certinfo)
- {
- return certinfo->tpm2->pub.publicArea.parameters.rsaDetail.keyBits;
- }
- void release_tpm2_ctx(struct openconnect_info *vpninfo, struct cert_info *certinfo)
- {
- if (certinfo->tpm2) {
- clear_mem(certinfo->tpm2->ownerauth.buffer, sizeof(certinfo->tpm2->ownerauth.buffer));
- clear_mem(certinfo->tpm2->userauth.buffer, sizeof(certinfo->tpm2->userauth.buffer));
- if (certinfo->tpm2->tcti_ctx)
- Tss2_TctiLdr_Finalize(&certinfo->tpm2->tcti_ctx);
- free(certinfo->tpm2);
- }
- certinfo->tpm2 = NULL;
- }
|