Merge pull request #291 from JacobBarthelmeh/sftp

add special case for real path and refactor clean_path
pull/301/head
John Safranek 2020-11-09 09:02:03 -08:00 committed by GitHub
commit ee139f8e0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 222 additions and 82 deletions

View File

@ -9508,12 +9508,26 @@ int SendChannelSuccess(WOLFSSH* ssh, word32 channelId, int success)
#if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \
!defined(NO_WOLFSSH_SERVER)
/* cleans up absolute path */
void clean_path(char* path)
/* cleans up absolute path
* returns size of new path on success (strlen sz) and negative values on fail*/
int wolfSSH_CleanPath(WOLFSSH* ssh, char* in)
{
int i;
long sz = (long)WSTRLEN(path);
long sz;
byte found;
char *path;
if (in == NULL) {
return WS_BAD_ARGUMENT;
}
sz = (long)WSTRLEN(in);
path = (char*)WMALLOC(sz+1, ssh->ctx->heap, DYNTYPE_PATH);
if (path == NULL) {
return WS_MEMORY_E;
}
WMEMCPY(path, in, sz);
path[sz] = '\0';
#if defined(WOLFSSL_NUCLEUS) || defined(USE_WINDOWS_API)
for (i = 0; i < sz; i++) {
@ -9643,6 +9657,18 @@ void clean_path(char* path)
}
#endif
}
/* copy result back to 'in' buffer */
if (WSTRLEN(in) < WSTRLEN(path)) {
WLOG(WS_LOG_ERROR, "Fatal error cleaning path");
WFREE(path, ssh->ctx->heap, DYNTYPE_PATH);
return WS_BUFFER_E;
}
sz = WSTRLEN(path);
WMEMCPY(in, path, sz);
in[sz] = '\0';
WFREE(path, ssh->ctx->heap, DYNTYPE_PATH);
return (int)sz;
}
#endif /* WOLFSSH_SFTP || WOLFSSH_SCP */

View File

@ -1054,9 +1054,11 @@ static int ScpCheckForRename(WOLFSSH* ssh, int cmdSz)
WSTRNCPY(buf, ssh->scpBasePath, cmdSz);
buf[sz] = '\0';
WSTRNCAT(buf, "/..", sizeof("/.."));
clean_path(buf);
idx = (int)WSTRLEN(buf) + 1; /* +1 for delimiter */
idx = wolfSSH_CleanPath(ssh, buf);
if (idx < 0) {
return WS_FATAL_ERROR;
}
idx = idx + 1; /* +1 for delimiter */
#ifdef WOLFSSL_NUCLEUS
/* no delimiter to skip in case of at base address */
if (idx == 4) { /* case of 4 for drive letter plus ":\" + 1 */
@ -1219,7 +1221,8 @@ int ParseScpCommand(WOLFSSH* ssh)
#endif
}
ret = ParseBasePathHelper(ssh, cmdSz);
clean_path((char*)ssh->scpBasePath);
if (wolfSSH_CleanPath(ssh, (char*)ssh->scpBasePath) < 0)
ret = WS_FATAL_ERROR;
break;
case 'f':
@ -1239,7 +1242,9 @@ int ParseScpCommand(WOLFSSH* ssh)
#else
ssh->scpBasePath = cmd + idx;
#endif
clean_path((char*)ssh->scpBasePath);
if (wolfSSH_CleanPath(ssh,
(char*)ssh->scpBasePath) < 0)
ret = WS_FATAL_ERROR;
}
break;
} /* end switch */
@ -1787,8 +1792,7 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath,
{
DSTAT stat;
clean_path((char*)basePath);
wolfSSH_CleanPath(ssh, (char*)basePath);
/* make sure is directory */
if ((ret = NU_Get_First(&stat, basePath)) != NU_SUCCESS) {
/* if back to root directory i.e. A:/ then handle case
@ -1830,7 +1834,7 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath,
WSTRNCAT(abslut, (char*)basePath, WOLFSSH_MAX_FILENAME);
WSTRNCAT(abslut, "/", WOLFSSH_MAX_FILENAME);
WSTRNCAT(abslut, fileName, WOLFSSH_MAX_FILENAME);
clean_path(abslut);
wolfSSH_CleanPath(ssh, abslut);
if (WFOPEN(&fp, abslut, "wb") != 0) {
#else
if (WFOPEN(&fp, fileName, "wb") != 0) {
@ -1888,7 +1892,7 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath,
WSTRNCAT(abslut, (char*)basePath, WOLFSSH_MAX_FILENAME);
WSTRNCAT(abslut, "/", WOLFSSH_MAX_FILENAME);
WSTRNCAT(abslut, fileName, WOLFSSH_MAX_FILENAME);
clean_path(abslut);
wolfSSH_CleanPath(ssh, abslut);
if (WMKDIR(ssh->fs, abslut, fileMode) != 0) {
/* check if directory already exists */
if (NU_Make_Dir(abslut) != NUF_EXIST) {
@ -1912,7 +1916,7 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath,
#ifdef WOLFSSL_NUCLEUS
WSTRNCAT((char*)basePath, "/", sizeof("/"));
WSTRNCAT((char*)basePath, fileName, WOLFSSH_MAX_FILENAME);
clean_path((char*)basePath);
wolfSSH_CleanPath(ssh, (char*)basePath);
#else
if (WCHDIR(fileName) != 0) {
wolfSSH_SetScpErrorMsg(ssh, "unable to cd into directory");
@ -1927,7 +1931,7 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath,
/* cd out of directory */
#ifdef WOLFSSL_NUCLEUS
WSTRNCAT((char*)basePath, "/..", WOLFSSH_MAX_FILENAME - 1);
clean_path((char*)basePath);
wolfSSH_CleanPath(ssh, (char*)basePath);
#else
if (WCHDIR("..") != 0) {
wolfSSH_SetScpErrorMsg(ssh, "unable to cd out of directory");
@ -2217,15 +2221,18 @@ static int ScpProcessEntry(WOLFSSH* ssh, char* fileName, word64* mTime,
DEFAULT_SCP_FILE_NAME_SZ);
WSTRNCPY(fileName, sendCtx->currentDir->dir.lfname,
DEFAULT_SCP_FILE_NAME_SZ);
clean_path(filePath);
if (wolfSSH_CleanPath(ssh, filePath) < 0) {
ret = WS_SCP_ABORT;
}
#else
WSTRNCAT(filePath, sendCtx->entry->d_name,
DEFAULT_SCP_FILE_NAME_SZ);
WSTRNCPY(fileName, sendCtx->entry->d_name,
DEFAULT_SCP_FILE_NAME_SZ);
#endif
ret = GetFileStats(sendCtx, filePath, mTime, aTime,
fileMode);
if (ret == WS_SUCCESS) {
ret = GetFileStats(sendCtx, filePath, mTime, aTime, fileMode);
}
}
}

View File

@ -1107,6 +1107,7 @@ static int wolfSSH_SFTP_RecvRealPath(WOLFSSH* ssh, int reqId, byte* data,
word32 rSz;
word32 lidx = 0;
word32 i;
int ret;
byte* out;
word32 outSz = 0;
@ -1168,8 +1169,19 @@ static int wolfSSH_SFTP_RecvRealPath(WOLFSSH* ssh, int reqId, byte* data,
WMEMCPY(r, wd, WOLFSSH_MAX_FILENAME);
}
clean_path(r);
rSz = (int)WSTRLEN(r);
if ((ret = wolfSSH_CleanPath(ssh, r)) < 0) {
return WS_FATAL_ERROR;
}
rSz = (word32)ret;
/* For real path remove ending case of /.
* Lots of peers send a '.' wanting a return of the current absolute path
* not the absolute path + .
*/
if (r[rSz - 2] == WS_DELIM && r[rSz - 1] == '.') {
r[rSz - 1] = '\0';
rSz -= 1;
}
/* for real path always send '/' chars */
for (i = 0; i < rSz; i++) {
@ -1572,12 +1584,17 @@ int wolfSSH_SFTP_RecvRMDIR(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
WMEMCPY(dir, data + idx, sz);
dir[sz] = '\0';
clean_path(dir);
#ifndef USE_WINDOWS_API
ret = WRMDIR(ssh->fs, dir);
#else /* USE_WINDOWS_API */
ret = WS_RemoveDirectoryA(dir, ssh->ctx->heap) == 0;
#endif /* USE_WINDOWS_API */
if (wolfSSH_CleanPath(ssh, dir) < 0) {
ret = WS_FATAL_ERROR;
}
if (ret == 0) {
#ifndef USE_WINDOWS_API
ret = WRMDIR(ssh->fs, dir);
#else /* USE_WINDOWS_API */
ret = WS_RemoveDirectoryA(dir, ssh->ctx->heap) == 0;
#endif /* USE_WINDOWS_API */
}
WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER);
res = (ret != 0)? err : suc;
@ -1671,7 +1688,12 @@ int wolfSSH_SFTP_RecvMKDIR(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
else {
ato32(data + idx, &mode);
}
clean_path(dir);
if (wolfSSH_CleanPath(ssh, dir) < 0) {
WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_FATAL_ERROR;
}
#ifndef USE_WINDOWS_API
ret = WMKDIR(ssh->fs, dir, mode);
#else /* USE_WINDOWS_API */
@ -1793,7 +1815,10 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
atr.per = 0644;
}
clean_path(dir);
if (wolfSSH_CleanPath(ssh, dir) < 0) {
WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_FATAL_ERROR;
}
fd = WOPEN(dir, m, atr.per);
if (fd < 0) {
WLOG(WS_LOG_SFTP, "Error opening file %s", dir);
@ -1925,7 +1950,10 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
}
#endif
clean_path(dir);
if (wolfSSH_CleanPath(ssh, dir) < 0) {
return WS_FATAL_ERROR;
}
fileHandle = WS_CreateFileA(dir, desiredAccess, 0, creationDisp,
FILE_ATTRIBUTE_NORMAL, ssh->ctx->heap);
if (fileHandle == INVALID_HANDLE_VALUE) {
@ -2038,7 +2066,11 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
dir[sz] = '\0';
/* get directory handle */
clean_path(dir);
if (wolfSSH_CleanPath(ssh, dir) < 0) {
WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_FATAL_ERROR;
}
if (WOPENDIR(ssh->fs, ssh->ctx->heap, &ctx, dir) != 0) {
WLOG(WS_LOG_SFTP, "Error with opening directory");
WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER);
@ -2140,7 +2172,10 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
}
WMEMCPY(dirName, data + idx, sz);
dirName[sz] = '\0';
clean_path(dirName);
if (wolfSSH_CleanPath(ssh, buf) < 0) {
WFREE(dirName, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_FATAL_ERROR;
}
/* get directory handle */
findHandle = (HANDLE)WS_FindFirstFileA(dirName,
@ -2403,7 +2438,12 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out,
}
WSTRNCAT(buf, out->fName, bufSz + 1);
clean_path(buf);
if (wolfSSH_CleanPath(ssh, buf) < 0) {
WLOG(WS_LOG_SFTP, "Error cleaning path to get attributes");
WFREE(buf, out->heap, DYNTYPE_SFTP);
return WS_FATAL_ERROR;
}
if (SFTP_GetAttributes(ssh->fs, buf, &out->atrb, 0, ssh->ctx->heap)
!= WS_SUCCESS) {
WLOG(WS_LOG_SFTP, "Unable to get attribute values for %s", buf);
@ -2490,7 +2530,11 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out,
}
WSTRNCAT(buf, out->fName, bufSz + 1);
clean_path(buf);
if (wolfSSH_CleanPath(ssh, buf) < 0) {
WFREE(buf, out->heap, DYNTYPE_SFTP);
return WS_FATAL_ERROR;
}
if (SFTP_GetAttributes(ssh->fs, buf, &out->atrb, 0, ssh->ctx->heap)
!= WS_SUCCESS) {
WLOG(WS_LOG_SFTP, "Unable to get attribute values for %s",
@ -2585,7 +2629,11 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out,
}
WSTRNCAT(buf, out->fName, bufSz + 1);
clean_path(buf);
if (wolfSSH_CleanPath(ssh, buf) < 0) {
WFREE(buf, out->heap, DYNTYPE_SFTP);
return WS_FATAL_ERROR;
}
if (SFTP_GetAttributes(ssh->fs, buf, &out->atrb, 0, ssh->ctx->heap)
!= WS_SUCCESS) {
WLOG(WS_LOG_SFTP, "Unable to get attribute values for %s",
@ -2659,7 +2707,11 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out,
}
WSTRNCAT(buf, out->fName, bufSz + 1);
clean_path(buf);
if (wolfSSH_CleanPath(ssh, buf) < 0) {
WFREE(buf, out->heap, DYNTYPE_SFTP);
return WS_FATAL_ERROR;
}
if (SFTP_GetAttributes(ssh->fs, buf, &out->atrb, 0, ssh->ctx->heap)
!= WS_SUCCESS) {
WLOG(WS_LOG_SFTP, "Unable to get attribute values for %s",
@ -3520,28 +3572,33 @@ int wolfSSH_SFTP_RecvRemove(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
WMEMCPY(name, data + idx, sz);
name[sz] = '\0';
clean_path(name);
#ifndef USE_WINDOWS_API
if ((ret = WREMOVE(ssh->fs, name)) < 0)
#else /* USE_WINDOWS_API */
if (WS_DeleteFileA(name, ssh->ctx->heap) == 0)
#endif /* USE_WINDOWS_API */
{
WLOG(WS_LOG_SFTP, "Error removing file");
#if defined(WOLFSSL_NUCLEUS) && defined(DEBUG_WOLFSSH)
if (ret == NUF_ACCES)
WLOG(WS_LOG_SFTP, "access error");
if (ret == NUF_BAD_USER)
WLOG(WS_LOG_SFTP, "bad user");
if (ret == NUF_IO_ERROR)
WLOG(WS_LOG_SFTP, "io error");
if (ret == NUF_NOFILE)
WLOG(WS_LOG_SFTP, "%s file not found", name);
#endif
if (wolfSSH_CleanPath(ssh, name) < 0) {
ret = WS_BAD_FILE_E;
}
else {
ret = WS_SUCCESS;
if (ret == WS_SUCCESS) {
#ifndef USE_WINDOWS_API
if ((ret = WREMOVE(ssh->fs, name)) < 0)
#else /* USE_WINDOWS_API */
if (WS_DeleteFileA(name, ssh->ctx->heap) == 0)
#endif /* USE_WINDOWS_API */
{
WLOG(WS_LOG_SFTP, "Error removing file");
#if defined(WOLFSSL_NUCLEUS) && defined(DEBUG_WOLFSSH)
if (ret == NUF_ACCES)
WLOG(WS_LOG_SFTP, "access error");
if (ret == NUF_BAD_USER)
WLOG(WS_LOG_SFTP, "bad user");
if (ret == NUF_IO_ERROR)
WLOG(WS_LOG_SFTP, "io error");
if (ret == NUF_NOFILE)
WLOG(WS_LOG_SFTP, "%s file not found", name);
#endif
ret = WS_BAD_FILE_E;
}
else {
ret = WS_SUCCESS;
}
}
/* Let the client know the results from trying to remove the file */
@ -3625,8 +3682,13 @@ int wolfSSH_SFTP_RecvRename(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
nw[sz] = '\0';
}
clean_path(old);
clean_path(nw);
if (wolfSSH_CleanPath(ssh, old) < 0) {
ret = WS_FATAL_ERROR;
}
if (wolfSSH_CleanPath(ssh, nw) < 0) {
ret = WS_FATAL_ERROR;
}
if (ret == WS_SUCCESS) {
#ifndef USE_WINDOWS_API
if (WRENAME(ssh->fs, old, nw) < 0)
@ -4314,21 +4376,31 @@ int wolfSSH_SFTP_RecvSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
name[sz] = '\0';
/* try to get file attributes and send back to client */
clean_path(name);
WMEMSET((byte*)&atr, 0, sizeof(WS_SFTP_FILEATRB));
if (SFTP_GetAttributes(ssh->fs, name, &atr, 0, ssh->ctx->heap)
!= WS_SUCCESS) {
WLOG(WS_LOG_SFTP, "Unable to get stat of file/directory");
if (wolfSSH_CleanPath(ssh, name) < 0) {
if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId,
"STAT error", "English", NULL, &outSz) != WS_SIZE_ONLY) {
WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_FATAL_ERROR;
}
ret = WS_BAD_FILE_E;
ret = WS_FATAL_ERROR;
}
else {
sz = SFTP_AtributesSz(ssh, &atr);
outSz = sz + WOLFSSH_SFTP_HEADER;
if (ret == WS_SUCCESS) {
WMEMSET((byte*)&atr, 0, sizeof(WS_SFTP_FILEATRB));
if (SFTP_GetAttributes(ssh->fs, name, &atr, 0, ssh->ctx->heap)
!= WS_SUCCESS) {
WLOG(WS_LOG_SFTP, "Unable to get stat of file/directory");
if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId,
"STAT error", "English", NULL, &outSz) != WS_SIZE_ONLY) {
WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_FATAL_ERROR;
}
ret = WS_BAD_FILE_E;
}
else {
sz = SFTP_AtributesSz(ssh, &atr);
outSz = sz + WOLFSSH_SFTP_HEADER;
}
}
WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER);
@ -4365,7 +4437,7 @@ int wolfSSH_SFTP_RecvLSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
{
WS_SFTP_FILEATRB atr;
char* name = NULL;
int ret;
int ret = WS_SUCCESS;
word32 sz;
word32 idx = 0;
@ -4391,24 +4463,34 @@ int wolfSSH_SFTP_RecvLSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
}
WMEMCPY(name, data + idx, sz);
name[sz] = '\0';
clean_path(name);
/* try to get file attributes and send back to client */
WMEMSET((byte*)&atr, 0, sizeof(WS_SFTP_FILEATRB));
if ((ret = SFTP_GetAttributes(ssh->fs, name, &atr, 1, ssh->ctx->heap))
!= WS_SUCCESS) {
/* tell peer that was not ok */
WLOG(WS_LOG_SFTP, "Unable to get lstat of file/directory");
if (wolfSSH_CleanPath(ssh, name) < 0) {
WLOG(WS_LOG_SFTP, "Unable to clean path");
if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId,
"LSTAT error", "English", NULL, &outSz) != WS_SIZE_ONLY) {
WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_FATAL_ERROR;
}
ret = WS_BAD_FILE_E;
ret = WS_FATAL_ERROR;
}
else {
sz = SFTP_AtributesSz(ssh, &atr);
outSz = sz + WOLFSSH_SFTP_HEADER;
/* try to get file attributes and send back to client */
if (ret == WS_SUCCESS) {
WMEMSET((byte*)&atr, 0, sizeof(WS_SFTP_FILEATRB));
if ((ret = SFTP_GetAttributes(ssh->fs, name, &atr, 1, ssh->ctx->heap))
!= WS_SUCCESS) {
/* tell peer that was not ok */
WLOG(WS_LOG_SFTP, "Unable to get lstat of file/directory");
if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId,
"LSTAT error", "English", NULL, &outSz) != WS_SIZE_ONLY) {
WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_FATAL_ERROR;
}
ret = WS_BAD_FILE_E;
}
else {
sz = SFTP_AtributesSz(ssh, &atr);
outSz = sz + WOLFSSH_SFTP_HEADER;
}
}
WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER);
@ -4531,9 +4613,12 @@ int wolfSSH_SFTP_RecvSetSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
}
WMEMCPY(name, data + idx, sz); idx += sz;
name[sz] = '\0';
clean_path(name);
if (wolfSSH_CleanPath(ssh, name) < 0) {
ret = WS_FATAL_ERROR;
}
if (SFTP_ParseAtributes_buffer(ssh, &atr, data, &idx, maxSz) != 0) {
if (ret == WS_SUCCESS &&
SFTP_ParseAtributes_buffer(ssh, &atr, data, &idx, maxSz) != 0) {
type = WOLFSSH_FTP_FAILURE;
res = per;
ret = WS_BAD_FILE_E;

View File

@ -56,7 +56,28 @@ static char inBuf[1024] = {0};
/* return 0 on success */
static int Expected(int command)
{
int i;
switch (command) {
case 3: /* pwd */
/* working directory should not contain a '.' at the end */
for (i = 0; i < (int)sizeof(inBuf); i++) {
if (inBuf[i] == '\n') {
inBuf[i] = '\0';
break;
}
}
if (inBuf[WSTRLEN(inBuf) - 2] != '/') {
printf("unexpected pwd of %s\n looking for '/'\n", inBuf);
return -1;
}
if (inBuf[WSTRLEN(inBuf) - 1] != 'a') {
printf("unexpected pwd of %s\n looking for 'a'\n", inBuf);
return -1;
}
break;
case 4:
{
char expt1[] = ".\n..\nwolfSSH sftp> ";

View File

@ -868,7 +868,8 @@ enum WS_DynamicTypes {
DYNTYPE_AGENT_KEY,
DYNTYPE_AGENT_BUFFER,
DYNTYPE_FILE,
DYNTYPE_TEMP
DYNTYPE_TEMP,
DYNTYPE_PATH
};
@ -945,7 +946,7 @@ WOLFSSH_LOCAL int wsScpSendCallback(WOLFSSH*, int, const char*, char*, word32,
#endif
WOLFSSH_LOCAL void clean_path(char* path);
WOLFSSH_LOCAL int wolfSSH_CleanPath(WOLFSSH* ssh, char* in);
WOLFSSH_LOCAL void DumpOctetString(const byte*, word32);
WOLFSSH_LOCAL int wolfSSH_oct2dec(WOLFSSH* ssh, byte* oct, word32 octSz);
WOLFSSH_LOCAL void AddAssign64(word32*, word32);