From patchwork Sat Jan 25 00:15:08 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Mauro S. M. Rodrigues" X-Patchwork-Id: 1229138 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 484GqM0Hb8z9sRR for ; Sat, 25 Jan 2020 11:19:59 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 484GqL4yP6zDqgL for ; Sat, 25 Jan 2020 11:19:58 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=none (no SPF record) smtp.mailfrom=linux.vnet.ibm.com (client-ip=148.163.158.5; helo=mx0a-001b2d01.pphosted.com; envelope-from=maurosr@linux.vnet.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 484GmX0r6szDqgH for ; Sat, 25 Jan 2020 11:17:31 +1100 (AEDT) Received: from pps.filterd (m0098420.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00P07TEv108682 for ; Fri, 24 Jan 2020 19:17:29 -0500 Received: from ppma01dal.us.ibm.com (83.d6.3fa9.ip4.static.sl-reverse.com [169.63.214.131]) by mx0b-001b2d01.pphosted.com with ESMTP id 2xr61rfvpw-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Fri, 24 Jan 2020 19:17:29 -0500 Received: from pps.filterd (ppma01dal.us.ibm.com [127.0.0.1]) by ppma01dal.us.ibm.com (8.16.0.27/8.16.0.27) with SMTP id 00P0AEgc021253 for ; Sat, 25 Jan 2020 00:17:28 GMT Received: from b03cxnp07029.gho.boulder.ibm.com (b03cxnp07029.gho.boulder.ibm.com [9.17.130.16]) by ppma01dal.us.ibm.com with ESMTP id 2xksn7sc9a-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT) for ; Sat, 25 Jan 2020 00:17:28 +0000 Received: from b03ledav004.gho.boulder.ibm.com (b03ledav004.gho.boulder.ibm.com [9.17.130.235]) by b03cxnp07029.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00P0HPNE61800936 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 25 Jan 2020 00:17:25 GMT Received: from b03ledav004.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C1C5B7805C; Sat, 25 Jan 2020 00:17:25 +0000 (GMT) Received: from b03ledav004.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 0E88878060; Sat, 25 Jan 2020 00:17:24 +0000 (GMT) Received: from localhost (unknown [9.85.157.37]) by b03ledav004.gho.boulder.ibm.com (Postfix) with ESMTP; Sat, 25 Jan 2020 00:17:24 +0000 (GMT) From: "Mauro S. M. Rodrigues" To: skiboot@lists.ozlabs.org Date: Fri, 24 Jan 2020 21:15:08 -0300 Message-Id: <20200125001510.708149-14-maurosr@linux.vnet.ibm.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200125001510.708149-1-maurosr@linux.vnet.ibm.com> References: <20200125001510.708149-1-maurosr@linux.vnet.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.572 definitions=2020-01-24_08:2020-01-24, 2020-01-24 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 lowpriorityscore=0 malwarescore=0 bulkscore=0 phishscore=0 impostorscore=0 priorityscore=1501 spamscore=0 mlxlogscore=999 mlxscore=0 clxscore=1015 suspectscore=3 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1911200001 definitions=main-2001250000 Subject: [Skiboot] [PATCH 13/15] Introduce tsscryptombed X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: grimm@linux.ibm.com, nayna@linux.ibm.com Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" This re-implements several crypto operations that TSS uses but rely on openssl. Here we use mbedtls instead. Signed-off-by: Claudio Carvalho Signed-off-by: Mauro S. M. Rodrigues --- libstb/tss2/tsscryptombed.c | 1512 +++++++++++++++++++++++++++++++++++ 1 file changed, 1512 insertions(+) create mode 100644 libstb/tss2/tsscryptombed.c diff --git a/libstb/tss2/tsscryptombed.c b/libstb/tss2/tsscryptombed.c new file mode 100644 index 000000000..05a8cdab3 --- /dev/null +++ b/libstb/tss2/tsscryptombed.c @@ -0,0 +1,1512 @@ +/********************************************************************************/ +/* */ +/* TSS Library Dependent Crypto Support */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* ECC Salt functions written by Bill Martin */ +/* */ +/* (c) Copyright IBM Corporation 2019. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation 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. */ +/********************************************************************************/ + +/* Interface to mbedtls crypto library */ + +#include +#include +#include + +#ifdef TPM_POSIX +#include +#endif +#ifdef TPM_WINDOWS +#include +#endif + +#ifndef TPM_TSS_NORSA +#include +#endif +#include +#ifdef TPM_ALG_SHA1 +#include +#endif +#include +#include +#include +#include + +#include +#include +/* if no RSA and no ECC, don't need any asymmetric support */ +#ifdef TPM_TSS_NORSA +#ifdef TPM_TSS_NOECC +#define TPM_TSS_NOASYM +#endif +#endif + +#ifndef TPM_TSS_NOASYM +#include +#endif + +#include +#include +#include +#include + +#include +#include + +extern int tssVverbose; +extern int tssVerbose; + +/* local prototypes */ + +static void TSS_Error(int irc); +static TPM_RC TSS_Hash_GetMd(mbedtls_md_type_t *mdType, + TPMI_ALG_HASH hashAlg); +#ifndef TPM_TSS_NORSA +static TPM_RC TSS_RsaNew(void **rsaKey); +#endif +static int32_t crypto_seed_bytes(void *ctx __unused, unsigned char *buf, size_t len); +TPM_RC tss_skiboot_crypto_rand_bytes(unsigned char *output, size_t output_len); +static int32_t tss_skiboot_crypto_drbg_init(void); +/* + Initialization +*/ +static struct lock drbg_lock = LOCK_UNLOCKED; +static mbedtls_hmac_drbg_context drbg_ctx; + + +TPM_RC TSS_RandBytes(unsigned char *buffer, uint32_t size){ + + return tss_skiboot_crypto_rand_bytes(buffer, size); /* output random */ +} + +static int32_t crypto_seed_bytes(void *ctx __unused, unsigned char *buf, size_t len){ + return TSS_Get_Random_Number(buf, len); +} + +TPM_RC tss_skiboot_crypto_rand_bytes(unsigned char *output, size_t output_len) +{ + int32_t rc; + + tss_skiboot_crypto_drbg_init(); + lock(&drbg_lock); + rc = mbedtls_hmac_drbg_random(&drbg_ctx, output, output_len); + unlock(&drbg_lock); + + return rc; +} + +static int32_t tss_skiboot_crypto_drbg_init(void) +{ + int32_t rc; + const mbedtls_md_info_t *md_info; + + if (tssVerbose) printf("mbedtls_hmac_drbg_init\n"); + mbedtls_hmac_drbg_init(&drbg_ctx); + + if (tssVerbose) printf("mbedtls_md_info_from_type\n"); + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + assert(md_info); + + if (tssVerbose) printf("mbedtls_hmac_drbg_seed\n"); + rc = mbedtls_hmac_drbg_seed(&drbg_ctx, md_info, + crypto_seed_bytes, NULL, NULL, 0); + if (tssVerbose) printf("mbedtls_hmac_drbg_seed rc=%d\n",rc); + if (rc) { + return rc; + } + + if (tssVerbose) printf("mbedtls_hmac_drbg_set_reseed_interval\n"); + mbedtls_hmac_drbg_set_reseed_interval(&drbg_ctx, 1000); + + if (tssVerbose) printf("mbedtls_hmac_drbg_set_prediction_resistance\n"); + mbedtls_hmac_drbg_set_prediction_resistance(&drbg_ctx, + MBEDTLS_HMAC_DRBG_PR_OFF); + + if (tssVerbose) printf("crypto_drbg_init end\n"); + return rc; +} + + +#ifndef TPM_TSS_NOASYM +static TPM_RC TSS_PkContextNew(mbedtls_pk_context **ctx); +#endif + +/* TSS_PkContextNew() allocates and initializes a mbedtls_pk_context */ + +#ifndef TPM_TSS_NOASYM + +static TPM_RC TSS_PkContextNew(mbedtls_pk_context **ctx) /* freed by caller */ +{ + TPM_RC rc = 0; + + /* sanity check for the free */ + if (rc == 0) { + if (*ctx != NULL) { + if (tssVerbose) printf("TSS_PkContextNew: Error (fatal), token %p should be NULL\n", + *ctx); + rc = TSS_RC_ALLOC_INPUT; + } + } + /* allocate the mbedtls_pk_context */ + if (rc == 0) { + rc = TSS_Malloc((unsigned char **)ctx, sizeof(mbedtls_pk_context)); + } + /* initialize but do not set up the context */ + if (rc == 0) { + mbedtls_pk_init(*ctx); + } + return rc; +} +#endif /* TPM_TSS_NOASYM */ + +/* Error trace */ + +static void TSS_Error(int irc) +{ + int src = 0 - irc; + if (tssVerbose) printf("mbedtls error -%04x\n", src); + return; +} + +/* + Digests +*/ + +/* TSS_Hash_GetMd() maps from a TCG hash algorithm to am mbedtls_md_type_t */ + +static TPM_RC TSS_Hash_GetMd(mbedtls_md_type_t *mdType, + TPMI_ALG_HASH hashAlg) +{ + TPM_RC rc = 0; + + if (rc == 0) { + switch (hashAlg) { +#ifdef TPM_ALG_SHA1 + case TPM_ALG_SHA1: + *mdType = MBEDTLS_MD_SHA1; + break; +#endif +#ifdef TPM_ALG_SHA256 + case TPM_ALG_SHA256: + *mdType = MBEDTLS_MD_SHA256; + break; +#endif +#ifdef TPM_ALG_SHA384 + case TPM_ALG_SHA384: + *mdType = MBEDTLS_MD_SHA384; + break; +#endif +#ifdef TPM_ALG_SHA512 + case TPM_ALG_SHA512: + *mdType = MBEDTLS_MD_SHA512; + break; +#endif + default: + rc = TSS_RC_BAD_HASH_ALGORITHM; + } + } + return rc; +} + +/* On call, digest->hashAlg is the desired hash algorithm + + length 0 is ignored, buffer NULL terminates list. +*/ + +TPM_RC TSS_HMAC_Generate_valist(TPMT_HA *digest, /* largest size of a digest */ + const TPM2B_KEY *hmacKey, + va_list ap) +{ + const mbedtls_md_info_t *mdInfo = NULL; + mbedtls_md_type_t mdType; + mbedtls_md_context_t ctx; + int done = FALSE; + uint8_t *buffer; + TPM_RC rc = 0; + int irc = 0; + int length; + + mbedtls_md_init(&ctx); /* initialize the context */ + /* map from TPM digest algorithm to mbedtls type */ + if (rc == 0) { + rc = TSS_Hash_GetMd(&mdType, digest->hashAlg); + } + if (rc == 0) { + mdInfo = mbedtls_md_info_from_type(mdType); + if (mdInfo == NULL) { + rc = TSS_RC_HMAC; + } + } + if (rc == 0) { + irc = mbedtls_md_setup(&ctx, /* freed @1 */ + mdInfo, + 1); /* flag, hmac used */ + if (irc != 0) { + TSS_Error(irc); + rc = TSS_RC_HMAC; + } + } + if (rc == 0) { + rc = mbedtls_md_hmac_starts(&ctx, + hmacKey->b.buffer, + hmacKey->b.size); + if (irc != 0) { + TSS_Error(irc); + rc = TSS_RC_HMAC; + } + } + while ((rc == 0) && !done) { + length = va_arg(ap, int); /* first vararg is the length */ + buffer = va_arg(ap, unsigned char *); /* second vararg is the array */ + if (buffer != NULL) { /* loop until a NULL buffer terminates */ + if (length < 0) { + if (tssVerbose) printf("TSS_HMAC_Generate: Length is negative\n"); + rc = TSS_RC_HMAC; + } + else { + irc = mbedtls_md_hmac_update(&ctx, buffer, length); + if (irc != 0) { + TSS_Error(irc); + if (tssVerbose) printf("TSS_HMAC_Generate: HMAC_Update failed\n"); + rc = TSS_RC_HMAC; + } + } + } + else { + done = TRUE; + } + } + + if (rc == 0) { + irc = mbedtls_md_hmac_finish(&ctx, (uint8_t *)&digest->digest); + if (irc != 0) { + TSS_Error(irc); + rc = TSS_RC_HMAC; + } + } + mbedtls_md_free(&ctx); /* @1 */ + return rc; +} + +/* + valist is int length, unsigned char *buffer pairs + + length 0 is ignored, buffer NULL terminates list. +*/ + +TPM_RC TSS_Hash_Generate_valist(TPMT_HA *digest, /* largest size of a digest */ + va_list ap) +{ + const mbedtls_md_info_t *mdInfo = NULL; + mbedtls_md_context_t ctx; + mbedtls_md_type_t mdType; + int done = FALSE; + uint8_t *buffer; + TPM_RC rc = 0; + int irc = 0; + int length; + + mbedtls_md_init(&ctx); /* initialize the context */ + /* map from TPM digest algorithm to mbedtls type */ + if (rc == 0) { + rc = TSS_Hash_GetMd(&mdType, digest->hashAlg); + } + if (rc == 0) { + mdInfo = mbedtls_md_info_from_type(mdType); + if (mdInfo == NULL) { + if (tssVerbose) printf("TSS_Hash_Generate: Hash algorithm not found\n"); + rc = TSS_RC_HASH; + } + } + if (rc == 0) { + irc = mbedtls_md_setup(&ctx, /* freed @1 */ + mdInfo, + 0); /* flag, hash used */ + if (irc != 0) { + TSS_Error(irc); + if (tssVerbose) printf("TSS_Hash_Generate: mbedtls_md_setup failed\n"); + rc = TSS_RC_HASH; + } + } + if (rc == 0) { + irc = mbedtls_md_starts(&ctx); + if (irc != 0) { + TSS_Error(irc); + if (tssVerbose) printf("TSS_Hash_Generate: mbedtls_md_starts failed\n"); + rc = TSS_RC_HASH; + } + } + while ((rc == 0) && !done) { + length = va_arg(ap, int); /* first vararg is the length */ + buffer = va_arg(ap, unsigned char *); /* second vararg is the array */ + if (buffer != NULL) { /* loop until a NULL buffer terminates */ + if (length < 0) { + if (tssVerbose) printf("TSS_Hash_Generate: Length is negative\n"); + rc = TSS_RC_HASH; + } + else { + /* if (tssVverbose) TSS_PrintAll("TSS_Hash_Generate:", buffer, length); */ + if (length != 0) { + irc = mbedtls_md_update(&ctx, buffer, length); + if (irc != 0) { + TSS_Error(irc); + rc = TSS_RC_HASH; + } + } + } + } + else { + done = TRUE; + } + } + if (rc == 0) { + irc = mbedtls_md_finish(&ctx, (uint8_t *)&digest->digest); + if (irc != 0) { + TSS_Error(irc); + rc = TSS_RC_HASH; + } + } + mbedtls_md_free(&ctx); /* @1 */ + return rc; +} + +/* + RSA functions +*/ + +#ifndef TPM_TSS_NORSA + +/* NOTE: For mbedtls, TSS_RsaNew() and TSS_RsaFree() are not symmetrical. + + TSS_RsaNew() allocates the inner mbedtls_rsa_context structure. TSS_RsaNew() should not have + been public for OpenSSL, and is tetained but deprecated. It is private for mbedtls. + + TSS_RsaFree(), which is public because it frees the TSS_RSAGeneratePublicTokenI() result, frees + the outer mbedtls_pk_context structure. +*/ + + +/* TSS_RsaNew() allocates an mbedtls RSA key token. + + This abstracts the crypto library specific allocation. + + For mbedtls, rsaKey is a mbedtls_rsa_context structure. +*/ + +TPM_RC TSS_RsaNew(void **rsaKey) +{ + TPM_RC rc = 0; + + /* sanity check for the free */ + if (rc == 0) { + if (*rsaKey != NULL) { + if (tssVerbose) printf("TSS_RsaNew: Error (fatal), token %p should be NULL\n", + *rsaKey); + rc = TSS_RC_ALLOC_INPUT; + } + } + /* construct the private key object */ + if (rc == 0) { + rc = TSS_Malloc((unsigned char **)rsaKey, sizeof(mbedtls_rsa_context)); + } + if (rc == 0) { + mbedtls_rsa_init(*rsaKey, MBEDTLS_RSA_PKCS_V15, 0); + } + return rc; +} + +/* TSS_RsaFree() frees an mbedtls_pk_context RSA key token. + + For compatibility with other crypto libraries, this is the outer wrapper, not the inner RSA + structure. + + This abstracts the crypto library specific free. +*/ + +void TSS_RsaFree(void *rsaKey) +{ + mbedtls_pk_free(rsaKey); + free(rsaKey); + return; +} + +/* TSS_RSAGeneratePublicTokenI() generates an mbedtls_pk_context RSA public key token from n and e + + Free rsa_pub_key using TSS_RsaFree(); +*/ + +TPM_RC TSS_RSAGeneratePublicTokenI(void **rsa_pub_key, /* freed by caller */ + const unsigned char *narr, /* public modulus */ + uint32_t nbytes, + const unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + const mbedtls_pk_info_t *pkInfo = NULL; + mbedtls_rsa_context *rsaCtx = NULL; + TPM_RC rc = 0; + int irc; + + + /* allocate and initialize the mbedtls_pk_context public key token */ + if (rc == 0) { + rc = TSS_PkContextNew((mbedtls_pk_context **)rsa_pub_key); /* freed by caller */ + } + /* allocate and initialize the inner mbedtls_rsa_context */ + if (rc == 0) { + rc = TSS_RsaNew((void **)&rsaCtx); /* freed @1 contexts freed with wrapper */ + } + if (rc == 0) { + irc = mbedtls_rsa_import_raw(rsaCtx, + narr, nbytes, + NULL, 0, /* p */ + NULL, 0, /* q */ + NULL, 0, /* d */ + earr, ebytes); + if (irc != 0) { + TSS_Error(irc); + rc = TSS_RC_RSA_KEY_CONVERT; + } + } + if (rc == 0) { + irc = mbedtls_rsa_complete(rsaCtx); + if (irc != 0) { + TSS_Error(irc); + rc = TSS_RC_RSA_KEY_CONVERT; + } + } + if (rc == 0) { + irc = mbedtls_rsa_check_pubkey(rsaCtx); + if (irc != 0) { + TSS_Error(irc); + rc = TSS_RC_RSA_KEY_CONVERT; + } + } + /* build the mbedtls_pk_context from the mbedtls_rsa_context */ + if (rc == 0) { + pkInfo = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA); + if (pkInfo == NULL) { + if (tssVerbose) printf("TSS_RSAGeneratePublicTokenI: " + "Error in mbedtls_pk_info_from_type()\n"); + rc = TSS_RC_RSA_KEY_CONVERT; + } + } + /* set the metadata */ + if (rc == 0) { + irc = mbedtls_pk_setup(*rsa_pub_key, pkInfo); + if (irc != 0) { + TSS_Error(irc); + if (tssVerbose) printf("TSS_RSAGeneratePublicTokenI: Error in mbedtls_pk_setup()\n"); + rc = TSS_RC_RSA_KEY_CONVERT; + } + } + /* copy the key data */ + if (rc == 0) { + mbedtls_pk_context *pkCtx = (mbedtls_pk_context *)*rsa_pub_key; + mbedtls_rsa_context *rsaPkCtx = mbedtls_pk_rsa(*pkCtx); + memcpy(rsaPkCtx, rsaCtx, sizeof(mbedtls_rsa_context)); + } + free(rsaCtx); + return rc; +} + +/* TSS_RSAPublicEncrypt() pads 'decrypt_data' to 'encrypt_data_size' and encrypts using the public + key 'n, e'. +*/ + +TPM_RC TSS_RSAPublicEncrypt(unsigned char *encrypt_data, /* encrypted data */ + size_t encrypt_data_size, /* size of encrypted data buffer */ + const unsigned char *decrypt_data, /* decrypted data */ + size_t decrypt_data_size, + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes, + unsigned char *p, /* encoding parameter */ + int pl, + TPMI_ALG_HASH halg) /* OAEP hash algorithm */ +{ + unsigned char *padded_data = NULL; + mbedtls_pk_context *pkCtx = NULL; + TPM_RC rc = 0; + int irc; + + if (tssVverbose) printf(" TSS_RSAPublicEncrypt: Input data size %lu\n", + (unsigned long)decrypt_data_size); + /* intermediate buffer for the decrypted but still padded data */ + if (rc == 0) { + rc = TSS_Malloc(&padded_data, encrypt_data_size); /* freed @2 */ + } + /* construct the mbedtls_pk_context public key */ + if (rc == 0) { + rc = TSS_RSAGeneratePublicTokenI((void **)&pkCtx, /* freed @1 */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + if (rc == 0) { + padded_data[0] = 0x00; + rc = TSS_RSA_padding_add_PKCS1_OAEP(padded_data, /* to */ + encrypt_data_size, /* to length */ + decrypt_data, /* from */ + decrypt_data_size, /* from length */ + p, /* encoding parameter */ + pl, /* encoding parameter length */ + halg); /* OAEP hash algorithm */ + } + if (rc == 0) { + mbedtls_rsa_context *rsaCtx = NULL; + if (tssVverbose) + printf(" TSS_RSAPublicEncrypt: Padded data size %lu\n", + (unsigned long)encrypt_data_size); + if (tssVverbose) TSS_PrintAll(" TPM_RSAPublicEncrypt: Padded data", padded_data, + encrypt_data_size); + /* encrypt with public key. Must pad first and then encrypt because the encrypt + * call cannot specify an encoding parameter + * returns the size of the encrypted data. On error, -1 is returned + */ + rsaCtx = mbedtls_pk_rsa(*pkCtx); /* get inner RSA key */ + irc = mbedtls_rsa_public(rsaCtx, /* key */ + padded_data, /* from - the clear text data */ + encrypt_data); /* the padded and encrypted data */ + if (irc != 0) { + TSS_Error(irc); + if (tssVerbose) printf("TSS_RSAPublicEncrypt: Error in mbedtls_rsa_public()\n"); + rc = TSS_RC_RSA_ENCRYPT; + } + } + if (rc == 0) { + if (tssVverbose) printf(" TSS_RSAPublicEncrypt: RSA_public_encrypt() success\n"); + } + TSS_RsaFree(pkCtx); /* @1 */ + free(padded_data); /* @2 */ + return rc; +} + +#endif /* TPM_TSS_NORSA */ + +#ifndef TPM_TSS_NOECC +#if 0 /* Not implemented for mbedtls */ + +/* TSS_GeneratePlatformEphemeralKey sets the EC parameters to NIST P256 for generating the ephemeral + key. Some OpenSSL versions do not come with NIST p256. */ + +static TPM_RC TSS_ECC_GeneratePlatformEphemeralKey(CURVE_DATA *eCurveData, EC_KEY *myecc) +{ + TPM_RC rc = 0; + BIGNUM *p = NULL; + BIGNUM *a = NULL; + BIGNUM *b = NULL; + BIGNUM *x = NULL; + BIGNUM *y = NULL; + BIGNUM *z = NULL; + EC_POINT *G = NULL; /* generator */ + + /* ---------------------------------------------------------- * + * Set the EC parameters to NISTp256. Openssl versions might * + * not have NISTP256 as a possible parameter so we make it * + * possible by setting the curve ourselves. * + * ---------------------------------------------------------- */ + + /* NIST P256 from FIPS 186-3 */ + if (rc == 0) { + if (tssVverbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: Converting p\n"); + rc = TSS_BN_hex2bn(&p, /* freed @1 */ + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"); + } + if (rc == 0) { + if (tssVverbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: Converting a\n"); + rc = TSS_BN_hex2bn(&a, /* freed @2 */ + "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"); + } + if (rc == 0) { + if (tssVverbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: Converting b\n"); + rc = TSS_BN_hex2bn(&b, /* freed @3 */ + "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"); + } + if (rc == 0) { + if (tssVverbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: New group\n"); + eCurveData->G = EC_GROUP_new(EC_GFp_mont_method()); /* freed @4 */ + if (eCurveData->G == NULL) { + if (tssVerbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: " + "Error creating new group\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + if (rc == 0) { + if (tssVverbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: Set the curve prime\n"); + if (EC_GROUP_set_curve_GFp(eCurveData->G, p, a, b, eCurveData->ctx) == 0) { + if (tssVerbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: " + "Error seting curve prime\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + if (rc == 0) { + G = EC_POINT_new(eCurveData->G); /* freed @5 */ + if (G == NULL ){ + if (tssVerbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: EC_POINT_new failed\n"); + rc = TSS_RC_OUT_OF_MEMORY; + } + } + if (rc == 0) { + rc = TSS_BN_hex2bn(&x, /* freed @6 */ + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"); + } + if (rc == 0) { + rc = TSS_BN_hex2bn(&y, /* freed @7 */ + "4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"); + } + if (rc == 0) { + if (EC_POINT_set_affine_coordinates_GFp(eCurveData->G, G, x, y, eCurveData->ctx) == 0) { + if (tssVerbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: Error, " + "Cannot create TPM public point from coordinates\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + /* sanity check to see if point is on the curve */ + if (rc == 0) { + if (EC_POINT_is_on_curve(eCurveData->G, G, eCurveData->ctx) == 0) { + if (tssVerbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: Error, " + "Point not on curve\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + if (rc == 0) { + rc = TSS_BN_hex2bn(&z, /* freed @8 */ + "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"); + } + if (rc == 0) { + if (EC_GROUP_set_generator(eCurveData->G, G, z, BN_value_one()) == 0) { + if (tssVerbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: Error, " + "EC_GROUP_set_generator()\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + if (rc == 0) { + if (EC_GROUP_check(eCurveData->G, eCurveData->ctx) == 0) { + if (tssVerbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: Error, " + "EC_GROUP_check()\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + if (rc == 0) { + if (EC_KEY_set_group(myecc, eCurveData->G) == 0) { + if (tssVerbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: Error, " + "EC_KEY_set_group()\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + if (rc == 0) { +#if 0 + if (tssVverbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: " + "Address of eCurveData->G is %p\n", eCurveData->G); + if (tssVverbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: " + "Address of eCurveData->CTX is %p\n", eCurveData->ctx); +#endif + if (tssVverbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: " + "Set group for key\n"); + } + /* Create the public/private EC key pair here */ + if (rc == 0) { + if (EC_KEY_generate_key(myecc) == 0) { + if (tssVerbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: " + "Error generating the ECC key.\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + if (rc == 0) { + if (!EC_KEY_check_key(myecc)) { + if (tssVerbose) printf("TSS_ECC_GeneratePlatformEphemeralKey: " + "Error on EC_KEY_check_key()\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + if (p != NULL) BN_clear_free(p); /* @1 */ + if (a != NULL) BN_clear_free(a); /* @2 */ + if (b != NULL) BN_clear_free(b); /* @3 */ + if (rc != 0) { + EC_GROUP_free(eCurveData->G); /* @4 */ + EC_POINT_free(G); /* @5 */ + } + if (x != NULL) BN_clear_free(x); /* @6 */ + if (y != NULL) BN_clear_free(y); /* @7 */ + if (z != NULL) BN_clear_free(z); /* @8 */ + + /* don't free the key info. This curve was constructed out of parameters, not of the openssl + library */ + /* EC_KEY_free(myecc) */ + /* EC_POINT_free(G); */ + return rc; +} + +#endif + +/* TSS_ECC_Salt() returns both the plaintext and excrypted salt, based on the salt key bPublic. + + This is currently hard coded to the TPM_ECC_NIST_P256 curve. +*/ + +TPM_RC TSS_ECC_Salt(TPM2B_DIGEST *salt, + TPM2B_ENCRYPTED_SECRET *encryptedSalt, + TPMT_PUBLIC *publicArea) +{ + TPM_RC rc = 0; + salt = salt; + encryptedSalt = encryptedSalt; + publicArea = publicArea; + if (tssVerbose) printf("TSS_ECC_Salt: Unimplemented for mbedtls library\n"); + rc = TSS_RC_COMMAND_UNIMPLEMENTED; +#if 0 + EC_KEY *myecc = NULL; /* ephemeral key */ + const BIGNUM *d_caller; /* ephemeral private key */ + const EC_POINT *callerPointPub; /* ephemeral public key */ + EC_POINT *tpmPointPub = NULL; + BIGNUM *p_tpmX = NULL; + BIGNUM *bigY = NULL; + BIGNUM *zBn = NULL; + EC_POINT *rPoint = NULL; + BIGNUM *thepoint = NULL; + BIGNUM *sharedX = NULL; + BIGNUM *yBn = NULL; + uint32_t sizeInBytes; + uint32_t sizeInBits; + uint8_t *sharedXBin = NULL; + unsigned int lengthSharedXBin; + BIGNUM *p_caller_Xbn = NULL; + BIGNUM *p_caller_Ybn = NULL; + uint8_t *p_caller_Xbin = NULL; + uint8_t *p_caller_Ybin = NULL; + uint8_t *p_tpmXbin = NULL; + unsigned int length_p_caller_Xbin; + unsigned int length_p_caller_Ybin; + unsigned int length_p_tpmXbin; + TPM2B_ECC_PARAMETER sharedX_For_KDFE; + TPM2B_ECC_PARAMETER p_caller_X_For_KDFE; + TPM2B_ECC_PARAMETER p_tpmX_For_KDFE; + CURVE_DATA eCurveData; + + eCurveData.ctx = NULL; /* for free */ + eCurveData.G = NULL; /* this is initialized in TSS_ECC_GeneratePlatformEphemeralKey() at + EC_GROUP_new() but gcc -O3 emits a warning that it's + uninitialized. */ + /* only NIST P256 is currently supported */ + if (rc == 0) { + if ((publicArea->parameters.eccDetail.curveID != TPM_ECC_NIST_P256)) { + if (tssVerbose) + printf("TSS_ECC_Salt: ECC curve ID %04x not supported\n", + publicArea->parameters.eccDetail.curveID); + rc = TSS_RC_BAD_SALT_KEY; + } + } + if (rc == 0) { + myecc = EC_KEY_new(); /* freed @1 */ + if (myecc == NULL) { + if (tssVerbose) printf("TSS_ECC_Salt: EC_KEY_new failed\n"); + rc = TSS_RC_OUT_OF_MEMORY; + } + } + if (rc == 0) { + eCurveData.ctx = BN_CTX_new(); /* freed @16 */ + if (eCurveData.ctx == NULL) { + if (tssVerbose) printf("TSS_ECC_Salt: BN_CTX_new failed\n"); + rc = TSS_RC_OUT_OF_MEMORY; + } + } + /* Generate the TSS EC ephemeral key pair outside the TPM for the salt. The public part of this + key is actually the 'encrypted' salt. */ + if (rc == 0) { + if (tssVverbose) printf("TSS_ECC_Salt: " + "Calling TSS_ECC_GeneratePlatformEphemeralKey\n"); + rc = TSS_ECC_GeneratePlatformEphemeralKey(&eCurveData, myecc); + } + if (rc == 0) { + d_caller = EC_KEY_get0_private_key(myecc); /* ephemeral private key */ + callerPointPub = EC_KEY_get0_public_key(myecc); /* ephemeral public key */ + } + /* validate that the public point is on the NIST P-256 curve */ + if (rc == 0) { + if (EC_POINT_is_on_curve(eCurveData.G, callerPointPub, eCurveData.ctx) == 0) { + if (tssVerbose) printf("TSS_ECC_Salt: " + "Generated point not on curve\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + if (rc == 0) { + /* let d_caller be private scalar and P_caller be public point */ + /* p_tpm is public point. p_tpmX is to be X-coordinate and p_tpmY the + Y-coordinate */ + + /* Allocate the space for P_tpm */ + tpmPointPub = EC_POINT_new(eCurveData.G); /* freed @2 */ + if (tpmPointPub == NULL) { + if (tssVerbose) printf("TSS_ECC_Salt: EC_POINT_new failed\n"); + rc = TSS_RC_OUT_OF_MEMORY; + } + } + /* grab the public point x and y using the parameters passed in */ + if (rc == 0) { + if (tssVverbose) printf("TSS_ECC_Salt: " + "Salt key sizes are X: %d and Y: %d\n", + publicArea->unique.ecc.x.t.size, + publicArea->unique.ecc.y.t.size); + p_tpmX = BN_bin2bn((const unsigned char *)&publicArea->unique.ecc.x.t.buffer, + publicArea->unique.ecc.x.t.size, NULL); /* freed @3 */ + if (p_tpmX == NULL) { + if (tssVerbose) printf("TSS_ECC_Salt: BN_bin2bn p_tpmX failed\n"); + rc = TSS_RC_OUT_OF_MEMORY; + } + } + if (rc == 0) { + bigY = BN_bin2bn((const unsigned char*)&publicArea->unique.ecc.y.t.buffer, + publicArea->unique.ecc.y.t.size, bigY); /* freed @15 */ + if (bigY == NULL) { + if (tssVerbose) printf("TSS_ECC_Salt: BN_bin2bn bigY failed\n"); + rc = TSS_RC_OUT_OF_MEMORY; + } + } + if (rc == 0) { + if (tssVverbose) printf("TSS_ECC_Salt: " + "Salt public key X %s\n", BN_bn2hex(p_tpmX)); + if (tssVverbose) printf("TSS_ECC_Salt: " + "Salt public key Y %s\n", BN_bn2hex(bigY)); + } + /* Create the openssl form of the TPM salt public key as EC_POINT using coordinates */ + if (rc == 0) { + if (EC_POINT_set_affine_coordinates_GFp + (eCurveData.G, tpmPointPub, p_tpmX, bigY, eCurveData.ctx) == 0) { + if (tssVerbose) printf("TSS_ECC_Salt: " + "Cannot create TPM public point from coordinates\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + /* RFC 2440 Named curve prime256v1 */ + if (rc == 0) { + rc = TSS_BN_hex2bn(&zBn, /* freed @4 */ + "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"); + } + /* add the generator z to the group we are constructing */ + if (rc == 0) { + if (EC_GROUP_set_generator(eCurveData.G, tpmPointPub, zBn, BN_value_one()) == 0) { + if(tssVerbose) printf ("TSS_ECC_Salt: " + "Error EC_GROUP_set_generator()\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + /* Check for validity of our group */ + if (rc == 0) { + if (EC_GROUP_check(eCurveData.G, eCurveData.ctx) == 0) { + if (tssVerbose) printf("TSS_ECC_Salt: " + "ec_group_check() failed\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + /* Check to see if what we think is the TPM point is on the curve */ + if (rc == 0) { + if (EC_POINT_is_on_curve(eCurveData.G, tpmPointPub, eCurveData.ctx) == 0) { + if (tssVerbose) printf("TSS_ECC_Salt: Error, " + "Point not on curve\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + else { + if (tssVverbose) printf("TSS_ECC_Salt: " + "Validated that TPM EC point is on curve\n"); + } + } + if (rc == 0) { + rPoint = EC_POINT_new(eCurveData.G); + if (rPoint == NULL) { + if (tssVerbose) printf("TSS_ECC_Salt: " + "Cannot create rPoint\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + /* Point multiply the TPM public point by the ephemeral scalar. This will produce the + point from which we get the shared X coordinate, which we keep for use in KDFE. The + TPM will calculate the same X. */ + if (rc == 0) { + if (EC_POINT_mul(eCurveData.G, rPoint, NULL, tpmPointPub, + d_caller, eCurveData.ctx) == 0) { + if (tssVerbose) printf("TSS_ECC_Salt: " + "EC_POINT_mul failed\n") ; + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + else { + if (tssVverbose) printf("TSS_ECC_Salt: " + "EC_POINT_mul() succeeded\n"); + } + } + /* Check to see if calculated point is on the curve, just for extra sanity */ + if (rc == 0) { + if (EC_POINT_is_on_curve(eCurveData.G, rPoint, eCurveData.ctx) == 0) { + if (tssVerbose) printf("TSS_ECC_Salt: Error," + "Point r is not on curve\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + else { + if (tssVverbose) printf("TSS_ECC_Salt: " + "Point calculated by EC_POINT_mul() is on the curve\n"); + } + } + if (rc == 0) { + thepoint = EC_POINT_point2bn(eCurveData.G, rPoint, POINT_CONVERSION_UNCOMPRESSED, + NULL, eCurveData.ctx); /* freed @6 */ + if (thepoint == NULL) { + if (tssVerbose) printf("TSS_ECC_Salt: " + "EC_POINT_point2bn thepoint failed\n"); + rc = TSS_RC_OUT_OF_MEMORY; + } + } + /* get sharedX */ + if (rc == 0) { + rc = TSS_BN_new(&sharedX); /* freed @7 */ + } + if (rc == 0) { + rc = TSS_BN_new(&yBn); /* freed @8 */ + } + if (rc == 0) { + if (EC_POINT_get_affine_coordinates_GFp(eCurveData.G, rPoint, + sharedX, yBn, eCurveData.ctx) == 0) { + if (tssVerbose) printf("TSS_ECC_Salt: " + "EC_POINT_get_affine_coordinates_GFp() failed\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + if (rc == 0) { + sizeInBytes = TSS_GetDigestSize(publicArea->nameAlg); + sizeInBits = sizeInBytes * 8; + rc = TSS_Malloc(&sharedXBin, BN_num_bytes(sharedX)); /* freed @9 */ + } + if (rc == 0) { + lengthSharedXBin = (unsigned int)BN_bn2bin(sharedX, sharedXBin); + if (tssVverbose) TSS_PrintAll("TSS_ECC_Salt: sharedXBin", + sharedXBin, + lengthSharedXBin); + } + /* encrypted salt is just the ephemeral public key */ + if (rc == 0) { + rc = TSS_BN_new(&p_caller_Xbn); /* freed 10 */ + } + if (rc == 0) { + rc = TSS_BN_new(&p_caller_Ybn); /* freed @11 */ + } + if (rc == 0) { + if (tssVverbose) printf("TSS_ECC_Salt: " + "Allocated space for ephemeral BIGNUM X, Y\n"); + } + /* Get the X-coordinate and Y-Coordinate */ + if (rc == 0) { + if (EC_POINT_get_affine_coordinates_GFp(eCurveData.G, callerPointPub, + p_caller_Xbn, p_caller_Ybn, + eCurveData.ctx) == 0) { + if (tssVerbose) printf("TSS_ECC_Salt: " + "EC_POINT_get_affine_coordinates_GFp() failed\n"); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + else { + if (tssVverbose) printf("TSS_ECC_Salt: " + "Retrieved X and Y coordinates from ephemeral public\n"); + } + } + if (rc == 0) { + rc = TSS_Malloc(&p_caller_Xbin, BN_num_bytes(p_caller_Xbn)); /* freed @12 */ + } + if (rc == 0) { + rc = TSS_Malloc(&p_caller_Ybin , BN_num_bytes(p_caller_Ybn)); /* freed @13 */ + } + if (rc == 0) { + if (tssVverbose) printf("TSS_ECC_Salt: " + "Allocated space for ephemeral binary X and y\n"); + } + if (rc == 0) { + rc = TSS_Malloc(&p_tpmXbin, BN_num_bytes(p_tpmX)); /* freed @14 */ + } + if (rc == 0) { + length_p_tpmXbin = (unsigned int)BN_bn2bin(p_tpmX, p_tpmXbin); + if (tssVverbose) TSS_PrintAll("TSS_ECC_Salt: p_tpmXbin ", + p_tpmXbin, + length_p_tpmXbin); + length_p_caller_Xbin = (unsigned int)BN_bn2bin(p_caller_Xbn, p_caller_Xbin); + if (tssVverbose) TSS_PrintAll("TSS_ECC_Salt: p_caller_Xbin", + p_caller_Xbin, + length_p_caller_Xbin); + length_p_caller_Ybin = (unsigned int)BN_bn2bin(p_caller_Ybn, p_caller_Ybin); + if (tssVverbose) TSS_PrintAll("TSS_ECC_Salt: p_caller_Ybin", + p_caller_Ybin, + length_p_caller_Ybin); + } + /* in->encryptedSalt TPM2B_ENCRYPTED_SECRET is a size and TPMU_ENCRYPTED_SECRET secret. + TPMU_ENCRYPTED_SECRET is a TPMS_ECC_POINT + TPMS_ECC_POINT has two TPMB_ECC_PARAMETER, x and y + */ + if (rc == 0) { + /* TPMS_ECC_POINT 256/8 is a hard coded value for NIST P256, the only curve + currently supported */ + uint8_t *secret = encryptedSalt->t.secret; /* TPMU_ENCRYPTED_SECRET pointer for + clarity */ + /* TPM2B_ENCRYPTED_SECRET size */ + encryptedSalt->t.size = sizeof(uint16_t) + (256/8) + sizeof(uint16_t) + (256/8); + /* leading zeros, because some points may be less than 32 bytes */ + memset(secret, 0, sizeof(TPMU_ENCRYPTED_SECRET)); + /* TPMB_ECC_PARAMETER X point */ + *(uint16_t *)(secret) = htons(256/8); + memcpy(secret + + sizeof(uint16_t) + (256/8) - length_p_caller_Xbin, + p_caller_Xbin, length_p_caller_Xbin); + /* TPMB_ECC_PARAMETER Y point */ + *(uint16_t *)(secret + sizeof(uint16_t) + (256/8)) = htons(256/8); + memcpy(secret + + sizeof(uint16_t) + (256/8) + + sizeof(uint16_t) + (256/8) - length_p_caller_Ybin, + p_caller_Ybin, length_p_caller_Ybin); + } + if (rc == 0) { + if (tssVverbose) TSS_PrintAll("TSS_ECC_Salt: ECC encrypted salt", + encryptedSalt->t.secret, + encryptedSalt->t.size); + } + /* TPM2B_ECC_PARAMETER sharedX_For_KDFE */ + if (rc == 0) { + if (lengthSharedXBin > 32) { + if (tssVerbose) printf("TSS_ECC_Salt: " + "lengthSharedXBin %u too large\n", + lengthSharedXBin); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + if (rc == 0) { + sharedX_For_KDFE.t.size = 32; + memset(sharedX_For_KDFE.t.buffer, 0, sizeof(sharedX_For_KDFE.t.buffer)); + memcpy(sharedX_For_KDFE.t.buffer + 32 - lengthSharedXBin, + sharedXBin, lengthSharedXBin); + if (tssVverbose) TSS_PrintAll("TSS_ECC_Salt: sharedX_For_KDFE", + sharedX_For_KDFE.t.buffer, + sharedX_For_KDFE.t.size); + } + /* TPM2B_ECC_PARAMETER p_caller_X_For_KDFE */ + if (rc == 0) { + if (length_p_caller_Xbin > 32) { + if (tssVerbose) printf("TSS_ECC_Salt: " + "length_p_caller_Xbin %u too large\n", + length_p_caller_Xbin); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + if (rc == 0) { + p_caller_X_For_KDFE.t.size = 32; + memset(p_caller_X_For_KDFE.t.buffer, 0, sizeof(p_caller_X_For_KDFE.t.buffer)); + memcpy(p_caller_X_For_KDFE.t.buffer + 32 - length_p_caller_Xbin, + p_caller_Xbin, length_p_caller_Xbin); + if (tssVverbose) TSS_PrintAll("TSS_ECC_Salt: p_caller_X_For_KDFE", + p_caller_X_For_KDFE.t.buffer, + p_caller_X_For_KDFE.t.size); + } + /* p_tpmX_For_KDFE */ + if (rc == 0) { + if (length_p_tpmXbin > 32) { + if (tssVerbose) printf("TSS_ECC_Salt: " + "length_p_tpmXbin %u too large\n", + length_p_tpmXbin); + rc = TSS_RC_EC_EPHEMERAL_FAILURE; + } + } + if (rc == 0) { + p_tpmX_For_KDFE .t.size = 32; + memset(p_tpmX_For_KDFE.t.buffer, 0, sizeof(p_tpmX_For_KDFE.t.buffer)); + memcpy(p_tpmX_For_KDFE.t.buffer + 32 - length_p_tpmXbin, + p_tpmXbin, length_p_tpmXbin); + if (tssVverbose) TSS_PrintAll("TSS_ECC_Salt: p_tpmX_For_KDFE", + p_tpmX_For_KDFE.t.buffer, + p_tpmX_For_KDFE.t.size); + } + if (rc == 0) { + if (tssVverbose) printf("TSS_ECC_Salt: " + "Calling TSS_KDFE\n"); + /* TPM2B_DIGEST salt size is the largest supported digest algorithm. + This has already been validated when unmarshaling the Name hash algorithm. + */ + /* salt = KDFe(tpmKey_NameAlg, sharedX, "SECRET", P_caller, P_tpm, + tpmKey_NameAlgSizeBits) */ + salt->t.size = sizeInBytes; + rc = TSS_KDFE((uint8_t *)&salt->t.buffer, /* KDFe output */ + publicArea->nameAlg, /* hash algorithm */ + &sharedX_For_KDFE.b, /* Z (key) */ + "SECRET", /* KDFe label */ + &p_caller_X_For_KDFE.b, /* context U */ + &p_tpmX_For_KDFE.b, /* context V */ + sizeInBits); /* required size of key in bits */ + } + if (rc == 0) { + if (tssVverbose) TSS_PrintAll("TSS_ECC_Salt: salt", + (uint8_t *)&salt->t.buffer, + salt->t.size); + } + /* cleanup */ + if (myecc != NULL) EC_KEY_free(myecc); /* @1 */ + if (tpmPointPub != NULL) EC_POINT_free(tpmPointPub); /* @2 */ + if (p_tpmX != NULL) BN_clear_free(p_tpmX); /* @3 */ + if (zBn != NULL) BN_clear_free(zBn); /* @4 */ + if (rPoint != NULL) EC_POINT_free(rPoint); /* @5 */ + if (thepoint != NULL) BN_clear_free(thepoint); /* @6 */ + if (sharedX != NULL) BN_clear_free(sharedX); /* @7 */ + if (yBn != NULL) BN_clear_free(yBn); /* @8 */ + free(sharedXBin); /* @9 */ + if (p_caller_Xbn != NULL) BN_clear_free(p_caller_Xbn); /* @10 */ + if (p_caller_Ybn != NULL) BN_clear_free(p_caller_Ybn); /* @11 */ + free(p_caller_Xbin); /* @12 */ + free(p_caller_Ybin); /* @13 */ + free(p_tpmXbin); /* @14 */ + if (bigY != NULL) BN_clear_free(bigY); /* @15 */ + if (eCurveData.ctx != NULL) BN_CTX_free(eCurveData.ctx); /* @16 */ +#endif /* 0 */ + return rc; +} + +#endif /* TPM_TSS_NOECC */ + +/* + AES +*/ + +TPM_RC TSS_AES_GetEncKeySize(size_t *tssSessionEncKeySize) +{ + *tssSessionEncKeySize = sizeof(mbedtls_aes_context); + return 0; +} +TPM_RC TSS_AES_GetDecKeySize(size_t *tssSessionDecKeySize) +{ + *tssSessionDecKeySize = sizeof(mbedtls_aes_context); + return 0; +} + +#define TSS_AES_KEY_BITS 128 + +#ifndef TPM_TSS_NOCRYPTO +#ifndef TPM_TSS_NOFILE + +TPM_RC TSS_AES_KeyGenerate(void *tssSessionEncKey, + void *tssSessionDecKey) +{ + TPM_RC rc = 0; + int irc; + unsigned char userKey[AES_128_BLOCK_SIZE_BYTES]; + const char *envKeyString = NULL; + unsigned char *envKeyBin = NULL; + size_t envKeyBinLen; + + if (rc == 0) { + envKeyString = getenv("TPM_SESSION_ENCKEY"); + } + if (envKeyString == NULL) { + /* If the env variable TPM_SESSION_ENCKEY is not set, generate a random key for this + TSS_CONTEXT */ + if (rc == 0) { + rc = TSS_RandBytes(userKey, AES_128_BLOCK_SIZE_BYTES); + } + } + /* The env variable TPM_SESSION_ENCKEY can set a (typically constant) encryption key. This is + useful for scripting, where the env variable is set to a random seed at the beginning of the + script. */ + else { + /* hexascii to binary */ + if (rc == 0) { + rc = TSS_Array_Scan(&envKeyBin, /* freed @1 */ + &envKeyBinLen, envKeyString); + } + /* range check */ + if (rc == 0) { + if (envKeyBinLen != AES_128_BLOCK_SIZE_BYTES) { + if (tssVerbose) + printf("TSS_AES_KeyGenerate: Error, env variable length %lu not %lu\n", + (unsigned long)envKeyBinLen, (unsigned long)sizeof(userKey)); + rc = TSS_RC_BAD_PROPERTY_VALUE; + + } + } + /* copy the binary to the common userKey for use below */ + if (rc == 0) { + memcpy(userKey, envKeyBin, envKeyBinLen); + } + } + /* translate to an mbedtls key token */ + if (rc == 0) { + mbedtls_aes_init(tssSessionEncKey); + irc = mbedtls_aes_setkey_enc(tssSessionEncKey, userKey, TSS_AES_KEY_BITS); + if (irc != 0) { + TSS_Error(irc); + if (tssVerbose) + printf("TSS_AES_KeyGenerate: Error setting mbedtls AES encryption key\n"); + rc = TSS_RC_AES_KEYGEN_FAILURE; + } + } + if (rc == 0) { + mbedtls_aes_init(tssSessionDecKey); + irc = mbedtls_aes_setkey_dec(tssSessionDecKey, userKey, TSS_AES_KEY_BITS); + if (irc != 0) { + TSS_Error(irc); + if (tssVerbose) { + printf("TSS_AES_KeyGenerate: Error setting mbedtls AES decryption key\n"); + } + rc = TSS_RC_AES_KEYGEN_FAILURE; + } + } + free(envKeyBin); /* @1 */ + return rc; +} + +#endif +#endif + +/* TSS_AES_Encrypt() is AES non-portable code to encrypt 'decrypt_data' to 'encrypt_data' using CBC. + This function uses the session encryption key for encrypting session state. + + The stream is padded as per PKCS#7 / RFC2630 + + 'encrypt_data' must be free by the caller +*/ + +#ifndef TPM_TSS_NOFILE + +TPM_RC TSS_AES_Encrypt(void *tssSessionEncKey, + unsigned char **encrypt_data, /* output, caller frees */ + uint32_t *encrypt_length, /* output */ + const unsigned char *decrypt_data, /* input */ + uint32_t decrypt_length) /* input */ +{ + unsigned char ivec[AES_128_BLOCK_SIZE_BYTES]; /* initial chaining vector */ + unsigned char *decrypt_data_pad; + uint32_t pad_length; + TPM_RC rc = 0; + int irc; + + decrypt_data_pad = NULL; /* freed @1 */ + if (rc == 0) { + /* calculate the pad length and padded data length */ + pad_length = AES_128_BLOCK_SIZE_BYTES - (decrypt_length % AES_128_BLOCK_SIZE_BYTES); + *encrypt_length = decrypt_length + pad_length; + /* allocate memory for the encrypted response */ + rc = TSS_Malloc(encrypt_data, *encrypt_length); + } + /* allocate memory for the padded decrypted data */ + if (rc == 0) { + rc = TSS_Malloc(&decrypt_data_pad, *encrypt_length); + } + /* pad the decrypted clear text data */ + if (rc == 0) { + /* unpadded original data */ + memcpy(decrypt_data_pad, decrypt_data, decrypt_length); + /* last gets pad = pad length */ + memset(decrypt_data_pad + decrypt_length, pad_length, pad_length); + /* set the IV */ + memset(ivec, 0, sizeof(ivec)); + /* encrypt the padded input to the output */ + irc = mbedtls_aes_crypt_cbc(tssSessionEncKey, + MBEDTLS_AES_ENCRYPT, + *encrypt_length, + ivec, + decrypt_data_pad, + *encrypt_data); + if (irc != 0) { + TSS_Error(irc); + if (tssVerbose) printf("TSS_AES_Encrypt: Encryption failure -%04x\n", -irc); + rc = TSS_RC_AES_ENCRYPT_FAILURE; + } + } + free(decrypt_data_pad); /* @1 */ + return rc; +} + +#endif /* TPM_TSS_NOFILE */ + +/* TSS_AES_Decrypt() is AES non-portable code to decrypt 'encrypt_data' to 'decrypt_data' using CBC. + This function uses the session encryption key for decrypting session state. + + The stream must be padded as per PKCS#7 / RFC2630 + + decrypt_data must be free by the caller +*/ + +#ifndef TPM_TSS_NOFILE + +TPM_RC TSS_AES_Decrypt(void *tssSessionDecKey, + unsigned char **decrypt_data, /* output, caller frees */ + uint32_t *decrypt_length, /* output */ + const unsigned char *encrypt_data, /* input */ + uint32_t encrypt_length) /* input */ +{ + TPM_RC rc = 0; + int irc; + uint32_t pad_length; + uint32_t i; + unsigned char *pad_data; + unsigned char ivec[AES_128_BLOCK_SIZE_BYTES]; /* initial chaining vector */ + + /* sanity check encrypted length */ + if (rc == 0) { + if (encrypt_length < AES_128_BLOCK_SIZE_BYTES) { + if (tssVerbose) printf("TSS_AES_Decrypt: Error, bad length %u\n", + encrypt_length); + rc = TSS_RC_AES_DECRYPT_FAILURE; + } + } + /* allocate memory for the padded decrypted data */ + if (rc == 0) { + rc = TSS_Malloc(decrypt_data, encrypt_length); + } + /* decrypt the input to the padded output */ + if (rc == 0) { + /* set the IV */ + memset(ivec, 0, sizeof(ivec)); + /* decrypt the padded input to the output */ + irc = mbedtls_aes_crypt_cbc(tssSessionDecKey, + MBEDTLS_AES_DECRYPT, + encrypt_length, + ivec, + encrypt_data, + *decrypt_data); + } + /* get the pad length */ + if (rc == 0) { + /* get the pad length from the last byte */ + pad_length = (uint32_t)*(*decrypt_data + encrypt_length - 1); + /* sanity check the pad length */ + if ((pad_length == 0) || + (pad_length > AES_128_BLOCK_SIZE_BYTES)) { + if (tssVerbose) printf("TSS_AES_Decrypt: Error, illegal pad length\n"); + rc = TSS_RC_AES_DECRYPT_FAILURE; + } + } + if (rc == 0) { + /* get the unpadded length */ + *decrypt_length = encrypt_length - pad_length; + /* pad starting point */ + pad_data = *decrypt_data + *decrypt_length; + /* sanity check the pad */ + for (i = 0 ; (rc == 0) && (i < pad_length) ; i++, pad_data++) { + if (*pad_data != pad_length) { + if (tssVerbose) printf("TSS_AES_Decrypt: Error, bad pad %02x at index %u\n", + *pad_data, i); + rc = TSS_RC_AES_DECRYPT_FAILURE; + } + } + } + return rc; +} + +#endif /* TPM_TSS_NOFILE */ + +/* TSS_AES_EncryptCFB() is the unpadded AES used for command parameter encryption. + + The input and output are the same length. +*/ + +TPM_RC TSS_AES_EncryptCFB(uint8_t *dOut, /* OUT: the encrypted data */ + uint32_t keySizeInBits, /* IN: key size in bits */ + uint8_t *key, /* IN: key buffer */ + uint8_t *iv, /* IN/OUT: IV for decryption */ + uint32_t dInSize, /* IN: data size */ + uint8_t *dIn) /* IN: data buffer */ +{ + mbedtls_aes_context aes_ctx; + TPM_RC rc = 0; + int irc; + + mbedtls_aes_init(&aes_ctx); + if (rc == 0) { + irc = mbedtls_aes_setkey_enc(&aes_ctx, key, keySizeInBits); /* freed @1 */ + if (irc != 0) { + TSS_Error(irc); + rc = TSS_RC_AES_KEYGEN_FAILURE; + } + } + if (rc == 0) { + size_t iv_off = 0; + irc = mbedtls_aes_crypt_cfb128(&aes_ctx, + MBEDTLS_AES_ENCRYPT, + dInSize, + &iv_off, + iv, + dIn, + dOut); + if (irc != 0) { + TSS_Error(irc); + if (tssVerbose) printf("TSS_AES_EncryptCFB: Encryption failure -%04x\n", -irc); + rc = TSS_RC_AES_ENCRYPT_FAILURE; + } + } + mbedtls_aes_free(&aes_ctx); /* @1 */ + return rc; +} + +/* TSS_AES_DecryptCFB() is the unpadded AES used for response parameter decryption. + + The input and output are the same length. +*/ + +TPM_RC TSS_AES_DecryptCFB(uint8_t *dOut, /* OUT: the decrypted data */ + uint32_t keySizeInBits, /* IN: key size in bits */ + uint8_t *key, /* IN: key buffer */ + uint8_t *iv, /* IN/OUT: IV for decryption. */ + uint32_t dInSize, /* IN: data size */ + uint8_t *dIn) /* IN: data buffer */ +{ + mbedtls_aes_context aes_ctx; + TPM_RC rc = 0; + int irc; + + if (tssVverbose) TSS_PrintAll("TSS_AES_DecryptCFB:", key, keySizeInBits/8); + mbedtls_aes_init(&aes_ctx); + if (rc == 0) { + irc = mbedtls_aes_setkey_enc(&aes_ctx, key, keySizeInBits); /* freed @1 */ + if (irc != 0) { + TSS_Error(irc); + rc = TSS_RC_AES_KEYGEN_FAILURE; + } + } + if (rc == 0) { + size_t iv_off = 0; + irc = mbedtls_aes_crypt_cfb128(&aes_ctx, + MBEDTLS_AES_DECRYPT, + dInSize, + &iv_off, + iv, + dIn, + dOut); + if (irc != 0) { + TSS_Error(irc); + if (tssVerbose) printf("TSS_AES_DecryptCFB: Decryption failure -%04x\n", -irc); + rc = TSS_RC_AES_DECRYPT_FAILURE; + } + } + mbedtls_aes_free(&aes_ctx); /* @1 */ + return rc; +}