mirror of https://github.com/wolfSSL/wolfssh.git
Rebase for tpm public key authentication with wolfssh
parent
e5042df0c1
commit
77c8db6cc2
|
@ -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
|
61
README.md
61
README.md
|
@ -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
|
||||
====================
|
||||
|
|
14
configure.ac
14
configure.ac
|
@ -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"])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
240
src/internal.c
240
src/internal.c
|
@ -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
196
src/ssh.c
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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*);
|
||||
|
|
Loading…
Reference in New Issue