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