From f6addad16064261d6ec58d56644d5daca5151b72 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 8 Nov 2021 11:50:31 -0800 Subject: [PATCH] Experimental SSH support for public key based authentication using a TPM. --- examples/keygen/keygen.c | 84 ++++++++++++++++++++++++++++++++++++++++ src/tpm2_wrap.c | 19 +++++++++ wolftpm/tpm2_wrap.h | 16 ++++++++ 3 files changed, 119 insertions(+) diff --git a/examples/keygen/keygen.c b/examples/keygen/keygen.c index 7e573642..166da00b 100644 --- a/examples/keygen/keygen.c +++ b/examples/keygen/keygen.c @@ -30,6 +30,8 @@ #include #include /* atoi */ +#include +#include #ifndef WOLFTPM2_NO_WRAPPER @@ -56,6 +58,9 @@ static void usage(void) printf("* -sym: Use Symmetric Cypher for key generation\n"); printf("\tDefault Symmetric Cypher is AES CTR with 256 bits\n"); printf("* -t: Use default template (otherwise AIK)\n"); + printf("* -ssh: Use template for SSH key (only RSA algorithm)\n"); + printf("\tStores public key in id_rsa.pub\n"); + printf("\tStores private key in keyblob.bin\n"); printf("* -aes/xor: Use Parameter Encryption\n"); printf("Example usage:\n"); printf("\t* RSA, default template\n"); @@ -108,6 +113,34 @@ static int symChoice(const char* arg, TPM_ALG_ID* algSym, int* keyBits, return TPM_RC_SUCCESS; } +static int writeKeyPubSsh(const char *filename, const byte *buf, word32 buf_size) +{ + int rc = TPM_RC_FAILURE; +#if !defined(WOLFTPM2_NO_WOLFCRYPT) && !defined(NO_FILESYSTEM) + XFILE fp = NULL; + size_t fileSz = 0; + + if (filename == NULL || buf == NULL) + return BAD_FUNC_ARG; + + fp = XFOPEN(filename, "wt"); + if (fp != XBADFILE) { + fileSz = XFWRITE(buf, 1, buf_size, fp); + /* sanity check */ + if (fileSz == buf_size) { + rc = TPM_RC_SUCCESS; + } +#ifdef DEBUG_WOLFTPM + printf("Public PEM file size = %zu\n", fileSz); + TPM2_PrintBin(buf, buf_size); +#endif + XFCLOSE(fp); + } +#endif + return rc; + +} + int TPM2_Keygen_Example(void* userCtx, int argc, char *argv[]) { int rc; @@ -127,6 +160,7 @@ int TPM2_Keygen_Example(void* userCtx, int argc, char *argv[]) int endorseKey = 0; int pemFiles = 0; int bAIK = 1; + int bSSH = 0; int keyBits = 256; const char *outputFile = "keyblob.bin"; const char *ekPubFile = "ek.pub"; @@ -183,6 +217,10 @@ int TPM2_Keygen_Example(void* userCtx, int argc, char *argv[]) if (XSTRNCMP(argv[argc-1], "-pem", 4) == 0) { pemFiles = 1; } + if (XSTRNCMP(argv[argc-1], "-ssh", 4) == 0) { + bSSH = 1; + bAIK = 0; + } if (XSTRNCMP(argv[argc-1], "-aes", 4) == 0) { paramEncAlg = TPM_ALG_CFB; } @@ -273,6 +311,20 @@ int TPM2_Keygen_Example(void* userCtx, int argc, char *argv[]) XMEMCPY(auth.buffer, gAiKeyAuth, auth.size); } + else if (bSSH) { + if (alg == TPM_ALG_RSA) { + printf("SSH template for RSA key\n"); + rc = wolfTPM2_GetKeyTemplate_RSA_SSH(&publicTemplate, TPM_ALG_SHA1); + + /* set session for authorization key */ + auth.size = (int)sizeof(gKeyAuth)-1; + XMEMCPY(auth.buffer, gKeyAuth, auth.size); + } + else { + printf("SSH template for ECC key not implemented\n"); + rc = BAD_FUNC_ARG; + } + } else { if (alg == TPM_ALG_RSA) { printf("RSA template\n"); @@ -315,6 +367,11 @@ int TPM2_Keygen_Example(void* userCtx, int argc, char *argv[]) /* Save key as encrypted blob to the disk */ #if !defined(WOLFTPM2_NO_WOLFCRYPT) && !defined(NO_FILESYSTEM) rc = writeKeyBlob(outputFile, &newKeyBlob); + if (rc != 0) { + printf("Failure to store key blob\n"); + goto exit; + } + /* Generate key artifacts needed for remote attestation */ if (bAIK) { /* Store primary public key */ @@ -328,6 +385,33 @@ int TPM2_Keygen_Example(void* userCtx, int argc, char *argv[]) XFCLOSE(fp); } } + + if (bSSH) { + WOLFTPM2_KEY tpmKey; + RsaKey rsaKey; + byte der[MAX_RSA_KEY_BYTES], pem[MAX_RSA_KEY_BYTES]; + int derSz, pemSz; + + /* Prepare wolfCrypt key structure */ + rc = wc_InitRsaKey(&rsaKey, NULL); + if (rc != 0) goto exit; + /* Prepare wolfTPM key structure */ + XMEMCPY(&tpmKey.handle, &newKey.handle, sizeof(tpmKey.handle)); + XMEMCPY(&tpmKey.pub, &newKey.pub, sizeof(tpmKey.pub)); + /* Convert the wolfTPM key to wolfCrypt format */ + rc = wolfTPM2_RsaKey_TpmToWolf(&dev, &tpmKey, &rsaKey); + if (rc != 0) goto exit; + /* Convert the wolfCrypt key to DER format */ + rc = wc_RsaKeyToPublicDer(&rsaKey, der, sizeof(der)); + if (rc <= 0) goto exit; + derSz = rc; + /* Convert the DER key to PEM format */ + rc = wc_DerToPem(der, derSz, pem, sizeof(pem), PUBLICKEY_TYPE); + if (rc <= 0) goto exit; + pemSz = rc; + /* Store PEM output to file */ + rc = writeKeyPubSsh("id_rsa.pub", pem, (word32)pemSz); + } #else if (alg == TPM_ALG_SYMCIPHER) { printf("The Public Part of a symmetric key contains only meta data\n"); diff --git a/src/tpm2_wrap.c b/src/tpm2_wrap.c index b57513f5..214b32dd 100644 --- a/src/tpm2_wrap.c +++ b/src/tpm2_wrap.c @@ -4149,6 +4149,25 @@ int wolfTPM2_GetKeyTemplate_ECC_AIK(TPMT_PUBLIC* publicTemplate) return ret; } +int wolfTPM2_GetKeyTemplate_RSA_SSH(TPMT_PUBLIC* publicTemplate, TPM_ALG_ID hashAlg) +{ + int ret; + TPMA_OBJECT objectAttributes = ( + TPMA_OBJECT_fixedTPM | TPMA_OBJECT_fixedParent | + TPMA_OBJECT_sensitiveDataOrigin | TPMA_OBJECT_userWithAuth | + TPMA_OBJECT_decrypt | TPMA_OBJECT_noDA); + + /* "ssh-rsa" requires RSA key be: + * at least 2048 bits + * OAEP signature scheme with SHA1 hash algorithm */ + ret = GetKeyTemplateRSA(publicTemplate, TPM_ALG_SHA256, + objectAttributes, 2048, 0, TPM_ALG_OAEP, hashAlg); + if (ret == 0) { + publicTemplate->parameters.rsaDetail.symmetric.algorithm = TPM_ALG_NULL; + } + return ret; +} + int wolfTPM2_GetNvAttributesTemplate(TPM_HANDLE auth, word32* nvAttributes) { if (nvAttributes == NULL) diff --git a/wolftpm/tpm2_wrap.h b/wolftpm/tpm2_wrap.h index b46e5168..40433524 100644 --- a/wolftpm/tpm2_wrap.h +++ b/wolftpm/tpm2_wrap.h @@ -2160,6 +2160,22 @@ WOLFTPM_API int wolfTPM2_GetKeyTemplate_RSA_AIK(TPMT_PUBLIC* publicTemplate); */ WOLFTPM_API int wolfTPM2_GetKeyTemplate_ECC_AIK(TPMT_PUBLIC* publicTemplate); +/*! + \ingroup wolfTPM2_Wrappers + \brief Prepares a TPM public template for generating a new TPM key that can be used with the SSH protocol + Note: Choose the hashing algorithm carefully, SSH servers could require SHA-256 or even SHA-512 + + \return TPM_RC_SUCCESS: successful + \return BAD_FUNC_ARG: check the provided arguments + + \param publicTemplate pointer to an empty structure of TPMT_PUBLIC type, to store the new template + \param hashAlg integer value of TPM_ALG_ID type, specify the hashing algorithm used by ssh-rsa + + \sa wolfTPM2_GetKeyTemplate_RSA + \sa wolfTPM2_GetKeyTemplate_RSA_AIK +*/ +WOLFTPM_API int wolfTPM2_GetKeyTemplate_RSA_SSH(TPMT_PUBLIC* publicTemplate, TPM_ALG_ID hashAlg); + /*! \ingroup wolfTPM2_Wrappers \brief Prepares a TPM NV Index template