diff --git a/.github/workflows/sshd-test.yml b/.github/workflows/sshd-test.yml
new file mode 100644
index 000000000..42287a66f
--- /dev/null
+++ b/.github/workflows/sshd-test.yml
@@ -0,0 +1,32 @@
+name: wolfSSHd Test
+
+on:
+  push:
+    branches: [ '*' ]
+  pull_request:
+    branches: [ '*' ]
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@v2
+      with:
+          repository: wolfSSL/wolfssl.git
+          ref: master
+    - name: build wolfSSL
+      run: ./autogen.sh && ./configure --enable-all --prefix=/usr && make && sudo make install
+    - uses: actions/checkout@v2
+    - name: autogen
+      run: ./autogen.sh
+    - name: configure
+      run: ./configure --enable-all CPPFLAGS=-DWOLFSSH_NO_FPKI
+    - name: make
+      run: make
+    - name: make check
+      run: make check
+    - name: run wolfSSHd tests
+      run: sudo ./run_all_sshd_tests.sh
+      working-directory: ./apps/wolfsshd/test
diff --git a/apps/wolfssh/common.c b/apps/wolfssh/common.c
index 3945866c2..f83d135f7 100644
--- a/apps/wolfssh/common.c
+++ b/apps/wolfssh/common.c
@@ -66,7 +66,11 @@ static const byte publicKeyType[] = "x509v3-ecdsa-sha2-nistp256";
 #endif
 
 
-#if defined(WOLFSSH_CERTS)
+static inline void ato32(const byte* c, word32* u32)
+{
+    *u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
+}
+
 
 static int load_der_file(const char* filename, byte** out, word32* outSz)
 {
@@ -119,12 +123,9 @@ static int load_der_file(const char* filename, byte** out, word32* outSz)
 }
 
 
-#if (defined(OPENSSL_ALL) || defined(WOLFSSL_IP_ALT_NAME))
-static inline void ato32(const byte* c, word32* u32)
-{
-    *u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3];
-}
+#if defined(WOLFSSH_CERTS)
 
+#if (defined(OPENSSL_ALL) || defined(WOLFSSL_IP_ALT_NAME))
 /* when set as true then ignore miss matching IP addresses */
 static int IPOverride = 0;
 
@@ -186,20 +187,240 @@ void ClientIPOverride(int flag)
 #endif /* WOLFSSH_CERTS */
 
 
+static int AppendKeyToFile(const char* filename, const char* name,
+        const char* type, const char* key)
+{
+    WFILE *f;
+    int ret;
+
+    ret = WFOPEN(NULL, &f, filename, "a");
+    if (ret == 0 && f != WBADFILE) {
+        fprintf(f, "%s %s %s\n", name, type, key);
+        WFCLOSE(NULL, f);
+    }
+
+    return ret;
+}
+
+
+static int FingerprintKey(const byte* pubKey, word32 pubKeySz, char* out)
+{
+    wc_Sha256 sha;
+    byte digest[WC_SHA256_DIGEST_SIZE];
+    char fp[48] = { 0 };
+    word32 fpSz = sizeof(fp);
+    int ret;
+
+    ret = wc_InitSha256(&sha);
+    if (ret == 0)
+        ret = wc_Sha256Update(&sha, pubKey, pubKeySz);
+    if (ret == 0)
+        ret = wc_Sha256Final(&sha, digest);
+
+    if (ret == 0)
+        ret = Base64_Encode_NoNl(digest, sizeof(digest), (byte*)fp, &fpSz);
+
+    if (ret == 0) {
+        if (fp[fpSz] == '=') {
+            fp[fpSz] = 0;
+        }
+
+        WSTRCAT(out, "SHA256:");
+        WSTRCAT(out, fp);
+    }
+
+    return ret;
+}
+
+
+static int GetConfirmation(void)
+{
+    int c, confirmed = 0;
+
+    printf("Y/n: ");
+    c = getchar();
+
+    if (c == 'Y') {
+        confirmed = 1;
+    }
+
+    return confirmed;
+}
+
+
+#define WOLFSSH_CLIENT_ENCKEY_SIZE_ESTIMATE 1200
+#define WOLFSSH_CLIENT_PUBKEYTYPE_SIZE_ESTIMATE 54
+#define WOLFSSH_CLIENT_FINGERPRINT_SIZE_ESTIMATE 56
+
 int ClientPublicKeyCheck(const byte* pubKey, word32 pubKeySz, void* ctx)
 {
-    int ret = 0;
+    char *cursor;
+    char *line;
+    const char *targetName = (const char*)ctx;
+    char *name;
+    char *keyType;
+    char *key;
+    char *knownHosts = NULL;
+    char *knownHostsName = NULL;
+    char *encodedKey = NULL;
+    char *pubKeyType = NULL;
+    char *fp = NULL;
+    int ret = 0, found = 0, badMatch = 0, otherMatch = 0;
+    word32 sz, lineCount = 0;
+
+    {
+        const char *defaultName = "/.ssh/known_hosts";
+        char *env;
+
+        env = getenv("HOME");
+        if (env != NULL) {
+            sz = (word32)(WSTRLEN(env) + WSTRLEN(defaultName) + 1);
+            knownHostsName = (char*)WMALLOC(sz, NULL, 0);
+            if (knownHostsName != NULL) {
+                WSTRCPY(knownHostsName, env);
+                WSTRCAT(knownHostsName, defaultName);
+            }
+        }
+        else
+            ret = -1;
+    }
 
-    #ifdef DEBUG_WOLFSSH
-        printf("Sample public key check callback\n"
-               "  public key = %p\n"
-               "  public key size = %u\n"
-               "  ctx = %s\n", pubKey, pubKeySz, (const char*)ctx);
-    #else
-        (void)pubKey;
-        (void)pubKeySz;
-        (void)ctx;
-    #endif
+    if (ret == 0) {
+        sz = 0;
+        ret = load_der_file(knownHostsName, (byte**)&knownHosts, &sz);
+    }
+
+    if (ret == 0) {
+        if (sz < sizeof(word32)) {
+            /* This file is too small. There must be at least a word32
+             * length size. */
+            ret = -1;
+        }
+    }
+
+    if (ret == 0) {
+        /* load_der_file() loads exactly what's in the file. Since it is
+         * NL terminated lines of known host data, and the last line ends
+         * in a NL, overwrite that with a nul to terminate the new string. */
+        knownHosts[sz - 1] = 0;
+
+        encodedKey = (char*)WMALLOC(WOLFSSH_CLIENT_ENCKEY_SIZE_ESTIMATE
+                + WOLFSSH_CLIENT_PUBKEYTYPE_SIZE_ESTIMATE
+                + WOLFSSH_CLIENT_FINGERPRINT_SIZE_ESTIMATE, NULL, 0);
+        if (encodedKey == NULL) {
+            ret = -1;
+        }
+    }
+
+    if (ret == 0) {
+        pubKeyType = encodedKey + WOLFSSH_CLIENT_ENCKEY_SIZE_ESTIMATE;
+        fp = pubKeyType + WOLFSSH_CLIENT_PUBKEYTYPE_SIZE_ESTIMATE;
+
+        encodedKey[0] = 0;
+        pubKeyType[0] = 0;
+        fp[0] = 0;
+
+        /* Get the key type out of the key. */
+        ato32(pubKey, &sz);
+        if ((sz > pubKeySz - sizeof(word32))
+                    || (sz > WOLFSSH_CLIENT_PUBKEYTYPE_SIZE_ESTIMATE - 1)) {
+            ret = -1;
+        }
+    }
+
+    if (ret == 0) {
+        WMEMCPY(pubKeyType, pubKey + LENGTH_SZ, sz);
+        pubKeyType[sz] = 0;
+
+        sz = WOLFSSH_CLIENT_ENCKEY_SIZE_ESTIMATE;
+        ret = Base64_Encode_NoNl(pubKey, pubKeySz, (byte*)encodedKey, &sz);
+    }
+
+    if (ret == 0)
+        ret = FingerprintKey(pubKey, pubKeySz, fp);
+
+    cursor = (ret == 0) ? knownHosts : NULL;
+
+    while (cursor) {
+        lineCount++;
+        line = WSTRSEP(&cursor, "\n");
+        if (line != NULL && *line) {
+            name = WSTRSEP(&line, " ");
+            keyType = WSTRSEP(&line, " ");
+            key = WSTRSEP(&line, " ");
+            if (name && keyType && key) {
+                int nameMatch, keyTypeMatch, keyMatch;
+
+                nameMatch = WSTRCMP(targetName , name) == 0;
+                keyTypeMatch = WSTRCMP(pubKeyType, keyType) == 0;
+                keyMatch = WSTRCMP(encodedKey, key) == 0;
+
+                if (nameMatch) {
+                    if (keyTypeMatch) {
+                        if (keyMatch) {
+                            found = 1;
+                        }
+                        else {
+                            badMatch = 1;
+                        }
+                        break;
+                    }
+                }
+                else {
+                    if (keyTypeMatch && keyMatch) {
+                        /* report key used on different address */
+                        if (!otherMatch) {
+                            printf("Key fingerprint is %s.\n", fp);
+                            printf("This key matches other servers:\n");
+                            otherMatch = 1;
+                        }
+                        if (otherMatch) {
+                            printf("\t%s:%u: %s\n",
+                                    knownHostsName, lineCount, name);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    if (ret == 0) {
+        if (badMatch) {
+            printf("That server is known, but that key is not.\n");
+            printf("Rejecting connection and closing.\n");
+            ret = -1;
+        }
+        else if (otherMatch) {
+            if (!found) {
+                printf("Does this key look familiar to you?\n");
+                printf("Fingerprint: %s\n", fp);
+                printf("Shall I add it to the known hosts?\n");
+                /* Query. */
+                if (GetConfirmation()) {
+                    ret = AppendKeyToFile(knownHostsName,
+                            targetName, pubKeyType, encodedKey);
+                }
+                else {
+                    ret = -1;
+                }
+            }
+            else {
+                printf("This key matched multiple servers including %s.\n",
+                        targetName);
+                printf("Attempting to connect.\n");
+            }
+        }
+        else if (!found) {
+            printf("The server is unknown and the key is unknown.\n");
+            printf("Fingerprint: %s\n", fp);
+            printf("Shall I add it to the known hosts?\n");
+            /* Query. */
+            if (GetConfirmation()) {
+                ret = AppendKeyToFile(knownHostsName,
+                        targetName, pubKeyType, encodedKey);
+            }
+        }
+    }
 
 #ifdef WOLFSSH_CERTS
 #if defined(OPENSSL_ALL) || defined(WOLFSSL_IP_ALT_NAME)
@@ -260,6 +481,13 @@ int ClientPublicKeyCheck(const byte* pubKey, word32 pubKeySz, void* ctx)
 #endif
 #endif
 
+    if (encodedKey)
+        WFREE(encodedKey, NULL, 0);
+    if (knownHosts)
+        WFREE(knownHosts, NULL, 0);
+    if (knownHostsName)
+        WFREE(knownHostsName, NULL, 0);
+
     return ret;
 }
 
@@ -314,7 +542,7 @@ int ClientUserAuth(byte authType,
 
         if (defaultPassword != NULL) {
             passwordSz = (word32)strlen(defaultPassword);
-            memcpy(userPassword, defaultPassword, passwordSz);
+            WMEMCPY(userPassword, defaultPassword, passwordSz);
         }
         else {
             printf("Password: ");
@@ -379,7 +607,7 @@ int ClientSetEcho(int type)
             newTerm.c_lflag &= ~(ICANON | ECHOE | ECHOK | ECHONL | ISIG);
         }
         else {
-            newTerm.c_lflag |= (ICANON | ECHONL);
+            newTerm.c_lflag |= ICANON;
         }
 
         if (tcsetattr(STDIN_FILENO, TCSANOW, &newTerm) != 0) {
diff --git a/apps/wolfsshd/auth.c b/apps/wolfsshd/auth.c
index 4da1fb8d8..53722ee20 100644
--- a/apps/wolfsshd/auth.c
+++ b/apps/wolfsshd/auth.c
@@ -762,7 +762,7 @@ static int CheckPasswordWIN(const char* usr, const byte* pw, word32 pwSz, WOLFSS
 
     usrWSz = WSTRLEN(usr) * sizeof(WCHAR);
 
-    usrW = (WCHAR*)WMALLOC(usrWSz + 1, authCtx->heap, DYNTYPE_SSHD);
+    usrW = (WCHAR*)WMALLOC((usrWSz * sizeof(WCHAR)) + sizeof(WCHAR), authCtx->heap, DYNTYPE_SSHD);
     if (usrW == NULL) {
         wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Ran out of memory");
         ret = WSSHD_AUTH_FAILURE;
@@ -1363,6 +1363,12 @@ static int SetDefaultPublicKeyCheck(WOLFSSHD_AUTH* auth)
     return ret;
 }
 
+#ifndef WOLFSSH_SSHD_USER
+    #define WOLFSSH_SSHD_USER sshd
+#endif
+#define WOLFSSH_USER_GET_STRING(x) #x
+#define WOLFSSH_USER_STRING(x) WOLFSSH_USER_GET_STRING(x)
+
 static int SetDefualtUserID(WOLFSSHD_AUTH* auth)
 {
 #ifdef _WIN32
@@ -1370,13 +1376,13 @@ static int SetDefualtUserID(WOLFSSHD_AUTH* auth)
     return 0;
 #else
     struct passwd* pwInfo;
-    const char* usr = "sshd";
     int ret = WS_SUCCESS;
 
-    pwInfo = getpwnam(usr);
+    pwInfo = getpwnam(WOLFSSH_USER_STRING(WOLFSSH_SSHD_USER));
     if (pwInfo == NULL) {
         /* user name not found on system */
-        wolfSSH_Log(WS_LOG_INFO, "[SSHD] No sshd user found to use");
+        wolfSSH_Log(WS_LOG_INFO, "[SSHD] No %s user found to use",
+            WOLFSSH_USER_STRING(WOLFSSH_SSHD_USER));
         ret = WS_FATAL_ERROR;
     }
 
diff --git a/apps/wolfsshd/test/run_all_sshd_tests.sh b/apps/wolfsshd/test/run_all_sshd_tests.sh
index 638391d48..4c082d2cd 100755
--- a/apps/wolfsshd/test/run_all_sshd_tests.sh
+++ b/apps/wolfsshd/test/run_all_sshd_tests.sh
@@ -25,7 +25,7 @@ else
     start_wolfsshd "sshd_config_test"
     if [ -z "$PID" ]; then
         echo "Issue starting up wolfSSHd"
-        exit -1
+        exit 1
     fi
 fi
 
@@ -46,11 +46,12 @@ run_test() {
             printf "Shutting down test wolfSSHd\n"
             stop_wolfsshd
         fi
-        exit -1
+        exit 1
     fi
 }
 
 run_test "sshd_exec_test.sh"
+run_test "sshd_term_size_test.sh"
 
 # add aditional tests here, check on var USING_LOCAL_HOST if can make sshd
 # server start/restart with changes
diff --git a/apps/wolfsshd/test/sshd_login_grace_test.sh b/apps/wolfsshd/test/sshd_login_grace_test.sh
new file mode 100755
index 000000000..9e498d8cd
--- /dev/null
+++ b/apps/wolfsshd/test/sshd_login_grace_test.sh
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+# sshd local test
+
+if [ -z "$1" ] || [ -z "$2" ]; then
+    echo "expecting host and port as arguments"
+    echo "./sshd_exec_test.sh 127.0.0.1 22222"
+    exit 1
+fi
+
+PWD=`pwd`
+USER=`whoami`
+TEST_PORT="$2"
+TEST_HOST="$1"
+
+if [ -f ./log.txt ]; then
+    sudo rm -rf log.txt
+fi
+touch log.txt
+
+source ./start_sshd.sh
+cat <<EOF > sshd_config_test_login_grace
+Port $TEST_PORT
+Protocol 2
+LoginGraceTime 5
+PermitRootLogin yes
+PasswordAuthentication yes
+PermitEmptyPasswords no
+UsePrivilegeSeparation no
+UseDNS no
+HostKey $PWD/../../../keys/server-key.pem
+AuthorizedKeysFile $PWD/authorized_keys_test
+EOF
+
+start_wolfsshd "sshd_config_test_login_grace"
+pushd ../../..
+
+TEST_CLIENT="./examples/client/client"
+PRIVATE_KEY="./keys/hansel-key-ecc.der"
+PUBLIC_KEY="./keys/hansel-key-ecc.pub"
+
+RESULT=`$TEST_CLIENT -u $USER -i $PRIVATE_KEY -j $PUBLIC_KEY -h $TEST_HOST -p $TEST_PORT -c 'sleep 6 && echo still connected && exit'`
+echo "$RESULT" | grep "still connected"
+RESULT=$?
+if [ "$RESULT" != 0 ]; then
+    echo "FAIL: Connection was not held open"
+    exit 1
+fi
+
+# test grace login timeout by stalling on password prompt
+timeout 7 "$TEST_CLIENT" -u "$USER" -h "$TEST_HOST" -p "$TEST_PORT" -t
+
+popd
+cat ./log.txt | grep "Failed login within grace period"
+RESULT=$?
+if [ "$RESULT" != 0 ]; then
+    echo "FAIL: Grace period not hit"
+    exit 1
+fi
+
+stop_wolfsshd
+exit 0
+
+
diff --git a/apps/wolfsshd/test/sshd_term_size_test.sh b/apps/wolfsshd/test/sshd_term_size_test.sh
new file mode 100755
index 000000000..22d2f3a33
--- /dev/null
+++ b/apps/wolfsshd/test/sshd_term_size_test.sh
@@ -0,0 +1,98 @@
+#!/bin/bash
+
+# sshd local test
+
+pushd ../../..
+
+TEST_CLIENT="./examples/client/client"
+USER=`whoami`
+PRIVATE_KEY="./keys/hansel-key-ecc.der"
+PUBLIC_KEY="./keys/hansel-key-ecc.pub"
+
+if [ -z "$1" ] || [ -z "$2" ]; then
+    echo "expecting host and port as arguments"
+    echo "./sshd_exec_test.sh 127.0.0.1 22222"
+    exit 1
+fi
+
+set -e
+echo "Creating tmux session at $PWD with command :"
+tmux new-session -d -s test "$TEST_CLIENT -t -u $USER -i $PRIVATE_KEY -j $PUBLIC_KEY -h \"$1\" -p \"$2\""
+
+# give the command a second to establish SSH connection
+sleep 0.5
+
+COL=`tmux display -p -t test '#{pane_width}'`
+ROW=`tmux display -p -t test '#{pane_height}'`
+
+# get the terminals columns and lines
+tmux send-keys -t test 'echo col=$COLUMNS row=$LINES'
+tmux send-keys -t test 'ENTER'
+tmux capture-pane -t test
+RESULT=`tmux show-buffer | grep -v echo | grep -v rejecting | grep "col="`
+
+echo "$RESULT"
+echo ""
+echo ""
+ROW_FOUND=`echo "$RESULT" | sed -e 's/.*[^0-9]\([0-9]\+\)[^0-9]*$/\1/'`
+COL_FOUND=`echo "$RESULT" | sed -r 's/^[^0-9]*([0-9]+).*$/\1/'`
+
+if [ "$COL" != "$COL_FOUND" ]; then
+    echo "Col found was $COL_FOUND which does not match expected $COL"
+    exit 1
+fi
+
+if [ "$ROW" != "$ROW_FOUND" ]; then
+    echo "Row found was $ROW_FOUND which does not match expected $ROW"
+    exit 1
+fi
+
+# resize tmux after connection is open is not working @TODO
+#tmux set-window-option -g aggressive-resize
+#printf '\e[8;50;100t'
+#tmux resize-pane -x 50 -y 10 -t test
+
+# close down the SSH session
+tmux send-keys -t test 'exit'
+tmux send-keys -t test 'ENTER'
+set +e
+
+# kill off the session if it's still running, but don't error out if the session
+# has already closed down
+tmux kill-session -t test
+set -e
+
+tmux new-session -d -x 50 -y 10 -s test "$TEST_CLIENT -t -u $USER -i $PRIVATE_KEY -j $PUBLIC_KEY -h \"$1\" -p \"$2\""
+
+# give the command a second to establish SSH connection
+sleep 0.5
+
+echo "New COL=$COL ROW=$ROW"
+
+tmux send-keys -t test 'echo col=$COLUMNS row=$LINES'
+tmux send-keys -t test 'ENTER'
+tmux capture-pane -t test
+RESULT=`tmux show-buffer | grep -v echo | grep -v rejecting | grep "col="`
+
+ROW_FOUND=`echo "$RESULT" | sed -e 's/.*[^0-9]\([0-9]\+\)[^0-9]*$/\1/'`
+COL_FOUND=`echo "$RESULT" | sed -r 's/^[^0-9]*([0-9]+).*$/\1/'`
+
+if [ "50" != "$COL_FOUND" ]; then
+    echo "Col found was $COL_FOUND which does not match expected 50"
+    exit 1
+fi
+
+if [ "10" != "$ROW_FOUND" ]; then
+    echo "Row found was $ROW_FOUND which does not match expected 10"
+    exit 1
+fi
+
+# close down the SSH session
+tmux send-keys -t test 'exit'
+tmux send-keys -t test 'ENTER'
+set +e
+tmux kill-session -t test
+
+popd
+exit 0
+
diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c
index db48ea8d5..5a98e5cf4 100644
--- a/apps/wolfsshd/wolfsshd.c
+++ b/apps/wolfsshd/wolfsshd.c
@@ -1148,6 +1148,9 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
     return ret;
 }
 #else
+#if defined(HAVE_SYS_IOCTL_H)
+    #include <sys/ioctl.h>
+#endif
 
 /* handles creating a new shell env. and maintains SSH connection for incoming
  * user input as well as output of the shell.
@@ -1288,6 +1291,10 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
         exit(0); /* exit child process and close down SSH connection */
     }
 
+    /* do not wait for status of child process, and signal that the child can
+     * be reaped to avoid zombie processes when running in the foreground */
+    signal(SIGCHLD, SIG_IGN);
+
     if (wolfSSHD_AuthReducePermissionsUser(conn->auth, pPasswd->pw_uid,
         pPasswd->pw_gid) != WS_SUCCESS) {
         wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error setting user ID");
@@ -1314,6 +1321,21 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
         return WS_FATAL_ERROR;
     }
 
+    /* set initial size of terminal based on saved size */
+#if defined(HAVE_SYS_IOCTL_H)
+    {
+        struct winsize s;
+
+        WMEMSET(&s, 0, sizeof s);
+        s.ws_col = ssh->curX;
+        s.ws_row = ssh->curY;
+        s.ws_xpixel = ssh->curXP;
+        s.ws_ypixel = ssh->curYP;
+        ioctl(childFd, TIOCSWINSZ, &s);
+    }
+#endif
+
+    wolfSSH_SetTerminalResizeCtx(ssh, (void*)&childFd);
     while (ChildRunning) {
         byte tmp[2];
         fd_set readFds;
@@ -1509,6 +1531,14 @@ static void* HandleConnection(void* arg)
                 error = WS_FATAL_ERROR;
         }
 
+        if (graceTime > 0) {
+    #ifdef WIN32
+            /* @TODO SetTimer(NULL, NULL, graceTime, alarmCatch); */
+    #else
+            alarm(0); /* cancel any alarm */
+    #endif
+        }
+
         if (ret != WS_SUCCESS && ret != WS_SFTP_COMPLETE &&
             ret != WS_SCP_INIT) {
             wolfSSH_Log(WS_LOG_ERROR,
@@ -1671,6 +1701,7 @@ static void* HandleConnection(void* arg)
         WCLOSESOCKET(conn->fd);
     }
     wolfSSH_Log(WS_LOG_INFO, "[SSHD] Return from closing connection = %d", ret);
+    WFREE(conn, NULL, DYNTYPE_SSHD);
 
 #ifdef _WIN32
     return 0;
@@ -1703,6 +1734,11 @@ static int NewConnection(WOLFSSHD_CONNECTION* conn)
             exit(0);
         }
         else {
+            /* do not wait for status of child process, and signal that the
+               child can be reaped to avoid zombie processes when running in
+               the foreground */
+            signal(SIGCHLD, SIG_IGN);
+
             wolfSSH_Log(WS_LOG_INFO, "[SSHD] Spawned new process %d\n", pd);
             WCLOSESOCKET(conn->fd);
         }
@@ -1966,7 +2002,11 @@ static int StartSSHD(int argc, char** argv)
             break;
         #else
             ShowUsage();
+            #ifndef _WIN32
             return WS_FATAL_ERROR;
+            #else
+            return;
+            #endif
         #endif
 
         case 't':
@@ -2033,7 +2073,9 @@ static int StartSSHD(int argc, char** argv)
 
 #ifdef __unix__
         /* Daemonizing in POSIX, so set a syslog based log */
-        wolfSSH_SetLoggingCb(SyslogCb);
+        if (logFile == stderr) {
+            wolfSSH_SetLoggingCb(SyslogCb);
+        }
 #endif
         p = fork();
         if (p < 0) {
@@ -2144,27 +2186,33 @@ static int StartSSHD(int argc, char** argv)
     #endif
         /* wait for incoming connections and fork them off */
         while (ret == WS_SUCCESS && quit == 0) {
-            WOLFSSHD_CONNECTION conn;
+            WOLFSSHD_CONNECTION* conn;
 #ifdef WOLFSSL_NUCLEUS
             struct addr_struct clientAddr;
 #else
             SOCKADDR_IN_T clientAddr;
             socklen_t     clientAddrSz = sizeof(clientAddr);
 #endif
-            conn.auth = auth;
-            conn.listenFd = (int)listenFd;
-            conn.isThreaded = isDaemon;
+            conn = (WOLFSSHD_CONNECTION*)WMALLOC(sizeof(WOLFSSHD_CONNECTION), NULL, DYNTYPE_SSHD);
+            if (conn == NULL) {
+                wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Failed to malloc memory for connection");
+                break;
+            }
+
+            conn->auth = auth;
+            conn->listenFd = (int)listenFd;
+            conn->isThreaded = isDaemon;
 
             /* wait for a connection */
             if (PendingConnection(listenFd)) {
-                conn.ctx = ctx;
+                conn->ctx = ctx;
 #ifdef WOLFSSL_NUCLEUS
-                conn.fd = NU_Accept(listenFd, &clientAddr, 0);
+                conn->fd = NU_Accept(listenFd, &clientAddr, 0);
 #else
-                conn.fd = (int)accept(listenFd, (struct sockaddr*)&clientAddr,
+                conn->fd = (int)accept(listenFd, (struct sockaddr*)&clientAddr,
                     &clientAddrSz);
-                if (conn.fd >= 0) {
-                    inet_ntop(AF_INET, &clientAddr.sin_addr, conn.ip,
+                if (conn->fd >= 0) {
+                    inet_ntop(AF_INET, &clientAddr.sin_addr, conn->ip,
                         INET_ADDRSTRLEN);
                 }
 #endif
@@ -2172,7 +2220,7 @@ static int StartSSHD(int argc, char** argv)
                 {
 #ifdef USE_WINDOWS_API
                     unsigned long blocking = 1;
-                    if (ioctlsocket(conn.fd, FIONBIO, &blocking)
+                    if (ioctlsocket(conn->fd, FIONBIO, &blocking)
                         == SOCKET_ERROR)
                         err_sys("ioctlsocket failed");
 #elif defined(WOLFSSL_MDK_ARM) || defined(WOLFSSL_KEIL_TCP_NET) \
@@ -2180,15 +2228,15 @@ static int StartSSHD(int argc, char** argv)
                         defined(WOLFSSL_NUCLEUS)
                     /* non blocking not supported, for now */
 #else
-                    int flags = fcntl(conn.fd, F_GETFL, 0);
+                    int flags = fcntl(conn->fd, F_GETFL, 0);
                     if (flags < 0)
                         err_sys("fcntl get failed");
-                    flags = fcntl(conn.fd, F_SETFL, flags | O_NONBLOCK);
+                    flags = fcntl(conn->fd, F_SETFL, flags | O_NONBLOCK);
                     if (flags < 0)
                         err_sys("fcntl set failed");
 #endif
                 }
-                ret = NewConnection(&conn);
+                ret = NewConnection(conn);
             }
 #ifdef _WIN32
             /* check if service has been shutdown */
@@ -2258,7 +2306,7 @@ int main(int argc, char** argv)
         }
     }
     else {
-        StartSSHD(argc, (LPSTR*)argv);
+        StartSSHD(argc, (LPTSTR*)argv);
     }
     return 0;
 #else
diff --git a/configure.ac b/configure.ac
index 3d29d3aa8..280451af5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -50,6 +50,9 @@ AC_PROG_INSTALL
 AC_CHECK_SIZEOF([long long])
 AC_CHECK_SIZEOF([long])
 AC_CHECK_SIZEOF([off_t])
+AC_TYPE_SIZE_T
+AC_TYPE_UINT8_T
+AC_TYPE_UINTPTR_T
 
 # Check headers/libs
 AC_CHECK_HEADERS([sys/select.h sys/time.h sys/ioctl.h pty.h util.h termios.h])
diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c
index 3d141bf4c..63409c2f6 100644
--- a/examples/echoserver/echoserver.c
+++ b/examples/echoserver/echoserver.c
@@ -1142,8 +1142,9 @@ static int ssh_worker(thread_ctx_t* threadCtx)
 
 #ifdef WOLFSSH_SFTP
 
-#define TEST_SFTP_TIMEOUT_NONE 0
+#define TEST_SFTP_TIMEOUT_SHORT 0
 #define TEST_SFTP_TIMEOUT 1
+#define TEST_SFTP_TIMEOUT_LONG 60
 
 /* handle SFTP operations
  * returns 0 on success
@@ -1165,8 +1166,17 @@ static int sftp_worker(thread_ctx_t* threadCtx)
             /* Yes, process the SFTP data. */
             ret = wolfSSH_SFTP_read(ssh);
             error = wolfSSH_get_error(ssh);
-            timeout = (ret == WS_REKEYING) ?
-                TEST_SFTP_TIMEOUT : TEST_SFTP_TIMEOUT_NONE;
+
+            if (ret == WS_REKEYING) {
+                timeout = TEST_SFTP_TIMEOUT;
+            }
+            else if (error == WS_WINDOW_FULL) {
+                timeout = TEST_SFTP_TIMEOUT_LONG;
+            }
+            else {
+                timeout = TEST_SFTP_TIMEOUT_SHORT;
+            }
+
             if (error == WS_WANT_READ || error == WS_WANT_WRITE ||
                 error == WS_CHAN_RXD || error == WS_REKEYING ||
                 error == WS_WINDOW_FULL)
@@ -1184,6 +1194,10 @@ static int sftp_worker(thread_ctx_t* threadCtx)
         if (selected == WS_SELECT_ERROR_READY) {
             break;
         }
+        else if (selected == WS_SELECT_TIMEOUT) {
+            timeout = TEST_SFTP_TIMEOUT_LONG;
+            continue;
+        }
 
         if (ret == WS_WANT_READ || ret == WS_WANT_WRITE ||
                 selected == WS_SELECT_RECV_READY) {
@@ -1217,7 +1231,7 @@ static int sftp_worker(thread_ctx_t* threadCtx)
             ret = wolfSSH_SFTP_read(ssh);
             error = wolfSSH_get_error(ssh);
             timeout = (ret == WS_REKEYING) ?
-                TEST_SFTP_TIMEOUT : TEST_SFTP_TIMEOUT_NONE;
+                TEST_SFTP_TIMEOUT : TEST_SFTP_TIMEOUT_SHORT;
             if (error == WS_WANT_READ || error == WS_WANT_WRITE ||
                 error == WS_CHAN_RXD || error == WS_REKEYING ||
                 error == WS_WINDOW_FULL)
diff --git a/examples/sftpclient/sftpclient.c b/examples/sftpclient/sftpclient.c
index adbb5df53..9e1a7d4d7 100644
--- a/examples/sftpclient/sftpclient.c
+++ b/examples/sftpclient/sftpclient.c
@@ -523,6 +523,12 @@ static int doCmds(func_args* args)
 #endif
 
             if (ret != WS_SUCCESS) {
+                if (wolfSSH_get_error(ssh) == WS_SFTP_NOT_FILE_E) {
+                    if (SFTP_FPUTS(args, "Not a regular file\n")  < 0) {
+                         err_msg("fputs error");
+                         return -1;
+                    }
+                }
                 if (SFTP_FPUTS(args, "Error getting file\n")  < 0) {
                      err_msg("fputs error");
                      return -1;
@@ -628,6 +634,12 @@ static int doCmds(func_args* args)
 #endif
 
             if (ret != WS_SUCCESS) {
+                if (wolfSSH_get_error(ssh) == WS_SFTP_NOT_FILE_E) {
+                    if (SFTP_FPUTS(args, "Not a regular file\n")  < 0) {
+                         err_msg("fputs error");
+                         return -1;
+                    }
+                }
                 if (SFTP_FPUTS(args, "Error pushing file\n") < 0) {
                     err_msg("fputs error");
                     return -1;
diff --git a/keys/id_ecdsa b/keys/id_ecdsa
new file mode 100644
index 000000000..a73f1d4fe
--- /dev/null
+++ b/keys/id_ecdsa
@@ -0,0 +1,9 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
+1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTAqdBgCp8bYSq2kQQ48/Ud8Iy6Mjnb
+/fpB3LfSE/1kx9VaaE4FL3i9Gg2vDV0eLGM3PWksFNPhULxtcYJyjaBjAAAAqJAeleSQHp
+XkAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMCp0GAKnxthKraR
+BDjz9R3wjLoyOdv9+kHct9IT/WTH1VpoTgUveL0aDa8NXR4sYzc9aSwU0+FQvG1xgnKNoG
+MAAAAgPrOgktioNqad/wHNC/rt/zVrpNqDnOwg9tNDFMOTwo8AAAANYm9iQGxvY2FsaG9z
+dAECAw==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/keys/id_ecdsa.pub b/keys/id_ecdsa.pub
new file mode 100644
index 000000000..22fb1dc32
--- /dev/null
+++ b/keys/id_ecdsa.pub
@@ -0,0 +1 @@
+ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMCp0GAKnxthKraRBDjz9R3wjLoyOdv9+kHct9IT/WTH1VpoTgUveL0aDa8NXR4sYzc9aSwU0+FQvG1xgnKNoGM= bob@localhost
diff --git a/keys/id_rsa b/keys/id_rsa
new file mode 100644
index 000000000..b1cd15885
--- /dev/null
+++ b/keys/id_rsa
@@ -0,0 +1,27 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
+NhAAAAAwEAAQAAAQEAy2cigZDlpBT+X2MJHAoHnfeFf6+LHm6BDkAT8V9ejHA4dY0Aepb6
+NbV6u/oYZlueKPeAZ3GNztR9szoL6FSlMvkd9oqvfoxjTGu71T0981ybJelqqGATGtevHU
+6Jko/I0+lgSQFKWQJ7D3Dj2zlZpIXB2Q7xl/i9kFZgaIqFhUHdWO9JMOwCFwoDrhd8v5xk
+y1v3OIIZDxiYxVIKbf2J07WbwiSFAxXfiX8TjUBDLFmtqt1AF6LjAyGyaRICXkaGJQ/QJ9
+sX85h9bkiPlGNAtQGQtNUg3tC9GqOkZ9tCKY1Efh/r0zosOA7ufxg6ymLpq1C4LU/4ENGH
+kuRPAKvu8wAAA8gztJfmM7SX5gAAAAdzc2gtcnNhAAABAQDLZyKBkOWkFP5fYwkcCged94
+V/r4seboEOQBPxX16McDh1jQB6lvo1tXq7+hhmW54o94BncY3O1H2zOgvoVKUy+R32iq9+
+jGNMa7vVPT3zXJsl6WqoYBMa168dTomSj8jT6WBJAUpZAnsPcOPbOVmkhcHZDvGX+L2QVm
+BoioWFQd1Y70kw7AIXCgOuF3y/nGTLW/c4ghkPGJjFUgpt/YnTtZvCJIUDFd+JfxONQEMs
+Wa2q3UAXouMDIbJpEgJeRoYlD9An2xfzmH1uSI+UY0C1AZC01SDe0L0ao6Rn20IpjUR+H+
+vTOiw4Du5/GDrKYumrULgtT/gQ0YeS5E8Aq+7zAAAAAwEAAQAAAQEAvbdBiQXkGyn1pHST
+/5IfTqia3OCX6td5ChicQUsJvgXBs2rDopQFZmkRxBjd/0K+/0jyfAl/EgZCBBRFHPsuZp
+/S4ayzSV6aE6J8vMT1bnLWxwKyl7+csjGwRK6HRKtVzsnjI9TPSrw0mc9ax5PzV6/mgZUd
+o/i+nszh+UASj5mYrBGqMiINspzX6YC+qoUHor3rEJOd9p1aO+N5+1fDKiDnlkM5IO0Qsz
+GktuwL0fzv9zBnGfnWVJz3CorfP1OW5KCtrDn7BnkQf1eBeVLzq/uoglUjS4DNnVfLA67D
+O4ZfwtnoW8Gr2R+KdvnypvHnDeY5X51r5PDgL4+7z47pWQAAAIBNFcAzHHE19ISGN8YRHk
+23/r/3zfvzHU68GSKR1Xj/Y4LSdRTpSm3wBrdQ17f5B4V7RVl2CJvoPekTggnBDQlLJ7fU
+NU93/nZrY9teYdrNh03buL54VVb5tUM+KN+27zERlTj0/LmYJupN97sZXmlgKsvLbcsnM2
+i7HuQQaFnsIQAAAIEA5wqFVatT9yovt8pS7rAyYUL/cqc50TZ/5Nwfy5uasRyf1BphHwEW
+LEimBemVc+VrNwAkt6MFWuloK5ssqb1ubvtRI8Mntd15rRfZtq/foS3J8FJxueXLDWlECy
+PmVyfVN1Vv4ZeirBy9BTYLiSuxMes+HYks3HucQhxIN1j8SA0AAACBAOFgRjfWXv1/93Jp
+6CCJ5c98MWP+zu1FbLIlklxPb85osZqlazXHNPPEtblC4z+OqRGMCsv2683anU4ZzcTFIk
+JS3lzeJ3tdAH4osQ5etKkV4mcdCmeRpjudB9VbaziVhPX02qkPWpM0ckPrgB3hVNUDPz89
+GtJd3mlhyY5IfFL/AAAADWJvYkBsb2NhbGhvc3QBAgMEBQ==
+-----END OPENSSH PRIVATE KEY-----
diff --git a/keys/id_rsa.pub b/keys/id_rsa.pub
new file mode 100644
index 000000000..9cf541905
--- /dev/null
+++ b/keys/id_rsa.pub
@@ -0,0 +1 @@
+ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLZyKBkOWkFP5fYwkcCged94V/r4seboEOQBPxX16McDh1jQB6lvo1tXq7+hhmW54o94BncY3O1H2zOgvoVKUy+R32iq9+jGNMa7vVPT3zXJsl6WqoYBMa168dTomSj8jT6WBJAUpZAnsPcOPbOVmkhcHZDvGX+L2QVmBoioWFQd1Y70kw7AIXCgOuF3y/nGTLW/c4ghkPGJjFUgpt/YnTtZvCJIUDFd+JfxONQEMsWa2q3UAXouMDIbJpEgJeRoYlD9An2xfzmH1uSI+UY0C1AZC01SDe0L0ao6Rn20IpjUR+H+vTOiw4Du5/GDrKYumrULgtT/gQ0YeS5E8Aq+7z bob@localhost
diff --git a/keys/include.am b/keys/include.am
index 5f314bb05..cc2aa720f 100644
--- a/keys/include.am
+++ b/keys/include.am
@@ -22,5 +22,6 @@ EXTRA_DIST+= \
             keys/server-cert.der keys/server-cert.pem \
             keys/fred-cert.der keys/fred-cert.pem \
             keys/server-key.pem keys/fred-key.der keys/fred-key.pem \
+            keys/id_ecdsa keys/id_ecdsa.pub keys/id_rsa keys/id_rsa.pub \
             keys/renewcerts.sh keys/renewcerts.cnf
 
diff --git a/src/agent.c b/src/agent.c
index 9706706f0..f72b7185e 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -1553,7 +1553,7 @@ void wolfSSH_AGENT_ID_free(WOLFSSH_AGENT_ID* id, void* heap)
             WFREE(id->keyBuffer, heap, DYNTYPE_STRING);
         }
         WMEMSET(id, 0, sizeof(WOLFSSH_AGENT_ID));
-        WFREE(id, heap, DYNATYPE_AGENT_ID);
+        WFREE(id, heap, DYNTYPE_AGENT_ID);
     }
 
     WLOG(WS_LOG_AGENT, "Leaving wolfSSH_AGENT_ID_free()");
diff --git a/src/internal.c b/src/internal.c
index 098f51825..c68e136c0 100644
--- a/src/internal.c
+++ b/src/internal.c
@@ -137,6 +137,8 @@
     Set when all ECDH algorithms are disabled. Set to disable use of all ECDH
     algorithms for key agreement. Setting this will force all ECDH key agreement
     algorithms off.
+  WOLFSSH_KEY_QUANTITY_REQ
+    Number of keys required to be in an OpenSSH-style key wrapper.
 */
 
 static const char sshProtoIdStr[] = "SSH-2.0-wolfSSHv"
@@ -419,6 +421,18 @@ const char* GetErrorString(int err)
         case WS_MATCH_UA_KEY_ID_E:
             return "unable to match user auth key type";
 
+        case WS_KEY_AUTH_MAGIC_E:
+            return "key auth magic check error";
+
+        case WS_KEY_CHECK_VAL_E:
+            return "key check value error";
+
+        case WS_KEY_FORMAT_E:
+            return "key format wrong error";
+
+        case WS_SFTP_NOT_FILE_E:
+            return "not a regular file";
+
         default:
             return "Unknown error code";
     }
@@ -634,8 +648,9 @@ void CtxResourceFree(WOLFSSH_CTX* ctx)
 #ifdef WOLFSSH_TERM
 /* default terminal resize handling callbacks */
 
-#if defined(USE_WINDOWS_API) && defined(WOLFSSH_SSHD)
-static int WS_WindowsTermResize(WOLFSSH* ssh, word32 col, word32 row, word32 colP,
+#if defined(WOLFSSH_SSHD) && !defined(WOLFSSH_RESIZE_NO_DEFUALT)
+#if defined(USE_WINDOWS_API)
+static int WS_TermResize(WOLFSSH* ssh, word32 col, word32 row, word32 colP,
     word32 rowP, void* usrCtx)
 {
     HPCON* term = (HPCON*)usrCtx;
@@ -656,7 +671,33 @@ static int WS_WindowsTermResize(WOLFSSH* ssh, word32 col, word32 row, word32 col
 
     return ret;
 }
+#elif defined(HAVE_SYS_IOCTL_H)
+
+#include <sys/ioctl.h>
+static int WS_TermResize(WOLFSSH* ssh, word32 col, word32 row, word32 colP,
+    word32 rowP, void* usrCtx)
+{
+    struct winsize s;
+    int ret = WS_SUCCESS;
+    int* fd = (int*)usrCtx;
+
+    if (fd != NULL) {
+        WMEMSET(&s, 0, sizeof s);
+        s.ws_row = row;
+        s.ws_col = col;
+        s.ws_xpixel = colP;
+        s.ws_ypixel = rowP;
+
+        ioctl(*fd, TIOCSWINSZ, &s);
+    }
+
+    (void)ssh;
+    return ret;
+}
+#else
+    #define WOLFSSH_RESIZE_NO_DEFUALT
 #endif
+#endif /* WOLFSSH_SSHD */
 
 #endif /* WOLFSSH_TERM */
 
@@ -752,10 +793,10 @@ WOLFSSH* SshInit(WOLFSSH* ssh, WOLFSSH_CTX* ctx)
     ssh->agentEnabled = ctx->agentEnabled;
 #endif
 
-#ifdef WOLFSSH_TERM
-    #if defined(USE_WINDOWS_API) && defined(WOLFSSH_SSHD)
-    ssh->termResizeCb = WS_WindowsTermResize;
-    #endif
+#if defined(WOLFSSH_TERM) && defined(WOLFSSH_SSHD)
+#ifndef WOLFSSH_RESIZE_NO_DEFUALT
+    ssh->termResizeCb = WS_TermResize;
+#endif
 #endif
 
     if (BufferInit(&ssh->inputBuffer, 0, ctx->heap) != WS_SUCCESS  ||
@@ -845,21 +886,51 @@ void SshResourceFree(WOLFSSH* ssh, void* heap)
 #endif
 }
 
-union wolfSSH_key {
+
+typedef struct WS_KeySignature {
+    byte keySigId;
+    word32 sigSz;
+    const char *name;
+    word32 nameSz;
+    union {
 #ifndef WOLFSSH_NO_RSA
-    RsaKey rsa;
+        struct {
+            RsaKey key;
+        } rsa;
 #endif
 #ifndef WOLFSSH_NO_ECDSA
-    ecc_key ecc;
+        struct {
+            ecc_key key;
+        } ecc;
 #endif
-};
+    } ks;
+} WS_KeySignature;
+
+
+static void wolfSSH_KEY_clean(WS_KeySignature* key)
+{
+    if (key != NULL) {
+        if (key->keySigId == ID_SSH_RSA) {
+#ifndef WOLFSSH_NO_RSA
+            wc_FreeRsaKey(&key->ks.rsa.key);
+#endif
+        }
+        else if (key->keySigId == ID_ECDSA_SHA2_NISTP256 ||
+                key->keySigId == ID_ECDSA_SHA2_NISTP384 ||
+                key->keySigId == ID_ECDSA_SHA2_NISTP521) {
+#ifndef WOLFSSH_NO_ECDSA
+            wc_ecc_free(&key->ks.ecc.key);
+#endif
+        }
+    }
+}
 
 
 /*
- * Identifies the flavor of a key, RSA or ECDSA, and returns the key type ID.
- * The process is to decode the key as if it was RSA and if that fails try
- * to load it as if ECDSA. Both public and private keys can be decoded.
- * For RSA keys, the key format is described as "ssh-rsa".
+ * Identifies the flavor of an ASN.1 key, RSA or ECDSA, and returns the key
+ * type ID. The process is to decode the key as if it was RSA and if that
+ * fails try to load it as if ECDSA. Both public and private keys can be
+ * decoded. For RSA keys, the key format is described as "ssh-rsa".
  *
  * @param in        key to identify
  * @param inSz      size of key
@@ -867,88 +938,369 @@ union wolfSSH_key {
  * @param heap      heap to use for memory allocation
  * @return          keyId as int, WS_MEMORY_E, WS_UNIMPLEMENTED_E
  */
-int IdentifyKey(const byte* in, word32 inSz, int isPrivate, void* heap)
+int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap)
 {
-    union wolfSSH_key *key = NULL;
-    int keyId = ID_UNKNOWN;
+    WS_KeySignature *key = NULL;
     word32 idx;
     int ret;
     int dynType = isPrivate ? DYNTYPE_PRIVKEY : DYNTYPE_PUBKEY;
     WOLFSSH_UNUSED(dynType);
 
-    key = (union wolfSSH_key*)WMALLOC(sizeof(union wolfSSH_key), heap, dynType);
+    key = (WS_KeySignature*)WMALLOC(sizeof(WS_KeySignature), heap, dynType);
+
+    if (key == NULL) {
+        ret = WS_MEMORY_E;
+    }
+    else {
+        WMEMSET(key, 0, sizeof(*key));
+        key->keySigId = ID_UNKNOWN;
 
 #ifndef WOLFSSH_NO_RSA
-    if (key != NULL) {
         /* Check RSA key */
-        if (keyId == ID_UNKNOWN) {
+        if (key->keySigId == ID_UNKNOWN) {
             idx = 0;
-            ret = wc_InitRsaKey(&key->rsa, NULL);
+            ret = wc_InitRsaKey(&key->ks.rsa.key, NULL);
 
             if (ret == 0) {
                 if (isPrivate) {
-                    ret = wc_RsaPrivateKeyDecode(in, &idx, &key->rsa, inSz);
+                    ret = wc_RsaPrivateKeyDecode(in, &idx,
+                            &key->ks.rsa.key, inSz);
                 }
                 else {
-                    ret = wc_RsaPublicKeyDecode(in, &idx, &key->rsa, inSz);
+                    ret = wc_RsaPublicKeyDecode(in, &idx,
+                            &key->ks.rsa.key, inSz);
                 }
 
                 /* If decode was successful, this is an RSA key. */
                 if (ret == 0) {
-                    keyId = ID_SSH_RSA;
+                    key->keySigId = ID_SSH_RSA;
                 }
             }
 
-            wc_FreeRsaKey(&key->rsa);
+            wc_FreeRsaKey(&key->ks.rsa.key);
         }
-    }
 #endif /* WOLFSSH_NO_RSA */
 #ifndef WOLFSSH_NO_ECDSA
-    if (key != NULL) {
         /* Check ECDSA key */
-        if (keyId == ID_UNKNOWN) {
+        if (key->keySigId == ID_UNKNOWN) {
             idx = 0;
-            ret = wc_ecc_init_ex(&key->ecc, heap, INVALID_DEVID);
+            ret = wc_ecc_init_ex(&key->ks.ecc.key, heap, INVALID_DEVID);
 
             if (ret == 0) {
                 if (isPrivate) {
-                    ret = wc_EccPrivateKeyDecode(in, &idx, &key->ecc, inSz);
+                    ret = wc_EccPrivateKeyDecode(in, &idx,
+                            &key->ks.ecc.key, inSz);
                 }
                 else {
-                    ret = wc_EccPublicKeyDecode(in, &idx, &key->ecc, inSz);
+                    ret = wc_EccPublicKeyDecode(in, &idx,
+                            &key->ks.ecc.key, inSz);
                 }
 
                 /* If decode was successful, this is an ECDSA key. */
                 if (ret == 0) {
-                    switch (wc_ecc_get_curve_id(key->ecc.idx)) {
+                    switch (wc_ecc_get_curve_id(key->ks.ecc.key.idx)) {
                         case ECC_SECP256R1:
-                            keyId = ID_ECDSA_SHA2_NISTP256;
+                            key->keySigId = ID_ECDSA_SHA2_NISTP256;
                             break;
                         case ECC_SECP384R1:
-                            keyId = ID_ECDSA_SHA2_NISTP384;
+                            key->keySigId = ID_ECDSA_SHA2_NISTP384;
                             break;
                         case ECC_SECP521R1:
-                            keyId = ID_ECDSA_SHA2_NISTP521;
+                            key->keySigId = ID_ECDSA_SHA2_NISTP521;
                             break;
                     }
                 }
             }
 
-            wc_ecc_free(&key->ecc);
+            wc_ecc_free(&key->ks.ecc.key);
         }
-    }
 #endif /* WOLFSSH_NO_ECDSA */
 
+        if (key->keySigId == ID_UNKNOWN) {
+            ret = WS_UNIMPLEMENTED_E;
+        }
+        else {
+            ret = key->keySigId;
+        }
+
+        WFREE(key, heap, dynType);
+    }
+
+    return ret;
+}
+
+
+/*
+ * Utility function to read an Mpint from the stream directly into a mp_int.
+ */
+static INLINE int GetMpintToMp(mp_int* mp,
+        const byte* buf, word32 len, word32* idx)
+{
+    const byte* val = NULL;
+    word32 valSz = 0;
+    int ret;
+
+    ret = GetMpint(&valSz, &val, buf, len, idx);
+    if (ret == WS_SUCCESS)
+        ret = mp_read_unsigned_bin(mp, val, valSz);
+
+    return ret;
+}
+
+
+/*
+ * For the given RSA key, calculate p^-1 and q^-1. wolfCrypt's RSA
+ * code expects them, but the OpenSSH format key doesn't store them.
+ * TODO: Add a RSA read function to wolfCrypt to handle this condition.
+ */
+static INLINE int CalcRsaInverses(RsaKey* key)
+{
+    mp_int m;
+    int ret;
+
+    ret = mp_init(&m);
+    if (ret == MP_OKAY) {
+        ret = mp_sub_d(&key->p, 1, &m);
+        if (ret == MP_OKAY)
+            ret = mp_mod(&key->d, &m, &key->dP);
+        if (ret == MP_OKAY)
+            ret = mp_sub_d(&key->q, 1, &m);
+        if (ret == MP_OKAY)
+            ret = mp_mod(&key->d, &m, &key->dQ);
+        mp_forcezero(&m);
+    }
+
+    return ret;
+}
+
+
+/*
+ * Utility for GetOpenSshKey() to read in RSA keys.
+ */
+static int GetOpenSshKeyRsa(RsaKey* key,
+        const byte* buf, word32 len, word32* idx)
+{
+    int ret;
+
+    ret = wc_InitRsaKey(key, NULL);
+    if (ret == WS_SUCCESS)
+        ret = GetMpintToMp(&key->n, buf, len, idx);
+    if (ret == WS_SUCCESS)
+        ret = GetMpintToMp(&key->e, buf, len, idx);
+    if (ret == WS_SUCCESS)
+        ret = GetMpintToMp(&key->d, buf, len, idx);
+    if (ret == WS_SUCCESS)
+        ret = GetMpintToMp(&key->u, buf, len, idx);
+    if (ret == WS_SUCCESS)
+        ret = GetMpintToMp(&key->p, buf, len, idx);
+    if (ret == WS_SUCCESS)
+        ret = GetMpintToMp(&key->q, buf, len, idx);
+
+    /* Calculate dP and dQ for wolfCrypt. */
+    if (ret == WS_SUCCESS)
+        ret = CalcRsaInverses(key);
+
+    if (ret != WS_SUCCESS)
+        ret = WS_RSA_E;
+
+    return ret;
+}
+
+
+/*
+ * Utility for GetOpenSshKey() to read in ECDSA keys.
+ */
+static int GetOpenSshKeyEcc(ecc_key* key,
+        const byte* buf, word32 len, word32* idx)
+{
+    const byte *name = NULL, *priv = NULL, *pub = NULL;
+    word32 nameSz = 0, privSz = 0, pubSz = 0;
+    int ret;
+
+    ret = wc_ecc_init(key);
+    if (ret == WS_SUCCESS)
+        ret = GetStringRef(&nameSz, &name, buf, len, idx); /* curve name */
+    if (ret == WS_SUCCESS)
+        ret = GetStringRef(&pubSz, &pub, buf, len, idx); /* Q */
+    if (ret == WS_SUCCESS)
+        ret = GetMpint(&privSz, &priv, buf, len, idx); /* d */
+
+    if (ret == WS_SUCCESS)
+        ret = wc_ecc_import_private_key_ex(priv, privSz, pub, pubSz,
+                key, ECC_CURVE_DEF);
+
+    if (ret != WS_SUCCESS)
+        ret = WS_ECC_E;
+
+    return ret;
+}
+
+
+/*
+ * Decodes an OpenSSH format key.
+ */
+static int GetOpenSshKey(WS_KeySignature *key,
+        const byte* buf, word32 len, word32* idx)
+{
+    const char AuthMagic[] = "openssh-key-v1";
+    const byte* str = NULL;
+    word32 keyCount = 0, strSz, i;
+    int ret = WS_SUCCESS;
+
+    if (WSTRCMP(AuthMagic, (const char*)buf) != 0) {
+        ret = WS_KEY_AUTH_MAGIC_E;
+    }
+
+    if (ret == WS_SUCCESS) {
+        *idx += (word32)WSTRLEN(AuthMagic) + 1;
+        ret = GetSkip(buf, len, idx); /* ciphername */
+    }
+
+    if (ret == WS_SUCCESS)
+        ret = GetSkip(buf, len, idx); /* kdfname */
+
+    if (ret == WS_SUCCESS)
+        ret = GetSkip(buf, len, idx); /* kdfoptions */
+
+    if (ret == WS_SUCCESS)
+        ret = GetUint32(&keyCount, buf, len, idx); /* key count */
+
+    if (ret == WS_SUCCESS) {
+        if (keyCount != WOLFSSH_KEY_QUANTITY_REQ) {
+            ret = WS_KEY_FORMAT_E;
+        }
+    }
+
+    if (ret == WS_SUCCESS) {
+        strSz = 0;
+        ret = GetStringRef(&strSz, &str, buf, len, idx);
+                /* public buf */
+    }
+
+    if (ret == WS_SUCCESS) {
+        strSz = 0;
+        ret = GetStringRef(&strSz, &str, buf, len, idx);
+                /* list of private keys */
+
+        /* If there isn't a private key, the key file is bad. */
+        if (ret == WS_SUCCESS && strSz == 0) {
+            ret = WS_KEY_FORMAT_E;
+        }
+
+        if (ret == WS_SUCCESS) {
+            const byte* subStr = NULL;
+            word32 subStrSz = 0, subIdx = 0, check1 = 0, check2 = ~0;
+            byte keyId;
+
+            idx = 0;
+            if (ret == WS_SUCCESS)
+                ret = GetUint32(&check1, str, strSz, &subIdx); /* checkint 1 */
+            if (ret == WS_SUCCESS)
+                ret = GetUint32(&check2, str, strSz, &subIdx); /* checkint 2 */
+            if (ret == WS_SUCCESS) {
+                if (check1 != check2) {
+                    ret = WS_KEY_CHECK_VAL_E;
+                }
+            }
+            if (ret == WS_SUCCESS) {
+                for (i = 0; i < keyCount; i++) {
+                    ret = GetStringRef(&subStrSz, &subStr,
+                            str, strSz, &subIdx);
+                    if (ret == WS_SUCCESS) {
+                        keyId = NameToId((const char*)subStr, subStrSz);
+                        key->keySigId = keyId;
+                    }
+                    if (ret == WS_SUCCESS) {
+                        switch (keyId) {
+                        #ifndef WOLFSSH_NO_RSA
+                            case ID_SSH_RSA:
+                                ret = GetOpenSshKeyRsa(&key->ks.rsa.key,
+                                        str, strSz, &subIdx);
+                                break;
+                        #endif
+                        #ifndef WOLFSSH_NO_ECDSA
+                            case ID_ECDSA_SHA2_NISTP256:
+                                ret = GetOpenSshKeyEcc(&key->ks.ecc.key,
+                                        str, strSz, &subIdx);
+                                break;
+                        #endif
+                            default:
+                                ret = WS_UNIMPLEMENTED_E;
+                                break;
+                        }
+                        if (ret == WS_SUCCESS)
+                            ret = GetSkip(str, strSz, &subIdx);
+                                    /* key comment */
+                    }
+                }
+                /* Padding: Add increasing digits to pad to the nearest
+                 * block size. Default block size is 8, but depends on
+                 * the encryption algo. The private key chunk's length,
+                 * and the length of the comment delimit the end of the
+                 * encrypted blob. No added padding required. */
+                if (ret == WS_SUCCESS) {
+                    if (strSz % MIN_BLOCK_SZ == 0) {
+                        if (strSz > subIdx) {
+                            /* The padding starts at 1. */
+                            check2 = strSz - subIdx;
+                            for (check1 = 1;
+                                 check1 <= check2;
+                                 check1++, subIdx++) {
+                                if (check1 != str[subIdx]) {
+                                    /* Bad pad value. */
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return ret;
+}
+
+
+/*
+ * Identifies the flavor of an OpenSSH key, RSA or ECDSA, and returns the
+ * key type ID. The process is to decode the key extracting the identifiers,
+ * and try to decode the key as the type indicated type. For RSA keys, the
+ * key format is described as "ssh-rsa".
+ *
+ * @param in        key to identify
+ * @param inSz      size of key
+ * @param heap      heap to use for memory allocation
+ * @return          keyId as int, WS_MEMORY_E, WS_UNIMPLEMENTED_E,
+ *                  WS_INVALID_ALGO_ID
+ */
+int IdentifyOpenSshKey(const byte* in, word32 inSz, void* heap)
+{
+    WS_KeySignature *key = NULL;
+    word32 idx = 0;
+    int ret;
+
+    key = (WS_KeySignature*)WMALLOC(sizeof(WS_KeySignature),
+            heap, DYNTYPE_PRIVKEY);
+
     if (key == NULL) {
         ret = WS_MEMORY_E;
     }
-    else if (keyId == ID_UNKNOWN) {
-        ret = WS_UNIMPLEMENTED_E;
-    }
     else {
-        ret = keyId;
+        WMEMSET(key, 0, sizeof(*key));
+        key->keySigId = ID_NONE;
+
+        ret = GetOpenSshKey(key, in, inSz, &idx);
+
+        if (ret == WS_SUCCESS) {
+            ret = key->keySigId;
+        }
+        else if (key->keySigId == ID_UNKNOWN) {
+            ret = WS_UNIMPLEMENTED_E;
+        }
+
+        wolfSSH_KEY_clean(key);
+        WFREE(key, heap, DYNTYPE_PRIVKEY);
     }
-    WFREE(key, heap, dynType);
 
     return ret;
 }
@@ -958,7 +1310,7 @@ int IdentifyKey(const byte* in, word32 inSz, int isPrivate, void* heap)
 /*
  * Identifies the flavor of an X.509 certificate, RSA or ECDSA, and returns
  * the key type ID. The process is to decode the certificate and pass the
- * public key to IdentifyKey.
+ * public key to IdentifyAsn1Key.
  *
  * @param in        certificate to identify
  * @param inSz      size of certificate
@@ -1005,7 +1357,7 @@ static int IdentifyCert(const byte* in, word32 inSz, void* heap)
     }
 
     if (ret == 0) {
-        ret = IdentifyKey(key, keySz, 0, heap);
+        ret = IdentifyAsn1Key(key, keySz, 0, heap);
     }
 
     WFREE(key, heap, DYNTYPE_PUBKEY);
@@ -1194,7 +1546,7 @@ static int SetHostCertificate(WOLFSSH_CTX* ctx,
 
         if (pvtKey->publicKeyFmt == certId) {
             if (pvtKey->cert != NULL) {
-                WFREE(pvtKey->cert, heap, dynamicType);
+                WFREE(pvtKey->cert, ctx->heap, dynamicType);
             }
         }
         else {
@@ -1288,9 +1640,12 @@ int wolfSSH_ProcessBuffer(WOLFSSH_CTX* ctx,
     if (ctx == NULL || in == NULL || inSz == 0)
         return WS_BAD_ARGUMENT;
 
-    if (format != WOLFSSH_FORMAT_ASN1 && format != WOLFSSH_FORMAT_PEM &&
-                                         format != WOLFSSH_FORMAT_RAW)
+    if (format != WOLFSSH_FORMAT_ASN1
+            && format != WOLFSSH_FORMAT_PEM
+            && format != WOLFSSH_FORMAT_RAW
+            && format != WOLFSSH_FORMAT_OPENSSH) {
         return WS_BAD_FILETYPE_E;
+    }
 
     if (type == BUFTYPE_CA) {
         dynamicType = DYNTYPE_CA;
@@ -1341,7 +1696,7 @@ int wolfSSH_ProcessBuffer(WOLFSSH_CTX* ctx,
     /* Maybe decrypt */
 
     if (type == BUFTYPE_PRIVKEY) {
-        ret = IdentifyKey(der, derSz, 1, ctx->heap);
+        ret = IdentifyAsn1Key(der, derSz, 1, ctx->heap);
         if (ret < 0) {
             WFREE(der, heap, dynamicType);
             return ret;
@@ -1713,6 +2068,11 @@ static const NameIdPair NameIdMap[] = {
 
     /* Ext Info IDs */
     { ID_EXTINFO_SERVER_SIG_ALGS, "server-sig-algs" },
+
+    /* Curve Name IDs */
+    { ID_CURVE_NISTP256, "nistp256" },
+    { ID_CURVE_NISTP384, "nistp384" },
+    { ID_CURVE_NISTP521, "nistp521" },
 };
 
 
@@ -1880,17 +2240,19 @@ int ChannelUpdateForward(WOLFSSH_CHANNEL* channel,
                                 const char* origin, word32 originPort,
                                 int isDirect)
 {
+    void* heap = NULL;
     int ret = WS_SUCCESS;
     char* hostCopy = NULL;
     char* originCopy = NULL;
     word32 hostSz;
     word32 originSz;
 
+    WOLFSSH_UNUSED(heap);
+
     if (channel == NULL || host == NULL || origin == NULL)
         ret = WS_BAD_ARGUMENT;
     else {
-        void* heap = channel->ssh->ctx->heap;
-
+        heap = channel->ssh->ctx->heap;
         hostSz = (word32)WSTRLEN(host) + 1;
         originSz = (word32)WSTRLEN(origin) + 1;
         hostCopy = (char*)WMALLOC(hostSz, heap, DYNTYPE_STRING);
@@ -2397,6 +2759,26 @@ int GetSize(word32* v, const byte* buf, word32 len, word32* idx)
 }
 
 
+int GetSkip(const byte* buf, word32 len, word32* idx)
+{
+    int result;
+    word32 sz;
+
+    result = GetUint32(&sz, buf, len, idx);
+
+    if (result == WS_SUCCESS) {
+        result = WS_BUFFER_E;
+
+        if (*idx < len && sz <= len - *idx) {
+            *idx += sz;
+            result = WS_SUCCESS;
+        }
+    }
+
+    return result;
+}
+
+
 /* Gets the size of the mpint, and puts the pointer to the start of
  * buf's number into *mpint. This function does not copy. */
 int GetMpint(word32* mpintSz, const byte** mpint,
@@ -4303,7 +4685,7 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx)
         /* Verify h with the server's public key. */
         if (ret == WS_SUCCESS) {
 #ifndef WOLFSSH_NO_RSA
-        int tmpIdx = begin;
+        int tmpIdx = begin - sigSz;
 #endif
             /* Skip past the sig name. Check it, though. Other SSH
              * implementations do the verify based on the name, despite what
@@ -5264,7 +5646,7 @@ static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk,
     if (checkDigest)
         WFREE(checkDigest, ssh->ctx->heap, DYNTYPE_BUFFER);
     if (encDigest)
-        WFREE(encDigest, ssh->ctx_heap, DYNTYPE_BUFFER);
+        WFREE(encDigest, ssh->ctx->heap, DYNTYPE_BUFFER);
 #endif
     WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthRequestRsa(), ret = %d", ret);
     return ret;
@@ -6819,6 +7201,8 @@ static int DoChannelRequest(WOLFSSH* ssh,
                 WLOG(WS_LOG_DEBUG, "  heightPixels = %u", heightPixels);
                 ssh->curX = widthChar;
                 ssh->curY = heightRows;
+                ssh->curXP = widthPixels;
+                ssh->curYP = heightPixels;
                 if (ssh->termResizeCb) {
                     if (ssh->termResizeCb(ssh, widthChar, heightRows,
                                 widthPixels, heightPixels, ssh->termCtx)
@@ -7106,7 +7490,7 @@ static int DoChannelExtendedData(WOLFSSH* ssh,
 }
 
 
-static int DoPacket(WOLFSSH* ssh)
+static int DoPacket(WOLFSSH* ssh, byte* bufferConsumed)
 {
     byte* buf = (byte*)ssh->inputBuffer.buffer;
     word32 idx = ssh->inputBuffer.idx;
@@ -7119,6 +7503,8 @@ static int DoPacket(WOLFSSH* ssh)
 
     WLOG(WS_LOG_DEBUG, "DoPacket sequence number: %d", ssh->peerSeq);
 
+    *bufferConsumed = 0;
+
     idx += UINT32_SZ;
     padSz = buf[idx++];
 
@@ -7346,6 +7732,7 @@ static int DoPacket(WOLFSSH* ssh)
     idx += padSz;
     ssh->inputBuffer.idx = idx;
     ssh->peerSeq++;
+    *bufferConsumed = 1;
 
     return ret;
 }
@@ -7734,6 +8121,7 @@ int DoReceive(WOLFSSH* ssh)
     byte peerBlockSz = ssh->peerBlockSz;
     byte peerMacSz = ssh->peerMacSz;
     byte aeadMode = ssh->peerAeadMode;
+    byte bufferConsumed = 0;
 
     switch (ssh->processReplyState) {
         case PROCESS_INIT:
@@ -7840,15 +8228,13 @@ int DoReceive(WOLFSSH* ssh)
             NO_BREAK;
 
         case PROCESS_PACKET:
-            ret = DoPacket(ssh);
+            ret = DoPacket(ssh, &bufferConsumed);
             ssh->error = ret;
             if (ret < 0 && !(ret == WS_CHAN_RXD || ret == WS_EXTDATA ||
                     ret == WS_CHANNEL_CLOSED || ret == WS_WANT_WRITE ||
-                    ret == WS_REKEYING)) {
-                return WS_FATAL_ERROR;
+                    ret == WS_REKEYING || ret == WS_WANT_READ)) {
+                ret = WS_FATAL_ERROR;
             }
-            WLOG(WS_LOG_DEBUG, "PR3: peerMacSz = %u", peerMacSz);
-            ssh->inputBuffer.idx += peerMacSz;
             break;
 
         default:
@@ -7856,9 +8242,15 @@ int DoReceive(WOLFSSH* ssh)
             ssh->error = WS_INPUT_CASE_E;
             return WS_FATAL_ERROR;
     }
-    WLOG(WS_LOG_DEBUG, "PR4: Shrinking input buffer");
-    ShrinkBuffer(&ssh->inputBuffer, 1);
-    ssh->processReplyState = PROCESS_INIT;
+
+    if (bufferConsumed) {
+        WLOG(WS_LOG_DEBUG, "PR3: peerMacSz = %u", peerMacSz);
+        ssh->inputBuffer.idx += peerMacSz;
+
+        WLOG(WS_LOG_DEBUG, "PR4: Shrinking input buffer");
+        ShrinkBuffer(&ssh->inputBuffer, 1);
+        ssh->processReplyState = PROCESS_INIT;
+    }
 
     WLOG(WS_LOG_DEBUG, "PR5: txCount = %u, rxCount = %u",
          ssh->txCount, ssh->rxCount);
@@ -8814,7 +9206,7 @@ static int SendKexGetSigningKey(WOLFSSH* ssh,
             sigKeyBlock_ptr->sk.ecc.primeName =
                     PrimeNameForId(ssh->handshake->pubKeyId);
             sigKeyBlock_ptr->sk.ecc.primeNameSz =
-                    (word32)strlen(sigKeyBlock_ptr->sk.ecc.primeName);
+                    (word32)WSTRLEN(sigKeyBlock_ptr->sk.ecc.primeName);
 
             /* Decode the user-configured ECDSA private key. */
             sigKeyBlock_ptr->sk.ecc.qSz =
@@ -9104,7 +9496,7 @@ int SendKexDhReply(WOLFSSH* ssh)
         sigKeyBlock_ptr->pubKeyName =
             IdToName(SigTypeForId(sigKeyBlock_ptr->pubKeyId));
         sigKeyBlock_ptr->pubKeyNameSz =
-                (word32)strlen(sigKeyBlock_ptr->pubKeyName);
+                (word32)WSTRLEN(sigKeyBlock_ptr->pubKeyName);
         sigKeyBlock_ptr->pubKeyFmtId = sigKeyBlock_ptr->pubKeyId;
         if (sigKeyBlock_ptr->pubKeyId == ID_RSA_SHA2_256
                 || sigKeyBlock_ptr->pubKeyId == ID_RSA_SHA2_512) {
@@ -9113,7 +9505,7 @@ int SendKexDhReply(WOLFSSH* ssh)
         sigKeyBlock_ptr->pubKeyFmtName =
                 IdToName(sigKeyBlock_ptr->pubKeyFmtId);
         sigKeyBlock_ptr->pubKeyFmtNameSz =
-                (word32)strlen(sigKeyBlock_ptr->pubKeyFmtName);
+                (word32)WSTRLEN(sigKeyBlock_ptr->pubKeyFmtName);
 
         switch (ssh->handshake->kexId) {
 #ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256
@@ -10556,40 +10948,6 @@ int SendExtInfo(WOLFSSH* ssh)
 }
 
 
-typedef struct WS_KeySignature {
-    byte keySigId;
-    word32 sigSz;
-    const char *name;
-    word32 nameSz;
-    union {
-#ifndef WOLFSSH_NO_RSA
-        struct {
-            RsaKey key;
-            byte e[256];
-            word32 eSz;
-            byte ePad;
-            byte n[256];
-            word32 nSz;
-            byte nPad;
-        } rsa;
-#endif
-#ifndef WOLFSSH_NO_ECDSA
-        struct {
-            ecc_key key;
-            word32 keyBlobSz;
-            const char *keyBlobName;
-            word32 keyBlobNameSz;
-            byte q[256];
-            word32 qSz;
-            byte qPad;
-            const char *primeName;
-            word32 primeNameSz;
-        } ecc;
-#endif
-    } ks;
-} WS_KeySignature;
-
-
 /* Updates the payload size, and maybe loads keys. */
 static int PrepareUserAuthRequestPassword(WOLFSSH* ssh, word32* payloadSz,
         const WS_UserAuthData* authData)
@@ -10647,15 +11005,24 @@ static int PrepareUserAuthRequestRsa(WOLFSSH* ssh, word32* payloadSz,
     if (ret == WS_SUCCESS) {
         word32 idx = 0;
         #ifdef WOLFSSH_AGENT
-        if (ssh->agentEnabled)
+        if (ssh->agentEnabled) {
             ret = wc_RsaPublicKeyDecode(authData->sf.publicKey.publicKey,
                     &idx, &keySig->ks.rsa.key,
                     authData->sf.publicKey.publicKeySz);
+        }
         else
         #endif
+        {
             ret = wc_RsaPrivateKeyDecode(authData->sf.publicKey.privateKey,
                     &idx, &keySig->ks.rsa.key,
                     authData->sf.publicKey.privateKeySz);
+            if (ret != 0) {
+                idx = 0;
+                ret = GetOpenSshKey(keySig,
+                        authData->sf.publicKey.privateKey,
+                        authData->sf.publicKey.privateKeySz, &idx);
+            }
+        }
     }
 
     if (ret == WS_SUCCESS) {
@@ -11037,9 +11404,17 @@ static int PrepareUserAuthRequestEcc(WOLFSSH* ssh, word32* payloadSz,
         }
         else
         #endif
+        {
             ret = wc_EccPrivateKeyDecode(authData->sf.publicKey.privateKey,
                     &idx, &keySig->ks.ecc.key,
                     authData->sf.publicKey.privateKeySz);
+            if (ret != 0) {
+                idx = 0;
+                ret = GetOpenSshKey(keySig,
+                        authData->sf.publicKey.privateKey,
+                        authData->sf.publicKey.privateKeySz, &idx);
+            }
+        }
     }
 
     if (ret == WS_SUCCESS) {
@@ -11719,23 +12094,6 @@ static int BuildUserAuthRequestPublicKey(WOLFSSH* ssh,
 }
 
 
-static void CleanupUserAuthRequestPublicKey(WS_KeySignature* keySig)
-{
-    if (keySig != NULL) {
-        if (keySig->keySigId == ID_SSH_RSA) {
-#ifndef WOLFSSH_NO_RSA
-            wc_FreeRsaKey(&keySig->ks.rsa.key);
-#endif
-        }
-        else if (keySig->keySigId == ID_ECDSA_SHA2_NISTP256 ||
-                keySig->keySigId == ID_ECDSA_SHA2_NISTP384 ||
-                keySig->keySigId == ID_ECDSA_SHA2_NISTP521) {
-#ifndef WOLFSSH_NO_ECDSA
-            wc_ecc_free(&keySig->ks.ecc.key);
-#endif
-        }
-    }
-}
 #endif
 
 
@@ -11885,7 +12243,7 @@ int SendUserAuthRequest(WOLFSSH* ssh, byte authType, int addSig)
     }
 
     if (authId == ID_USERAUTH_PUBLICKEY)
-        CleanupUserAuthRequestPublicKey(keySig_ptr);
+        wolfSSH_KEY_clean(keySig_ptr);
 
     if (ret == WS_SUCCESS) {
         ret = wolfSSH_SendPacket(ssh);
@@ -13491,7 +13849,6 @@ int wolfSSH_CleanPath(WOLFSSH* ssh, char* in)
 #endif /* WOLFSSH_SFTP || WOLFSSH_SCP */
 
 
-#ifdef DEBUG_WOLFSSH
 
 #define LINE_WIDTH 16
 void DumpOctetString(const byte* input, word32 inputSz)
@@ -13527,7 +13884,6 @@ void DumpOctetString(const byte* input, word32 inputSz)
     }
 }
 
-#endif
 
 #ifdef WOLFSSH_SFTP
 
diff --git a/src/log.c b/src/log.c
index fdd541be3..2f66d5a9c 100644
--- a/src/log.c
+++ b/src/log.c
@@ -173,7 +173,7 @@ void wolfSSH_Log(enum wolfSSH_LogLevel level, const char *const fmt, ...)
 
     /* format msg */
     va_start(vlist, fmt);
-    WVSNPRINTF(msgStr, sizeof(msgStr), fmt, vlist);
+    WVSNPRINTF(msgStr, sizeof(msgStr)-1, fmt, vlist);
     va_end(vlist);
 
     if (logFunction)
diff --git a/src/ssh.c b/src/ssh.c
index 93a5df572..4e3758d72 100644
--- a/src/ssh.c
+++ b/src/ssh.c
@@ -1323,7 +1323,6 @@ void* wolfSSH_GetPublicKeyCheckCtx(WOLFSSH* ssh)
     return NULL;
 }
 
-#ifdef WOLFSSH_TERM
 
 #if defined(WOLFSSH_TERM) && !defined(NO_FILESYSTEM)
 /* Used to resize terminal window with shell connections
@@ -1361,8 +1360,6 @@ void wolfSSH_SetTerminalResizeCtx(WOLFSSH* ssh, void* usrCtx)
 }
 #endif
 
-#endif
-
 
 /* Used to set the channel request type sent in wolfSSH connect. The default
  * type set is shell if this function is not called.
@@ -1489,138 +1486,278 @@ union wolfSSH_key {
 #endif
 };
 
-/* Reads a key from the buffer in to out. If the out buffer doesn't exist
-   it is created. The type of key is stored in outType. It'll be a pointer
-   to a constant string. Format indicates the format of the key, currently
-   either SSH format (a public key) or ASN.1 in DER or PEM format (a
-   private key). */
-int wolfSSH_ReadKey_buffer(const byte* in, word32 inSz, int format,
-        byte** out, word32* outSz, const byte** outType, word32* outTypeSz,
+static const char* PrivBeginOpenSSH = "-----BEGIN OPENSSH PRIVATE KEY-----";
+static const char* PrivEndOpenSSH = "-----END OPENSSH PRIVATE KEY-----";
+static const char* PrivBeginPrefix = "-----BEGIN ";
+/* static const char* PrivEndPrefix = "-----END "; */
+static const char* PrivSuffix = " PRIVATE KEY-----";
+
+
+static int DoSshPubKey(const byte* in, word32 inSz, byte** out,
+        word32* outSz, const byte** outType, word32* outTypeSz,
         void* heap)
 {
-    int ret = WS_SUCCESS;
     byte* newKey = NULL;
+    char* c;
+    char* last;
+    char* type = NULL;
+    char* key = NULL;
+    int ret = WS_SUCCESS;
+    word32 newKeySz, typeSz;
 
+    WOLFSSH_UNUSED(inSz);
     WOLFSSH_UNUSED(heap);
 
-    if (in == NULL || inSz == 0 || out == NULL || outSz == NULL ||
-            outType == NULL || outTypeSz == NULL)
-        return WS_BAD_ARGUMENT;
-
-    if (format == WOLFSSH_FORMAT_SSH) {
-        char* c;
-        char* last;
-        char* type = NULL;
-        char* key = NULL;
-
-        /*
-           SSH format is:
-           type AAAABASE64ENCODEDKEYDATA comment
-        */
-        c = WSTRDUP((const char*)in, heap, DYNTYPE_STRING);
+    /*
+       SSH format is:
+       type AAAABASE64ENCODEDKEYDATA comment
+    */
+    c = WSTRDUP((const char*)in, heap, DYNTYPE_STRING);
+    if (c != NULL) {
         type = WSTRTOK(c, " \n", &last);
         key = WSTRTOK(NULL, " \n", &last);
+    }
+    else {
+        ret = WS_MEMORY_E;
+    }
 
-        if (type != NULL && key != NULL) {
-            const char* name;
-            word32 typeSz;
-            byte nameId;
-
-            typeSz = (word32)WSTRLEN(type);
-
-            nameId = NameToId(type, typeSz);
-            name = IdToName(nameId);
-            *outType = (const byte*)name;
-            *outTypeSz = typeSz;
-
-            if (*out == NULL) {
-                /* set size based on sanity check in wolfSSL base64 decode
-                 * function */
-                *outSz = ((word32)WSTRLEN(key) * 3 + 3) / 4;
-                newKey = (byte*)WMALLOC(*outSz, heap, DYNTYPE_PRIVKEY);
-                if (newKey == NULL) {
-                    return WS_MEMORY_E;
-                }
-                *out = newKey;
-            }
-
-            ret = Base64_Decode((byte*)key, (word32)WSTRLEN(key), *out, outSz);
-        }
-
-        if (ret != 0) {
-            WLOG(WS_LOG_DEBUG, "Base64 decode of public key failed.");
+    if (ret == WS_SUCCESS) {
+        if (type == NULL || key == NULL) {
             ret = WS_PARSE_E;
         }
-
-        WFREE(c, heap, DYNTYPE_STRING);
     }
-    else if (format == WOLFSSH_FORMAT_ASN1) {
+
+    if (ret == WS_SUCCESS) {
+        typeSz = (word32)WSTRLEN(type);
+        /* set size based on sanity check in wolfSSL base64 decode
+         * function */
+        newKeySz = ((word32)WSTRLEN(key) * 3 + 3) / 4;
         if (*out == NULL) {
-            newKey = (byte*)WMALLOC(inSz, heap, DYNTYPE_PRIVKEY);
+            newKey = (byte*)WMALLOC(newKeySz, heap, DYNTYPE_PRIVKEY);
             if (newKey == NULL) {
-                return WS_MEMORY_E;
+                ret = WS_MEMORY_E;
             }
-            *out = newKey;
         }
         else {
-            if (*outSz < inSz) {
-                WLOG(WS_LOG_DEBUG, "DER private key output size too small");
-                return WS_BUFFER_E;
+            if (*outSz < newKeySz) {
+                WLOG(WS_LOG_DEBUG, "PEM private key output size too small");
+                ret = WS_BUFFER_E;
+            }
+            else {
+                newKey = *out;
             }
-            newKey = *out;
         }
-        *outSz = inSz;
-        WMEMCPY(newKey, in, inSz);
+    }
 
-        ret = IdentifyKey(in, inSz, 1, heap);
-        if (ret > 0) {
-            *outType = (const byte*)IdToName(ret);
+    if (ret == WS_SUCCESS) {
+        ret = Base64_Decode((byte*)key, (word32)WSTRLEN(key),
+                newKey, &newKeySz);
+
+        if (ret == 0) {
+            *out = newKey;
+            *outSz = newKeySz;
+            *outType = (const byte *)IdToName(NameToId(type, typeSz));
             *outTypeSz = (word32)WSTRLEN((const char*)*outType);
             ret = WS_SUCCESS;
         }
+        else {
+            WLOG(WS_LOG_DEBUG, "Base64 decode of public key failed.");
+            if (*out == NULL) {
+                WFREE(newKey, heap, DYNTYPE_PRIVKEY);
+            }
+            ret = WS_PARSE_E;
+        }
     }
-    else if (format == WOLFSSH_FORMAT_PEM) {
-        word32 newKeySz = inSz; /* binary will be smaller than PEM */
 
+    WFREE(c, heap, DYNTYPE_STRING);
+    return ret;
+}
+
+
+static int DoAsn1Key(const byte* in, word32 inSz, byte** out,
+        word32* outSz, const byte** outType, word32* outTypeSz,
+        void* heap)
+{
+    int ret = WS_SUCCESS;
+    byte* newKey = NULL;
+
+    WOLFSSH_UNUSED(heap);
+
+    if (*out == NULL) {
+        newKey = (byte*)WMALLOC(inSz, heap, DYNTYPE_PRIVKEY);
+        if (newKey == NULL) {
+            return WS_MEMORY_E;
+        }
+    }
+    else {
+        if (*outSz < inSz) {
+            WLOG(WS_LOG_DEBUG, "DER private key output size too small");
+            return WS_BUFFER_E;
+        }
+        newKey = *out;
+    }
+
+    ret = IdentifyAsn1Key(in, inSz, 1, heap);
+
+    if (ret > 0) {
+        *out = newKey;
+        *outSz = inSz;
+        WMEMCPY(newKey, in, inSz);
+        *outType = (const byte*)IdToName(ret);
+        *outTypeSz = (word32)WSTRLEN((const char*)*outType);
+        ret = WS_SUCCESS;
+    }
+    else {
+        WLOG(WS_LOG_DEBUG, "unable to identify key");
         if (*out == NULL) {
-            newKey = (byte*)WMALLOC(newKeySz, heap, DYNTYPE_PRIVKEY);
-            if (newKey == NULL) {
-                return WS_MEMORY_E;
-            }
-            *out = newKey;
+            WFREE(newKey, heap, DYNTYPE_PRIVKEY);
         }
-        else {
-            if (*outSz < inSz) {
-                WLOG(WS_LOG_DEBUG, "PEM private key output size too small");
-                return WS_BUFFER_E;
-            }
-            newKey = *out;
+    }
+
+    return ret;
+}
+
+
+static int DoPemKey(const byte* in, word32 inSz, byte** out,
+        word32* outSz, const byte** outType, word32* outTypeSz,
+        void* heap)
+{
+    int ret = WS_SUCCESS;
+    byte* newKey = NULL;
+    word32 newKeySz = inSz; /* binary will be smaller than PEM */
+
+    WOLFSSH_UNUSED(heap);
+
+    if (*out == NULL) {
+        newKey = (byte*)WMALLOC(inSz, heap, DYNTYPE_PRIVKEY);
+        if (newKey == NULL) {
+            return WS_MEMORY_E;
+        }
+    }
+    else {
+        if (*outSz < inSz) {
+            WLOG(WS_LOG_DEBUG, "PEM private key output size too small");
+            return WS_BUFFER_E;
         }
+        newKey = *out;
+    }
 
-        /* If it is PEM, convert to ASN1 then process. */
-        ret = wc_KeyPemToDer(in, inSz, newKey, newKeySz, NULL);
-        if (ret > 0) {
-            newKeySz = (word32)ret;
-            ret = WS_SUCCESS;
+    /* If it is PEM, convert to ASN1 then process. */
+    ret = wc_KeyPemToDer(in, inSz, newKey, newKeySz, NULL);
+    if (ret > 0) {
+        newKeySz = (word32)ret;
+        ret = WS_SUCCESS;
+    }
+    else {
+        WLOG(WS_LOG_DEBUG, "Base64 decode of public key failed.");
+        ret = WS_PARSE_E;
+    }
+
+    if (ret == WS_SUCCESS) {
+        ret = IdentifyAsn1Key(newKey, newKeySz, 1, heap);
+    }
+
+    if (ret > 0) {
+        *out = newKey;
+        *outSz = newKeySz;
+        *outType = (const byte*)IdToName(ret);
+        *outTypeSz = (word32)WSTRLEN((const char*)*outType);
+        ret = WS_SUCCESS;
+    }
+    else {
+        WLOG(WS_LOG_DEBUG, "unable to identify key");
+        if (*out == NULL) {
+            WFREE(newKey, heap, DYNTYPE_PRIVKEY);
         }
-        else {
-            WLOG(WS_LOG_DEBUG, "Base64 decode of public key failed.");
-            ret = WS_PARSE_E;
+    }
+
+    return ret;
+}
+
+
+static int DoOpenSshKey(const byte* in, word32 inSz, byte** out,
+        word32* outSz, const byte** outType, word32* outTypeSz,
+        void* heap)
+{
+    int ret = WS_SUCCESS;
+    byte* newKey = NULL;
+    word32 newKeySz = inSz; /* binary will be smaller than PEM */
+
+    if (*out == NULL) {
+        newKey = (byte*)WMALLOC(newKeySz, heap, DYNTYPE_PRIVKEY);
+        if (newKey == NULL) {
+            return WS_MEMORY_E;
         }
+    }
+    else {
+        if (*outSz < inSz) {
+            WLOG(WS_LOG_DEBUG, "PEM private key output size too small");
+            return WS_BUFFER_E;
+        }
+        newKey = *out;
+    }
 
-        if (ret == WS_SUCCESS) {
-            ret = IdentifyKey(newKey, newKeySz, 1, heap);
-            if (ret > 0) {
-                *outSz = newKeySz;
-                *outType = (const byte*)IdToName(ret);
-                *outTypeSz = (word32)WSTRLEN((const char*)*outType);
-                ret = WS_SUCCESS;
-            }
-            else {
-                WLOG(WS_LOG_DEBUG, "unable to identify key");
-            }
+    in += WSTRLEN(PrivBeginOpenSSH);
+    inSz -= (word32)(WSTRLEN(PrivBeginOpenSSH) + WSTRLEN(PrivEndOpenSSH) + 2);
+
+    ret = Base64_Decode((byte*)in, inSz, newKey, &newKeySz);
+    if (ret == 0) {
+        ret = WS_SUCCESS;
+    }
+    else {
+        WLOG(WS_LOG_DEBUG, "Base64 decode of public key failed.");
+        ret = WS_PARSE_E;
+    }
+
+    if (ret == WS_SUCCESS) {
+        ret = IdentifyOpenSshKey(newKey, newKeySz, heap);
+    }
+
+    if (ret > 0) {
+        *out = newKey;
+        *outSz = newKeySz;
+        *outType = (const byte*)IdToName(ret);
+        *outTypeSz = (word32)WSTRLEN((const char*)*outType);
+        ret = WS_SUCCESS;
+    }
+    else {
+        WLOG(WS_LOG_DEBUG, "unable to identify key");
+        if (*out == NULL) {
+            WFREE(newKey, heap, DYNTYPE_PRIVKEY);
         }
     }
+
+    return ret;
+}
+
+
+/* Reads a key from the buffer in to out. If the out buffer doesn't exist
+   it is created. The type of key is stored in outType. It'll be a pointer
+   to a constant string. Format indicates the format of the key, currently
+   either SSH format (a public key) or ASN.1 in DER or PEM format (a
+   private key). */
+int wolfSSH_ReadKey_buffer(const byte* in, word32 inSz, int format,
+        byte** out, word32* outSz, const byte** outType, word32* outTypeSz,
+        void* heap)
+{
+    int ret = WS_SUCCESS;
+
+    if (in == NULL || inSz == 0 || out == NULL || outSz == NULL ||
+            outType == NULL || outTypeSz == NULL)
+        return WS_BAD_ARGUMENT;
+
+    if (format == WOLFSSH_FORMAT_SSH) {
+        ret = DoSshPubKey(in, inSz, out, outSz, outType, outTypeSz, heap);
+    }
+    else if (format == WOLFSSH_FORMAT_ASN1) {
+        ret = DoAsn1Key(in, inSz, out, outSz, outType, outTypeSz, heap);
+    }
+    else if (format == WOLFSSH_FORMAT_PEM) {
+        ret = DoPemKey(in, inSz, out, outSz, outType, outTypeSz, heap);
+    }
+    else if (format == WOLFSSH_FORMAT_OPENSSH) {
+        ret = DoOpenSshKey(in, inSz, out, outSz, outType, outTypeSz, heap);
+    }
     else {
         WLOG(WS_LOG_DEBUG, "Invalid key format");
         ret = WS_BAD_ARGUMENT;
@@ -1687,9 +1824,17 @@ int wolfSSH_ReadKey_file(const char* name,
             format = WOLFSSH_FORMAT_SSH;
             in[inSz] = 0;
         }
-        else if ((WSTRNSTR((const char*)in, "-----BEGIN ", inSz)
+#if 0
+        else if (WSTRNSTR((const char*)in, PrivBeginOpenSSH, inSz) != NULL &&
+                WSTRNSTR((const char*)in, PrivEndOpenSSH, inSz) != NULL) {
+#endif
+        else if (WSTRNSTR((const char*)in, PrivBeginOpenSSH, inSz) != NULL) {
+            *isPrivate = 1;
+            format = WOLFSSH_FORMAT_OPENSSH;
+        }
+        else if ((WSTRNSTR((const char*)in, PrivBeginPrefix, inSz)
                     == (const char*)in)
-                && (WSTRNSTR((const char*)in, "PRIVATE KEY-----", inSz)
+                && (WSTRNSTR((const char*)in, PrivSuffix, inSz)
                     != NULL)) {
             *isPrivate = 1;
             format = WOLFSSH_FORMAT_PEM;
diff --git a/src/wolfsftp.c b/src/wolfsftp.c
index d50792fd3..3bc55c09e 100644
--- a/src/wolfsftp.c
+++ b/src/wolfsftp.c
@@ -1977,6 +1977,7 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
     char* res   = NULL;
     char  ier[] = "Internal Failure";
     char  oer[] = "Open File Error";
+    char  naf[] = "Not A File";
 
     if (ssh == NULL) {
         return WS_BAD_ARGUMENT;
@@ -2036,20 +2037,40 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
         m |= WOLFSSH_O_EXCL;
     }
 
-    /* if file permissions not set then use default */
-    if (!(atr.flags & WOLFSSH_FILEATRB_PERM)) {
-        atr.per = 0644;
+    {
+        WS_SFTP_FILEATRB fileAtr = { 0 };
+        if (SFTP_GetAttributes(ssh->fs,
+                        dir, &fileAtr, 1, ssh->ctx->heap) == WS_SUCCESS) {
+            if ((fileAtr.per & FILEATRB_PER_MASK_TYPE) != FILEATRB_PER_FILE) {
+                WLOG(WS_LOG_SFTP, "Not a file");
+                ssh->error = WS_SFTP_NOT_FILE_E;
+
+                res = naf;
+                if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId,
+                            res, "English", NULL, &outSz) != WS_SIZE_ONLY) {
+                    return WS_FATAL_ERROR;
+                }
+                ret = WS_FATAL_ERROR;
+            }
+        }
     }
 
-    fd = WOPEN(ssh->fs, dir, m, atr.per);
-    if (fd < 0) {
-        WLOG(WS_LOG_SFTP, "Error opening file %s", dir);
-        res = oer;
-        if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, res,
-                "English", NULL, &outSz) != WS_SIZE_ONLY) {
-            return WS_FATAL_ERROR;
+    if (ret == WS_SUCCESS) {
+        /* if file permissions not set then use default */
+        if (!(atr.flags & WOLFSSH_FILEATRB_PERM)) {
+            atr.per = 0644;
+        }
+
+        fd = WOPEN(ssh->fs, dir, m, atr.per);
+        if (fd < 0) {
+            WLOG(WS_LOG_SFTP, "Error opening file %s", dir);
+            res = oer;
+            if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, res,
+                    "English", NULL, &outSz) != WS_SIZE_ONLY) {
+                return WS_FATAL_ERROR;
+            }
+            ret = WS_BAD_FILE_E;
         }
-        ret = WS_BAD_FILE_E;
     }
 
 #ifdef WOLFSSH_STOREHANDLE
@@ -2171,8 +2192,9 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
     }
 #endif
 
-    fileHandle = WS_CreateFileA(dir, desiredAccess, 0, creationDisp,
-            FILE_ATTRIBUTE_NORMAL, ssh->ctx->heap);
+    fileHandle = WS_CreateFileA(dir, desiredAccess,
+            (FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE),
+            creationDisp, FILE_ATTRIBUTE_NORMAL, ssh->ctx->heap);
     if (fileHandle == INVALID_HANDLE_VALUE) {
         WLOG(WS_LOG_SFTP, "Error opening file %s", dir);
         res = oer;
@@ -4707,9 +4729,9 @@ static int PopulateAttributes(WS_SFTP_FILEATRB* atr, WSTAT_T* stats)
     atr->per = 0755;
     /* Mimic S_IFMT */
     if (stats->type == FS_DIR_ENTRY_FILE)
-        atr->per |= 0040000;
+        atr->per |= FILEATRB_PER_FILE;
     else if (stats->type == FS_DIR_ENTRY_DIR)
-        atr->per |= 0100000;
+        atr->per |= FILEATRB_PER_DIR;
     else
         return WS_BAD_FILE_E;
 
@@ -5087,19 +5109,29 @@ int wolfSSH_SFTP_RecvLSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
     return ret;
 }
 
-
-#if !defined(USE_WINDOWS_API) && !defined(WOLFSSH_ZEPHYR)
+#if !defined(USE_WINDOWS_API) && !defined(WOLFSSH_ZEPHYR) && !defined(WOLFSSH_SFTP_SETMODE)
 /* Set the files mode
  * return WS_SUCCESS on success */
-static int SFTP_SetMode(WOLFSSH* ssh, char* name, word32 mode) {
-    WOLFSSH_UNUSED(ssh);
-    if (WCHMOD(ssh->fs, name, mode) != 0) {
+static int SFTP_SetMode(void* fs, char* name, word32 mode) {
+    WOLFSSH_UNUSED(fs);
+    if (WCHMOD(fs, name, mode) != 0) {
         return WS_BAD_FILE_E;
     }
     return WS_SUCCESS;
 }
 #endif
 
+#if !defined(USE_WINDOWS_API) && !defined(WOLFSSH_ZEPHYR) && !defined(WOLFSSH_SFTP_SETMODEHANDLE)
+/* Set the files mode
+ * return WS_SUCCESS on success */
+static int SFTP_SetModeHandle(void* fs, WFD handle, word32 mode) {
+    WOLFSSH_UNUSED(fs);
+    if (WFCHMOD(fs, handle, mode) != 0) {
+        return WS_BAD_FILE_E;
+    }
+    return WS_SUCCESS;
+}
+#endif
 
 #if !defined(_WIN32_WCE) && !defined(WOLFSSH_ZEPHYR)
 
@@ -5122,7 +5154,7 @@ static int SFTP_SetFileAttributes(WOLFSSH* ssh, char* name, WS_SFTP_FILEATRB* at
 #if !defined(USE_WINDOWS_API) && !defined(WOLFSSH_ZEPHYR)
     /* check if permissions attribute present */
     if (atr->flags & WOLFSSH_FILEATRB_PERM) {
-        ret = SFTP_SetMode(ssh, name, atr->per);
+        ret = SFTP_SetMode(ssh->fs, name, atr->per);
     }
 #endif
 
@@ -5162,9 +5194,7 @@ static int SFTP_SetFileAttributesHandle(WOLFSSH* ssh, WFD handle, WS_SFTP_FILEAT
 #ifndef USE_WINDOWS_API
     /* check if permissions attribute present */
     if (atr->flags & WOLFSSH_FILEATRB_PERM) {
-         if (WFCHMOD(ssh->fs, handle, atr->per) != 0) {
-           ret = WS_BAD_FILE_E;
-        }
+        ret = SFTP_SetModeHandle(ssh->fs, handle, atr->per);
     }
 #endif
 
@@ -7474,6 +7504,9 @@ int wolfSSH_SFTP_SendReadPacket(WOLFSSH* ssh, byte* handle, word32 handleSz,
                         WLOG(WS_LOG_SFTP, "OK or EOF found");
                         ret = 0; /* nothing was read */
                     }
+                    else {
+                        ret = WS_FATAL_ERROR;
+                    }
                 }
                 state->state = STATE_SEND_READ_CLEANUP;
                 NO_BREAK;
@@ -8469,6 +8502,14 @@ int wolfSSH_SFTP_Get(WOLFSSH* ssh, char* from,
                     state->state = STATE_GET_CLEANUP;
                     continue;
                 }
+                if ((state->attrib.per & FILEATRB_PER_MASK_TYPE)
+                        != FILEATRB_PER_FILE) {
+                    WLOG(WS_LOG_SFTP, "Not a file");
+                    ssh->error = WS_SFTP_NOT_FILE_E;
+                    ret = WS_FATAL_ERROR;
+                    state->state = STATE_GET_CLEANUP;
+                    continue;
+                }
                 state->handleSz = WOLFSSH_MAX_HANDLE;
                 state->state = STATE_GET_OPEN_REMOTE;
                 NO_BREAK;
@@ -8512,8 +8553,9 @@ int wolfSSH_SFTP_Get(WOLFSSH* ssh, char* from,
                         if (state->gOfst > 0)
                             desiredAccess |= FILE_APPEND_DATA;
                         state->fileHandle = WS_CreateFileA(to, desiredAccess,
-                                0, CREATE_ALWAYS,
-                                FILE_ATTRIBUTE_NORMAL, ssh->ctx->heap);
+                            (FILE_SHARE_DELETE | FILE_SHARE_READ |
+                             FILE_SHARE_WRITE), CREATE_ALWAYS,
+                            FILE_ATTRIBUTE_NORMAL, ssh->ctx->heap);
                     }
                     if (resume) {
                         WMEMSET(&state->offset, 0, sizeof(OVERLAPPED));
@@ -8701,6 +8743,21 @@ int wolfSSH_SFTP_Put(WOLFSSH* ssh, char* from, char* to, byte resume,
             case STATE_PUT_OPEN_LOCAL:
                 WLOG(WS_LOG_SFTP, "SFTP PUT STATE: OPEN LOCAL");
             #ifndef USE_WINDOWS_API
+                {
+                    WS_SFTP_FILEATRB fileAtr = { 0 };
+                    if (SFTP_GetAttributes(ssh->fs,
+                                from, &fileAtr, 1, ssh->ctx->heap)
+                            == WS_SUCCESS) {
+                        if ((fileAtr.per & FILEATRB_PER_MASK_TYPE)
+                                != FILEATRB_PER_FILE) {
+                            WLOG(WS_LOG_SFTP, "Not a file");
+                            ssh->error = WS_SFTP_NOT_FILE_E;
+                            ret = WS_FATAL_ERROR;
+                            state->state = STATE_PUT_CLEANUP;
+                            continue;
+                        }
+                    }
+                }
                 ret = WFOPEN(ssh->fs, &state->fl, from, "rb");
                 if (ret != 0) {
                     WLOG(WS_LOG_SFTP, "Unable to open input file");
diff --git a/tests/api.c b/tests/api.c
index 1e098fdfb..9353c4d2b 100644
--- a/tests/api.c
+++ b/tests/api.c
@@ -602,6 +602,203 @@ static void test_wolfSSH_CertMan(void)
 }
 
 
+#define KEY_BUF_SZ 2048
+
+#ifndef WOLFSSH_NO_RSA
+
+const char id_rsa[] =
+    "-----BEGIN OPENSSH PRIVATE KEY-----\n"
+    "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn\n"
+    "NhAAAAAwEAAQAAAQEAy2cigZDlpBT+X2MJHAoHnfeFf6+LHm6BDkAT8V9ejHA4dY0Aepb6\n"
+    "NbV6u/oYZlueKPeAZ3GNztR9szoL6FSlMvkd9oqvfoxjTGu71T0981ybJelqqGATGtevHU\n"
+    "6Jko/I0+lgSQFKWQJ7D3Dj2zlZpIXB2Q7xl/i9kFZgaIqFhUHdWO9JMOwCFwoDrhd8v5xk\n"
+    "y1v3OIIZDxiYxVIKbf2J07WbwiSFAxXfiX8TjUBDLFmtqt1AF6LjAyGyaRICXkaGJQ/QJ9\n"
+    "sX85h9bkiPlGNAtQGQtNUg3tC9GqOkZ9tCKY1Efh/r0zosOA7ufxg6ymLpq1C4LU/4ENGH\n"
+    "kuRPAKvu8wAAA8gztJfmM7SX5gAAAAdzc2gtcnNhAAABAQDLZyKBkOWkFP5fYwkcCged94\n"
+    "V/r4seboEOQBPxX16McDh1jQB6lvo1tXq7+hhmW54o94BncY3O1H2zOgvoVKUy+R32iq9+\n"
+    "jGNMa7vVPT3zXJsl6WqoYBMa168dTomSj8jT6WBJAUpZAnsPcOPbOVmkhcHZDvGX+L2QVm\n"
+    "BoioWFQd1Y70kw7AIXCgOuF3y/nGTLW/c4ghkPGJjFUgpt/YnTtZvCJIUDFd+JfxONQEMs\n"
+    "Wa2q3UAXouMDIbJpEgJeRoYlD9An2xfzmH1uSI+UY0C1AZC01SDe0L0ao6Rn20IpjUR+H+\n"
+    "vTOiw4Du5/GDrKYumrULgtT/gQ0YeS5E8Aq+7zAAAAAwEAAQAAAQEAvbdBiQXkGyn1pHST\n"
+    "/5IfTqia3OCX6td5ChicQUsJvgXBs2rDopQFZmkRxBjd/0K+/0jyfAl/EgZCBBRFHPsuZp\n"
+    "/S4ayzSV6aE6J8vMT1bnLWxwKyl7+csjGwRK6HRKtVzsnjI9TPSrw0mc9ax5PzV6/mgZUd\n"
+    "o/i+nszh+UASj5mYrBGqMiINspzX6YC+qoUHor3rEJOd9p1aO+N5+1fDKiDnlkM5IO0Qsz\n"
+    "GktuwL0fzv9zBnGfnWVJz3CorfP1OW5KCtrDn7BnkQf1eBeVLzq/uoglUjS4DNnVfLA67D\n"
+    "O4ZfwtnoW8Gr2R+KdvnypvHnDeY5X51r5PDgL4+7z47pWQAAAIBNFcAzHHE19ISGN8YRHk\n"
+    "23/r/3zfvzHU68GSKR1Xj/Y4LSdRTpSm3wBrdQ17f5B4V7RVl2CJvoPekTggnBDQlLJ7fU\n"
+    "NU93/nZrY9teYdrNh03buL54VVb5tUM+KN+27zERlTj0/LmYJupN97sZXmlgKsvLbcsnM2\n"
+    "i7HuQQaFnsIQAAAIEA5wqFVatT9yovt8pS7rAyYUL/cqc50TZ/5Nwfy5uasRyf1BphHwEW\n"
+    "LEimBemVc+VrNwAkt6MFWuloK5ssqb1ubvtRI8Mntd15rRfZtq/foS3J8FJxueXLDWlECy\n"
+    "PmVyfVN1Vv4ZeirBy9BTYLiSuxMes+HYks3HucQhxIN1j8SA0AAACBAOFgRjfWXv1/93Jp\n"
+    "6CCJ5c98MWP+zu1FbLIlklxPb85osZqlazXHNPPEtblC4z+OqRGMCsv2683anU4ZzcTFIk\n"
+    "JS3lzeJ3tdAH4osQ5etKkV4mcdCmeRpjudB9VbaziVhPX02qkPWpM0ckPrgB3hVNUDPz89\n"
+    "GtJd3mlhyY5IfFL/AAAADWJvYkBsb2NhbGhvc3QBAgMEBQ==\n"
+    "-----END OPENSSH PRIVATE KEY-----\n";
+
+const char id_rsa_pub[] =
+    "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLZyKBkOWkFP5fYwkcCged94V/r4seboEO"
+    "QBPxX16McDh1jQB6lvo1tXq7+hhmW54o94BncY3O1H2zOgvoVKUy+R32iq9+jGNMa7vVPT3z"
+    "XJsl6WqoYBMa168dTomSj8jT6WBJAUpZAnsPcOPbOVmkhcHZDvGX+L2QVmBoioWFQd1Y70kw"
+    "7AIXCgOuF3y/nGTLW/c4ghkPGJjFUgpt/YnTtZvCJIUDFd+JfxONQEMsWa2q3UAXouMDIbJp"
+    "EgJeRoYlD9An2xfzmH1uSI+UY0C1AZC01SDe0L0ao6Rn20IpjUR+H+vTOiw4Du5/GDrKYumr"
+    "ULgtT/gQ0YeS5E8Aq+7z bob@localhost\n";
+
+#endif /* WOLFSSH_NO_RSA */
+
+#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256
+
+const char id_ecdsa[] =
+    "-----BEGIN OPENSSH PRIVATE KEY-----\n"
+    "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS\n"
+    "1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTAqdBgCp8bYSq2kQQ48/Ud8Iy6Mjnb\n"
+    "/fpB3LfSE/1kx9VaaE4FL3i9Gg2vDV0eLGM3PWksFNPhULxtcYJyjaBjAAAAqJAeleSQHp\n"
+    "XkAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMCp0GAKnxthKraR\n"
+    "BDjz9R3wjLoyOdv9+kHct9IT/WTH1VpoTgUveL0aDa8NXR4sYzc9aSwU0+FQvG1xgnKNoG\n"
+    "MAAAAgPrOgktioNqad/wHNC/rt/zVrpNqDnOwg9tNDFMOTwo8AAAANYm9iQGxvY2FsaG9z\n"
+    "dAECAw==\n"
+    "-----END OPENSSH PRIVATE KEY-----\n";
+
+const char id_ecdsa_pub[] =
+    "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABB"
+    "BMCp0GAKnxthKraRBDjz9R3wjLoyOdv9+kHct9IT/WTH1VpoTgUveL0aDa8NXR4sYzc9aSwU"
+    "0+FQvG1xgnKNoGM= bob@localhost\n";
+
+#endif /* WOLFSSH_NO_ECDSA_SHA2_NISTP256 */
+
+static void test_wolfSSH_ReadKey(void)
+{
+#if !defined(WOLFSSH_NO_RSA) || !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256)
+    byte *key, *keyCheck, *derKey;
+    const byte* keyType;
+    word32 keySz, keyTypeSz, derKeySz;
+    int ret;
+#endif
+
+#ifndef WOLFSSH_NO_RSA
+
+    /* OpenSSH Format, ssh-rsa, private, need alloc */
+    key = NULL;
+    keySz = 0;
+    keyType = NULL;
+    keyTypeSz = 0;
+    ret = wolfSSH_ReadKey_buffer((const byte*)id_rsa, (word32)WSTRLEN(id_rsa),
+            WOLFSSH_FORMAT_OPENSSH, &key, &keySz, &keyType, &keyTypeSz, NULL);
+    AssertIntEQ(ret, WS_SUCCESS);
+    AssertNotNull(key);
+    AssertIntGT(keySz, 0);
+    AssertStrEQ(keyType, "ssh-rsa");
+    AssertIntEQ(keyTypeSz, (word32)WSTRLEN("ssh-rsa"));
+    WFREE(key, NULL, DYNTYPE_FILE);
+
+    /* SSL PEM Format, ssh-rsa, private, need alloc */
+    derKey = NULL;
+    derKeySz = 0;
+    key = NULL;
+    keySz = 0;
+    keyType = NULL;
+    keyTypeSz = 0;
+    ret = ConvertHexToBin(serverKeyRsaDer, &derKey, &derKeySz,
+            NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+    AssertIntEQ(ret, 0);
+    ret = wolfSSH_ReadKey_buffer(derKey, derKeySz, WOLFSSH_FORMAT_ASN1,
+            &key, &keySz, &keyType, &keyTypeSz, NULL);
+    AssertIntEQ(ret, WS_SUCCESS);
+    AssertNotNull(key);
+    AssertIntGT(keySz, 0);
+    AssertStrEQ(keyType, "ssh-rsa");
+    AssertIntEQ(keyTypeSz, (word32)WSTRLEN("ssh-rsa"));
+    WFREE(key, NULL, DYNTYPE_FILE);
+    WFREE(derKey, NULL, 0);
+
+    /* OpenSSH Format, ssh-rsa, public, need alloc */
+    key = NULL;
+    keySz = 0;
+    keyType = NULL;
+    keyTypeSz = 0;
+    ret = wolfSSH_ReadKey_buffer((const byte*)id_rsa_pub,
+            (word32)WSTRLEN(id_rsa_pub), WOLFSSH_FORMAT_SSH,
+            &key, &keySz, &keyType, &keyTypeSz, NULL);
+    AssertIntEQ(ret, WS_SUCCESS);
+    AssertNotNull(key);
+    AssertIntGT(keySz, 0);
+    AssertStrEQ(keyType, "ssh-rsa");
+    AssertIntEQ(keyTypeSz, (word32)WSTRLEN("ssh-rsa"));
+    WFREE(key, NULL, DYNTYPE_FILE);
+
+    /* OpenSSH Format, ssh-rsa, private, no alloc */
+    keyCheck = (byte*)WMALLOC(KEY_BUF_SZ, NULL, DYNTYPE_FILE);
+    AssertNotNull(keyCheck);
+    key = keyCheck;
+    keySz = KEY_BUF_SZ;
+    keyType = NULL;
+    keyTypeSz = 0;
+    ret = wolfSSH_ReadKey_buffer((const byte*)id_rsa, (word32)WSTRLEN(id_rsa),
+            WOLFSSH_FORMAT_OPENSSH, &key, &keySz, &keyType, &keyTypeSz, NULL);
+    AssertIntEQ(ret, WS_SUCCESS);
+    AssertTrue(key == keyCheck);
+    AssertIntGT(keySz, 0);
+    AssertStrEQ(keyType, "ssh-rsa");
+    AssertIntEQ(keyTypeSz, (word32)WSTRLEN("ssh-rsa"));
+    WFREE(keyCheck, NULL, DYNTYPE_FILE);
+
+#endif /* WOLFSSH_NO_RSA */
+
+#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256
+
+    /* OpenSSH Format, ecdsa-sha2-nistp256, private, need alloc */
+    key = NULL;
+    keySz = 0;
+    keyType = NULL;
+    keyTypeSz = 0;
+    ret = wolfSSH_ReadKey_buffer((const byte*)id_ecdsa,
+            (word32)WSTRLEN(id_ecdsa), WOLFSSH_FORMAT_OPENSSH,
+            &key, &keySz, &keyType, &keyTypeSz, NULL);
+    AssertIntEQ(ret, WS_SUCCESS);
+    AssertNotNull(key);
+    AssertIntGT(keySz, 0);
+    AssertStrEQ(keyType, "ecdsa-sha2-nistp256");
+    AssertIntEQ(keyTypeSz, (word32)WSTRLEN("ecdsa-sha2-nistp256"));
+    WFREE(key, NULL, DYNTYPE_FILE);
+
+    /* SSL DER Format, ecdsa-sha2-nistp256, private, need alloc */
+    derKey = NULL;
+    derKeySz = 0;
+    key = NULL;
+    keySz = 0;
+    keyType = NULL;
+    keyTypeSz = 0;
+    ret = ConvertHexToBin(serverKeyEccDer, &derKey, &derKeySz,
+            NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+    AssertIntEQ(ret, WS_SUCCESS);
+    ret = wolfSSH_ReadKey_buffer(derKey, derKeySz, WOLFSSH_FORMAT_ASN1,
+            &key, &keySz, &keyType, &keyTypeSz, NULL);
+    AssertIntEQ(ret, WS_SUCCESS);
+    AssertNotNull(key);
+    AssertIntGT(keySz, 0);
+    AssertStrEQ(keyType, "ecdsa-sha2-nistp256");
+    AssertIntEQ(keyTypeSz, (word32)WSTRLEN("ecdsa-sha2-nistp256"));
+    WFREE(key, NULL, DYNTYPE_FILE);
+    WFREE(derKey, NULL, 0);
+
+    /* OpenSSH Format, ecdsa-sha2-nistp256, public, need alloc */
+    key = NULL;
+    keySz = 0;
+    keyType = NULL;
+    keyTypeSz = 0;
+    ret = wolfSSH_ReadKey_buffer((const byte*)id_ecdsa_pub,
+            (word32)WSTRLEN(id_ecdsa_pub), WOLFSSH_FORMAT_SSH,
+            &key, &keySz, &keyType, &keyTypeSz, NULL);
+    AssertIntEQ(ret, WS_SUCCESS);
+    AssertNotNull(key);
+    AssertIntGT(keySz, 0);
+    AssertStrEQ(keyType, "ecdsa-sha2-nistp256");
+    AssertIntEQ(keyTypeSz, (word32)WSTRLEN("ecdsa-sha2-nistp256"));
+    WFREE(key, NULL, DYNTYPE_FILE);
+
+#endif /* WOLFSSH_NO_ECDSA_SHA2_NISTP256 */
+}
+
+
 #ifdef WOLFSSH_SCP
 
 static int my_ScpRecv(WOLFSSH* ssh, int state, const char* basePath,
@@ -1125,6 +1322,7 @@ int wolfSSH_ApiTest(int argc, char** argv)
     test_wolfSSH_CTX_UsePrivateKey_buffer();
     test_wolfSSH_CTX_UseCert_buffer();
     test_wolfSSH_CertMan();
+    test_wolfSSH_ReadKey();
 
     /* SCP tests */
     test_wolfSSH_SCP_CB();
diff --git a/wolfssh/error.h b/wolfssh/error.h
index d964b7ac3..d1fdfdd27 100644
--- a/wolfssh/error.h
+++ b/wolfssh/error.h
@@ -128,8 +128,12 @@ enum WS_ErrorCodes {
     WS_CERT_KEY_SIZE_E      = -1087, /* Key size error */
     WS_CTX_KEY_COUNT_E      = -1088, /* Adding too many private keys */
     WS_MATCH_UA_KEY_ID_E    = -1089, /* Match user auth key key fail */
+    WS_KEY_AUTH_MAGIC_E     = -1090, /* OpenSSH key auth magic check fail */
+    WS_KEY_CHECK_VAL_E      = -1091, /* OpenSSH key check value fail */
+    WS_KEY_FORMAT_E         = -1092, /* OpenSSH key format fail */
+    WS_SFTP_NOT_FILE_E      = -1093, /* Not a regular file */
     
-    WS_LAST_E               = -1089  /* Update this to indicate last error */
+    WS_LAST_E               = -1093  /* Update this to indicate last error */
 };
 
 
diff --git a/wolfssh/internal.h b/wolfssh/internal.h
index f9b5dcc5a..cb2a4dce3 100644
--- a/wolfssh/internal.h
+++ b/wolfssh/internal.h
@@ -347,12 +347,20 @@ enum {
 
     ID_EXTINFO_SERVER_SIG_ALGS,
 
+    ID_CURVE_NISTP256,
+    ID_CURVE_NISTP384,
+    ID_CURVE_NISTP521,
+
     ID_UNKNOWN
 };
 
 
 #define WOLFSSH_MAX_NAMESZ 32
-#define WOLFSSH_MAX_CHN_NAMESZ 256
+
+#ifndef WOLFSSH_MAX_CHN_NAMESZ
+    #define WOLFSSH_MAX_CHN_NAMESZ 4096
+#endif
+
 #define MAX_ENCRYPTION 3
 #define MAX_INTEGRITY 2
 #define MAX_KEY_EXCHANGE 2
@@ -416,6 +424,9 @@ enum {
 #ifndef WOLFSSH_MAX_PUB_KEY_ALGO
     #define WOLFSSH_MAX_PUB_KEY_ALGO (WOLFSSH_MAX_PVT_KEYS + 2)
 #endif
+#ifndef WOLFSSH_KEY_QUANTITY_REQ
+    #define WOLFSSH_KEY_QUANTITY_REQ 1
+#endif
 
 WOLFSSH_LOCAL byte NameToId(const char*, word32);
 WOLFSSH_LOCAL const char* IdToName(byte);
@@ -804,6 +815,8 @@ struct WOLFSSH {
     void* termCtx;
     word32 curX; /* current terminal width */
     word32 curY; /* current terminal height */
+    word32 curXP; /* pixel width  */
+    word32 curYP; /* pixel height */
 #endif
 };
 
@@ -851,8 +864,9 @@ WOLFSSH_LOCAL void ChannelDelete(WOLFSSH_CHANNEL*, void*);
 WOLFSSH_LOCAL WOLFSSH_CHANNEL* ChannelFind(WOLFSSH*, word32, byte);
 WOLFSSH_LOCAL int ChannelRemove(WOLFSSH*, word32, byte);
 WOLFSSH_LOCAL int ChannelPutData(WOLFSSH_CHANNEL*, byte*, word32);
-WOLFSSH_LOCAL int IdentifyKey(const byte* in, word32 inSz,
+WOLFSSH_LOCAL int IdentifyAsn1Key(const byte* in, word32 inSz,
         int isPrivate, void* heap);
+WOLFSSH_LOCAL int IdentifyOpenSshKey(const byte* in, word32 inSz, void* heap);
 WOLFSSH_LOCAL int wolfSSH_ProcessBuffer(WOLFSSH_CTX*,
                                         const byte*, word32,
                                         int, int);
@@ -865,6 +879,7 @@ WOLFSSH_LOCAL int GetUint32(word32* v,
         const byte* buf, word32 len, word32* idx);
 WOLFSSH_LOCAL int GetSize(word32* v,
         const byte* buf, word32 len, word32* idx);
+WOLFSSH_LOCAL int GetSkip(const byte* buf, word32 len, word32* idx);
 WOLFSSH_LOCAL int GetMpint(word32* mpintSz, const byte** mpint,
         const byte* buf, word32 len, word32* idx);
 WOLFSSH_LOCAL int GetString(char* s, word32* sSz,
diff --git a/wolfssh/port.h b/wolfssh/port.h
index ce2503c5f..189109c63 100644
--- a/wolfssh/port.h
+++ b/wolfssh/port.h
@@ -485,6 +485,9 @@ extern "C" {
     #define WSTRNCMP(s1,s2,n) strncmp((s1),(s2),(n))
     #define WSTRSPN(s1,s2)    strspn((s1),(s2))
     #define WSTRCSPN(s1,s2)   strcspn((s1),(s2))
+    #define WSTRSEP(s,d)      strsep((s),(d))
+    #define WSTRCAT(s1,s2)    strcat((s1),(s2))
+    #define WSTRCPY(s1,s2)    strcpy((s1),(s2))
 
     /* for these string functions use internal versions */
     WOLFSSH_API char* wstrnstr(const char*, const char*, unsigned int);
@@ -499,7 +502,7 @@ extern "C" {
         #define WSTRNCPY(s1,s2,n) strncpy_s((s1),(n),(s2),(n))
         #define WSTRNCASECMP(s1,s2,n) _strnicmp((s1),(s2),(n))
         #define WSNPRINTF(s,n,f,...) _snprintf_s((s),(n),_TRUNCATE,(f),##__VA_ARGS__)
-        #define WVSNPRINTF(s,n,f,...) _vsnprintf_s((s),(n),(n),(f),##__VA_ARGS__)
+        #define WVSNPRINTF(s,n,f,...) _vsnprintf_s((s),(n),_TRUNCATE,(f),##__VA_ARGS__)
         #define WSTRTOK(s1,s2,s3) strtok_s((s1),(s2),(s3))
     #elif defined(MICROCHIP_MPLAB_HARMONY) || defined(MICROCHIP_PIC32)
         #include <stdio.h>
@@ -1390,7 +1393,7 @@ extern "C" {
 
 
 #ifndef WOLFSSH_UNUSED
-    #define WOLFSSH_UNUSED(arg) (void)(arg);
+    #define WOLFSSH_UNUSED(arg) (void)(arg)
 #endif
 
 
diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h
index 492ab5dd4..ab315daad 100644
--- a/wolfssh/ssh.h
+++ b/wolfssh/ssh.h
@@ -311,6 +311,7 @@ enum WS_FormatTypes {
     WOLFSSH_FORMAT_PEM,
     WOLFSSH_FORMAT_RAW,
     WOLFSSH_FORMAT_SSH,
+    WOLFSSH_FORMAT_OPENSSH
 };
 
 
diff --git a/wolfssh/test.h b/wolfssh/test.h
index b4db3b4d5..9b767f08c 100644
--- a/wolfssh/test.h
+++ b/wolfssh/test.h
@@ -176,6 +176,7 @@
 #else /* USE_WINDOWS_API */
     #include <unistd.h>
     #include <sys/socket.h>
+    #include <sys/select.h>
     #include <pthread.h>
     #include <netdb.h>
     #include <netinet/in.h>
@@ -897,12 +898,14 @@ static INLINE void WaitTcpReady(func_args* args)
  * The tag WOLFSSL_THREAD is defined as a part of this compatibility, and
  * will also be checked for. Note that the following types and defines are
  * used by the examples to define themselves for use as threads by the test
- * tools, but they themselves do not use threading.
+ * tools, but they themselves do not use threading. Before v5.6.4, a new
+ * macro for return from threads was added.
  */
-#define WOLFSSL_V5_5_1 0x05005001
+#define WOLFSSL_V5_5_2 0x05005002
+#define WOLFSSL_V5_6_4 0x05006004
 
-#if (LIBWOLFSSL_VERSION_HEX < WOLFSSL_V5_5_1) && !defined(WOLFSSL_THREAD)
-    #define WOLFSSH_OLD_THREADING
+#if (LIBWOLFSSL_VERSION_HEX < WOLFSSL_V5_5_2) && !defined(WOLFSSL_THREAD)
+    #define WOLFSSH_OLDER_THREADING
     #ifdef SINGLE_THREADED
         typedef unsigned int  THREAD_RETURN;
         typedef void*         THREAD_TYPE;
@@ -927,11 +930,17 @@ static INLINE void WaitTcpReady(func_args* args)
     #define WOLFSSH_THREAD WOLFSSL_THREAD
 #endif
 
+#if (LIBWOLFSSL_VERSION_HEX < WOLFSSL_V5_6_4) \
+        && !defined(WOLFSSL_RETURN_FROM_THREAD)
+    #define WOLFSSL_RETURN_FROM_THREAD(x) return (THREAD_RETURN)(x)
+    #define WOLFSSH_OLD_THREADING
+#endif
+
 
 #ifdef WOLFSSH_TEST_THREADING
 
 
-#ifndef WOLFSSH_OLD_THREADING
+#if !defined(WOLFSSH_OLD_THREADING) && !defined(WOLFSSH_OLDER_THREADING)
 
 static INLINE void ThreadStart(THREAD_CB fun, void* args, THREAD_TYPE* thread)
 {
@@ -1056,7 +1065,7 @@ static INLINE void ThreadStartNoJoin(THREAD_FUNC fun, void* args)
     ThreadDetach(thread);
 }
 
-#endif /* WOLFSSH_OLD_THREADING */
+#endif /* !WOLFSSH_OLD_THREADING && !WOLFSSH_OLDER_THREADING */
 
 #endif /* WOLFSSH_TEST_THREADING */
 
diff --git a/wolfssh/wolfsftp.h b/wolfssh/wolfsftp.h
index b0272b2d6..8fbbdbb77 100644
--- a/wolfssh/wolfsftp.h
+++ b/wolfssh/wolfsftp.h
@@ -126,6 +126,13 @@ struct WS_SFTP_FILEATRB_EX {
     WS_SFTP_FILEATRB_EX* next;
 };
 
+#define FILEATRB_PER_MASK_TYPE 0770000
+#define FILEATRB_PER_FILE      0100000
+#define FILEATRB_PER_DEV_CHAR  0020000
+#define FILEATRB_PER_DIR       0040000
+#define FILEATRB_PER_DEV_BLOCK 0060000
+#define FILEATRB_PER_MASK_PERM 0000777
+
 typedef struct WS_SFTP_FILEATRB {
     word32 flags;
     word32 sz[2]; /* sz[0] being the lower and sz[1] being the upper */