Skip to content

Commit

Permalink
Support for TPM based public key authentication using wolfTPM (WIP).
Browse files Browse the repository at this point in the history
  • Loading branch information
dgarske committed Nov 8, 2024
1 parent 5305170 commit 8f4e544
Show file tree
Hide file tree
Showing 9 changed files with 603 additions and 52 deletions.
59 changes: 58 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,13 @@ Additional build options for wolfSSL are located in
[chapter two](https://www.wolfssl.com/docs/wolfssl-manual/ch2/).
of the wolfSSH manual.


building
--------

From the wolfSSH source directory run:

$ ./autogen.sh
$ ./autogen.sh (if cloned from GitHub)
$ ./configure --with-wolfssl=[/usr/local]
$ make
$ make check
Expand Down Expand Up @@ -528,6 +529,62 @@ fred-cert.der would be:

$ ./examples/client/client -u fred -J ./keys/fred-cert.der -i ./keys/fred-key.der

TPM
===

wolfSSH now supports TPM support with client key authentication.

When using TPM for client side public key authentication wolfSSH has dependencies
on wolfCrypt and wolfTPM. Youll also need to have a tpm simulator
[wolfTPM](https://www.wolfssl.com/products/wolftpm/)
[wolfSSL](https://www.wolfssl.com/products/wolfssl/)
You'll need to build and configure wolfTPM, wolfSSL, and wolfSSH like so:

$ cd <wolfSSL, wolfTPM, wolfSSH>
$ ./autogen.sh (if cloned from GitHub)
$ <Configuration>
$ make
$ make check

<Configuration>
wolfSSL
$ ./configure --enable-wolftpm --enable-wolfssh
wolfTPM
$ ./configure --enable-swtpm
wolfSSH
$ ./configure --enable-tpm

For testing TPM with private rsa key you'll need to run the server from a TPM
simulator like `ibmswtpm2`. This can be done as followed:

$ cd src
$ ./tpm_server

Before starting the echoserver you need to run the keygen for keyblob in wolfTPM
using:

$ ./examples/keygen/keygen keyblob.bin -rsa -t -pem

Take key.pem and convert the TPM public key to the ssh-rsa BASE64 username format:
`ssh-keygen -f key.pem -i -m PKCS8`. Update echoserver.c user "jill"'s public key.

The directory `examples` contains an echoserver that any client should
be able to connect to. From wolfSSH open two terminal instances and run the
server:

$ ./examples/echoserver/echoserver

From another terminal run the client with the keyblob:

$ ./examples/client/client -i ../wolfTPM/keyblob.bin -u jill

For debuging run server like above then:

$ <lldb, gdb, etc.> ./examples/client/client

Set break point or just run:

$ r -i ../wolfTPM/keyblob.bin -u jill

WOLFSSH APPLICATIONS
====================
Expand Down
16 changes: 16 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,16 @@ 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])

if test "$ENABLED_TPM" != "no"
then
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/ .])])
fi

# smallstack
AC_ARG_ENABLE([smallstack],
[AS_HELP_STRING([--enable-smallstack],[Enable small stack (default: disabled)])],
Expand Down Expand Up @@ -225,6 +235,10 @@ AS_IF([test "x$ENABLED_SSHD" = "xyes"],
[AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_SSHD"])
AS_IF([test "x$ENABLED_SSHCLIENT" = "xyes"],
[AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_SSHCLIENT"])
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"])

if test "$ENABLED_SSHD" = "yes"; then
if test -n "$PAM_LIB"
Expand Down Expand Up @@ -279,6 +293,7 @@ AM_CONDITIONAL([BUILD_AGENT],[test "x$ENABLED_AGENT" = "xyes"])
AM_CONDITIONAL([BUILD_SSHD],[test "x$ENABLED_SSHD" = "xyes"])
AM_CONDITIONAL([BUILD_SSHCLIENT],[test "x$ENABLED_SSHCLIENT" = "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 @@ -322,6 +337,7 @@ AS_ECHO([" * sftp: $ENABLED_SFTP"])
AS_ECHO([" * sshd: $ENABLED_SSHD"])
AS_ECHO([" * ssh client: $ENABLED_SSHCLIENT"])
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"])
76 changes: 62 additions & 14 deletions examples/client/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@
#include <wolfssl/wolfcrypt/asn.h>
#endif

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

#ifndef NO_WOLFSSH_CLIENT

Expand Down Expand Up @@ -125,7 +129,9 @@ static void ShowUsage(void)


static const char* pubKeyName = NULL;
static const char* certName = NULL;
#ifdef WOLFSSH_CERTS
static const char* certName = NULL;
#endif
static const char* caCert = NULL;


Expand Down Expand Up @@ -549,7 +555,7 @@ static int wolfSSH_AGENT_DefaultActions(WS_AgentCbAction action, void* vCtx)
ret = WS_AGENT_NOT_AVAILABLE;

if (ret == WS_AGENT_SUCCESS) {
memset(name, 0, sizeof(struct sockaddr_un));
WMEMSET(name, 0, sizeof(struct sockaddr_un));
name->sun_family = AF_LOCAL;
strncpy(name->sun_path, sockName, sizeof(name->sun_path));
name->sun_path[sizeof(name->sun_path) - 1] = '\0';
Expand Down Expand Up @@ -781,11 +787,17 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
if (keepOpen)
err_sys("Threading needed for terminal session\n");
#endif

#ifndef WOLFSSH_TPM
#ifdef WOLFSSH_CERTS
if ((pubKeyName == NULL && certName == NULL) && privKeyName != NULL) {
err_sys("If setting priv key, need pub key.");
}

#else
if (pubKeyName == NULL && privKeyName != NULL) {
err_sys("If setting priv key, need pub key.");
}
#endif
#endif
ret = ClientSetPrivateKey(privKeyName, userEcc, NULL);
if (ret != 0) {
err_sys("Error setting private key");
Expand Down Expand Up @@ -840,6 +852,9 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
if (ssh == NULL)
err_sys("Couldn't create wolfSSH session.");

#ifdef WOLFSSH_TPM
CLientSetTpm(ssh);
#endif
#if defined(WOLFSSL_PTHREADS) && defined(WOLFSSL_TEST_GLOBAL_REQ)
wolfSSH_SetGlobalReq(ctx, callbackGlobalReq);
wolfSSH_SetGlobalReqCtx(ssh, &ssh); /* dummy ctx */
Expand All @@ -850,7 +865,7 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)

#ifdef WOLFSSH_AGENT
if (useAgent) {
memset(&agentCbCtx, 0, sizeof(agentCbCtx));
WMEMSET(&agentCbCtx, 0, sizeof(agentCbCtx));
agentCbCtx.state = AGENT_STATE_INIT;
wolfSSH_set_agent_cb_ctx(ssh, &agentCbCtx);
}
Expand Down Expand Up @@ -913,37 +928,57 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
tcp_socket(&sockFd, ((struct sockaddr_in *)&clientAddr)->sin_family);

ret = connect(sockFd, (const struct sockaddr *)&clientAddr, clientAddrSz);
if (ret != 0)
if (ret != 0) {
ClientFreeBuffers(pubKeyName, privKeyName, NULL);
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
err_sys("Couldn't connect to server.");
}

if (nonBlock)
tcp_set_nonblocking(&sockFd);

ret = wolfSSH_set_fd(ssh, (int)sockFd);
if (ret != WS_SUCCESS)
if (ret != WS_SUCCESS) {
ClientFreeBuffers(pubKeyName, privKeyName, NULL);
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
err_sys("Couldn't set the session's socket.");
}

if (cmd != NULL) {
ret = wolfSSH_SetChannelType(ssh, WOLFSSH_SESSION_EXEC,
(byte*)cmd, (word32)WSTRLEN((char*)cmd));
if (ret != WS_SUCCESS)
if (ret != WS_SUCCESS) {
ClientFreeBuffers(pubKeyName, privKeyName, NULL);
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
err_sys("Couldn't set the channel type.");
}
}

#ifdef WOLFSSH_TERM
if (keepOpen) {
ret = wolfSSH_SetChannelType(ssh, WOLFSSH_SESSION_TERMINAL, NULL, 0);
if (ret != WS_SUCCESS)
if (ret != WS_SUCCESS) {
ClientFreeBuffers(pubKeyName, privKeyName, NULL);
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
err_sys("Couldn't set the terminal channel type.");
}
}
#endif

if (!nonBlock)
ret = wolfSSH_connect(ssh);
else
ret = NonBlockSSH_connect(ssh);
if (ret != WS_SUCCESS)
if (ret != WS_SUCCESS) {
ClientFreeBuffers(pubKeyName, privKeyName, NULL);
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
err_sys("Couldn't connect SSH stream.");
}

#if !defined(SINGLE_THREADED) && !defined(WOLFSSL_NUCLEUS) && \
defined(WOLFSSH_TERM) && !defined(NO_FILESYSTEM)
Expand Down Expand Up @@ -1040,16 +1075,23 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
#endif
ret = wolfSSH_stream_send(ssh, (byte*)testString,
(word32)strlen(testString));
if (ret <= 0)
if (ret <= 0) {
ClientFreeBuffers(pubKeyName, privKeyName, NULL);
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
err_sys("Couldn't send test string.");

}
do {
ret = wolfSSH_stream_read(ssh, (byte*)rxBuf, sizeof(rxBuf) - 1);
if (ret <= 0) {
ret = wolfSSH_get_error(ssh);
if (ret != WS_WANT_READ && ret != WS_WANT_WRITE &&
ret != WS_CHAN_RXD)
ret != WS_CHAN_RXD) {
ClientFreeBuffers(pubKeyName, privKeyName, NULL);
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
err_sys("Stream read failed.");
}
}
} while (ret == WS_WANT_READ || ret == WS_WANT_WRITE);

Expand All @@ -1065,11 +1107,17 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
if (ret != WS_SOCKET_ERROR_E && wolfSSH_get_error(ssh) != WS_SOCKET_ERROR_E
&& wolfSSH_get_error(ssh) != WS_CHANNEL_CLOSED) {
if (ret != WS_SUCCESS) {
ClientFreeBuffers(pubKeyName, privKeyName, NULL);
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
err_sys("Sending the shutdown messages failed.");
}
ret = wolfSSH_worker(ssh, NULL);
if (ret != WS_SUCCESS && ret != WS_SOCKET_ERROR_E &&
ret != WS_CHANNEL_CLOSED) {
ClientFreeBuffers(pubKeyName, privKeyName, NULL);
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
err_sys("Failed to listen for close messages from the peer.");
}
}
Expand All @@ -1079,14 +1127,14 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
((func_args*)args)->return_code = wolfSSH_GetExitStatus(ssh);
#endif

ClientFreeBuffers(pubKeyName, privKeyName, NULL);
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
if (ret != WS_SUCCESS && ret != WS_SOCKET_ERROR_E &&
ret != WS_CHANNEL_CLOSED) {
err_sys("Closing client stream failed");
}

ClientFreeBuffers(pubKeyName, privKeyName, NULL);
#if !defined(WOLFSSH_NO_ECC) && defined(FP_ECC) && defined(HAVE_THREAD_LS)
wc_ecc_fp_free(); /* free per thread cache */
#endif
Expand Down
Loading

0 comments on commit 8f4e544

Please sign in to comment.