Skip to content

Commit

Permalink
Added integration of TPM 2.0 into wolfSSH
Browse files Browse the repository at this point in the history
* Added --enable-tpm build option
* Added new members to WOLFSSH_CTX structure
* Added TPM 2.0 key handling in client example
* Added TPM 2.0 signing in wolfSSH internals
* Added wolfSSH set methods for TPM device and key
* Added TPM helper functions from wolfTPM into wolfSSH
* Modified automake, wolfTPM is used as a system library
  • Loading branch information
dgarske committed Jan 10, 2023
1 parent 834a03c commit f07f835
Show file tree
Hide file tree
Showing 9 changed files with 329 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "wolfTPM"]
path = wolfTPM
url = https://github.com/wolfSSL/wolfTPM.git
10 changes: 10 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ AC_ARG_WITH(wolfssl,
)

AC_CHECK_LIB([wolfssl],[wolfCrypt_Init],,[AC_MSG_ERROR([libwolfssl is required for ${PACKAGE}. It can be obtained from https://www.wolfssl.com/download.html/ .])])
AC_CHECK_LIB([wolftpm],[wolfTPM2_Init],,[AC_MSG_ERROR([libwolftpm is required for ${PACKAGE}. It can be obtained from https://www.wolfssl.com/download.html/ .])])
AC_CHECK_FUNCS([gethostbyname getaddrinfo gettimeofday inet_ntoa memset socket wc_ecc_set_rng])
AC_CHECK_DECLS([[pread],[pwrite]],,[unistd.h])

Expand Down Expand Up @@ -202,6 +203,11 @@ AC_ARG_ENABLE([certs],
[AS_HELP_STRING([--enable-certs],[Enable X.509 cert support (default: disabled)])],
[ENABLED_CERTS=$enableval],[ENABLED_CERTS=no])

# TPM 2.0 Support
AC_ARG_ENABLE([tpm],
[AS_HELP_STRING([--enable-tpm],[Enable TPM 2.0 support (default: disabled)])],
[ENABLED_TPM=$enableval],[ENABLED_TPM=no])

# smallstack
AC_ARG_ENABLE([smallstack],
[AS_HELP_STRING([--enable-smallstack],[Enable small stack (default: disabled)])],
Expand Down Expand Up @@ -248,6 +254,8 @@ AS_IF([test "x$ENABLED_SHELL" = "xyes"],
[AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_SHELL"])
AS_IF([test "x$ENABLED_AGENT" = "xyes"],[AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_AGENT"])
AS_IF([test "x$ENABLED_CERTS" = "xyes"],[AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_CERTS"])
AS_IF([test "x$ENABLED_TPM" = "xyes"],
[AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_TPM"])
AS_IF([test "x$ENABLED_SMALLSTACK" = "xyes"],
[AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_SMALL_STACK"])
AS_IF([test "x$ENABLED_SSHD" = "xyes"],
Expand Down Expand Up @@ -305,6 +313,7 @@ AM_CONDITIONAL([BUILD_SHELL],[test "x$ENABLED_SHELL" = "xyes"])
AM_CONDITIONAL([BUILD_AGENT],[test "x$ENABLED_AGENT" = "xyes"])
AM_CONDITIONAL([BUILD_SSHD],[test "x$ENABLED_SSHD" = "xyes"])
AM_CONDITIONAL([BUILD_CERTS],[test "x$ENABLED_CERTS" = "xyes"])
AM_CONDITIONAL([BUILD_TPM],[test "x$ENABLED_TPM" = "xyes"])

AX_HARDEN_CC_COMPILER_FLAGS

Expand Down Expand Up @@ -347,6 +356,7 @@ AS_ECHO([" * scp: $ENABLED_SCP"])
AS_ECHO([" * sftp: $ENABLED_SFTP"])
AS_ECHO([" * sshd: $ENABLED_SSHD"])
AS_ECHO([" * agent: $ENABLED_AGENT"])
AS_ECHO([" * TPM 2.0 support: $ENABLED_TPM"])
AS_ECHO([" * TCP/IP Forwarding: $ENABLED_FWD"])
AS_ECHO([" * X.509 Certs: $ENABLED_CERTS"])
AS_ECHO([" * Examples: $ENABLED_EXAMPLES"])
Expand Down
227 changes: 226 additions & 1 deletion examples/client/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@
#include <wolfssl/wolfcrypt/asn.h>
#endif

#ifdef WOLFSSH_TPM
#include <wolftpm/tpm2_wrap.h>
#include "../../wolfTPM/examples/tpm_io.h"
#endif /* WOLFSSH_TPM */

#ifndef NO_WOLFSSH_CLIENT

Expand Down Expand Up @@ -702,6 +706,140 @@ static THREAD_RET readInput(void* in)
}


#ifdef WOLFSSH_AGENT
static inline void ato32(const byte* c, word32* u32)
{
*u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
}
#endif


#ifdef WOLFSSH_TPM

#define TPM2_DEMO_STORAGE_KEY_HANDLE 0x81000200 /* Persistent Storage Key Handle (RSA) */

static const char gStorageKeyAuth[] = "ThisIsMyStorageKeyAuth";

static int getPrimaryStoragekey(WOLFTPM2_DEV* pDev,
WOLFTPM2_KEY* pStorageKey,
TPM_ALG_ID alg)
{
int rc;

/* See if SRK already exists */
rc = wolfTPM2_ReadPublicKey(pDev, pStorageKey, TPM2_DEMO_STORAGE_KEY_HANDLE);
if (rc != 0) {
/* Create primary storage key */
rc = wolfTPM2_CreateSRK(pDev, pStorageKey, alg,
(byte*)gStorageKeyAuth, sizeof(gStorageKeyAuth)-1);
#ifndef WOLFTPM_WINAPI
if (rc == TPM_RC_SUCCESS) {
/* Move storage key into persistent NV */
rc = wolfTPM2_NVStoreKey(pDev, TPM_RH_OWNER, pStorageKey,
TPM2_DEMO_STORAGE_KEY_HANDLE);
}
#endif
}
else {
/* specify auth password for storage key */
pStorageKey->handle.auth.size = sizeof(gStorageKeyAuth)-1;
WMEMCPY(pStorageKey->handle.auth.buffer, gStorageKeyAuth,
pStorageKey->handle.auth.size);
}
if (rc != 0) {
printf("Loading SRK: Storage failed 0x%x: %s\n", rc,
TPM2_GetRCString(rc));
return rc;
}
printf("Loading SRK: Storage 0x%x (%d bytes)\n",
(word32)pStorageKey->handle.hndl, pStorageKey->pub.size);
return rc;
}


static int readKeyBlob(const char* filename, WOLFTPM2_KEYBLOB* key)
{
int rc = 0;
#if !defined(NO_FILESYSTEM) && !defined(NO_WRITE_TEMP_FILES)
WFILE *fp = NULL;
size_t fileSz = 0;
size_t bytes_read = 0;
byte pubAreaBuffer[sizeof(TPM2B_PUBLIC)];
int pubAreaSize;

WMEMSET(key, 0, sizeof(WOLFTPM2_KEYBLOB));

if (WFOPEN(&fp, filename, "rb") == 0) {
WFSEEK(fp, 0, XSEEK_END);
fileSz = WFTELL(fp);
WREWIND(fp);
if (fileSz > sizeof(key->priv) + sizeof(key->pub)) {
printf("File size check failed\n");
rc = BUFFER_E; goto exit;
}
printf("Reading %d bytes from %s\n", (int)fileSz, filename);

bytes_read = WFREAD(&key->pub.size, 1, sizeof(key->pub.size), fp);
if (bytes_read != sizeof(key->pub.size)) {
printf("Read %zu, expected size marker of %zu bytes\n",
bytes_read, sizeof(key->pub.size));
goto exit;
}
fileSz -= bytes_read;

bytes_read = WFREAD(pubAreaBuffer, 1, sizeof(UINT16) + key->pub.size, fp);
if (bytes_read != sizeof(UINT16) + key->pub.size) {
printf("Read %zu, expected public blob %zu bytes\n",
bytes_read, sizeof(UINT16) + key->pub.size);
goto exit;
}
fileSz -= bytes_read; /* Reminder bytes for private key part */

/* Decode the byte stream into a publicArea structure ready for use */
rc = TPM2_ParsePublic(&key->pub, pubAreaBuffer,
(word32)sizeof(pubAreaBuffer), &pubAreaSize);
if (rc != TPM_RC_SUCCESS) return rc;

if (fileSz > 0) {
printf("Reading the private part of the key\n");
bytes_read = WFREAD(&key->priv, 1, fileSz, fp);
if (bytes_read != fileSz) {
printf("Read %zu, expected private blob %zu bytes\n",
bytes_read, fileSz);
goto exit;
}
rc = 0; /* success */
}

/* sanity check the sizes */
if (pubAreaSize != (key->pub.size + (int)sizeof(key->pub.size)) ||
key->priv.size > sizeof(key->priv.buffer)) {
printf("Struct size check failed (pub %d, priv %d)\n",
key->pub.size, key->priv.size);
rc = BUFFER_E;
}
}
else {
rc = BUFFER_E;
printf("File %s not found!\n", filename);
printf("Keys can be generated by running:\n"
" ./examples/keygen/keygen rsa_test_blob.raw -rsa -t\n"
" ./examples/keygen/keygen ecc_test_blob.raw -ecc -t\n");
}

exit:
if (fp)
WFCLOSE(fp);
#else
(void)filename;
(void)key;
#endif /* !NO_FILESYSTEM && !NO_WRITE_TEMP_FILES */
return rc;
}

#endif /* WOLFSSH_TPM */


static THREAD_RET readPeer(void* in)
{
byte buf[80];
Expand Down Expand Up @@ -995,6 +1133,65 @@ static int wolfSSH_AGENT_IO_Cb(WS_AgentIoCbAction action,
#endif /* WOLFSSH_AGENT */


#ifdef WOLFSSH_TPM
static int wolfSSH_TPM_InitKey(WOLFTPM2_DEV* dev, const char* name, WOLFTPM2_KEY* tpmKey)
{
WOLFTPM2_KEY storage;
WOLFTPM2_KEYBLOB tpmKeyBlob;

if (wolfTPM2_Init(dev, TPM2_IoCb, NULL) != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFSSH
printf("TPM 2.0 Device initialization failed\n");
#endif
return WOLFSSH_TPM_FAILED_INIT;
}

/* TPM 2.0 keys live under a Primary Key, acquire such key */
if (getPrimaryStoragekey(dev, &storage, TPM_ALG_RSA)) {
#ifdef DEBUG_WOLFSSH
printf("Acquiring a Primary TPM 2.0 Key failed\n");
#endif
return WOLFSSH_TPM_FAILED_LOAD_PRIMARY;
}

/* Load the TPM 2.0 key blob from disk */
if (readKeyBlob(name, &tpmKeyBlob) != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFSSH
printf("Reading key blob from disk failed\n");
#endif
return WOLFSSH_TPM_FAILED_READ_KEYBLOB;
}

/* Load the key into the TPM device */
if (wolfTPM2_LoadKey(dev, &tpmKeyBlob, &storage.handle) != TPM_RC_SUCCESS) {
#ifdef DEBUG_WOLFSSH
printf("wolfTPM2_LoadKey failed\n");
#endif
return WOLFSSH_TPM_FAILED_LOAD_KEY;
}
#ifdef DEBUG_WOLFSSH
printf("Loaded key to 0x%x\n", (word32)tpmKeyBlob.handle.hndl);
#endif

WMEMCPY(&tpmKey->handle, &tpmKeyBlob.handle, sizeof(tpmKey->handle));
WMEMCPY(&tpmKey->pub, &tpmKeyBlob.pub, sizeof(tpmKey->pub));
return WOLFSSH_TPM_SUCCESS;
}


static void wolfSSH_TPM_Cleanup(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key)
{
if (key != NULL) {
wolfTPM2_UnloadHandle(dev, &key->handle);
}

if (dev != NULL) {
wolfTPM2_Cleanup(dev);
}
}
#endif /* WOLFSSH_TPM */


THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
{
WOLFSSH_CTX* ctx = NULL;
Expand Down Expand Up @@ -1022,6 +1219,10 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
byte useAgent = 0;
WS_AgentCbActionCtx agentCbCtx;
#endif
#ifdef WOLFSSH_TPM
WOLFTPM2_DEV tpmDev;
WOLFTPM2_KEY tpmKey;
#endif

int argc = ((func_args*)args)->argc;
char** argv = ((func_args*)args)->argv;
Expand Down Expand Up @@ -1157,7 +1358,18 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
if (ret != 0) err_sys("Couldn't load private key buffer.");
}
else {
#ifndef NO_FILESYSTEM
#if defined(WOLFSSH_TPM)
/* Protecting the SSH Private Key using a TPM 2.0 device
*
* TPM-backed keys do not require a user buffer, because
* the private key is loaded securely inside the TPM and
* used only from within the TPM for higher security.
*
* Successfully loaded TPM key has a TPM Handle that is
* later passed to wolfSSH for use
*/
ret = wolfSSH_TPM_InitKey(&tpmDev, privKeyName, &tpmKey);
#elif !defined(NO_FILESYSTEM)
userPrivateKey = NULL; /* create new buffer based on parsed input */
ret = wolfSSH_ReadKey_file(privKeyName,
(byte**)&userPrivateKey, &userPrivateKeySz,
Expand Down Expand Up @@ -1239,6 +1451,15 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
if (ssh == NULL)
err_sys("Couldn't create wolfSSH session.");

#ifdef WOLFSSH_TPM
/* Link the TPM 2.0 device to the SSH session
* This way, SSH client operations that can
* take advantage of the hardware security
* will have access to the TPM 2.0 device */
wolfSSH_SetTpmDev(ssh, &tpmDev);
wolfSSH_SetTpmKey(ssh, &tpmKey);
#endif

#if defined(WOLFSSL_PTHREADS) && defined(WOLFSSL_TEST_GLOBAL_REQ)
wolfSSH_SetGlobalReq(ctx, callbackGlobalReq);
wolfSSH_SetGlobalReqCtx(ssh, &ssh); /* dummy ctx */
Expand Down Expand Up @@ -1399,6 +1620,10 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
if (privKeyName != NULL && userPrivateKey != NULL) {
WFREE(userPrivateKey, NULL, DYNTYPE_PRIVKEY);
}
#ifdef WOLFSSH_TPM
wolfSSH_TPM_Cleanup(&tpmDev, &tpmKey);
#endif

#if !defined(WOLFSSH_NO_ECC) && defined(FP_ECC) && defined(HAVE_THREAD_LS)
wc_ecc_fp_free(); /* free per thread cache */
#endif
Expand Down
4 changes: 4 additions & 0 deletions examples/client/include.am
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@ examples_client_client_SOURCES = examples/client/client.c \
examples/client/client.h
examples_client_client_LDADD = src/libwolfssh.la
examples_client_client_DEPENDENCIES = src/libwolfssh.la

if BUILD_TPM
examples_client_client_SOURCES += ../wolfTPM/examples/tpm_io.c
endif
endif
19 changes: 16 additions & 3 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@
#include "src/misc.c"
#endif

#ifdef WOLFSSH_TPM
#include <wolftpm/tpm2_wrap.h>
#endif

/*
Flags:
Expand Down Expand Up @@ -10087,11 +10090,21 @@ static int BuildUserAuthRequestRsa(WOLFSSH* ssh,
ret = WS_CRYPTO_FAILED;
}
else {
int sigSz;
int sigSz = 0;
WLOG(WS_LOG_INFO, "Signing hash with RSA.");
#ifdef WOLFSSH_TPM
if (ssh->ctx->tpmDev && ssh->ctx->tpmKey) {
wolfTPM2_SignHashScheme(ssh->ctx->tpmDev, ssh->ctx->tpmKey,
encDigest, encDigestSz,
output+begin, (int*)&sigSz,
TPM_ALG_OAEP, TPM_ALG_SHA1);
}
else
#else
sigSz = wc_RsaSSL_Sign(encDigest, encDigestSz,
output + begin, keySig->sigSz,
&keySig->ks.rsa.key, ssh->rng);
output + begin, keySig->sigSz,
&keySig->ks.rsa.key, ssh->rng);
#endif
if (sigSz <= 0 || (word32)sigSz != keySig->sigSz) {
WLOG(WS_LOG_DEBUG, "SUAR: Bad RSA Sign");
ret = WS_RSA_E;
Expand Down
Loading

0 comments on commit f07f835

Please sign in to comment.