Rebase for tpm public key authentication with wolfssh

pull/754/head
aidan garske 2025-04-01 16:44:55 -07:00
parent e5042df0c1
commit 77c8db6cc2
14 changed files with 1071 additions and 137 deletions

143
.github/workflows/tpm-ssh.yml vendored 100644
View File

@ -0,0 +1,143 @@
name: TPM SSH Test
on:
push:
branches: [ '*' ]
pull_request:
branches: [ '*' ]
jobs:
test-tpm-ssh:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
path: wolfssh
# Clone dependencies
- name: Clone wolfSSL
uses: actions/checkout@v4
with:
repository: wolfSSL/wolfssl
path: wolfssl
- name: Clone wolfTPM
uses: actions/checkout@v4
with:
repository: wolfSSL/wolftpm
path: wolftpm
# Install dependencies
- name: Install Dependencies
run: |
sudo apt-get update
sudo apt-get install -y libtool automake autoconf
sudo apt-get install -y build-essential git autoconf-archive \
libcmocka-dev libssl-dev uthash-dev libglib2.0-dev \
tpm2-tools openssh-client
# Clone, build, and start TPM Simulator
- name: Clone and Build TPM Simulator
run: |
git clone https://github.com/kgoldman/ibmswtpm2
cd ibmswtpm2/src
make
./tpm_server &
sleep 2
cd ../..
# Build and install wolfSSL
- name: Build wolfSSL
run: |
cd wolfssl
./autogen.sh
./configure --enable-wolftpm --enable-wolfssh
make
sudo make install
sudo ldconfig
cd ..
# Build and install wolfTPM
- name: Build wolfTPM
run: |
cd wolftpm
./autogen.sh
./configure --enable-swtpm
make
sudo make install
sudo ldconfig
cd ..
# Build wolfSSH
- name: Build wolfSSH
run: |
cd wolfssh
./autogen.sh
./configure --enable-tpm
make
sudo make install
sudo ldconfig
cd ..
# Test TPM SSH Default Password
- name: Test TPM SSH Default Password
run: |
# Generate key with default password
cd wolftpm
./examples/keygen/keygen keyblob.bin -rsa -t -pem -eh
# Convert key to SSH format
ssh-keygen -f key.pem -i -m PKCS8 > ../wolfssh/key.ssh
cd ..
# Start echoserver and wait for it to be ready
cd wolfssh
./examples/echoserver/echoserver -1 -s key.ssh &
echo "Echoserver started with PID: $!"
sleep 2
cd ..
# Test client connection with default password
cd wolfssh
./examples/client/client -i ../wolftpm/keyblob.bin -u hansel -K ThisIsMyKeyAuth
cd ..
# Test the TPM SSH Custom Password
- name: Test TPM SSH Custom Password
run: |
# Test with custom password
cd wolftpm
./examples/keygen/keygen keyblob2.bin -rsa -t -pem -eh -auth=custompassword
# Convert key to SSH format
ssh-keygen -f key.pem -i -m PKCS8 > ../wolfssh/key.ssh
cd ..
# Start echoserver and wait for it to be ready
cd wolfssh
./examples/echoserver/echoserver -1 -s key.ssh &
echo "Echoserver started with PID: $!"
sleep 2
cd ..
# Test with custom password
cd wolfssh
./examples/client/client -i ../wolftpm/keyblob2.bin -u hansel -K custompassword
cd ..
# Cleanup
pkill -f tpm_server
sleep 2
# Archive artifacts for debugging
- name: Archive test artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: test-artifacts
path: |
wolftpm/keyblob.bin
wolftpm/keyblob2.bin
wolftpm/key.pem
wolfssh/key.ssh

View File

@ -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
@ -528,6 +529,64 @@ fred-cert.der would be:
$ ./examples/client/client -u fred -J ./keys/fred-cert.der -i ./keys/fred-key.der
TPM PUBLIC 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
using the endorsment key in wolfTPM with the following commands:
Default password to `ThisIsMyKeyAuth`:
$ ./examples/keygen/keygen keyblob.bin -rsa -t -pem -eh
Custom password:
$ ./examples/keygen/keygen keyblob.bin -rsa -t -pem -eh -auth=<custompassword>
This will produce a key.pem TPM public key which needs to be converted the to
the ssh-rsa BASE64 username format using this command:
$ ssh-keygen -f key.pem -i -m PKCS8 > ../wolfssh/key.ssh
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 with the key.ssh file you created in the previous step:
$ ./examples/echoserver/echoserver -s key.ssh
From another terminal run the client with the keyblob. Using primary endorsement key
If you used the default password for keygen you must specify the password:
$ ./examples/client/client -i ../wolfTPM/keyblob.bin -u hansel -K ThisIsMyKeyAuth
If you used a custom password for keygen you must specify the password you used:
$ ./examples/client/client -i ../wolfTPM/keyblob.bin -u hansel -K <custompassword>
WOLFSSH APPLICATIONS
====================

View File

@ -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)])],
@ -225,6 +235,8 @@ 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"])
if test "$ENABLED_SSHD" = "yes"; then
if test -n "$PAM_LIB"
@ -279,6 +291,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
@ -322,6 +335,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"])

View File

@ -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
@ -89,6 +93,9 @@ static void ShowUsage(void)
printf(" -p <num> port to connect on, default %d\n", wolfSshPort);
printf(" -u <username> username to authenticate as (REQUIRED)\n");
printf(" -P <password> password for username, prompted if omitted\n");
#ifdef WOLFSSH_TPM
printf(" -K <password> TPM key authentication password\n");
#endif
printf(" -i <filename> filename for the user's private key\n");
printf(" -j <filename> filename for the user's public key\n");
printf(" -x exit after successful connection without doing\n"
@ -125,7 +132,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;
@ -549,7 +558,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';
@ -638,6 +647,7 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
char* host = (char*)wolfSshIp;
const char* username = NULL;
const char* password = NULL;
const char* tpmKeyAuth = NULL;
const char* cmd = NULL;
const char* privKeyName = NULL;
const char* keyList = NULL;
@ -659,7 +669,7 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
(void)keepOpen;
while ((ch = mygetopt(argc, argv, "?ac:h:i:j:p:tu:xzNP:RJ:A:XeEk:q")) != -1) {
while ((ch = mygetopt(argc, argv, "?ac:h:i:j:p:tu:xzNP:RJ:A:XeEk:qK:")) != -1) {
switch (ch) {
case 'h':
host = myoptarg;
@ -763,6 +773,12 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
break;
#endif
#ifdef WOLFSSH_TPM
case 'K':
tpmKeyAuth = myoptarg;
break;
#endif
case '?':
ShowUsage();
exit(EXIT_SUCCESS);
@ -781,12 +797,23 @@ 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.");
}
ret = ClientSetPrivateKey(privKeyName, userEcc, NULL);
#else
if (pubKeyName == NULL && privKeyName != NULL) {
err_sys("If setting priv key, need pub key.");
}
#endif
#endif
#ifdef WOLFSSH_TPM
if (tpmKeyAuth == NULL) {
err_sys("You must specify a password for the TPM key");
}
#endif
ret = ClientSetPrivateKey(privKeyName, userEcc, NULL, tpmKeyAuth);
if (ret != 0) {
err_sys("Error setting private key");
}
@ -840,6 +867,10 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
if (ssh == NULL)
err_sys("Couldn't create wolfSSH session.");
#ifdef WOLFSSH_TPM
if (tpmKeyAuth != NULL)
ClientSetTpm(ssh);
#endif
#if defined(WOLFSSL_PTHREADS) && defined(WOLFSSL_TEST_GLOBAL_REQ)
wolfSSH_SetGlobalReq(ctx, callbackGlobalReq);
wolfSSH_SetGlobalReqCtx(ssh, &ssh); /* dummy ctx */
@ -850,7 +881,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);
}
@ -913,28 +944,44 @@ 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
@ -942,8 +989,12 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
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)
@ -1040,16 +1091,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);
@ -1065,11 +1123,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.");
}
}
@ -1079,6 +1143,7 @@ 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 &&
@ -1086,7 +1151,6 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
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

View File

@ -33,6 +33,12 @@
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/coding.h>
#ifdef WOLFSSH_TPM
#include <wolftpm/tpm2_wrap.h>
#include <hal/tpm_io.h>
#endif
#include "examples/client/common.h"
#if !defined(USE_WINDOWS_API) && !defined(MICROCHIP_PIC32) && \
!defined(WOLFSSH_ZEPHYR)
@ -53,7 +59,8 @@ static byte pubKeyLoaded = 0; /* was a public key loaded */
static byte userPrivateKeyBuf[1191]; /* Size equal to hanselPrivateRsaSz. */
static byte* userPrivateKey = userPrivateKeyBuf;
static word32 userPublicKeyTypeSz = 0;
static word32 userPrivateKeySz = sizeof(userPrivateKeyBuf);
static byte userPrivateKeyAlloc = 0;
static word32 userPrivateKeySz = 0;
static word32 userPrivateKeyTypeSz = 0;
static byte isPrivate = 0;
@ -73,6 +80,10 @@ static const byte publicKeyType[] = "x509v3-ecdsa-sha2-nistp256";
#endif
#ifdef WOLFSSH_TPM
WOLFTPM2_DEV tpmDev;
WOLFTPM2_KEY tpmKey;
#endif /* WOLFSSH_TPM */
#ifndef WOLFSSH_NO_RSA
@ -743,16 +754,235 @@ int ClientUseCert(const char* certName, void* heap)
return ret;
}
#ifdef WOLFSSH_TPM
static int readKeyBlob(const char* filename, WOLFTPM2_KEYBLOB* key)
{
int rc = 0;
#if !defined(NO_FILESYSTEM) && !defined(NO_WRITE_TEMP_FILES)
XFILE fp = NULL;
size_t fileSz = 0;
size_t bytes_read = 0;
byte pubAreaBuffer[sizeof(TPM2B_PUBLIC)];
int pubAreaSize;
WLOG(WS_LOG_DEBUG, "Entering readKeyBlob()");
XMEMSET(key, 0, sizeof(WOLFTPM2_KEYBLOB));
fp = XFOPEN(filename, "rb");
if (fp != XBADFILE) {
XFSEEK(fp, 0, XSEEK_END);
fileSz = XFTELL(fp);
XREWIND(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 = XFREAD(&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 = XFREAD(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 != 0) return rc;
if (fileSz > 0) {
printf("Reading the private part of the key\n");
bytes_read = XFREAD(&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)
XFCLOSE(fp);
#else
(void)filename;
(void)key;
#endif /* !NO_FILESYSTEM && !NO_WRITE_TEMP_FILES */
WLOG(WS_LOG_DEBUG, "Leaving readKeyBlob(), rc = %d", rc);
return rc;
}
static int wolfSSH_TPM_InitKey(WOLFTPM2_DEV* dev, const char* name,
WOLFTPM2_KEY* pTpmKey, const char* tpmKeyAuth)
{
int rc = 0;
WOLFTPM2_KEY endorse;
WOLFTPM2_KEYBLOB tpmKeyBlob;
WOLFTPM2_SESSION tpmSession;
byte* p = NULL;
WLOG(WS_LOG_DEBUG, "Entering wolfSSH_TPM_InitKey()");
/* Initialize the TPM 2.0 device */
if (rc == 0) {
rc = wolfTPM2_Init(dev, TPM2_IoCb, NULL);
if (rc != 0) {
WLOG(WS_LOG_DEBUG,
"TPM 2.0 Device initialization failed, rc: %d", rc);
}
}
/* Create primary endorsement key (EK) */
if (rc == 0) {
rc = wolfTPM2_CreateEK(dev, &endorse, TPM_ALG_RSA);
if (rc != 0) {
WLOG(WS_LOG_DEBUG, "Creating EK failed, rc: %d", rc);
}
}
/* Create and set policy session for EK */
if (rc == 0) {
endorse.handle.policyAuth = 1;
rc = wolfTPM2_CreateAuthSession_EkPolicy(dev, &tpmSession);
if (rc != 0) {
WLOG(WS_LOG_DEBUG,
"Creating EK policy session failed, rc: %d", rc);
}
}
if (rc == 0) {
rc = wolfTPM2_SetAuthSession(dev, 0, &tpmSession, 0);
if (rc != 0) {
WLOG(WS_LOG_DEBUG, "Setting auth session failed, rc: %d", rc);
}
}
/* Load the TPM 2.0 key blob from disk */
if (rc == 0) {
rc = readKeyBlob(name, &tpmKeyBlob);
if (rc != 0) {
WLOG(WS_LOG_DEBUG,
"Reading key blob from disk failed, rc: %d", rc);
}
}
/* Use global auth if provided */
if (rc == 0 && tpmKeyAuth != NULL) {
tpmKeyBlob.handle.auth.size = (word32)XSTRLEN(tpmKeyAuth);
XMEMCPY(tpmKeyBlob.handle.auth.buffer, tpmKeyAuth,
tpmKeyBlob.handle.auth.size);
}
/* Load the public key into the TPM device */
if (rc == 0) {
rc = wolfTPM2_LoadKey(dev, &tpmKeyBlob, &endorse.handle);
if (rc != 0) {
WLOG(WS_LOG_DEBUG, "wolfTPM2_LoadKey failed, rc: %d", rc);
} else {
WLOG(WS_LOG_DEBUG, "Loaded key to 0x%x\n",
(word32)tpmKeyBlob.handle.hndl);
}
}
/* Read the public key and extract the public key as a DER/ASN.1 */
if (rc == 0) {
userPublicKeySz = sizeof(userPublicKeyBuf);
rc = wolfTPM2_ExportPublicKeyBuffer(dev, (WOLFTPM2_KEY*)&tpmKeyBlob,
ENCODING_TYPE_ASN1, userPublicKey, &userPublicKeySz);
if (rc != 0) {
WLOG(WS_LOG_DEBUG, "Exporting TPM key failed, rc: %d", rc);
}
}
/* Read public key from buffer and convert key to OpenSSH format */
if (rc == 0) {
rc = wolfSSH_ReadPublicKey_buffer(userPublicKey, userPublicKeySz,
WOLFSSH_FORMAT_ASN1, &p, &userPublicKeySz, &userPublicKeyType,
&userPublicKeyTypeSz, NULL);
if (rc == 0) {
userPublicKey = p;
} else {
WLOG(WS_LOG_DEBUG, "Reading public key failed, rc: %d", rc);
}
}
/* Copy key info */
if (rc == 0) {
XMEMCPY(&pTpmKey->handle, &tpmKeyBlob.handle, sizeof(pTpmKey->handle));
XMEMCPY(&pTpmKey->pub, &tpmKeyBlob.pub, sizeof(pTpmKey->pub));
wolfTPM2_UnloadHandle(dev, &endorse.handle);
}
WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_TPM_InitKey(), rc = %d", rc);
return rc;
}
static void wolfSSH_TPM_Cleanup(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key)
{
WLOG(WS_LOG_DEBUG, "Entering wolfSSH_TPM_Cleanup()");
if (key != NULL) {
wolfTPM2_UnloadHandle(dev, &key->handle);
}
if (dev != NULL) {
wolfTPM2_Cleanup(dev);
}
WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_TPM_Cleanup()");
}
/* Set the tpm device and key for the client side */
int ClientSetTpm(WOLFSSH* ssh)
{
if (ssh != NULL) {
wolfSSH_SetTpmDev(ssh, &tpmDev);
wolfSSH_SetTpmKey(ssh, &tpmKey);
}
return 0;
}
#endif /* WOLFSSH_TPM */
/* Reads the private key to use from file name privKeyName.
* returns 0 on success */
int ClientSetPrivateKey(const char* privKeyName, int userEcc, void* heap)
int ClientSetPrivateKey(const char* privKeyName, int userEcc,
void* heap, const char* tpmKeyAuth)
{
int ret = 0;
(void)tpmKeyAuth; /* Not used */
if (privKeyName == NULL) {
if (userEcc) {
#ifndef WOLFSSH_NO_ECC
userPrivateKeySz = sizeof(userPrivateKeyBuf);
ret = wolfSSH_ReadKey_buffer(hanselPrivateEcc, hanselPrivateEccSz,
WOLFSSH_FORMAT_ASN1, &userPrivateKey, &userPrivateKeySz,
&userPrivateKeyType, &userPrivateKeyTypeSz, heap);
@ -760,6 +990,7 @@ int ClientSetPrivateKey(const char* privKeyName, int userEcc, void* heap)
}
else {
#ifndef WOLFSSH_NO_RSA
userPrivateKeySz = sizeof(userPrivateKeyBuf);
ret = wolfSSH_ReadKey_buffer(hanselPrivateRsa, hanselPrivateRsaSz,
WOLFSSH_FORMAT_ASN1, &userPrivateKey, &userPrivateKeySz,
&userPrivateKeyType, &userPrivateKeyTypeSz, heap);
@ -768,8 +999,23 @@ int ClientSetPrivateKey(const char* privKeyName, int userEcc, void* heap)
isPrivate = 1;
}
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
*/
WMEMSET(&tpmDev, 0, sizeof(tpmDev));
WMEMSET(&tpmKey, 0, sizeof(tpmKey));
ret = wolfSSH_TPM_InitKey(&tpmDev, privKeyName, &tpmKey, tpmKeyAuth);
#elif !defined(NO_FILESYSTEM)
userPrivateKey = NULL; /* create new buffer based on parsed input */
userPrivateKeyAlloc = 1;
userPrivateKeySz = sizeof(userPrivateKeyBuf);
ret = wolfSSH_ReadKey_file(privKeyName,
(byte**)&userPrivateKey, &userPrivateKeySz,
(const byte**)&userPrivateKeyType, &userPrivateKeyTypeSz,
@ -777,13 +1023,12 @@ int ClientSetPrivateKey(const char* privKeyName, int userEcc, void* heap)
#else
printf("file system not compiled in!\n");
ret = NOT_COMPILED_IN;
#endif
#endif /* WOLFSSH_TPM / NO_FILESYSTEM */
}
return ret;
}
/* Set public key to use
* returns 0 on success */
int ClientUsePubKey(const char* pubKeyName, int userEcc, void* heap)
@ -821,8 +1066,8 @@ int ClientUsePubKey(const char* pubKeyName, int userEcc, void* heap)
&isPrivate, heap);
#else
printf("file system not compiled in!\n");
ret = -1;
#endif
ret = NOT_COMPILED_IN;
#endif /* NO_FILESYSTEM */
if (ret == 0) {
pubKeyLoaded = 1;
}
@ -859,16 +1104,20 @@ int ClientLoadCA(WOLFSSH_CTX* ctx, const char* caCert)
return ret;
}
void ClientFreeBuffers(const char* pubKeyName, const char* privKeyName,
void* heap)
{
word32 entry;
if (pubKeyName != NULL && userPublicKey != NULL) {
#ifdef WOLFSSH_TPM
wolfSSH_TPM_Cleanup(&tpmDev, &tpmKey);
#endif
if (pubKeyName != NULL && userPublicKey != NULL &&
userPublicKey != userPublicKeyBuf) {
WFREE(userPublicKey, heap, DYNTYPE_PRIVKEY);
}
if (privKeyName != NULL && userPrivateKey != NULL) {
if (privKeyName != NULL && userPrivateKey != NULL &&
userPrivateKeyAlloc) {
WFREE(userPrivateKey, heap, DYNTYPE_PRIVKEY);
}

View File

@ -22,16 +22,19 @@
#define WOLFSSH_COMMON_H
int ClientLoadCA(WOLFSSH_CTX* ctx, const char* caCert);
int ClientUsePubKey(const char* pubKeyName, int userEcc, void* heap);
int ClientSetPrivateKey(const char* privKeyName, int userEcc, void* heap);
int ClientSetPrivateKey(const char* privKeyName, int userEcc,
void* heap, const char* tpmKeyAuth);
int ClientUseCert(const char* certName, void* heap);
int ClientSetEcho(int type);
int ClientUserAuth(byte authType,
WS_UserAuthData* authData,
void* ctx);
WS_UserAuthData* authData, void* ctx);
int ClientPublicKeyCheck(const byte* pubKey, word32 pubKeySz, void* ctx);
void ClientIPOverride(int flag);
void ClientFreeBuffers(const char* pubKeyName, const char* privKeyName,
void* heap);
#ifdef WOLFSSH_TPM
int ClientSetTpm(WOLFSSH* ssh);
#endif
#endif /* WOLFSSH_COMMON_H */

View File

@ -43,6 +43,7 @@
#include <wolfssh/agent.h>
#include <wolfssh/test.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/logging.h>
#include "examples/echoserver/echoserver.h"
@ -1783,21 +1784,24 @@ static const char samplePublicKeyEccBuffer[] =
#endif
#ifndef WOLFSSH_NO_RSA
static const char samplePublicKeyRsaBuffer[] =
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9P3ZFowOsONXHD5MwWiCciXytBRZGho"
"MNiisWSgUs5HdHcACuHYPi2W6Z1PBFmBWT9odOrGRjoZXJfDDoPi+j8SSfDGsc/hsCmc3G"
"p2yEhUZUEkDhtOXyqjns1ickC9Gh4u80aSVtwHRnJZh9xPhSq5tLOhId4eP61s+a5pwjTj"
"nEhBaIPUJO2C/M0pFnnbZxKgJlX7t1Doy7h5eXxviymOIvaCZKU+x5OopfzM/wFkey0EPW"
"NmzI5y/+pzU5afsdeEWdiQDIQc80H6Pz8fsoFPvYSG+s4/wz0duu7yeeV1Ypoho65Zr+pE"
"nIf7dO0B8EblgWt+ud+JI8wrAhfE4x hansel\n"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqDwRVTRVk/wjPhoo66+Mztrc31KsxDZ"
"+kAV0139PHQ+wsueNpba6jNn5o6mUTEOrxrz0LMsDJOBM7CmG0983kF4gRIihECpQ0rcjO"
"P6BSfbVTE9mfIK5IsUiZGd8SoE9kSV2pJ2FvZeBQENoAxEFk0zZL9tchPS+OCUGbK4SDjz"
"uNZl/30Mczs73N3MBzi6J1oPo7sFlqzB6ecBjK2Kpjus4Y1rYFphJnUxtKvB0s+hoaadru"
"biE57dK6BrH5iZwVLTQKux31uCJLPhiktI3iLbdlGZEctJkTasfVSsUizwVIyRjhVKmbdI"
"RGwkU38D043AR1h0mUoGCPIKuqcFMf gretel\n";
#endif
#ifdef WOLFSSH_TPM
static const char* sampleTpmPublicKeyRsaBuffer = "";
#else
static const char* samplePublicKeyRsaBuffer =
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqDwRVTRVk/wjPhoo66+Mztrc31KsxDZ"
"+kAV0139PHQ+wsueNpba6jNn5o6mUTEOrxrz0LMsDJOBM7CmG0983kF4gRIihECpQ0rcjO"
"P6BSfbVTE9mfIK5IsUiZGd8SoE9kSV2pJ2FvZeBQENoAxEFk0zZL9tchPS+OCUGbK4SDjz"
"uNZl/30Mczs73N3MBzi6J1oPo7sFlqzB6ecBjK2Kpjus4Y1rYFphJnUxtKvB0s+hoaadru"
"biE57dK6BrH5iZwVLTQKux31uCJLPhiktI3iLbdlGZEctJkTasfVSsUizwVIyRjhVKmbdI"
"RGwkU38D043AR1h0mUoGCPIKuqcFMf gretel\n"
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9P3ZFowOsONXHD5MwWiCciXytBRZGho"
"MNiisWSgUs5HdHcACuHYPi2W6Z1PBFmBWT9odOrGRjoZXJfDDoPi+j8SSfDGsc/hsCmc3G"
"p2yEhUZUEkDhtOXyqjns1ickC9Gh4u80aSVtwHRnJZh9xPhSq5tLOhId4eP61s+a5pwjTj"
"nEhBaIPUJO2C/M0pFnnbZxKgJlX7t1Doy7h5eXxviymOIvaCZKU+x5OopfzM/wFkey0EPW"
"NmzI5y/+pzU5afsdeEWdiQDIQc80H6Pz8fsoFPvYSG+s4/wz0duu7yeeV1Ypoho65Zr+pE"
"nIf7dO0B8EblgWt+ud+JI8wrAhfE4x hansel\n";
#endif /* WOLFSSH_TPM */
#endif /* WOLFSSH_NO_RSA */
#ifdef WOLFSSH_ALLOW_USERAUTH_NONE
@ -2094,6 +2098,46 @@ static int LoadPubKeyList(StrList* strList, int format, PwMapList* mapList)
}
#endif
#ifdef WOLFSSH_TPM
static char* LoadTpmSshKey(const char* keyFile)
{
FILE* file;
char* buffer = NULL;
char* ret = NULL;
long length;
file = fopen(keyFile, "rb");
if (!file) {
fprintf(stderr,
"Failed to open TPM key file: %s\n", keyFile);
return NULL;
}
fseek(file, 0, SEEK_END);
length = ftell(file);
fseek(file, 0, SEEK_SET);
buffer = (char*)WMALLOC(length + 8 + 1, NULL, DYNTYPE_BUFFER);
if (buffer) {
if (fread(buffer, 1, length, file) == (size_t)length) {
while (length > 0 && (buffer[length-1] == '\n' ||
buffer[length-1] == '\r')) {
length--;
}
WMEMCPY(buffer + length, " hansel\n", 8);
buffer[length + 8] = '\0';
ret = buffer;
}
else {
WFREE(buffer, NULL, DYNTYPE_BUFFER);
}
}
fclose(file);
return ret;
}
#endif
static int wsUserAuthResult(byte res,
WS_UserAuthData* authData,
void* ctx)
@ -2357,6 +2401,7 @@ static void ShowUsage(void)
" (user assumed in comment)\n");
printf(" -I <name>:<file>\n"
" load in a SSH public key to accept from peer\n");
printf(" -s <file> load in a TPM public key file to replace default hansel key\n");
printf(" -J <name>:<file>\n"
" load in an X.509 PEM cert to accept from peer\n");
printf(" -K <name>:<file>\n"
@ -2419,6 +2464,9 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args)
const char* macList = NULL;
const char* cipherList = NULL;
ES_HEAP_HINT* heap = NULL;
#ifdef WOLFSSH_TPM
static char* tpmKeyPath = NULL;
#endif
int multipleConnections = 1;
int userEcc = 0;
int peerEcc = 0;
@ -2441,7 +2489,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args)
kbAuthData.promptCount = 0;
if (argc > 0) {
const char* optlist = "?1a:d:efEp:R:Ni:j:i:I:J:K:P:k:b:x:m:c:";
const char* optlist = "?1a:d:efEp:R:Ni:j:i:I:J:K:P:k:b:x:m:c:s:";
myoptind = 0;
while ((ch = mygetopt(argc, argv, optlist)) != -1) {
switch (ch) {
@ -2545,6 +2593,12 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args)
cipherList = myoptarg;
break;
case 's':
#ifdef WOLFSSH_TPM
tpmKeyPath = myoptarg;
#endif
break;
default:
ShowUsage();
serverArgs->return_code = MY_EX_USAGE;
@ -2577,6 +2631,23 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args)
ES_ERROR("Couldn't initialize wolfSSH.\n");
}
/* Load custom TPM key if specified */
#ifdef WOLFSSH_TPM
if (tpmKeyPath != NULL) {
const char* newBuffer = LoadTpmSshKey(tpmKeyPath);
if (newBuffer != NULL) {
sampleTpmPublicKeyRsaBuffer = newBuffer;
}
else {
ES_ERROR("Failed to load TPM key from %s\n", tpmKeyPath);
}
printf("New sampleTpmPublicKeyRsaBuffer:\n%s\n", sampleTpmPublicKeyRsaBuffer);
}
else {
printf("No TPM key loaded\n");
}
#endif
#ifdef WOLFSSH_STATIC_MEMORY
{
int ret;
@ -2791,7 +2862,11 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args)
}
else {
#ifndef WOLFSSH_NO_RSA
bufName = samplePublicKeyRsaBuffer;
#ifdef WOLFSSH_TPM
bufName = sampleTpmPublicKeyRsaBuffer;
#else
bufName = samplePublicKeyRsaBuffer;
#endif
#endif
}
if (bufName != NULL) {
@ -2988,8 +3063,6 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args)
#endif /* NO_WOLFSSH_SERVER */
void wolfSSL_Debugging_ON(void);
int wolfSSH_Echoserver(int argc, char** argv)
{
func_args args;

View File

@ -218,7 +218,7 @@ THREAD_RETURN WOLFSSH_THREAD scp_client(void* args)
err_sys("Empty path values");
}
ret = ClientSetPrivateKey(privKeyName, 0, NULL);
ret = ClientSetPrivateKey(privKeyName, 0, NULL, NULL);
if (ret != 0) {
err_sys("Error setting private key");
}

View File

@ -1317,7 +1317,7 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args)
}
#endif /* WOLFSSH_STATIC_MEMORY */
ret = ClientSetPrivateKey(privKeyName, userEcc, heap);
ret = ClientSetPrivateKey(privKeyName, userEcc, heap, NULL);
if (ret != 0) {
err_sys("Error setting private key");
}

View File

@ -70,6 +70,12 @@
#endif
#endif
#ifdef WOLFSSH_TPM
#include <wolftpm/tpm2_wrap.h>
#include <wolftpm/tpm2.h>
#endif
#include <wolfssl/wolfcrypt/coding.h>
/*
Flags:
@ -1209,43 +1215,22 @@ void SshResourceFree(WOLFSSH* ssh, void* heap)
}
typedef struct WS_KeySignature {
byte keySigId;
word32 sigSz;
const char *name;
void *heap;
word32 nameSz;
union {
#ifndef WOLFSSH_NO_RSA
struct {
RsaKey key;
} rsa;
#endif
#ifndef WOLFSSH_NO_ECDSA
struct {
ecc_key key;
} ecc;
#endif
#ifndef WOLFSSH_NO_ED25519
struct {
ed25519_key key;
} ed25519;
#endif
} ks;
} WS_KeySignature;
static void wolfSSH_KEY_clean(WS_KeySignature* key)
void wolfSSH_KEY_clean(WS_KeySignature* key)
{
if (key != NULL) {
if (key->keySigId == ID_SSH_RSA) {
#ifndef WOLFSSH_NO_RSA
wc_FreeRsaKey(&key->ks.rsa.key);
#endif
}
else if (key->keySigId == ID_ED25519) {
#ifndef WOLFSSH_NO_ED25519
wc_ed25519_free(&key->ks.ed25519.key);
#endif
}
else if (key->keySigId == ID_ECDSA_SHA2_NISTP256 ||
key->keySigId == ID_ECDSA_SHA2_NISTP384 ||
key->keySigId == ID_ECDSA_SHA2_NISTP521) {
key->keySigId == ID_ECDSA_SHA2_NISTP384 ||
key->keySigId == ID_ECDSA_SHA2_NISTP521) {
#ifndef WOLFSSH_NO_ECDSA
wc_ecc_free(&key->ks.ecc.key);
#endif
@ -1264,9 +1249,11 @@ static void wolfSSH_KEY_clean(WS_KeySignature* key)
* @param inSz size of key
* @param isPrivate indicates private or public key
* @param heap heap to use for memory allocation
* @param pkey optionally return populated WS_KeySignature
* @return keyId as int, WS_MEMORY_E, WS_UNIMPLEMENTED_E
*/
int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap)
int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap,
WS_KeySignature **pkey)
{
WS_KeySignature *key = NULL;
word32 idx;
@ -1274,8 +1261,11 @@ int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap)
int dynType = isPrivate ? DYNTYPE_PRIVKEY : DYNTYPE_PUBKEY;
WOLFSSH_UNUSED(dynType);
key = (WS_KeySignature*)WMALLOC(sizeof(WS_KeySignature), heap, dynType);
if (pkey != NULL) {
*pkey = NULL;
}
key = (WS_KeySignature*)WMALLOC(sizeof(WS_KeySignature), heap, dynType);
if (key == NULL) {
ret = WS_MEMORY_E;
}
@ -1304,8 +1294,6 @@ int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap)
key->keySigId = ID_SSH_RSA;
}
}
wc_FreeRsaKey(&key->ks.rsa.key);
}
#endif /* WOLFSSH_NO_RSA */
#ifndef WOLFSSH_NO_ECDSA
@ -1339,8 +1327,6 @@ int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap)
}
}
}
wc_ecc_free(&key->ks.ecc.key);
}
#endif /* WOLFSSH_NO_ECDSA */
#if !defined(WOLFSSH_NO_ED25519)
@ -1348,7 +1334,7 @@ int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap)
idx = 0;
ret = wc_ed25519_init_ex(&key->ks.ed25519.key, heap, INVALID_DEVID);
if(ret == 0) {
if (ret == 0) {
if (isPrivate) {
ret = wc_Ed25519PrivateKeyDecode(in, &idx,
&key->ks.ed25519.key, inSz);
@ -1360,10 +1346,8 @@ int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap)
}
/* If decode was successful, this is a Ed25519 key. */
if(ret == 0)
if (ret == 0)
key->keySigId = ID_ED25519;
wc_ed25519_free(&key->ks.ed25519.key);
}
#endif /* WOLFSSH_NO_ED25519 */
@ -1371,10 +1355,17 @@ int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap)
ret = WS_UNIMPLEMENTED_E;
}
else {
if (pkey != NULL)
*pkey = key;
ret = key->keySigId;
}
WFREE(key, heap, dynType);
/* if not returning key then free it */
if (pkey == NULL || *pkey == NULL) {
wolfSSH_KEY_clean(key);
WFREE(key, heap, dynType);
key = NULL;
}
}
return ret;
@ -1579,6 +1570,96 @@ static int GetOpenSshKeyEd25519(ed25519_key* key,
return ret;
}
#endif
#ifdef WOLFSSH_TPM
#ifndef WOLFSSH_NO_ECDSA
static int GetOpenSshPublicKeyEcc(ecc_key* key, const byte* buf, word32 len,
word32* idx)
{
int ret = WS_CRYPTO_FAILED;
(void)key;
(void)buf;
(void)len;
(void)idx;
/* TODO: Add ECC public key: See DoUserAuthRequestEcc and wc_ecc_import_x963 */
return ret;
}
#endif
#ifndef WOLFSSH_NO_ED25519
static int GetOpenSshKeyPublicEd25519(ed25519_key* key, const byte* buf,
word32 len, word32* idx)
{
int ret = WS_CRYPTO_FAILED;
(void)key;
(void)buf;
(void)len;
(void)idx;
/* TODO: Add ECC public key: See DoUserAuthRequestEd25519 and wc_ed25519_import_public */
return ret;
}
#endif
#ifndef WOLFSSH_NO_RSA
static int GetOpenSshPublicKeyRsa(RsaKey* key, const byte* buf, word32 len,
word32* idx)
{
int ret;
const byte *n = NULL, *e = NULL;
word32 nSz = 0, eSz = 0;
ret = GetMpint(&eSz, &e, buf, len, idx);
if (ret == WS_SUCCESS) {
ret = GetMpint(&nSz, &n, buf, len, idx);
}
if (ret == WS_SUCCESS) {
ret = wc_RsaPublicKeyDecodeRaw(n, nSz, e, eSz, key);
if (ret != 0) {
WLOG(WS_LOG_DEBUG, "Could not decode RSA public key");
ret = WS_CRYPTO_FAILED;
}
}
return ret;
}
#endif
static int GetOpenSshPublicKey(WS_KeySignature *key,
const byte* buf, word32 len, word32* idx)
{
int ret = WS_SUCCESS;
const byte* publicKeyType;
word32 publicKeyTypeSz = 0;
byte keyId;
ret = GetStringRef(&publicKeyTypeSz, &publicKeyType, buf, len, idx);
keyId = NameToId((const char*)publicKeyType, publicKeyTypeSz);
switch (keyId) {
#ifndef WOLFSSH_NO_RSA
case ID_SSH_RSA:
ret = GetOpenSshPublicKeyRsa(&key->ks.rsa.key, buf, len, idx);
break;
#endif
#ifndef WOLFSSH_NO_ECDSA
case ID_ECDSA_SHA2_NISTP256:
case ID_ECDSA_SHA2_NISTP384:
case ID_ECDSA_SHA2_NISTP521:
ret = GetOpenSshPublicKeyEcc(&key->ks.ecc.key, buf, len, idx);
break;
#endif
#ifndef WOLFSSH_NO_ED25519
case ID_ED25519:
ret = GetOpenSshKeyPublicEd25519(&key->ks.ed25519.key, buf, len, idx);
break;
#endif
default:
ret = WS_UNIMPLEMENTED_E;
break;
}
return ret;
}
#endif /* WOLFSSH_TPM */
/*
* Decodes an OpenSSH format key.
*/
@ -1808,10 +1889,11 @@ static int IdentifyCert(const byte* in, word32 inSz, void* heap)
}
if (ret == 0) {
ret = IdentifyAsn1Key(key, keySz, 0, heap);
ret = IdentifyAsn1Key(key, keySz, 0, heap, NULL);
}
if (key != NULL) {
WFREE(key, heap, DYNTYPE_PUBKEY);
}
WFREE(key, heap, DYNTYPE_PUBKEY);
if (cert != NULL) {
wc_FreeDecodedCert(cert);
#ifdef WOLFSSH_SMALL_STACK
@ -2151,9 +2233,10 @@ int wolfSSH_ProcessBuffer(WOLFSSH_CTX* ctx,
/* Maybe decrypt */
if (type == BUFTYPE_PRIVKEY) {
ret = IdentifyAsn1Key(der, derSz, 1, ctx->heap);
ret = IdentifyAsn1Key(der, derSz, 1, ctx->heap, NULL);
if (ret < 0) {
WFREE(der, heap, dynamicType);
if (der != NULL)
WFREE(der, heap, dynamicType);
return ret;
}
keyId = (byte)ret;
@ -7364,9 +7447,14 @@ static int DoUserAuthRequestPublicKey(WOLFSSH* ssh, WS_UserAuthData* authData,
/* Parse the public key format, signature algo, and signature blob. */
if (ret == WS_SUCCESS) {
/* Server expects openssh style ssh-rsa base64encoded public key */
begin = 0;
ret = GetStringRef(&pubKeyFmtSz, &pubKeyFmt,
pubKeyBlob, pubKeyBlobSz, &begin);
if (ret != WS_SUCCESS) {
WLOG(WS_LOG_DEBUG, "DUARPK: Invalid public key format: "
"example: \"ssh-rsa\"");
}
}
if (hasSig) {
@ -7756,6 +7844,11 @@ static int DoUserAuthFailure(WOLFSSH* ssh,
for (j = 0; j < sizeof(ssh->supportedAuth); j++) {
if (authList[i] == ssh->supportedAuth[j]) {
switch(authList[i]) {
#ifdef WOLFSSH_TPM
case ID_USERAUTH_PUBLICKEY:
authType |= WOLFSSH_USERAUTH_PUBLICKEY;
break;
#else /* !WOLFSSH_TPM */
case ID_USERAUTH_PASSWORD:
authType |= WOLFSSH_USERAUTH_PASSWORD;
break;
@ -7767,6 +7860,7 @@ static int DoUserAuthFailure(WOLFSSH* ssh,
authType |= WOLFSSH_USERAUTH_PUBLICKEY;
break;
#endif
#endif /* WOLFSSH_TPM */
default:
break;
}
@ -11621,6 +11715,14 @@ static int SignHRsa(WOLFSSH* ssh, byte* sig, word32* sigSz,
if (ret == WS_SUCCESS) {
WLOG(WS_LOG_INFO, "Signing hash with %s.",
IdToName(ssh->handshake->pubKeyId));
#ifdef WOLFSSH_TPM
if (ssh->ctx->tpmDev && ssh->ctx->tpmKey) {
ret = wolfTPM2_SignHashScheme(ssh->ctx->tpmDev,
ssh->ctx->tpmKey, encSig, encSigSz, sig, (int*)sigSz,
TPM_ALG_RSASSA, TPM2_GetTpmHashType(hashId));
}
else
#endif /* WOLFSSH_TPM */
ret = wc_RsaSSL_Sign(encSig, encSigSz, sig,
KEX_SIG_SIZE, &sigKey->sk.rsa.key,
ssh->rng);
@ -13362,6 +13464,15 @@ static int PrepareUserAuthRequestRsa(WOLFSSH* ssh, word32* payloadSz,
authData->sf.publicKey.publicKeySz);
}
else
#endif /* WOLFSSH_AGENT */
#ifdef WOLFSSH_TPM
if (authData->sf.publicKey.privateKey == NULL ||
authData->sf.publicKey.privateKeySz == 0) {
ret = GetOpenSshPublicKey(keySig,
authData->sf.publicKey.publicKey,
authData->sf.publicKey.publicKeySz, &idx);
}
else
#endif
{
ret = wc_RsaPrivateKeyDecode(authData->sf.publicKey.privateKey,
@ -13459,7 +13570,7 @@ static int BuildUserAuthRequestRsa(WOLFSSH* ssh,
}
}
else
#endif
#endif /* WOLFSSH_AGENT */
{
if (ret == WS_SUCCESS) {
WMEMSET(digest, 0, sizeof(digest));
@ -13515,19 +13626,44 @@ static int BuildUserAuthRequestRsa(WOLFSSH* ssh,
ret = WS_CRYPTO_FAILED;
}
else {
int sigSz;
WLOG(WS_LOG_INFO, "Signing hash with RSA.");
sigSz = wc_RsaSSL_Sign(encDigest, encDigestSz,
#ifdef WOLFSSH_TPM
int sigSz;
sigSz = keySig->sigSz;
if (ssh->ctx->tpmDev && ssh->ctx->tpmKey) {
ret = wc_RsaPad_ex(encDigest, encDigestSz, output+begin,
sigSz, RSA_BLOCK_TYPE_1, ssh->rng, WC_RSA_PKCSV15_PAD,
WC_HASH_TYPE_NONE, WC_MGF1NONE, NULL, 0, 0, 0,
ssh->ctx->heap);
if (ret == 0) {
/* private RSA operation */
ret = wolfTPM2_RsaDecrypt(ssh->ctx->tpmDev,
ssh->ctx->tpmKey, TPM_ALG_NULL, /* no padding */
output+begin, sigSz, output+begin, (int*)&sigSz);
ret = (ret == 0) ? sigSz : WS_RSA_E;
}
}
else {
WLOG(WS_LOG_DEBUG, "SendKexDhReply: TPM key or device not set");
ret = WS_CRYPTO_FAILED;
}
#else /* !WOLFSSH_TPM */
ret = wc_RsaSSL_Sign(encDigest, encDigestSz,
output + begin, keySig->sigSz,
&keySig->ks.rsa.key, ssh->rng);
if (sigSz <= 0 || (word32)sigSz != keySig->sigSz) {
#endif /* WOLFSSH_TPM */
if (ret <= 0 || (word32)ret != keySig->sigSz) {
WLOG(WS_LOG_DEBUG, "SUAR: Bad RSA Sign");
ret = WS_RSA_E;
}
else {
#ifdef WOLFSSH_TPM
ret = 0;
#else
ret = wolfSSH_RsaVerify(output + begin, keySig->sigSz,
encDigest, encDigestSz, &keySig->ks.rsa.key,
ssh->ctx->heap, "SUAR");
#endif
}
}
}
@ -13546,7 +13682,7 @@ static int BuildUserAuthRequestRsa(WOLFSSH* ssh,
}
return ret;
}
} /* END BuildUserAuthRequestRsa */
#ifdef WOLFSSH_CERTS
@ -14405,7 +14541,7 @@ static int BuildUserAuthRequestEd25519(WOLFSSH* ssh,
#if !defined(WOLFSSH_NO_RSA) || !defined(WOLFSSH_NO_ECDSA) \
|| !defined(WOLFSSH_NO_ED25519)
static int PrepareUserAuthRequestPublicKey(WOLFSSH* ssh, word32* payloadSz,
const WS_UserAuthData* authData, WS_KeySignature* keySig)
WS_UserAuthData* authData, WS_KeySignature* keySig)
{
int ret = WS_SUCCESS;
@ -14635,7 +14771,7 @@ static int BuildUserAuthRequestPublicKey(WOLFSSH* ssh,
}
#endif
#endif /* !WOLFSSH_NO_RSA || !WOLFSSH_NO_ECDSA || !WOLFSSH_NO_ED25519 */
int SendUserAuthKeyboardResponse(WOLFSSH* ssh)
{

196
src/ssh.c
View File

@ -400,6 +400,56 @@ const char* wolfSSH_ErrorToName(int err)
}
#ifdef WOLFSSH_TPM
void wolfSSH_SetTpmDev(WOLFSSH* ssh, WOLFTPM2_DEV* dev)
{
WLOG(WS_LOG_DEBUG, "Entering wolfSSH_SetTpmDev()");
if (ssh && ssh->ctx)
ssh->ctx->tpmDev = dev;
if (ssh->ctx->tpmDev == NULL) {
WLOG(WS_LOG_DEBUG, "wolfSSH_SetTpmDev: Set tpm dev failed");
}
}
void wolfSSH_SetTpmKey(WOLFSSH* ssh, WOLFTPM2_KEY* key)
{
WLOG(WS_LOG_DEBUG, "Entering wolfSSH_SetTpmKey()");
if (ssh && ssh->ctx)
ssh->ctx->tpmKey = key;
if (ssh->ctx->tpmDev == NULL) {
WLOG(WS_LOG_DEBUG, "wolfSSH_SetTpmKey: Set tpm key failed");
}
}
void* wolfSSH_GetTpmDev(WOLFSSH* ssh)
{
WLOG(WS_LOG_DEBUG, "Entering wolfSSH_SetTpmDev()");
if (ssh && ssh->ctx) {
return ssh->ctx->tpmDev;
}
return NULL;
}
void* wolfSSH_GetTpmKey(WOLFSSH* ssh)
{
WLOG(WS_LOG_DEBUG, "Entering wolfSSH_SetTpmKey()");
if (ssh && ssh->ctx) {
return ssh->ctx->tpmKey;
}
return NULL;
}
#endif /* WOLFSSH_TPM */
#ifndef NO_WOLFSSH_SERVER
const char acceptError[] = "accept error: %s, %d";
@ -1693,42 +1743,102 @@ static int DoSshPubKey(const byte* in, word32 inSz, byte** out,
static int DoAsn1Key(const byte* in, word32 inSz, byte** out,
word32* outSz, const byte** outType, word32* outTypeSz,
void* heap)
int isPrivate, void* heap)
{
int ret = WS_SUCCESS;
byte* newKey = NULL;
WS_KeySignature* key = NULL;
WOLFSSH_UNUSED(heap);
if (*out == NULL) {
newKey = (byte*)WMALLOC(inSz, heap, DYNTYPE_PRIVKEY);
if (newKey == NULL) {
return WS_MEMORY_E;
}
}
else {
if (*outSz < inSz) {
WLOG(WS_LOG_DEBUG, "DER private key output size too small");
return WS_BUFFER_E;
}
newKey = *out;
ret = IdentifyAsn1Key(in, inSz, isPrivate, heap, &key);
if (ret <= 0) {
WLOG(WS_LOG_DEBUG, "Unable to identify ASN.1 key");
}
ret = IdentifyAsn1Key(in, inSz, 1, heap);
if (ret > 0 && !isPrivate) {
long e;
byte n[RSA_MAX_SIZE]; /* TODO: Handle small stack */
word32 nSz = (word32)sizeof(n), eSz = (word32)sizeof(e);
const char* keyFormat = "ssh-rsa";
word32 idx = 0;
int nMsb = 0;
*outType = (const byte*)IdToName(ret);
*outTypeSz = (word32)WSTRLEN((const char*)*outType);
ret = wc_RsaFlattenPublicKey(&key->ks.rsa.key, (byte*)&e, &eSz, n, &nSz);
if (ret == 0) {
if (n[0] & 0x80) {
/* if MSB is set need leading zero */
nMsb = 1;
}
*outSz = LENGTH_SZ + (word32)WSTRLEN(keyFormat) +
LENGTH_SZ + eSz +
LENGTH_SZ + nSz + nMsb;
newKey = (byte*)WMALLOC(*outSz, heap, DYNTYPE_PRIVKEY);
if (newKey == NULL) {
ret = WS_MEMORY_E;
}
}
if (ret == 0) {
/* encode the key format string */
c32toa((word32)WSTRLEN(keyFormat), &newKey[idx]);
idx += LENGTH_SZ;
WMEMCPY(&newKey[idx], keyFormat, (word32)WSTRLEN(keyFormat));
idx += (word32)WSTRLEN(keyFormat);
/* encode public exponent (e) */
c32toa(eSz, &newKey[idx]);
idx += LENGTH_SZ;
WMEMCPY(&newKey[idx], &e, eSz);
idx += eSz;
/* encode public modulus (n) */
c32toa(nSz + nMsb, &newKey[idx]);
idx += LENGTH_SZ;
if (nMsb) {
newKey[idx++] = 0;
}
WMEMCPY(&newKey[idx], n, nSz);
*out = newKey;
}
}
else if (ret > 0 && isPrivate) {
if (*out == NULL) {
newKey = (byte*)WMALLOC(inSz, heap, DYNTYPE_PRIVKEY);
if (newKey == NULL) {
ret = WS_MEMORY_E;
return ret;
}
}
else {
if (*outSz < inSz) {
WLOG(WS_LOG_DEBUG, "DER private key output size too small");
ret = WS_BUFFER_E;
return ret;
}
newKey = *out;
}
if (ret > 0) {
*out = newKey;
*outSz = inSz;
WMEMCPY(newKey, in, inSz);
*outType = (const byte*)IdToName(ret);
*outTypeSz = (word32)WSTRLEN((const char*)*outType);
ret = WS_SUCCESS;
}
else {
WLOG(WS_LOG_DEBUG, "Unable to identify ASN.1 key");
if (*out == NULL) {
WFREE(newKey, heap, DYNTYPE_PRIVKEY);
}
wolfSSH_KEY_clean(key);
WFREE(key, heap, isPrivate ? DYNTYPE_PRIVKEY : DYNTYPE_PUBKEY);
if (*out == NULL) {
WFREE(newKey, heap, DYNTYPE_PRIVKEY);
}
if (ret > 0) {
ret = WS_SUCCESS;
}
return ret;
@ -1737,7 +1847,7 @@ static int DoAsn1Key(const byte* in, word32 inSz, byte** out,
static int DoPemKey(const byte* in, word32 inSz, byte** out,
word32* outSz, const byte** outType, word32* outTypeSz,
void* heap)
int isPrivate, void* heap)
{
int ret = WS_SUCCESS;
byte* newKey = NULL;
@ -1760,7 +1870,16 @@ static int DoPemKey(const byte* in, word32 inSz, byte** out,
}
/* If it is PEM, convert to ASN1 then process. */
ret = wc_KeyPemToDer(in, inSz, newKey, newKeySz, NULL);
if (isPrivate) {
ret = wc_KeyPemToDer(in, inSz, newKey, newKeySz, NULL);
}
else {
#ifdef WOLFSSH_TPM
ret = wc_PubKeyPemToDer(in, inSz, newKey, newKeySz);
#else
ret = NOT_COMPILED_IN;
#endif
}
if (ret > 0) {
newKeySz = (word32)ret;
ret = WS_SUCCESS;
@ -1771,7 +1890,7 @@ static int DoPemKey(const byte* in, word32 inSz, byte** out,
}
if (ret == WS_SUCCESS) {
ret = IdentifyAsn1Key(newKey, newKeySz, 1, heap);
ret = IdentifyAsn1Key(newKey, newKeySz, 1, heap, NULL);
}
if (ret > 0) {
@ -1853,9 +1972,9 @@ static int DoOpenSshKey(const byte* in, word32 inSz, byte** out,
to a constant string. Format indicates the format of the key, currently
either SSH format (a public key) or ASN.1 in DER or PEM format (a
private key). */
int wolfSSH_ReadKey_buffer(const byte* in, word32 inSz, int format,
int wolfSSH_ReadKey_buffer_ex(const byte* in, word32 inSz, int format,
byte** out, word32* outSz, const byte** outType, word32* outTypeSz,
void* heap)
int isPrivate, void* heap)
{
int ret = WS_SUCCESS;
@ -1867,10 +1986,12 @@ int wolfSSH_ReadKey_buffer(const byte* in, word32 inSz, int format,
ret = DoSshPubKey(in, inSz, out, outSz, outType, outTypeSz, heap);
}
else if (format == WOLFSSH_FORMAT_ASN1) {
ret = DoAsn1Key(in, inSz, out, outSz, outType, outTypeSz, heap);
ret = DoAsn1Key(in, inSz, out, outSz, outType, outTypeSz,
isPrivate, heap);
}
else if (format == WOLFSSH_FORMAT_PEM) {
ret = DoPemKey(in, inSz, out, outSz, outType, outTypeSz, heap);
ret = DoPemKey(in, inSz, out, outSz, outType, outTypeSz,
isPrivate, heap);
}
else if (format == WOLFSSH_FORMAT_OPENSSH) {
ret = DoOpenSshKey(in, inSz, out, outSz, outType, outTypeSz, heap);
@ -1882,6 +2003,21 @@ int wolfSSH_ReadKey_buffer(const byte* in, word32 inSz, int format,
return ret;
}
int wolfSSH_ReadKey_buffer(const byte* in, word32 inSz, int format,
byte** out, word32* outSz, const byte** outType, word32* outTypeSz,
void* heap)
{
return wolfSSH_ReadKey_buffer_ex(in, inSz, format, out, outSz,
outType, outTypeSz, 1, heap);
}
int wolfSSH_ReadPublicKey_buffer(const byte* in, word32 inSz, int format,
byte** out, word32* outSz, const byte** outType, word32* outTypeSz,
void* heap)
{
return wolfSSH_ReadKey_buffer_ex(in, inSz, format, out, outSz,
outType, outTypeSz, 0, heap);
}
#if !defined(NO_FILESYSTEM) && !defined(WOLFSSH_USER_FILESYSTEM)
@ -1958,8 +2094,8 @@ int wolfSSH_ReadKey_file(const char* name,
format = WOLFSSH_FORMAT_ASN1;
}
ret = wolfSSH_ReadKey_buffer(in, inSz, format,
out, outSz, outType, outTypeSz, heap);
ret = wolfSSH_ReadKey_buffer_ex(in, inSz, format,
out, outSz, outType, outTypeSz, *isPrivate, heap);
}
WFCLOSE(ssh->fs, file);

View File

@ -137,7 +137,7 @@ enum WS_ErrorCodes {
WS_AUTH_PENDING = -1096, /* User authentication still pending */
WS_KDF_E = -1097, /* KDF error*/
WS_LAST_E = -1097 /* Update this to indicate last error */
WS_LAST_E = WS_KDF_E /* Update this to indicate last error */
};

View File

@ -38,6 +38,8 @@
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/rsa.h>
#include <wolfssl/wolfcrypt/curve25519.h>
#include <wolfssl/wolfcrypt/ed25519.h>
#ifdef WOLFSSH_SCP
#include <wolfssh/wolfscp.h>
#endif
@ -48,6 +50,9 @@
#include <wolfssh/certman.h>
#endif /* WOLFSSH_CERTS */
#ifdef WOLFSSH_TPM
#include <wolftpm/tpm2_wrap.h>
#endif /* WOLFSSH_TPM */
#if !defined (ALIGN16)
#if defined (__GNUC__)
@ -572,6 +577,10 @@ struct WOLFSSH_CTX {
#ifdef WOLFSSH_AGENT
byte agentEnabled;
#endif /* WOLFSSH_AGENT */
#ifdef WOLFSSH_TPM
WOLFTPM2_DEV* tpmDev;
WOLFTPM2_KEY* tpmKey;
#endif /* WOLFSSH_TPM */
WS_CallbackKeyingCompletion keyingCompletionCb;
};
@ -952,14 +961,43 @@ WOLFSSH_LOCAL void ChannelDelete(WOLFSSH_CHANNEL*, void*);
WOLFSSH_LOCAL WOLFSSH_CHANNEL* ChannelFind(WOLFSSH*, word32, byte);
WOLFSSH_LOCAL int ChannelRemove(WOLFSSH*, word32, byte);
WOLFSSH_LOCAL int ChannelPutData(WOLFSSH_CHANNEL*, byte*, word32);
WOLFSSH_LOCAL int IdentifyAsn1Key(const byte* in, word32 inSz,
int isPrivate, void* heap);
WOLFSSH_LOCAL int IdentifyOpenSshKey(const byte* in, word32 inSz, void* heap);
WOLFSSH_LOCAL int wolfSSH_ProcessBuffer(WOLFSSH_CTX*,
const byte*, word32,
int, int);
WOLFSSH_LOCAL int wolfSSH_FwdWorker(WOLFSSH*);
typedef struct WS_KeySignature {
byte keySigId;
word32 sigSz;
const char *name;
void *heap;
word32 nameSz;
union {
#ifndef WOLFSSH_NO_RSA
struct {
RsaKey key;
} rsa;
#endif
#ifndef WOLFSSH_NO_ECDSA
struct {
ecc_key key;
} ecc;
#endif
#ifndef WOLFSSH_NO_ED25519
struct {
ed25519_key key;
} ed25519;
#endif
} ks;
} WS_KeySignature;
WOLFSSH_LOCAL int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap,
WS_KeySignature **pkey);
WOLFSSH_LOCAL void wolfSSH_KEY_clean(WS_KeySignature* key);
WOLFSSH_LOCAL int IdentifyOpenSshKey(const byte* in, word32 inSz, void* heap);
/* Parsing functions */
WOLFSSH_LOCAL int GetBoolean(byte* v,
const byte* buf, word32 len, word32* idx);

View File

@ -39,6 +39,10 @@
#include <wolfssh/port.h>
#include <wolfssh/error.h>
#ifdef WOLFSSH_TPM
#include <wolftpm/tpm2_wrap.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -83,9 +87,16 @@ WOLFSSH_API void wolfSSH_SetHighwaterCb(WOLFSSH_CTX*, word32,
WOLFSSH_API void wolfSSH_SetHighwaterCtx(WOLFSSH*, void*);
WOLFSSH_API void* wolfSSH_GetHighwaterCtx(WOLFSSH*);
WOLFSSH_API int wolfSSH_ReadKey_buffer_ex(const byte* in, word32 inSz, int format,
byte** out, word32* outSz, const byte** outType, word32* outTypeSz,
int isPrivate, void* heap);
WOLFSSH_API int wolfSSH_ReadKey_buffer(const byte* in, word32 inSz, int format,
byte** out, word32* outSz, const byte** outType, word32* outTypeSz,
void* heap);
WOLFSSH_API int wolfSSH_ReadPublicKey_buffer(const byte* in, word32 inSz, int format,
byte** out, word32* outSz, const byte** outType, word32* outTypeSz,
void* heap);
WOLFSSH_API int wolfSSH_ReadKey_file(const char* name,
byte** out, word32* outSz, const byte** outType, word32* outTypeSz,
byte* isPrivate, void* heap);
@ -258,6 +269,14 @@ WOLFSSH_API int wolfSSH_get_error(const WOLFSSH*);
WOLFSSH_API const char* wolfSSH_get_error_name(const WOLFSSH*);
WOLFSSH_API const char* wolfSSH_ErrorToName(int);
/* TPM 2.0 integration related functions */
#ifdef WOLFSSH_TPM
WOLFSSH_API void wolfSSH_SetTpmDev(WOLFSSH* ssh, WOLFTPM2_DEV* dev);
WOLFSSH_API void wolfSSH_SetTpmKey(WOLFSSH* ssh, WOLFTPM2_KEY* key);
WOLFSSH_API void* wolfSSH_GetTpmDev(WOLFSSH* ssh);
WOLFSSH_API void* wolfSSH_GetTpmKey(WOLFSSH* ssh);
#endif /* WOLFSSH_TPM */
/* I/O callbacks */
typedef int (*WS_CallbackIORecv)(WOLFSSH*, void*, word32, void*);
typedef int (*WS_CallbackIOSend)(WOLFSSH*, void*, word32, void*);