diff --git a/.gitignore b/.gitignore index 7b7715b2..2abec1b5 100644 --- a/.gitignore +++ b/.gitignore @@ -219,3 +219,5 @@ hash/sha256-hash sslkeylog.log server-tls13 client-tls13 + +tpm/evp_tpm diff --git a/tpm/Makefile b/tpm/Makefile new file mode 100644 index 00000000..868fbc51 --- /dev/null +++ b/tpm/Makefile @@ -0,0 +1,14 @@ +CC=gcc +WOLF_INSTALL_DIR=/usr/local +CFLAGS=-I$(WOLF_INSTALL_DIR)/include -Wall +LIBS=-L$(WOLF_INSTALL_DIR)/lib -lwolfssl -lwolftpm + +all:evp_tpm + +evp_tpm:evp_tpm.o + $(CC) -o $@ $^ $(CFLAGS) $(CPPFLAGS) $(LIBS) + +.PHONY: clean all + +clean: + rm -f *.o evp_tpm diff --git a/tpm/README.md b/tpm/README.md new file mode 100644 index 00000000..c071997f --- /dev/null +++ b/tpm/README.md @@ -0,0 +1,61 @@ +# TPM Examples + +## EVP with TPM Example (evp_tpm.c) + +This example shows use of the EVP compatibility layer with the crypto callbacks and TPM. +Note: Requires PR https://github.com/wolfSSL/wolfssl/pull/4333 + +### Building wolfSSL + +``` +% ./configure --enable-opensslextra --enable-wolftpm --enable-cryptocb [--enable-debug] [--prefix=DIR] +% make +% make install +``` + +### Building wolfTPM + +``` +% ./configure [--enable-swtpm] [--enable-debug] [--prefix=DIR] +% make +% make install +``` + +### Building evp_tpm example + +```sh +% make +gcc -I/usr/local/include -Wall -c -o evp_tpm.o evp_tpm.c +gcc -o evp_tpm evp_tpm.o -I/usr/local/include -Wall -L/usr/local/lib -lwolfssl -lwolftpm +``` + +### Example Output + +```sh +% ./evp_tpm +wolfSSL Entering wolfCrypt_Init +TPM2: Caps 0x00000000, Did 0x0000, Vid 0x0000, Rid 0x 0 +TPM2_Startup pass +TPM2_SelfTest pass +TPM2_ReadPublic Handle 0x81000201: pub 90, name 34, qualifiedName 34 +Loading SRK: Storage 0x81000201 (90 bytes) +TPM2_Create key: pub 88, priv 126 +Public Area (size 88): + Type: ECC (0x23), name: SHA256 (0xB), objAttr: 0x40460, authPolicy sz: 0 + ECC: sym algorithm: NULL (0x10), sym keyBits: 0, sym mode: Unknown (0x0) + scheme: ECDSA (0x18), scheme hash: SHA256 (0xB), curveID: size 32, 0x3 + KDF scheme: NULL (0x10), KDF alg: Unknown (0x0), unique X/Y size 32/32 +TPM2_Load Key Handle 0x80000002 +Create/Load ECC Key: Handle 0x80000002 (88 bytes) +EVP_MD_ecc_signing() +CryptoCbFunc Pk: Type 4 +TPM2_Sign: ECDSA 64 +EVP_DigestSignFinal sz 72 +EVP_DigestVerifyFinal success +Result: success (0) +TPM2_FlushContext: Closed handle 0x80000002 +``` + +## Support + +For questions please email support@wolfssl.com diff --git a/tpm/evp_tpm.c b/tpm/evp_tpm.c new file mode 100644 index 00000000..634268e9 --- /dev/null +++ b/tpm/evp_tpm.c @@ -0,0 +1,295 @@ +/* evp_tpm.c + * + * Copyright (C) 2006-2021 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#ifndef WOLFSSL_USER_SETTINGS + #include + #include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + + +/* Storage Key Parameters */ +#define TPM2_DEMO_STORAGE_EC_KEY_HANDLE 0x81000201 /* Persistent Storage Key Handle (ECC) */ +static const char gStorageKeyAuth[] = "ThisIsMyStorageKeyAuth"; +static const char gKeyAuth[] = "ThisIsMyKeyAuth"; + +typedef struct TpmCryptoCbCtx { + WOLFTPM2_DEV* dev; + WOLFTPM2_KEY* eccKey; +} TpmCryptoCbCtx; + +static int CreateLoadExportTpmKey(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* tpmKey, + WOLFTPM2_KEY* storageKey, byte* pubKeyDer, word32* pubKeyDerSz) +{ + int ret; + TPMT_PUBLIC publicTemplate; + ecc_key* wolfEccKey; + + wolfTPM2_GetKeyTemplate_ECC(&publicTemplate, + TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth | + TPMA_OBJECT_sign | TPMA_OBJECT_noDA, + TPM_ECC_NIST_P256, TPM_ALG_ECDSA); + ret = wolfTPM2_CreateAndLoadKey(dev, tpmKey, &storageKey->handle, + &publicTemplate, (byte*)gKeyAuth, sizeof(gKeyAuth)-1); + if (ret == 0) { + wolfEccKey = wc_ecc_key_new(NULL); + if (wolfEccKey != NULL) { + /* extract public key der */ + /* load public portion of key into wolf ECC Key */ + ret = wolfTPM2_EccKey_TpmToWolf(dev, tpmKey, wolfEccKey); + if (ret == 0) { + ret = wc_EccPublicKeyToDer(wolfEccKey, + pubKeyDer, *pubKeyDerSz, 1); + if (ret >= 0) { + *pubKeyDerSz = ret; + ret = 0; + } + } + wc_ecc_key_free(wolfEccKey); + } + } + + if (ret == 0) { + printf("Create/Load ECC Key: Handle 0x%x (%d bytes)\n", + (word32)tpmKey->handle.hndl, tpmKey->pub.size); + } + else { + printf("Create/Load ECC Key: failed 0x%x: %s\n", ret, + TPM2_GetRCString(ret)); + } + return ret; +} + +static int LoadPrimaryStoragekey(WOLFTPM2_DEV* pDev, WOLFTPM2_KEY* pStorageKey, + TPM_ALG_ID alg) +{ + int ret; + + /* See if SRK already exists */ + ret = wolfTPM2_ReadPublicKey(pDev, pStorageKey, + TPM2_DEMO_STORAGE_EC_KEY_HANDLE); + if (ret != 0) { + /* Create primary storage key */ + ret = wolfTPM2_CreateSRK(pDev, pStorageKey, alg, + (byte*)gStorageKeyAuth, sizeof(gStorageKeyAuth)-1); + if (ret == TPM_RC_SUCCESS) { + /* Move storage key into persistent NV */ + ret = wolfTPM2_NVStoreKey(pDev, TPM_RH_OWNER, pStorageKey, + TPM2_DEMO_STORAGE_EC_KEY_HANDLE); + } + } + else { + /* specify auth password for storage key */ + pStorageKey->handle.auth.size = sizeof(gStorageKeyAuth)-1; + XMEMCPY(pStorageKey->handle.auth.buffer, gStorageKeyAuth, + pStorageKey->handle.auth.size); + } + + if (ret == 0) { + printf("Loading SRK: Storage 0x%x (%d bytes)\n", + (word32)pStorageKey->handle.hndl, pStorageKey->pub.size); + } + else { + printf("Loading SRK: Storage failed 0x%x: %s\n", ret, + TPM2_GetRCString(ret)); + } + return ret; +} + + +int CryptoCbFunc(int devId, wc_CryptoInfo* info, void* ctx) +{ + int ret = CRYPTOCB_UNAVAILABLE; + TpmCryptoCbCtx* tlsCtx = (TpmCryptoCbCtx*)ctx; + + if (info == NULL || ctx == NULL || tlsCtx->dev == NULL) { + return BAD_FUNC_ARG; + } + + (void)devId; + + if (info->algo_type == WC_ALGO_TYPE_PK) { + printf("CryptoCbFunc Pk: Type %d\n", info->pk.type); + + if (info->pk.type == WC_PK_TYPE_ECDSA_SIGN) { + byte sigRS[MAX_ECC_BYTES*2]; + byte *r = sigRS, *s; + word32 rsLen = sizeof(sigRS), rLen, sLen; + word32 inlen = info->pk.eccsign.inlen; + + /* truncate input to match key size */ + rLen = wc_ecc_size(info->pk.eccsign.key); + if (inlen > rLen) + inlen = rLen; + + ret = wolfTPM2_SignHash(tlsCtx->dev, tlsCtx->eccKey, + info->pk.eccsign.in, inlen, sigRS, (int*)&rsLen); + if (ret == 0) { + /* Encode ECDSA Header */ + rLen = sLen = rsLen / 2; + s = &sigRS[rLen]; + ret = wc_ecc_rs_raw_to_sig(r, rLen, s, sLen, + info->pk.eccsign.out, info->pk.eccsign.outlen); + } + } + } + + /* need to return negative here for error */ + if (ret != TPM_RC_SUCCESS && ret != CRYPTOCB_UNAVAILABLE) { + printf("CryptoCbFunc failed ret = %d\n", ret); + ret = WC_HW_E; + } + + return ret; +} + +static int test_EVP_MD_ecc_signing(int devId, const byte* pubKeyBuf, word32 pubKeySz) +{ + int ret = 0; +#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) + EVP_MD_CTX mdCtx; + EVP_PKEY* privKey; + EVP_PKEY* pubKey = NULL; + const char testData[] = "Hi There"; + unsigned int testDataSz = (unsigned int)XSTRLEN(testData); + unsigned char check[ECC_MAX_SIG_SIZE]; + size_t checkSz = ECC_MAX_SIG_SIZE; + const unsigned char *p; + + printf("EVP_MD_ecc_signing()\n"); + + privKey = wolfSSL_d2i_PrivateKey_id(EVP_PKEY_EC, NULL, NULL, devId); + if (privKey == NULL) { + ret = MEMORY_E; + } + if (ret == 0) { + p = pubKeyBuf; + pubKey = d2i_PUBKEY(NULL, &p, pubKeySz); + if (pubKey == NULL) { + ret = MEMORY_E; + } + } + + if (ret == 0) { + EVP_MD_CTX_init(&mdCtx); + ret = EVP_DigestSignInit(&mdCtx, NULL, EVP_sha256(), NULL, privKey); + if (ret == WOLFSSL_SUCCESS) + ret = EVP_DigestSignUpdate(&mdCtx, testData, testDataSz); + if (ret == WOLFSSL_SUCCESS) + ret = EVP_DigestSignFinal(&mdCtx, check, &checkSz); + EVP_MD_CTX_cleanup(&mdCtx); + + if (ret == WOLFSSL_SUCCESS) { + printf("EVP_DigestSignFinal sz %d\n", (int)checkSz); + ret = 0; + } + else { + ret = -1; /* failure */ + } + } + + if (ret == 0) { + EVP_MD_CTX_init(&mdCtx); + ret = EVP_DigestVerifyInit(&mdCtx, NULL, EVP_sha256(), NULL, pubKey); + if (ret == WOLFSSL_SUCCESS) + ret = EVP_DigestVerifyUpdate(&mdCtx, testData, testDataSz); + if (ret == WOLFSSL_SUCCESS) + ret = EVP_DigestVerifyFinal(&mdCtx, check, checkSz); + EVP_MD_CTX_cleanup(&mdCtx); + + if (ret == WOLFSSL_SUCCESS) { + printf("EVP_DigestVerifyFinal success\n"); + ret = 0; + } + else { + ret = -1; /* failure */ + } + } + + EVP_PKEY_free(pubKey); + EVP_PKEY_free(privKey); +#else + ret = NOT_COMPILED_IN; +#endif + return ret; +} + + +int main(void) +{ + int ret; + WOLFTPM2_DEV dev; + WOLFTPM2_KEY tpmKey; + WOLFTPM2_KEY storageKey; + TpmCryptoCbCtx tpmCtx; + int devId = INVALID_DEVID; + byte pubKeyDer[1024]; + word32 pubKeyDerSz = 1024; + + XMEMSET(&tpmCtx, 0, sizeof(tpmCtx)); + XMEMSET(&tpmKey, 0, sizeof(tpmKey)); + XMEMSET(&storageKey, 0, sizeof(storageKey)); + XMEMSET(pubKeyDer, 0, sizeof(pubKeyDer)); + tpmCtx.eccKey = &tpmKey; + + ret = wolfTPM2_Init(&dev, NULL, NULL); + if (ret == 0) { + wolfSSL_Debugging_OFF(); + + ret = wolfTPM2_GetTpmDevId(&dev); + if (ret >= 0) { + devId = ret; + tpmCtx.dev = &dev; + + ret = wc_CryptoDev_RegisterDevice(devId, CryptoCbFunc, &tpmCtx); + } + } + if (ret == 0) { + ret = LoadPrimaryStoragekey(&dev, &storageKey, TPM_ALG_ECC); + } + if (ret == 0) { + ret = CreateLoadExportTpmKey(&dev, &tpmKey, &storageKey, + pubKeyDer, &pubKeyDerSz); + } + if (ret == 0) { + ret = test_EVP_MD_ecc_signing(devId, pubKeyDer, pubKeyDerSz); + } + + printf("Result: %s (%d)\n", ret == 0 ? "success" : + wolfSSL_ERR_reason_error_string(ret), ret); + + wolfTPM2_UnloadHandle(&dev, &tpmKey.handle); + wolfTPM2_Cleanup(&dev); + + return ret; +}