diff --git a/.gitignore b/.gitignore
index b2fb7e02..1de1eddc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,6 +48,7 @@ diff
.vimrc
# examples
+examples/client/client
examples/echoserver/echoserver
examples/server/server
diff --git a/README.md b/README.md
index b771d716..f4b83b2e 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ wolfSSH is dependent on wolfCrypt. The simplest configuration of wolfSSL
required for wolfSSH is the default build.
$ cd wolfssl
- $ ./configure [OPTIONS]
+ $ ./configure [OPTIONS] CPPFLAGS=-DWOLFSSL_PUBLIC_MP
$ make check
$ sudo make install
@@ -95,6 +95,8 @@ release notes
- Added ECDH Group Exchange with SHA2 hashing and curves nistp256,
nistp384, and nistp521.
- Added ECDSA with SHA2 hashing and curves nistp256, nistp384, and nistp521.
+- Added client support.
+- Added an example client.
- Changed the echoserver to allow only one connection, but multiple
connections are allowed with a command line option.
- Added option to echoserver to offer an ECC public key.
diff --git a/configure.ac b/configure.ac
index 918327c7..f8a13cc6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -68,9 +68,6 @@ TAO_REQUIRE_LIBWOLFSSL
#REQUIRE_CYASSL([scep])
#REQUIRE_WOLFCRYPT([aes rsa dh])
-# Disable any client code. For size, as nothing calls it.
-AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSL_NO_CLIENT"
-
# since we have autoconf available, we can use cyassl options header
AM_CPPFLAGS="$AM_CPPFLAGS -DHAVE_CYASSL_OPTIONS"
diff --git a/examples/client/client.c b/examples/client/client.c
new file mode 100644
index 00000000..5a2cdd47
--- /dev/null
+++ b/examples/client/client.c
@@ -0,0 +1,295 @@
+/* client.c
+ *
+ * Copyright (C) 2014-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSH.
+ *
+ * wolfSSH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with wolfSSH. If not, see .
+ */
+
+
+#define SINGLE_THREADED
+ /* The client doesn't use threading. */
+
+#include
+#include
+#include "examples/client/client.h"
+#ifndef USE_WINDOWS_API
+ #include
+#endif
+
+
+const char testString[] = "Hello, wolfSSH!";
+
+
+#ifndef USE_WINDOWS_API
+ static struct termios originalTerm;
+#else
+ static DWORD originalTerm;
+#endif
+
+static int InitEcho(void)
+{
+#ifndef USE_WINDOWS_API
+ return tcgetattr(STDIN_FILENO, &originalTerm);
+#else
+ HANDLE stdinHandle = GetStdHandle(STD_INPUT_HANDLE);
+ return (GetConsoleMode(stdinHandle, &originalTerm) == 0);
+#endif
+}
+
+
+static int SetEcho(int on)
+{
+#ifndef USE_WINDOWS_API
+ if (on) {
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &originalTerm) != 0) {
+ printf("Couldn't restore the terminal settings.\n");
+ return -1;
+ }
+ }
+ else {
+ struct termios newTerm;
+ memcpy(&newTerm, &originalTerm, sizeof(struct termios));
+
+ newTerm.c_lflag &= ~ECHO;
+ newTerm.c_lflag |= (ICANON | ECHONL);
+
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &newTerm) != 0) {
+ printf("Couldn't turn off echo.\n");
+ return -1;
+ }
+ }
+#else
+ HANDLE stdinHandle = GetStdHandle(STD_INPUT_HANDLE);
+ if (on) {
+ if (SetConsoleMode(stdinHandle, originalTerm) == 0) {
+ printf("Couldn't restore the terminal settings.\n");
+ return -1;
+ }
+ }
+ else {
+ DWORD newTerm = originalTerm;
+
+ newTerm &= ~ENABLE_ECHO_INPUT;
+
+ if (SetConsoleMode(stdinHandle, newTerm) == 0) {
+ printf("Couldn't turn off echo.\n");
+ return -1;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+
+static void ShowUsage(void)
+{
+ printf("client %s\n", LIBWOLFSSH_VERSION_STRING);
+ printf(" -? display this help and exit\n");
+ printf(" -h host to connect to, default %s\n", wolfSshIp);
+ printf(" -p port to connect on, default %d\n", wolfSshPort);
+ printf(" -u username to authenticate as (REQUIRED)\n");
+ printf(" -P password for username, prompted if omitted\n");
+}
+
+
+byte userPassword[256];
+
+static int wsUserAuth(byte authType,
+ WS_UserAuthData* authData,
+ void* ctx)
+{
+ const char* defaultPassword = (const char*)ctx;
+ word32 passwordSz;
+ int ret = WOLFSSH_USERAUTH_SUCCESS;
+
+ (void)authType;
+ if (defaultPassword != NULL) {
+ passwordSz = (word32)strlen(defaultPassword);
+ memcpy(userPassword, defaultPassword, passwordSz);
+ }
+ else {
+ printf("Password: ");
+ SetEcho(0);
+ if (fgets((char*)userPassword, sizeof(userPassword), stdin) == NULL) {
+ printf("Getting password failed.\n");
+ ret = WOLFSSH_USERAUTH_FAILURE;
+ }
+ else {
+ char* c = strpbrk((char*)userPassword, "\r\n");;
+ if (c != NULL)
+ *c = '\0';
+ passwordSz = (word32)strlen((const char*)userPassword);
+ }
+ SetEcho(1);
+#ifdef USE_WINDOWS_API
+ printf("\r\n");
+#endif
+ }
+
+ if (ret == WOLFSSH_USERAUTH_SUCCESS) {
+ authData->sf.password.password = userPassword;
+ authData->sf.password.passwordSz = passwordSz;
+ }
+
+ return ret;
+}
+
+
+THREAD_RETURN WOLFSSH_THREAD client_test(void* args)
+{
+ WOLFSSH_CTX* ctx = NULL;
+ WOLFSSH* ssh = NULL;
+ SOCKET_T sockFd = WOLFSSH_SOCKET_INVALID;
+ SOCKADDR_IN_T clientAddr;
+ socklen_t clientAddrSz = sizeof(clientAddr);
+ char rxBuf[80];
+ int ret;
+ char ch;
+ word16 port = wolfSshPort;
+ char* host = (char*)wolfSshIp;
+ const char* username = NULL;
+ const char* password = NULL;
+
+ int argc = ((func_args*)args)->argc;
+ char** argv = ((func_args*)args)->argv;
+ ((func_args*)args)->return_code = 0;
+
+ while ((ch = mygetopt(argc, argv, "?h:p:u:P:")) != -1) {
+ switch (ch) {
+ case 'h':
+ host = myoptarg;
+ break;
+
+ case 'p':
+ port = (word16)atoi(myoptarg);
+ #if !defined(NO_MAIN_DRIVER) || defined(USE_WINDOWS_API)
+ if (port == 0)
+ err_sys("port number cannot be 0");
+ #endif
+ break;
+
+ case 'u':
+ username = myoptarg;
+ break;
+
+ case 'P':
+ password = myoptarg;
+ break;
+
+ case '?':
+ ShowUsage();
+ exit(EXIT_SUCCESS);
+
+ default:
+ ShowUsage();
+ exit(MY_EX_USAGE);
+ }
+ }
+ myoptind = 0; /* reset for test cases */
+
+ if (username == NULL)
+ err_sys("client requires a username parameter.");
+
+ ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL);
+ if (ctx == NULL)
+ err_sys("Couldn't create wolfSSH client context.");
+
+ wolfSSH_SetUserAuth(ctx, wsUserAuth);
+
+ ssh = wolfSSH_new(ctx);
+ if (ssh == NULL)
+ err_sys("Couldn't create wolfSSH session.");
+
+ if (password != NULL)
+ wolfSSH_SetUserAuthCtx(ssh, (void*)password);
+
+ ret = wolfSSH_SetUsername(ssh, username);
+ if (ret != WS_SUCCESS)
+ err_sys("Couldn't set the username.");
+
+ build_addr(&clientAddr, host, port);
+ tcp_socket(&sockFd);
+ ret = connect(sockFd, (const struct sockaddr *)&clientAddr, clientAddrSz);
+ if (ret != 0)
+ err_sys("Couldn't connect to server.");
+
+ ret = wolfSSH_set_fd(ssh, (int)sockFd);
+ if (ret != WS_SUCCESS)
+ err_sys("Couldn't set the session's socket.");
+
+ ret = wolfSSH_connect(ssh);
+ if (ret != WS_SUCCESS)
+ err_sys("Couldn't connect SSH stream.");
+
+ ret = wolfSSH_stream_send(ssh, (byte*)testString,
+ (word32)strlen(testString));
+ if (ret <= 0)
+ err_sys("Couldn't send test string.");
+
+ ret = wolfSSH_stream_read(ssh, (byte*)rxBuf, sizeof(rxBuf) - 1);
+ if (ret <= 0)
+ err_sys("Stream read failed.");
+ rxBuf[ret] = '\0';
+ printf("Server said: %s\n", rxBuf);
+
+ ret = wolfSSH_shutdown(ssh);
+ if (ret != WS_SUCCESS)
+ err_sys("Closing stream failed.");
+
+ WCLOSESOCKET(sockFd);
+ wolfSSH_free(ssh);
+ wolfSSH_CTX_free(ctx);
+
+ return 0;
+}
+
+
+#ifndef NO_MAIN_DRIVER
+
+ int main(int argc, char** argv)
+ {
+ func_args args;
+
+ args.argc = argc;
+ args.argv = argv;
+ args.return_code = 0;
+
+ WSTARTTCP();
+
+ if (InitEcho() != 0)
+ err_sys("Couldn't initialize terminal.");
+
+ #ifdef DEBUG_WOLFSSH
+ wolfSSH_Debugging_ON();
+ #endif
+
+ wolfSSH_Init();
+
+ ChangeToWolfSshRoot();
+ #ifndef NO_WOLFSSH_CLIENT
+ client_test(&args);
+ #endif /* NO_WOLFSSH_CLIENT */
+
+ wolfSSH_Cleanup();
+
+ return args.return_code;
+ }
+
+ int myoptind = 0;
+ char* myoptarg = NULL;
+
+#endif /* NO_MAIN_DRIVER */
diff --git a/examples/client/client.h b/examples/client/client.h
new file mode 100644
index 00000000..57eaaa24
--- /dev/null
+++ b/examples/client/client.h
@@ -0,0 +1,31 @@
+/* client.h
+ *
+ * Copyright (C) 2014-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSH.
+ *
+ * wolfSSH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with wolfSSH. If not, see .
+ */
+
+
+#pragma once
+
+#ifndef _WOLFSSH_CLIENT_H_
+#define _WOLFSSH_CLIENT_H_
+
+
+THREAD_RETURN WOLFSSH_THREAD client_test(void* args);
+
+
+#endif /* _WOLFSSH_CLIENT_H_ */
diff --git a/examples/client/include.am b/examples/client/include.am
new file mode 100644
index 00000000..7d085127
--- /dev/null
+++ b/examples/client/include.am
@@ -0,0 +1,11 @@
+# vim:ft=automake
+# All paths should be given relative to the root
+
+noinst_PROGRAMS += examples/client/client
+noinst_HEADERS += examples/client/client.h
+examples_client_client_SOURCES = examples/client/client.c
+examples_client_client_LDADD = src/libwolfssh.la
+examples_client_client_DEPENDENCIES = src/libwolfssh.la
+
+dist_example_DATA+= examples/client/client.c
+DISTCLEANFILES+= examples/client/.libs/client
diff --git a/examples/echoserver/echoserver.h b/examples/echoserver/echoserver.h
old mode 100755
new mode 100644
diff --git a/examples/include.am b/examples/include.am
index d9060ccb..5bf75eee 100644
--- a/examples/include.am
+++ b/examples/include.am
@@ -2,4 +2,5 @@
# included from Top Level Makefile.am
# All paths should be given relative to the root
+include examples/client/include.am
include examples/echoserver/include.am
diff --git a/examples/server/server.c b/examples/server/server.c
index 73251767..cb0cae92 100644
--- a/examples/server/server.c
+++ b/examples/server/server.c
@@ -1,6 +1,6 @@
/* server.c
*
- * Copyright (C) 2014-2016 wolfSSL Inc.
+ * Copyright (C) 2014-2017 wolfSSL Inc.
*
* This file is part of wolfSSH.
*
@@ -19,286 +19,165 @@
*/
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+#ifdef WOLFSSL_USER_SETTINGS
+ #include
+#else
+ #include
+#endif
+
+#include
+#include
#include
-#ifndef SO_NOSIGPIPE
- #include
-#endif
+#include
+#include "examples/server/server.h"
-typedef int SOCKET_T;
-#ifdef TEST_IPV6
- typedef struct sockaddr_in6 SOCKADDR_IN_T;
- #define AF_INET_V AF_INET6
- static const char* wolfsshIP = "::1";
-#else
- typedef struct sockaddr_in SOCKADDR_IN_T;
- #define AF_INET_V AF_INET
- static const char* wolfsshIP = "127.0.0.1";
-#endif
-#define SERVER_PORT_NUMBER 22222
-#define SCRATCH_BUFFER_SIZE 1200
+static const char serverBanner[] = "wolfSSH Example Server\n";
-#if defined(__MACH__) || defined(USE_WINDOWS_API)
- #ifndef _SOCKLEN_T
- typedef int socklen_t;
- #endif
-#endif
-/* HPUX doesn't use socklent_t for third parameter to accept, unless
- _XOPEN_SOURCE_EXTENDED is defined */
-#if !defined(__hpux__) && !defined(CYASSL_MDK_ARM) && !defined(CYASSL_IAR_ARM)
- typedef socklen_t SOCKLEN_T;
-#else
- #if defined _XOPEN_SOURCE_EXTENDED
- typedef socklen_t SOCKLEN_T;
- #else
- typedef int SOCKLEN_T;
- #endif
-#endif
-
-
-#if defined(_POSIX_THREADS) && !defined(__MINGW32__)
- typedef void* THREAD_RETURN;
- typedef pthread_t THREAD_TYPE;
- #define CYASSL_THREAD
- #define INFINITE -1
- #define WAIT_OBJECT_0 0L
-#elif defined(CYASSL_MDK_ARM)
- typedef unsigned int THREAD_RETURN;
- typedef int THREAD_TYPE;
- #define CYASSL_THREAD
-#else
- typedef unsigned int THREAD_RETURN;
- typedef intptr_t THREAD_TYPE;
- #define CYASSL_THREAD __stdcall
-#endif
typedef struct {
- SOCKET_T clientFd;
+ WOLFSSH* ssh;
+ SOCKET_T fd;
+ word32 id;
} thread_ctx_t;
-#ifdef __GNUC__
- #define WS_NORETURN __attribute__((noreturn))
-#else
- #define WS_NORETURN
+#ifndef EXAMPLE_HIGHWATER_MARK
+ #define EXAMPLE_HIGHWATER_MARK 0x3FFF8000 /* 1GB - 32kB */
#endif
-
-
-static INLINE WS_NORETURN void err_sys(const char* msg)
-{
- printf("server error: %s\n", msg);
-
-#ifndef __GNUC__
- /* scan-build (which pretends to be gnuc) can get confused and think the
- * msg pointer can be null even when hardcoded and then it won't exit,
- * making null pointer checks above the err_sys() call useless.
- * We could just always exit() but some compilers will complain about no
- * possible return, with gcc we know the attribute to handle that with
- * WS_NORETURN. */
- if (msg)
+#ifndef EXAMPLE_BUFFER_SZ
+ #define EXAMPLE_BUFFER_SZ 4096
#endif
- {
- exit(EXIT_FAILURE);
- }
-}
+#define SCRATCH_BUFFER_SZ 1200
-static INLINE void build_addr(SOCKADDR_IN_T* addr, const char* peer,
- uint16_t port)
+static byte find_char(const byte* str, const byte* buf, word32 bufSz)
{
- int useLookup = 0;
- (void)useLookup;
+ const byte* cur;
- memset(addr, 0, sizeof(SOCKADDR_IN_T));
-
-#ifndef TEST_IPV6
- /* peer could be in human readable form */
- if ( (peer != INADDR_ANY) && isalpha((int)peer[0])) {
- #ifdef CYASSL_MDK_ARM
- int err;
- struct hostent* entry = gethostbyname(peer, &err);
- #else
- struct hostent* entry = gethostbyname(peer);
- #endif
-
- if (entry) {
- memcpy(&addr->sin_addr.s_addr, entry->h_addr_list[0],
- entry->h_length);
- useLookup = 1;
+ while (bufSz) {
+ cur = str;
+ while (*cur != '\0') {
+ if (*cur == *buf)
+ return *cur;
+ cur++;
}
- else
- err_sys("no entry for host");
+ buf++;
+ bufSz--;
}
-#endif
-
-#ifndef TEST_IPV6
- #if defined(CYASSL_MDK_ARM)
- addr->sin_family = PF_INET;
- #else
- addr->sin_family = AF_INET_V;
- #endif
- addr->sin_port = htons(port);
- if (peer == INADDR_ANY)
- addr->sin_addr.s_addr = INADDR_ANY;
- else {
- if (!useLookup)
- addr->sin_addr.s_addr = inet_addr(peer);
- }
-#else
- addr->sin6_family = AF_INET_V;
- addr->sin6_port = htons(port);
- if (peer == INADDR_ANY)
- addr->sin6_addr = in6addr_any;
- else {
- #ifdef HAVE_GETADDRINFO
- struct addrinfo hints;
- struct addrinfo* answer = NULL;
- int ret;
- char strPort[80];
-
- memset(&hints, 0, sizeof(hints));
-
- hints.ai_family = AF_INET_V;
- hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM;
- hints.ai_protocol = udp ? IPPROTO_UDP : IPPROTO_TCP;
-
- SNPRINTF(strPort, sizeof(strPort), "%d", port);
- strPort[79] = '\0';
-
- ret = getaddrinfo(peer, strPort, &hints, &answer);
- if (ret < 0 || answer == NULL)
- err_sys("getaddrinfo failed");
-
- memcpy(addr, answer->ai_addr, answer->ai_addrlen);
- freeaddrinfo(answer);
- #else
- printf("no ipv6 getaddrinfo, loopback only tests/examples\n");
- addr->sin6_addr = in6addr_loopback;
- #endif
- }
-#endif
-}
-
-
-static INLINE void tcp_socket(SOCKET_T* sockFd)
-{
- *sockFd = socket(AF_INET_V, SOCK_STREAM, 0);
-
-#ifdef USE_WINDOWS_API
- if (*sockFd == INVALID_SOCKET)
- err_sys("socket failed\n");
-#else
- if (*sockFd < 0)
- err_sys("socket failed\n");
-#endif
-
-#ifndef USE_WINDOWS_API
-#ifdef SO_NOSIGPIPE
- {
- int on = 1;
- socklen_t len = sizeof(on);
- int res = setsockopt(*sockFd, SOL_SOCKET, SO_NOSIGPIPE, &on, len);
- if (res < 0)
- err_sys("setsockopt SO_NOSIGPIPE failed\n");
- }
-#elif defined(CYASSL_MDK_ARM)
- /* nothing to define */
-#else /* no S_NOSIGPIPE */
- signal(SIGPIPE, SIG_IGN);
-#endif /* S_NOSIGPIPE */
-
-#if defined(TCP_NODELAY)
- {
- int on = 1;
- socklen_t len = sizeof(on);
- int res = setsockopt(*sockFd, IPPROTO_TCP, TCP_NODELAY, &on, len);
- if (res < 0)
- err_sys("setsockopt TCP_NODELAY failed\n");
- }
-#endif
-#endif /* USE_WINDOWS_API */
-}
-
-
-static INLINE void tcp_bind(SOCKET_T* sockFd, uint16_t port, int useAnyAddr)
-{
- SOCKADDR_IN_T addr;
-
- /* don't use INADDR_ANY by default, firewall may block, make user switch
- on */
- build_addr(&addr, (useAnyAddr ? INADDR_ANY : wolfsshIP), port);
- tcp_socket(sockFd);
-
-#if !defined(USE_WINDOWS_API) && !defined(CYASSL_MDK_ARM)
- {
- int res, on = 1;
- socklen_t len = sizeof(on);
- res = setsockopt(*sockFd, SOL_SOCKET, SO_REUSEADDR, &on, len);
- if (res < 0)
- err_sys("setsockopt SO_REUSEADDR failed\n");
- }
-#endif
-
- if (bind(*sockFd, (const struct sockaddr*)&addr, sizeof(addr)) != 0)
- err_sys("tcp bind failed");
-}
-
-
-static THREAD_RETURN CYASSL_THREAD server_worker(void* vArgs)
-{
- WOLFSSH* ssh = (WOLFSSH*)vArgs;
- SOCKET_T clientFd = wolfSSH_get_fd(ssh);
- const char* msgA = "Who's there?!\r\n";
- const char* msgB = "Go away!\r\n";
-
- char rxBuf[4096];
- int rxBufSz;
-
- if (wolfSSH_accept(ssh) == WS_SUCCESS) {
-
- wolfSSH_stream_send(ssh, (uint8_t*)msgA, (uint32_t)strlen(msgA));
-
- rxBufSz = wolfSSH_stream_read(ssh, (uint8_t*)rxBuf, sizeof(rxBuf));
- if (rxBufSz > 0) {
- rxBuf[rxBufSz] = 0;
- printf("client sent %d bytes\n%s", rxBufSz, rxBuf);
- }
- else
- printf("wolfSSH_stream_read returned %d\n", rxBufSz);
-
- wolfSSH_stream_send(ssh, (uint8_t*)msgB, (uint32_t)strlen(msgB));
- }
- close(clientFd);
- wolfSSH_free(ssh);
return 0;
}
-static int load_file(const char* fileName, uint8_t* buf, uint32_t bufSz)
+static int dump_stats(thread_ctx_t* ctx)
+{
+ char stats[1024];
+ word32 statsSz;
+ word32 txCount, rxCount, seq, peerSeq;
+
+ wolfSSH_GetStats(ctx->ssh, &txCount, &rxCount, &seq, &peerSeq);
+
+ WSNPRINTF(stats, sizeof(stats),
+ "Statistics for Thread #%u:\r\n"
+ " txCount = %u\r\n rxCount = %u\r\n"
+ " seq = %u\r\n peerSeq = %u\r\n",
+ ctx->id, txCount, rxCount, seq, peerSeq);
+ statsSz = (word32)strlen(stats);
+
+ fprintf(stderr, "%s", stats);
+ return wolfSSH_stream_send(ctx->ssh, (byte*)stats, statsSz);
+}
+
+
+static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs)
+{
+ thread_ctx_t* threadCtx = (thread_ctx_t*)vArgs;
+
+ if (wolfSSH_accept(threadCtx->ssh) == WS_SUCCESS) {
+ byte* buf = NULL;
+ byte* tmpBuf;
+ int bufSz, backlogSz = 0, rxSz, txSz, stop = 0, txSum;
+
+ do {
+ bufSz = EXAMPLE_BUFFER_SZ + backlogSz;
+
+ tmpBuf = (byte*)realloc(buf, bufSz);
+ if (tmpBuf == NULL)
+ stop = 1;
+ else
+ buf = tmpBuf;
+
+ if (!stop) {
+ rxSz = wolfSSH_stream_read(threadCtx->ssh,
+ buf + backlogSz,
+ EXAMPLE_BUFFER_SZ);
+ if (rxSz > 0) {
+ backlogSz += rxSz;
+ txSum = 0;
+ txSz = 0;
+
+ while (backlogSz != txSum && txSz >= 0 && !stop) {
+ txSz = wolfSSH_stream_send(threadCtx->ssh,
+ buf + txSum,
+ backlogSz - txSum);
+
+ if (txSz > 0) {
+ byte c;
+ const byte matches[] = { 0x03, 0x05, 0x06, 0x00 };
+
+ c = find_char(matches, buf + txSum, txSz);
+ switch (c) {
+ case 0x03:
+ stop = 1;
+ break;
+ case 0x06:
+ if (wolfSSH_TriggerKeyExchange(threadCtx->ssh)
+ != WS_SUCCESS)
+ stop = 1;
+ break;
+ case 0x05:
+ if (dump_stats(threadCtx) <= 0)
+ stop = 1;
+ break;
+ }
+ txSum += txSz;
+ }
+ else if (txSz != WS_REKEYING)
+ stop = 1;
+ }
+
+ if (txSum < backlogSz)
+ memmove(buf, buf + txSum, backlogSz - txSum);
+ backlogSz -= txSum;
+ }
+ else
+ stop = 1;
+ }
+ } while (!stop);
+
+ free(buf);
+ }
+ WCLOSESOCKET(threadCtx->fd);
+ wolfSSH_free(threadCtx->ssh);
+ free(threadCtx);
+
+ return 0;
+}
+
+
+static int load_file(const char* fileName, byte* buf, word32 bufSz)
{
FILE* file;
- uint32_t fileSz;
- uint32_t readSz;
+ word32 fileSz;
+ word32 readSz;
if (fileName == NULL) return 0;
- file = fopen(fileName, "rb");
- if (file == NULL) return 0;
+ if (WFOPEN(&file, fileName, "rb") != 0)
+ return 0;
fseek(file, 0, SEEK_END);
- fileSz = (uint32_t)ftell(file);
+ fileSz = (word32)ftell(file);
rewind(file);
if (fileSz > bufSz) {
@@ -306,24 +185,324 @@ static int load_file(const char* fileName, uint8_t* buf, uint32_t bufSz)
return 0;
}
- readSz = (uint32_t)fread(buf, 1, fileSz, file);
+ readSz = (word32)fread(buf, 1, fileSz, file);
if (readSz < fileSz) {
fclose(file);
return 0;
}
+ fclose(file);
+
return fileSz;
}
-int main(void)
+static INLINE void c32toa(word32 u32, byte* c)
+{
+ c[0] = (u32 >> 24) & 0xff;
+ c[1] = (u32 >> 16) & 0xff;
+ c[2] = (u32 >> 8) & 0xff;
+ c[3] = u32 & 0xff;
+}
+
+
+/* Map user names to passwords */
+/* Use arrays for username and p. The password or public key can
+ * be hashed and the hash stored here. Then I won't need the type. */
+typedef struct PwMap {
+ byte type;
+ byte username[32];
+ word32 usernameSz;
+ byte p[SHA256_DIGEST_SIZE];
+ struct PwMap* next;
+} PwMap;
+
+
+typedef struct PwMapList {
+ PwMap* head;
+} PwMapList;
+
+
+static PwMap* PwMapNew(PwMapList* list, byte type, const byte* username,
+ word32 usernameSz, const byte* p, word32 pSz)
+{
+ PwMap* map;
+
+ map = (PwMap*)malloc(sizeof(PwMap));
+ if (map != NULL) {
+ Sha256 sha;
+ byte flatSz[4];
+
+ map->type = type;
+ if (usernameSz >= sizeof(map->username))
+ usernameSz = sizeof(map->username) - 1;
+ memcpy(map->username, username, usernameSz + 1);
+ map->username[usernameSz] = 0;
+ map->usernameSz = usernameSz;
+
+ wc_InitSha256(&sha);
+ c32toa(pSz, flatSz);
+ wc_Sha256Update(&sha, flatSz, sizeof(flatSz));
+ wc_Sha256Update(&sha, p, pSz);
+ wc_Sha256Final(&sha, map->p);
+
+ map->next = list->head;
+ list->head = map;
+ }
+
+ return map;
+}
+
+
+static void PwMapListDelete(PwMapList* list)
+{
+ if (list != NULL) {
+ PwMap* head = list->head;
+
+ while (head != NULL) {
+ PwMap* cur = head;
+ head = head->next;
+ memset(cur, 0, sizeof(PwMap));
+ free(cur);
+ }
+ }
+}
+
+
+static const char samplePasswordBuffer[] =
+ "jill:upthehill\n"
+ "jack:fetchapail\n";
+
+
+static const char samplePublicKeyEccBuffer[] =
+ "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAA"
+ "BBBNkI5JTP6D0lF42tbxX19cE87hztUS6FSDoGvPfiU0CgeNSbI+aFdKIzTP5CQEJSvm25"
+ "qUzgDtH7oyaQROUnNvk= hansel\n"
+ "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAA"
+ "BBBKAtH8cqaDbtJFjtviLobHBmjCtG56DMkP6A4M2H9zX2/YCg1h9bYS7WHd9UQDwXO1Hh"
+ "IZzRYecXh7SG9P4GhRY= gretel\n";
+
+
+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";
+
+
+static int LoadPasswordBuffer(byte* buf, word32 bufSz, PwMapList* list)
+{
+ char* str = (char*)buf;
+ char* delimiter;
+ char* username;
+ char* password;
+
+ /* Each line of passwd.txt is in the format
+ * username:password\n
+ * This function modifies the passed-in buffer. */
+
+ if (list == NULL)
+ return -1;
+
+ if (buf == NULL || bufSz == 0)
+ return 0;
+
+ while (*str != 0) {
+ delimiter = strchr(str, ':');
+ username = str;
+ *delimiter = 0;
+ password = delimiter + 1;
+ str = strchr(password, '\n');
+ *str = 0;
+ str++;
+ if (PwMapNew(list, WOLFSSH_USERAUTH_PASSWORD,
+ (byte*)username, (word32)strlen(username),
+ (byte*)password, (word32)strlen(password)) == NULL ) {
+
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int LoadPublicKeyBuffer(byte* buf, word32 bufSz, PwMapList* list)
+{
+ char* str = (char*)buf;
+ char* delimiter;
+ byte* publicKey64;
+ word32 publicKey64Sz;
+ byte* username;
+ word32 usernameSz;
+ byte publicKey[300];
+ word32 publicKeySz;
+
+ /* Each line of passwd.txt is in the format
+ * ssh-rsa AAAB3BASE64ENCODEDPUBLICKEYBLOB username\n
+ * This function modifies the passed-in buffer. */
+ if (list == NULL)
+ return -1;
+
+ if (buf == NULL || bufSz == 0)
+ return 0;
+
+ while (*str != 0) {
+ /* Skip the public key type. This example will always be ssh-rsa. */
+ delimiter = strchr(str, ' ');
+ str = delimiter + 1;
+ delimiter = strchr(str, ' ');
+ publicKey64 = (byte*)str;
+ *delimiter = 0;
+ publicKey64Sz = (word32)(delimiter - str);
+ str = delimiter + 1;
+ delimiter = strchr(str, '\n');
+ username = (byte*)str;
+ *delimiter = 0;
+ usernameSz = (word32)(delimiter - str);
+ str = delimiter + 1;
+ publicKeySz = sizeof(publicKey);
+
+ if (Base64_Decode(publicKey64, publicKey64Sz,
+ publicKey, &publicKeySz) != 0) {
+
+ return -1;
+ }
+
+ if (PwMapNew(list, WOLFSSH_USERAUTH_PUBLICKEY,
+ username, usernameSz,
+ publicKey, publicKeySz) == NULL ) {
+
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int wsUserAuth(byte authType,
+ WS_UserAuthData* authData,
+ void* ctx)
+{
+ PwMapList* list;
+ PwMap* map;
+ byte authHash[SHA256_DIGEST_SIZE];
+
+ if (ctx == NULL) {
+ fprintf(stderr, "wsUserAuth: ctx not set");
+ return WOLFSSH_USERAUTH_FAILURE;
+ }
+
+ if (authType != WOLFSSH_USERAUTH_PASSWORD &&
+ authType != WOLFSSH_USERAUTH_PUBLICKEY) {
+
+ return WOLFSSH_USERAUTH_FAILURE;
+ }
+
+ /* Hash the password or public key with its length. */
+ {
+ Sha256 sha;
+ byte flatSz[4];
+ wc_InitSha256(&sha);
+ if (authType == WOLFSSH_USERAUTH_PASSWORD) {
+ c32toa(authData->sf.password.passwordSz, flatSz);
+ wc_Sha256Update(&sha, flatSz, sizeof(flatSz));
+ wc_Sha256Update(&sha,
+ authData->sf.password.password,
+ authData->sf.password.passwordSz);
+ }
+ else if (authType == WOLFSSH_USERAUTH_PUBLICKEY) {
+ c32toa(authData->sf.publicKey.publicKeySz, flatSz);
+ wc_Sha256Update(&sha, flatSz, sizeof(flatSz));
+ wc_Sha256Update(&sha,
+ authData->sf.publicKey.publicKey,
+ authData->sf.publicKey.publicKeySz);
+ }
+ wc_Sha256Final(&sha, authHash);
+ }
+
+ list = (PwMapList*)ctx;
+ map = list->head;
+
+ while (map != NULL) {
+ if (authData->usernameSz == map->usernameSz &&
+ memcmp(authData->username, map->username, map->usernameSz) == 0) {
+
+ if (authData->type == map->type) {
+ if (memcmp(map->p, authHash, SHA256_DIGEST_SIZE) == 0) {
+ return WOLFSSH_USERAUTH_SUCCESS;
+ }
+ else {
+ return (authType == WOLFSSH_USERAUTH_PASSWORD ?
+ WOLFSSH_USERAUTH_INVALID_PASSWORD :
+ WOLFSSH_USERAUTH_INVALID_PUBLICKEY);
+ }
+ }
+ else {
+ return WOLFSSH_USERAUTH_INVALID_AUTHTYPE;
+ }
+ }
+ map = map->next;
+ }
+
+ return WOLFSSH_USERAUTH_INVALID_USER;
+}
+
+
+static void ShowUsage(void)
+{
+ printf("server %s\n", LIBWOLFSSH_VERSION_STRING);
+ printf("-h Help, print this usage\n");
+ printf("-m Allow multiple connections\n");
+ printf("-e Use ECC private key\n");
+}
+
+
+THREAD_RETURN WOLFSSH_THREAD server_test(void* args)
{
WOLFSSH_CTX* ctx = NULL;
+ PwMapList pwMapList;
SOCKET_T listenFd = 0;
+ word32 defaultHighwater = EXAMPLE_HIGHWATER_MARK;
+ word32 threadCount = 0;
+ int multipleConnections = 0;
+ int useEcc = 0;
+ char ch;
+ word16 port = wolfSshPort;
- #ifdef DEBUG_WOLFSSH
- wolfSSH_Debugging_ON();
- #endif
+ int argc = ((func_args*)args)->argc;
+ char** argv = ((func_args*)args)->argv;
+ ((func_args*)args)->return_code = 0;
+
+ while ((ch = mygetopt(argc, argv, "hme")) != -1) {
+ switch (ch) {
+ case 'h' :
+ ShowUsage();
+ exit(EXIT_SUCCESS);
+
+ case 'm' :
+ multipleConnections = 1;
+ break;
+
+ case 'e' :
+ useEcc = 1;
+ break;
+
+ default:
+ ShowUsage();
+ exit(MY_EX_USAGE);
+ }
+ }
+ myoptind = 0; /* reset for test cases */
if (wolfSSH_Init() != WS_SUCCESS) {
fprintf(stderr, "Couldn't initialize wolfSSH.\n");
@@ -336,62 +515,91 @@ int main(void)
exit(EXIT_FAILURE);
}
+ memset(&pwMapList, 0, sizeof(pwMapList));
+ wolfSSH_SetUserAuth(ctx, wsUserAuth);
+ wolfSSH_CTX_SetBanner(ctx, serverBanner);
+
{
- uint8_t buf[SCRATCH_BUFFER_SIZE];
- uint32_t bufSz;
+ const char* bufName;
+ byte buf[SCRATCH_BUFFER_SZ];
+ word32 bufSz;
- bufSz = load_file("./certs/server-cert.der", buf, SCRATCH_BUFFER_SIZE);
- if (bufSz == 0) {
- fprintf(stderr, "Couldn't load certificate file.\n");
- exit(EXIT_FAILURE);
- }
- if (wolfSSH_CTX_UseCert_buffer(ctx,
- buf, bufSz, WOLFSSH_FORMAT_ASN1) < 0) {
- fprintf(stderr, "Couldn't use certificate buffer.\n");
- exit(EXIT_FAILURE);
- }
-
- bufSz = load_file("./certs/server-key.der", buf, SCRATCH_BUFFER_SIZE);
+ bufName = useEcc ? "./keys/server-key-ecc.der" :
+ "./keys/server-key-rsa.der" ;
+ bufSz = load_file(bufName, buf, SCRATCH_BUFFER_SZ);
if (bufSz == 0) {
fprintf(stderr, "Couldn't load key file.\n");
exit(EXIT_FAILURE);
}
- if (wolfSSH_CTX_UsePrivateKey_buffer(ctx,
- buf, bufSz, WOLFSSH_FORMAT_ASN1) < 0) {
+ if (wolfSSH_CTX_UsePrivateKey_buffer(ctx, buf, bufSz,
+ WOLFSSH_FORMAT_ASN1) < 0) {
fprintf(stderr, "Couldn't use key buffer.\n");
exit(EXIT_FAILURE);
}
+
+ bufSz = (word32)strlen(samplePasswordBuffer);
+ memcpy(buf, samplePasswordBuffer, bufSz);
+ buf[bufSz] = 0;
+ LoadPasswordBuffer(buf, bufSz, &pwMapList);
+
+ bufName = useEcc ? samplePublicKeyEccBuffer :
+ samplePublicKeyRsaBuffer;
+ bufSz = (word32)strlen(bufName);
+ memcpy(buf, bufName, bufSz);
+ buf[bufSz] = 0;
+ LoadPublicKeyBuffer(buf, bufSz, &pwMapList);
}
- tcp_bind(&listenFd, SERVER_PORT_NUMBER, 0);
+ tcp_listen(&listenFd, &port, 1);
- for (;;) {
+ do {
SOCKET_T clientFd = 0;
SOCKADDR_IN_T clientAddr;
- SOCKLEN_T clientAddrSz = sizeof(clientAddr);
+ socklen_t clientAddrSz = sizeof(clientAddr);
THREAD_TYPE thread;
WOLFSSH* ssh;
+ thread_ctx_t* threadCtx;
+
+ threadCtx = (thread_ctx_t*)malloc(sizeof(thread_ctx_t));
+ if (threadCtx == NULL) {
+ fprintf(stderr, "Couldn't allocate thread context data.\n");
+ exit(EXIT_FAILURE);
+ }
ssh = wolfSSH_new(ctx);
if (ssh == NULL) {
fprintf(stderr, "Couldn't allocate SSH data.\n");
exit(EXIT_FAILURE);
}
-
- if (listen(listenFd, 5) != 0)
- err_sys("tcp listen failed");
+ wolfSSH_SetUserAuthCtx(ssh, &pwMapList);
+ /* Use the session object for its own highwater callback ctx */
+ if (defaultHighwater > 0) {
+ wolfSSH_SetHighwaterCtx(ssh, (void*)ssh);
+ wolfSSH_SetHighwater(ssh, defaultHighwater);
+ }
clientFd = accept(listenFd, (struct sockaddr*)&clientAddr,
&clientAddrSz);
if (clientFd == -1)
err_sys("tcp accept failed");
- wolfSSH_set_fd(ssh, clientFd);
+ wolfSSH_set_fd(ssh, (int)clientFd);
- pthread_create(&thread, 0, server_worker, ssh);
- pthread_detach(thread);
- }
+ threadCtx->ssh = ssh;
+ threadCtx->fd = clientFd;
+ threadCtx->id = threadCount++;
+ start_thread(server_worker, threadCtx, &thread);
+
+ if (multipleConnections)
+ detach_thread(thread);
+ else
+ join_thread(thread);
+
+ } while (multipleConnections);
+
+ PwMapListDelete(&pwMapList);
+ wolfSSH_CTX_free(ctx);
if (wolfSSH_Cleanup() != WS_SUCCESS) {
fprintf(stderr, "Couldn't clean up wolfSSH.\n");
exit(EXIT_FAILURE);
@@ -400,3 +608,34 @@ int main(void)
return 0;
}
+#ifndef NO_MAIN_DRIVER
+
+ int main(int argc, char** argv)
+ {
+ func_args args;
+
+ args.argc = argc;
+ args.argv = argv;
+ args.return_code = 0;
+
+ WSTARTTCP();
+
+ ChangeToWolfSshRoot();
+ #ifdef DEBUG_WOLFSSH
+ wolfSSH_Debugging_ON();
+ #endif
+
+ wolfSSH_Init();
+
+ server_test(&args);
+
+ wolfSSH_Cleanup();
+
+ return args.return_code;
+ }
+
+
+ int myoptind = 0;
+ char* myoptarg = NULL;
+
+#endif /* NO_MAIN_DRIVER */
diff --git a/examples/server/server.h b/examples/server/server.h
new file mode 100644
index 00000000..4cddd8e6
--- /dev/null
+++ b/examples/server/server.h
@@ -0,0 +1,31 @@
+/* server.h
+ *
+ * Copyright (C) 2014-2017 wolfSSL Inc.
+ *
+ * This file is part of wolfSSH.
+ *
+ * wolfSSH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with wolfSSH. If not, see .
+ */
+
+
+#pragma once
+
+#ifndef _WOLFSSH_SERVER_H_
+#define _WOLFSSH_SERVER_H_
+
+
+THREAD_RETURN WOLFSSH_THREAD server_test(void* args);
+
+
+#endif /* _WOLFSSH_SERVER_H_ */
diff --git a/ide/winvs/client/client.vcxproj b/ide/winvs/client/client.vcxproj
new file mode 100644
index 00000000..58988156
--- /dev/null
+++ b/ide/winvs/client/client.vcxproj
@@ -0,0 +1,334 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ DLL Debug
+ Win32
+
+
+ DLL Debug
+ x64
+
+
+ DLL Release
+ Win32
+
+
+ DLL Release
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+
+
+
+
+ {7c2ccf0d-a155-4914-bd1c-9a47c0530e65}
+
+
+
+ {663A7133-B13B-4C37-A5EC-97CA4D60CA3A}
+ Win32Proj
+ client
+
+
+
+ Application
+ true
+ v110
+ Unicode
+
+
+ Application
+ true
+ v110
+ Unicode
+
+
+ Application
+ true
+ v110
+ Unicode
+
+
+ Application
+ true
+ v110
+ Unicode
+
+
+ Application
+ false
+ v110
+ true
+ Unicode
+
+
+ Application
+ false
+ v110
+ true
+ Unicode
+
+
+ Application
+ false
+ v110
+ true
+ Unicode
+
+
+ Application
+ false
+ v110
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ $(Configuration)\$(Platform)\obj\
+ $(SolutionDir)$(Configuration)\$(Platform)\
+
+
+ false
+ $(Configuration)\$(Platform)\obj\
+ $(SolutionDir)$(Configuration)\$(Platform)\
+
+
+ false
+ $(Configuration)\$(Platform)\obj\
+ $(SolutionDir)$(Configuration)\$(Platform)\
+
+
+ false
+ $(Configuration)\$(Platform)\obj\
+ $(SolutionDir)$(Configuration)\$(Platform)\
+
+
+ false
+ $(SolutionDir)$(Configuration)\$(Platform)\
+ $(Configuration)\$(Platform)\obj\
+
+
+ false
+ $(SolutionDir)$(Configuration)\$(Platform)\
+ $(Configuration)\$(Platform)\obj\
+
+
+ false
+ $(SolutionDir)$(Configuration)\$(Platform)\
+ $(Configuration)\$(Platform)\obj\
+
+
+ false
+ $(SolutionDir)$(Configuration)\$(Platform)\
+ $(Configuration)\$(Platform)\obj\
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;WOLFSSL_USER_SETTINGS;%(PreprocessorDefinitions)
+ ..;..\..\..;$(wolfCryptDir);%(AdditionalIncludeDirectories)
+ ProgramDatabase
+
+
+ Console
+ true
+ wolfssl.lib;ws2_32.lib;%(AdditionalDependencies)
+ msvcrt.lib
+ $(wolfCryptDebug32)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;WOLFSSL_USER_SETTINGS;%(PreprocessorDefinitions)
+ ..;..\..\..;$(wolfCryptDir);%(AdditionalIncludeDirectories)
+ ProgramDatabase
+
+
+ Console
+ true
+ wolfssl.lib;ws2_32.lib;%(AdditionalDependencies)
+ msvcrt.lib
+ $(wolfCryptDllDebug32)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;WOLFSSL_USER_SETTINGS;%(PreprocessorDefinitions)
+ ..;..\..\..;$(wolfCryptDir);%(AdditionalIncludeDirectories)
+ ProgramDatabase
+
+
+ Console
+ true
+ wolfssl.lib;ws2_32.lib;%(AdditionalDependencies)
+ msvcrt.lib
+ $(wolfCryptDebug64)
+
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_CONSOLE;WOLFSSL_USER_SETTINGS;%(PreprocessorDefinitions)
+ ..;..\..\..;$(wolfCryptDir);%(AdditionalIncludeDirectories)
+ ProgramDatabase
+
+
+ Console
+ true
+ wolfssl.lib;ws2_32.lib;%(AdditionalDependencies)
+ msvcrt.lib
+ $(wolfCryptDllDebug64)
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;WOLFSSL_USER_SETTINGS;%(PreprocessorDefinitions)
+ ..;..\..\..;$(wolfCryptDir);%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ wolfssl.lib;ws2_32.lib;%(AdditionalDependencies)
+ true
+ true
+ $(wolfCryptRelease32)
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;WOLFSSL_USER_SETTINGS;%(PreprocessorDefinitions)
+ ..;..\..\..;$(wolfCryptDir);%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ wolfssl.lib;ws2_32.lib;%(AdditionalDependencies)
+ true
+ true
+ $(wolfCryptDllRelease32)
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;WOLFSSL_USER_SETTINGS;%(PreprocessorDefinitions)
+ ..;..\..\..;$(wolfCryptDir);%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ wolfssl.lib;ws2_32.lib;%(AdditionalDependencies)
+ true
+ true
+ $(wolfCryptRelease64)
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;WOLFSSL_USER_SETTINGS;%(PreprocessorDefinitions)
+ ..;..\..\..;$(wolfCryptDir);%(AdditionalIncludeDirectories)
+
+
+ Console
+ true
+ wolfssl.lib;ws2_32.lib;%(AdditionalDependencies)
+ true
+ true
+ $(wolfCryptDllRelease64)
+
+
+
+
+
+
diff --git a/ide/winvs/client/client.vcxproj.user b/ide/winvs/client/client.vcxproj.user
new file mode 100644
index 00000000..23a5dce7
--- /dev/null
+++ b/ide/winvs/client/client.vcxproj.user
@@ -0,0 +1,19 @@
+
+
+
+ WindowsLocalDebugger
+ PATH=$(wolfCryptDllDebug32);%PATH%
+
+
+ WindowsLocalDebugger
+ PATH=$(wolfCryptDllDebug64);%PATH%
+
+
+ WindowsLocalDebugger
+ PATH=$(wolfCryptDllRelease32);%PATH%
+
+
+ WindowsLocalDebugger
+ PATH=$(wolfCryptDllRelease64);%PATH%
+
+
diff --git a/ide/winvs/include.am b/ide/winvs/include.am
index a033848b..c4b755b1 100644
--- a/ide/winvs/include.am
+++ b/ide/winvs/include.am
@@ -10,5 +10,7 @@ EXTRA_DIST+= ide/winvs/api-test/api-test.vcxproj
EXTRA_DIST+= ide/winvs/api-test/api-test.vcxproj.user
EXTRA_DIST+= ide/winvs/unit-test/unit-test.vcxproj
EXTRA_DIST+= ide/winvs/unit-test/unit-test.vcxproj.user
+EXTRA_DIST+= ide/winvs/client/client.vcxproj
+EXTRA_DIST+= ide/winvs/client/client.vcxproj.user
EXTRA_DIST+= ide/winvs/echoserver/echoserver.vcxproj
EXTRA_DIST+= ide/winvs/echoserver/echoserver.vcxproj.user
diff --git a/ide/winvs/wolfssh.sln b/ide/winvs/wolfssh.sln
old mode 100644
new mode 100755
index db071946..545f61d3
--- a/ide/winvs/wolfssh.sln
+++ b/ide/winvs/wolfssh.sln
@@ -1,98 +1,116 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Express 2012 for Windows Desktop
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wolfssh", "wolfssh\wolfssh.vcxproj", "{7C2CCF0D-A155-4914-BD1C-9A47C0530E65}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "api-test", "api-test\api-test.vcxproj", "{07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}"
- ProjectSection(ProjectDependencies) = postProject
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65} = {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echoserver", "echoserver\echoserver.vcxproj", "{B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}"
- ProjectSection(ProjectDependencies) = postProject
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65} = {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unit-test", "unit-test\unit-test.vcxproj", "{CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Win32 = Debug|Win32
- Debug|x64 = Debug|x64
- DLL Debug|Win32 = DLL Debug|Win32
- DLL Debug|x64 = DLL Debug|x64
- DLL Release|Win32 = DLL Release|Win32
- DLL Release|x64 = DLL Release|x64
- Release|Win32 = Release|Win32
- Release|x64 = Release|x64
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.Debug|Win32.ActiveCfg = Debug|Win32
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.Debug|Win32.Build.0 = Debug|Win32
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.Debug|x64.ActiveCfg = Debug|x64
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.Debug|x64.Build.0 = Debug|x64
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.DLL Debug|Win32.Build.0 = DLL Debug|Win32
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.DLL Debug|x64.Build.0 = DLL Debug|x64
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.DLL Release|Win32.ActiveCfg = DLL Release|Win32
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.DLL Release|Win32.Build.0 = DLL Release|Win32
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.DLL Release|x64.ActiveCfg = DLL Release|x64
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.DLL Release|x64.Build.0 = DLL Release|x64
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.Release|Win32.ActiveCfg = Release|Win32
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.Release|Win32.Build.0 = Release|Win32
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.Release|x64.ActiveCfg = Release|x64
- {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.Release|x64.Build.0 = Release|x64
- {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.Debug|Win32.ActiveCfg = Debug|Win32
- {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.Debug|Win32.Build.0 = Debug|Win32
- {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.Debug|x64.ActiveCfg = Debug|x64
- {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.Debug|x64.Build.0 = Debug|x64
- {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32
- {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.DLL Debug|Win32.Build.0 = DLL Debug|Win32
- {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
- {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.DLL Debug|x64.Build.0 = DLL Debug|x64
- {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.DLL Release|Win32.ActiveCfg = DLL Release|Win32
- {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.DLL Release|Win32.Build.0 = DLL Release|Win32
- {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.DLL Release|x64.ActiveCfg = DLL Release|x64
- {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.DLL Release|x64.Build.0 = DLL Release|x64
- {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.Release|Win32.ActiveCfg = Release|Win32
- {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.Release|Win32.Build.0 = Release|Win32
- {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.Release|x64.ActiveCfg = Release|x64
- {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.Release|x64.Build.0 = Release|x64
- {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.Debug|Win32.ActiveCfg = Debug|Win32
- {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.Debug|Win32.Build.0 = Debug|Win32
- {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.Debug|x64.ActiveCfg = Debug|x64
- {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.Debug|x64.Build.0 = Debug|x64
- {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32
- {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.DLL Debug|Win32.Build.0 = DLL Debug|Win32
- {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
- {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.DLL Debug|x64.Build.0 = DLL Debug|x64
- {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.DLL Release|Win32.ActiveCfg = DLL Release|Win32
- {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.DLL Release|Win32.Build.0 = DLL Release|Win32
- {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.DLL Release|x64.ActiveCfg = DLL Release|x64
- {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.DLL Release|x64.Build.0 = DLL Release|x64
- {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.Release|Win32.ActiveCfg = Release|Win32
- {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.Release|Win32.Build.0 = Release|Win32
- {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.Release|x64.ActiveCfg = Release|x64
- {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.Release|x64.Build.0 = Release|x64
- {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.Debug|Win32.ActiveCfg = Debug|Win32
- {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.Debug|Win32.Build.0 = Debug|Win32
- {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.Debug|x64.ActiveCfg = Debug|x64
- {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.Debug|x64.Build.0 = Debug|x64
- {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32
- {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.DLL Debug|Win32.Build.0 = DLL Debug|Win32
- {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
- {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.DLL Debug|x64.Build.0 = DLL Debug|x64
- {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.DLL Release|Win32.ActiveCfg = DLL Release|Win32
- {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.DLL Release|Win32.Build.0 = DLL Release|Win32
- {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.DLL Release|x64.ActiveCfg = DLL Release|x64
- {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.DLL Release|x64.Build.0 = DLL Release|x64
- {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.Release|Win32.ActiveCfg = Release|Win32
- {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.Release|Win32.Build.0 = Release|Win32
- {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.Release|x64.ActiveCfg = Release|x64
- {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.Release|x64.Build.0 = Release|x64
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Express 2012 for Windows Desktop
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wolfssh", "wolfssh\wolfssh.vcxproj", "{7C2CCF0D-A155-4914-BD1C-9A47C0530E65}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "api-test", "api-test\api-test.vcxproj", "{07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}"
+ ProjectSection(ProjectDependencies) = postProject
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65} = {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "echoserver", "echoserver\echoserver.vcxproj", "{B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}"
+ ProjectSection(ProjectDependencies) = postProject
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65} = {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unit-test", "unit-test\unit-test.vcxproj", "{CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "client", "client\client.vcxproj", "{663A7133-B13B-4C37-A5EC-97CA4D60CA3A}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ DLL Debug|Win32 = DLL Debug|Win32
+ DLL Debug|x64 = DLL Debug|x64
+ DLL Release|Win32 = DLL Release|Win32
+ DLL Release|x64 = DLL Release|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.Debug|Win32.Build.0 = Debug|Win32
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.Debug|x64.ActiveCfg = Debug|x64
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.Debug|x64.Build.0 = Debug|x64
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.DLL Debug|Win32.Build.0 = DLL Debug|Win32
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.DLL Debug|x64.Build.0 = DLL Debug|x64
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.DLL Release|Win32.ActiveCfg = DLL Release|Win32
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.DLL Release|Win32.Build.0 = DLL Release|Win32
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.DLL Release|x64.ActiveCfg = DLL Release|x64
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.DLL Release|x64.Build.0 = DLL Release|x64
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.Release|Win32.ActiveCfg = Release|Win32
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.Release|Win32.Build.0 = Release|Win32
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.Release|x64.ActiveCfg = Release|x64
+ {7C2CCF0D-A155-4914-BD1C-9A47C0530E65}.Release|x64.Build.0 = Release|x64
+ {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.Debug|Win32.ActiveCfg = Debug|Win32
+ {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.Debug|Win32.Build.0 = Debug|Win32
+ {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.Debug|x64.ActiveCfg = Debug|x64
+ {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.Debug|x64.Build.0 = Debug|x64
+ {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32
+ {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.DLL Debug|Win32.Build.0 = DLL Debug|Win32
+ {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
+ {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.DLL Debug|x64.Build.0 = DLL Debug|x64
+ {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.DLL Release|Win32.ActiveCfg = DLL Release|Win32
+ {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.DLL Release|Win32.Build.0 = DLL Release|Win32
+ {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.DLL Release|x64.ActiveCfg = DLL Release|x64
+ {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.DLL Release|x64.Build.0 = DLL Release|x64
+ {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.Release|Win32.ActiveCfg = Release|Win32
+ {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.Release|Win32.Build.0 = Release|Win32
+ {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.Release|x64.ActiveCfg = Release|x64
+ {07D36DB5-210E-45A6-8270-2DAD9DCDEFD7}.Release|x64.Build.0 = Release|x64
+ {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.Debug|Win32.Build.0 = Debug|Win32
+ {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.Debug|x64.ActiveCfg = Debug|x64
+ {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.Debug|x64.Build.0 = Debug|x64
+ {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32
+ {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.DLL Debug|Win32.Build.0 = DLL Debug|Win32
+ {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
+ {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.DLL Debug|x64.Build.0 = DLL Debug|x64
+ {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.DLL Release|Win32.ActiveCfg = DLL Release|Win32
+ {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.DLL Release|Win32.Build.0 = DLL Release|Win32
+ {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.DLL Release|x64.ActiveCfg = DLL Release|x64
+ {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.DLL Release|x64.Build.0 = DLL Release|x64
+ {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.Release|Win32.ActiveCfg = Release|Win32
+ {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.Release|Win32.Build.0 = Release|Win32
+ {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.Release|x64.ActiveCfg = Release|x64
+ {B4E163C2-ECA0-4DA2-9FD9-4CD6599C9D4D}.Release|x64.Build.0 = Release|x64
+ {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.Debug|Win32.Build.0 = Debug|Win32
+ {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.Debug|x64.ActiveCfg = Debug|x64
+ {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.Debug|x64.Build.0 = Debug|x64
+ {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32
+ {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.DLL Debug|Win32.Build.0 = DLL Debug|Win32
+ {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
+ {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.DLL Debug|x64.Build.0 = DLL Debug|x64
+ {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.DLL Release|Win32.ActiveCfg = DLL Release|Win32
+ {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.DLL Release|Win32.Build.0 = DLL Release|Win32
+ {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.DLL Release|x64.ActiveCfg = DLL Release|x64
+ {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.DLL Release|x64.Build.0 = DLL Release|x64
+ {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.Release|Win32.ActiveCfg = Release|Win32
+ {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.Release|Win32.Build.0 = Release|Win32
+ {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.Release|x64.ActiveCfg = Release|x64
+ {CBF8A91E-C52B-4044-9FDA-B99D5D3CFF02}.Release|x64.Build.0 = Release|x64
+ {663A7133-B13B-4C37-A5EC-97CA4D60CA3A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {663A7133-B13B-4C37-A5EC-97CA4D60CA3A}.Debug|Win32.Build.0 = Debug|Win32
+ {663A7133-B13B-4C37-A5EC-97CA4D60CA3A}.Debug|x64.ActiveCfg = Debug|x64
+ {663A7133-B13B-4C37-A5EC-97CA4D60CA3A}.Debug|x64.Build.0 = Debug|x64
+ {663A7133-B13B-4C37-A5EC-97CA4D60CA3A}.DLL Debug|Win32.ActiveCfg = DLL Debug|Win32
+ {663A7133-B13B-4C37-A5EC-97CA4D60CA3A}.DLL Debug|Win32.Build.0 = DLL Debug|Win32
+ {663A7133-B13B-4C37-A5EC-97CA4D60CA3A}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
+ {663A7133-B13B-4C37-A5EC-97CA4D60CA3A}.DLL Debug|x64.Build.0 = DLL Debug|x64
+ {663A7133-B13B-4C37-A5EC-97CA4D60CA3A}.DLL Release|Win32.ActiveCfg = DLL Release|Win32
+ {663A7133-B13B-4C37-A5EC-97CA4D60CA3A}.DLL Release|Win32.Build.0 = DLL Release|Win32
+ {663A7133-B13B-4C37-A5EC-97CA4D60CA3A}.DLL Release|x64.ActiveCfg = DLL Release|x64
+ {663A7133-B13B-4C37-A5EC-97CA4D60CA3A}.DLL Release|x64.Build.0 = DLL Release|x64
+ {663A7133-B13B-4C37-A5EC-97CA4D60CA3A}.Release|Win32.ActiveCfg = Release|Win32
+ {663A7133-B13B-4C37-A5EC-97CA4D60CA3A}.Release|Win32.Build.0 = Release|Win32
+ {663A7133-B13B-4C37-A5EC-97CA4D60CA3A}.Release|x64.ActiveCfg = Release|x64
+ {663A7133-B13B-4C37-A5EC-97CA4D60CA3A}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/keys/gretel-key-ecc.pem b/keys/gretel-key-ecc.pem
new file mode 100644
index 00000000..a7b3d06b
--- /dev/null
+++ b/keys/gretel-key-ecc.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIFWdSB6pL/oYzrP6d0YAxNvTiz6d72/NN0aHIzx3mat4oAoGCCqGSM49
+AwEHoUQDQgAEoC0fxypoNu0kWO2+IuhscGaMK0bnoMyQ/oDgzYf3Nfb9gKDWH1th
+LtYd31RAPBc7UeEhnNFh5xeHtIb0/gaFFg==
+-----END EC PRIVATE KEY-----
diff --git a/keys/key-gretel.pem b/keys/gretel-key-rsa.pem
similarity index 100%
rename from keys/key-gretel.pem
rename to keys/gretel-key-rsa.pem
diff --git a/keys/hansel-key-ecc.pem b/keys/hansel-key-ecc.pem
new file mode 100644
index 00000000..5655f35a
--- /dev/null
+++ b/keys/hansel-key-ecc.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIANuF9O5uKvI+R/xLURMOxKxpHfY7Q5qvmDC9ovn04eDoAoGCCqGSM49
+AwEHoUQDQgAE2QjklM/oPSUXja1vFfX1wTzuHO1RLoVIOga89+JTQKB41Jsj5oV0
+ojNM/kJAQlK+bbmpTOAO0fujJpBE5Sc2+Q==
+-----END EC PRIVATE KEY-----
diff --git a/keys/key-hansel.pem b/keys/hansel-key-rsa.pem
similarity index 100%
rename from keys/key-hansel.pem
rename to keys/hansel-key-rsa.pem
diff --git a/keys/include.am b/keys/include.am
index 8bd995f1..e07693d3 100644
--- a/keys/include.am
+++ b/keys/include.am
@@ -12,7 +12,10 @@ EXTRA_DIST+= \
keys/server-key-ecc-521.pem \
keys/server-key-rsa.der \
keys/server-key-rsa.pem \
- keys/key-hansel.pem \
- keys/key-gretel.pem \
- keys/publickeys.txt \
+ keys/hansel-key-ecc.pem \
+ keys/hansel-key-rsa.pem \
+ keys/gretel-key-ecc.pem \
+ keys/gretel-key-rsa.pem \
+ keys/pubkeys-ecc.txt \
+ keys/pubkeys-rsa.txt \
keys/passwd.txt
diff --git a/keys/pubkeys-ecc.txt b/keys/pubkeys-ecc.txt
new file mode 100644
index 00000000..692835e9
--- /dev/null
+++ b/keys/pubkeys-ecc.txt
@@ -0,0 +1,2 @@
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNkI5JTP6D0lF42tbxX19cE87hztUS6FSDoGvPfiU0CgeNSbI+aFdKIzTP5CQEJSvm25qUzgDtH7oyaQROUnNvk= hansel
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBKAtH8cqaDbtJFjtviLobHBmjCtG56DMkP6A4M2H9zX2/YCg1h9bYS7WHd9UQDwXO1HhIZzRYecXh7SG9P4GhRY= gretel
diff --git a/keys/publickeys.txt b/keys/pubkeys-rsa.txt
similarity index 100%
rename from keys/publickeys.txt
rename to keys/pubkeys-rsa.txt
diff --git a/src/internal.c b/src/internal.c
index f712c26b..41c9e907 100644
--- a/src/internal.c
+++ b/src/internal.c
@@ -37,6 +37,7 @@
#include
#include
#include
+#include
#include
#ifdef NO_INLINE
@@ -1310,7 +1311,6 @@ static int GetUint32(word32* v, byte* buf, word32 len, word32* idx)
}
-#ifndef WOLFSSH_NO_CLIENT
/* Gets the size of the mpint, and puts the pointer to the start of
* buf's number into *mpint. This function does not copy. */
static int GetMpint(word32* mpintSz, byte** mpint,
@@ -1332,7 +1332,6 @@ static int GetMpint(word32* mpintSz, byte** mpint,
return result;
}
-#endif /* WOLFSSH_NO_CLIENT */
/* Gets the size of a string, copies it as much of it as will fit in
@@ -2008,7 +2007,6 @@ static int DoKexDhInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
}
-#ifndef WOLFSSH_NO_CLIENT
static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
{
byte* pubKey;
@@ -2316,7 +2314,6 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
WLOG(WS_LOG_DEBUG, "Leaving DoKexDhReply(), ret = %d", ret);
return ret;
}
-#endif /* WOLFSSH_NO_CLIENT */
static int DoNewKeys(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
@@ -2416,7 +2413,6 @@ static int DoKexDhGexRequest(WOLFSSH* ssh,
}
-#ifndef WOLFSSH_NO_CLIENT
static int DoKexDhGexGroup(WOLFSSH* ssh,
byte* buf, word32 len, word32* idx)
{
@@ -2473,7 +2469,6 @@ static int DoKexDhGexGroup(WOLFSSH* ssh,
return ret;
}
-#endif /* WOLFSSH_NO_CLIENT */
static int DoIgnore(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
@@ -2654,7 +2649,6 @@ static int DoServiceRequest(WOLFSSH* ssh,
}
-#ifndef WOLFSSH_NO_CLIENT
static int DoServiceAccept(WOLFSSH* ssh,
byte* buf, word32 len, word32* idx)
{
@@ -2678,7 +2672,6 @@ static int DoServiceAccept(WOLFSSH* ssh,
return WS_SUCCESS;
}
-#endif /* WOLFSSH_NO_CLIENT */
/* Utility for DoUserAuthRequest() */
@@ -2756,9 +2749,11 @@ static int DoUserAuthRequestPassword(WOLFSSH* ssh, WS_UserAuthData* authData,
/* Utility for DoUserAuthRequestPublicKey() */
/* returns negative for error, positive is size of digest. */
static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk,
- byte* digest, word32 digestSz)
+ byte hashId, byte* digest, word32 digestSz)
{
RsaKey key;
+ byte checkDigest[MAX_ENCODED_SIG_SZ];
+ int checkDigestSz;
byte* publicKeyType;
word32 publicKeyTypeSz = 0;
byte* n;
@@ -2836,13 +2831,34 @@ static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk,
if (ret == WS_SUCCESS) {
n = pk->signature + i;
- ret = wc_RsaSSL_Verify(n, nSz, digest, digestSz, &key);
- if (ret <= 0) {
+ checkDigestSz = wc_RsaSSL_Verify(n, nSz, checkDigest,
+ sizeof(checkDigest), &key);
+ if (checkDigestSz <= 0) {
WLOG(WS_LOG_DEBUG, "Could not verify signature");
ret = WS_CRYPTO_FAILED;
}
}
+ if (ret == WS_SUCCESS) {
+ byte encDigest[MAX_ENCODED_SIG_SZ];
+ word32 encDigestSz;
+ volatile int compare;
+ volatile int sizeCompare;
+
+ encDigestSz = wc_EncodeSignature(encDigest, digest,
+ wc_HashGetDigestSize(hashId),
+ wc_HashGetOID(hashId));
+
+ compare = ConstantCompare(encDigest, checkDigest,
+ encDigestSz);
+ sizeCompare = encDigestSz != (word32)checkDigestSz;
+
+ if ((compare | sizeCompare) == 0)
+ ret = WS_SUCCESS;
+ else
+ ret = WS_RSA_E;
+ }
+
wc_FreeRsaKey(&key);
WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthRequestRsa(), ret = %d", ret);
@@ -2850,6 +2866,141 @@ static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk,
}
+/* Utility for DoUserAuthRequestPublicKey() */
+/* returns negative for error, positive is size of digest. */
+static int DoUserAuthRequestEcc(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk,
+ byte hashId, byte* digest, word32 digestSz)
+{
+ ecc_key key;
+ byte* publicKeyType;
+ word32 publicKeyTypeSz = 0;
+ byte* curveName;
+ word32 curveNameSz = 0;
+ mp_int r, s;
+ byte* q;
+ word32 sz, qSz;
+ word32 i = 0;
+ int ret = WS_SUCCESS;
+
+ (void)hashId;
+
+ WLOG(WS_LOG_DEBUG, "Entering DoUserAuthRequestRsa()");
+
+ if (ssh == NULL || pk == NULL || digest == NULL || digestSz == 0)
+ ret = WS_BAD_ARGUMENT;
+
+ /* First check that the public key's type matches the one we are
+ * expecting. */
+ if (ret == WS_SUCCESS)
+ ret = GetUint32(&publicKeyTypeSz, pk->publicKey, pk->publicKeySz, &i);
+
+ if (ret == WS_SUCCESS) {
+ publicKeyType = pk->publicKey + i;
+ i += publicKeyTypeSz;
+ if (publicKeyTypeSz != pk->publicKeyTypeSz &&
+ WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) {
+
+ WLOG(WS_LOG_DEBUG,
+ "Public Key's type does not match public key type");
+ ret = WS_INVALID_ALGO_ID;
+ }
+ }
+
+ if (ret == WS_SUCCESS)
+ ret = GetUint32(&curveNameSz, pk->publicKey, pk->publicKeySz, &i);
+
+ if (ret == WS_SUCCESS) {
+ curveName = pk->publicKey + i;
+ i += curveNameSz;
+ ret = GetUint32(&qSz, pk->publicKey, pk->publicKeySz, &i);
+ }
+
+ if (ret == WS_SUCCESS) {
+ q = pk->publicKey + i;
+ i += qSz;
+ ret = wc_ecc_init_ex(&key, ssh->ctx->heap, INVALID_DEVID);
+ }
+
+ if (ret == 0)
+ ret = wc_ecc_import_x963(q, qSz, &key);
+
+ if (ret != 0) {
+ WLOG(WS_LOG_DEBUG, "Could not decode public key");
+ ret = WS_CRYPTO_FAILED;
+ }
+
+ if (ret == WS_SUCCESS) {
+ i = 0;
+ /* First check that the signature's public key type matches the one
+ * we are expecting. */
+ ret = GetUint32(&publicKeyTypeSz, pk->signature, pk->signatureSz, &i);
+ }
+
+ if (ret == WS_SUCCESS) {
+ publicKeyType = pk->signature + i;
+ i += publicKeyTypeSz;
+
+ if (publicKeyTypeSz != pk->publicKeyTypeSz &&
+ WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) {
+
+ WLOG(WS_LOG_DEBUG,
+ "Signature's type does not match public key type");
+ ret = WS_INVALID_ALGO_ID;
+ }
+ }
+
+ if (ret == WS_SUCCESS) {
+ /* Get the size of the signature blob. */
+ ret = GetUint32(&sz, pk->signature, pk->signatureSz, &i);
+ }
+
+ if (ret == WS_SUCCESS) {
+ /* Get R and S. */
+ ret = GetUint32(&sz, pk->signature, pk->signatureSz, &i);
+ }
+
+ if (ret == WS_SUCCESS) {
+ ret = mp_read_unsigned_bin(&r, pk->signature + i, sz);
+ if (ret != 0)
+ ret = WS_PARSE_E;
+ else
+ ret = WS_SUCCESS;
+ }
+
+ if (ret == WS_SUCCESS) {
+ i += sz;
+ ret = GetUint32(&sz, pk->signature, pk->signatureSz, &i);
+ }
+
+ if (ret == WS_SUCCESS) {
+ ret = mp_read_unsigned_bin(&s, pk->signature + i, sz);
+ if (ret != 0)
+ ret = WS_PARSE_E;
+ else
+ ret = WS_SUCCESS;
+ }
+
+ if (ret == WS_SUCCESS) {
+ int status = 0;
+
+ ret = wc_ecc_verify_hash_ex(&r, &s, digest, digestSz, &status, &key);
+ if (ret != 0) {
+ WLOG(WS_LOG_DEBUG, "Could not verify signature");
+ ret = WS_CRYPTO_FAILED;
+ }
+ else
+ ret = status ? WS_SUCCESS : WS_ECC_E;
+ }
+
+ mp_clear(&r);
+ mp_clear(&s);
+ wc_ecc_free(&key);
+
+ WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthRequestEcc(), ret = %d", ret);
+ return ret;
+}
+
+
/* Utility for DoUserAuthRequest() */
static int DoUserAuthRequestPublicKey(WOLFSSH* ssh, WS_UserAuthData* authData,
byte* buf, word32 len, word32* idx)
@@ -2929,80 +3080,73 @@ static int DoUserAuthRequestPublicKey(WOLFSSH* ssh, WS_UserAuthData* authData,
pk->publicKey, pk->publicKeySz);
}
else {
- byte checkDigest[MAX_ENCODED_SIG_SZ];
- word32 checkDigestSz = sizeof(checkDigest);
- byte encDigest[MAX_ENCODED_SIG_SZ];
- word32 encDigestSz;
+ wc_HashAlg hash;
+ byte digest[WC_MAX_DIGEST_SIZE];
+ word32 digestSz;
+ byte hashId = WC_HASH_TYPE_SHA;
byte pkTypeId;
- WMEMSET(checkDigest, 0, sizeof(checkDigest));
- WMEMSET(encDigest, 0, sizeof(encDigest));
-
- pkTypeId = NameToId((char*)pk->publicKeyType, pk->publicKeyTypeSz);
-
- if (pkTypeId == ID_SSH_RSA)
- ret = DoUserAuthRequestRsa(ssh, pk, checkDigest, checkDigestSz);
- else
+ pkTypeId = NameToId((char*)pk->publicKeyType,
+ pk->publicKeyTypeSz);
+ if (pkTypeId == ID_UNKNOWN)
ret = WS_INVALID_ALGO_ID;
- if (ret > 0) {
- checkDigestSz = (word32)ret;
- ret = WS_SUCCESS;
+ if (ret == WS_SUCCESS) {
+ hashId = HashForId(pkTypeId);
+ WMEMSET(digest, 0, sizeof(digest));
+ digestSz = wc_HashGetDigestSize(hashId);
+ ret = wc_HashInit(&hash, hashId);
}
- if (ret == WS_SUCCESS) {
- wc_HashAlg hash;
- byte hashId = WC_HASH_TYPE_SHA;
- byte digest[WC_MAX_DIGEST_SIZE];
- volatile int compare;
- volatile int sizeCompare;
+ if (ret == 0) {
+ c32toa(ssh->sessionIdSz, digest);
+ ret = wc_HashUpdate(&hash, hashId, digest, UINT32_SZ);
+ }
- ret = wc_HashInit(&hash, hashId);
- if (ret == 0) {
- c32toa(ssh->sessionIdSz, digest);
- ret = wc_HashUpdate(&hash, hashId, digest, UINT32_SZ);
- }
- if (ret == WS_SUCCESS)
- ret = wc_HashUpdate(&hash, hashId,
- ssh->sessionId, ssh->sessionIdSz);
+ if (ret == 0)
+ ret = wc_HashUpdate(&hash, hashId,
+ ssh->sessionId, ssh->sessionIdSz);
- if (ret == 0) {
- digest[0] = MSGID_USERAUTH_REQUEST;
- ret = wc_HashUpdate(&hash, hashId, digest, MSG_ID_SZ);
- }
+ if (ret == 0) {
+ digest[0] = MSGID_USERAUTH_REQUEST;
+ ret = wc_HashUpdate(&hash, hashId, digest, MSG_ID_SZ);
+ }
- /* The rest of the fields in the signature are already
- * in the buffer. Just need to account for the sizes. */
- if (ret == 0)
- ret = wc_HashUpdate(&hash, hashId, pk->dataToSign,
- authData->usernameSz +
- authData->serviceNameSz +
- authData->authNameSz + BOOLEAN_SZ +
- pk->publicKeyTypeSz + pk->publicKeySz +
- (UINT32_SZ * 5));
- if (ret == 0)
- ret = wc_HashFinal(&hash, hashId, digest);
-
- encDigestSz = wc_EncodeSignature(encDigest, digest,
- wc_HashGetDigestSize(hashId),
- wc_HashGetOID(hashId));
+ /* The rest of the fields in the signature are already
+ * in the buffer. Just need to account for the sizes. */
+ if (ret == 0)
+ ret = wc_HashUpdate(&hash, hashId, pk->dataToSign,
+ authData->usernameSz +
+ authData->serviceNameSz +
+ authData->authNameSz + BOOLEAN_SZ +
+ pk->publicKeyTypeSz + pk->publicKeySz +
+ (UINT32_SZ * 5));
+ if (ret == 0) {
+ ret = wc_HashFinal(&hash, hashId, digest);
if (ret != 0)
ret = WS_CRYPTO_FAILED;
+ else
+ ret = WS_SUCCESS;
+ }
- if (ret == WS_SUCCESS) {
- compare = ConstantCompare(encDigest, checkDigest,
- encDigestSz);
- sizeCompare = encDigestSz != checkDigestSz;
+ if (ret == WS_SUCCESS) {
+ if (pkTypeId == ID_SSH_RSA)
+ ret = DoUserAuthRequestRsa(ssh, pk,
+ hashId, digest, digestSz);
+ else if (pkTypeId == ID_ECDSA_SHA2_NISTP256 ||
+ pkTypeId == ID_ECDSA_SHA2_NISTP384 ||
+ pkTypeId == ID_ECDSA_SHA2_NISTP521)
+ ret = DoUserAuthRequestEcc(ssh, pk,
+ hashId, digest, digestSz);
+ }
- if (compare || sizeCompare || ret < 0) {
- WLOG(WS_LOG_DEBUG, "DUARPK: signature compare failure");
- ret = SendUserAuthFailure(ssh, 0);
- }
- else {
- ssh->clientState = CLIENT_USERAUTH_DONE;
- }
- }
+ if (ret != WS_SUCCESS) {
+ WLOG(WS_LOG_DEBUG, "DUARPK: signature compare failure");
+ ret = SendUserAuthFailure(ssh, 0);
+ }
+ else {
+ ssh->clientState = CLIENT_USERAUTH_DONE;
}
}
}
@@ -3075,7 +3219,6 @@ static int DoUserAuthRequest(WOLFSSH* ssh,
}
-#ifndef WOLFSSH_NO_CLIENT
static int DoUserAuthFailure(WOLFSSH* ssh,
byte* buf, word32 len, word32* idx)
{
@@ -3152,7 +3295,6 @@ static int DoUserAuthBanner(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthBanner(), ret = %d", ret);
return ret;
}
-#endif /* WOLFSSH_NO_CLIENT */
static int DoGlobalRequest(WOLFSSH* ssh,
@@ -3630,6 +3772,17 @@ static int DoPacket(WOLFSSH* ssh)
ret = DoKexDhInit(ssh, buf + idx, payloadSz, &payloadIdx);
break;
+ case MSGID_KEXDH_REPLY:
+ if (ssh->handshake->kexId == ID_DH_GEX_SHA256) {
+ WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_GEX_GROUP");
+ ret = DoKexDhGexGroup(ssh, buf + idx, payloadSz, &payloadIdx);
+ }
+ else {
+ WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_REPLY");
+ ret = DoKexDhReply(ssh, buf + idx, payloadSz, &payloadIdx);
+ }
+ break;
+
case MSGID_KEXDH_GEX_REQUEST:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_GEX_REQUEST");
ret = DoKexDhGexRequest(ssh, buf + idx, payloadSz, &payloadIdx);
@@ -3640,16 +3793,41 @@ static int DoPacket(WOLFSSH* ssh)
ret = DoKexDhInit(ssh, buf + idx, payloadSz, &payloadIdx);
break;
+ case MSGID_KEXDH_GEX_REPLY:
+ WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_GEX_INIT");
+ ret = DoKexDhReply(ssh, buf + idx, payloadSz, &payloadIdx);
+ break;
+
case MSGID_SERVICE_REQUEST:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_SERVICE_REQUEST");
ret = DoServiceRequest(ssh, buf + idx, payloadSz, &payloadIdx);
break;
+ case MSGID_SERVICE_ACCEPT:
+ WLOG(WS_LOG_DEBUG, "Decoding MSGID_SERVER_ACCEPT");
+ ret = DoServiceAccept(ssh, buf + idx, payloadSz, &payloadIdx);
+ break;
+
case MSGID_USERAUTH_REQUEST:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_USERAUTH_REQUEST");
ret = DoUserAuthRequest(ssh, buf + idx, payloadSz, &payloadIdx);
break;
+ case MSGID_USERAUTH_FAILURE:
+ WLOG(WS_LOG_DEBUG, "Decoding MSGID_USERAUTH_FAILURE");
+ ret = DoUserAuthFailure(ssh, buf + idx, payloadSz, &payloadIdx);
+ break;
+
+ case MSGID_USERAUTH_SUCCESS:
+ WLOG(WS_LOG_DEBUG, "Decoding MSGID_USERAUTH_SUCCESS");
+ ret = DoUserAuthSuccess(ssh, buf + idx, payloadSz, &payloadIdx);
+ break;
+
+ case MSGID_USERAUTH_BANNER:
+ WLOG(WS_LOG_DEBUG, "Decoding MSGID_USERAUTH_BANNER");
+ ret = DoUserAuthBanner(ssh, buf + idx, payloadSz, &payloadIdx);
+ break;
+
case MSGID_GLOBAL_REQUEST:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_GLOBAL_REQUEST");
ret = DoGlobalRequest(ssh, buf + idx, payloadSz, &payloadIdx);
@@ -3705,44 +3883,6 @@ static int DoPacket(WOLFSSH* ssh)
ret = DoChannelFailure(ssh, buf + idx, payloadSz, &payloadIdx);
break;
-#ifndef WOLFSSH_NO_CLIENT
- case MSGID_KEXDH_REPLY:
- if (ssh->handshake->kexId == ID_DH_GEX_SHA256) {
- WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_GEX_GROUP");
- ret = DoKexDhGexGroup(ssh, buf + idx, payloadSz, &payloadIdx);
- }
- else {
- WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_REPLY");
- ret = DoKexDhReply(ssh, buf + idx, payloadSz, &payloadIdx);
- }
- break;
-
- case MSGID_KEXDH_GEX_REPLY:
- WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_GEX_INIT");
- ret = DoKexDhReply(ssh, buf + idx, payloadSz, &payloadIdx);
- break;
-
- case MSGID_SERVICE_ACCEPT:
- WLOG(WS_LOG_DEBUG, "Decoding MSGID_SERVER_ACCEPT");
- ret = DoServiceAccept(ssh, buf + idx, payloadSz, &payloadIdx);
- break;
-
- case MSGID_USERAUTH_FAILURE:
- WLOG(WS_LOG_DEBUG, "Decoding MSGID_USERAUTH_FAILURE");
- ret = DoUserAuthFailure(ssh, buf + idx, payloadSz, &payloadIdx);
- break;
-
- case MSGID_USERAUTH_SUCCESS:
- WLOG(WS_LOG_DEBUG, "Decoding MSGID_USERAUTH_SUCCESS");
- ret = DoUserAuthSuccess(ssh, buf + idx, payloadSz, &payloadIdx);
- break;
-
- case MSGID_USERAUTH_BANNER:
- WLOG(WS_LOG_DEBUG, "Decoding MSGID_USERAUTH_BANNER");
- ret = DoUserAuthBanner(ssh, buf + idx, payloadSz, &payloadIdx);
- break;
-#endif /* WOLFSSL_NO_CLIENT */
-
default:
WLOG(WS_LOG_DEBUG, "Unimplemented message ID (%d)", msg);
#ifdef SHOW_UNIMPLEMENTED
@@ -5203,7 +5343,6 @@ int SendNewKeys(WOLFSSH* ssh)
}
-#ifndef WOLFSSH_NO_CLIENT
int SendKexDhGexRequest(WOLFSSH* ssh)
{
byte* output;
@@ -5244,7 +5383,6 @@ int SendKexDhGexRequest(WOLFSSH* ssh)
WLOG(WS_LOG_DEBUG, "Leaving SendKexDhGexRequest(), ret = %d", ret);
return ret;
}
-#endif /* WOLFSSH_NO_CLIENT */
int SendKexDhGexGroup(WOLFSSH* ssh)
@@ -5318,7 +5456,6 @@ int SendKexDhGexGroup(WOLFSSH* ssh)
}
-#ifndef WOLFSSH_NO_CLIENT
int SendKexDhInit(WOLFSSH* ssh)
{
byte* output;
@@ -5444,7 +5581,6 @@ int SendKexDhInit(WOLFSSH* ssh)
WLOG(WS_LOG_DEBUG, "Leaving SendKexDhInit(), ret = %d", ret);
return ret;
}
-#endif /* WOLFSSH_NO_CLIENT */
int SendUnimplemented(WOLFSSH* ssh)
@@ -5606,7 +5742,6 @@ int SendDebug(WOLFSSH* ssh, byte alwaysDisplay, const char* msg)
}
-#ifndef WOLFSSH_NO_CLIENT
int SendServiceRequest(WOLFSSH* ssh, byte serviceId)
{
const char* serviceName;
@@ -5648,7 +5783,6 @@ int SendServiceRequest(WOLFSSH* ssh, byte serviceId)
WLOG(WS_LOG_DEBUG, "Leaving SendServiceRequest(), ret = %d", ret);
return ret;
}
-#endif /* WOLFSSH_NO_CLIENT */
int SendServiceAccept(WOLFSSH* ssh, byte serviceId)
@@ -5694,7 +5828,6 @@ static const char cannedAuths[] = "publickey,password";
static const word32 cannedAuthsSz = sizeof(cannedAuths) - 1;
-#ifndef WOLFSSH_NO_CLIENT
int SendUserAuthRequest(WOLFSSH* ssh, byte authId)
{
byte* output;
@@ -5784,7 +5917,6 @@ int SendUserAuthRequest(WOLFSSH* ssh, byte authId)
WLOG(WS_LOG_DEBUG, "Leaving SendUserAuthRequest(), ret = %d", ret);
return ret;
}
-#endif /* WOLFSSH_NO_CLIENT */
int SendUserAuthFailure(WOLFSSH* ssh, byte partialSuccess)
@@ -5983,7 +6115,6 @@ int SendRequestSuccess(WOLFSSH* ssh, int success)
}
-#ifndef WOLFSSH_NO_CLIENT
int SendChannelOpenSession(WOLFSSH* ssh,
word32 initialWindowSz, word32 maxPacketSz)
{
@@ -6044,7 +6175,6 @@ int SendChannelOpenSession(WOLFSSH* ssh,
WLOG(WS_LOG_DEBUG, "Leaving SendChannelOpenSession(), ret = %d", ret);
return ret;
}
-#endif /* WOLFSSH_NO_CLIENT */
int SendChannelOpenConf(WOLFSSH* ssh)
@@ -6295,7 +6425,6 @@ int SendChannelWindowAdjust(WOLFSSH* ssh, word32 peerChannel,
}
-#ifndef WOLFSSH_NO_CLIENT
static const char cannedShellName[] = "shell";
static const word32 cannedShellNameSz = sizeof(cannedShellName) - 1;
@@ -6346,7 +6475,6 @@ int SendChannelRequestShell(WOLFSSH* ssh)
WLOG(WS_LOG_DEBUG, "Leaving SendChannelRequestShell(), ret = %d", ret);
return ret;
}
-#endif /* WOLFSSH_NO_CLIENT */
int SendChannelSuccess(WOLFSSH* ssh, word32 channelId, int success)
diff --git a/src/ssh.c b/src/ssh.c
index d260f922..07a5d1bd 100644
--- a/src/ssh.c
+++ b/src/ssh.c
@@ -371,6 +371,187 @@ int wolfSSH_accept(WOLFSSH* ssh)
}
+const char connectError[] = "connect error: %s, %d";
+const char connectState[] = "connect state: %s";
+
+
+int wolfSSH_connect(WOLFSSH* ssh)
+{
+ WLOG(WS_LOG_DEBUG, "Entering wolfSSH_connect()");
+
+ if (ssh == NULL)
+ return WS_BAD_ARGUMENT;
+
+ switch (ssh->connectState) {
+
+ case CONNECT_BEGIN:
+ if ( (ssh->error = SendProtoId(ssh)) < WS_SUCCESS) {
+ WLOG(WS_LOG_DEBUG, connectError, "BEGIN", ssh->error);
+ return WS_FATAL_ERROR;
+ }
+ ssh->connectState = CONNECT_CLIENT_VERSION_SENT;
+ WLOG(WS_LOG_DEBUG, connectState, "CLIENT_VERSION_SENT");
+ FALL_THROUGH;
+
+ case CONNECT_CLIENT_VERSION_SENT:
+ while (ssh->serverState < SERVER_VERSION_DONE) {
+ if ( (ssh->error = DoProtoId(ssh)) < WS_SUCCESS) {
+ WLOG(WS_LOG_DEBUG, connectError,
+ "CLIENT_VERSION_SENT", ssh->error);
+ return WS_FATAL_ERROR;
+ }
+ }
+ ssh->connectState = CONNECT_SERVER_VERSION_DONE;
+ WLOG(WS_LOG_DEBUG, connectState, "SERVER_VERSION_DONE");
+ FALL_THROUGH;
+
+ case CONNECT_SERVER_VERSION_DONE:
+ if ( (ssh->error = SendKexInit(ssh)) < WS_SUCCESS) {
+ WLOG(WS_LOG_DEBUG, acceptError,
+ "SERVER_VERSION_DONE", ssh->error);
+ return WS_FATAL_ERROR;
+ }
+ ssh->connectState = CONNECT_CLIENT_KEXINIT_SENT;
+ WLOG(WS_LOG_DEBUG, connectState, "CLIENT_KEXINIT_SENT");
+ FALL_THROUGH;
+
+ case CONNECT_CLIENT_KEXINIT_SENT:
+ while (ssh->serverState < SERVER_KEXINIT_DONE) {
+ if ( (ssh->error = DoReceive(ssh)) < WS_SUCCESS) {
+ WLOG(WS_LOG_DEBUG, connectError,
+ "CLIENT_KEXINIT_SENT", ssh->error);
+ return WS_FATAL_ERROR;
+ }
+ }
+ ssh->connectState = CONNECT_SERVER_KEXINIT_DONE;
+ WLOG(WS_LOG_DEBUG, connectState, "SERVER_KEXINIT_DONE");
+ FALL_THROUGH;
+
+ case CONNECT_SERVER_KEXINIT_DONE:
+ if (ssh->handshake->kexId == ID_DH_GEX_SHA256)
+ ssh->error = SendKexDhGexRequest(ssh);
+ else
+ ssh->error = SendKexDhInit(ssh);
+ if (ssh->error < WS_SUCCESS) {
+ WLOG(WS_LOG_DEBUG, connectError,
+ "SERVER_KEXINIT_DONE", ssh->error);
+ return WS_FATAL_ERROR;
+ }
+ ssh->connectState = CONNECT_CLIENT_KEXDH_INIT_SENT;
+ WLOG(WS_LOG_DEBUG, connectState, "CLIENT_KEXDH_INIT_SENT");
+ FALL_THROUGH;
+
+ case CONNECT_CLIENT_KEXDH_INIT_SENT:
+ while (ssh->isKeying) {
+ if ( (ssh->error = DoReceive(ssh)) < WS_SUCCESS) {
+ WLOG(WS_LOG_DEBUG, connectError,
+ "CLIENT_KEXDH_INIT_SENT", ssh->error);
+ return WS_FATAL_ERROR;
+ }
+ }
+ ssh->connectState = CONNECT_KEYED;
+ WLOG(WS_LOG_DEBUG, connectState, "KEYED");
+ FALL_THROUGH;
+
+ case CONNECT_KEYED:
+ if ( (ssh->error = SendServiceRequest(ssh, ID_SERVICE_USERAUTH)) <
+ WS_SUCCESS) {
+ WLOG(WS_LOG_DEBUG, connectError, "KEYED", ssh->error);
+ return WS_FATAL_ERROR;
+ }
+ ssh->connectState = CONNECT_CLIENT_USERAUTH_REQUEST_SENT;
+ WLOG(WS_LOG_DEBUG, connectState, "CLIENT_USERAUTH_REQUEST_SENT");
+ FALL_THROUGH;
+
+ case CONNECT_CLIENT_USERAUTH_REQUEST_SENT:
+ while (ssh->serverState < SERVER_USERAUTH_REQUEST_DONE) {
+ if ( (ssh->error = DoReceive(ssh)) < WS_SUCCESS) {
+ WLOG(WS_LOG_DEBUG, connectError,
+ "CLIENT_USERAUTH_REQUEST_SENT", ssh->error);
+ return WS_FATAL_ERROR;
+ }
+ }
+ ssh->connectState = CONNECT_SERVER_USERAUTH_REQUEST_DONE;
+ WLOG(WS_LOG_DEBUG, connectState, "SERVER_USERAUTH_REQUEST_DONE");
+ FALL_THROUGH;
+
+ case CONNECT_SERVER_USERAUTH_REQUEST_DONE:
+ if ( (ssh->error = SendUserAuthRequest(ssh, ID_NONE)) <
+ WS_SUCCESS) {
+ WLOG(WS_LOG_DEBUG, connectError,
+ "SERVER_USERAUTH_REQUEST_DONE", ssh->error);
+ return WS_FATAL_ERROR;
+ }
+ ssh->connectState = CONNECT_CLIENT_USERAUTH_SENT;
+ WLOG(WS_LOG_DEBUG, connectState, "CLIENT_USERAUTH_SENT");
+ FALL_THROUGH;
+
+ case CONNECT_CLIENT_USERAUTH_SENT:
+ while (ssh->serverState < SERVER_USERAUTH_ACCEPT_DONE) {
+ if ( (ssh->error = DoReceive(ssh)) < WS_SUCCESS) {
+ WLOG(WS_LOG_DEBUG, connectError,
+ "CLIENT_USERAUTH_SENT", ssh->error);
+ return WS_FATAL_ERROR;
+ }
+ }
+ ssh->connectState = CONNECT_SERVER_USERAUTH_ACCEPT_DONE;
+ WLOG(WS_LOG_DEBUG, connectState, "SERVER_USERAUTH_ACCEPT_DONE");
+ FALL_THROUGH;
+
+ case CONNECT_SERVER_USERAUTH_ACCEPT_DONE:
+ if ( (ssh->error = SendChannelOpenSession(ssh, DEFAULT_WINDOW_SZ,
+ DEFAULT_MAX_PACKET_SZ)) < WS_SUCCESS) {
+ WLOG(WS_LOG_DEBUG, connectError,
+ "SERVER_USERAUTH_ACCEPT_DONE", ssh->error);
+ return WS_FATAL_ERROR;
+ }
+ ssh->connectState = CONNECT_CLIENT_CHANNEL_OPEN_SESSION_SENT;
+ WLOG(WS_LOG_DEBUG, connectState,
+ "CLIENT_CHANNEL_OPEN_SESSION_SENT");
+ FALL_THROUGH;
+
+ case CONNECT_CLIENT_CHANNEL_OPEN_SESSION_SENT:
+ while (ssh->serverState < SERVER_CHANNEL_OPEN_DONE) {
+ if ( (ssh->error = DoReceive(ssh)) < WS_SUCCESS) {
+ WLOG(WS_LOG_DEBUG, connectError,
+ "CLIENT_CHANNEL_OPEN_SESSION_SENT", ssh->error);
+ return WS_FATAL_ERROR;
+ }
+ }
+ ssh->connectState = CONNECT_SERVER_CHANNEL_OPEN_SESSION_DONE;
+ WLOG(WS_LOG_DEBUG, connectState,
+ "SERVER_CHANNEL_OPEN_SESSION_DONE");
+ FALL_THROUGH;
+
+ case CONNECT_SERVER_CHANNEL_OPEN_SESSION_DONE:
+ if ( (ssh->error = SendChannelRequestShell(ssh)) < WS_SUCCESS) {
+ WLOG(WS_LOG_DEBUG, connectError,
+ "SERVER_CHANNEL_OPEN_SESSION_DONE", ssh->error);
+ return WS_FATAL_ERROR;
+ }
+ ssh->connectState = CONNECT_CLIENT_CHANNEL_REQUEST_SHELL_SENT;
+ WLOG(WS_LOG_DEBUG, connectState,
+ "CLIENT_CHANNEL_REQUEST_SHELL_SENT");
+ FALL_THROUGH;
+
+ case CONNECT_CLIENT_CHANNEL_REQUEST_SHELL_SENT:
+ while (ssh->serverState < SERVER_DONE) {
+ if ( (ssh->error = DoReceive(ssh)) < WS_SUCCESS) {
+ WLOG(WS_LOG_DEBUG, connectError,
+ "CLIENT_CHANNEL_REQUEST_SHELL_SENT", ssh->error);
+ return WS_FATAL_ERROR;
+ }
+ }
+ ssh->connectState = CONNECT_SERVER_CHANNEL_REQUEST_SHELL_DONE;
+ WLOG(WS_LOG_DEBUG, connectState,
+ "SERVER_CHANNEL_REQUEST_SHELL_DONE");
+ }
+
+ WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_connect()");
+ return WS_SUCCESS;
+}
+
+
int wolfSSH_shutdown(WOLFSSH* ssh)
{
int ret = WS_SUCCESS;
@@ -507,6 +688,41 @@ void* wolfSSH_GetUserAuthCtx(WOLFSSH* ssh)
}
+int wolfSSH_SetUsername(WOLFSSH* ssh, const char* username)
+{
+ char* value = NULL;
+ word32 valueSz;
+ int ret = WS_SUCCESS;
+
+ if (ssh == NULL || ssh->handshake == NULL ||
+ ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER ||
+ username == NULL) {
+
+ ret = WS_BAD_ARGUMENT;
+ }
+
+ if (ret == WS_SUCCESS) {
+ valueSz = (word32)WSTRLEN(username);
+ if (valueSz > 0)
+ value = (char*)WMALLOC(valueSz + 1, ssh->ctx->heap, DYNTYPE_STRING);
+ if (value == NULL)
+ ret = WS_MEMORY_E;
+ }
+
+ if (ret == WS_SUCCESS) {
+ WSTRNCPY(value, username, valueSz + 1);
+ if (ssh->userName != NULL) {
+ WFREE(ssh->userName, heap, DYNTYPE_STRING);
+ ssh->userName = NULL;
+ }
+ ssh->userName = value;
+ ssh->userNameSz = valueSz;
+ }
+
+ return ret;
+}
+
+
int wolfSSH_CTX_SetBanner(WOLFSSH_CTX* ctx,
const char* newBanner)
{
diff --git a/wolfssh/settings.h b/wolfssh/settings.h
index 5ae684a3..bda707e4 100644
--- a/wolfssh/settings.h
+++ b/wolfssh/settings.h
@@ -45,9 +45,6 @@ extern "C" {
#define USE_WINDOWS_API
#endif
-#define WOLFSSH_NO_CLIENT
- /* The client code is incomplete. */
-
#ifdef __cplusplus
}
diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h
index ca5af78b..5f3f0131 100644
--- a/wolfssh/ssh.h
+++ b/wolfssh/ssh.h
@@ -125,11 +125,14 @@ WOLFSSH_API void wolfSSH_SetUserAuth(WOLFSSH_CTX*, WS_CallbackUserAuth);
WOLFSSH_API void wolfSSH_SetUserAuthCtx(WOLFSSH*, void*);
WOLFSSH_API void* wolfSSH_GetUserAuthCtx(WOLFSSH*);
+WOLFSSH_API int wolfSSH_SetUsername(WOLFSSH*, const char*);
+
WOLFSSH_API int wolfSSH_CTX_SetBanner(WOLFSSH_CTX*, const char*);
WOLFSSH_API int wolfSSH_CTX_UsePrivateKey_buffer(WOLFSSH_CTX*,
const byte*, word32, int);
WOLFSSH_API int wolfSSH_accept(WOLFSSH*);
+WOLFSSH_API int wolfSSH_connect(WOLFSSH*);
WOLFSSH_API int wolfSSH_shutdown(WOLFSSH*);
WOLFSSH_API int wolfSSH_stream_read(WOLFSSH*, byte*, word32);
WOLFSSH_API int wolfSSH_stream_send(WOLFSSH*, byte*, word32);
diff --git a/wolfssh/test.h b/wolfssh/test.h
old mode 100755
new mode 100644