Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wolfSSH support for using TPM based key for authentication #754

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
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 "hansel"'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 hansel

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 hansel

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
Loading