From eb82d2bf285cea59d2392224c6ef332be631e199 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 1 Jul 2014 17:27:47 -0700 Subject: [PATCH] Adding code --- examples/server/server.c | 226 ++++++++++++++++++++++++++++++++ src/ssh.c | 271 +++++++++++++++++++++++++++++++++++++++ wolfssh/internal.h | 57 ++++++++ wolfssh/ssh.h | 20 +++ 4 files changed, 574 insertions(+) diff --git a/examples/server/server.c b/examples/server/server.c index 6154bdc..819a450 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -20,12 +20,234 @@ */ +#include + #include + #include + #include + #include + #include + #include + #include + #include + #include #include #include +typedef unsigned short word16; +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 + +#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* ACCEPT_THIRD_T; +#else + #if defined _XOPEN_SOURCE_EXTENDED + typedef socklen_t* ACCEPT_THIRD_T; + #else + typedef int* ACCEPT_THIRD_T; + #endif +#endif + + +static WINLINE void err_sys(const char* msg) +{ + printf("server error: %s\n", msg); + if (msg) + exit(EXIT_FAILURE); +} + + +static WINLINE void build_addr(SOCKADDR_IN_T* addr, const char* peer, + word16 port) +{ + int useLookup = 0; + (void)useLookup; + + 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; + } + else + err_sys("no entry for host"); + } +#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 WINLINE 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 WINLINE void tcp_listen(SOCKET_T* sockfd, word16* 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"); + if (listen(*sockfd, 5) != 0) + err_sys("tcp listen failed"); + #if !defined(USE_WINDOWS_API) + if (*port == 0) { + socklen_t len = sizeof(addr); + if (getsockname(*sockfd, (struct sockaddr*)&addr, &len) == 0) { + #ifndef TEST_IPV6 + *port = ntohs(addr.sin_port); + #else + *port = ntohs(addr.sin6_port); + #endif + } + } + #endif +} + + +static WINLINE void tcp_accept(SOCKET_T* sockfd, SOCKET_T* clientfd, word16 port) +{ + SOCKADDR_IN_T client; + socklen_t client_len = sizeof(client); + + tcp_listen(sockfd, &port, 1); + + *clientfd = accept(*sockfd, (struct sockaddr*)&client, + (ACCEPT_THIRD_T)&client_len); + + if (*clientfd == -1) + err_sys("tcp accept failed"); +} + + int main(void) { + SOCKET_T sockfd = 0; + SOCKET_T clientfd = 0; + #ifdef DEBUG_WOLFSSH wolfSSH_Debugging_ON(); #endif @@ -34,9 +256,13 @@ int main(void) exit(EXIT_FAILURE); } + tcp_accept(&sockfd, &clientfd, 22222); + if (wolfSSH_Cleanup() != WS_SUCCESS) { fprintf(stderr, "Couldn't clean up wolfSSH.\n"); exit(EXIT_FAILURE); } + + return 0; } diff --git a/src/ssh.c b/src/ssh.c index cd97c43..6dbab74 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -44,3 +44,274 @@ int wolfSSH_Cleanup(void) return WS_SUCCESS; } + +static WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, void* heap) +{ + WLOG(WS_LOG_DEBUG, "Enter CtxInit()"); + + if (ctx == NULL) + return ctx; + + WMEMSET(ctx, 0, sizeof(WOLFSSH_CTX)); + + if (heap) + ctx->heap = heap; + +#ifndef WOLFSSH_USER_IO + ctx->ioRecvCb = wsEmbedRecv; + ctx->ioSendCb = wsEmbedSend; +#endif /* WOLFSSH_USER_IO */ + + return ctx; +} + + +WOLFSSH_CTX* wolfSSH_CTX_new(void* heap) +{ + WOLFSSH_CTX* ctx; + + WLOG(WS_LOG_DEBUG, "Enter wolfSSH_CTX_new()"); + + ctx = (WOLFSSH_CTX*)WMALLOC(sizeof(WOLFSSH_CTX), heap, WOLFSSH_CTX_TYPE); + ctx = CtxInit(ctx, heap); + + WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_CTX_new(), ctx = %p", ctx); + + return ctx; +} + + +static void CtxResourceFree(WOLFSSH_CTX* ctx) +{ + /* when context holds resources, free here */ + (void)ctx; + + WLOG(WS_LOG_DEBUG, "Enter CtxResourceFree()"); +} + + +void wolfSSH_CTX_free(WOLFSSH_CTX* ctx) +{ + WLOG(WS_LOG_DEBUG, "Enter wolfSSH_CTX_free()"); + + if (ctx) { + CtxResourceFree(ctx); + WFREE(ctx, ctx->heap, WOLFSSH_CTX_TYPE); + } +} + + +static WOLFSSH* SshInit(WOLFSSH* ssh, WOLFSSH_CTX* ctx) +{ + WLOG(WS_LOG_DEBUG, "Enter SshInit()"); + + if (ssh == NULL) + return ssh; + + WMEMSET(ssh, 0, sizeof(WOLFSSH)); /* default init to zeros */ + + if (ctx) + ssh->ctx = ctx; + else { + WLOG(WS_LOG_ERROR, "Trying to init a wolfSSH w/o wolfSSH_CTX"); + wolfSSH_free(ssh); + return NULL; + } + + ssh->rfd = -1; /* set to invalid */ + ssh->wfd = -1; /* set to invalid */ + ssh->ioReadCtx = &ssh->rfd; /* prevent invalid access if not correctly */ + ssh->ioWriteCtx = &ssh->wfd; /* set */ + + return ssh; +} + + +WOLFSSH* wolfSSH_new(WOLFSSH_CTX* ctx) +{ + WOLFSSH* ssh; + void* heap = NULL; + + if (ctx) + heap = ctx->heap; + + WLOG(WS_LOG_DEBUG, "Enter wolfSSH_new()"); + + ssh = (WOLFSSH*)WMALLOC(sizeof(WOLFSSH), heap, WOLFSSH_TYPE); + ssh = SshInit(ssh, ctx); + + WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_new(), ssh = %p", ssh); + + return ssh; +} + + +static void SshResourceFree(WOLFSSH* ssh) +{ + /* when ssh holds resources, free here */ + (void)ssh; + + WLOG(WS_LOG_DEBUG, "Enter sshResourceFree()"); +} + + +void wolfSSH_free(WOLFSSH* ssh) +{ + WLOG(WS_LOG_DEBUG, "Enter wolfSSH_free()"); + + if (ssh) { + SshResourceFree(ssh); + WFREE(ssh, ssh->ctx ? ssh->ctx->heap : NULL, WOLFSSH_TYPE); + } +} + + +static WOLFSSH_CHAN* SshChanInit(WOLFSSH_CHAN* chan, WOLFSSH* ssh) +{ + WLOG(WS_LOG_DEBUG, "Enter SshChanInit()"); + + if (chan == NULL) + return chan; + + WMEMSET(chan, 0, sizeof(WOLFSSH_CHAN)); /* default init to zeros */ + + if (ssh) { + chan->ssh = ssh; + chan->ctx = ssh->ctx; + } + else { + WLOG(WS_LOG_ERROR, "Trying to init a wolfSSH_CHAN w/o wolfSSH"); + wolfSSH_CHAN_free(chan); + return NULL; + } + + return chan; +} + + +WOLFSSH_CHAN* wolfSSH_CHAN_new(WOLFSSH* ssh) +{ + WOLFSSH_CHAN* chan; + void* heap = NULL; + + WLOG(WS_LOG_DEBUG, "Enter wolfSSH_CHAN_new()"); + + if (ssh != NULL && ssh->ctx != NULL) + heap = ssh->ctx->heap; + + chan = (WOLFSSH_CHAN*)WMALLOC(sizeof(WOLFSSH_CHAN), + heap, WOLFSSH_CHAN_TYPE); + + chan = SshChanInit(chan, ssh); + + WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_CHAN_new(), chan = %p", chan); + + return chan; +} + + +static void SshChanResourceFree(WOLFSSH_CHAN* chan) +{ + /* when ssh channel holds resources, free here */ + (void)chan; + + WLOG(WS_LOG_DEBUG, "Enter SshChanResourceFree()"); +} + + +void wolfSSH_CHAN_free(WOLFSSH_CHAN* chan) +{ + WLOG(WS_LOG_DEBUG, "Enter wolfSCEP_free()"); + + if (chan) { + SshChanResourceFree(chan); + WFREE(chan, chan->ctx ? chan->ctx->heap : NULL, WOLFSCEP_TYPE); + } +} + + +int wolfSSH_set_fd(WOLFSSH* ssh, int fd) +{ + WLOG(WS_LOG_DEBUG, "Enter wolfSSH_set_fd()"); + + if (ssh) { + ssh->rfd = fd; + ssh->wfd = fd; + + ssh->ioReadCtx = &ssh->rfd; + ssh->ioWriteCtx = &ssh->wfd; + + return WS_SUCCESS; + } + return WS_BAD_ARGUMENT; +} + + +int wolfSSH_get_fd(const WOLFSSH* ssh) +{ + WLOG(WS_LOG_DEBUG, "Enter wolfSSH_get_fd()"); + + if (ssh) + return ssh->rfd; + + return WS_BAD_ARGUMENT; +} + + +enum { + doProcessInit +}; + + +int ProcessReply(WOLFSSH* ssh) +{ + int ret = WS_FATAL_ERROR; + int readSz; + + (void)readSz; + for (;;) { + switch (ssh->processReply) { + case doProcessInit: + readSz = ssh->blockSz; + } + } + return ret; +} + + +int wolfSSH_accept(WOLFSSH* ssh) +{ + switch (ssh->acceptState) { + case ACCEPT_BEGIN: + if ( (ssh->error = ProcessReply(ssh)) < 0) { + WLOG(WS_LOG_DEBUG, "accept reply error: %d", ssh->error); + return WS_FATAL_ERROR; + } + ssh->acceptState = CLIENT_VERSION_DONE; + WLOG(WS_LOG_DEBUG, "accept state CLIENT_VERSION_DONE"); + + case CLIENT_VERSION_DONE: + break; + + case SERVER_VERSION_SENT: + break; + } + + return WS_FATAL_ERROR; +} + + + +int SendServerVersion(WOLFSSH* ssh) +{ + (void)ssh; + return WS_FATAL_ERROR; +} + + +int DoClientVersion(WOLFSSH* ssh) +{ + (void)ssh; + return WS_FATAL_ERROR; +} + diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 8c931c8..5844187 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -29,21 +29,65 @@ extern "C" { #endif +enum { + /* Any of the items can be none. */ + ID_NONE, + + /* Encryption IDs */ + ID_AES128_CBC, + ID_AES128_CTR, + ID_AES128_GCM_WOLF, + + /* Integrity IDs */ + ID_HMAC_SHA1, + ID_HMAC_SHA1_96, + + /* Key Exchange IDs */ + ID_DH_GROUP1_SHA1, + ID_DH_GROUP14_SHA1, + + /* Public Key IDs */ + ID_SSH_RSA, + + ID_UNKNOWN +}; + + +WOLFSSH_LOCAL uint8_t NameToId(const char*); +WOLFSSH_LOCAL const char* IdToName(uint8_t); + + /* our wolfSSH Context */ struct WOLFSSH_CTX { void* heap; /* heap hint */ WS_CallbackIORecv ioRecvCb; /* I/O Receive Callback */ WS_CallbackIOSend ioSendCb; /* I/O Send Callback */ + uint8_t compression; }; /* our wolfSSH session */ struct WOLFSSH { WOLFSSH_CTX* ctx; /* owner context */ + int error; + int rfd; + int wfd; void* ioReadCtx; /* I/O Read Context handle */ void* ioWriteCtx; /* I/O Write Context handle */ int rflags; /* optional read flags */ int wflags; /* optional write flags */ + WOLFSSH_CHAN *channel; /* single data channel */ + uint8_t blockSz; + uint8_t acceptState; + uint8_t processReply; +}; + + +/* wolfSSH channel */ +struct WOLFSSH_CHAN { + WOLFSSH_CTX* ctx; + WOLFSSH* ssh; + int id; }; @@ -55,6 +99,19 @@ WOLFSSH_LOCAL int wsEmbedSend(WOLFSSH* ssh, void*, uint32_t sz, void* ctx); #endif /* WOLFSSH_USER_IO */ + +WOLFSSH_LOCAL int ProcessReply(WOLFSSH*); +WOLFSSH_LOCAL int SendServerVersion(WOLFSSH*); +WOLFSSH_LOCAL int DoClientVersion(WOLFSSH*); + + +enum { + ACCEPT_BEGIN = 0, + CLIENT_VERSION_DONE, + SERVER_VERSION_SENT, +}; + + #ifdef __cplusplus } #endif diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index 58bb0c6..2ea0938 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -42,12 +42,31 @@ WOLFSSH_API int wolfSSH_Cleanup(void); WOLFSSH_API int wolfSSH_Debugging_ON(void); WOLFSSH_API void wolfSSH_Debugging_OFF(void); +/* context functions */ +WOLFSSH_API WOLFSSH_CTX* wolfSSH_CTX_new(void*); +WOLFSSH_API void wolfSSH_CTX_free(WOLFSSH_CTX*); + +/* ssh session functions */ +WOLFSSH_API WOLFSSH* wolfSSH_new(WOLFSSH_CTX*); +WOLFSSH_API void wolfSSH_free(WOLFSSH*); + +/* ssh channel functions */ +WOLFSSH_API WOLFSSH_CHAN* wolfSSH_CHAN_new(WOLFSSH*); +WOLFSSH_API void wolfSSH_CHAN_free(WOLFSSH_CHAN*); + +WOLFSSH_API int wolfSSH_set_fd(WOLFSSH*, int); +WOLFSSH_API int wolfSSH_get_fd(const WOLFSSH*); + WOLFSSH_API const char* wolfSSH_get_error(int); /* I/O callbacks */ typedef int (*WS_CallbackIORecv)(WOLFSSH*, void* buf, uint32_t sz, void* ctx); typedef int (*WS_CallbackIOSend)(WOLFSSH*, void* buf, uint32_t sz, void* ctx); +/* Channel I/O callbacks */ +typedef int (*WSH_CallbackChanRecv)(); +typedef int (*WSH_CallbackChanSend)(); + WOLFSSH_API void wolfSSH_SetIORecv(WOLFSSH_CTX*, WS_CallbackIORecv); WOLFSSH_API void wolfSSH_SetIOSend(WOLFSSH_CTX*, WS_CallbackIOSend); @@ -57,6 +76,7 @@ WOLFSSH_API void wolfSSH_SetIOWriteCtx(WOLFSSH* ssh, void *ctx); WOLFSSH_API void* wolfSSH_GetIOReadCtx(WOLFSSH* ssh); WOLFSSH_API void* wolfSSH_GetIOWriteCtx(WOLFSSH* ssh); +WOLFSSH_API int wolfSSH_accept(WOLFSSH* ssh); /* dynamic memory types */