ssh

Dependents:   OS

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers internal.c Source File

internal.c

00001 /* internal.c
00002  *
00003  * Copyright (C) 2014-2016 wolfSSL Inc.
00004  *
00005  * This file is part of wolfSSH.
00006  *
00007  * wolfSSH is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 3 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * wolfSSH is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with wolfSSH.  If not, see <http://www.gnu.org/licenses/>.
00019  */
00020 
00021 
00022 /*
00023  * The internal module contains the private data and functions. The public
00024  * API calls into this module to do the work of processing the connections.
00025  */
00026 
00027 
00028 #ifdef HAVE_CONFIG_H
00029     #include <config.h>
00030 #endif
00031 
00032 #include <wolfssh/ssh.h>
00033 #include <wolfssh/internal.h>
00034 #include <wolfssh/log.h>
00035 #include <wolfcrypt/asn.h>
00036 #include <wolfcrypt/dh.h>
00037 #include <wolfcrypt/rsa.h>
00038 #include <wolfcrypt/ecc.h>
00039 #include <wolfcrypt/hmac.h>
00040 #include <wolfcrypt/integer.h>
00041 #include <wolfcrypt/signature.h>
00042 
00043 //#include "esp_log.h"
00044 //#include "esp_system.h"
00045 
00046 #ifdef NO_INLINE
00047     #include <wolfssh/misc.h>
00048 #else
00049     #define WOLFSSH_MISC_INCLUDED
00050     #include "src/misc.c"
00051 #endif
00052 
00053 
00054 static const char sshProtoIdStr[] = "SSH-2.0-wolfSSHv"
00055                                     LIBWOLFSSH_VERSION_STRING
00056                                     "\r\n";
00057 #ifndef WOLFSSH_DEFAULT_GEXDH_MIN
00058     #define WOLFSSH_DEFAULT_GEXDH_MIN 1024
00059 #endif
00060 #ifndef WOLFSSH_DEFAULT_GEXDH_PREFERRED
00061     #define WOLFSSH_DEFAULT_GEXDH_PREFERRED 3072
00062 #endif
00063 #ifndef WOLFSSH_DEFAULT_GEXDH_MAX
00064     #define WOLFSSH_DEFAULT_GEXDH_MAX 8192
00065 #endif
00066 
00067 
00068 const char* GetErrorString(int err)
00069 {
00070     (void)err;
00071 
00072 #ifdef NO_WOLFSSH_STRINGS
00073     return "No wolfSSH strings available";
00074 #else
00075     switch (err) {
00076         case WS_SUCCESS:
00077             return "function success";
00078 
00079         case WS_FATAL_ERROR:
00080             return "general function failure";
00081 
00082         case WS_BAD_ARGUMENT:
00083             return "bad function argument";
00084 
00085         case WS_MEMORY_E:
00086             return "memory allocation failure";
00087 
00088         case WS_BUFFER_E:
00089             return "input/output buffer size error";
00090 
00091         case WS_PARSE_E:
00092             return "general parsing error";
00093 
00094         case WS_NOT_COMPILED:
00095             return "feature not compiled in";
00096 
00097         case WS_OVERFLOW_E:
00098             return "would overflow if continued failure";
00099 
00100         case WS_BAD_USAGE:
00101             return "bad example usage";
00102 
00103         case WS_SOCKET_ERROR_E:
00104             return "socket error";
00105 
00106         case WS_WANT_READ:
00107             return "I/O callback would read block error";
00108 
00109         case WS_WANT_WRITE:
00110             return "I/O callback would write block error";
00111 
00112         case WS_RECV_OVERFLOW_E:
00113             return "receive buffer overflow";
00114 
00115         case WS_VERSION_E:
00116             return "peer version unsupported";
00117 
00118         case WS_SEND_OOB_READ_E:
00119             return "attempted to read buffer out of bounds";
00120 
00121         case WS_INPUT_CASE_E:
00122             return "bad process input state, programming error";
00123 
00124         case WS_BAD_FILETYPE_E:
00125             return "bad filetype";
00126 
00127         case WS_UNIMPLEMENTED_E:
00128             return "feature not implemented";
00129 
00130         case WS_RSA_E:
00131             return "RSA buffer error";
00132 
00133         case WS_BAD_FILE_E:
00134             return "bad file";
00135 
00136         case WS_DECRYPT_E:
00137             return "decrypt error";
00138 
00139         case WS_ENCRYPT_E:
00140             return "encrypt error";
00141 
00142         case WS_VERIFY_MAC_E:
00143             return "verify mac error";
00144 
00145         case WS_CREATE_MAC_E:
00146             return "verify mac error";
00147 
00148         case WS_RESOURCE_E:
00149             return "insufficient resources for new channel";
00150 
00151         case WS_INVALID_CHANTYPE:
00152             return "peer requested invalid channel type";
00153 
00154         case WS_INVALID_CHANID:
00155             return "peer requested invalid channel id";
00156 
00157         case WS_INVALID_USERNAME:
00158             return "invalid user name";
00159 
00160         case WS_CRYPTO_FAILED:
00161             return "crypto action failed";
00162 
00163         case WS_INVALID_STATE_E:
00164             return "invalid state";
00165 
00166         case WS_REKEYING:
00167             return "rekeying with peer";
00168 
00169         case WS_INVALID_PRIME_CURVE:
00170             return "invalid prime curve in ecc";
00171 
00172         case WS_ECC_E:
00173             return "ECDSA buffer error";
00174 
00175         case WS_CHANOPEN_FAILED:
00176             return "peer returned channel open failure";
00177 
00178         case WS_CHANNEL_CLOSED:
00179             return "channel closed";
00180 
00181         default:
00182             return "Unknown error code";
00183     }
00184 #endif
00185 }
00186 
00187 
00188 static int wsHighwater(byte dir, void* ctx)
00189 {
00190     int ret = WS_SUCCESS;
00191 
00192     (void)dir;
00193 
00194     if (ctx) {
00195         WOLFSSH* ssh = (WOLFSSH*)ctx;
00196 
00197         WLOG(WS_LOG_DEBUG, "HIGHWATER MARK: (%u) %s",
00198              wolfSSH_GetHighwater(ssh),
00199              (dir == WOLFSSH_HWSIDE_RECEIVE) ? "receive" : "transmit");
00200 
00201         ret = wolfSSH_TriggerKeyExchange(ssh);
00202     }
00203 
00204     return ret;
00205 }
00206 
00207 
00208 static INLINE void HighwaterCheck(WOLFSSH* ssh, byte side)
00209 {
00210     if (!ssh->highwaterFlag && ssh->highwaterMark &&
00211         (ssh->txCount >= ssh->highwaterMark ||
00212          ssh->rxCount >= ssh->highwaterMark)) {
00213 
00214         WLOG(WS_LOG_DEBUG, "%s over high water mark",
00215              (side == WOLFSSH_HWSIDE_TRANSMIT) ? "Transmit" : "Receive");
00216 
00217         ssh->highwaterFlag = 1;
00218 
00219         if (ssh->ctx->highwaterCb)
00220             ssh->ctx->highwaterCb(side, ssh->highwaterCtx);
00221     }
00222 }
00223 
00224 
00225 static HandshakeInfo* HandshakeInfoNew(void* heap)
00226 {
00227     HandshakeInfo* newHs;
00228 
00229     WLOG(WS_LOG_DEBUG, "Entering HandshakeInfoNew()");
00230     newHs = (HandshakeInfo*)WMALLOC(sizeof(HandshakeInfo),
00231                                     heap, DYNTYPE_HS);
00232     if (newHs != NULL) {
00233         WMEMSET(newHs, 0, sizeof(HandshakeInfo));
00234         newHs->kexId = ID_NONE;
00235         newHs->pubKeyId  = ID_NONE;
00236         newHs->encryptId = ID_NONE;
00237         newHs->macId = ID_NONE;
00238         newHs->blockSz = MIN_BLOCK_SZ;
00239         newHs->hashId = WC_HASH_TYPE_NONE;
00240         newHs->dhGexMinSz = WOLFSSH_DEFAULT_GEXDH_MIN;
00241         newHs->dhGexPreferredSz = WOLFSSH_DEFAULT_GEXDH_PREFERRED;
00242         newHs->dhGexMaxSz = WOLFSSH_DEFAULT_GEXDH_MAX;
00243     }
00244 
00245     return newHs;
00246 }
00247 
00248 void ForceZero(const void* mem, word32 length){
00249     }
00250 
00251 static void HandshakeInfoFree(HandshakeInfo* hs, void* heap)
00252 {
00253     (void)heap;
00254 
00255     WLOG(WS_LOG_DEBUG, "Entering HandshakeInfoFree()");
00256     if (hs) {
00257         WFREE(hs->kexInit, heap, DYNTYPE_STRING);
00258         WFREE(hs->primeGroup, heap, DYNTYPE_MPINT);
00259         WFREE(hs->generator, heap, DYNTYPE_MPINT);
00260         ForceZero(hs, sizeof(HandshakeInfo));
00261         WFREE(hs, heap, DYNTYPE_HS);
00262     }
00263 }
00264 
00265 
00266 #ifdef DEBUG_WOLFSSH
00267 
00268 static const char cannedBanner[] =
00269     "CANNED BANNER\r\n"
00270     "This server is an example test server. "
00271     "It should have its own banner, but\r\n"
00272     "it is currently using a canned one in "
00273     "the library. Be happy or not.\r\n";
00274 static const word32 cannedBannerSz = sizeof(cannedBanner) - 1;
00275 
00276 #endif /* DEBUG_WOLFSSH */
00277 
00278 
00279 WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, byte side, void* heap)
00280 {
00281     WLOG(WS_LOG_DEBUG, "Entering CtxInit()");
00282 
00283     if (ctx == NULL)
00284         return ctx;
00285 
00286     WMEMSET(ctx, 0, sizeof(WOLFSSH_CTX));
00287 
00288     if (heap)
00289         ctx->heap = heap;
00290 
00291     ctx->side = side;
00292 #ifndef WOLFSSH_USER_IO
00293     ctx->ioRecvCb = wsEmbedRecv;
00294     ctx->ioSendCb = wsEmbedSend;
00295 #endif /* WOLFSSH_USER_IO */
00296     ctx->highwaterMark = DEFAULT_HIGHWATER_MARK;
00297     ctx->highwaterCb = wsHighwater;
00298 #ifdef DEBUG_WOLFSSH
00299     ctx->banner = cannedBanner;
00300     ctx->bannerSz = cannedBannerSz;
00301 #endif /* DEBUG_WOLFSSH */
00302 
00303     return ctx;
00304 }
00305 
00306 
00307 void CtxResourceFree(WOLFSSH_CTX* ctx)
00308 {
00309     WLOG(WS_LOG_DEBUG, "Entering CtxResourceFree()");
00310 
00311     if (ctx->privateKey) {
00312         ForceZero(ctx->privateKey, ctx->privateKeySz);
00313         WFREE(ctx->privateKey, ctx->heap, DYNTYPE_PRIVKEY);
00314     }
00315 }
00316 
00317 
00318 WOLFSSH* SshInit(WOLFSSH* ssh, WOLFSSH_CTX* ctx)
00319 {
00320     HandshakeInfo* handshake;
00321     RNG*           rng;
00322     void*          heap;
00323 
00324     WLOG(WS_LOG_DEBUG, "Entering SshInit()");
00325     //ESP_LOGI("WOLFSSH", "SshInit()");
00326 
00327     if (ssh == NULL || ctx == NULL)
00328         return ssh;
00329     heap = ctx->heap;
00330     //ESP_LOGI("WOLFSSH", "heap=ctx->heap");
00331 
00332     handshake = HandshakeInfoNew(heap);
00333     //ESP_LOGI("WOLFSSH", "HandshakeInfoNew(heap) OK");
00334     rng = (RNG*)WMALLOC(sizeof(RNG), heap, DYNTYPE_RNG);
00335     //ESP_LOGI("WOLFSSH", "malloc RNG OK");
00336 
00337     //if(handshake == NULL) ESP_LOGE("WOLFSSH", "handshake is NULL");
00338     //if(rng == NULL) ESP_LOGE("WOLFSSH", "rng is NULL");
00339 
00340 
00341     //ESP_LOGI("WOLFSSH", "wc_InitRng(rng), free heap:%d", esp_get_free_heap_size());
00342 
00343     int wc_InitRng_result = wc_InitRng(rng);
00344 
00345     if (handshake == NULL || rng == NULL || wc_InitRng_result != 0) {
00346         //ESP_LOGE("WOLFSSH", "Cannot allocate memory, wc_InitRng_result ret=%d", wc_InitRng_result);
00347         WLOG(WS_LOG_DEBUG, "SshInit: Cannot allocate memory.\n");
00348         WFREE(handshake, heap, DYNTYPE_HS);
00349         WFREE(rng, heap, DYNTYPE_RNG);
00350         wolfSSH_free(ssh);
00351         return NULL;
00352     }
00353 
00354     WMEMSET(ssh, 0, sizeof(WOLFSSH));  /* default init to zeros */
00355     //ESP_LOGI("WOLFSSH", "memset WOLFSSH");
00356 
00357     ssh->ctx         = ctx;
00358     ssh->error       = WS_SUCCESS;
00359     ssh->rfd         = -1;         /* set to invalid */
00360     ssh->wfd         = -1;         /* set to invalid */
00361     ssh->ioReadCtx   = &ssh->rfd;  /* prevent invalid access if not correctly */
00362     ssh->ioWriteCtx  = &ssh->wfd;  /* set */
00363     ssh->highwaterMark = ctx->highwaterMark;
00364     ssh->highwaterCtx  = (void*)ssh;
00365     ssh->acceptState = ACCEPT_BEGIN;
00366     ssh->clientState = CLIENT_BEGIN;
00367     ssh->isKeying    = 1;
00368     ssh->nextChannel = DEFAULT_NEXT_CHANNEL;
00369     ssh->blockSz     = MIN_BLOCK_SZ;
00370     ssh->encryptId   = ID_NONE;
00371     ssh->macId       = ID_NONE;
00372     ssh->peerBlockSz = MIN_BLOCK_SZ;
00373     ssh->rng         = rng;
00374     ssh->kSz         = sizeof(ssh->k);
00375     ssh->handshake   = handshake;
00376 
00377     //ESP_LOGI("WOLFSSH", "BufferInit...");
00378     if (BufferInit(&ssh->inputBuffer, 0, ctx->heap) != WS_SUCCESS ||
00379         BufferInit(&ssh->outputBuffer, 0, ctx->heap) != WS_SUCCESS) {
00380 
00381         wolfSSH_free(ssh);
00382         ssh = NULL;
00383     }
00384     //ESP_LOGI("WOLFSSH", "BufferInit OK");
00385 
00386     return ssh;
00387 }
00388 
00389 void SshResourceFree(WOLFSSH* ssh, void* heap)
00390 {
00391     /* when ssh holds resources, free here */
00392     (void)heap;
00393 
00394     WLOG(WS_LOG_DEBUG, "Entering sshResourceFree()");
00395 
00396     ShrinkBuffer(&ssh->inputBuffer, 1);
00397     ShrinkBuffer(&ssh->outputBuffer, 1);
00398     ForceZero(ssh->k, ssh->kSz);
00399     HandshakeInfoFree(ssh->handshake, heap);
00400     ForceZero(&ssh->keys, sizeof(Keys));
00401     ForceZero(&ssh->peerKeys, sizeof(Keys));
00402     if (ssh->rng) {
00403         wc_FreeRng(ssh->rng);
00404         WFREE(ssh->rng, heap, DYNTYPE_RNG);
00405     }
00406     if (ssh->userName) {
00407         WFREE(ssh->userName, heap, DYNTYPE_STRING);
00408     }
00409     if (ssh->peerProtoId) {
00410         WFREE(ssh->peerProtoId, heap, DYNTYPE_STRING);
00411     }
00412     if (ssh->channelList) {
00413         WOLFSSH_CHANNEL* cur = ssh->channelList;
00414         WOLFSSH_CHANNEL* next;
00415         while (cur) {
00416             next = cur->next;
00417             ChannelDelete(cur, heap);
00418             cur = next;
00419         }
00420     }
00421 }
00422 
00423 
00424 int wolfSSH_ProcessBuffer(WOLFSSH_CTX* ctx,
00425                           const byte* in, word32 inSz,
00426                           int format, int type)
00427 {
00428     int dynamicType;
00429     void* heap;
00430     byte* der;
00431     word32 derSz;
00432 
00433     if (ctx == NULL || in == NULL || inSz == 0)
00434         return WS_BAD_ARGUMENT;
00435 
00436     if (format != WOLFSSH_FORMAT_ASN1 && format != WOLFSSH_FORMAT_PEM &&
00437                                          format != WOLFSSH_FORMAT_RAW)
00438         return WS_BAD_FILETYPE_E;
00439 
00440     if (type == BUFTYPE_CA)
00441         dynamicType = DYNTYPE_CA;
00442     else if (type == BUFTYPE_CERT)
00443         dynamicType = DYNTYPE_CERT;
00444     else if (type == BUFTYPE_PRIVKEY)
00445         dynamicType = DYNTYPE_PRIVKEY;
00446     else
00447         return WS_BAD_ARGUMENT;
00448 
00449     heap = ctx->heap;
00450 
00451     if (format == WOLFSSH_FORMAT_PEM)
00452         return WS_UNIMPLEMENTED_E;
00453     else {
00454         /* format is ASN1 or RAW */
00455         der = (byte*)WMALLOC(inSz, heap, dynamicType);
00456         if (der == NULL)
00457             return WS_MEMORY_E;
00458         WMEMCPY(der, in, inSz);
00459         derSz = inSz;
00460     }
00461 
00462     /* Maybe decrypt */
00463 
00464     if (type == BUFTYPE_PRIVKEY) {
00465         if (ctx->privateKey)
00466             WFREE(ctx->privateKey, heap, dynamicType);
00467         ctx->privateKey = der;
00468         ctx->privateKeySz = derSz;
00469     }
00470     else {
00471         WFREE(der, heap, dynamicType);
00472         return WS_UNIMPLEMENTED_E;
00473     }
00474 
00475     if (type == BUFTYPE_PRIVKEY && format != WOLFSSH_FORMAT_RAW) {
00476         /* Check RSA key */
00477         union {
00478             RsaKey rsa;
00479             ecc_key ecc;
00480         } key;
00481         word32 scratch = 0;
00482         int ret;
00483 
00484         if (wc_InitRsaKey(&key.rsa, NULL) < 0)
00485             return WS_RSA_E;
00486 
00487         ret = wc_RsaPrivateKeyDecode(der, &scratch, &key.rsa, derSz);
00488         wc_FreeRsaKey(&key.rsa);
00489 
00490         if (ret < 0) {
00491             /* Couldn't decode as RSA key. Try decoding as ECC key. */
00492             scratch = 0;
00493             if (wc_ecc_init_ex(&key.ecc, ctx->heap, INVALID_DEVID) != 0)
00494                 return WS_ECC_E;
00495 
00496             ret = wc_EccPrivateKeyDecode(ctx->privateKey, &scratch,
00497                                          &key.ecc, ctx->privateKeySz);
00498             if (ret == 0) {
00499                 int curveId = wc_ecc_get_curve_id(key.ecc.idx);
00500                 if (curveId == ECC_SECP256R1 ||
00501                     curveId == ECC_SECP384R1 ||
00502                     curveId == ECC_SECP521R1) {
00503 
00504                     ctx->useEcc = curveId;
00505                 }
00506                 else
00507                     ret = WS_BAD_FILE_E;
00508             }
00509             wc_ecc_free(&key.ecc);
00510 
00511             if (ret != 0)
00512                 return WS_BAD_FILE_E;
00513         }
00514     }
00515 
00516     return WS_SUCCESS;
00517 }
00518 
00519 void c32toa(word32 u32, byte* c){
00520     }
00521     
00522 int GenerateKey(byte hashId, byte keyId,
00523                 byte* key, word32 keySz,
00524                 const byte* k, word32 kSz,
00525                 const byte* h, word32 hSz,
00526                 const byte* sessionId, word32 sessionIdSz)
00527 {
00528     word32 blocks, remainder;
00529     wc_HashAlg hash;
00530     byte kPad = 0;
00531     byte pad = 0;
00532     byte kSzFlat[LENGTH_SZ];
00533     int digestSz;
00534     int ret;
00535 
00536     if (key == NULL || keySz == 0 ||
00537         k == NULL || kSz == 0 ||
00538         h == NULL || hSz == 0 ||
00539         sessionId == NULL || sessionIdSz == 0) {
00540 
00541         WLOG(WS_LOG_DEBUG, "GK: bad argument");
00542         return WS_BAD_ARGUMENT;
00543     }
00544 
00545     digestSz = wc_HashGetDigestSize(hashId);
00546     if (digestSz == 0) {
00547         WLOG(WS_LOG_DEBUG, "GK: bad hash ID");
00548         return WS_BAD_ARGUMENT;
00549     }
00550 
00551     if (k[0] & 0x80) kPad = 1;
00552     c32toa(kSz + kPad, kSzFlat);
00553 
00554     blocks = keySz / digestSz;
00555     remainder = keySz % digestSz;
00556 
00557     ret = wc_HashInit(&hash, hashId);
00558     if (ret == WS_SUCCESS)
00559         ret = wc_HashUpdate(&hash, hashId, kSzFlat, LENGTH_SZ);
00560     if (ret == WS_SUCCESS && kPad)
00561         ret = wc_HashUpdate(&hash, hashId, &pad, 1);
00562     if (ret == WS_SUCCESS)
00563         ret = wc_HashUpdate(&hash, hashId, k, kSz);
00564     if (ret == WS_SUCCESS)
00565         ret = wc_HashUpdate(&hash, hashId, h, hSz);
00566     if (ret == WS_SUCCESS)
00567         ret = wc_HashUpdate(&hash, hashId, &keyId, sizeof(keyId));
00568     if (ret == WS_SUCCESS)
00569         ret = wc_HashUpdate(&hash, hashId, sessionId, sessionIdSz);
00570 
00571     if (ret == WS_SUCCESS) {
00572         if (blocks == 0) {
00573             if (remainder > 0) {
00574                 byte lastBlock[WC_MAX_DIGEST_SIZE];
00575                 ret = wc_HashFinal(&hash, hashId, lastBlock);
00576                 if (ret == WS_SUCCESS)
00577                     WMEMCPY(key, lastBlock, remainder);
00578             }
00579         }
00580         else {
00581             word32 runningKeySz, curBlock;
00582 
00583             runningKeySz = digestSz;
00584             ret = wc_HashFinal(&hash, hashId, key);
00585 
00586             for (curBlock = 1; curBlock < blocks; curBlock++) {
00587                 ret = wc_HashInit(&hash, hashId);
00588                 if (ret != WS_SUCCESS) break;
00589                 ret = wc_HashUpdate(&hash, hashId, kSzFlat, LENGTH_SZ);
00590                 if (ret != WS_SUCCESS) break;
00591                 if (kPad)
00592                     ret = wc_HashUpdate(&hash, hashId, &pad, 1);
00593                 if (ret != WS_SUCCESS) break;
00594                 ret = wc_HashUpdate(&hash, hashId, k, kSz);
00595                 if (ret != WS_SUCCESS) break;
00596                 ret = wc_HashUpdate(&hash, hashId, h, hSz);
00597                 if (ret != WS_SUCCESS) break;
00598                 ret = wc_HashUpdate(&hash, hashId, key, runningKeySz);
00599                 if (ret != WS_SUCCESS) break;
00600                 ret = wc_HashFinal(&hash, hashId, key + runningKeySz);
00601                 if (ret != WS_SUCCESS) break;
00602                 runningKeySz += digestSz;
00603             }
00604 
00605             if (remainder > 0) {
00606                 byte lastBlock[WC_MAX_DIGEST_SIZE];
00607                 if (ret == WS_SUCCESS)
00608                     ret = wc_HashInit(&hash, hashId);
00609                 if (ret == WS_SUCCESS)
00610                     ret = wc_HashUpdate(&hash, hashId, kSzFlat, LENGTH_SZ);
00611                 if (ret == WS_SUCCESS && kPad)
00612                     ret = wc_HashUpdate(&hash, hashId, &pad, 1);
00613                 if (ret == WS_SUCCESS)
00614                     ret = wc_HashUpdate(&hash, hashId, k, kSz);
00615                 if (ret == WS_SUCCESS)
00616                     ret = wc_HashUpdate(&hash, hashId, h, hSz);
00617                 if (ret == WS_SUCCESS)
00618                     ret = wc_HashUpdate(&hash, hashId, key, runningKeySz);
00619                 if (ret == WS_SUCCESS)
00620                     ret = wc_HashFinal(&hash, hashId, lastBlock);
00621                 if (ret == WS_SUCCESS)
00622                     WMEMCPY(key + runningKeySz, lastBlock, remainder);
00623             }
00624         }
00625     }
00626 
00627     if (ret != WS_SUCCESS)
00628         ret = WS_CRYPTO_FAILED;
00629 
00630     return ret;
00631 }
00632 
00633 
00634 static int GenerateKeys(WOLFSSH* ssh)
00635 {
00636     Keys* cK;
00637     Keys* sK;
00638     byte hashId;
00639     int ret = WS_SUCCESS;
00640 
00641     if (ssh == NULL)
00642         ret = WS_BAD_ARGUMENT;
00643     else {
00644         if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER) {
00645             cK = &ssh->handshake->peerKeys;
00646             sK = &ssh->handshake->keys;
00647         }
00648         else {
00649             cK = &ssh->handshake->keys;
00650             sK = &ssh->handshake->peerKeys;
00651         }
00652         hashId = ssh->handshake->hashId;
00653     }
00654 
00655     if (ret == WS_SUCCESS)
00656         ret = GenerateKey(hashId, 'A',
00657                           cK->iv, cK->ivSz,
00658                           ssh->k, ssh->kSz, ssh->h, ssh->hSz,
00659                           ssh->sessionId, ssh->sessionIdSz);
00660     if (ret == WS_SUCCESS)
00661         ret = GenerateKey(hashId, 'B',
00662                           sK->iv, sK->ivSz,
00663                           ssh->k, ssh->kSz, ssh->h, ssh->hSz,
00664                           ssh->sessionId, ssh->sessionIdSz);
00665     if (ret == WS_SUCCESS)
00666         ret = GenerateKey(hashId, 'C',
00667                           cK->encKey, cK->encKeySz,
00668                           ssh->k, ssh->kSz, ssh->h, ssh->hSz,
00669                           ssh->sessionId, ssh->sessionIdSz);
00670     if (ret == WS_SUCCESS)
00671         ret = GenerateKey(hashId, 'D',
00672                           sK->encKey, sK->encKeySz,
00673                           ssh->k, ssh->kSz, ssh->h, ssh->hSz,
00674                           ssh->sessionId, ssh->sessionIdSz);
00675     if (!ssh->handshake->aeadMode) {
00676         if (ret == WS_SUCCESS)
00677             ret = GenerateKey(hashId, 'E',
00678                               cK->macKey, cK->macKeySz,
00679                               ssh->k, ssh->kSz, ssh->h, ssh->hSz,
00680                               ssh->sessionId, ssh->sessionIdSz);
00681         if (ret == WS_SUCCESS)
00682             ret = GenerateKey(hashId, 'F',
00683                               sK->macKey, sK->macKeySz,
00684                               ssh->k, ssh->kSz, ssh->h, ssh->hSz,
00685                               ssh->sessionId, ssh->sessionIdSz);
00686     }
00687 #ifdef SHOW_SECRETS
00688     if (ret == WS_SUCCESS) {
00689         printf("\n** Showing Secrets **\nK:\n");
00690         DumpOctetString(ssh->k, ssh->kSz);
00691         printf("H:\n");
00692         DumpOctetString(ssh->h, ssh->hSz);
00693         printf("Session ID:\n");
00694         DumpOctetString(ssh->sessionId, ssh->sessionIdSz);
00695         printf("A:\n");
00696         DumpOctetString(cK->iv, cK->ivSz);
00697         printf("B:\n");
00698         DumpOctetString(sK->iv, sK->ivSz);
00699         printf("C:\n");
00700         DumpOctetString(cK->encKey, cK->encKeySz);
00701         printf("D:\n");
00702         DumpOctetString(sK->encKey, sK->encKeySz);
00703         printf("E:\n");
00704         DumpOctetString(cK->macKey, cK->macKeySz);
00705         printf("F:\n");
00706         DumpOctetString(sK->macKey, sK->macKeySz);
00707         printf("\n");
00708     }
00709 #endif /* SHOW_SECRETS */
00710 
00711     return ret;
00712 }
00713 
00714 
00715 typedef struct {
00716     byte id;
00717     const char* name;
00718 } NameIdPair;
00719 
00720 
00721 static const NameIdPair NameIdMap[] = {
00722     { ID_NONE, "none" },
00723 
00724     /* Encryption IDs */
00725     { ID_AES128_CBC, "aes128-cbc" },
00726     { ID_AES128_GCM, "aes128-gcm@openssh.com" },
00727 
00728     /* Integrity IDs */
00729     { ID_HMAC_SHA1, "hmac-sha1" },
00730     { ID_HMAC_SHA1_96, "hmac-sha1-96" },
00731     { ID_HMAC_SHA2_256, "hmac-sha2-256" },
00732 
00733     /* Key Exchange IDs */
00734     { ID_DH_GROUP1_SHA1, "diffie-hellman-group1-sha1" },
00735     { ID_DH_GROUP14_SHA1, "diffie-hellman-group14-sha1" },
00736     { ID_DH_GEX_SHA256, "diffie-hellman-group-exchange-sha256" },
00737     { ID_ECDH_SHA2_NISTP256, "ecdh-sha2-nistp256" },
00738     { ID_ECDH_SHA2_NISTP384, "ecdh-sha2-nistp384" },
00739     { ID_ECDH_SHA2_NISTP521, "ecdh-sha2-nistp521" },
00740 
00741     /* Public Key IDs */
00742     { ID_SSH_RSA, "ssh-rsa" },
00743     { ID_ECDSA_SHA2_NISTP256, "ecdsa-sha2-nistp256" },
00744     { ID_ECDSA_SHA2_NISTP384, "ecdsa-sha2-nistp384" },
00745     { ID_ECDSA_SHA2_NISTP521, "ecdsa-sha2-nistp521" },
00746 
00747     /* Service IDs */
00748     { ID_SERVICE_USERAUTH, "ssh-userauth" },
00749     { ID_SERVICE_CONNECTION, "ssh-connection" },
00750 
00751     /* UserAuth IDs */
00752     { ID_USERAUTH_PASSWORD, "password" },
00753     { ID_USERAUTH_PUBLICKEY, "publickey" },
00754 
00755     /* Channel Type IDs */
00756     { ID_CHANTYPE_SESSION, "session" }
00757 };
00758 
00759 
00760 byte NameToId(const char* name, word32 nameSz)
00761 {
00762     byte id = ID_UNKNOWN;
00763     word32 i;
00764 
00765     for (i = 0; i < (sizeof(NameIdMap)/sizeof(NameIdPair)); i++) {
00766         if (nameSz == WSTRLEN(NameIdMap[i].name) &&
00767             WSTRNCMP(name, NameIdMap[i].name, nameSz) == 0) {
00768 
00769             id = NameIdMap[i].id;
00770             break;
00771         }
00772     }
00773 
00774     return id;
00775 }
00776 
00777 
00778 const char* IdToName(byte id)
00779 {
00780     const char* name = "unknown";
00781     word32 i;
00782 
00783     for (i = 0; i < (sizeof(NameIdMap)/sizeof(NameIdPair)); i++) {
00784         if (NameIdMap[i].id == id) {
00785             name = NameIdMap[i].name;
00786             break;
00787         }
00788     }
00789 
00790     return name;
00791 }
00792 
00793 
00794 WOLFSSH_CHANNEL* ChannelNew(WOLFSSH* ssh, byte channelType,
00795                             word32 initialWindowSz, word32 maxPacketSz)
00796 {
00797     WOLFSSH_CHANNEL* newChannel = NULL;
00798 
00799     WLOG(WS_LOG_DEBUG, "Entering ChannelNew()");
00800     if (ssh == NULL || ssh->ctx == NULL) {
00801         WLOG(WS_LOG_DEBUG, "Trying to create new channel without ssh or ctx");
00802     }
00803     else {
00804         void* heap = ssh->ctx->heap;
00805 
00806         newChannel = (WOLFSSH_CHANNEL*)WMALLOC(sizeof(WOLFSSH_CHANNEL),
00807                                                heap, DYNTYPE_CHANNEL);
00808         if (newChannel != NULL)
00809         {
00810             byte* buffer;
00811 
00812             buffer = (byte*)WMALLOC(initialWindowSz, heap, DYNTYPE_BUFFER);
00813             if (buffer != NULL) {
00814                 WMEMSET(newChannel, 0, sizeof(WOLFSSH_CHANNEL));
00815                 newChannel->channelType = channelType;
00816                 newChannel->channel = ssh->nextChannel++;
00817                 newChannel->windowSz = initialWindowSz;
00818                 newChannel->maxPacketSz = maxPacketSz;
00819                 /*
00820                  * In the context of the channel input buffer, the buffer is
00821                  * a fixed size. The property length will be the insert point
00822                  * for new received data. The property idx will be the pull
00823                  * point for the data.
00824                  */
00825                 newChannel->inputBuffer.heap = heap;
00826                 newChannel->inputBuffer.buffer = buffer;
00827                 newChannel->inputBuffer.bufferSz = initialWindowSz;
00828                 newChannel->inputBuffer.dynamicFlag = 1;
00829             }
00830             else {
00831                 WLOG(WS_LOG_DEBUG, "Unable to allocate new channel's buffer");
00832                 WFREE(newChannel, heap, DYNTYPE_CHANNEL);
00833                 newChannel = NULL;
00834             }
00835         }
00836         else {
00837             WLOG(WS_LOG_DEBUG, "Unable to allocate new channel");
00838         }
00839     }
00840 
00841     WLOG(WS_LOG_INFO, "Leaving ChannelNew(), ret = %p", newChannel);
00842 
00843     return newChannel;
00844 }
00845 
00846 
00847 void ChannelDelete(WOLFSSH_CHANNEL* channel, void* heap)
00848 {
00849     (void)heap;
00850 
00851     if (channel) {
00852         WFREE(channel->inputBuffer.buffer,
00853               channel->inputBuffer.heap, DYNTYPE_BUFFER);
00854         WFREE(channel, heap, DYNTYPE_CHANNEL);
00855     }
00856 }
00857 
00858 
00859 #define FIND_SELF 0
00860 #define FIND_PEER 1
00861 
00862 WOLFSSH_CHANNEL* ChannelFind(WOLFSSH* ssh, word32 channel, byte peer)
00863 {
00864     WOLFSSH_CHANNEL* findChannel = NULL;
00865 
00866     WLOG(WS_LOG_DEBUG, "Entering ChannelFind()");
00867 
00868     if (ssh == NULL) {
00869         WLOG(WS_LOG_DEBUG, "Null ssh, not looking for channel");
00870     }
00871     else {
00872         WOLFSSH_CHANNEL* list = ssh->channelList;
00873         word32 listSz = ssh->channelListSz;
00874 
00875         while (list && listSz) {
00876             if (channel == ((peer == FIND_PEER) ?
00877                             list->peerChannel : list->channel)) {
00878                 findChannel = list;
00879                 break;
00880             }
00881             list = list->next;
00882             listSz--;
00883         }
00884     }
00885 
00886     WLOG(WS_LOG_DEBUG, "Leaving ChannelFind(): %p", findChannel);
00887 
00888     return findChannel;
00889 }
00890 
00891 
00892 int ChannelUpdate(WOLFSSH_CHANNEL* channel, word32 peerChannelId,
00893                   word32 peerInitialWindowSz, word32 peerMaxPacketSz)
00894 {
00895     int ret = WS_SUCCESS;
00896 
00897     if (channel == NULL)
00898         ret = WS_BAD_ARGUMENT;
00899     else {
00900         channel->peerChannel = peerChannelId;
00901         channel->peerWindowSz = peerInitialWindowSz;
00902         channel->peerMaxPacketSz = peerMaxPacketSz;
00903     }
00904 
00905     return ret;
00906 }
00907 
00908 
00909 static int ChannelAppend(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel)
00910 {
00911     int ret = WS_SUCCESS;
00912 
00913     WLOG(WS_LOG_DEBUG, "Entering ChannelAppend()");
00914 
00915     if (ssh == NULL || channel == NULL)
00916         ret = WS_BAD_ARGUMENT;
00917 
00918     if (ssh->channelList == NULL) {
00919         ssh->channelList = channel;
00920         ssh->channelListSz = 1;
00921     }
00922     else {
00923         WOLFSSH_CHANNEL* cur = ssh->channelList;
00924         while (cur->next != NULL)
00925             cur = cur->next;
00926         cur->next = channel;
00927         ssh->channelListSz++;
00928     }
00929 
00930     WLOG(WS_LOG_DEBUG, "Leaving ChannelAppend(), ret = %d", ret);
00931     return ret;
00932 }
00933 
00934 
00935 int ChannelRemove(WOLFSSH* ssh, word32 channel, byte peer)
00936 {
00937     int ret = WS_SUCCESS;
00938     WOLFSSH_CHANNEL* list;
00939 
00940     WLOG(WS_LOG_DEBUG, "Entering ChannelRemove()");
00941 
00942     if (ssh == NULL)
00943         ret = WS_BAD_ARGUMENT;
00944 
00945     list = ssh->channelList;
00946     if (list == NULL)
00947         ret = WS_INVALID_CHANID;
00948 
00949     if (ret == WS_SUCCESS) {
00950         WOLFSSH_CHANNEL* prev = NULL;
00951         word32 listSz = ssh->channelListSz;
00952 
00953         while (list && listSz) {
00954             if (channel == ((peer == FIND_PEER) ?
00955                             list->peerChannel : list->channel)) {
00956                 if (prev == NULL)
00957                     ssh->channelList = list->next;
00958                 else
00959                     prev->next = list->next;
00960                 ChannelDelete(list, ssh->ctx->heap);
00961                 ssh->channelListSz--;
00962 
00963                 break;
00964             }
00965             prev = list;
00966             list = list->next;
00967             listSz--;
00968         }
00969 
00970         if (listSz == 0)
00971             ret = WS_INVALID_CHANID;
00972     }
00973 
00974     WLOG(WS_LOG_DEBUG, "Leaving ChannelRemove(), ret = %d", ret);
00975     return ret;
00976 }
00977 
00978 
00979 int ChannelPutData(WOLFSSH_CHANNEL* channel, byte* data, word32 dataSz)
00980 {
00981     Buffer* inBuf;
00982 
00983     WLOG(WS_LOG_DEBUG, "Entering ChannelPutData()");
00984 
00985     if (channel == NULL || data == NULL)
00986         return WS_BAD_ARGUMENT;
00987 
00988     inBuf = &channel->inputBuffer;
00989 
00990     if (inBuf->length < inBuf->bufferSz &&
00991         inBuf->length + dataSz <= inBuf->bufferSz) {
00992 
00993         WMEMCPY(inBuf->buffer + inBuf->length, data, dataSz);
00994         inBuf->length += dataSz;
00995 
00996         WLOG(WS_LOG_INFO, "  dataSz = %u", dataSz);
00997         WLOG(WS_LOG_INFO, "  windowSz = %u", channel->windowSz);
00998         channel->windowSz -= dataSz;
00999         WLOG(WS_LOG_INFO, "  windowSz = %u", channel->windowSz);
01000     }
01001     else {
01002         return WS_RECV_OVERFLOW_E;
01003     }
01004 
01005     return WS_SUCCESS;
01006 }
01007 
01008 
01009 int BufferInit(Buffer* buffer, word32 size, void* heap)
01010 {
01011     if (buffer == NULL)
01012         return WS_BAD_ARGUMENT;
01013 
01014     if (size <= STATIC_BUFFER_LEN)
01015         size = STATIC_BUFFER_LEN;
01016 
01017     WMEMSET(buffer, 0, sizeof(Buffer));
01018     buffer->heap = heap;
01019     buffer->bufferSz = size;
01020     if (size > STATIC_BUFFER_LEN) {
01021         buffer->buffer = (byte*)WMALLOC(size, heap, DYNTYPE_BUFFER);
01022         if (buffer->buffer == NULL)
01023             return WS_MEMORY_E;
01024         buffer->dynamicFlag = 1;
01025     }
01026     else
01027         buffer->buffer = buffer->staticBuffer;
01028 
01029     return WS_SUCCESS;
01030 }
01031 
01032 
01033 int GrowBuffer(Buffer* buf, word32 sz, word32 usedSz)
01034 {
01035 #if 0
01036     WLOG(WS_LOG_DEBUG, "GB: buf = %p", buf);
01037     WLOG(WS_LOG_DEBUG, "GB: sz = %d", sz);
01038     WLOG(WS_LOG_DEBUG, "GB: usedSz = %d", usedSz);
01039 #endif
01040     /* New buffer will end up being sz+usedSz long
01041      * empty space at the head of the buffer will be compressed */
01042     if (buf != NULL) {
01043         word32 newSz = sz + usedSz;
01044         /*WLOG(WS_LOG_DEBUG, "GB: newSz = %d", newSz);*/
01045 
01046         if (newSz > buf->bufferSz) {
01047             byte* newBuffer = (byte*)WMALLOC(newSz,
01048                                                      buf->heap, DYNTYPE_BUFFER);
01049 
01050             if (newBuffer == NULL)
01051                 return WS_MEMORY_E;
01052 
01053             /*WLOG(WS_LOG_DEBUG, "GB: resizing buffer");*/
01054             if (buf->length > 0)
01055                 WMEMCPY(newBuffer, buf->buffer + buf->idx, usedSz);
01056 
01057             if (!buf->dynamicFlag)
01058                 buf->dynamicFlag = 1;
01059             else
01060                 WFREE(buf->buffer, buf->heap, DYNTYPE_BUFFER);
01061 
01062             buf->buffer = newBuffer;
01063             buf->bufferSz = newSz;
01064             buf->length = usedSz;
01065             buf->idx = 0;
01066         }
01067     }
01068 
01069     return WS_SUCCESS;
01070 }
01071 
01072 
01073 void ShrinkBuffer(Buffer* buf, int forcedFree)
01074 {
01075     WLOG(WS_LOG_DEBUG, "Entering ShrinkBuffer()");
01076 
01077     if (buf != NULL) {
01078         word32 usedSz = buf->length - buf->idx;
01079 
01080         WLOG(WS_LOG_DEBUG, "SB: usedSz = %u, forcedFree = %u",
01081              usedSz, forcedFree);
01082 
01083         if (!forcedFree && usedSz > STATIC_BUFFER_LEN)
01084             return;
01085 
01086         if (!forcedFree && usedSz) {
01087             WLOG(WS_LOG_DEBUG, "SB: shifting down");
01088             WMEMCPY(buf->staticBuffer, buf->buffer + buf->idx, usedSz);
01089         }
01090 
01091         if (buf->dynamicFlag) {
01092             WLOG(WS_LOG_DEBUG, "SB: releasing dynamic buffer");
01093             WFREE(buf->buffer, buf->heap, DYNTYPE_BUFFER);
01094         }
01095         buf->dynamicFlag = 0;
01096         buf->buffer = buf->staticBuffer;
01097         buf->bufferSz = STATIC_BUFFER_LEN;
01098         buf->length = forcedFree ? 0 : usedSz;
01099         buf->idx = 0;
01100     }
01101 
01102     WLOG(WS_LOG_DEBUG, "Leaving ShrinkBuffer()");
01103 }
01104 
01105 
01106 static int Receive(WOLFSSH* ssh, byte* buf, word32 sz)
01107 {
01108     int recvd;
01109 
01110     if (ssh->ctx->ioRecvCb == NULL) {
01111         WLOG(WS_LOG_DEBUG, "Your IO Recv callback is null, please set");
01112         return -1;
01113     }
01114 
01115 retry:
01116     recvd = ssh->ctx->ioRecvCb(ssh, buf, sz, ssh->ioReadCtx);
01117     WLOG(WS_LOG_DEBUG, "Receive: recvd = %d", recvd);
01118     if (recvd < 0)
01119         switch (recvd) {
01120             case WS_CBIO_ERR_GENERAL:        /* general/unknown error */
01121                 return -1;
01122 
01123             case WS_CBIO_ERR_WANT_READ:      /* want read, would block */
01124                 return WS_WANT_READ;
01125 
01126             case WS_CBIO_ERR_CONN_RST:       /* connection reset */
01127                 ssh->connReset = 1;
01128                 return -1;
01129 
01130             case WS_CBIO_ERR_ISR:            /* interrupt */
01131                 goto retry;
01132 
01133             case WS_CBIO_ERR_CONN_CLOSE:     /* peer closed connection */
01134                 ssh->isClosed = 1;
01135                 return -1;
01136 
01137             case WS_CBIO_ERR_TIMEOUT:
01138                 return -1;
01139 
01140             default:
01141                 return recvd;
01142         }
01143 
01144     return recvd;
01145 }
01146 
01147 
01148 static int GetInputText(WOLFSSH* ssh, byte** pEol)
01149 {
01150     int gotLine = 0;
01151     int inSz = 255;
01152     int in;
01153     char *eol;
01154 
01155     if (GrowBuffer(&ssh->inputBuffer, inSz, 0) < 0)
01156         return WS_MEMORY_E;
01157 
01158     do {
01159         in = Receive(ssh,
01160                      ssh->inputBuffer.buffer + ssh->inputBuffer.length, inSz);
01161 
01162         if (in == -1)
01163             return WS_SOCKET_ERROR_E;
01164 
01165         if (in == WS_WANT_READ)
01166             return WS_WANT_READ;
01167 
01168         if (in > inSz)
01169             return WS_RECV_OVERFLOW_E;
01170 
01171         ssh->inputBuffer.length += in;
01172         inSz -= in;
01173 
01174         eol = WSTRNSTR((const char*)ssh->inputBuffer.buffer, "\r\n",
01175                        ssh->inputBuffer.length);
01176 
01177         if (eol)
01178             gotLine = 1;
01179 
01180     } while (!gotLine && inSz);
01181 
01182     if (pEol)
01183         *pEol = (byte*)eol;
01184 
01185     return (gotLine ? WS_SUCCESS : WS_VERSION_E);
01186 }
01187 
01188 
01189 static int SendBuffered(WOLFSSH* ssh)
01190 {
01191     WLOG(WS_LOG_DEBUG, "Entering SendBuffered()");
01192 
01193     if (ssh->ctx->ioSendCb == NULL) {
01194         WLOG(WS_LOG_DEBUG, "Your IO Send callback is null, please set");
01195         return WS_SOCKET_ERROR_E;
01196     }
01197 
01198     while (ssh->outputBuffer.length > 0) {
01199         int sent = ssh->ctx->ioSendCb(ssh,
01200                                ssh->outputBuffer.buffer + ssh->outputBuffer.idx,
01201                                ssh->outputBuffer.length, ssh->ioReadCtx);
01202 
01203         if (sent < 0) {
01204             switch (sent) {
01205                 case WS_CBIO_ERR_WANT_WRITE:     /* want write, would block */
01206                     return WS_WANT_WRITE;
01207 
01208                 case WS_CBIO_ERR_CONN_RST:       /* connection reset */
01209                     ssh->connReset = 1;
01210                     break;
01211 
01212                 case WS_CBIO_ERR_CONN_CLOSE:     /* peer closed connection */
01213                     ssh->isClosed = 1;
01214                     break;
01215             }
01216             return WS_SOCKET_ERROR_E;
01217         }
01218 
01219         if ((word32)sent > ssh->outputBuffer.length) {
01220             WLOG(WS_LOG_DEBUG, "SendBuffered() out of bounds read");
01221             return WS_SEND_OOB_READ_E;
01222         }
01223 
01224         ssh->outputBuffer.idx += sent;
01225         ssh->outputBuffer.length -= sent;
01226     }
01227 
01228     ssh->outputBuffer.idx = 0;
01229 
01230     WLOG(WS_LOG_DEBUG, "SB: Shrinking output buffer");
01231     ShrinkBuffer(&ssh->outputBuffer, 0);
01232 
01233     HighwaterCheck(ssh, WOLFSSH_HWSIDE_TRANSMIT);
01234 
01235     return WS_SUCCESS;
01236 }
01237 
01238 
01239 static int GetInputData(WOLFSSH* ssh, word32 size)
01240 {
01241     int in;
01242     int inSz;
01243     int maxLength;
01244     int usedLength;
01245 
01246     /* check max input length */
01247     usedLength = ssh->inputBuffer.length - ssh->inputBuffer.idx;
01248     maxLength  = ssh->inputBuffer.bufferSz - usedLength;
01249     inSz       = (int)(size - usedLength);      /* from last partial read */
01250 #if 0
01251     WLOG(WS_LOG_DEBUG, "GID: size = %u", size);
01252     WLOG(WS_LOG_DEBUG, "GID: usedLength = %d", usedLength);
01253     WLOG(WS_LOG_DEBUG, "GID: maxLength = %d", maxLength);
01254     WLOG(WS_LOG_DEBUG, "GID: inSz = %d", inSz);
01255 #endif
01256     /*
01257      * usedLength - how much untouched data is in the buffer
01258      * maxLength - how much empty space is in the buffer
01259      * inSz - difference between requested data and empty space in the buffer
01260      *        how much more we need to allocate
01261      */
01262 
01263     if (inSz <= 0)
01264         return WS_SUCCESS;
01265 
01266     /*
01267      * If we need more space than there is left in the buffer grow buffer.
01268      * Growing the buffer also compresses empty space at the head of the
01269      * buffer and resets idx to 0.
01270      */
01271     if (inSz > maxLength) {
01272         if (GrowBuffer(&ssh->inputBuffer, size, usedLength) < 0)
01273             return WS_MEMORY_E;
01274     }
01275 
01276     /* Put buffer data at start if not there */
01277     /* Compress the buffer if needed, i.e. buffer idx is non-zero */
01278     if (usedLength > 0 && ssh->inputBuffer.idx != 0) {
01279         WMEMMOVE(ssh->inputBuffer.buffer,
01280                 ssh->inputBuffer.buffer + ssh->inputBuffer.idx,
01281                 usedLength);
01282     }
01283 
01284     /* remove processed data */
01285     ssh->inputBuffer.idx    = 0;
01286     ssh->inputBuffer.length = usedLength;
01287 
01288     /* read data from network */
01289     do {
01290         in = Receive(ssh,
01291                      ssh->inputBuffer.buffer + ssh->inputBuffer.length, inSz);
01292         if (in == -1) {
01293             //ESP_LOGE("WOLFSSH", "GetInputData: WS_SOCKET_ERROR_E");
01294             return WS_SOCKET_ERROR_E;
01295         }
01296 
01297         if (in == WS_WANT_READ) {
01298             //ESP_LOGE("WOLFSSH", "GetInputData: WS_WANT_READ");
01299             return WS_WANT_READ;
01300         }
01301 
01302         if (in > inSz) {
01303             //ESP_LOGE("WOLFSSH", "GetInputData: WS_RECV_OVERFLOW_E");
01304             return WS_RECV_OVERFLOW_E;
01305         }
01306 
01307         ssh->inputBuffer.length += in;
01308         inSz -= in;
01309 
01310     } while (ssh->inputBuffer.length < size);
01311 
01312     return 0;
01313 }
01314 
01315 
01316 static int GetBoolean(byte* v, byte* buf, word32 len, word32* idx)
01317 {
01318     int result = WS_BUFFER_E;
01319 
01320     if (*idx < len) {
01321         *v = buf[*idx];
01322         *idx += BOOLEAN_SZ;
01323         result = WS_SUCCESS;
01324     }
01325 
01326     return result;
01327 }
01328 
01329 void ato32(const byte* c, word32 * u32){}
01330 
01331 static int GetUint32(word32* v, byte* buf, word32 len, word32* idx)
01332 {
01333     int result = WS_BUFFER_E;
01334 
01335     if (*idx < len && *idx + UINT32_SZ <= len) {
01336         ato32(buf + *idx, v);
01337         *idx += UINT32_SZ;
01338         result = WS_SUCCESS;
01339     }
01340 
01341     return result;
01342 }
01343 
01344 
01345 /* Gets the size of the mpint, and puts the pointer to the start of
01346  * buf's number into *mpint. This function does not copy. */
01347 static int GetMpint(word32* mpintSz, byte** mpint,
01348                     byte* buf, word32 len, word32* idx)
01349 {
01350     int result;
01351 
01352     result = GetUint32(mpintSz, buf, len, idx);
01353 
01354     if (result == WS_SUCCESS) {
01355         result = WS_BUFFER_E;
01356 
01357         if (*idx < len && *idx + *mpintSz <= len) {
01358             *mpint = buf + *idx;
01359             *idx += *mpintSz;
01360             result = WS_SUCCESS;
01361         }
01362     }
01363 
01364     return result;
01365 }
01366 
01367 
01368 /* Gets the size of a string, copies it as much of it as will fit in
01369  * the provided buffer, and terminates it with a NULL. */
01370 static int GetString(char* s, word32* sSz,
01371                      byte* buf, word32 len, word32 *idx)
01372 {
01373     int result;
01374     word32 strSz;
01375 
01376     result = GetUint32(&strSz, buf, len, idx);
01377 
01378     if (result == WS_SUCCESS) {
01379         result = WS_BUFFER_E;
01380         if (*idx < len && *idx + strSz <= len) {
01381             *sSz = (strSz >= *sSz) ? *sSz : strSz;
01382             WMEMCPY(s, buf + *idx, *sSz);
01383             *idx += strSz;
01384             s[*sSz] = 0;
01385             result = WS_SUCCESS;
01386         }
01387     }
01388 
01389     return result;
01390 }
01391 
01392 
01393 static int GetNameList(byte* idList, word32* idListSz,
01394                        byte* buf, word32 len, word32* idx)
01395 {
01396     byte idListIdx;
01397     word32 nameListSz, nameListIdx;
01398     word32 begin;
01399     byte* name;
01400     word32 nameSz;
01401     int ret = WS_SUCCESS;
01402 
01403     WLOG(WS_LOG_DEBUG, "Entering GetNameList()");
01404 
01405     if (idList == NULL || idListSz == NULL ||
01406         buf == NULL || len == 0 || idx == NULL) {
01407 
01408         ret = WS_BAD_ARGUMENT;
01409     }
01410 
01411     /*
01412      * This iterates across a name list and finds names that end in either the
01413      * comma delimeter or with the end of the list.
01414      */
01415 
01416     if (ret == WS_SUCCESS) {
01417         begin = *idx;
01418         if (begin >= len || begin + 4 >= len)
01419             ret = WS_BUFFER_E;
01420     }
01421 
01422     if (ret == WS_SUCCESS)
01423         ret = GetUint32(&nameListSz, buf, len, &begin);
01424 
01425     /* The strings we want are now in the bounds of the message, and the
01426      * length of the list. Find the commas, or end of list, and then decode
01427      * the values. */
01428     if (ret == WS_SUCCESS) {
01429         name = buf + begin;
01430         nameSz = 0;
01431         nameListIdx = 0;
01432         idListIdx = 0;
01433 
01434         while (nameListIdx < nameListSz) {
01435             nameListIdx++;
01436 
01437             if (nameListIdx == nameListSz)
01438                 nameSz++;
01439 
01440             if (nameListIdx == nameListSz || name[nameSz] == ',') {
01441                 byte id;
01442 
01443                 id = NameToId((char*)name, nameSz);
01444                 {
01445                     const char* displayName = IdToName(id);
01446                     if (displayName) {
01447                         WLOG(WS_LOG_DEBUG, "DNL: name ID = %s", displayName);
01448                     }
01449                 }
01450                 if (id != ID_UNKNOWN)
01451                     idList[idListIdx++] = id;
01452 
01453                 name += 1 + nameSz;
01454                 nameSz = 0;
01455             }
01456             else
01457                 nameSz++;
01458         }
01459 
01460         begin += nameListSz;
01461         *idListSz = idListIdx;
01462         *idx = begin;
01463     }
01464 
01465     WLOG(WS_LOG_DEBUG, "Leaving GetNameList(), ret = %d", ret);
01466     return ret;
01467 }
01468 
01469 
01470 static const byte  cannedEncAlgo[] = {ID_AES128_GCM, ID_AES128_CBC};
01471 static const byte  cannedMacAlgo[] = {ID_HMAC_SHA2_256, ID_HMAC_SHA1_96,
01472                                          ID_HMAC_SHA1};
01473 static const byte  cannedKeyAlgoRsa[] = {ID_SSH_RSA};
01474 static const byte  cannedKeyAlgoEcc256[] = {ID_ECDSA_SHA2_NISTP256};
01475 static const byte  cannedKeyAlgoEcc384[] = {ID_ECDSA_SHA2_NISTP384};
01476 static const byte  cannedKeyAlgoEcc521[] = {ID_ECDSA_SHA2_NISTP521};
01477 static const byte  cannedKexAlgo[] = {ID_ECDH_SHA2_NISTP256,
01478                                          ID_DH_GEX_SHA256,
01479                                          ID_DH_GROUP14_SHA1,
01480                                          ID_DH_GROUP1_SHA1};
01481 
01482 static const word32 cannedEncAlgoSz = sizeof(cannedEncAlgo);
01483 static const word32 cannedMacAlgoSz = sizeof(cannedMacAlgo);
01484 static const word32 cannedKeyAlgoRsaSz = sizeof(cannedKeyAlgoRsa);
01485 static const word32 cannedKeyAlgoEcc256Sz = sizeof(cannedKeyAlgoEcc256);
01486 static const word32 cannedKeyAlgoEcc384Sz = sizeof(cannedKeyAlgoEcc384);
01487 static const word32 cannedKeyAlgoEcc521Sz = sizeof(cannedKeyAlgoEcc521);
01488 static const word32 cannedKexAlgoSz = sizeof(cannedKexAlgo);
01489 
01490 
01491 static byte MatchIdLists(const byte* left, word32 leftSz,
01492                          const byte* right, word32 rightSz)
01493 {
01494     word32 i, j;
01495 
01496     if (left != NULL && leftSz > 0 && right != NULL && rightSz > 0) {
01497         for (i = 0; i < leftSz; i++) {
01498             for (j = 0; j < rightSz; j++) {
01499                 if (left[i] == right[j]) {
01500 #if 0
01501                     WLOG(WS_LOG_DEBUG, "MID: matched %s", IdToName(left[i]));
01502 #endif
01503                     return left[i];
01504                 }
01505             }
01506         }
01507     }
01508 
01509     return ID_UNKNOWN;
01510 }
01511 
01512 
01513 static INLINE byte BlockSzForId(byte id)
01514 {
01515     switch (id) {
01516         case ID_AES128_CBC:
01517         case ID_AES128_GCM:
01518             return AES_BLOCK_SIZE;
01519         default:
01520             return 0;
01521     }
01522 }
01523 
01524 
01525 static INLINE byte MacSzForId(byte id)
01526 {
01527     switch (id) {
01528         case ID_HMAC_SHA1:
01529             return SHA_DIGEST_SIZE;
01530         case ID_HMAC_SHA1_96:
01531             return SHA1_96_SZ;
01532         case ID_HMAC_SHA2_256:
01533             return SHA256_DIGEST_SIZE;
01534         default:
01535             return 0;
01536     }
01537 }
01538 
01539 
01540 static INLINE byte KeySzForId(byte id)
01541 {
01542     switch (id) {
01543         case ID_HMAC_SHA1:
01544         case ID_HMAC_SHA1_96:
01545             return SHA_DIGEST_SIZE;
01546         case ID_HMAC_SHA2_256:
01547             return SHA256_DIGEST_SIZE;
01548         case ID_AES128_CBC:
01549         case ID_AES128_GCM:
01550             return AES_BLOCK_SIZE;
01551         default:
01552             return 0;
01553     }
01554 }
01555 
01556 
01557 static INLINE byte HashForId(byte id)
01558 {
01559     switch (id) {
01560         case ID_DH_GROUP1_SHA1:
01561         case ID_DH_GROUP14_SHA1:
01562         case ID_SSH_RSA:
01563             return WC_HASH_TYPE_SHA;
01564         case ID_DH_GEX_SHA256:
01565         case ID_ECDH_SHA2_NISTP256:
01566         case ID_ECDSA_SHA2_NISTP256:
01567             return WC_HASH_TYPE_SHA256;
01568         case ID_ECDH_SHA2_NISTP384:
01569         case ID_ECDSA_SHA2_NISTP384:
01570             return WC_HASH_TYPE_SHA384;
01571         case ID_ECDH_SHA2_NISTP521:
01572         case ID_ECDSA_SHA2_NISTP521:
01573             return WC_HASH_TYPE_SHA512;
01574         default:
01575             return WC_HASH_TYPE_NONE;
01576     }
01577 }
01578 
01579 
01580 static INLINE int wcPrimeForId(byte id)
01581 {
01582     switch (id) {
01583         case ID_ECDH_SHA2_NISTP256:
01584         case ID_ECDSA_SHA2_NISTP256:
01585             return ECC_SECP256R1;
01586         case ID_ECDH_SHA2_NISTP384:
01587         case ID_ECDSA_SHA2_NISTP384:
01588             return ECC_SECP384R1;
01589         case ID_ECDH_SHA2_NISTP521:
01590         case ID_ECDSA_SHA2_NISTP521:
01591             return ECC_SECP521R1;
01592         default:
01593             return ECC_CURVE_INVALID;
01594     }
01595 }
01596 static INLINE const char *PrimeNameForId(byte id)
01597 {
01598     switch (id) {
01599         case ID_ECDH_SHA2_NISTP256:
01600         case ID_ECDSA_SHA2_NISTP256:
01601             return "nistp256";
01602         case ID_ECDH_SHA2_NISTP384:
01603         case ID_ECDSA_SHA2_NISTP384:
01604             return "nistp384";
01605         case ID_ECDH_SHA2_NISTP521:
01606         case ID_ECDSA_SHA2_NISTP521:
01607             return "nistp521";
01608         default:
01609             return "unknown";
01610     }
01611 }
01612 
01613 
01614 static INLINE byte AeadModeForId(byte id)
01615 {
01616     return (id == ID_AES128_GCM);
01617 }
01618 
01619 
01620 static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
01621 {
01622     int ret = WS_SUCCESS;
01623     byte algoId;
01624     byte list[6];
01625     word32 listSz;
01626     word32 skipSz;
01627     word32 begin;
01628 
01629     WLOG(WS_LOG_DEBUG, "Entering DoKexInit()");
01630 
01631     if (ssh == NULL || buf == NULL || len == 0 || idx == NULL)
01632         ret = WS_BAD_ARGUMENT;
01633 
01634     /*
01635      * I don't need to save what the client sends here. I should decode
01636      * each list into a local array of IDs, and pick the one the peer is
01637      * using that's on my known list, or verify that the one the peer can
01638      * support the other direction is on my known list. All I need to do
01639      * is save the actual values.
01640      */
01641 
01642     if (ssh->handshake == NULL) {
01643         ssh->handshake = HandshakeInfoNew(ssh->ctx->heap);
01644         if (ssh->handshake == NULL) {
01645             WLOG(WS_LOG_DEBUG, "Couldn't allocate handshake info");
01646             ret = WS_MEMORY_E;
01647         }
01648     }
01649 
01650     if (ret == WS_SUCCESS) {
01651         begin = *idx;
01652 
01653         /* Check that the cookie exists inside the message */
01654         if (begin + COOKIE_SZ > len) {
01655             /* error, out of bounds */
01656             ret = WS_PARSE_E;
01657         }
01658         else {
01659             /* Move past the cookie. */
01660             begin += COOKIE_SZ;
01661         }
01662     }
01663 
01664     /* KEX Algorithms */
01665     if (ret == WS_SUCCESS) {
01666         WLOG(WS_LOG_DEBUG, "DKI: KEX Algorithms");
01667         listSz = 2;
01668         ret = GetNameList(list, &listSz, buf, len, &begin);
01669         if (ret == WS_SUCCESS) {
01670             algoId = MatchIdLists(list, listSz, cannedKexAlgo, cannedKexAlgoSz);
01671             if (algoId == ID_UNKNOWN) {
01672                 WLOG(WS_LOG_DEBUG, "Unable to negotiate KEX Algo");
01673                 ret = WS_INVALID_ALGO_ID;
01674             }
01675             else {
01676                 ssh->handshake->kexId = algoId;
01677                 ssh->handshake->hashId = HashForId(algoId);
01678             }
01679         }
01680     }
01681 
01682     /* Server Host Key Algorithms */
01683     if (ret == WS_SUCCESS) {
01684         WLOG(WS_LOG_DEBUG, "DKI: Server Host Key Algorithms");
01685         listSz = 1;
01686         ret = GetNameList(list, &listSz, buf, len, &begin);
01687         if (ret == WS_SUCCESS) {
01688             const byte *cannedKeyAlgo;
01689             word32 cannedKeyAlgoSz;
01690 
01691             switch (ssh->ctx->useEcc) {
01692                 case ECC_SECP256R1:
01693                     cannedKeyAlgo = cannedKeyAlgoEcc256;
01694                     cannedKeyAlgoSz = cannedKeyAlgoEcc256Sz;
01695                     break;
01696                 case ECC_SECP384R1:
01697                     cannedKeyAlgo = cannedKeyAlgoEcc384;
01698                     cannedKeyAlgoSz = cannedKeyAlgoEcc384Sz;
01699                     break;
01700                 case ECC_SECP521R1:
01701                     cannedKeyAlgo = cannedKeyAlgoEcc521;
01702                     cannedKeyAlgoSz = cannedKeyAlgoEcc521Sz;
01703                     break;
01704                 default:
01705                     cannedKeyAlgo = cannedKeyAlgoRsa;
01706                     cannedKeyAlgoSz = cannedKeyAlgoRsaSz;
01707             }
01708             algoId = MatchIdLists(list, listSz,
01709                                   cannedKeyAlgo, cannedKeyAlgoSz);
01710             if (algoId == ID_UNKNOWN) {
01711                 WLOG(WS_LOG_DEBUG, "Unable to negotiate Server Host Key Algo");
01712                 return WS_INVALID_ALGO_ID;
01713             }
01714             else
01715                 ssh->handshake->pubKeyId = algoId;
01716         }
01717     }
01718 
01719     /* Enc Algorithms - Client to Server */
01720     if (ret == WS_SUCCESS) {
01721         WLOG(WS_LOG_DEBUG, "DKI: Enc Algorithms - Client to Server");
01722         listSz = 3;
01723         ret = GetNameList(list, &listSz, buf, len, &begin);
01724         if (ret == WS_SUCCESS) {
01725             algoId = MatchIdLists(list, listSz, cannedEncAlgo, cannedEncAlgoSz);
01726             if (algoId == ID_UNKNOWN) {
01727                 WLOG(WS_LOG_DEBUG, "Unable to negotiate Encryption Algo C2S");
01728                 ret = WS_INVALID_ALGO_ID;
01729             }
01730         }
01731     }
01732 
01733     /* Enc Algorithms - Server to Client */
01734     if (ret == WS_SUCCESS) {
01735         WLOG(WS_LOG_DEBUG, "DKI: Enc Algorithms - Server to Client");
01736         listSz = 3;
01737         ret = GetNameList(list, &listSz, buf, len, &begin);
01738         if (MatchIdLists(list, listSz, &algoId, 1) == ID_UNKNOWN) {
01739             WLOG(WS_LOG_DEBUG, "Unable to negotiate Encryption Algo S2C");
01740             ret = WS_INVALID_ALGO_ID;
01741         }
01742         else {
01743             ssh->handshake->encryptId = algoId;
01744             ssh->handshake->aeadMode = AeadModeForId(algoId);
01745             ssh->handshake->blockSz = BlockSzForId(algoId);
01746             ssh->handshake->keys.encKeySz =
01747                 ssh->handshake->peerKeys.encKeySz =
01748                 KeySzForId(algoId);
01749             if (!ssh->handshake->aeadMode) {
01750                 ssh->handshake->keys.ivSz =
01751                     ssh->handshake->peerKeys.ivSz =
01752                     ssh->handshake->blockSz;
01753             }
01754             else {
01755                 ssh->handshake->keys.ivSz =
01756                     ssh->handshake->peerKeys.ivSz =
01757                     AEAD_NONCE_SZ;
01758                 ssh->handshake->macSz = ssh->handshake->blockSz;
01759             }
01760         }
01761     }
01762 
01763     /* MAC Algorithms - Client to Server */
01764     if (ret == WS_SUCCESS) {
01765         WLOG(WS_LOG_DEBUG, "DKI: MAC Algorithms - Client to Server");
01766         listSz = 2;
01767         ret = GetNameList(list, &listSz, buf, len, &begin);
01768         if (ret == WS_SUCCESS && !ssh->aeadMode) {
01769             algoId = MatchIdLists(list, listSz, cannedMacAlgo, cannedMacAlgoSz);
01770             if (algoId == ID_UNKNOWN) {
01771                 WLOG(WS_LOG_DEBUG, "Unable to negotiate MAC Algo C2S");
01772                 ret = WS_INVALID_ALGO_ID;
01773             }
01774         }
01775     }
01776 
01777     /* MAC Algorithms - Server to Client */
01778     if (ret == WS_SUCCESS) {
01779         WLOG(WS_LOG_DEBUG, "DKI: MAC Algorithms - Server to Client");
01780         listSz = 2;
01781         ret = GetNameList(list, &listSz, buf, len, &begin);
01782         if (ret == WS_SUCCESS && !ssh->handshake->aeadMode) {
01783             if (MatchIdLists(list, listSz, &algoId, 1) == ID_UNKNOWN) {
01784                 WLOG(WS_LOG_DEBUG, "Unable to negotiate MAC Algo S2C");
01785                 ret = WS_INVALID_ALGO_ID;
01786             }
01787             else {
01788                 ssh->handshake->macId = algoId;
01789                 ssh->handshake->macSz = MacSzForId(algoId);
01790                 ssh->handshake->keys.macKeySz =
01791                     ssh->handshake->peerKeys.macKeySz =
01792                     KeySzForId(algoId);
01793             }
01794         }
01795     }
01796 
01797     /* Compression Algorithms - Client to Server */
01798     if (ret == WS_SUCCESS) {
01799         /* The compression algorithm lists should have none as a value. */
01800         algoId = ID_NONE;
01801 
01802         WLOG(WS_LOG_DEBUG, "DKI: Compression Algorithms - Client to Server");
01803         listSz = 1;
01804         ret = GetNameList(list, &listSz, buf, len, &begin);
01805         if (ret == WS_SUCCESS) {
01806             if (MatchIdLists(list, listSz, &algoId, 1) == ID_UNKNOWN) {
01807                 WLOG(WS_LOG_DEBUG, "Unable to negotiate Compression Algo C2S");
01808                 ret = WS_INVALID_ALGO_ID;
01809             }
01810         }
01811     }
01812 
01813     /* Compression Algorithms - Server to Client */
01814     if (ret == WS_SUCCESS) {
01815         WLOG(WS_LOG_DEBUG, "DKI: Compression Algorithms - Server to Client");
01816         listSz = 1;
01817         ret = GetNameList(list, &listSz, buf, len, &begin);
01818         if (ret == WS_SUCCESS) {
01819             if (MatchIdLists(list, listSz, &algoId, 1) == ID_UNKNOWN) {
01820                 WLOG(WS_LOG_DEBUG, "Unable to negotiate Compression Algo S2C");
01821                 ret = WS_INVALID_ALGO_ID;
01822             }
01823         }
01824     }
01825 
01826     /* Languages - Client to Server, skip */
01827     if (ret == WS_SUCCESS) {
01828         WLOG(WS_LOG_DEBUG, "DKI: Languages - Client to Server");
01829         ret = GetUint32(&skipSz, buf, len, &begin);
01830         if (ret == WS_SUCCESS)
01831             begin += skipSz;
01832     }
01833 
01834     /* Languages - Server to Client, skip */
01835     if (ret == WS_SUCCESS) {
01836         WLOG(WS_LOG_DEBUG, "DKI: Languages - Server to Client");
01837         ret = GetUint32(&skipSz, buf, len, &begin);
01838         if (ret == WS_SUCCESS)
01839             begin += skipSz;
01840     }
01841 
01842     /* First KEX Packet Follows */
01843     if (ret == WS_SUCCESS) {
01844         WLOG(WS_LOG_DEBUG, "DKI: KEX Packet Follows");
01845         ret = GetBoolean(&ssh->handshake->kexPacketFollows, buf, len, &begin);
01846     }
01847 
01848     /* Skip the "for future use" length. */
01849     if (ret == WS_SUCCESS) {
01850         WLOG(WS_LOG_DEBUG, "DKI: For Future Use");
01851         ret = GetUint32(&skipSz, buf, len, &begin);
01852         if (ret == WS_SUCCESS)
01853             begin += skipSz;
01854     }
01855 
01856     if (ret == WS_SUCCESS) {
01857         byte scratchLen[LENGTH_SZ];
01858         word32 strSz;
01859 
01860         if (!ssh->isKeying) {
01861             WLOG(WS_LOG_DEBUG, "Keying initiated");
01862             ret = SendKexInit(ssh);
01863         }
01864 
01865         if (ret == WS_SUCCESS)
01866             ret = wc_HashInit(&ssh->handshake->hash, ssh->handshake->hashId);
01867 
01868         if (ret == WS_SUCCESS) {
01869             if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER)
01870                 ret = wc_HashUpdate(&ssh->handshake->hash,
01871                                     ssh->handshake->hashId,
01872                                     ssh->peerProtoId, ssh->peerProtoIdSz);
01873         }
01874 
01875         if (ret == WS_SUCCESS) {
01876             strSz = (word32)WSTRLEN(sshProtoIdStr) - SSH_PROTO_EOL_SZ;
01877             c32toa(strSz, scratchLen);
01878             ret = wc_HashUpdate(&ssh->handshake->hash, ssh->handshake->hashId,
01879                                 scratchLen, LENGTH_SZ);
01880         }
01881 
01882         if (ret == WS_SUCCESS)
01883             ret = wc_HashUpdate(&ssh->handshake->hash, ssh->handshake->hashId,
01884                                 (const byte*)sshProtoIdStr, strSz);
01885 
01886         if (ret == WS_SUCCESS) {
01887             if (ssh->ctx->side == WOLFSSH_ENDPOINT_CLIENT) {
01888                 ret = wc_HashUpdate(&ssh->handshake->hash,
01889                                     ssh->handshake->hashId,
01890                                     ssh->peerProtoId, ssh->peerProtoIdSz);
01891                 if (ret == WS_SUCCESS)
01892                     ret = wc_HashUpdate(&ssh->handshake->hash,
01893                                         ssh->handshake->hashId,
01894                                         ssh->handshake->kexInit,
01895                                         ssh->handshake->kexInitSz);
01896             }
01897         }
01898 
01899         if (ret == WS_SUCCESS) {
01900             c32toa(len + 1, scratchLen);
01901             ret = wc_HashUpdate(&ssh->handshake->hash, ssh->handshake->hashId,
01902                                 scratchLen, LENGTH_SZ);
01903         }
01904 
01905         if (ret == WS_SUCCESS) {
01906             scratchLen[0] = MSGID_KEXINIT;
01907             ret = wc_HashUpdate(&ssh->handshake->hash, ssh->handshake->hashId,
01908                                 scratchLen, MSG_ID_SZ);
01909         }
01910 
01911         if (ret == WS_SUCCESS)
01912             ret = wc_HashUpdate(&ssh->handshake->hash, ssh->handshake->hashId,
01913                                 buf, len);
01914 
01915         if (ret == WS_SUCCESS) {
01916             if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER)
01917                 ret = wc_HashUpdate(&ssh->handshake->hash,
01918                                     ssh->handshake->hashId,
01919                                     ssh->handshake->kexInit,
01920                                     ssh->handshake->kexInitSz);
01921         }
01922 
01923         if (ret == WS_SUCCESS) {
01924             *idx = begin;
01925             if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER)
01926                 ssh->clientState = CLIENT_KEXINIT_DONE;
01927             else
01928                 ssh->serverState = SERVER_KEXINIT_DONE;
01929         }
01930     }
01931 
01932     WLOG(WS_LOG_DEBUG, "Leaving DoKexInit(), ret = %d", ret);
01933     return ret;
01934 }
01935 
01936 
01937 static const byte dhGenerator[] = { 2 };
01938 static const byte dhPrimeGroup1[] = {
01939     /* SSH DH Group 1 (Oakley Group 2, 1024-bit MODP Group, RFC 2409) */
01940     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
01941     0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
01942     0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
01943     0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
01944     0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
01945     0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
01946     0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
01947     0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
01948     0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
01949     0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
01950     0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
01951     0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
01952     0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
01953     0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
01954     0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
01955     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
01956 };
01957 static const byte dhPrimeGroup14[] = {
01958     /* SSH DH Group 14 (Oakley Group 14, 2048-bit MODP Group, RFC 3526) */
01959     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
01960     0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
01961     0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
01962     0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
01963     0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
01964     0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
01965     0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
01966     0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
01967     0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
01968     0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
01969     0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
01970     0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
01971     0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
01972     0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
01973     0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
01974     0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
01975     0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
01976     0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
01977     0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
01978     0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
01979     0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
01980     0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
01981     0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
01982     0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
01983     0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
01984     0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
01985     0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
01986     0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
01987     0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
01988     0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
01989     0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
01990     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
01991 };
01992 
01993 static const word32 dhGeneratorSz = sizeof(dhGenerator);
01994 static const word32 dhPrimeGroup1Sz = sizeof(dhPrimeGroup1);
01995 static const word32 dhPrimeGroup14Sz = sizeof(dhPrimeGroup14);
01996 
01997 
01998 static int DoKexDhInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
01999 {
02000     /* First get the length of the MP_INT, and then add in the hash of the
02001      * mp_int value of e as it appears in the packet. After that, decode e
02002      * into an mp_int struct for the DH calculation by wolfCrypt.
02003      *
02004      * This function also works as MSGID_KEXECDH_INIT (30). That message
02005      * has the same format as MSGID_KEXDH_INIT, except it is the ECDH Q value
02006      * in the message isn't of the DH e value. Treat the Q as e. */
02007     /* DYNTYPE_DH */
02008 
02009     byte* e;
02010     word32 eSz;
02011     word32 begin;
02012     int ret = WS_SUCCESS;
02013 
02014     if (ssh == NULL || buf == NULL || len == 0 || idx == NULL)
02015         ret = WS_BAD_ARGUMENT;
02016 
02017     if (ret == WS_SUCCESS) {
02018         begin = *idx;
02019         ret = GetUint32(&eSz, buf, len, &begin);
02020     }
02021 
02022     if (ret == WS_SUCCESS) {
02023         e = buf + begin;
02024         begin += eSz;
02025 
02026         if (eSz <= sizeof(ssh->handshake->e)) {
02027             WMEMCPY(ssh->handshake->e, e, eSz);
02028             ssh->handshake->eSz = eSz;
02029         }
02030 
02031         ssh->clientState = CLIENT_KEXDH_INIT_DONE;
02032         *idx = begin;
02033 
02034         //ESP_LOGI("WOLFSSH", "Sending KexDH Reply to client");
02035         ret = SendKexDhReply(ssh);
02036     }
02037 
02038     return ret;
02039 }
02040 
02041 
02042 static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
02043 {
02044     byte* pubKey;
02045     word32 pubKeySz;
02046     byte* f;
02047     word32 fSz;
02048     byte* sig;
02049     word32 sigSz;
02050     word32 scratch;
02051     byte  scratchLen[LENGTH_SZ];
02052     word32 kPad = 0;
02053     struct {
02054         byte useRsa;
02055         word32 keySz;
02056         union {
02057             struct {
02058                 RsaKey   key;
02059             } rsa;
02060             struct {
02061                 ecc_key key;
02062             } ecc;
02063         } sk;
02064     } sigKeyBlock;
02065     word32 begin;
02066     int ret = WS_SUCCESS;
02067 
02068     WLOG(WS_LOG_DEBUG, "Entering DoKexDhReply()");
02069 
02070     if (ssh == NULL || buf == NULL || len == 0 || idx == NULL)
02071         ret = WS_BAD_ARGUMENT;
02072 
02073     if (ret == WS_SUCCESS) {
02074         begin = *idx;
02075         pubKey = buf + begin;
02076         ret = GetUint32(&pubKeySz, buf, len, &begin);
02077     }
02078 
02079     if (ret == WS_SUCCESS)
02080         ret = wc_HashUpdate(&ssh->handshake->hash,
02081                             ssh->handshake->hashId,
02082                             pubKey, pubKeySz + LENGTH_SZ);
02083 
02084     if (ret == WS_SUCCESS) {
02085         pubKey = buf + begin;
02086         begin += pubKeySz;
02087     }
02088 
02089     /* If using DH-GEX include the GEX specific values. */
02090     if (ssh->handshake->kexId == ID_DH_GEX_SHA256) {
02091         byte primeGroupPad = 0, generatorPad = 0;
02092 
02093         /* Hash in the client's requested minimum key size. */
02094         if (ret == 0) {
02095             c32toa(ssh->handshake->dhGexMinSz, scratchLen);
02096             ret = wc_HashUpdate(&ssh->handshake->hash,
02097                                 ssh->handshake->hashId,
02098                                 scratchLen, LENGTH_SZ);
02099         }
02100         /* Hash in the client's requested preferred key size. */
02101         if (ret == 0) {
02102             c32toa(ssh->handshake->dhGexPreferredSz, scratchLen);
02103             ret = wc_HashUpdate(&ssh->handshake->hash,
02104                                 ssh->handshake->hashId,
02105                                 scratchLen, LENGTH_SZ);
02106         }
02107         /* Hash in the client's requested maximum key size. */
02108         if (ret == 0) {
02109             c32toa(ssh->handshake->dhGexMaxSz, scratchLen);
02110             ret = wc_HashUpdate(&ssh->handshake->hash,
02111                                 ssh->handshake->hashId,
02112                                 scratchLen, LENGTH_SZ);
02113         }
02114         /* Add a pad byte if the mpint has the MSB set. */
02115         if (ret == 0) {
02116             if (ssh->handshake->primeGroup[0] & 0x80)
02117                 primeGroupPad = 1;
02118 
02119             /* Hash in the length of the GEX prime group. */
02120             c32toa(ssh->handshake->primeGroupSz + primeGroupPad,
02121                    scratchLen);
02122             ret = wc_HashUpdate(&ssh->handshake->hash,
02123                                 ssh->handshake->hashId,
02124                                 scratchLen, LENGTH_SZ);
02125         }
02126         /* Hash in the pad byte for the GEX prime group. */
02127         if (ret == 0) {
02128             if (primeGroupPad) {
02129                 scratchLen[0] = 0;
02130                 ret = wc_HashUpdate(&ssh->handshake->hash,
02131                                     ssh->handshake->hashId,
02132                                     scratchLen, 1);
02133             }
02134         }
02135         /* Hash in the GEX prime group. */
02136         if (ret == 0)
02137             ret  = wc_HashUpdate(&ssh->handshake->hash,
02138                                  ssh->handshake->hashId,
02139                                  ssh->handshake->primeGroup,
02140                                  ssh->handshake->primeGroupSz);
02141         /* Add a pad byte if the mpint has the MSB set. */
02142         if (ret == 0) {
02143             if (ssh->handshake->generator[0] & 0x80)
02144                 generatorPad = 1;
02145 
02146             /* Hash in the length of the GEX generator. */
02147             c32toa(ssh->handshake->generatorSz + generatorPad, scratchLen);
02148             ret = wc_HashUpdate(&ssh->handshake->hash,
02149                                 ssh->handshake->hashId,
02150                                 scratchLen, LENGTH_SZ);
02151         }
02152         /* Hash in the pad byte for the GEX generator. */
02153         if (ret == 0) {
02154             if (generatorPad) {
02155                 scratchLen[0] = 0;
02156                 ret = wc_HashUpdate(&ssh->handshake->hash,
02157                                     ssh->handshake->hashId,
02158                                     scratchLen, 1);
02159             }
02160         }
02161         /* Hash in the GEX generator. */
02162         if (ret == 0)
02163             ret = wc_HashUpdate(&ssh->handshake->hash,
02164                                 ssh->handshake->hashId,
02165                                 ssh->handshake->generator,
02166                                 ssh->handshake->generatorSz);
02167     }
02168 
02169     /* Hash in the size of the client's DH e-value (ECDH Q-value). */
02170     if (ret == 0) {
02171         c32toa(ssh->handshake->eSz, scratchLen);
02172         ret = wc_HashUpdate(&ssh->handshake->hash, ssh->handshake->hashId,
02173                             scratchLen, LENGTH_SZ);
02174     }
02175     /* Hash in the client's DH e-value (ECDH Q-value). */
02176     if (ret == 0)
02177         ret = wc_HashUpdate(&ssh->handshake->hash, ssh->handshake->hashId,
02178                             ssh->handshake->e, ssh->handshake->eSz);
02179 
02180     /* Get and hash in the server's DH f-value (ECDH Q-value) */
02181     if (ret == WS_SUCCESS) {
02182         f = buf + begin;
02183         ret = GetUint32(&fSz, buf, len, &begin);
02184     }
02185 
02186     if (ret == WS_SUCCESS)
02187         ret = wc_HashUpdate(&ssh->handshake->hash,
02188                             ssh->handshake->hashId,
02189                             f, fSz + LENGTH_SZ);
02190 
02191     if (ret == WS_SUCCESS) {
02192         f = buf + begin;
02193         begin += fSz;
02194         ret = GetUint32(&sigSz, buf, len, &begin);
02195     }
02196 
02197     if (ret == WS_SUCCESS) {
02198         sig = buf + begin;
02199         begin += sigSz;
02200         *idx = begin;
02201 
02202         /* Load in the server's public signing key */
02203         sigKeyBlock.useRsa = ssh->handshake->pubKeyId == ID_SSH_RSA;
02204 
02205         if (sigKeyBlock.useRsa) {
02206             byte* e;
02207             word32 eSz;
02208             byte* n;
02209             word32 nSz;
02210             word32 pubKeyIdx = 0;
02211 
02212             ret = wc_InitRsaKey(&sigKeyBlock.sk.rsa.key, ssh->ctx->heap);
02213             if (ret != 0)
02214                 ret = WS_RSA_E;
02215             if (ret == 0)
02216                 ret = GetUint32(&scratch, pubKey, pubKeySz, &pubKeyIdx);
02217             /* This is the algo name. */
02218             if (ret == WS_SUCCESS) {
02219                 pubKeyIdx += scratch;
02220                 ret = GetUint32(&eSz, pubKey, pubKeySz, &pubKeyIdx);
02221             }
02222             if (ret == WS_SUCCESS) {
02223                 e = pubKey + pubKeyIdx;
02224                 pubKeyIdx += eSz;
02225                 ret = GetUint32(&nSz, pubKey, pubKeySz, &pubKeyIdx);
02226             }
02227             if (ret == WS_SUCCESS) {
02228                 n = pubKey + pubKeyIdx;
02229                 ret = wc_RsaPublicKeyDecodeRaw(n, nSz, e, eSz,
02230                                                &sigKeyBlock.sk.rsa.key);
02231             }
02232 
02233             if (ret == 0)
02234                 sigKeyBlock.keySz = sizeof(sigKeyBlock.sk.rsa.key);
02235             else
02236                 ret = WS_RSA_E;
02237         }
02238         else {
02239             ret = wc_ecc_init_ex(&sigKeyBlock.sk.ecc.key, ssh->ctx->heap,
02240                                  INVALID_DEVID);
02241             if (ret == 0)
02242                 ret = wc_ecc_import_x963(pubKey, pubKeySz,
02243                                          &sigKeyBlock.sk.ecc.key);
02244             if (ret == 0)
02245                 sigKeyBlock.keySz = sizeof(sigKeyBlock.sk.ecc.key);
02246             else
02247                 ret = WS_ECC_E;
02248         }
02249 
02250         /* Generate and hash in the shared secret */
02251         if (ret == 0) {
02252             if (!ssh->handshake->useEcc) {
02253                 ret = wc_DhAgree(&ssh->handshake->privKey.dh,
02254                                  ssh->k, &ssh->kSz,
02255                                  ssh->handshake->x, ssh->handshake->xSz,
02256                                  f, fSz);
02257                 ForceZero(ssh->handshake->x, ssh->handshake->xSz);
02258                 wc_FreeDhKey(&ssh->handshake->privKey.dh);
02259             }
02260             else {
02261                 ecc_key key;
02262                 ret = wc_ecc_init(&key);
02263                 if (ret == 0)
02264                     ret = wc_ecc_import_x963(f, fSz, &key);
02265                 if (ret == 0)
02266                     ret = wc_ecc_shared_secret(&ssh->handshake->privKey.ecc,
02267                                                &key, ssh->k, &ssh->kSz);
02268                 wc_ecc_free(&key);
02269                 wc_ecc_free(&ssh->handshake->privKey.ecc);
02270             }
02271         }
02272 
02273         /* Hash in the shared secret K. */
02274         if (ret == 0) {
02275             kPad = (ssh->k[0] & 0x80) ? 1 : 0;
02276             c32toa(ssh->kSz + kPad, scratchLen);
02277             ret = wc_HashUpdate(&ssh->handshake->hash, ssh->handshake->hashId,
02278                                 scratchLen, LENGTH_SZ);
02279         }
02280         if (ret == 0) {
02281             if (kPad) {
02282                 scratchLen[0] = 0;
02283                 ret = wc_HashUpdate(&ssh->handshake->hash,
02284                                     ssh->handshake->hashId, scratchLen, 1);
02285             }
02286         }
02287         if (ret == 0)
02288             ret = wc_HashUpdate(&ssh->handshake->hash, ssh->handshake->hashId,
02289                                 ssh->k, ssh->kSz);
02290 
02291         /* Save the exchange hash value H, and session ID. */
02292         if (ret == 0)
02293             ret = wc_HashFinal(&ssh->handshake->hash,
02294                                ssh->handshake->hashId, ssh->h);
02295         if (ret == 0) {
02296             ssh->hSz = wc_HashGetDigestSize(ssh->handshake->hashId);
02297             if (ssh->sessionIdSz == 0) {
02298                 WMEMCPY(ssh->sessionId, ssh->h, ssh->hSz);
02299                 ssh->sessionIdSz = ssh->hSz;
02300             }
02301         }
02302 
02303         if (ret != WS_SUCCESS)
02304             ret = WS_CRYPTO_FAILED;
02305     }
02306 
02307     /* Verify h with the server's public key. */
02308     if (ret == WS_SUCCESS) {
02309         /* Skip past the sig name. Check it, though. Other SSH implementations
02310          * do the verify based on the name, despite what was agreed upon. XXX*/
02311         begin = 0;
02312         ret = GetUint32(&scratch, sig, sigSz, &begin);
02313         if (ret == WS_SUCCESS) {
02314             begin += scratch;
02315             ret = GetUint32(&scratch, sig, sigSz, &begin);
02316         }
02317         if (ret == WS_SUCCESS) {
02318             sig = sig + begin;
02319             sigSz = scratch;
02320 
02321             ret = wc_SignatureVerify(HashForId(ssh->handshake->pubKeyId),
02322                                      sigKeyBlock.useRsa ?
02323                                       WC_SIGNATURE_TYPE_RSA_W_ENC :
02324                                       WC_SIGNATURE_TYPE_ECC,
02325                                      ssh->h, ssh->hSz, sig, sigSz,
02326                                      &sigKeyBlock.sk, sigKeyBlock.keySz);
02327             if (ret != 0) {
02328                 WLOG(WS_LOG_DEBUG,
02329                      "DoKexDhReply: Signature Verify fail (%d)", ret);
02330                 ret = sigKeyBlock.useRsa ? WS_RSA_E : WS_ECC_E;
02331             }
02332         }
02333     }
02334 
02335     if (sigKeyBlock.useRsa)
02336         wc_FreeRsaKey(&sigKeyBlock.sk.rsa.key);
02337     else
02338         wc_ecc_free(&sigKeyBlock.sk.ecc.key);
02339 
02340     if (ret == WS_SUCCESS)
02341         ret = GenerateKeys(ssh);
02342 
02343     if (ret == WS_SUCCESS)
02344         ret = SendNewKeys(ssh);
02345 
02346     WLOG(WS_LOG_DEBUG, "Leaving DoKexDhReply(), ret = %d", ret);
02347     return ret;
02348 }
02349 
02350 
02351 static int DoNewKeys(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
02352 {
02353     int ret = WS_SUCCESS;
02354 
02355     (void)buf;
02356     (void)len;
02357     (void)idx;
02358 
02359     if (ssh == NULL)
02360         ret = WS_BAD_ARGUMENT;
02361 
02362     if (ret == WS_SUCCESS) {
02363         ssh->peerEncryptId = ssh->handshake->encryptId;
02364         ssh->peerMacId = ssh->handshake->macId;
02365         ssh->peerBlockSz = ssh->handshake->blockSz;
02366         ssh->peerMacSz = ssh->handshake->macSz;
02367         ssh->peerAeadMode = ssh->handshake->aeadMode;
02368         WMEMCPY(&ssh->peerKeys, &ssh->handshake->peerKeys, sizeof(Keys));
02369 
02370         switch (ssh->peerEncryptId) {
02371             case ID_NONE:
02372                 WLOG(WS_LOG_DEBUG, "DNK: peer using cipher none");
02373                 //ESP_LOGI("WOLFSSH", "DNK: peer using cipher none");
02374                 break;
02375 
02376             case ID_AES128_CBC:
02377                 WLOG(WS_LOG_DEBUG, "DNK: peer using cipher aes128-cbc");
02378                 ret = wc_AesSetKey(&ssh->decryptCipher.aes,
02379                                    ssh->peerKeys.encKey, ssh->peerKeys.encKeySz,
02380                                    ssh->peerKeys.iv, AES_DECRYPTION);
02381                 //ESP_LOGI("WOLFSSH", "DNK: peer using cipher aes128-cbc");
02382                 break;
02383 
02384             case ID_AES128_GCM:
02385                 WLOG(WS_LOG_DEBUG, "DNK: peer using cipher aes128-gcm");
02386                 ret = wc_AesGcmSetKey(&ssh->decryptCipher.aes,
02387                                       ssh->peerKeys.encKey,
02388                                       ssh->peerKeys.encKeySz);
02389                 //ESP_LOGI("WOLFSSH", "DNK: peer using cipher aes128-gcm");
02390                 break;
02391 
02392             default:
02393                 WLOG(WS_LOG_DEBUG, "DNK: peer using cipher invalid");
02394                 //ESP_LOGI("WOLFSSH", "DNK: peer using cipher invalid");
02395                 break;
02396         }
02397 
02398         if (ret == 0)
02399             ret = WS_SUCCESS;
02400         else
02401             ret = WS_CRYPTO_FAILED;
02402     }
02403 
02404     if (ret == WS_SUCCESS) {
02405         ssh->rxCount = 0;
02406         ssh->highwaterFlag = 0;
02407         ssh->isKeying = 0;
02408         HandshakeInfoFree(ssh->handshake, ssh->ctx->heap);
02409         ssh->handshake = NULL;
02410         WLOG(WS_LOG_DEBUG, "Keying completed");
02411         //ESP_LOGI("WOLFSSH", "Keying completed");
02412     }
02413 
02414     return ret;
02415 }
02416 
02417 
02418 static int DoKexDhGexRequest(WOLFSSH* ssh,
02419                              byte* buf, word32 len, word32* idx)
02420 {
02421     word32 begin;
02422     int ret = WS_SUCCESS;
02423 
02424     if (ssh == NULL || buf == NULL || len == 0 || idx == NULL)
02425         ret = WS_BAD_ARGUMENT;
02426 
02427     if (ret == WS_SUCCESS) {
02428         begin = *idx;
02429         ret = GetUint32(&ssh->handshake->dhGexMinSz, buf, len, &begin);
02430     }
02431 
02432     if (ret == WS_SUCCESS) {
02433         ret = GetUint32(&ssh->handshake->dhGexPreferredSz, buf, len, &begin);
02434     }
02435 
02436     if (ret == WS_SUCCESS) {
02437         ret = GetUint32(&ssh->handshake->dhGexMaxSz, buf, len, &begin);
02438     }
02439 
02440     if (ret == WS_SUCCESS) {
02441         WLOG(WS_LOG_INFO, "  min = %u, preferred = %u, max = %u",
02442                 ssh->handshake->dhGexMinSz,
02443                 ssh->handshake->dhGexPreferredSz,
02444                 ssh->handshake->dhGexMaxSz);
02445         *idx = begin;
02446         ret = SendKexDhGexGroup(ssh);
02447     }
02448 
02449     return ret;
02450 }
02451 
02452 
02453 static int DoKexDhGexGroup(WOLFSSH* ssh,
02454                            byte* buf, word32 len, word32* idx)
02455 {
02456     byte* primeGroup = NULL;
02457     word32 primeGroupSz;
02458     byte* generator = NULL;
02459     word32 generatorSz;
02460     word32 begin;
02461     int ret = WS_UNIMPLEMENTED_E;
02462 
02463     if (ssh == NULL || buf == NULL || len == 0 || idx == NULL)
02464         ret = WS_BAD_ARGUMENT;
02465 
02466     if (ret == WS_SUCCESS) {
02467         begin = *idx;
02468         ret = GetMpint(&primeGroupSz, &primeGroup, buf, len, &begin);
02469     }
02470 
02471     if (ret == WS_SUCCESS)
02472         ret = GetMpint(&generatorSz, &generator, buf, len, &begin);
02473 
02474     if (ret == WS_SUCCESS) {
02475         ssh->handshake->primeGroup =
02476             (byte*)WMALLOC(primeGroupSz + UINT32_SZ,
02477                            ssh->ctx->heap, DYNTYPE_MPINT);
02478         if (ssh->handshake->primeGroup == NULL)
02479             ret = WS_MEMORY_E;
02480     }
02481 
02482     if (ret == WS_SUCCESS) {
02483         ssh->handshake->generator =
02484             (byte*)WMALLOC(generatorSz + UINT32_SZ,
02485                            ssh->ctx->heap, DYNTYPE_MPINT);
02486         if (ssh->handshake->generator == NULL) {
02487             ret = WS_MEMORY_E;
02488             WFREE(ssh->handshake->primeGroup, ssh->ctx->heap, DYNTYPE_MPINT);
02489             ssh->handshake->primeGroup = NULL;
02490         }
02491     }
02492 
02493     if (WS_SUCCESS) {
02494         c32toa(primeGroupSz, ssh->handshake->primeGroup);
02495         WMEMCPY(ssh->handshake->primeGroup + UINT32_SZ,
02496                 primeGroup, primeGroupSz);
02497         ssh->handshake->primeGroupSz = primeGroupSz;
02498         c32toa(generatorSz, ssh->handshake->generator);
02499         WMEMCPY(ssh->handshake->generator + UINT32_SZ,
02500                 generator, generatorSz);
02501         ssh->handshake->generatorSz = generatorSz;
02502 
02503         *idx = begin;
02504         ret = SendKexDhInit(ssh);
02505     }
02506 
02507     return ret;
02508 }
02509 
02510 
02511 static int DoIgnore(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
02512 {
02513     word32 dataSz;
02514     word32 begin = *idx;
02515 
02516     (void)ssh;
02517     (void)len;
02518 
02519     ato32(buf + begin, &dataSz);
02520     begin += LENGTH_SZ + dataSz;
02521 
02522     *idx = begin;
02523 
02524     return WS_SUCCESS;
02525 }
02526 
02527 
02528 static int DoDebug(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
02529 {
02530     byte  alwaysDisplay;
02531     char*    msg = NULL;
02532     char*    lang = NULL;
02533     word32 strSz;
02534     word32 begin = *idx;
02535 
02536     (void)ssh;
02537     (void)len;
02538 
02539     alwaysDisplay = buf[begin++];
02540 
02541     ato32(buf + begin, &strSz);
02542     begin += LENGTH_SZ;
02543     if (strSz > 0) {
02544         msg = (char*)WMALLOC(strSz + 1, ssh->ctx->heap, DYNTYPE_STRING);
02545         if (msg != NULL) {
02546             WMEMCPY(msg, buf + begin, strSz);
02547             msg[strSz] = 0;
02548         }
02549         else {
02550             return WS_MEMORY_E;
02551         }
02552         begin += strSz;
02553     }
02554 
02555     ato32(buf + begin, &strSz);
02556     begin += LENGTH_SZ;
02557     if (strSz > 0) {
02558         lang = (char*)WMALLOC(strSz + 1, ssh->ctx->heap, DYNTYPE_STRING);
02559         if (lang != NULL) {
02560             WMEMCPY(lang, buf + begin, strSz);
02561             lang[strSz] = 0;
02562         }
02563         else {
02564             WFREE(msg, ssh->ctx->heap, DYNTYPE_STRING);
02565             return WS_MEMORY_E;
02566         }
02567         begin += strSz;
02568     }
02569 
02570     if (alwaysDisplay) {
02571         WLOG(WS_LOG_DEBUG, "DEBUG MSG (%s): %s",
02572              (lang == NULL) ? "none" : lang,
02573              (msg == NULL) ? "no message" : msg);
02574     }
02575 
02576     *idx = begin;
02577 
02578     WFREE(msg, ssh->ctx->heap, DYNTYPE_STRING);
02579     WFREE(lang, ssh->ctx->heap, DYNTYPE_STRING);
02580 
02581     return WS_SUCCESS;
02582 }
02583 
02584 
02585 static int DoUnimplemented(WOLFSSH* ssh,
02586                            byte* buf, word32 len, word32* idx)
02587 {
02588     word32 seq;
02589     word32 begin = *idx;
02590 
02591     (void)ssh;
02592     (void)len;
02593 
02594     ato32(buf + begin, &seq);
02595     begin += UINT32_SZ;
02596 
02597     WLOG(WS_LOG_DEBUG, "UNIMPLEMENTED: seq %u", seq);
02598 
02599     *idx = begin;
02600 
02601     return WS_SUCCESS;
02602 }
02603 
02604 
02605 static int DoDisconnect(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
02606 {
02607     word32 reason;
02608     const char* reasonStr;
02609     word32 begin = *idx;
02610 
02611     (void)ssh;
02612     (void)len;
02613     (void)reasonStr;
02614 
02615     ato32(buf + begin, &reason);
02616     begin += UINT32_SZ;
02617 
02618 #ifdef NO_WOLFSSH_STRINGS
02619     WLOG(WS_LOG_DEBUG, "DISCONNECT: (%u)", reason);
02620 #elif defined(DEBUG_WOLFSSH)
02621     switch (reason) {
02622         case WOLFSSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT:
02623             reasonStr = "host not allowed to connect"; break;
02624         case WOLFSSH_DISCONNECT_PROTOCOL_ERROR:
02625             reasonStr = "protocol error"; break;
02626         case WOLFSSH_DISCONNECT_KEY_EXCHANGE_FAILED:
02627             reasonStr = "key exchange failed"; break;
02628         case WOLFSSH_DISCONNECT_RESERVED:
02629             reasonStr = "reserved"; break;
02630         case WOLFSSH_DISCONNECT_MAC_ERROR:
02631             reasonStr = "mac error"; break;
02632         case WOLFSSH_DISCONNECT_COMPRESSION_ERROR:
02633             reasonStr = "compression error"; break;
02634         case WOLFSSH_DISCONNECT_SERVICE_NOT_AVAILABLE:
02635             reasonStr = "service not available"; break;
02636         case WOLFSSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED:
02637             reasonStr = "protocol version not supported"; break;
02638         case WOLFSSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE:
02639             reasonStr = "host key not verifiable"; break;
02640         case WOLFSSH_DISCONNECT_CONNECTION_LOST:
02641             reasonStr = "connection lost"; break;
02642         case WOLFSSH_DISCONNECT_BY_APPLICATION:
02643             reasonStr = "disconnect by application"; break;
02644         case WOLFSSH_DISCONNECT_TOO_MANY_CONNECTIONS:
02645             reasonStr = "too many connections"; break;
02646         case WOLFSSH_DISCONNECT_AUTH_CANCELLED_BY_USER:
02647             reasonStr = "auth cancelled by user"; break;
02648         case WOLFSSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE:
02649             reasonStr = "no more auth methods available"; break;
02650         case WOLFSSH_DISCONNECT_ILLEGAL_USER_NAME:
02651             reasonStr = "illegal user name"; break;
02652         default:
02653             reasonStr = "unknown reason";
02654     }
02655     WLOG(WS_LOG_DEBUG, "DISCONNECT: (%u) %s", reason, reasonStr);
02656 #endif
02657 
02658     *idx = begin;
02659 
02660     return WS_SUCCESS;
02661 }
02662 
02663 
02664 static int DoServiceRequest(WOLFSSH* ssh,
02665                             byte* buf, word32 len, word32* idx)
02666 {
02667     word32 begin = *idx;
02668     word32 nameSz;
02669     char     serviceName[32];
02670 
02671     (void)len;
02672 
02673     ato32(buf + begin, &nameSz);
02674     begin += LENGTH_SZ;
02675 
02676     WMEMCPY(serviceName, buf + begin, nameSz);
02677     begin += nameSz;
02678     serviceName[nameSz] = 0;
02679 
02680     *idx = begin;
02681 
02682     WLOG(WS_LOG_DEBUG, "Requesting service: %s", serviceName);
02683     ssh->clientState = CLIENT_USERAUTH_REQUEST_DONE;
02684 
02685     return WS_SUCCESS;
02686 }
02687 
02688 
02689 static int DoServiceAccept(WOLFSSH* ssh,
02690                            byte* buf, word32 len, word32* idx)
02691 {
02692     word32 begin = *idx;
02693     word32 nameSz;
02694     char     serviceName[32];
02695 
02696     (void)len;
02697 
02698     ato32(buf + begin, &nameSz);
02699     begin += LENGTH_SZ;
02700 
02701     WMEMCPY(serviceName, buf + begin, nameSz);
02702     begin += nameSz;
02703     serviceName[nameSz] = 0;
02704 
02705     *idx = begin;
02706 
02707     WLOG(WS_LOG_DEBUG, "Accepted service: %s", serviceName);
02708     ssh->serverState = SERVER_USERAUTH_REQUEST_DONE;
02709 
02710     return WS_SUCCESS;
02711 }
02712 
02713 
02714 /* Utility for DoUserAuthRequest() */
02715 static int DoUserAuthRequestPassword(WOLFSSH* ssh, WS_UserAuthData* authData,
02716                                      byte* buf, word32 len, word32* idx)
02717 {
02718     word32 begin;
02719     WS_UserAuthData_Password* pw;
02720     int ret = WS_SUCCESS;
02721 
02722     WLOG(WS_LOG_DEBUG, "Entering DoUserAuthRequestPassword()");
02723 
02724     if (ssh == NULL || authData == NULL ||
02725         buf == NULL || len == 0 || idx == NULL) {
02726 
02727         ret = WS_BAD_ARGUMENT;
02728     }
02729 
02730     if (ret == WS_SUCCESS) {
02731         begin = *idx;
02732         pw = &authData->sf.password;
02733         authData->type = WOLFSSH_USERAUTH_PASSWORD;
02734         ret = GetBoolean(&pw->hasNewPassword, buf, len, &begin);
02735     }
02736 
02737     if (ret == WS_SUCCESS)
02738         ret = GetUint32(&pw->passwordSz, buf, len, &begin);
02739 
02740     if (ret == WS_SUCCESS) {
02741         pw->password = buf + begin;
02742         begin += pw->passwordSz;
02743 
02744         if (pw->hasNewPassword) {
02745             /* Skip the password change. Maybe error out since we aren't
02746              * supporting password changes at this time. */
02747             ret = GetUint32(&pw->newPasswordSz, buf, len, &begin);
02748             if (ret == WS_SUCCESS) {
02749                 pw->newPassword = buf + begin;
02750                 begin += pw->newPasswordSz;
02751             }
02752         }
02753         else {
02754             pw->newPassword = NULL;
02755             pw->newPasswordSz = 0;
02756         }
02757 
02758         if (ssh->ctx->userAuthCb != NULL) {
02759             WLOG(WS_LOG_DEBUG, "DUARPW: Calling the userauth callback");
02760             ret = ssh->ctx->userAuthCb(WOLFSSH_USERAUTH_PASSWORD,
02761                                        authData, ssh->userAuthCtx);
02762             if (ret == WOLFSSH_USERAUTH_SUCCESS) {
02763                 WLOG(WS_LOG_DEBUG, "DUARPW: password check successful");
02764                 ssh->clientState = CLIENT_USERAUTH_DONE;
02765                 ret = WS_SUCCESS;
02766             }
02767             else {
02768                 WLOG(WS_LOG_DEBUG, "DUARPW: password check failed");
02769                 ret = SendUserAuthFailure(ssh, 0);
02770             }
02771         }
02772         else {
02773             WLOG(WS_LOG_DEBUG, "DUARPW: No user auth callback");
02774             ret = SendUserAuthFailure(ssh, 0);
02775         }
02776     }
02777 
02778     if (ret == WS_SUCCESS)
02779         *idx = begin;
02780 
02781     WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthRequestPassword(), ret = %d", ret);
02782     return ret;
02783 }
02784 
02785 int ConstantCompare(byte encDigest[], byte checkDigest[],
02786                                   word32 encDigestSz){
02787                                     return 0;
02788                                     }
02789                                   
02790 
02791 /* Utility for DoUserAuthRequestPublicKey() */
02792 /* returns negative for error, positive is size of digest. */
02793 static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk,
02794                                 byte hashId, byte* digest, word32 digestSz)
02795 {
02796     RsaKey key;
02797     byte checkDigest[MAX_ENCODED_SIG_SZ];
02798     int checkDigestSz;
02799     byte* publicKeyType;
02800     word32 publicKeyTypeSz = 0;
02801     byte* n;
02802     word32 nSz = 0;
02803     byte* e;
02804     word32 eSz = 0;
02805     word32 i = 0;
02806     int ret = WS_SUCCESS;
02807 
02808     WLOG(WS_LOG_DEBUG, "Entering DoUserAuthRequestRsa()");
02809 
02810     if (ssh == NULL || pk == NULL || digest == NULL || digestSz == 0)
02811         ret = WS_BAD_ARGUMENT;
02812 
02813     /* First check that the public key's type matches the one we are
02814      * expecting. */
02815     if (ret == WS_SUCCESS)
02816         ret = GetUint32(&publicKeyTypeSz, pk->publicKey, pk->publicKeySz, &i);
02817 
02818     if (ret == WS_SUCCESS) {
02819         publicKeyType = pk->publicKey + i;
02820         i += publicKeyTypeSz;
02821         if (publicKeyTypeSz != pk->publicKeyTypeSz &&
02822             WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) {
02823 
02824             WLOG(WS_LOG_DEBUG,
02825                 "Public Key's type does not match public key type");
02826             ret = WS_INVALID_ALGO_ID;
02827         }
02828     }
02829 
02830     if (ret == WS_SUCCESS)
02831         ret = GetUint32(&eSz, pk->publicKey, pk->publicKeySz, &i);
02832 
02833     if (ret == WS_SUCCESS) {
02834         e = pk->publicKey + i;
02835         i += eSz;
02836         ret = GetUint32(&nSz, pk->publicKey, pk->publicKeySz, &i);
02837     }
02838 
02839     if (ret == WS_SUCCESS) {
02840         n = pk->publicKey + i;
02841 
02842         ret = wc_InitRsaKey(&key, ssh->ctx->heap);
02843         if (ret == 0)
02844             ret = wc_RsaPublicKeyDecodeRaw(n, nSz, e, eSz, &key);
02845         if (ret != 0) {
02846             WLOG(WS_LOG_DEBUG, "Could not decode public key");
02847             ret = WS_CRYPTO_FAILED;
02848         }
02849     }
02850 
02851     if (ret == WS_SUCCESS) {
02852         i = 0;
02853         /* First check that the signature's public key type matches the one
02854          * we are expecting. */
02855         ret = GetUint32(&publicKeyTypeSz, pk->publicKey, pk->publicKeySz, &i);
02856     }
02857 
02858     if (ret == WS_SUCCESS) {
02859         publicKeyType = pk->publicKey + i;
02860         i += publicKeyTypeSz;
02861 
02862         if (publicKeyTypeSz != pk->publicKeyTypeSz &&
02863             WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) {
02864 
02865             WLOG(WS_LOG_DEBUG,
02866                  "Signature's type does not match public key type");
02867             ret = WS_INVALID_ALGO_ID;
02868         }
02869     }
02870 
02871     if (ret == WS_SUCCESS)
02872         ret = GetUint32(&nSz, pk->signature, pk->signatureSz, &i);
02873 
02874     if (ret == WS_SUCCESS) {
02875         n = pk->signature + i;
02876         checkDigestSz = wc_RsaSSL_Verify(n, nSz, checkDigest,
02877                                          sizeof(checkDigest), &key);
02878         if (checkDigestSz <= 0) {
02879             WLOG(WS_LOG_DEBUG, "Could not verify signature");
02880             ret = WS_CRYPTO_FAILED;
02881         }
02882     }
02883 
02884     if (ret == WS_SUCCESS) {
02885         byte encDigest[MAX_ENCODED_SIG_SZ];
02886         word32 encDigestSz;
02887         volatile int compare;
02888         volatile int sizeCompare;
02889 
02890         encDigestSz = wc_EncodeSignature(encDigest, digest,
02891                                          wc_HashGetDigestSize(hashId),
02892                                          wc_HashGetOID(hashId));
02893 
02894         compare = ConstantCompare(encDigest, checkDigest,
02895                                   encDigestSz);
02896         sizeCompare = encDigestSz != (word32)checkDigestSz;
02897 
02898         if ((compare | sizeCompare) == 0)
02899             ret = WS_SUCCESS;
02900         else
02901             ret = WS_RSA_E;
02902     }
02903 
02904     wc_FreeRsaKey(&key);
02905 
02906     WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthRequestRsa(), ret = %d", ret);
02907     return ret;
02908 }
02909 
02910 
02911 /* Utility for DoUserAuthRequestPublicKey() */
02912 /* returns negative for error, positive is size of digest. */
02913 static int DoUserAuthRequestEcc(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk,
02914                                 byte hashId, byte* digest, word32 digestSz)
02915 {
02916     ecc_key key;
02917     byte* publicKeyType;
02918     word32 publicKeyTypeSz = 0;
02919     byte* curveName;
02920     word32 curveNameSz = 0;
02921     mp_int r, s;
02922     byte* q;
02923     word32 sz, qSz;
02924     word32 i = 0;
02925     int ret = WS_SUCCESS;
02926 
02927     (void)hashId;
02928 
02929     WLOG(WS_LOG_DEBUG, "Entering DoUserAuthRequestRsa()");
02930 
02931     if (ssh == NULL || pk == NULL || digest == NULL || digestSz == 0)
02932         ret = WS_BAD_ARGUMENT;
02933 
02934     /* First check that the public key's type matches the one we are
02935      * expecting. */
02936     if (ret == WS_SUCCESS)
02937         ret = GetUint32(&publicKeyTypeSz, pk->publicKey, pk->publicKeySz, &i);
02938 
02939     if (ret == WS_SUCCESS) {
02940         publicKeyType = pk->publicKey + i;
02941         i += publicKeyTypeSz;
02942         if (publicKeyTypeSz != pk->publicKeyTypeSz &&
02943             WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) {
02944 
02945             WLOG(WS_LOG_DEBUG,
02946                 "Public Key's type does not match public key type");
02947             ret = WS_INVALID_ALGO_ID;
02948         }
02949     }
02950 
02951     if (ret == WS_SUCCESS)
02952         ret = GetUint32(&curveNameSz, pk->publicKey, pk->publicKeySz, &i);
02953 
02954     if (ret == WS_SUCCESS) {
02955         curveName = pk->publicKey + i;
02956         (void)curveName; /* Not used at the moment, hush the compiler. */
02957         i += curveNameSz;
02958         ret = GetUint32(&qSz, pk->publicKey, pk->publicKeySz, &i);
02959     }
02960 
02961     if (ret == WS_SUCCESS) {
02962         q = pk->publicKey + i;
02963         i += qSz;
02964         ret = wc_ecc_init_ex(&key, ssh->ctx->heap, INVALID_DEVID);
02965     }
02966 
02967     if (ret == 0)
02968         ret = wc_ecc_import_x963(q, qSz, &key);
02969 
02970     if (ret != 0) {
02971         WLOG(WS_LOG_DEBUG, "Could not decode public key");
02972         ret = WS_CRYPTO_FAILED;
02973     }
02974 
02975     if (ret == WS_SUCCESS) {
02976         i = 0;
02977         /* First check that the signature's public key type matches the one
02978          * we are expecting. */
02979         ret = GetUint32(&publicKeyTypeSz, pk->signature, pk->signatureSz, &i);
02980     }
02981 
02982     if (ret == WS_SUCCESS) {
02983         publicKeyType = pk->signature + i;
02984         i += publicKeyTypeSz;
02985 
02986         if (publicKeyTypeSz != pk->publicKeyTypeSz &&
02987             WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) {
02988 
02989             WLOG(WS_LOG_DEBUG,
02990                  "Signature's type does not match public key type");
02991             ret = WS_INVALID_ALGO_ID;
02992         }
02993     }
02994 
02995     if (ret == WS_SUCCESS) {
02996         /* Get the size of the signature blob. */
02997         ret = GetUint32(&sz, pk->signature, pk->signatureSz, &i);
02998     }
02999 
03000     if (ret == WS_SUCCESS) {
03001         /* Get R and S. */
03002         ret = GetUint32(&sz, pk->signature, pk->signatureSz, &i);
03003     }
03004 
03005     if (ret == WS_SUCCESS) {
03006         ret = mp_read_unsigned_bin(&r, pk->signature + i, sz);
03007         if (ret != 0)
03008             ret = WS_PARSE_E;
03009         else
03010             ret = WS_SUCCESS;
03011     }
03012 
03013     if (ret == WS_SUCCESS) {
03014         i += sz;
03015         ret = GetUint32(&sz, pk->signature, pk->signatureSz, &i);
03016     }
03017 
03018     if (ret == WS_SUCCESS) {
03019         ret = mp_read_unsigned_bin(&s, pk->signature + i, sz);
03020         if (ret != 0)
03021             ret = WS_PARSE_E;
03022         else
03023             ret = WS_SUCCESS;
03024     }
03025 
03026     if (ret == WS_SUCCESS) {
03027         int status = 0;
03028 
03029         ret = wc_ecc_verify_hash_ex(&r, &s, digest, digestSz, &status, &key);
03030         if (ret != 0) {
03031             WLOG(WS_LOG_DEBUG, "Could not verify signature");
03032             ret = WS_CRYPTO_FAILED;
03033         }
03034         else
03035             ret = status ? WS_SUCCESS : WS_ECC_E;
03036     }
03037 
03038     mp_clear(&r);
03039     mp_clear(&s);
03040     wc_ecc_free(&key);
03041 
03042     WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthRequestEcc(), ret = %d", ret);
03043     return ret;
03044 }
03045 
03046 
03047 /* Utility for DoUserAuthRequest() */
03048 static int DoUserAuthRequestPublicKey(WOLFSSH* ssh, WS_UserAuthData* authData,
03049                                       byte* buf, word32 len, word32* idx)
03050 {
03051     word32 begin;
03052     WS_UserAuthData_PublicKey* pk;
03053     int ret = WS_SUCCESS;
03054     int authFailure = 0;
03055 
03056     WLOG(WS_LOG_DEBUG, "Entering DoUserAuthRequestPublicKey()");
03057 
03058     if (ssh == NULL || authData == NULL ||
03059         buf == NULL || len == 0 || idx == NULL) {
03060 
03061         ret = WS_BAD_ARGUMENT;
03062     }
03063 
03064     if (ret == WS_SUCCESS) {
03065         begin = *idx;
03066         pk = &authData->sf.publicKey;
03067         authData->type = WOLFSSH_USERAUTH_PUBLICKEY;
03068         ret = GetBoolean(&pk->hasSignature, buf, len, &begin);
03069     }
03070 
03071     if (ret == WS_SUCCESS)
03072         ret = GetUint32(&pk->publicKeyTypeSz, buf, len, &begin);
03073 
03074     if (ret == WS_SUCCESS) {
03075         pk->publicKeyType = buf + begin;
03076         begin += pk->publicKeyTypeSz;
03077         ret = GetUint32(&pk->publicKeySz, buf, len, &begin);
03078     }
03079 
03080     if (ret == WS_SUCCESS) {
03081         pk->publicKey = buf + begin;
03082         begin += pk->publicKeySz;
03083 
03084         if (pk->hasSignature) {
03085             ret = GetUint32(&pk->signatureSz, buf, len, &begin);
03086             if (ret == WS_SUCCESS) {
03087                 pk->signature = buf + begin;
03088                 begin += pk->signatureSz;
03089             }
03090         }
03091         else {
03092             pk->signature = NULL;
03093             pk->signatureSz = 0;
03094         }
03095 
03096         if (ret == WS_SUCCESS) {
03097             *idx = begin;
03098 
03099             if (ssh->ctx->userAuthCb != NULL) {
03100                 WLOG(WS_LOG_DEBUG, "DUARPK: Calling the userauth callback");
03101                 ret = ssh->ctx->userAuthCb(WOLFSSH_USERAUTH_PUBLICKEY,
03102                                            authData, ssh->userAuthCtx);
03103                 WLOG(WS_LOG_DEBUG, "DUARPK: callback result = %d", ret);
03104                 if (ret == WOLFSSH_USERAUTH_SUCCESS)
03105                     ret = WS_SUCCESS;
03106                 else {
03107                     ret = SendUserAuthFailure(ssh, 0);
03108                     authFailure = 1;
03109                 }
03110             }
03111             else {
03112                 WLOG(WS_LOG_DEBUG, "DUARPK: no userauth callback set");
03113                 ret = SendUserAuthFailure(ssh, 0);
03114                 authFailure = 1;
03115             }
03116         }
03117     }
03118 
03119     if (ret == WS_SUCCESS && !authFailure) {
03120         if (pk->signature == NULL) {
03121             WLOG(WS_LOG_DEBUG, "DUARPK: Send the PK OK");
03122             ret = SendUserAuthPkOk(ssh, pk->publicKeyType, pk->publicKeyTypeSz,
03123                                    pk->publicKey, pk->publicKeySz);
03124         }
03125         else {
03126             wc_HashAlg hash;
03127             byte digest[WC_MAX_DIGEST_SIZE];
03128             word32 digestSz;
03129             byte hashId = WC_HASH_TYPE_SHA;
03130             byte pkTypeId;
03131 
03132             pkTypeId = NameToId((char*)pk->publicKeyType,
03133                                 pk->publicKeyTypeSz);
03134             if (pkTypeId == ID_UNKNOWN)
03135                 ret = WS_INVALID_ALGO_ID;
03136 
03137             if (ret == WS_SUCCESS) {
03138                 hashId = HashForId(pkTypeId);
03139                 WMEMSET(digest, 0, sizeof(digest));
03140                 digestSz = wc_HashGetDigestSize(hashId);
03141                 ret = wc_HashInit(&hash, hashId);
03142             }
03143 
03144             if (ret == 0) {
03145                 c32toa(ssh->sessionIdSz, digest);
03146                 ret = wc_HashUpdate(&hash, hashId, digest, UINT32_SZ);
03147             }
03148 
03149             if (ret == 0)
03150                 ret = wc_HashUpdate(&hash, hashId,
03151                                     ssh->sessionId, ssh->sessionIdSz);
03152 
03153             if (ret == 0) {
03154                 digest[0] = MSGID_USERAUTH_REQUEST;
03155                 ret = wc_HashUpdate(&hash, hashId, digest, MSG_ID_SZ);
03156             }
03157 
03158             /* The rest of the fields in the signature are already
03159              * in the buffer. Just need to account for the sizes. */
03160             if (ret == 0)
03161                 ret = wc_HashUpdate(&hash, hashId, pk->dataToSign,
03162                                     authData->usernameSz +
03163                                     authData->serviceNameSz +
03164                                     authData->authNameSz + BOOLEAN_SZ +
03165                                     pk->publicKeyTypeSz + pk->publicKeySz +
03166                                     (UINT32_SZ * 5));
03167             if (ret == 0) {
03168                 ret = wc_HashFinal(&hash, hashId, digest);
03169 
03170                 if (ret != 0)
03171                     ret = WS_CRYPTO_FAILED;
03172                 else
03173                     ret = WS_SUCCESS;
03174             }
03175 
03176             if (ret == WS_SUCCESS) {
03177                 if (pkTypeId == ID_SSH_RSA)
03178                     ret = DoUserAuthRequestRsa(ssh, pk,
03179                                                hashId, digest, digestSz);
03180                 else if (pkTypeId == ID_ECDSA_SHA2_NISTP256 ||
03181                          pkTypeId == ID_ECDSA_SHA2_NISTP384 ||
03182                          pkTypeId == ID_ECDSA_SHA2_NISTP521)
03183                     ret = DoUserAuthRequestEcc(ssh, pk,
03184                                                hashId, digest, digestSz);
03185             }
03186 
03187             if (ret != WS_SUCCESS) {
03188                 WLOG(WS_LOG_DEBUG, "DUARPK: signature compare failure");
03189                 ret = SendUserAuthFailure(ssh, 0);
03190             }
03191             else {
03192                 ssh->clientState = CLIENT_USERAUTH_DONE;
03193             }
03194         }
03195     }
03196 
03197     WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthRequestPublicKey(), ret = %d", ret);
03198     return ret;
03199 }
03200 
03201 
03202 static int DoUserAuthRequest(WOLFSSH* ssh,
03203                              byte* buf, word32 len, word32* idx)
03204 {
03205     word32 begin;
03206     int ret = WS_SUCCESS;
03207     byte authNameId;
03208     WS_UserAuthData authData;
03209 
03210     WLOG(WS_LOG_DEBUG, "Entering DoUserAuthRequest()");
03211 
03212     if (ssh == NULL || buf == NULL || len == 0 || idx == NULL)
03213         ret = WS_BAD_ARGUMENT;
03214 
03215     if (ret == WS_SUCCESS) {
03216         begin = *idx;
03217         WMEMSET(&authData, 0, sizeof(authData));
03218         ret = GetUint32(&authData.usernameSz, buf, len, &begin);
03219     }
03220 
03221     if (ret == WS_SUCCESS) {
03222         authData.username = buf + begin;
03223         begin += authData.usernameSz;
03224 
03225         ret = GetUint32(&authData.serviceNameSz, buf, len, &begin);
03226     }
03227 
03228     if (ret == WS_SUCCESS) {
03229         authData.serviceName = buf + begin;
03230         begin += authData.serviceNameSz;
03231 
03232         ret = GetUint32(&authData.authNameSz, buf, len, &begin);
03233     }
03234 
03235     if (ret == WS_SUCCESS) {
03236         authData.authName = buf + begin;
03237         begin += authData.authNameSz;
03238         authNameId = NameToId((char*)authData.authName, authData.authNameSz);
03239 
03240         if (authNameId == ID_USERAUTH_PASSWORD)
03241             ret = DoUserAuthRequestPassword(ssh, &authData, buf, len, &begin);
03242         else if (authNameId == ID_USERAUTH_PUBLICKEY) {
03243             authData.sf.publicKey.dataToSign = buf + *idx;
03244             ret = DoUserAuthRequestPublicKey(ssh, &authData, buf, len, &begin);
03245         }
03246 #ifdef WOLFSSH_ALLOW_USERAUTH_NONE
03247         else if (authNameId == ID_NONE) {
03248             ssh->clientState = CLIENT_USERAUTH_DONE;
03249         }
03250 #endif
03251         else {
03252             WLOG(WS_LOG_DEBUG,
03253                  "invalid userauth type: %s", IdToName(authNameId));
03254             ret = SendUserAuthFailure(ssh, 0);
03255         }
03256 
03257         *idx = begin;
03258     }
03259 
03260     WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthRequest(), ret = %d", ret);
03261     return ret;
03262 }
03263 
03264 
03265 static int DoUserAuthFailure(WOLFSSH* ssh,
03266                              byte* buf, word32 len, word32* idx)
03267 {
03268     byte authList[3]; /* Should only ever be password, publickey, hostname */
03269     word32 authListSz;
03270     byte partialSuccess;
03271     byte authId = ID_USERAUTH_PASSWORD;
03272     int ret = WS_SUCCESS;
03273 
03274     WLOG(WS_LOG_DEBUG, "Entering DoUserAuthFailure()");
03275 
03276     if (ssh == NULL || buf == NULL || len == 0 || idx == NULL)
03277         ret = WS_BAD_ARGUMENT;
03278 
03279     if (ret == WS_SUCCESS)
03280         ret = GetNameList(authList, &authListSz, buf, len, idx);
03281 
03282     if (ret == WS_SUCCESS)
03283         ret = GetBoolean(&partialSuccess, buf, len, idx);
03284 
03285     if (ret == WS_SUCCESS)
03286         ret = SendUserAuthRequest(ssh, authId);
03287 
03288     WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthFailure(), ret = %d", ret);
03289     return ret;
03290 }
03291 
03292 
03293 static int DoUserAuthSuccess(WOLFSSH* ssh,
03294                              byte* buf, word32 len, word32* idx)
03295 {
03296     int ret = WS_SUCCESS;
03297 
03298     WLOG(WS_LOG_DEBUG, "Entering DoUserAuthSuccess()");
03299 
03300     /* This message does not have any payload. len should be 0. */
03301     if (ssh == NULL || buf == NULL || len != 0 || idx == NULL)
03302         ret = WS_BAD_ARGUMENT;
03303 
03304     ssh->serverState = SERVER_USERAUTH_ACCEPT_DONE;
03305 
03306     WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthSuccess(), ret = %d", ret);
03307     return ret;
03308 }
03309 
03310 
03311 static int DoUserAuthBanner(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
03312 {
03313     word32 begin;
03314     char banner[80];
03315     word32 bannerSz = sizeof(banner);
03316     int ret = WS_SUCCESS;
03317 
03318     WLOG(WS_LOG_DEBUG, "Entering DoUserAuthBanner()");
03319 
03320     if (ssh == NULL || buf == NULL || len == 0 || idx == NULL)
03321         ret = WS_BAD_ARGUMENT;
03322 
03323     if (ret == WS_SUCCESS) {
03324         begin = *idx;
03325         ret = GetString(banner, &bannerSz, buf, len, idx);
03326     }
03327 
03328     if (ret == WS_SUCCESS)
03329         ret = GetUint32(&bannerSz, buf, len, idx);
03330 
03331     if (ret == WS_SUCCESS) {
03332         begin += bannerSz;
03333         if (ssh->ctx->showBanner) {
03334             WLOG(WS_LOG_INFO, "%s", banner);
03335         }
03336     }
03337 
03338     WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthBanner(), ret = %d", ret);
03339     return ret;
03340 }
03341 
03342 
03343 static int DoGlobalRequest(WOLFSSH* ssh,
03344                            byte* buf, word32 len, word32* idx)
03345 {
03346     word32 begin;
03347     int ret = WS_SUCCESS;
03348     char name[80];
03349     word32 nameSz = sizeof(name);
03350     byte wantReply = 0;
03351 
03352     WLOG(WS_LOG_DEBUG, "Entering DoGlobalRequest()");
03353 
03354     if (ssh == NULL || buf == NULL || len == 0 || idx == NULL)
03355         ret = WS_BAD_ARGUMENT;
03356 
03357     if (ret == WS_SUCCESS) {
03358         begin = *idx;
03359         ret = GetString(name, &nameSz, buf, len, &begin);
03360     }
03361 
03362     if (ret == WS_SUCCESS) {
03363         WLOG(WS_LOG_DEBUG, "DGR: request name = %s", name);
03364         ret = GetBoolean(&wantReply, buf, len, &begin);
03365     }
03366 
03367     if (ret == WS_SUCCESS) {
03368         *idx += len;
03369 
03370         if (wantReply)
03371             ret = SendRequestSuccess(ssh, 0);
03372     }
03373 
03374     WLOG(WS_LOG_DEBUG, "Leaving DoGlobalRequest(), ret = %d", ret);
03375     return ret;
03376 }
03377 
03378 
03379 static int DoChannelOpen(WOLFSSH* ssh,
03380                          byte* buf, word32 len, word32* idx)
03381 {
03382     word32 begin = *idx;
03383     word32 typeSz;
03384     char type[32];
03385     byte typeId = ID_UNKNOWN;
03386     word32 peerChannelId;
03387     word32 peerInitialWindowSz;
03388     word32 peerMaxPacketSz;
03389     int ret;
03390     WOLFSSH_CHANNEL* newChannel;
03391 
03392     WLOG(WS_LOG_DEBUG, "Entering DoChannelOpen()");
03393     //ESP_LOGI("WOLFSSH", "Entering DoChannelOpen()");
03394 
03395     typeSz = sizeof(type);
03396     ret = GetString(type, &typeSz, buf, len, &begin);
03397 
03398     if (ret == WS_SUCCESS)
03399         ret = GetUint32(&peerChannelId, buf, len, &begin);
03400 
03401     if (ret == WS_SUCCESS)
03402         ret = GetUint32(&peerInitialWindowSz, buf, len, &begin);
03403 
03404     if (ret == WS_SUCCESS)
03405         ret = GetUint32(&peerMaxPacketSz, buf, len, &begin);
03406 
03407     if (ret == WS_SUCCESS) {
03408         *idx = begin;
03409 
03410         WLOG(WS_LOG_INFO, "  type = %s", type);
03411         WLOG(WS_LOG_INFO, "  peerChannelId = %u", peerChannelId);
03412         WLOG(WS_LOG_INFO, "  peerInitialWindowSz = %u", peerInitialWindowSz);
03413         WLOG(WS_LOG_INFO, "  peerMaxPacketSz = %u", peerMaxPacketSz);
03414 
03415         //ESP_LOGI("WOLFSSH", "DoChannelOpen type = %s", type);
03416         //ESP_LOGI("WOLFSSH", "DoChannelOpen peerChId = %u", peerChannelId);
03417         //ESP_LOGI("WOLFSSH", "DoChannelOpen peerInitWndSz = %u", peerInitialWindowSz);
03418         //ESP_LOGI("WOLFSSH", "DoChannelOpen peerMaxPktSz = %u", peerMaxPacketSz);
03419 
03420         typeId = NameToId(type, typeSz);
03421         if (typeId != ID_CHANTYPE_SESSION)
03422             ret = WS_INVALID_CHANTYPE;
03423         //ESP_LOGI("WOLFSSH", "DoChannelOpen ret = %d", ret);
03424     }
03425 
03426     if (ret == WS_SUCCESS) {
03427         newChannel = ChannelNew(ssh, typeId,
03428                                 DEFAULT_WINDOW_SZ, DEFAULT_MAX_PACKET_SZ);
03429         //ESP_LOGI("WOLFSSH", "DoChannelOpen newCh = %p", newChannel);
03430         if (newChannel == NULL)
03431             ret = WS_RESOURCE_E;
03432         else {
03433             ChannelUpdate(newChannel, peerChannelId,
03434                           peerInitialWindowSz, peerMaxPacketSz);
03435             //ESP_LOGI("WOLFSSH", "DoChannelOpen ChUpdate");
03436             if (ssh->channelListSz == 0)
03437                 ssh->defaultPeerChannelId = peerChannelId;
03438             ChannelAppend(ssh, newChannel);
03439 
03440             ssh->clientState = CLIENT_DONE;
03441         }
03442     }
03443 
03444     WLOG(WS_LOG_DEBUG, "Leaving DoChannelOpen(), ret = %d", ret);
03445     //ESP_LOGI("WOLFSSH", "Leaving DoChannelOpen(), ret = %d", ret);
03446     return ret;
03447 }
03448 
03449 
03450 static int DoChannelOpenConf(WOLFSSH* ssh,
03451                              byte* buf, word32 len, word32* idx)
03452 {
03453     WOLFSSH_CHANNEL* channel;
03454     word32 begin, channelId, peerChannelId,
03455            peerInitialWindowSz, peerMaxPacketSz;
03456     int ret = WS_SUCCESS;
03457 
03458     WLOG(WS_LOG_DEBUG, "Entering DoChannelOpenConf()");
03459 
03460     if (ssh == NULL || buf == NULL || len == 0 || idx == NULL)
03461         ret = WS_BAD_ARGUMENT;
03462 
03463     if (ret == WS_SUCCESS) {
03464         begin = *idx;
03465         ret = GetUint32(&channelId, buf, len, &begin);
03466     }
03467 
03468     if (ret == WS_SUCCESS)
03469         ret = GetUint32(&peerChannelId, buf, len, &begin);
03470 
03471     if (ret == WS_SUCCESS)
03472         ret = GetUint32(&peerInitialWindowSz, buf, len, &begin);
03473 
03474     if (ret == WS_SUCCESS)
03475         ret = GetUint32(&peerMaxPacketSz, buf, len, &begin);
03476 
03477     if (ret == WS_SUCCESS) {
03478         WLOG(WS_LOG_INFO, "  channelId = %u", channelId);
03479         WLOG(WS_LOG_INFO, "  peerChannelId = %u", peerChannelId);
03480         WLOG(WS_LOG_INFO, "  peerInitialWindowSz = %u", peerInitialWindowSz);
03481         WLOG(WS_LOG_INFO, "  peerMaxPacketSz = %u", peerMaxPacketSz);
03482 
03483         channel = ChannelFind(ssh, channelId, FIND_SELF);
03484         if (channel == NULL)
03485             ret = WS_INVALID_CHANID;
03486     }
03487 
03488     if (ret == WS_SUCCESS)
03489         ret = ChannelUpdate(channel, peerChannelId,
03490                             peerInitialWindowSz, peerMaxPacketSz);
03491 
03492     if (ret == WS_SUCCESS)
03493         ssh->serverState = SERVER_CHANNEL_OPEN_DONE;
03494 
03495     WLOG(WS_LOG_DEBUG, "Leaving DoChannelOpenConf(), ret = %d", ret);
03496     return ret;
03497 }
03498 
03499 
03500 static int DoChannelOpenFail(WOLFSSH* ssh,
03501                              byte* buf, word32 len, word32* idx)
03502 {
03503     char desc[80];
03504     word32 begin, channelId, reasonId, descSz, langSz;
03505     int ret = WS_SUCCESS;
03506 
03507     WLOG(WS_LOG_DEBUG, "Entering DoChannelOpenFail()");
03508 
03509     if (ssh == NULL || buf == NULL || len == 0 || idx == NULL)
03510         ret = WS_BAD_ARGUMENT;
03511 
03512     if (ret == WS_SUCCESS) {
03513         begin = *idx;
03514         ret = GetUint32(&channelId, buf, len, &begin);
03515     }
03516 
03517     if (ret == WS_SUCCESS)
03518         ret = GetUint32(&reasonId, buf, len, &begin);
03519 
03520     if (ret == WS_SUCCESS) {
03521         descSz = sizeof(desc);
03522         ret = GetString(desc, &descSz, buf, len, &begin);
03523     }
03524 
03525     if (ret == WS_SUCCESS)
03526         ret = GetUint32(&langSz, buf, len, &begin);
03527 
03528     if (ret == WS_SUCCESS) {
03529         *idx = begin + langSz;
03530 
03531         WLOG(WS_LOG_INFO, "channel open failure reason code: %u", reasonId);
03532         if (descSz > 0) {
03533             WLOG(WS_LOG_INFO, "description: %s", desc);
03534         }
03535 
03536         ret = ChannelRemove(ssh, channelId, FIND_SELF);
03537     }
03538 
03539     if (ret == WS_SUCCESS)
03540         ret = WS_CHANOPEN_FAILED;
03541 
03542     WLOG(WS_LOG_DEBUG, "Leaving DoChannelOpenFail(), ret = %d", ret);
03543     return ret;
03544 }
03545 
03546 
03547 static int DoChannelClose(WOLFSSH* ssh,
03548                           byte* buf, word32 len, word32* idx)
03549 {
03550     WOLFSSH_CHANNEL* channel = NULL;
03551     word32 begin = *idx;
03552     word32 channelId;
03553     int ret;
03554 
03555     WLOG(WS_LOG_DEBUG, "Entering DoChannelClose()");
03556 
03557     ret = GetUint32(&channelId, buf, len, &begin);
03558 
03559     if (ret == WS_SUCCESS) {
03560         *idx = begin;
03561 
03562         channel = ChannelFind(ssh, channelId, FIND_SELF);
03563         if (channel == NULL)
03564             ret = WS_INVALID_CHANID;
03565     }
03566 
03567     if (ret == WS_SUCCESS)
03568         ret = SendChannelClose(ssh, channelId);
03569 
03570     if (ret == WS_SUCCESS)
03571         ret = ChannelRemove(ssh, channelId, FIND_SELF);
03572 
03573     if (ret == WS_SUCCESS)
03574         ret = WS_CHANNEL_CLOSED;
03575 
03576     WLOG(WS_LOG_DEBUG, "Leaving DoChannelClose(), ret = %d", ret);
03577     return ret;
03578 }
03579 
03580 
03581 static int DoChannelRequest(WOLFSSH* ssh,
03582                             byte* buf, word32 len, word32* idx)
03583 {
03584     word32 begin = *idx;
03585     word32 channelId;
03586     word32 typeSz;
03587     char type[32];
03588     byte wantReply;
03589     int ret;
03590 
03591     WLOG(WS_LOG_DEBUG, "Entering DoChannelRequest()");
03592 
03593     ret = GetUint32(&channelId, buf, len, &begin);
03594 
03595     typeSz = sizeof(type);
03596     if (ret == WS_SUCCESS)
03597         ret = GetString(type, &typeSz, buf, len, &begin);
03598 
03599     if (ret == WS_SUCCESS)
03600         ret = GetBoolean(&wantReply, buf, len, &begin);
03601 
03602     if (ret != WS_SUCCESS) {
03603         WLOG(WS_LOG_DEBUG, "Leaving DoChannelRequest(), ret = %d", ret);
03604         return ret;
03605     }
03606 
03607     if (ret == WS_SUCCESS) {
03608         WLOG(WS_LOG_DEBUG, "  channelId = %u", channelId);
03609         WLOG(WS_LOG_DEBUG, "  type = %s", type);
03610         WLOG(WS_LOG_DEBUG, "  wantReply = %u", wantReply);
03611 
03612         if (WSTRNCMP(type, "pty-req", typeSz) == 0) {
03613             char term[32];
03614             word32 termSz;
03615             word32 widthChar, heightRows, widthPixels, heightPixels;
03616             word32 modesSz;
03617 
03618             termSz = sizeof(term);
03619             ret = GetString(term, &termSz, buf, len, &begin);
03620             if (ret == WS_SUCCESS)
03621                 ret = GetUint32(&widthChar, buf, len, &begin);
03622             if (ret == WS_SUCCESS)
03623                 ret = GetUint32(&heightRows, buf, len, &begin);
03624             if (ret == WS_SUCCESS)
03625                 ret = GetUint32(&widthPixels, buf, len, &begin);
03626             if (ret == WS_SUCCESS)
03627                 ret = GetUint32(&heightPixels, buf, len, &begin);
03628             if (ret == WS_SUCCESS)
03629                 ret = GetUint32(&modesSz, buf, len, &begin);
03630 
03631             if (ret == WS_SUCCESS) {
03632                 WLOG(WS_LOG_DEBUG, "  term = %s", term);
03633                 WLOG(WS_LOG_DEBUG, "  widthChar = %u", widthChar);
03634                 WLOG(WS_LOG_DEBUG, "  heightRows = %u", heightRows);
03635                 WLOG(WS_LOG_DEBUG, "  widthPixels = %u", widthPixels);
03636                 WLOG(WS_LOG_DEBUG, "  heightPixels = %u", heightPixels);
03637                 WLOG(WS_LOG_DEBUG, "  modes = %u", (modesSz - 1) / 5);
03638             }
03639         }
03640         else if (WSTRNCMP(type, "env", typeSz) == 0) {
03641             char name[32];
03642             word32 nameSz;
03643             char value[32];
03644             word32 valueSz;
03645 
03646             nameSz = sizeof(name);
03647             valueSz = sizeof(value);
03648             ret = GetString(name, &nameSz, buf, len, &begin);
03649             if (ret == WS_SUCCESS)
03650                 ret = GetString(value, &valueSz, buf, len, &begin);
03651 
03652             WLOG(WS_LOG_DEBUG, "  %s = %s", name, value);
03653         }
03654     }
03655 
03656     if (ret == WS_SUCCESS)
03657         *idx = len;
03658 
03659     if (wantReply) {
03660         int replyRet;
03661 
03662         replyRet = SendChannelSuccess(ssh, channelId, (ret == WS_SUCCESS));
03663         if (replyRet != WS_SUCCESS)
03664             ret = replyRet;
03665     }
03666 
03667     WLOG(WS_LOG_DEBUG, "Leaving DoChannelRequest(), ret = %d", ret);
03668     return ret;
03669 }
03670 
03671 
03672 static int DoChannelSuccess(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
03673 {
03674     int ret = WS_SUCCESS;
03675 
03676     WLOG(WS_LOG_DEBUG, "Entering DoChannelSuccess()");
03677 
03678     if (ssh == NULL || buf == NULL || len == 0 || idx == NULL)
03679         ret = WS_BAD_ARGUMENT;
03680 
03681     ssh->serverState = SERVER_DONE;
03682 
03683     WLOG(WS_LOG_DEBUG, "Leaving DoChannelSuccess(), ret = %d", ret);
03684     return ret;
03685 }
03686 
03687 
03688 static int DoChannelFailure(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
03689 {
03690     int ret = WS_SUCCESS;
03691 
03692     WLOG(WS_LOG_DEBUG, "Entering DoChannelFailure()");
03693 
03694     if (ssh == NULL || buf == NULL || len != 0 || idx == NULL)
03695         ret = WS_BAD_ARGUMENT;
03696 
03697     if (ret == WS_SUCCESS)
03698         ret = WS_CHANOPEN_FAILED;
03699     WLOG(WS_LOG_DEBUG, "Leaving DoChannelFailure(), ret = %d", ret);
03700     return ret;
03701 }
03702 
03703 
03704 static int DoChannelWindowAdjust(WOLFSSH* ssh,
03705                                  byte* buf, word32 len, word32* idx)
03706 {
03707     WOLFSSH_CHANNEL* channel = NULL;
03708     word32 begin = *idx;
03709     word32 channelId, bytesToAdd;
03710     int ret;
03711 
03712     WLOG(WS_LOG_DEBUG, "Entering DoChannelWindowAdjust()");
03713 
03714     ret = GetUint32(&channelId, buf, len, &begin);
03715     if (ret == WS_SUCCESS)
03716         ret = GetUint32(&bytesToAdd, buf, len, &begin);
03717 
03718     if (ret == WS_SUCCESS) {
03719         *idx = begin;
03720 
03721         channel = ChannelFind(ssh, channelId, FIND_SELF);
03722         if (channel == NULL)
03723             ret = WS_INVALID_CHANID;
03724         else {
03725             WLOG(WS_LOG_INFO, "  channelId = %u", channelId);
03726             WLOG(WS_LOG_INFO, "  bytesToAdd = %u", bytesToAdd);
03727             WLOG(WS_LOG_INFO, "  peerWindowSz = %u",
03728                  channel->peerWindowSz);
03729 
03730             channel->peerWindowSz += bytesToAdd;
03731 
03732             WLOG(WS_LOG_INFO, "  update peerWindowSz = %u",
03733                  channel->peerWindowSz);
03734 
03735         }
03736     }
03737 
03738     WLOG(WS_LOG_DEBUG, "Leaving DoChannelWindowAdjust(), ret = %d", ret);
03739     return ret;
03740 }
03741 
03742 
03743 static int DoChannelData(WOLFSSH* ssh,
03744                          byte* buf, word32 len, word32* idx)
03745 {
03746     WOLFSSH_CHANNEL* channel = NULL;
03747     word32 begin = *idx;
03748     word32 dataSz = 0;
03749     word32 channelId;
03750     int ret;
03751 
03752     WLOG(WS_LOG_DEBUG, "Entering DoChannelData()");
03753 
03754     ret = GetUint32(&channelId, buf, len, &begin);
03755     if (ret == WS_SUCCESS)
03756         ret = GetUint32(&dataSz, buf, len, &begin);
03757 
03758     if (ret == WS_SUCCESS) {
03759         *idx = begin + dataSz;
03760 
03761         channel = ChannelFind(ssh, channelId, FIND_SELF);
03762         if (channel == NULL)
03763             ret = WS_INVALID_CHANID;
03764         else
03765             ret = ChannelPutData(channel, buf + begin, dataSz);
03766     }
03767 
03768     WLOG(WS_LOG_DEBUG, "Leaving DoChannelData(), ret = %d", ret);
03769     return ret;
03770 }
03771 
03772 
03773 static int DoPacket(WOLFSSH* ssh)
03774 {
03775     byte* buf = (byte*)ssh->inputBuffer.buffer;
03776     word32 idx = ssh->inputBuffer.idx;
03777     word32 len = ssh->inputBuffer.length;
03778     word32 payloadSz;
03779     byte padSz;
03780     byte msg;
03781     word32 payloadIdx = 0;
03782     int ret;
03783 
03784     //ESP_LOGI("WOLFSSH", "DoPacket sequence number: %d", ssh->peerSeq);
03785     WLOG(WS_LOG_DEBUG, "DoPacket sequence number: %d", ssh->peerSeq);
03786 
03787     idx += LENGTH_SZ;
03788     padSz = buf[idx++];
03789     payloadSz = ssh->curSz - PAD_LENGTH_SZ - padSz - MSG_ID_SZ;
03790 
03791     msg = buf[idx++];
03792     /* At this point, payload starts at "buf + idx". */
03793 
03794     switch (msg) {
03795 
03796         case MSGID_DISCONNECT:
03797             //ESP_LOGI("WOLFSSH", "Decoding MSGID_DISCONNECT");
03798             WLOG(WS_LOG_DEBUG, "Decoding MSGID_DISCONNECT");
03799             ret = DoDisconnect(ssh, buf + idx, payloadSz, &payloadIdx);
03800             break;
03801 
03802         case MSGID_IGNORE:
03803             //ESP_LOGI("WOLFSSH", "Decoding MSGID_IGNORE");
03804             WLOG(WS_LOG_DEBUG, "Decoding MSGID_IGNORE");
03805             ret = DoIgnore(ssh, buf + idx, payloadSz, &payloadIdx);
03806             break;
03807 
03808         case MSGID_UNIMPLEMENTED:
03809             //ESP_LOGI("WOLFSSH", "Decoding MSGID_UNIMPLEMENTED");
03810             WLOG(WS_LOG_DEBUG, "Decoding MSGID_UNIMPLEMENTED");
03811             ret = DoUnimplemented(ssh, buf + idx, payloadSz, &payloadIdx);
03812             break;
03813 
03814         case MSGID_DEBUG:
03815             //ESP_LOGI("WOLFSSH", "Decoding MSGID_DEBUG");
03816             WLOG(WS_LOG_DEBUG, "Decoding MSGID_DEBUG");
03817             ret = DoDebug(ssh, buf + idx, payloadSz, &payloadIdx);
03818             break;
03819 
03820         case MSGID_KEXINIT:
03821             //ESP_LOGI("WOLFSSH", "Decoding MSGID_KEXINIT");
03822             WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXINIT");
03823             ret = DoKexInit(ssh, buf + idx, payloadSz, &payloadIdx);
03824             break;
03825 
03826         case MSGID_NEWKEYS:
03827             //ESP_LOGI("WOLFSSH", "Decoding MSGID_NEWKEYS");
03828             WLOG(WS_LOG_DEBUG, "Decoding MSGID_NEWKEYS");
03829             ret = DoNewKeys(ssh, buf + idx, payloadSz, &payloadIdx);
03830             break;
03831 
03832         case MSGID_KEXDH_INIT:
03833             //ESP_LOGI("WOLFSSH", "Decoding MSGID_KEXDH_INIT");
03834             WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_INIT");
03835             ret = DoKexDhInit(ssh, buf + idx, payloadSz, &payloadIdx);
03836             break;
03837 
03838         case MSGID_KEXDH_REPLY:
03839             if (ssh->handshake->kexId == ID_DH_GEX_SHA256) {
03840                 //ESP_LOGI("WOLFSSH", "Decoding MSGID_KEXDH_GEX_GROUP");
03841                 WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_GEX_GROUP");
03842                 ret = DoKexDhGexGroup(ssh, buf + idx, payloadSz, &payloadIdx);
03843             }
03844             else {
03845                 //ESP_LOGI("WOLFSSH", "Decoding MSGID_KEXDH_REPLY");
03846                 WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_REPLY");
03847                 ret = DoKexDhReply(ssh, buf + idx, payloadSz, &payloadIdx);
03848             }
03849             break;
03850 
03851         case MSGID_KEXDH_GEX_REQUEST:
03852             //ESP_LOGI("WOLFSSH", "Decoding MSGID_KEXDH_GEX_REQUEST");
03853             WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_GEX_REQUEST");
03854             ret = DoKexDhGexRequest(ssh, buf + idx, payloadSz, &payloadIdx);
03855             break;
03856 
03857         case MSGID_KEXDH_GEX_INIT:
03858             //ESP_LOGI("WOLFSSH", "Decoding MSGID_KEXDH_GEX_INIT");
03859             WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_GEX_INIT");
03860             ret = DoKexDhInit(ssh, buf + idx, payloadSz, &payloadIdx);
03861             break;
03862 
03863         case MSGID_KEXDH_GEX_REPLY:
03864             //ESP_LOGI("WOLFSSH", "Decoding MSGID_KEXDH_GEX_INIT");
03865             WLOG(WS_LOG_DEBUG, "Decoding MSGID_KEXDH_GEX_INIT");
03866             ret = DoKexDhReply(ssh, buf + idx, payloadSz, &payloadIdx);
03867             break;
03868 
03869         case MSGID_SERVICE_REQUEST:
03870             //ESP_LOGI("WOLFSSH", "Decoding MSGID_SERVICE_REQUEST");
03871             WLOG(WS_LOG_DEBUG, "Decoding MSGID_SERVICE_REQUEST");
03872             ret = DoServiceRequest(ssh, buf + idx, payloadSz, &payloadIdx);
03873             break;
03874 
03875         case MSGID_SERVICE_ACCEPT:
03876             //ESP_LOGI("WOLFSSH", "Decoding MSGID_SERVER_ACCEPT");
03877             WLOG(WS_LOG_DEBUG, "Decoding MSGID_SERVER_ACCEPT");
03878             ret = DoServiceAccept(ssh, buf + idx, payloadSz, &payloadIdx);
03879             break;
03880 
03881         case MSGID_USERAUTH_REQUEST:
03882             //ESP_LOGI("WOLFSSH", "Decoding MSGID_USERAUTH_REQUEST");
03883             WLOG(WS_LOG_DEBUG, "Decoding MSGID_USERAUTH_REQUEST");
03884             ret = DoUserAuthRequest(ssh, buf + idx, payloadSz, &payloadIdx);
03885             break;
03886 
03887         case MSGID_USERAUTH_FAILURE:
03888             //ESP_LOGI("WOLFSSH", "Decoding MSGID_USERAUTH_FAILURE");
03889             WLOG(WS_LOG_DEBUG, "Decoding MSGID_USERAUTH_FAILURE");
03890             ret = DoUserAuthFailure(ssh, buf + idx, payloadSz, &payloadIdx);
03891             break;
03892 
03893         case MSGID_USERAUTH_SUCCESS:
03894             //ESP_LOGI("WOLFSSH", "Decoding MSGID_USERAUTH_SUCCESS");
03895             WLOG(WS_LOG_DEBUG, "Decoding MSGID_USERAUTH_SUCCESS");
03896             ret = DoUserAuthSuccess(ssh, buf + idx, payloadSz, &payloadIdx);
03897             break;
03898 
03899         case MSGID_USERAUTH_BANNER:
03900             //ESP_LOGI("WOLFSSH", "Decoding MSGID_USERAUTH_BANNER");
03901             WLOG(WS_LOG_DEBUG, "Decoding MSGID_USERAUTH_BANNER");
03902             ret = DoUserAuthBanner(ssh, buf + idx, payloadSz, &payloadIdx);
03903             break;
03904 
03905         case MSGID_GLOBAL_REQUEST:
03906             //ESP_LOGI("WOLFSSH", "Decoding MSGID_GLOBAL_REQUEST");
03907             WLOG(WS_LOG_DEBUG, "Decoding MSGID_GLOBAL_REQUEST");
03908             ret = DoGlobalRequest(ssh, buf + idx, payloadSz, &payloadIdx);
03909             break;
03910 
03911         case MSGID_CHANNEL_OPEN:
03912             //ESP_LOGI("WOLFSSH", "Decoding MSGID_CHANNEL_OPEN");
03913             WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_OPEN");
03914             ret = DoChannelOpen(ssh, buf + idx, payloadSz, &payloadIdx);
03915             break;
03916 
03917         case MSGID_CHANNEL_OPEN_CONF:
03918             //ESP_LOGI("WOLFSSH", "Decoding MSGID_CHANNEL_OPEN_CONF");
03919             WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_OPEN_CONF");
03920             ret = DoChannelOpenConf(ssh, buf + idx, payloadSz, &payloadIdx);
03921             break;
03922 
03923         case MSGID_CHANNEL_OPEN_FAIL:
03924             //ESP_LOGI("WOLFSSH", "Decoding MSGID_CHANNEL_OPEN_FAIL");
03925             WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_OPEN_FAIL");
03926             ret = DoChannelOpenFail(ssh, buf + idx, payloadSz, &payloadIdx);
03927             break;
03928 
03929         case MSGID_CHANNEL_WINDOW_ADJUST:
03930             //ESP_LOGI("WOLFSSH", "Decoding MSGID_CHANNEL_WINDOW_ADJUST");
03931             WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_WINDOW_ADJUST");
03932             ret = DoChannelWindowAdjust(ssh, buf + idx, payloadSz, &payloadIdx);
03933             break;
03934 
03935         case MSGID_CHANNEL_DATA:
03936             //ESP_LOGI("WOLFSSH", "Decoding MSGID_CHANNEL_DATA");
03937             WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_DATA");
03938             ret = DoChannelData(ssh, buf + idx, payloadSz, &payloadIdx);
03939             break;
03940 
03941         case MSGID_CHANNEL_EOF:
03942             //ESP_LOGI("WOLFSSH", "Decoding MSGID_CHANNEL_EOF");
03943             WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_EOF");
03944             ret = WS_SUCCESS;
03945             break;
03946 
03947         case MSGID_CHANNEL_CLOSE:
03948             //ESP_LOGI("WOLFSSH", "Decoding MSGID_CHANNEL_CLOSE");
03949             WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_CLOSE");
03950             ret = DoChannelClose(ssh, buf + idx, payloadSz, &payloadIdx);
03951             break;
03952 
03953         case MSGID_CHANNEL_REQUEST:
03954             //ESP_LOGI("WOLFSSH", "Decoding MSGID_CHANNEL_REQUEST");
03955             WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_REQUEST");
03956             ret = DoChannelRequest(ssh, buf + idx, payloadSz, &payloadIdx);
03957             break;
03958 
03959         case MSGID_CHANNEL_SUCCESS:
03960             //ESP_LOGI("WOLFSSH", "Decoding MSGID_CHANNEL_SUCCESS");
03961             WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_SUCCESS");
03962             ret = DoChannelSuccess(ssh, buf + idx, payloadSz, &payloadIdx);
03963             break;
03964 
03965         case MSGID_CHANNEL_FAILURE:
03966             //ESP_LOGI("WOLFSSH", "Decoding MSGID_CHANNEL_FAILURE");
03967             WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_FAILURE");
03968             ret = DoChannelFailure(ssh, buf + idx, payloadSz, &payloadIdx);
03969             break;
03970 
03971         default:
03972             //ESP_LOGI("WOLFSSH", "Unimplemented message ID (%d)", msg);
03973             WLOG(WS_LOG_DEBUG, "Unimplemented message ID (%d)", msg);
03974 #ifdef SHOW_UNIMPLEMENTED
03975             DumpOctetString(buf + idx, payloadSz);
03976 #endif
03977             ret = SendUnimplemented(ssh);
03978     }
03979 
03980     if (ret == WS_SUCCESS) {
03981         idx += payloadIdx;
03982 
03983         if (idx + padSz > len) {
03984             WLOG(WS_LOG_DEBUG, "Not enough data in buffer for pad.");
03985             ret = WS_BUFFER_E;
03986         }
03987     }
03988 
03989     if (ret == WS_SUCCESS) {
03990         idx += padSz;
03991         ssh->inputBuffer.idx = idx;
03992         ssh->peerSeq++;
03993     }
03994 
03995     return ret;
03996 }
03997 
03998 
03999 static INLINE int Encrypt(WOLFSSH* ssh, byte* cipher, const byte* input,
04000                           word16 sz)
04001 {
04002     int ret = WS_SUCCESS;
04003 
04004     if (ssh == NULL || cipher == NULL || input == NULL || sz == 0)
04005         return WS_BAD_ARGUMENT;
04006 
04007     WLOG(WS_LOG_DEBUG, "Encrypt %s", IdToName(ssh->encryptId));
04008 
04009     switch (ssh->encryptId) {
04010         case ID_NONE:
04011             break;
04012 
04013         case ID_AES128_CBC:
04014             if (wc_AesCbcEncrypt(&ssh->encryptCipher.aes,
04015                                  cipher, input, sz) < 0) {
04016 
04017                 ret = WS_ENCRYPT_E;
04018             }
04019             break;
04020 
04021         default:
04022             ret = WS_INVALID_ALGO_ID;
04023     }
04024 
04025     ssh->txCount += sz;
04026 
04027     return ret;
04028 }
04029 
04030 
04031 static INLINE int Decrypt(WOLFSSH* ssh, byte* plain, const byte* input,
04032                           word16 sz)
04033 {
04034     int ret = WS_SUCCESS;
04035 
04036     if (ssh == NULL || plain == NULL || input == NULL || sz == 0)
04037         return WS_BAD_ARGUMENT;
04038 
04039     WLOG(WS_LOG_DEBUG, "Decrypt %s", IdToName(ssh->peerEncryptId));
04040 
04041     switch (ssh->peerEncryptId) {
04042         case ID_NONE:
04043             break;
04044 
04045         case ID_AES128_CBC:
04046             if (wc_AesCbcDecrypt(&ssh->decryptCipher.aes,
04047                                  plain, input, sz) < 0) {
04048 
04049                 ret = WS_DECRYPT_E;
04050             }
04051             break;
04052 
04053         default:
04054             ret = WS_INVALID_ALGO_ID;
04055     }
04056 
04057     ssh->rxCount += sz;
04058     HighwaterCheck(ssh, WOLFSSH_HWSIDE_RECEIVE);
04059 
04060     return ret;
04061 }
04062 
04063 
04064 static INLINE int CreateMac(WOLFSSH* ssh, const byte* in, word32 inSz,
04065                             byte* mac)
04066 {
04067     byte flatSeq[LENGTH_SZ];
04068     int ret;
04069 
04070     c32toa(ssh->seq, flatSeq);
04071 
04072     WLOG(WS_LOG_DEBUG, "CreateMac %s", IdToName(ssh->macId));
04073 
04074     /* Need to MAC the sequence number and the unencrypted packet */
04075     switch (ssh->macId) {
04076         case ID_NONE:
04077             ret = WS_SUCCESS;
04078             break;
04079 
04080         case ID_HMAC_SHA1_96:
04081             {
04082                 Hmac hmac;
04083                 byte digest[SHA_DIGEST_SIZE];
04084 
04085                 ret = wc_HmacSetKey(&hmac, SHA,
04086                                     ssh->keys.macKey, ssh->keys.macKeySz);
04087                 if (ret == WS_SUCCESS)
04088                     ret = wc_HmacUpdate(&hmac, flatSeq, sizeof(flatSeq));
04089                 if (ret == WS_SUCCESS)
04090                     ret = wc_HmacUpdate(&hmac, in, inSz);
04091                 if (ret == WS_SUCCESS)
04092                     ret = wc_HmacFinal(&hmac, digest);
04093                 if (ret == WS_SUCCESS)
04094                     WMEMCPY(mac, digest, SHA1_96_SZ);
04095             }
04096             break;
04097 
04098         case ID_HMAC_SHA1:
04099             {
04100                 Hmac hmac;
04101 
04102                 ret = wc_HmacSetKey(&hmac, SHA,
04103                                     ssh->keys.macKey, ssh->keys.macKeySz);
04104                 if (ret == WS_SUCCESS)
04105                     ret = wc_HmacUpdate(&hmac, flatSeq, sizeof(flatSeq));
04106                 if (ret == WS_SUCCESS)
04107                     ret = wc_HmacUpdate(&hmac, in, inSz);
04108                 if (ret == WS_SUCCESS)
04109                     ret = wc_HmacFinal(&hmac, mac);
04110             }
04111             break;
04112 
04113         case ID_HMAC_SHA2_256:
04114             {
04115                 Hmac hmac;
04116 
04117                 ret = wc_HmacSetKey(&hmac, SHA256,
04118                                     ssh->keys.macKey,
04119                                     ssh->keys.macKeySz);
04120                 if (ret == WS_SUCCESS)
04121                     ret = wc_HmacUpdate(&hmac, flatSeq, sizeof(flatSeq));
04122                 if (ret == WS_SUCCESS)
04123                     ret = wc_HmacUpdate(&hmac, in, inSz);
04124                 if (ret == WS_SUCCESS)
04125                     ret = wc_HmacFinal(&hmac, mac);
04126             }
04127             break;
04128 
04129         default:
04130             WLOG(WS_LOG_DEBUG, "Invalid Mac ID");
04131             ret = WS_FATAL_ERROR;
04132     }
04133 
04134     return ret;
04135 }
04136 
04137 
04138 static INLINE int VerifyMac(WOLFSSH* ssh, const byte* in, word32 inSz,
04139                             const byte* mac)
04140 {
04141     int ret;
04142     byte flatSeq[LENGTH_SZ];
04143     byte checkMac[MAX_HMAC_SZ];
04144     Hmac hmac;
04145 
04146     c32toa(ssh->peerSeq, flatSeq);
04147 
04148     WLOG(WS_LOG_DEBUG, "VerifyMac %s", IdToName(ssh->peerMacId));
04149     WLOG(WS_LOG_DEBUG, "VM: inSz = %u", inSz);
04150     WLOG(WS_LOG_DEBUG, "VM: seq = %u", ssh->peerSeq);
04151     WLOG(WS_LOG_DEBUG, "VM: keyLen = %u", ssh->peerKeys.macKeySz);
04152 
04153     WMEMSET(checkMac, 0, sizeof(checkMac));
04154 
04155     switch (ssh->peerMacId) {
04156         case ID_NONE:
04157             ret = WS_SUCCESS;
04158             break;
04159 
04160         case ID_HMAC_SHA1:
04161         case ID_HMAC_SHA1_96:
04162             ret = wc_HmacSetKey(&hmac, SHA,
04163                                 ssh->peerKeys.macKey, ssh->peerKeys.macKeySz);
04164             if (ret == WS_SUCCESS)
04165                 ret = wc_HmacUpdate(&hmac, flatSeq, sizeof(flatSeq));
04166             if (ret == WS_SUCCESS)
04167                 ret = wc_HmacUpdate(&hmac, in, inSz);
04168             if (ret == WS_SUCCESS)
04169                 ret = wc_HmacFinal(&hmac, checkMac);
04170             if (ConstantCompare(checkMac, mac, ssh->peerMacSz) != 0)
04171                 ret = WS_VERIFY_MAC_E;
04172             break;
04173 
04174         case ID_HMAC_SHA2_256:
04175             ret = wc_HmacSetKey(&hmac, SHA256,
04176                                 ssh->peerKeys.macKey, ssh->peerKeys.macKeySz);
04177             if (ret == WS_SUCCESS)
04178                 ret = wc_HmacUpdate(&hmac, flatSeq, sizeof(flatSeq));
04179             if (ret == WS_SUCCESS)
04180                 ret = wc_HmacUpdate(&hmac, in, inSz);
04181             if (ret == WS_SUCCESS)
04182                 ret = wc_HmacFinal(&hmac, checkMac);
04183             if (ConstantCompare(checkMac, mac, ssh->peerMacSz) != 0)
04184                 ret = WS_VERIFY_MAC_E;
04185             break;
04186 
04187         default:
04188             ret = WS_INVALID_ALGO_ID;
04189     }
04190 
04191     return ret;
04192 }
04193 
04194 
04195 static INLINE void AeadIncrementExpIv(byte* iv)
04196 {
04197     int i;
04198 
04199     iv += AEAD_IMP_IV_SZ;
04200 
04201     for (i = AEAD_EXP_IV_SZ-1; i >= 0; i--) {
04202         if (++iv[i]) return;
04203     }
04204 }
04205 
04206 
04207 static INLINE int EncryptAead(WOLFSSH* ssh, byte* cipher,
04208                               const byte* input, word16 sz,
04209                               byte* authTag, const byte* auth,
04210                               word16 authSz)
04211 {
04212     int ret = WS_SUCCESS;
04213 
04214     if (ssh == NULL || cipher == NULL || input == NULL || sz == 0 ||
04215         authTag == NULL || auth == NULL || authSz == 0)
04216         return WS_BAD_ARGUMENT;
04217 
04218     WLOG(WS_LOG_DEBUG, "EncryptAead %s", IdToName(ssh->encryptId));
04219 
04220     if (ssh->encryptId == ID_AES128_GCM) {
04221         ret = wc_AesGcmEncrypt(&ssh->encryptCipher.aes, cipher, input, sz,
04222                                ssh->keys.iv, ssh->keys.ivSz,
04223                                authTag, ssh->macSz, auth, authSz);
04224     }
04225     else
04226         ret = WS_INVALID_ALGO_ID;
04227 
04228     AeadIncrementExpIv(ssh->keys.iv);
04229     ssh->txCount += sz;
04230 
04231     return ret;
04232 }
04233 
04234 
04235 static INLINE int DecryptAead(WOLFSSH* ssh, byte* plain,
04236                               const byte* input, word16 sz,
04237                               const byte* authTag, const byte* auth,
04238                               word16 authSz)
04239 {
04240     int ret = WS_SUCCESS;
04241 
04242     if (ssh == NULL || plain == NULL || input == NULL || sz == 0 ||
04243         authTag == NULL || auth == NULL || authSz == 0)
04244         return WS_BAD_ARGUMENT;
04245 
04246     WLOG(WS_LOG_DEBUG, "DecryptAead %s", IdToName(ssh->peerEncryptId));
04247 
04248     if (ssh->peerEncryptId == ID_AES128_GCM) {
04249         ret = wc_AesGcmDecrypt(&ssh->decryptCipher.aes, plain, input, sz,
04250                                ssh->peerKeys.iv, ssh->peerKeys.ivSz,
04251                                authTag, ssh->peerMacSz, auth, authSz);
04252     }
04253     else
04254         ret = WS_INVALID_ALGO_ID;
04255 
04256     AeadIncrementExpIv(ssh->peerKeys.iv);
04257     ssh->rxCount += sz;
04258     HighwaterCheck(ssh, WOLFSSH_HWSIDE_RECEIVE);
04259 
04260     return ret;
04261 }
04262 
04263 
04264 int DoReceive(WOLFSSH* ssh)
04265 {
04266     int ret = WS_FATAL_ERROR;
04267     int verifyResult;
04268     word32 readSz;
04269     byte peerBlockSz = ssh->peerBlockSz;
04270     byte peerMacSz = ssh->peerMacSz;
04271     byte aeadMode = ssh->peerAeadMode;
04272 
04273     for (;;) {
04274         switch (ssh->processReplyState) {
04275             case PROCESS_INIT:
04276                 readSz = peerBlockSz;
04277                 //ESP_LOGI("WOLFSSH", "DoReceive: PROCESS_INT");
04278                 WLOG(WS_LOG_DEBUG, "PR1: size = %u", readSz);
04279                 //ESP_LOGI("WOLFSSH", "PR1: size = %u", readSz);
04280                 if ((ret = GetInputData(ssh, readSz)) < 0) {
04281                     return ret;
04282                 }
04283                 ssh->processReplyState = PROCESS_PACKET_LENGTH;
04284 
04285                 if (!aeadMode) {
04286                     /* Decrypt first block if encrypted */
04287                     ret = Decrypt(ssh,
04288                                   ssh->inputBuffer.buffer +
04289                                      ssh->inputBuffer.idx,
04290                                   ssh->inputBuffer.buffer +
04291                                      ssh->inputBuffer.idx,
04292                                   readSz);
04293                     if (ret != WS_SUCCESS) {
04294                         //ESP_LOGI("WOLFSSH", "PR: First decrypt fail");
04295                         WLOG(WS_LOG_DEBUG, "PR: First decrypt fail");
04296                         return ret;
04297                     }
04298                 }
04299                 //ESP_LOGI("WOLFSSH", "DoReceive: PROCESS_INT DONE");
04300                 FALL_THROUGH;
04301 
04302             case PROCESS_PACKET_LENGTH:
04303                 //ESP_LOGI("WOLFSSH", "DoReceive: PROCESS_PACKET_LENGTH");
04304                 /* Peek at the packet_length field. */
04305                 ato32(ssh->inputBuffer.buffer + ssh->inputBuffer.idx,
04306                       &ssh->curSz);
04307                 ssh->processReplyState = PROCESS_PACKET_FINISH;
04308                 FALL_THROUGH;
04309 
04310             case PROCESS_PACKET_FINISH:
04311                 //ESP_LOGI("WOLFSSH", "DoReceive: PROCESS_PACKET_FINISH");
04312                 readSz = ssh->curSz + LENGTH_SZ + peerMacSz;
04313                 WLOG(WS_LOG_DEBUG, "PR2: size = %u", readSz);
04314                 if (readSz > 0) {
04315                     if ((ret = GetInputData(ssh, readSz)) < 0) {
04316                         return ret;
04317                     }
04318 
04319                     if (!aeadMode) {
04320                         if (ssh->curSz + LENGTH_SZ - peerBlockSz > 0) {
04321                             ret = Decrypt(ssh,
04322                                           ssh->inputBuffer.buffer +
04323                                              ssh->inputBuffer.idx + peerBlockSz,
04324                                           ssh->inputBuffer.buffer +
04325                                              ssh->inputBuffer.idx + peerBlockSz,
04326                                           ssh->curSz + LENGTH_SZ - peerBlockSz);
04327                         }
04328                         else {
04329                             WLOG(WS_LOG_INFO,
04330                                  "Not trying to decrypt short message.");
04331                         }
04332 
04333                         /* Verify the buffer is big enough for the data and mac.
04334                          * Even if the decrypt step fails, verify the MAC anyway.
04335                          * This keeps consistent timing. */
04336                         verifyResult = VerifyMac(ssh,
04337                                                  ssh->inputBuffer.buffer +
04338                                                      ssh->inputBuffer.idx,
04339                                                  ssh->curSz + LENGTH_SZ,
04340                                                  ssh->inputBuffer.buffer +
04341                                                      ssh->inputBuffer.idx +
04342                                                      LENGTH_SZ + ssh->curSz);
04343                         if (ret != WS_SUCCESS) {
04344                             WLOG(WS_LOG_DEBUG, "PR: Decrypt fail");
04345                             return ret;
04346                         }
04347                         if (verifyResult != WS_SUCCESS) {
04348                             WLOG(WS_LOG_DEBUG, "PR: VerifyMac fail");
04349                             return ret;
04350                         }
04351                     }
04352                     else {
04353                         ret = DecryptAead(ssh,
04354                                           ssh->inputBuffer.buffer +
04355                                              ssh->inputBuffer.idx +
04356                                              LENGTH_SZ,
04357                                           ssh->inputBuffer.buffer +
04358                                              ssh->inputBuffer.idx +
04359                                              LENGTH_SZ,
04360                                           ssh->curSz,
04361                                           ssh->inputBuffer.buffer +
04362                                               ssh->inputBuffer.idx +
04363                                               ssh->curSz + LENGTH_SZ,
04364                                           ssh->inputBuffer.buffer +
04365                                               ssh->inputBuffer.idx,
04366                                           LENGTH_SZ);
04367 
04368                         if (ret != WS_SUCCESS) {
04369                             WLOG(WS_LOG_DEBUG, "PR: DecryptAead fail");
04370                             return ret;
04371                         }
04372                     }
04373                 }
04374                 ssh->processReplyState = PROCESS_PACKET;
04375                 FALL_THROUGH;
04376 
04377             case PROCESS_PACKET:
04378                 //ESP_LOGI("WOLFSSH", "DoReceive: PROCESS_PACKET");
04379                 if ( (ret = DoPacket(ssh)) < 0) {
04380                     return ret;
04381                 }
04382                 WLOG(WS_LOG_DEBUG, "PR3: peerMacSz = %u", peerMacSz);
04383                 ssh->inputBuffer.idx += peerMacSz;
04384                 break;
04385 
04386             default:
04387                 //ESP_LOGI("WOLFSSH", "DoReceive: Bad input state!!");
04388                 WLOG(WS_LOG_DEBUG, "Bad process input state, program error");
04389                 return WS_INPUT_CASE_E;
04390         }
04391         WLOG(WS_LOG_DEBUG, "PR4: Shrinking input buffer");
04392         //ESP_LOGI("WOLFSSH", "PR4: Shrinking input buffer");
04393         ShrinkBuffer(&ssh->inputBuffer, 1);
04394         ssh->processReplyState = PROCESS_INIT;
04395 
04396         WLOG(WS_LOG_DEBUG, "PR5: txCount = %u, rxCount = %u",
04397              ssh->txCount, ssh->rxCount);
04398         //ESP_LOGI("WOLFSSH", "PR5: txCount = %u, rxCount = %u", ssh->txCount, ssh->rxCount);
04399 
04400         return WS_SUCCESS;
04401     }
04402 }
04403 
04404 
04405 int DoProtoId(WOLFSSH* ssh)
04406 {
04407     int ret;
04408     word32 idSz;
04409     byte* eol;
04410 
04411     if ( (ret = GetInputText(ssh, &eol)) < 0) {
04412         WLOG(WS_LOG_DEBUG, "get input text failed");
04413         return ret;
04414     }
04415 
04416     if (eol == NULL) {
04417         WLOG(WS_LOG_DEBUG, "invalid EOL");
04418         return WS_VERSION_E;
04419     }
04420 
04421     if (WSTRNCASECMP((char*)ssh->inputBuffer.buffer,
04422                      sshProtoIdStr, SSH_PROTO_SZ) == 0) {
04423 
04424         if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER)
04425             ssh->clientState = CLIENT_VERSION_DONE;
04426         else
04427             ssh->serverState = SERVER_VERSION_DONE;
04428     }
04429     else {
04430         WLOG(WS_LOG_DEBUG, "SSH version mismatch");
04431         return WS_VERSION_E;
04432     }
04433 
04434     *eol = 0;
04435 
04436     idSz = (word32)WSTRLEN((char*)ssh->inputBuffer.buffer);
04437 
04438     /* Store the proto ID for later use. It is used in keying and rekeying. */
04439     ssh->peerProtoId = (byte*)WMALLOC(idSz + LENGTH_SZ,
04440                                          ssh->ctx->heap, DYNTYPE_STRING);
04441     if (ssh->peerProtoId == NULL)
04442         ret = WS_MEMORY_E;
04443     else {
04444         c32toa(idSz, ssh->peerProtoId);
04445         WMEMCPY(ssh->peerProtoId + LENGTH_SZ, ssh->inputBuffer.buffer, idSz);
04446         ssh->peerProtoIdSz = idSz + LENGTH_SZ;
04447     }
04448 
04449     ssh->inputBuffer.idx += idSz + SSH_PROTO_EOL_SZ;
04450     ShrinkBuffer(&ssh->inputBuffer, 0);
04451 
04452     return ret;
04453 }
04454 
04455 
04456 int SendProtoId(WOLFSSH* ssh)
04457 {
04458     int ret = WS_SUCCESS;
04459     word32 sshProtoIdStrSz;
04460 
04461     if (ssh == NULL)
04462         ret = WS_BAD_ARGUMENT;
04463 
04464     if (ret == WS_SUCCESS) {
04465         WLOG(WS_LOG_DEBUG, "%s", sshProtoIdStr);
04466         sshProtoIdStrSz = (word32)WSTRLEN(sshProtoIdStr);
04467         ret = GrowBuffer(&ssh->outputBuffer, sshProtoIdStrSz, 0);
04468     }
04469 
04470     if (ret == WS_SUCCESS) {
04471         WMEMCPY(ssh->outputBuffer.buffer, sshProtoIdStr, sshProtoIdStrSz);
04472         ssh->outputBuffer.length = sshProtoIdStrSz;
04473         ret = SendBuffered(ssh);
04474     }
04475 
04476     return ret;
04477 }
04478 
04479 
04480 static int PreparePacket(WOLFSSH* ssh, word32 payloadSz)
04481 {
04482     int ret = WS_SUCCESS;
04483     byte* output;
04484     word32 outputSz;
04485     word32 packetSz;
04486     word32 usedSz;
04487     byte paddingSz;
04488 
04489     if (ssh == NULL)
04490         ret = WS_BAD_ARGUMENT;
04491 
04492     if (ret == WS_SUCCESS) {
04493         /* Minimum value for paddingSz is 4. */
04494         paddingSz = ssh->blockSz -
04495                     ((ssh->aeadMode ? 0 : LENGTH_SZ) +
04496                      PAD_LENGTH_SZ + payloadSz) % ssh->blockSz;
04497         if (paddingSz < MIN_PAD_LENGTH)
04498             paddingSz += ssh->blockSz;
04499         ssh->paddingSz = paddingSz;
04500         packetSz = PAD_LENGTH_SZ + payloadSz + paddingSz;
04501         outputSz = LENGTH_SZ + packetSz + ssh->macSz;
04502         usedSz = ssh->outputBuffer.length - ssh->outputBuffer.idx;
04503 
04504         ret = GrowBuffer(&ssh->outputBuffer, outputSz, usedSz);
04505     }
04506 
04507     if (ret == WS_SUCCESS) {
04508         ssh->packetStartIdx = ssh->outputBuffer.length;
04509         output = ssh->outputBuffer.buffer + ssh->outputBuffer.length;
04510 
04511         /* fill in the packetSz, paddingSz */
04512         c32toa(packetSz, output);
04513         output[LENGTH_SZ] = paddingSz;
04514 
04515         ssh->outputBuffer.length += LENGTH_SZ + PAD_LENGTH_SZ;
04516     }
04517 
04518     return ret;
04519 }
04520 
04521 
04522 static int BundlePacket(WOLFSSH* ssh)
04523 {
04524     byte* output;
04525     word32 idx;
04526     byte paddingSz;
04527     int ret = WS_SUCCESS;
04528 
04529     if (ssh == NULL)
04530         ret = WS_BAD_ARGUMENT;
04531 
04532     if (ret == WS_SUCCESS) {
04533         output = ssh->outputBuffer.buffer;
04534         idx = ssh->outputBuffer.length;
04535         paddingSz = ssh->paddingSz;
04536 
04537         /* Add the padding */
04538         WLOG(WS_LOG_DEBUG, "BP: paddingSz = %u", paddingSz);
04539         if (ssh->encryptId == ID_NONE)
04540             WMEMSET(output + idx, 0, paddingSz);
04541         else if (wc_RNG_GenerateBlock(ssh->rng, output + idx, paddingSz) < 0)
04542             ret = WS_CRYPTO_FAILED;
04543     }
04544 
04545     if (!ssh->aeadMode) {
04546         if (ret == WS_SUCCESS) {
04547             idx += paddingSz;
04548             ret = CreateMac(ssh, ssh->outputBuffer.buffer + ssh->packetStartIdx,
04549                             ssh->outputBuffer.length -
04550                                 ssh->packetStartIdx + paddingSz,
04551                             output + idx);
04552         }
04553         else {
04554             WLOG(WS_LOG_DEBUG, "BP: failed to add padding");
04555         }
04556 
04557         if (ret == WS_SUCCESS) {
04558             idx += ssh->macSz;
04559             ret = Encrypt(ssh,
04560                           ssh->outputBuffer.buffer + ssh->packetStartIdx,
04561                           ssh->outputBuffer.buffer + ssh->packetStartIdx,
04562                           ssh->outputBuffer.length -
04563                               ssh->packetStartIdx + paddingSz);
04564         }
04565         else {
04566             WLOG(WS_LOG_DEBUG, "BP: failed to generate mac");
04567         }
04568     }
04569     else {
04570         if (ret == WS_SUCCESS) {
04571             idx += paddingSz;
04572             ret = EncryptAead(ssh,
04573                               ssh->outputBuffer.buffer +
04574                                   ssh->packetStartIdx + LENGTH_SZ,
04575                               ssh->outputBuffer.buffer +
04576                                   ssh->packetStartIdx + LENGTH_SZ,
04577                               ssh->outputBuffer.length -
04578                                   ssh->packetStartIdx + paddingSz -
04579                                   LENGTH_SZ,
04580                               output + idx,
04581                               ssh->outputBuffer.buffer +
04582                                   ssh->packetStartIdx,
04583                               LENGTH_SZ);
04584             idx += ssh->macSz;
04585         }
04586     }
04587 
04588     if (ret == WS_SUCCESS) {
04589         ssh->seq++;
04590         ssh->outputBuffer.length = idx;
04591     }
04592     else {
04593         WLOG(WS_LOG_DEBUG, "BP: failed to encrypt buffer");
04594     }
04595 
04596     return ret;
04597 }
04598 
04599 
04600 static INLINE void CopyNameList(byte* buf, word32* idx,
04601                                                 const char* src, word32 srcSz)
04602 {
04603     word32 begin = *idx;
04604 
04605     c32toa(srcSz, buf + begin);
04606     begin += LENGTH_SZ;
04607     WMEMCPY(buf + begin, src, srcSz);
04608     begin += srcSz;
04609 
04610     *idx = begin;
04611 }
04612 
04613 
04614 static const char cannedEncAlgoNames[] = "aes128-gcm@openssh.com,aes128-cbc";
04615 static const char cannedMacAlgoNames[] = "hmac-sha2-256,hmac-sha1-96,"
04616                                          "hmac-sha1";
04617 static const char cannedKeyAlgoRsaNames[] = "ssh-rsa";
04618 static const char cannedKeyAlgoEcc256Names[] = "ecdsa-sha2-nistp256";
04619 static const char cannedKeyAlgoEcc384Names[] = "ecdsa-sha2-nistp384";
04620 static const char cannedKeyAlgoEcc521Names[] = "ecdsa-sha2-nistp521";
04621 static const char cannedKexAlgoNames[] = "ecdh-sha2-nistp256,"
04622                                          "diffie-hellman-group-exchange-sha256,"
04623                                          "diffie-hellman-group14-sha1,"
04624                                          "diffie-hellman-group1-sha1";
04625 static const char cannedNoneNames[] = "none";
04626 
04627 static const word32 cannedEncAlgoNamesSz = sizeof(cannedEncAlgoNames) - 1;
04628 static const word32 cannedMacAlgoNamesSz = sizeof(cannedMacAlgoNames) - 1;
04629 static const word32 cannedKeyAlgoRsaNamesSz = sizeof(cannedKeyAlgoRsaNames) - 1;
04630 static const word32 cannedKeyAlgoEcc256NamesSz =
04631                                            sizeof(cannedKeyAlgoEcc256Names) - 1;
04632 static const word32 cannedKeyAlgoEcc384NamesSz =
04633                                            sizeof(cannedKeyAlgoEcc384Names) - 1;
04634 static const word32 cannedKeyAlgoEcc521NamesSz =
04635                                            sizeof(cannedKeyAlgoEcc521Names) - 1;
04636 static const word32 cannedKexAlgoNamesSz = sizeof(cannedKexAlgoNames) - 1;
04637 static const word32 cannedNoneNamesSz = sizeof(cannedNoneNames) - 1;
04638 
04639 
04640 int SendKexInit(WOLFSSH* ssh)
04641 {
04642     byte* output;
04643     byte* payload;
04644     word32 idx = 0;
04645     word32 payloadSz;
04646     int ret = WS_SUCCESS;
04647     const char* cannedKeyAlgoNames;
04648     word32 cannedKeyAlgoNamesSz;
04649 
04650     WLOG(WS_LOG_DEBUG, "Entering SendKexInit()");
04651 
04652     if (ssh == NULL)
04653         ret = WS_BAD_ARGUMENT;
04654 
04655     ssh->isKeying = 1;
04656     if (ssh->handshake == NULL) {
04657         ssh->handshake = HandshakeInfoNew(ssh->ctx->heap);
04658         if (ssh->handshake == NULL) {
04659             WLOG(WS_LOG_DEBUG, "Couldn't allocate handshake info");
04660             ret = WS_MEMORY_E;
04661         }
04662     }
04663 
04664     if (ret == WS_SUCCESS) {
04665         switch (ssh->ctx->useEcc) {
04666             case ECC_SECP256R1:
04667                 cannedKeyAlgoNames = cannedKeyAlgoEcc256Names;
04668                 cannedKeyAlgoNamesSz = cannedKeyAlgoEcc256NamesSz;
04669                 break;
04670             case ECC_SECP384R1:
04671                 cannedKeyAlgoNames = cannedKeyAlgoEcc384Names;
04672                 cannedKeyAlgoNamesSz = cannedKeyAlgoEcc384NamesSz;
04673                 break;
04674             case ECC_SECP521R1:
04675                 cannedKeyAlgoNames = cannedKeyAlgoEcc521Names;
04676                 cannedKeyAlgoNamesSz = cannedKeyAlgoEcc521NamesSz;
04677                 break;
04678             default:
04679                 cannedKeyAlgoNames = cannedKeyAlgoRsaNames;
04680                 cannedKeyAlgoNamesSz = cannedKeyAlgoRsaNamesSz;
04681         }
04682         payloadSz = MSG_ID_SZ + COOKIE_SZ + (LENGTH_SZ * 11) + BOOLEAN_SZ +
04683                    cannedKexAlgoNamesSz + cannedKeyAlgoNamesSz +
04684                    (cannedEncAlgoNamesSz * 2) +
04685                    (cannedMacAlgoNamesSz * 2) +
04686                    (cannedNoneNamesSz * 2);
04687         ret = PreparePacket(ssh, payloadSz);
04688     }
04689 
04690     if (ret == WS_SUCCESS) {
04691         output = ssh->outputBuffer.buffer;
04692         idx = ssh->outputBuffer.length;
04693         payload = output + idx;
04694 
04695         output[idx++] = MSGID_KEXINIT;
04696 
04697         ret = wc_RNG_GenerateBlock(ssh->rng, output + idx, COOKIE_SZ);
04698     }
04699 
04700     if (ret == WS_SUCCESS) {
04701         byte* buf;
04702         word32 bufSz = payloadSz + LENGTH_SZ;
04703 
04704         idx += COOKIE_SZ;
04705 
04706         CopyNameList(output, &idx, cannedKexAlgoNames, cannedKexAlgoNamesSz);
04707         CopyNameList(output, &idx, cannedKeyAlgoNames, cannedKeyAlgoNamesSz);
04708         CopyNameList(output, &idx, cannedEncAlgoNames, cannedEncAlgoNamesSz);
04709         CopyNameList(output, &idx, cannedEncAlgoNames, cannedEncAlgoNamesSz);
04710         CopyNameList(output, &idx, cannedMacAlgoNames, cannedMacAlgoNamesSz);
04711         CopyNameList(output, &idx, cannedMacAlgoNames, cannedMacAlgoNamesSz);
04712         CopyNameList(output, &idx, cannedNoneNames, cannedNoneNamesSz);
04713         CopyNameList(output, &idx, cannedNoneNames, cannedNoneNamesSz);
04714         c32toa(0, output + idx); /* Languages - Client To Server (0) */
04715         idx += LENGTH_SZ;
04716         c32toa(0, output + idx); /* Languages - Server To Client (0) */
04717         idx += LENGTH_SZ;
04718         output[idx++] = 0;       /* First KEX packet follows (false) */
04719         c32toa(0, output + idx); /* Reserved (0) */
04720         idx += LENGTH_SZ;
04721 
04722         ssh->outputBuffer.length = idx;
04723 
04724         buf = (byte*)WMALLOC(bufSz, ssh->ctx->heap, DYNTYPE_STRING);
04725         if (buf == NULL) {
04726             WLOG(WS_LOG_DEBUG, "Cannot allocate storage for KEX Init msg");
04727             ret = WS_MEMORY_E;
04728         }
04729         else {
04730             c32toa(payloadSz, buf);
04731             WMEMCPY(buf + LENGTH_SZ, payload, payloadSz);
04732             ssh->handshake->kexInit = buf;
04733             ssh->handshake->kexInitSz = bufSz;
04734         }
04735     }
04736 
04737     if (ret == WS_SUCCESS)
04738         ret = BundlePacket(ssh);
04739 
04740     if (ret == WS_SUCCESS)
04741         ret = SendBuffered(ssh);
04742 
04743     WLOG(WS_LOG_DEBUG, "Leaving SendKexInit(), ret = %d", ret);
04744     return ret;
04745 }
04746 
04747 
04748 /* SendKexDhReply()
04749  * It is also the funciton used for MSGID_KEXECDH_REPLY. The parameters
04750  * are analogous between the two messages. Where MSGID_KEXDH_REPLY has
04751  * server's public host key (K_S), f, and the signature of H;
04752  * MSGID_KEXECDH_REPLY has K_S, the server'e ephemeral public key (Q_S),
04753  * and the signature of H. This also applies to the GEX version of this.
04754  * H is calculated the same for KEXDH and KEXECDH, and has some exceptions
04755  * for GEXDH. */
04756 int SendKexDhReply(WOLFSSH* ssh)
04757 {
04758 /* This function and DoKexDhReply() are unwieldy and in need of refactoring. */
04759     const byte* primeGroup = dhPrimeGroup14;
04760     word32 primeGroupSz = dhPrimeGroup14Sz;
04761     const byte* generator = dhGenerator;
04762     word32 generatorSz = dhGeneratorSz;
04763 
04764     byte useEcc = 0;
04765     byte f[257];
04766     word32 fSz = sizeof(f);
04767     byte fPad = 0;
04768     byte kPad = 0;
04769 
04770     struct {
04771         byte useRsa;
04772         word32 sz;
04773         const char *name;
04774         word32 nameSz;
04775         union {
04776             struct {
04777                 RsaKey key;
04778                 byte e[257];
04779                 word32 eSz;
04780                 byte ePad;
04781                 byte n[257];
04782                 word32 nSz;
04783                 byte nPad;
04784             } rsa;
04785             struct {
04786                 ecc_key key;
04787                 word32 keyBlobSz;
04788                 const char *keyBlobName;
04789                 word32 keyBlobNameSz;
04790                 byte q[257];
04791                 word32 qSz;
04792                 byte qPad;
04793                 const char *primeName;
04794                 word32 primeNameSz;
04795             } ecc;
04796         } sk;
04797     } sigKeyBlock;
04798 
04799     byte sig[512];
04800     word32 sigSz = sizeof(sig);
04801     word32 sigBlockSz;
04802 
04803     word32 payloadSz;
04804     byte scratchLen[LENGTH_SZ];
04805     word32 scratch = 0;
04806     byte* output;
04807     word32 idx;
04808     int ret = WS_SUCCESS;
04809     byte msgId = MSGID_KEXDH_REPLY;
04810 
04811     WLOG(WS_LOG_DEBUG, "Entering SendKexDhReply()");
04812     //ESP_LOGI("WOLFSSH", "Entering SendKexDhReply()");
04813 
04814     sigKeyBlock.useRsa = ssh->handshake->pubKeyId == ID_SSH_RSA;
04815     sigKeyBlock.name = IdToName(ssh->handshake->pubKeyId);
04816     sigKeyBlock.nameSz = (word32)strlen(sigKeyBlock.name);
04817 
04818     switch (ssh->handshake->kexId) {
04819         case ID_DH_GROUP1_SHA1:
04820             //ESP_LOGI("WOLFSSH", "KexID: ID_DH_GROUP1_SHA1");
04821             primeGroup = dhPrimeGroup1;
04822             primeGroupSz = dhPrimeGroup1Sz;
04823             break;
04824 
04825         case ID_DH_GROUP14_SHA1:
04826             //ESP_LOGI("WOLFSSH", "KexID: ID_DH_GROUP14_SHA1 (default)");
04827             /* This is the default case. */
04828             break;
04829 
04830         case ID_DH_GEX_SHA256:
04831             //ESP_LOGI("WOLFSSH", "KexID: ID_DH_GEX_SHA256");
04832             msgId = MSGID_KEXDH_GEX_REPLY;
04833             break;
04834 
04835         case ID_ECDH_SHA2_NISTP256:
04836         case ID_ECDH_SHA2_NISTP384:
04837         case ID_ECDH_SHA2_NISTP521:
04838             //ESP_LOGI("WOLFSSH", "KexID: ID_ECDH_SHA2_NISTP256/384/521");
04839             useEcc = 1;
04840             msgId = MSGID_KEXDH_REPLY;
04841             break;
04842 
04843         default:
04844             //ESP_LOGI("WOLFSSH", "KexID: INVALID");
04845             ret = WS_INVALID_ALGO_ID;
04846     }
04847 
04848     /* At this point, the exchange hash, H, includes items V_C, V_S, I_C,
04849      * and I_S. Next add K_S, the server's public host key. K_S will
04850      * either be RSA or ECDSA public key blob. */
04851     if (ret == WS_SUCCESS) {
04852         if (sigKeyBlock.useRsa) {
04853             //ESP_LOGI("WOLFSSH", "KeyBlock: RSA");
04854             /* Decode the user-configured RSA private key. */
04855             sigKeyBlock.sk.rsa.eSz = sizeof(sigKeyBlock.sk.rsa.e);
04856             sigKeyBlock.sk.rsa.nSz = sizeof(sigKeyBlock.sk.rsa.n);
04857             //ESP_LOGI("WOLFSSH", "wc_InitRsaKey");
04858             ret = wc_InitRsaKey(&sigKeyBlock.sk.rsa.key, ssh->ctx->heap);
04859             //ESP_LOGI("WOLFSSH", "wc_InitRsaKey ret=%d", ret);
04860             if (ret == 0)
04861                 ret = wc_RsaPrivateKeyDecode(ssh->ctx->privateKey, &scratch,
04862                                              &sigKeyBlock.sk.rsa.key,
04863                                              (int)ssh->ctx->privateKeySz);
04864             //ESP_LOGI("WOLFSSH", "RSAPrivKey: %p (%d)", ssh->ctx->privateKey, (int)ssh->ctx->privateKeySz);
04865             //ESP_LOGI("WOLFSSH", "wc_RsaPrivateKeyDecode ret=%d", ret);
04866             /* Flatten the public key into mpint values for the hash. */
04867             if (ret == 0)
04868                 ret = wc_RsaFlattenPublicKey(&sigKeyBlock.sk.rsa.key,
04869                                              sigKeyBlock.sk.rsa.e,
04870                                              &sigKeyBlock.sk.rsa.eSz,
04871                                              sigKeyBlock.sk.rsa.n,
04872                                              &sigKeyBlock.sk.rsa.nSz);
04873             //ESP_LOGI("WOLFSSH", "wc_RsaFlattenPublicKey ret=%d", ret);
04874             if (ret == 0) {
04875                 /* Add a pad byte if the mpint has the MSB set. */
04876                 sigKeyBlock.sk.rsa.ePad = (sigKeyBlock.sk.rsa.e[0] & 0x80) ?
04877                                            1 : 0;
04878                 sigKeyBlock.sk.rsa.nPad = (sigKeyBlock.sk.rsa.n[0] & 0x80) ?
04879                                            1 : 0;
04880                 sigKeyBlock.sz = (LENGTH_SZ * 3) + sigKeyBlock.nameSz +
04881                                   sigKeyBlock.sk.rsa.eSz +
04882                                   sigKeyBlock.sk.rsa.ePad +
04883                                   sigKeyBlock.sk.rsa.nSz +
04884                                   sigKeyBlock.sk.rsa.nPad;
04885                 c32toa(sigKeyBlock.sz, scratchLen);
04886                 /* Hash in the length of the public key block. */
04887                 ret = wc_HashUpdate(&ssh->handshake->hash,
04888                                     ssh->handshake->hashId,
04889                                     scratchLen, LENGTH_SZ);
04890                 //ESP_LOGI("WOLFSSH", "wc_HashUpdate ret=%d", ret);
04891             }
04892             /* Hash in the length of the key type string. */
04893             if (ret == 0) {
04894                 c32toa(sigKeyBlock.nameSz, scratchLen);
04895                 ret = wc_HashUpdate(&ssh->handshake->hash,
04896                                     ssh->handshake->hashId,
04897                                     scratchLen, LENGTH_SZ);
04898                 //ESP_LOGI("WOLFSSH", "wc_HashUpdate ret=%d", ret);
04899             }
04900             /* Hash in the key type string. */
04901             if (ret == 0)
04902                 ret = wc_HashUpdate(&ssh->handshake->hash,
04903                                     ssh->handshake->hashId,
04904                                     (byte*)sigKeyBlock.name,
04905                                     sigKeyBlock.nameSz);
04906             //ESP_LOGI("WOLFSSH", "wc_HashUpdate ret=%d", ret);
04907             /* Hash in the length of the RSA public key E value. */
04908             if (ret == 0) {
04909                 c32toa(sigKeyBlock.sk.rsa.eSz + sigKeyBlock.sk.rsa.ePad,
04910                        scratchLen);
04911                 ret = wc_HashUpdate(&ssh->handshake->hash,
04912                                     ssh->handshake->hashId,
04913                                     scratchLen, LENGTH_SZ);
04914                 //ESP_LOGI("WOLFSSH", "wc_HashUpdate ret=%d", ret);
04915             }
04916             /* Hash in the pad byte for the RSA public key E value. */
04917             if (ret == 0) {
04918                 if (sigKeyBlock.sk.rsa.ePad) {
04919                     scratchLen[0] = 0;
04920                     ret = wc_HashUpdate(&ssh->handshake->hash,
04921                                         ssh->handshake->hashId, scratchLen, 1);
04922                     //ESP_LOGI("WOLFSSH", "wc_HashUpdate ret=%d", ret);
04923                 }
04924             }
04925             /* Hash in the RSA public key E value. */
04926             if (ret == 0)
04927                 ret = wc_HashUpdate(&ssh->handshake->hash,
04928                                     ssh->handshake->hashId,
04929                                     sigKeyBlock.sk.rsa.e,
04930                                     sigKeyBlock.sk.rsa.eSz);
04931             //ESP_LOGI("WOLFSSH", "wc_HashUpdate ret=%d", ret);
04932             /* Hash in the length of the RSA public key N value. */
04933             if (ret == 0) {
04934                 c32toa(sigKeyBlock.sk.rsa.nSz + sigKeyBlock.sk.rsa.nPad,
04935                        scratchLen);
04936                 ret = wc_HashUpdate(&ssh->handshake->hash,
04937                                     ssh->handshake->hashId,
04938                                     scratchLen, LENGTH_SZ);
04939                 //ESP_LOGI("WOLFSSH", "wc_HashUpdate ret=%d", ret);
04940             }
04941             /* Hash in the pad byte for the RSA public key N value. */
04942             if (ret == 0) {
04943                 if (sigKeyBlock.sk.rsa.nPad) {
04944                     scratchLen[0] = 0;
04945                     ret = wc_HashUpdate(&ssh->handshake->hash,
04946                                         ssh->handshake->hashId, scratchLen, 1);
04947                     //ESP_LOGI("WOLFSSH", "wc_HashUpdate ret=%d", ret);
04948                 }
04949             }
04950             /* Hash in the RSA public key N value. */
04951             if (ret == 0)
04952                 ret = wc_HashUpdate(&ssh->handshake->hash,
04953                                     ssh->handshake->hashId,
04954                                     sigKeyBlock.sk.rsa.n,
04955                                     sigKeyBlock.sk.rsa.nSz);
04956             //ESP_LOGI("WOLFSSH", "wc_HashUpdate ret=%d", ret);
04957         }
04958         else {
04959             //ESP_LOGI("WOLFSSH", "KeyBlock: Non-RSA");
04960             sigKeyBlock.sk.ecc.primeName =
04961                                        PrimeNameForId(ssh->handshake->pubKeyId);
04962             sigKeyBlock.sk.ecc.primeNameSz =
04963                                  (word32)strlen(sigKeyBlock.sk.ecc.primeName);
04964 
04965             /* Decode the user-configured ECDSA private key. */
04966             sigKeyBlock.sk.ecc.qSz = sizeof(sigKeyBlock.sk.ecc.q);
04967             ret = wc_ecc_init_ex(&sigKeyBlock.sk.ecc.key, ssh->ctx->heap,
04968                                  INVALID_DEVID);
04969             scratch = 0;
04970             if (ret == 0)
04971                 ret = wc_EccPrivateKeyDecode(ssh->ctx->privateKey, &scratch,
04972                                              &sigKeyBlock.sk.ecc.key,
04973                                              ssh->ctx->privateKeySz);
04974             /* Flatten the public key into x963 value for the exchange hash. */
04975             if (ret == 0)
04976                 ret = wc_ecc_export_x963(&sigKeyBlock.sk.ecc.key,
04977                                          sigKeyBlock.sk.ecc.q,
04978                                          &sigKeyBlock.sk.ecc.qSz);
04979             /* Hash in the length of the public key block. */
04980             if (ret == 0) {
04981                 sigKeyBlock.sz = (LENGTH_SZ * 3) +
04982                                  sigKeyBlock.nameSz +
04983                                  sigKeyBlock.sk.ecc.primeNameSz +
04984                                  sigKeyBlock.sk.ecc.qSz;
04985                 c32toa(sigKeyBlock.sz, scratchLen);
04986                 ret = wc_HashUpdate(&ssh->handshake->hash,
04987                                     ssh->handshake->hashId,
04988                                     scratchLen, LENGTH_SZ);
04989             }
04990             /* Hash in the length of the key type string. */
04991             if (ret == 0) {
04992                 c32toa(sigKeyBlock.nameSz, scratchLen);
04993                 ret = wc_HashUpdate(&ssh->handshake->hash,
04994                                     ssh->handshake->hashId,
04995                                     scratchLen, LENGTH_SZ);
04996             }
04997             /* Hash in the key type string. */
04998             if (ret == 0)
04999                 ret = wc_HashUpdate(&ssh->handshake->hash,
05000                                     ssh->handshake->hashId,
05001                                     (byte*)sigKeyBlock.name,
05002                                     sigKeyBlock.nameSz);
05003             /* Hash in the length of the name of the prime. */
05004             if (ret == 0) {
05005                 c32toa(sigKeyBlock.sk.ecc.primeNameSz, scratchLen);
05006                 ret = wc_HashUpdate(&ssh->handshake->hash,
05007                                     ssh->handshake->hashId,
05008                                     scratchLen, LENGTH_SZ);
05009             }
05010             /* Hash in the name of the prime. */
05011             if (ret == 0)
05012                 ret = wc_HashUpdate(&ssh->handshake->hash,
05013                                    ssh->handshake->hashId,
05014                                    (const byte*)sigKeyBlock.sk.ecc.primeName,
05015                                    sigKeyBlock.sk.ecc.primeNameSz);
05016             /* Hash in the length of the public key. */
05017             if (ret == 0) {
05018                 c32toa(sigKeyBlock.sk.ecc.qSz, scratchLen);
05019                 ret = wc_HashUpdate(&ssh->handshake->hash,
05020                                     ssh->handshake->hashId,
05021                                     scratchLen, LENGTH_SZ);
05022             }
05023             /* Hash in the public key. */
05024             if (ret == 0)
05025                 ret = wc_HashUpdate(&ssh->handshake->hash,
05026                                     ssh->handshake->hashId,
05027                                     sigKeyBlock.sk.ecc.q,
05028                                     sigKeyBlock.sk.ecc.qSz);
05029         }
05030 
05031         /* If using DH-GEX include the GEX specific values. */
05032         if (ssh->handshake->kexId == ID_DH_GEX_SHA256) {
05033             byte primeGroupPad = 0, generatorPad = 0;
05034 
05035             /* Hash in the client's requested minimum key size. */
05036             if (ret == 0) {
05037                 c32toa(ssh->handshake->dhGexMinSz, scratchLen);
05038                 ret = wc_HashUpdate(&ssh->handshake->hash,
05039                                     ssh->handshake->hashId,
05040                                     scratchLen, LENGTH_SZ);
05041             }
05042             //ESP_LOGI("WOLFSSH", "wc_HashUpdate(dhGexMinSz) ret=%d", ret);
05043             /* Hash in the client's requested preferred key size. */
05044             if (ret == 0) {
05045                 c32toa(ssh->handshake->dhGexPreferredSz, scratchLen);
05046                 ret = wc_HashUpdate(&ssh->handshake->hash,
05047                                     ssh->handshake->hashId,
05048                                     scratchLen, LENGTH_SZ);
05049             }
05050             //ESP_LOGI("WOLFSSH", "wc_HashUpdate(dhGexPreferredSz) ret=%d", ret);
05051             /* Hash in the client's requested maximum key size. */
05052             if (ret == 0) {
05053                 c32toa(ssh->handshake->dhGexMaxSz, scratchLen);
05054                 ret = wc_HashUpdate(&ssh->handshake->hash,
05055                                     ssh->handshake->hashId,
05056                                     scratchLen, LENGTH_SZ);
05057             }
05058             //ESP_LOGI("WOLFSSH", "wc_HashUpdate(dhGexMaxSz) ret=%d", ret);
05059             /* Add a pad byte if the mpint has the MSB set. */
05060             if (ret == 0) {
05061                 if (primeGroup[0] & 0x80)
05062                     primeGroupPad = 1;
05063 
05064                 /* Hash in the length of the GEX prime group. */
05065                 c32toa(primeGroupSz + primeGroupPad, scratchLen);
05066                 ret = wc_HashUpdate(&ssh->handshake->hash,
05067                                     ssh->handshake->hashId,
05068                                     scratchLen, LENGTH_SZ);
05069                 //ESP_LOGI("WOLFSSH", "wc_HashUpdate(primeGroupSz + primeGroupPad) ret=%d", ret);
05070             }
05071             /* Hash in the pad byte for the GEX prime group. */
05072             if (ret == 0) {
05073                 if (primeGroupPad) {
05074                     scratchLen[0] = 0;
05075                     ret = wc_HashUpdate(&ssh->handshake->hash,
05076                                         ssh->handshake->hashId,
05077                                         scratchLen, 1);
05078                     //ESP_LOGI("WOLFSSH", "wc_HashUpdate(primeGroupPad) ret=%d", ret);
05079                 }
05080             }
05081             /* Hash in the GEX prime group. */
05082             if (ret == 0)
05083                 ret  = wc_HashUpdate(&ssh->handshake->hash,
05084                                      ssh->handshake->hashId,
05085                                      primeGroup, primeGroupSz);
05086             //ESP_LOGI("WOLFSSH", "wc_HashUpdate(hasn in gex prime grp) ret=%d", ret);
05087             /* Add a pad byte if the mpint has the MSB set. */
05088             if (ret == 0) {
05089                 if (generator[0] & 0x80)
05090                     generatorPad = 1;
05091 
05092                 /* Hash in the length of the GEX generator. */
05093                 c32toa(generatorSz + generatorPad, scratchLen);
05094                 ret = wc_HashUpdate(&ssh->handshake->hash,
05095                                     ssh->handshake->hashId,
05096                                     scratchLen, LENGTH_SZ);
05097                 //ESP_LOGI("WOLFSSH", "wc_HashUpdate(add pad byte) ret=%d", ret);
05098             }
05099             /* Hash in the pad byte for the GEX generator. */
05100             if (ret == 0) {
05101                 if (generatorPad) {
05102                     scratchLen[0] = 0;
05103                     ret = wc_HashUpdate(&ssh->handshake->hash,
05104                                         ssh->handshake->hashId,
05105                                         scratchLen, 1);
05106                     //ESP_LOGI("WOLFSSH", "wc_HashUpdate(hash in the pad byte for gex gen) ret=%d", ret);
05107                 }
05108             }
05109             /* Hash in the GEX generator. */
05110             if (ret == 0)
05111                 ret = wc_HashUpdate(&ssh->handshake->hash,
05112                                     ssh->handshake->hashId,
05113                                     generator, generatorSz);
05114             //ESP_LOGI("WOLFSSH", "wc_HashUpdate(hash in the gex gen) ret=%d", ret);
05115         }
05116 
05117         /* Hash in the size of the client's DH e-value (ECDH Q-value). */
05118         if (ret == 0) {
05119             c32toa(ssh->handshake->eSz, scratchLen);
05120             ret = wc_HashUpdate(&ssh->handshake->hash, ssh->handshake->hashId,
05121                                 scratchLen, LENGTH_SZ);
05122             //ESP_LOGI("WOLFSSH", "wc_HashUpdate(client DH e-val size) ret=%d", ret);
05123         }
05124         /* Hash in the client's DH e-value (ECDH Q-value). */
05125         if (ret == 0)
05126             ret = wc_HashUpdate(&ssh->handshake->hash, ssh->handshake->hashId,
05127                                 ssh->handshake->e, ssh->handshake->eSz);
05128         //ESP_LOGI("WOLFSSH", "wc_HashUpdate(client DH e-val) ret=%d", ret);
05129 
05130         /* Make the server's DH f-value and the shared secret K. */
05131         /* Or make the server's ECDH private value, and the shared secret K. */
05132         if (ret == 0) {
05133             if (!useEcc) {
05134                 DhKey privKey;
05135                 byte y[256];
05136                 word32 ySz = sizeof(y);
05137 
05138                 ret = wc_InitDhKey(&privKey);
05139                 //ESP_LOGI("WOLFSSH", "wc_InitDhKey ret=%d", ret);
05140                 if (ret == 0)
05141                     ret = wc_DhSetKey(&privKey, primeGroup, primeGroupSz,
05142                                       generator, generatorSz);
05143                 //ESP_LOGI("WOLFSSH", "wc_DhSetKey ret=%d", ret);
05144                 if (ret == 0)
05145                     ret = wc_DhGenerateKeyPair(&privKey, ssh->rng,
05146                                                y, &ySz, f, &fSz);
05147                 //ESP_LOGI("WOLFSSH", "wc_DhGenerateKeyPair ret=%d", ret);
05148                 if (ret == 0)
05149                     ret = wc_DhAgree(&privKey, ssh->k, &ssh->kSz, y, ySz,
05150                                      ssh->handshake->e, ssh->handshake->eSz);
05151                 //ESP_LOGI("WOLFSSH", "wc_DhAgree ret=%d", ret);
05152                 ForceZero(y, ySz);
05153                 wc_FreeDhKey(&privKey);
05154             }
05155             else {
05156                 ecc_key pubKey;
05157                 ecc_key privKey;
05158                 int primeId = wcPrimeForId(ssh->handshake->kexId);
05159 
05160                 if (primeId == ECC_CURVE_INVALID)
05161                     ret = WS_INVALID_PRIME_CURVE;
05162 
05163                 if (ret == 0)
05164                     ret = wc_ecc_init_ex(&pubKey, ssh->ctx->heap,
05165                                          INVALID_DEVID);
05166                 if (ret == 0)
05167                     ret = wc_ecc_init_ex(&privKey, ssh->ctx->heap,
05168                                          INVALID_DEVID);
05169 
05170                 if (ret == 0)
05171                     ret = wc_ecc_import_x963_ex(ssh->handshake->e,
05172                                                 ssh->handshake->eSz,
05173                                                 &pubKey, primeId);
05174 
05175                 if (ret == 0)
05176                     ret = wc_ecc_make_key_ex(ssh->rng,
05177                                          wc_ecc_get_curve_size_from_id(primeId),
05178                                          &privKey, primeId);
05179                 if (ret == 0)
05180                     ret = wc_ecc_export_x963(&privKey, f, &fSz);
05181                 if (ret == 0)
05182                     ret = wc_ecc_shared_secret(&privKey, &pubKey,
05183                                                ssh->k, &ssh->kSz);
05184                 wc_ecc_free(&privKey);
05185                 wc_ecc_free(&pubKey);
05186             }
05187         }
05188 
05189         /* Hash in the server's DH f-value. */
05190         if (ret == 0) {
05191             fPad = (f[0] & 0x80) ? 1 : 0;
05192             c32toa(fSz + fPad, scratchLen);
05193             ret = wc_HashUpdate(&ssh->handshake->hash, ssh->handshake->hashId,
05194                                scratchLen, LENGTH_SZ);
05195             //ESP_LOGI("WOLFSSH", "wc_HashUpdate ret=%d", ret);
05196         }
05197         if (ret == 0) {
05198             if (fPad) {
05199                 scratchLen[0] = 0;
05200                 ret = wc_HashUpdate(&ssh->handshake->hash,
05201                                     ssh->handshake->hashId, scratchLen, 1);
05202                 //ESP_LOGI("WOLFSSH", "wc_HashUpdate ret=%d", ret);
05203             }
05204         }
05205         if (ret == 0)
05206             ret = wc_HashUpdate(&ssh->handshake->hash,
05207                                 ssh->handshake->hashId, f, fSz);
05208         //ESP_LOGI("WOLFSSH", "wc_HashUpdate ret=%d", ret);
05209 
05210         /* Hash in the shared secret K. */
05211         if (ret == 0) {
05212             kPad = (ssh->k[0] & 0x80) ? 1 : 0;
05213             c32toa(ssh->kSz + kPad, scratchLen);
05214             ret = wc_HashUpdate(&ssh->handshake->hash, ssh->handshake->hashId,
05215                                 scratchLen, LENGTH_SZ);
05216             //ESP_LOGI("WOLFSSH", "wc_HashUpdate ret=%d", ret);
05217         }
05218         if (ret == 0) {
05219             if (kPad) {
05220                 scratchLen[0] = 0;
05221                 ret = wc_HashUpdate(&ssh->handshake->hash,
05222                                     ssh->handshake->hashId, scratchLen, 1);
05223                 //ESP_LOGI("WOLFSSH", "wc_HashUpdate ret=%d", ret);
05224             }
05225         }
05226         if (ret == 0)
05227             ret = wc_HashUpdate(&ssh->handshake->hash, ssh->handshake->hashId,
05228                                 ssh->k, ssh->kSz);
05229         //ESP_LOGI("WOLFSSH", "wc_HashUpdate ret=%d", ret);
05230 
05231         /* Save the exchange hash value H, and session ID. */
05232         if (ret == 0)
05233             ret = wc_HashFinal(&ssh->handshake->hash,
05234                                ssh->handshake->hashId, ssh->h);
05235         //ESP_LOGI("WOLFSSH", "wc_HashUpdate ret=%d", ret);
05236         if (ret == 0) {
05237             ssh->hSz = wc_HashGetDigestSize(ssh->handshake->hashId);
05238             if (ssh->sessionIdSz == 0) {
05239                 WMEMCPY(ssh->sessionId, ssh->h, ssh->hSz);
05240                 ssh->sessionIdSz = ssh->hSz;
05241             }
05242         }
05243 
05244         if (ret != WS_SUCCESS)
05245             ret = WS_CRYPTO_FAILED;
05246         //ESP_LOGI("WOLFSSH", "overall ret ret=%d", ret);
05247     }
05248 
05249     /* Sign h with the server's private key. */
05250     if (ret == WS_SUCCESS) {
05251         wc_HashAlg digestHash;
05252         byte digest[WC_MAX_DIGEST_SIZE];
05253         byte sigHashId;
05254 
05255         sigHashId = HashForId(ssh->handshake->pubKeyId);
05256 
05257         ret = wc_HashInit(&digestHash, sigHashId);
05258         if (ret == 0)
05259             ret = wc_HashUpdate(&digestHash, sigHashId, ssh->h, ssh->hSz);
05260         if (ret == 0)
05261             ret = wc_HashFinal(&digestHash, sigHashId, digest);
05262         if (ret != 0)
05263             ret = WS_CRYPTO_FAILED;
05264 
05265         if (ret == WS_SUCCESS) {
05266             if (sigKeyBlock.useRsa) {
05267                 byte encSig[MAX_ENCODED_SIG_SZ];
05268                 word32 encSigSz;
05269 
05270                 encSigSz = wc_EncodeSignature(encSig, digest,
05271                                               wc_HashGetDigestSize(sigHashId),
05272                                               wc_HashGetOID(sigHashId));
05273                 if (encSigSz <= 0) {
05274                     WLOG(WS_LOG_DEBUG, "SendKexDhReply: Bad Encode Sig");
05275                     ret = WS_CRYPTO_FAILED;
05276                 }
05277                 else {
05278                     WLOG(WS_LOG_INFO, "Signing hash with RSA.");
05279                     sigSz = wc_RsaSSL_Sign(encSig, encSigSz, sig, sizeof(sig),
05280                                            &sigKeyBlock.sk.rsa.key, ssh->rng);
05281                     if (sigSz <= 0) {
05282                         WLOG(WS_LOG_DEBUG, "SendKexDhReply: Bad RSA Sign");
05283                         ret = WS_RSA_E;
05284                     }
05285                 }
05286             }
05287             else {
05288                 WLOG(WS_LOG_INFO, "Signing hash with ECDSA.");
05289                 sigSz = sizeof(sig);
05290                 ret = wc_ecc_sign_hash(digest, wc_HashGetDigestSize(sigHashId),
05291                                        sig, &sigSz,
05292                                        ssh->rng, &sigKeyBlock.sk.ecc.key);
05293                 if (ret != MP_OKAY) {
05294                     WLOG(WS_LOG_DEBUG, "SendKexDhReply: Bad ECDSA Sign");
05295                     ret = WS_ECC_E;
05296                 }
05297                 else {
05298                     byte r[257];
05299                     word32 rSz = sizeof(r);
05300                     byte rPad;
05301                     byte s[257];
05302                     word32 sSz = sizeof(s);
05303                     byte sPad;
05304 
05305                     ret = wc_ecc_sig_to_rs(sig, sigSz, r, &rSz, s, &sSz);
05306                     if (ret == 0) {
05307                         idx = 0;
05308                         rPad = (r[0] & 0x80) ? 1 : 0;
05309                         sPad = (s[0] & 0x80) ? 1 : 0;
05310                         sigSz = (LENGTH_SZ * 2) + rSz + rPad + sSz + sPad;
05311 
05312                         c32toa(rSz + rPad, sig + idx);
05313                         idx += LENGTH_SZ;
05314                         if (rPad)
05315                             sig[idx++] = 0;
05316                         WMEMCPY(sig + idx, r, rSz);
05317                         idx += rSz;
05318                         c32toa(sSz + sPad, sig + idx);
05319                         idx += LENGTH_SZ;
05320                         if (sPad)
05321                             sig[idx++] = 0;
05322                         WMEMCPY(sig + idx, s, sSz);
05323                     }
05324                 }
05325             }
05326         }
05327     }
05328 
05329     //ESP_LOGI("WOLFSSH", "Here??? %d", ret);
05330 
05331     if (sigKeyBlock.useRsa)
05332         wc_FreeRsaKey(&sigKeyBlock.sk.rsa.key);
05333     else
05334         wc_ecc_free(&sigKeyBlock.sk.ecc.key);
05335 
05336     sigBlockSz = (LENGTH_SZ * 2) + sigKeyBlock.nameSz + sigSz;
05337 
05338     if (ret == WS_SUCCESS)
05339         ret = GenerateKeys(ssh);
05340 
05341     /* Get the buffer, copy the packet data, once f is laid into the buffer,
05342      * add it to the hash and then add K. */
05343     if (ret == WS_SUCCESS) {
05344         payloadSz = MSG_ID_SZ + (LENGTH_SZ * 3) +
05345                     sigKeyBlock.sz + fSz + fPad + sigBlockSz;
05346         ret = PreparePacket(ssh, payloadSz);
05347     }
05348 
05349     if (ret == WS_SUCCESS) {
05350         output = ssh->outputBuffer.buffer;
05351         idx = ssh->outputBuffer.length;
05352 
05353         output[idx++] = msgId;
05354 
05355         /* Copy the rsaKeyBlock into the buffer. */
05356         c32toa(sigKeyBlock.sz, output + idx);
05357         idx += LENGTH_SZ;
05358         c32toa(sigKeyBlock.nameSz, output + idx);
05359         idx += LENGTH_SZ;
05360         WMEMCPY(output + idx, sigKeyBlock.name, sigKeyBlock.nameSz);
05361         idx += sigKeyBlock.nameSz;
05362         if (sigKeyBlock.useRsa) {
05363             c32toa(sigKeyBlock.sk.rsa.eSz + sigKeyBlock.sk.rsa.ePad,
05364                    output + idx);
05365             idx += LENGTH_SZ;
05366             if (sigKeyBlock.sk.rsa.ePad) output[idx++] = 0;
05367             WMEMCPY(output + idx, sigKeyBlock.sk.rsa.e, sigKeyBlock.sk.rsa.eSz);
05368             idx += sigKeyBlock.sk.rsa.eSz;
05369             c32toa(sigKeyBlock.sk.rsa.nSz + sigKeyBlock.sk.rsa.nPad,
05370                    output + idx);
05371             idx += LENGTH_SZ;
05372             if (sigKeyBlock.sk.rsa.nPad) output[idx++] = 0;
05373             WMEMCPY(output + idx, sigKeyBlock.sk.rsa.n, sigKeyBlock.sk.rsa.nSz);
05374             idx += sigKeyBlock.sk.rsa.nSz;
05375         }
05376         else {
05377             c32toa(sigKeyBlock.sk.ecc.primeNameSz, output + idx);
05378             idx += LENGTH_SZ;
05379             WMEMCPY(output + idx, sigKeyBlock.sk.ecc.primeName,
05380                     sigKeyBlock.sk.ecc.primeNameSz);
05381             idx += sigKeyBlock.sk.ecc.primeNameSz;
05382             c32toa(sigKeyBlock.sk.ecc.qSz, output + idx);
05383             idx += LENGTH_SZ;
05384             WMEMCPY(output + idx, sigKeyBlock.sk.ecc.q,
05385                     sigKeyBlock.sk.ecc.qSz);
05386             idx += sigKeyBlock.sk.ecc.qSz;
05387         }
05388 
05389         /* Copy the server's public key. F for DE, or Q_S for ECDH. */
05390         c32toa(fSz + fPad, output + idx);
05391         idx += LENGTH_SZ;
05392         if (fPad) output[idx++] = 0;
05393         WMEMCPY(output + idx, f, fSz);
05394         idx += fSz;
05395 
05396         /* Copy the signature of the exchange hash. */
05397         c32toa(sigBlockSz, output + idx);
05398         idx += LENGTH_SZ;
05399         c32toa(sigKeyBlock.nameSz, output + idx);
05400         idx += LENGTH_SZ;
05401         WMEMCPY(output + idx, sigKeyBlock.name, sigKeyBlock.nameSz);
05402         idx += sigKeyBlock.nameSz;
05403         c32toa(sigSz, output + idx);
05404         idx += LENGTH_SZ;
05405         WMEMCPY(output + idx, sig, sigSz);
05406         idx += sigSz;
05407 
05408         ssh->outputBuffer.length = idx;
05409 
05410         ret = BundlePacket(ssh);
05411     }
05412 
05413     if (ret == WS_SUCCESS)
05414         ret = SendNewKeys(ssh);
05415 
05416     WLOG(WS_LOG_DEBUG, "Leaving SendKexDhReply(), ret = %d", ret);
05417     return ret;
05418 }
05419 
05420 
05421 int SendNewKeys(WOLFSSH* ssh)
05422 {
05423     byte* output;
05424     word32 idx = 0;
05425     int ret = WS_SUCCESS;
05426 
05427     WLOG(WS_LOG_DEBUG, "Entering SendNewKeys()");
05428     if (ssh == NULL)
05429         ret = WS_BAD_ARGUMENT;
05430 
05431     if (ret == WS_SUCCESS)
05432         ret = PreparePacket(ssh, MSG_ID_SZ);
05433 
05434     if (ret == WS_SUCCESS) {
05435         output = ssh->outputBuffer.buffer;
05436         idx = ssh->outputBuffer.length;
05437 
05438         output[idx++] = MSGID_NEWKEYS;
05439 
05440         ssh->outputBuffer.length = idx;
05441 
05442         ret = BundlePacket(ssh);
05443     }
05444 
05445     if (ret == WS_SUCCESS)
05446         ret = SendBuffered(ssh);
05447 
05448     if (ret == WS_SUCCESS) {
05449         ssh->blockSz = ssh->handshake->blockSz;
05450         ssh->encryptId = ssh->handshake->encryptId;
05451         ssh->macSz = ssh->handshake->macSz;
05452         ssh->macId = ssh->handshake->macId;
05453         ssh->aeadMode = ssh->handshake->aeadMode;
05454         WMEMCPY(&ssh->keys, &ssh->handshake->keys, sizeof(Keys));
05455 
05456         switch (ssh->encryptId) {
05457             case ID_NONE:
05458                 WLOG(WS_LOG_DEBUG, "SNK: using cipher none");
05459                 break;
05460 
05461             case ID_AES128_CBC:
05462                 WLOG(WS_LOG_DEBUG, "SNK: using cipher aes128-cbc");
05463                 ret = wc_AesSetKey(&ssh->encryptCipher.aes,
05464                                   ssh->keys.encKey, ssh->keys.encKeySz,
05465                                   ssh->keys.iv, AES_ENCRYPTION);
05466                 break;
05467 
05468             case ID_AES128_GCM:
05469                 WLOG(WS_LOG_DEBUG, "SNK: using cipher aes128-gcm");
05470                 ret = wc_AesGcmSetKey(&ssh->encryptCipher.aes,
05471                                      ssh->keys.encKey, ssh->keys.encKeySz);
05472                 break;
05473 
05474             default:
05475                 WLOG(WS_LOG_DEBUG, "SNK: using cipher invalid");
05476                 ret = WS_INVALID_ALGO_ID;
05477         }
05478     }
05479 
05480     if (ret == WS_SUCCESS) {
05481         ssh->txCount = 0;
05482     }
05483 
05484     WLOG(WS_LOG_DEBUG, "Leaving SendNewKeys(), ret = %d", ret);
05485     return ret;
05486 }
05487 
05488 
05489 int SendKexDhGexRequest(WOLFSSH* ssh)
05490 {
05491     byte* output;
05492     word32 idx = 0;
05493     word32 payloadSz;
05494     int ret = WS_SUCCESS;
05495 
05496     WLOG(WS_LOG_DEBUG, "Entering SendKexDhGexRequest()");
05497     if (ssh == NULL)
05498         ret = WS_BAD_ARGUMENT;
05499 
05500     if (ret == WS_SUCCESS) {
05501         payloadSz = MSG_ID_SZ + (UINT32_SZ * 3);
05502         ret = PreparePacket(ssh, payloadSz);
05503     }
05504 
05505     if (ret == WS_SUCCESS) {
05506         output = ssh->outputBuffer.buffer;
05507         idx = ssh->outputBuffer.length;
05508 
05509         output[idx++] = MSGID_KEXDH_GEX_REQUEST;
05510 
05511         c32toa(ssh->handshake->dhGexMinSz, output + idx);
05512         idx += UINT32_SZ;
05513         c32toa(ssh->handshake->dhGexPreferredSz, output + idx);
05514         idx += UINT32_SZ;
05515         c32toa(ssh->handshake->dhGexMaxSz, output + idx);
05516         idx += UINT32_SZ;
05517 
05518         ssh->outputBuffer.length = idx;
05519 
05520         ret = BundlePacket(ssh);
05521     }
05522 
05523     if (ret == WS_SUCCESS)
05524         ret = SendBuffered(ssh);
05525 
05526     WLOG(WS_LOG_DEBUG, "Leaving SendKexDhGexRequest(), ret = %d", ret);
05527     return ret;
05528 }
05529 
05530 
05531 int SendKexDhGexGroup(WOLFSSH* ssh)
05532 {
05533     byte* output;
05534     word32 idx = 0;
05535     word32 payloadSz;
05536     const byte* primeGroup = dhPrimeGroup14;
05537     word32 primeGroupSz = dhPrimeGroup14Sz;
05538     const byte* generator = dhGenerator;
05539     word32 generatorSz = dhGeneratorSz;
05540     byte primePad = 0;
05541     byte generatorPad = 0;
05542     int ret = WS_SUCCESS;
05543 
05544     WLOG(WS_LOG_DEBUG, "Entering SendKexDhGexGroup()");
05545     if (ssh == NULL)
05546         ret = WS_BAD_ARGUMENT;
05547 
05548     if (primeGroup[0] & 0x80)
05549         primePad = 1;
05550 
05551     if (generator[0] & 0x80)
05552         generatorPad = 1;
05553 
05554     if (ret == WS_SUCCESS) {
05555         payloadSz = MSG_ID_SZ + (LENGTH_SZ * 2) +
05556                     primeGroupSz + primePad +
05557                     generatorSz + generatorPad;
05558         ret = PreparePacket(ssh, payloadSz);
05559     }
05560 
05561     if (ret == WS_SUCCESS) {
05562         output = ssh->outputBuffer.buffer;
05563         idx = ssh->outputBuffer.length;
05564 
05565         output[idx++] = MSGID_KEXDH_GEX_GROUP;
05566 
05567         c32toa(primeGroupSz + primePad, output + idx);
05568         idx += LENGTH_SZ;
05569 
05570         if (primePad) {
05571             output[idx] = 0;
05572             idx += 1;
05573         }
05574 
05575         WMEMCPY(output + idx, primeGroup, primeGroupSz);
05576         idx += primeGroupSz;
05577 
05578         c32toa(generatorSz + generatorPad, output + idx);
05579         idx += LENGTH_SZ;
05580 
05581         if (generatorPad) {
05582             output[idx] = 0;
05583             idx += 1;
05584         }
05585 
05586         WMEMCPY(output + idx, generator, generatorSz);
05587         idx += generatorSz;
05588 
05589         ssh->outputBuffer.length = idx;
05590 
05591         ret = BundlePacket(ssh);
05592     }
05593 
05594     if (ret == WS_SUCCESS)
05595         ret = SendBuffered(ssh);
05596 
05597     WLOG(WS_LOG_DEBUG, "Leaving SendKexDhGexGroup(), ret = %d", ret);
05598     return ret;
05599 }
05600 
05601 
05602 int SendKexDhInit(WOLFSSH* ssh)
05603 {
05604     byte* output;
05605     word32 idx = 0;
05606     word32 payloadSz;
05607     const byte* primeGroup = dhPrimeGroup14;
05608     word32 primeGroupSz = dhPrimeGroup14Sz;
05609     const byte* generator = dhGenerator;
05610     word32 generatorSz = dhGeneratorSz;
05611     int ret = WS_SUCCESS;
05612     byte msgId = MSGID_KEXDH_INIT;
05613     byte e[256];
05614     word32 eSz = sizeof(e);
05615     byte  ePad = 0;
05616 
05617     WLOG(WS_LOG_DEBUG, "Entering SendKexDhInit()");
05618 
05619     switch (ssh->handshake->kexId) {
05620         case ID_DH_GROUP1_SHA1:
05621             primeGroup = dhPrimeGroup1;
05622             primeGroupSz = dhPrimeGroup1Sz;
05623             break;
05624 
05625         case ID_DH_GROUP14_SHA1:
05626             /* This is the default case. */
05627             break;
05628 
05629         case ID_DH_GEX_SHA256:
05630             primeGroup = ssh->handshake->primeGroup;
05631             primeGroupSz = ssh->handshake->primeGroupSz;
05632             generator = ssh->handshake->generator;
05633             generatorSz = ssh->handshake->generatorSz;
05634             msgId = MSGID_KEXDH_GEX_INIT;
05635             break;
05636 
05637         case ID_ECDH_SHA2_NISTP256:
05638         case ID_ECDH_SHA2_NISTP384:
05639         case ID_ECDH_SHA2_NISTP521:
05640             ssh->handshake->useEcc = 1;
05641             msgId = MSGID_KEXECDH_INIT;
05642             break;
05643 
05644         default:
05645             WLOG(WS_LOG_DEBUG, "Invalid algo: %u", ssh->handshake->kexId);
05646             ret = WS_INVALID_ALGO_ID;
05647     }
05648 
05649 
05650     if (ret == WS_SUCCESS) {
05651         if (!ssh->handshake->useEcc) {
05652             DhKey* privKey = &ssh->handshake->privKey.dh;
05653 
05654             ret = wc_InitDhKey(privKey);
05655             if (ret == 0)
05656                 ret = wc_DhSetKey(privKey, primeGroup, primeGroupSz,
05657                                   generator, generatorSz);
05658             if (ret == 0)
05659                 ret = wc_DhGenerateKeyPair(privKey, ssh->rng,
05660                                            ssh->handshake->x,
05661                                            &ssh->handshake->xSz,
05662                                            e, &eSz);
05663         }
05664         else {
05665             ecc_key* privKey = &ssh->handshake->privKey.ecc;
05666             int primeId = wcPrimeForId(ssh->handshake->kexId);
05667 
05668             if (primeId == ECC_CURVE_INVALID)
05669                 ret = WS_INVALID_PRIME_CURVE;
05670 
05671             if (ret == 0)
05672                 ret = wc_ecc_init_ex(privKey, ssh->ctx->heap,
05673                                      INVALID_DEVID);
05674 
05675             if (ret == 0)
05676                 ret = wc_ecc_make_key_ex(ssh->rng,
05677                                      wc_ecc_get_curve_size_from_id(primeId),
05678                                      privKey, primeId);
05679             if (ret == 0)
05680                 ret = wc_ecc_export_x963(privKey, e, &eSz);
05681         }
05682 
05683         if (ret == 0)
05684             ret = WS_SUCCESS;
05685     }
05686 
05687     if (ret == WS_SUCCESS) {
05688         if (e[0] & 0x80)  {
05689             ePad = 1;
05690             ssh->handshake->e[0] = 0;
05691         }
05692         WMEMCPY(ssh->handshake->e + ePad, e, eSz);
05693         ssh->handshake->eSz = eSz + ePad;
05694 
05695         payloadSz = MSG_ID_SZ + LENGTH_SZ + eSz + ePad;
05696         ret = PreparePacket(ssh, payloadSz);
05697     }
05698 
05699     if (ret == WS_SUCCESS) {
05700         output = ssh->outputBuffer.buffer;
05701         idx = ssh->outputBuffer.length;
05702 
05703         output[idx++] = msgId;
05704 
05705         c32toa(eSz + ePad, output + idx);
05706         idx += LENGTH_SZ;
05707 
05708         if (ePad) {
05709             output[idx] = 0;
05710             idx += 1;
05711         }
05712 
05713         WMEMCPY(output + idx, e, eSz);
05714         idx += eSz;
05715 
05716         ssh->outputBuffer.length = idx;
05717 
05718         ret = BundlePacket(ssh);
05719     }
05720 
05721     if (ret == WS_SUCCESS)
05722         ret = SendBuffered(ssh);
05723 
05724     WLOG(WS_LOG_DEBUG, "Leaving SendKexDhInit(), ret = %d", ret);
05725     return ret;
05726 }
05727 
05728 
05729 int SendUnimplemented(WOLFSSH* ssh)
05730 {
05731     byte* output;
05732     word32 idx = 0;
05733     int ret = WS_SUCCESS;
05734 
05735     WLOG(WS_LOG_DEBUG,
05736          "Entering SendUnimplemented(), peerSeq = %u", ssh->peerSeq);
05737 
05738     if (ssh == NULL)
05739         ret = WS_BAD_ARGUMENT;
05740 
05741     if (ret == WS_SUCCESS)
05742         ret = PreparePacket(ssh, MSG_ID_SZ + LENGTH_SZ);
05743 
05744     if (ret == WS_SUCCESS) {
05745         output = ssh->outputBuffer.buffer;
05746         idx = ssh->outputBuffer.length;
05747 
05748         output[idx++] = MSGID_UNIMPLEMENTED;
05749         c32toa(ssh->peerSeq, output + idx);
05750         idx += UINT32_SZ;
05751 
05752         ssh->outputBuffer.length = idx;
05753 
05754         ret = BundlePacket(ssh);
05755     }
05756 
05757     if (ret == WS_SUCCESS)
05758         ret = SendBuffered(ssh);
05759 
05760     WLOG(WS_LOG_DEBUG, "Leaving SendUnimplemented(), ret = %d", ret);
05761     return ret;
05762 }
05763 
05764 
05765 int SendDisconnect(WOLFSSH* ssh, word32 reason)
05766 {
05767     byte* output;
05768     word32 idx = 0;
05769     int ret = WS_SUCCESS;
05770 
05771     if (ssh == NULL)
05772         ret = WS_BAD_ARGUMENT;
05773 
05774     if (ret == WS_SUCCESS)
05775         ret = PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ + (LENGTH_SZ * 2));
05776 
05777     if (ret == WS_SUCCESS) {
05778         output = ssh->outputBuffer.buffer;
05779         idx = ssh->outputBuffer.length;
05780 
05781         output[idx++] = MSGID_DISCONNECT;
05782         c32toa(reason, output + idx);
05783         idx += UINT32_SZ;
05784         c32toa(0, output + idx);
05785         idx += LENGTH_SZ;
05786         c32toa(0, output + idx);
05787         idx += LENGTH_SZ;
05788 
05789         ssh->outputBuffer.length = idx;
05790 
05791         ret = BundlePacket(ssh);
05792     }
05793 
05794     if (ret == WS_SUCCESS)
05795         ret = SendBuffered(ssh);
05796 
05797     return ret;
05798 }
05799 
05800 
05801 int SendIgnore(WOLFSSH* ssh, const unsigned char* data, word32 dataSz)
05802 {
05803     byte* output;
05804     word32 idx = 0;
05805     int ret = WS_SUCCESS;
05806 
05807     if (ssh == NULL || (data == NULL && dataSz > 0))
05808         ret = WS_BAD_ARGUMENT;
05809 
05810     if (ret == WS_SUCCESS)
05811         ret = PreparePacket(ssh, MSG_ID_SZ + LENGTH_SZ + dataSz);
05812 
05813     if (ret == WS_SUCCESS) {
05814         output = ssh->outputBuffer.buffer;
05815         idx = ssh->outputBuffer.length;
05816 
05817         output[idx++] = MSGID_IGNORE;
05818         c32toa(dataSz, output + idx);
05819         idx += LENGTH_SZ;
05820         if (dataSz > 0) {
05821             WMEMCPY(output + idx, data, dataSz);
05822             idx += dataSz;
05823         }
05824 
05825         ssh->outputBuffer.length = idx;
05826 
05827         ret = BundlePacket(ssh);
05828     }
05829 
05830     if (ret == WS_SUCCESS)
05831         ret = SendBuffered(ssh);
05832 
05833     return ret;
05834 }
05835 
05836 
05837 static const char cannedLangTag[] = "en-us";
05838 static const word32 cannedLangTagSz = sizeof(cannedLangTag) - 1;
05839 
05840 
05841 int SendDebug(WOLFSSH* ssh, byte alwaysDisplay, const char* msg)
05842 {
05843     word32 msgSz;
05844     byte* output;
05845     word32 idx = 0;
05846     int ret = WS_SUCCESS;
05847 
05848     if (ssh == NULL)
05849         ret = WS_BAD_ARGUMENT;
05850 
05851     if (ret == WS_SUCCESS) {
05852         msgSz = (msg != NULL) ? (word32)WSTRLEN(msg) : 0;
05853 
05854         ret = PreparePacket(ssh,
05855                             MSG_ID_SZ + BOOLEAN_SZ + (LENGTH_SZ * 2) +
05856                             msgSz + cannedLangTagSz);
05857     }
05858 
05859     if (ret == WS_SUCCESS) {
05860         output = ssh->outputBuffer.buffer;
05861         idx = ssh->outputBuffer.length;
05862 
05863         output[idx++] = MSGID_DEBUG;
05864         output[idx++] = (alwaysDisplay != 0);
05865         c32toa(msgSz, output + idx);
05866         idx += LENGTH_SZ;
05867         if (msgSz > 0) {
05868             WMEMCPY(output + idx, msg, msgSz);
05869             idx += msgSz;
05870         }
05871         c32toa(cannedLangTagSz, output + idx);
05872         idx += LENGTH_SZ;
05873         WMEMCPY(output + idx, cannedLangTag, cannedLangTagSz);
05874         idx += cannedLangTagSz;
05875 
05876         ssh->outputBuffer.length = idx;
05877 
05878         ret = BundlePacket(ssh);
05879     }
05880 
05881     if (ret == WS_SUCCESS)
05882         ret = SendBuffered(ssh);
05883 
05884     return ret;
05885 }
05886 
05887 
05888 int SendServiceRequest(WOLFSSH* ssh, byte serviceId)
05889 {
05890     const char* serviceName;
05891     word32 serviceNameSz;
05892     byte* output;
05893     word32 idx;
05894     int ret = WS_SUCCESS;
05895 
05896     WLOG(WS_LOG_DEBUG, "Entering SendServiceRequest()");
05897 
05898     if (ssh == NULL)
05899         ret = WS_BAD_ARGUMENT;
05900 
05901     if (ret == WS_SUCCESS) {
05902         serviceName = IdToName(serviceId);
05903         serviceNameSz = (word32)WSTRLEN(serviceName);
05904 
05905         ret = PreparePacket(ssh,
05906                             MSG_ID_SZ + LENGTH_SZ + serviceNameSz);
05907     }
05908 
05909     if (ret == WS_SUCCESS) {
05910         output = ssh->outputBuffer.buffer;
05911         idx = ssh->outputBuffer.length;
05912 
05913         output[idx++] = MSGID_SERVICE_REQUEST;
05914         c32toa(serviceNameSz, output + idx);
05915         idx += LENGTH_SZ;
05916         WMEMCPY(output + idx, serviceName, serviceNameSz);
05917         idx += serviceNameSz;
05918 
05919         ssh->outputBuffer.length = idx;
05920         ret = BundlePacket(ssh);
05921     }
05922 
05923     if (ret == WS_SUCCESS)
05924         ret = SendBuffered(ssh);
05925 
05926     WLOG(WS_LOG_DEBUG, "Leaving SendServiceRequest(), ret = %d", ret);
05927     return ret;
05928 }
05929 
05930 
05931 int SendServiceAccept(WOLFSSH* ssh, byte serviceId)
05932 {
05933     const char* serviceName;
05934     word32 serviceNameSz;
05935     byte* output;
05936     word32 idx;
05937     int ret = WS_SUCCESS;
05938 
05939     if (ssh == NULL)
05940         ret = WS_BAD_ARGUMENT;
05941 
05942     if (ret == WS_SUCCESS) {
05943         serviceName = IdToName(serviceId);
05944         serviceNameSz = (word32)WSTRLEN(serviceName);
05945         ret = PreparePacket(ssh, MSG_ID_SZ + LENGTH_SZ + serviceNameSz);
05946     }
05947 
05948     if (ret == WS_SUCCESS) {
05949         output = ssh->outputBuffer.buffer;
05950         idx = ssh->outputBuffer.length;
05951 
05952         output[idx++] = MSGID_SERVICE_ACCEPT;
05953         c32toa(serviceNameSz, output + idx);
05954         idx += LENGTH_SZ;
05955         WMEMCPY(output + idx, serviceName, serviceNameSz);
05956         idx += serviceNameSz;
05957 
05958         ssh->outputBuffer.length = idx;
05959 
05960         ret = BundlePacket(ssh);
05961     }
05962 
05963     if (ret == WS_SUCCESS)
05964         ret = SendUserAuthBanner(ssh);
05965 
05966     return ret;
05967 }
05968 
05969 
05970 static const char cannedAuths[] = "publickey,password";
05971 static const word32 cannedAuthsSz = sizeof(cannedAuths) - 1;
05972 
05973 
05974 int SendUserAuthRequest(WOLFSSH* ssh, byte authId)
05975 {
05976     byte* output;
05977     word32 idx;
05978     const char* authName;
05979     word32 authNameSz;
05980     const char* serviceName;
05981     word32 serviceNameSz;
05982     word32 payloadSz;
05983     int ret = WS_SUCCESS;
05984     WS_UserAuthData authData;
05985 
05986     WLOG(WS_LOG_DEBUG, "Entering SendUserAuthRequest()");
05987 
05988     if (ssh == NULL)
05989         ret = WS_BAD_ARGUMENT;
05990 
05991     if (ret == WS_SUCCESS) {
05992         if (authId == ID_USERAUTH_PASSWORD && ssh->ctx->userAuthCb != NULL) {
05993             WLOG(WS_LOG_DEBUG, "SUARPW: Calling the userauth callback");
05994             ret = ssh->ctx->userAuthCb(WOLFSSH_USERAUTH_PASSWORD,
05995                                        &authData, ssh->userAuthCtx);
05996             if (ret != WOLFSSH_USERAUTH_SUCCESS) {
05997                 WLOG(WS_LOG_DEBUG, "SUARPW: Couldn't get password");
05998                 ret = WS_FATAL_ERROR;
05999             }
06000         }
06001     }
06002 
06003     if (ret == WS_SUCCESS) {
06004         serviceName = IdToName(ID_SERVICE_CONNECTION);
06005         serviceNameSz = (word32)WSTRLEN(serviceName);
06006         authName = IdToName(authId);
06007         authNameSz = (word32)WSTRLEN(authName);
06008 
06009         payloadSz = MSG_ID_SZ + (LENGTH_SZ * 3) +
06010                     ssh->userNameSz + serviceNameSz + authNameSz;
06011 
06012         if (authId == ID_USERAUTH_PASSWORD) {
06013             payloadSz += BOOLEAN_SZ + LENGTH_SZ +
06014                          authData.sf.password.passwordSz;
06015         }
06016         else if (authId != ID_NONE)
06017             ret = WS_INVALID_ALGO_ID;
06018     }
06019 
06020     if (ret == WS_SUCCESS)
06021         ret = PreparePacket(ssh, payloadSz);
06022 
06023     if (ret == WS_SUCCESS) {
06024         output = ssh->outputBuffer.buffer;
06025         idx = ssh->outputBuffer.length;
06026 
06027         output[idx++] = MSGID_USERAUTH_REQUEST;
06028         c32toa(ssh->userNameSz, output + idx);
06029         idx += LENGTH_SZ;
06030         WMEMCPY(output + idx, ssh->userName, ssh->userNameSz);
06031         idx += ssh->userNameSz;
06032 
06033         c32toa(serviceNameSz, output + idx);
06034         idx += LENGTH_SZ;
06035         WMEMCPY(output + idx, serviceName, serviceNameSz);
06036         idx += serviceNameSz;
06037 
06038         c32toa(authNameSz, output + idx);
06039         idx += LENGTH_SZ;
06040         WMEMCPY(output + idx, authName, authNameSz);
06041         idx += authNameSz;
06042 
06043         if (authId == ID_USERAUTH_PASSWORD) {
06044             output[idx++] = 0; /* Boolean "FALSE" for password change */
06045             c32toa(authData.sf.password.passwordSz, output + idx);
06046             idx += LENGTH_SZ;
06047             WMEMCPY(output + idx, authData.sf.password.password,
06048                     authData.sf.password.passwordSz);
06049             idx += authData.sf.password.passwordSz;
06050         }
06051 
06052         ssh->outputBuffer.length = idx;
06053 
06054         ret = BundlePacket(ssh);
06055     }
06056 
06057     if (ret == WS_SUCCESS)
06058         ret = SendBuffered(ssh);
06059 
06060     WLOG(WS_LOG_DEBUG, "Leaving SendUserAuthRequest(), ret = %d", ret);
06061     return ret;
06062 }
06063 
06064 
06065 int SendUserAuthFailure(WOLFSSH* ssh, byte partialSuccess)
06066 {
06067     byte* output;
06068     word32 idx;
06069     int ret = WS_SUCCESS;
06070 
06071     WLOG(WS_LOG_DEBUG, "Entering SendUserAuthFailure()");
06072 
06073     if (ssh == NULL)
06074         ret = WS_BAD_ARGUMENT;
06075 
06076     if (ret == WS_SUCCESS)
06077         ret = PreparePacket(ssh,
06078                             MSG_ID_SZ + LENGTH_SZ +
06079                             cannedAuthsSz + BOOLEAN_SZ);
06080 
06081     if (ret == WS_SUCCESS) {
06082         output = ssh->outputBuffer.buffer;
06083         idx = ssh->outputBuffer.length;
06084 
06085         output[idx++] = MSGID_USERAUTH_FAILURE;
06086         c32toa(cannedAuthsSz, output + idx);
06087         idx += LENGTH_SZ;
06088         WMEMCPY(output + idx, cannedAuths, cannedAuthsSz);
06089         idx += cannedAuthsSz;
06090         output[idx++] = (partialSuccess != 0);
06091 
06092         ssh->outputBuffer.length = idx;
06093 
06094         ret = BundlePacket(ssh);
06095     }
06096 
06097     if (ret == WS_SUCCESS)
06098         ret = SendBuffered(ssh);
06099 
06100     return ret;
06101 }
06102 
06103 
06104 int SendUserAuthSuccess(WOLFSSH* ssh)
06105 {
06106     byte* output;
06107     word32 idx;
06108     int ret = WS_SUCCESS;
06109 
06110     if (ssh == NULL)
06111         ret = WS_BAD_ARGUMENT;
06112 
06113     if (ret == WS_SUCCESS)
06114         ret = PreparePacket(ssh, MSG_ID_SZ);
06115 
06116     if (ret == WS_SUCCESS) {
06117         output = ssh->outputBuffer.buffer;
06118         idx = ssh->outputBuffer.length;
06119 
06120         output[idx++] = MSGID_USERAUTH_SUCCESS;
06121 
06122         ssh->outputBuffer.length = idx;
06123 
06124         ret = BundlePacket(ssh);
06125     }
06126 
06127     if (ret == WS_SUCCESS)
06128         ret = SendBuffered(ssh);
06129 
06130     return ret;
06131 }
06132 
06133 
06134 int SendUserAuthPkOk(WOLFSSH* ssh,
06135                      const byte* algoName, word32 algoNameSz,
06136                      const byte* publicKey, word32 publicKeySz)
06137 {
06138     byte* output;
06139     word32 idx;
06140     int ret = WS_SUCCESS;
06141 
06142     if (ssh == NULL ||
06143         algoName == NULL || algoNameSz == 0 ||
06144         publicKey == NULL || publicKeySz == 0) {
06145 
06146         ret = WS_BAD_ARGUMENT;
06147     }
06148 
06149     if (ret == WS_SUCCESS)
06150         ret = PreparePacket(ssh, MSG_ID_SZ + (LENGTH_SZ * 2) +
06151                                  algoNameSz + publicKeySz);
06152 
06153     if (ret == WS_SUCCESS) {
06154         output = ssh->outputBuffer.buffer;
06155         idx = ssh->outputBuffer.length;
06156 
06157         output[idx++] = MSGID_USERAUTH_PK_OK;
06158         c32toa(algoNameSz, output + idx);
06159         idx += LENGTH_SZ;
06160         WMEMCPY(output + idx, algoName, algoNameSz);
06161         idx += algoNameSz;
06162         c32toa(publicKeySz, output + idx);
06163         idx += LENGTH_SZ;
06164         WMEMCPY(output + idx, publicKey, publicKeySz);
06165         idx += publicKeySz;
06166 
06167         ssh->outputBuffer.length = idx;
06168 
06169         ret = BundlePacket(ssh);
06170     }
06171 
06172     if (ret == WS_SUCCESS)
06173         ret = SendBuffered(ssh);
06174 
06175     return ret;
06176 }
06177 
06178 
06179 int SendUserAuthBanner(WOLFSSH* ssh)
06180 {
06181     byte* output;
06182     word32 idx;
06183     int ret = WS_SUCCESS;
06184     const char* banner;
06185     word32 bannerSz = 0;
06186 
06187     if (ssh == NULL)
06188         ret = WS_BAD_ARGUMENT;
06189 
06190     if (ssh->ctx->banner != NULL && ssh->ctx->bannerSz > 0) {
06191         banner = ssh->ctx->banner;
06192         bannerSz = ssh->ctx->bannerSz;
06193     }
06194 
06195     if (ret == WS_SUCCESS)
06196         ret = PreparePacket(ssh, MSG_ID_SZ + (LENGTH_SZ * 2) +
06197                             bannerSz + cannedLangTagSz);
06198 
06199     if (ret == WS_SUCCESS) {
06200         output = ssh->outputBuffer.buffer;
06201         idx = ssh->outputBuffer.length;
06202 
06203         output[idx++] = MSGID_USERAUTH_BANNER;
06204         c32toa(bannerSz, output + idx);
06205         idx += LENGTH_SZ;
06206         if (bannerSz > 0)
06207             WMEMCPY(output + idx, banner, bannerSz);
06208         idx += bannerSz;
06209         c32toa(cannedLangTagSz, output + idx);
06210         idx += LENGTH_SZ;
06211         WMEMCPY(output + idx, cannedLangTag, cannedLangTagSz);
06212         idx += cannedLangTagSz;
06213 
06214         ssh->outputBuffer.length = idx;
06215 
06216         ret = BundlePacket(ssh);
06217     }
06218 
06219     if (ret == WS_SUCCESS)
06220         ret = SendBuffered(ssh);
06221 
06222     return ret;
06223 }
06224 
06225 
06226 int SendRequestSuccess(WOLFSSH* ssh, int success)
06227 {
06228     byte* output;
06229     word32 idx;
06230     int ret = WS_SUCCESS;
06231 
06232     WLOG(WS_LOG_DEBUG, "Entering SendRequestSuccess(), %s",
06233          success ? "Success" : "Failure");
06234 
06235     if (ssh == NULL)
06236         ret = WS_BAD_ARGUMENT;
06237 
06238     if (ret == WS_SUCCESS)
06239         ret = PreparePacket(ssh, MSG_ID_SZ);
06240 
06241     if (ret == WS_SUCCESS) {
06242         output = ssh->outputBuffer.buffer;
06243         idx = ssh->outputBuffer.length;
06244 
06245         output[idx++] = success ?
06246                         MSGID_REQUEST_SUCCESS : MSGID_REQUEST_FAILURE;
06247 
06248         ssh->outputBuffer.length = idx;
06249 
06250         ret = BundlePacket(ssh);
06251     }
06252 
06253     if (ret == WS_SUCCESS)
06254         ret = SendBuffered(ssh);
06255 
06256     WLOG(WS_LOG_DEBUG, "Leaving SendRequestSuccess(), ret = %d", ret);
06257     return ret;
06258 }
06259 
06260 
06261 int SendChannelOpenSession(WOLFSSH* ssh,
06262                            word32 initialWindowSz, word32 maxPacketSz)
06263 {
06264     WOLFSSH_CHANNEL* newChannel;
06265     byte* output;
06266     const char* channelType;
06267     word32 channelTypeSz, channelId, idx;
06268     int ret = WS_SUCCESS;
06269 
06270     WLOG(WS_LOG_DEBUG, "Entering SendChannelOpenSession()");
06271 
06272     if (ssh == NULL)
06273         ret = WS_BAD_ARGUMENT;
06274 
06275     if (ret == WS_SUCCESS) {
06276         channelId = ssh->nextChannel;
06277         newChannel = ChannelNew(ssh, ID_CHANTYPE_SESSION,
06278                                 initialWindowSz, maxPacketSz);
06279         if (newChannel == NULL)
06280             ret = WS_MEMORY_E;
06281 
06282         if (ret == WS_SUCCESS)
06283             ret = ChannelAppend(ssh, newChannel);
06284     }
06285 
06286     if (ret == WS_SUCCESS) {
06287         channelType = IdToName(ID_CHANTYPE_SESSION);
06288         channelTypeSz = (word32)WSTRLEN(channelType);
06289 
06290         ret = PreparePacket(ssh, MSG_ID_SZ + LENGTH_SZ + channelTypeSz +
06291                                  (UINT32_SZ * 3));
06292     }
06293 
06294     if (ret == WS_SUCCESS) {
06295         output = ssh->outputBuffer.buffer;
06296         idx = ssh->outputBuffer.length;
06297 
06298         output[idx++] = MSGID_CHANNEL_OPEN;
06299         c32toa(channelTypeSz, output + idx);
06300         idx += LENGTH_SZ;
06301         WMEMCPY(output + idx, channelType, channelTypeSz);
06302         idx += channelTypeSz;
06303         c32toa(channelId, output + idx);
06304         idx += UINT32_SZ;
06305         c32toa(initialWindowSz, output + idx);
06306         idx += UINT32_SZ;
06307         c32toa(maxPacketSz, output + idx);
06308         idx += UINT32_SZ;
06309 
06310         ssh->outputBuffer.length = idx;
06311 
06312         ret = BundlePacket(ssh);
06313     }
06314 
06315     if (ret == WS_SUCCESS)
06316         ret = SendBuffered(ssh);
06317 
06318     WLOG(WS_LOG_DEBUG, "Leaving SendChannelOpenSession(), ret = %d", ret);
06319     return ret;
06320 }
06321 
06322 
06323 int SendChannelOpenConf(WOLFSSH* ssh)
06324 {
06325     byte* output;
06326     word32 idx;
06327     int ret = WS_SUCCESS;
06328     WOLFSSH_CHANNEL* channel;
06329 
06330     WLOG(WS_LOG_DEBUG, "Entering SendChannelOpenConf()");
06331 
06332     if (ssh == NULL)
06333         ret = WS_BAD_ARGUMENT;
06334 
06335     if (ret == WS_SUCCESS) {
06336         channel = ChannelFind(ssh, ssh->defaultPeerChannelId, FIND_PEER);
06337         if (channel == NULL)
06338             ret = WS_INVALID_CHANID;
06339     }
06340 
06341     if (ret == WS_SUCCESS)
06342         ret = PreparePacket(ssh, MSG_ID_SZ + (UINT32_SZ * 4));
06343 
06344     if (ret == WS_SUCCESS) {
06345         output = ssh->outputBuffer.buffer;
06346         idx = ssh->outputBuffer.length;
06347 
06348         output[idx++] = MSGID_CHANNEL_OPEN_CONF;
06349         c32toa(channel->peerChannel, output + idx);
06350         idx += UINT32_SZ;
06351         c32toa(channel->channel, output + idx);
06352         idx += UINT32_SZ;
06353         c32toa(channel->windowSz, output + idx);
06354         idx += UINT32_SZ;
06355         c32toa(channel->maxPacketSz, output + idx);
06356         idx += UINT32_SZ;
06357 
06358         ssh->outputBuffer.length = idx;
06359 
06360         ret = BundlePacket(ssh);
06361     }
06362 
06363     if (ret == WS_SUCCESS)
06364         ret = SendBuffered(ssh);
06365 
06366     WLOG(WS_LOG_DEBUG, "Leaving SendChannelOpenConf(), ret = %d", ret);
06367     return ret;
06368 }
06369 
06370 
06371 int SendChannelEof(WOLFSSH* ssh, word32 peerChannelId)
06372 {
06373     byte* output;
06374     word32 idx;
06375     int ret = WS_SUCCESS;
06376     WOLFSSH_CHANNEL* channel;
06377 
06378     WLOG(WS_LOG_DEBUG, "Entering SendChannelEof()");
06379 
06380     if (ssh == NULL)
06381         ret = WS_BAD_ARGUMENT;
06382 
06383     if (ret == WS_SUCCESS) {
06384         channel = ChannelFind(ssh, peerChannelId, FIND_PEER);
06385         if (channel == NULL)
06386             ret = WS_INVALID_CHANID;
06387     }
06388 
06389     if (ret == WS_SUCCESS)
06390         ret = PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ);
06391 
06392     if (ret == WS_SUCCESS) {
06393         output = ssh->outputBuffer.buffer;
06394         idx = ssh->outputBuffer.length;
06395 
06396         output[idx++] = MSGID_CHANNEL_EOF;
06397         c32toa(channel->peerChannel, output + idx);
06398         idx += UINT32_SZ;
06399 
06400         ssh->outputBuffer.length = idx;
06401 
06402         ret = BundlePacket(ssh);
06403     }
06404 
06405     if (ret == WS_SUCCESS)
06406         ret = SendBuffered(ssh);
06407 
06408     WLOG(WS_LOG_DEBUG, "Leaving SendChannelEof(), ret = %d", ret);
06409     return ret;
06410 }
06411 
06412 
06413 int SendChannelClose(WOLFSSH* ssh, word32 peerChannelId)
06414 {
06415     byte* output;
06416     word32 idx;
06417     int ret = WS_SUCCESS;
06418     WOLFSSH_CHANNEL* channel;
06419 
06420     WLOG(WS_LOG_DEBUG, "Entering SendChannelClose()");
06421 
06422     if (ssh == NULL)
06423         ret = WS_BAD_ARGUMENT;
06424 
06425     if (ret == WS_SUCCESS) {
06426         channel = ChannelFind(ssh, peerChannelId, FIND_PEER);
06427         if (channel == NULL)
06428             ret = WS_INVALID_CHANID;
06429     }
06430 
06431     if (ret == WS_SUCCESS)
06432         ret = PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ);
06433 
06434     if (ret == WS_SUCCESS) {
06435         output = ssh->outputBuffer.buffer;
06436         idx = ssh->outputBuffer.length;
06437 
06438         output[idx++] = MSGID_CHANNEL_CLOSE;
06439         c32toa(channel->peerChannel, output + idx);
06440         idx += UINT32_SZ;
06441 
06442         ssh->outputBuffer.length = idx;
06443 
06444         ret = BundlePacket(ssh);
06445     }
06446 
06447     if (ret == WS_SUCCESS)
06448         ret = SendBuffered(ssh);
06449 
06450     WLOG(WS_LOG_DEBUG, "Leaving SendChannelClose(), ret = %d", ret);
06451     return ret;
06452 }
06453 
06454 word32 min(word32 a, word32 b){
06455     return 0;
06456     }
06457 
06458 int SendChannelData(WOLFSSH* ssh, word32 peerChannel,
06459                     byte* data, word32 dataSz)
06460 {
06461     byte* output;
06462     word32 idx;
06463     int ret = WS_SUCCESS;
06464     WOLFSSH_CHANNEL* channel;
06465 
06466     WLOG(WS_LOG_DEBUG, "Entering SendChannelData()");
06467 
06468     if (ssh == NULL)
06469         ret = WS_BAD_ARGUMENT;
06470 
06471     if (ret == WS_SUCCESS) {
06472         if (ssh->isKeying)
06473             ret = WS_REKEYING;
06474     }
06475 
06476     if (ret == WS_SUCCESS) {
06477         channel = ChannelFind(ssh, peerChannel, FIND_PEER);
06478         if (channel == NULL) {
06479             WLOG(WS_LOG_DEBUG, "Invalid peer channel");
06480             ret = WS_INVALID_CHANID;
06481         }
06482     }
06483 
06484     if (ret == WS_SUCCESS) {
06485         word32 bound = min(channel->peerWindowSz, channel->peerMaxPacketSz);
06486 
06487         if (dataSz > bound) {
06488             WLOG(WS_LOG_DEBUG,
06489                  "Trying to send %u, client will only accept %u, limiting",
06490                  dataSz, bound);
06491             dataSz = bound;
06492         }
06493 
06494         ret = PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ + LENGTH_SZ + dataSz);
06495     }
06496 
06497     if (ret == WS_SUCCESS) {
06498         output = ssh->outputBuffer.buffer;
06499         idx = ssh->outputBuffer.length;
06500 
06501         output[idx++] = MSGID_CHANNEL_DATA;
06502         c32toa(channel->peerChannel, output + idx);
06503         idx += UINT32_SZ;
06504         c32toa(dataSz, output + idx);
06505         idx += LENGTH_SZ;
06506         WMEMCPY(output + idx, data, dataSz);
06507         idx += dataSz;
06508 
06509         ssh->outputBuffer.length = idx;
06510 
06511         ret = BundlePacket(ssh);
06512     }
06513 
06514     if (ret == WS_SUCCESS)
06515         ret = SendBuffered(ssh);
06516 
06517     if (ret == WS_SUCCESS) {
06518         WLOG(WS_LOG_INFO, "  dataSz = %u", dataSz);
06519         WLOG(WS_LOG_INFO, "  peerWindowSz = %u", channel->peerWindowSz);
06520         channel->peerWindowSz -= dataSz;
06521         WLOG(WS_LOG_INFO, "  update peerWindowSz = %u", channel->peerWindowSz);
06522         ret = dataSz;
06523     }
06524 
06525     WLOG(WS_LOG_DEBUG, "Leaving SendChannelData(), ret = %d", ret);
06526     return ret;
06527 }
06528 
06529 
06530 int SendChannelWindowAdjust(WOLFSSH* ssh, word32 peerChannel,
06531                             word32 bytesToAdd)
06532 {
06533     byte* output;
06534     word32 idx;
06535     int ret = WS_SUCCESS;
06536     WOLFSSH_CHANNEL* channel;
06537 
06538     WLOG(WS_LOG_DEBUG, "Entering SendChannelWindowAdjust()");
06539 
06540     if (ssh == NULL)
06541         ret = WS_BAD_ARGUMENT;
06542 
06543     channel = ChannelFind(ssh, peerChannel, FIND_PEER);
06544     if (channel == NULL) {
06545         WLOG(WS_LOG_DEBUG, "Invalid peer channel");
06546         ret = WS_INVALID_CHANID;
06547     }
06548     if (ret == WS_SUCCESS)
06549         ret = PreparePacket(ssh, MSG_ID_SZ + (UINT32_SZ * 2));
06550 
06551     if (ret == WS_SUCCESS) {
06552         output = ssh->outputBuffer.buffer;
06553         idx = ssh->outputBuffer.length;
06554 
06555         output[idx++] = MSGID_CHANNEL_WINDOW_ADJUST;
06556         c32toa(channel->peerChannel, output + idx);
06557         idx += UINT32_SZ;
06558         c32toa(bytesToAdd, output + idx);
06559         idx += UINT32_SZ;
06560 
06561         ssh->outputBuffer.length = idx;
06562 
06563         ret = BundlePacket(ssh);
06564     }
06565 
06566     if (ret == WS_SUCCESS)
06567         ret = SendBuffered(ssh);
06568 
06569     WLOG(WS_LOG_DEBUG, "Leaving SendChannelWindowAdjust(), ret = %d", ret);
06570     return ret;
06571 }
06572 
06573 
06574 static const char cannedShellName[] = "shell";
06575 static const word32 cannedShellNameSz = sizeof(cannedShellName) - 1;
06576 
06577 
06578 int SendChannelRequestShell(WOLFSSH* ssh)
06579 {
06580     byte* output;
06581     word32 idx;
06582     int ret = WS_SUCCESS;
06583     WOLFSSH_CHANNEL* channel;
06584 
06585     WLOG(WS_LOG_DEBUG, "Entering SendChannelRequestShell()");
06586 
06587     if (ssh == NULL)
06588         ret = WS_BAD_ARGUMENT;
06589 
06590     if (ret == WS_SUCCESS) {
06591         channel = ChannelFind(ssh, ssh->defaultPeerChannelId, FIND_PEER);
06592         if (channel == NULL)
06593             ret = WS_INVALID_CHANID;
06594     }
06595 
06596     if (ret == WS_SUCCESS)
06597         ret = PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ + LENGTH_SZ +
06598                                  cannedShellNameSz + BOOLEAN_SZ);
06599 
06600     if (ret == WS_SUCCESS) {
06601         output = ssh->outputBuffer.buffer;
06602         idx = ssh->outputBuffer.length;
06603 
06604         output[idx++] = MSGID_CHANNEL_REQUEST;
06605         c32toa(channel->peerChannel, output + idx);
06606         idx += UINT32_SZ;
06607         c32toa(cannedShellNameSz, output + idx);
06608         idx += LENGTH_SZ;
06609         WMEMCPY(output + idx, cannedShellName, cannedShellNameSz);
06610         idx += cannedShellNameSz;
06611         output[idx++] = 1;
06612 
06613         ssh->outputBuffer.length = idx;
06614 
06615         ret = BundlePacket(ssh);
06616     }
06617 
06618     if (ret == WS_SUCCESS)
06619         ret = SendBuffered(ssh);
06620 
06621     WLOG(WS_LOG_DEBUG, "Leaving SendChannelRequestShell(), ret = %d", ret);
06622     return ret;
06623 }
06624 
06625 
06626 int SendChannelSuccess(WOLFSSH* ssh, word32 channelId, int success)
06627 {
06628     byte* output;
06629     word32 idx;
06630     int ret = WS_SUCCESS;
06631     WOLFSSH_CHANNEL* channel;
06632 
06633     WLOG(WS_LOG_DEBUG, "Entering SendChannelSuccess(), %s",
06634          success ? "Success" : "Failure");
06635 
06636     if (ssh == NULL)
06637         ret = WS_BAD_ARGUMENT;
06638 
06639     if (ret == WS_SUCCESS) {
06640         channel = ChannelFind(ssh, channelId, FIND_SELF);
06641         if (channel == NULL) {
06642             WLOG(WS_LOG_DEBUG, "Invalid channel");
06643             ret = WS_INVALID_CHANID;
06644         }
06645     }
06646 
06647     if (ret == WS_SUCCESS)
06648         ret = PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ);
06649 
06650     if (ret == WS_SUCCESS) {
06651         output = ssh->outputBuffer.buffer;
06652         idx = ssh->outputBuffer.length;
06653 
06654         output[idx++] = success ?
06655                         MSGID_CHANNEL_SUCCESS : MSGID_CHANNEL_FAILURE;
06656         c32toa(channel->peerChannel, output + idx);
06657         idx += UINT32_SZ;
06658 
06659         ssh->outputBuffer.length = idx;
06660 
06661         ret = BundlePacket(ssh);
06662     }
06663 
06664     if (ret == WS_SUCCESS)
06665         ret = SendBuffered(ssh);
06666 
06667     WLOG(WS_LOG_DEBUG, "Leaving SendChannelSuccess(), ret = %d", ret);
06668     return ret;
06669 }
06670 
06671 
06672 #ifdef DEBUG_WOLFSSH
06673 
06674 #define LINE_WIDTH 16
06675 void DumpOctetString(const byte* input, word32 inputSz)
06676 {
06677     int rows = inputSz / LINE_WIDTH;
06678     int remainder = inputSz % LINE_WIDTH;
06679     int i,j;
06680 
06681     for (i = 0; i < rows; i++) {
06682         printf("%04X: ", i * LINE_WIDTH);
06683         for (j = 0; j < LINE_WIDTH; j++) {
06684             printf("%02X ", input[i * LINE_WIDTH + j]);
06685         }
06686         printf("\n");
06687     }
06688     if (remainder) {
06689         printf("%04X: ", i * LINE_WIDTH);
06690         for (j = 0; j < remainder; j++) {
06691             printf("%02X ", input[i * LINE_WIDTH + j]);
06692         }
06693         printf("\n");
06694     }
06695 }
06696 
06697 #endif