diff --git a/.github/workflows/kyber.yml b/.github/workflows/kyber.yml new file mode 100644 index 000000000..5308b7a0a --- /dev/null +++ b/.github/workflows/kyber.yml @@ -0,0 +1,96 @@ +name: Kyber Tests + +on: + push: + branches: [ '*' ] + pull_request: + branches: [ '*' ] + +env: + LIBOQS_REF: 0.10.0 + WOLFSSL_REF: v5.7.0-stable + OS_REF: ubuntu-latest + +jobs: + build_liboqs: + name: Build liboqs + runs-on: ubuntu-latest + timeout-minutes: 4 + steps: + - name: Checking cache for liboqs + uses: actions/cache@v4 + id: cache-liboqs + with: + path: build-dir/ + key: wolfssh-kyber-liboqs-${{ env.LIBOQS_REF }}-${{ env.OS_REF }} + lookup-only: true + + - name: Checkout liboqs + if: steps.cache-liboqs.outputs.cache-hit != 'true' + uses: actions/checkout@v4 + with: + repository: open-quantum-safe/liboqs + ref: ${{ env.LIBOQS_REF }} + path: liboqs + + - name: Build and install liboqs + if: steps.cache-liboqs.outputs.cache-hit != 'true' + working-directory: liboqs + run: | + mkdir build + cd build + cmake -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/build-dir -DOQS_MINIMAL_BUILD=KEM_kyber_512 -DOQS_USE_OPENSSL=0 .. + make + make install + + build_wolfssl: + name: Build wolfssl + runs-on: ubuntu-latest + timeout-minutes: 4 + steps: + - name: Checking cache for wolfssl + uses: actions/cache@v4 + id: cache-wolfssl + with: + path: build-dir/ + key: wolfssh-kyber-wolfssl-${{ env.WOLFSSL_REF }}-${{ env.OS_REF }} + lookup-only: true + + - name: Checkout, build, and install wolfssl + if: steps.cache-wolfssl.outputs.cache-hit != 'true' + uses: wolfSSL/actions-build-autotools-project@v1 + with: + repository: wolfssl/wolfssl + ref: ${{ env.WOLFSSL_REF }} + path: wolfssl + configure: --enable-wolfssh --enable-cryptonly --disable-examples --disable-crypttests + check: false + install: true + + build_wolfssh: + name: Build wolfssh + runs-on: ubuntu-latest + timeout-minutes: 4 + needs: [build_wolfssl, build_liboqs] + steps: + - name: Checking cache for liboqs + uses: actions/cache@v4 + with: + path: build-dir/ + key: wolfssh-kyber-liboqs-${{ env.LIBOQS_REF }}-${{ env.OS_REF }} + fail-on-cache-miss: true + + - name: Checking cache for wolfssl + uses: actions/cache@v4 + with: + path: build-dir/ + key: wolfssh-kyber-wolfssl-${{ env.WOLFSSL_REF }}-${{ env.OS_REF }} + fail-on-cache-miss: true + + - name: Checkout, build, and test wolfssh + uses: wolfSSL/actions-build-autotools-project@v1 + with: + repository: wolfssl/wolfssh + path: wolfssh + configure: --with-liboqs=${{ github.workspace }}/build-dir --with-wolfssl=${{ github.workspace }}/build-dir + check: true diff --git a/.github/workflows/macos-check.yml b/.github/workflows/macos-check.yml deleted file mode 100644 index 16145791c..000000000 --- a/.github/workflows/macos-check.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: macOS Build Test - -on: - push: - branches: [ '*' ] - pull_request: - branches: [ '*' ] - -jobs: - build: - - runs-on: macos-latest - - steps: - - uses: actions/checkout@v2 - with: - repository: wolfSSL/wolfssl.git - ref: master - - name: brew - run: brew install automake - - name: build wolfSSL - run: ./autogen.sh && ./configure --enable-ssh --enable-cryptonly && make check && sudo make install - - uses: actions/checkout@v2 - - name: autogen - run: ./autogen.sh - - name: configure - run: ./configure - - name: make - run: make - - name: make check - run: make check - - name: make distcheck - run: make distcheck - diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml new file mode 100644 index 000000000..5db5697d4 --- /dev/null +++ b/.github/workflows/os-check.yml @@ -0,0 +1,75 @@ +name: OS Check Test + +on: + push: + branches: [ '*' ] + pull_request: + branches: [ '*' ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + WOLFSSL_REF: v5.7.0-stable + +jobs: + build_wolfssl: + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, macos-latest ] + name: Build wolfssl + runs-on: ${{ matrix.os }} + timeout-minutes: 4 + steps: + - name: Checking cache for wolfssl + uses: actions/cache@v4 + id: cache-wolfssl + with: + path: build-dir/ + key: wolfssh-os-check-wolfssl-${{ env.WOLFSSL_REF }}-${{ matrix.os }} + lookup-only: true + + - name: Checkout, build, and install wolfssl + if: steps.cache-wolfssl.outputs.cache-hit != 'true' + uses: wolfSSL/actions-build-autotools-project@v1 + with: + repository: wolfssl/wolfssl + ref: ${{ env.WOLFSSL_REF }} + path: wolfssl + configure: --enable-all + check: false + install: true + + build_wolfssh: + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, macos-latest ] + config: [ + '', + '--enable-all', + '--enable-sftp', + '--enable-scp', + '--enable-shell', + ] + name: Build wolfssh + runs-on: ${{ matrix.os }} + timeout-minutes: 4 + needs: build_wolfssl + steps: + - name: Checking cache for wolfssl + uses: actions/cache@v4 + with: + path: build-dir/ + key: wolfssh-os-check-wolfssl-${{ env.WOLFSSL_REF }}-${{ matrix.os }} + fail-on-cache-miss: true + + - name: Checkout, build, and test wolfssh + uses: wolfSSL/actions-build-autotools-project@v1 + with: + repository: wolfssl/wolfssh + path: wolfssh + configure: ${{ matrix.config }} LDFLAGS="-L${{ github.workspace }}/build-dir/lib" CPPFLAGS="-I${{ github.workspace }}/build-dir/include" + check: true diff --git a/.github/workflows/singlethread-check.yml b/.github/workflows/singlethread-check.yml new file mode 100644 index 000000000..af56fe7e9 --- /dev/null +++ b/.github/workflows/singlethread-check.yml @@ -0,0 +1,75 @@ +name: Single-thread Check Test + +on: + push: + branches: [ '*' ] + pull_request: + branches: [ '*' ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + WOLFSSL_REF: v5.7.0-stable + +jobs: + build_wolfssl: + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, macos-latest ] + name: Build wolfssl + runs-on: ${{ matrix.os }} + timeout-minutes: 4 + steps: + - name: Checking cache for wolfssl + uses: actions/cache@v4 + id: cache-wolfssl + with: + path: build-dir/ + key: wolfssh-singlethread-check-wolfssl-${{ env.WOLFSSL_REF }}-${{ matrix.os }} + lookup-only: true + + - name: Checkout, build, and install wolfssl + if: steps.cache-wolfssl.outputs.cache-hit != 'true' + uses: wolfSSL/actions-build-autotools-project@v1 + with: + repository: wolfssl/wolfssl + ref: ${{ env.WOLFSSL_REF }} + path: wolfssl + configure: --enable-wolfssh --enable-singlethreaded --enable-keygen + check: false + install: true + + build_wolfssh: + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, macos-latest ] + config: [ + '', + '--enable-all', + '--enable-sftp', + '--enable-scp', + '--enable-shell', + ] + name: Build wolfssh + runs-on: ${{ matrix.os }} + timeout-minutes: 4 + needs: build_wolfssl + steps: + - name: Checking cache for wolfssl + uses: actions/cache@v4 + with: + path: build-dir/ + key: wolfssh-singlethread-check-wolfssl-${{ env.WOLFSSL_REF }}-${{ matrix.os }} + fail-on-cache-miss: true + + - name: Checkout, build, and test wolfssh + uses: wolfSSL/actions-build-autotools-project@v1 + with: + repository: wolfssl/wolfssh + path: wolfssh + configure: ${{ matrix.config }} LDFLAGS="-L${{ github.workspace }}/build-dir/lib" CPPFLAGS="-I${{ github.workspace }}/build-dir/include" + check: true diff --git a/.github/workflows/ubuntu-check.yml b/.github/workflows/ubuntu-check.yml deleted file mode 100644 index 8f10e6564..000000000 --- a/.github/workflows/ubuntu-check.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Ubuntu Build 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-ssh --enable-cryptonly --prefix=/usr && make check && sudo make install - - uses: actions/checkout@v2 - - name: autogen - run: ./autogen.sh - - name: configure - run: ./configure - - name: make - run: make - - name: make check - run: make check - - name: make distcheck - run: make distcheck - diff --git a/.github/workflows/zephyr.yml b/.github/workflows/zephyr.yml index 1221e120d..26750fcc6 100644 --- a/.github/workflows/zephyr.yml +++ b/.github/workflows/zephyr.yml @@ -16,7 +16,7 @@ jobs: zephyr-sdk: 0.16.1 runs-on: ubuntu-latest # This should be a safe limit for the tests to run. - timeout-minutes: 15 + timeout-minutes: 20 steps: - name: Install dependencies run: | @@ -77,6 +77,8 @@ jobs: run: | ./zephyr/scripts/twister --testsuite-root modules/lib/wolfssh --test zephyr/samples/tests/sample.lib.wolfssh_tests -vvv rm -rf zephyr/twister-out + ./zephyr/scripts/twister --testsuite-root modules/lib/wolfssh --test zephyr/samples/tests/sample.lib.wolfssh_nofs_tests -vvv + rm -rf zephyr/twister-out - name: Zip failure logs if: ${{ failure() && steps.wolfssh-test.outcome == 'failure' }} diff --git a/ChangeLog.md b/ChangeLog.md index 651c0f357..32500bc67 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,117 @@ +# wolfSSH v1.4.18 (July 22, 2024) + +## New Features + +- Add wolfSSL style static memory pool allocation support. +- Add Ed25519 public key support. +- Add Banner option to wolfSSHd configuration. +- Add non-blocking socket support to the example SCP client. + +## Improvements + +- Documentation updates. +- Update the Zephyr test action. +- Add a no-filesystem build to the Zephyr port. +- Update the macOS test action. +- Refactor certificate processing. Only verify certificates when a signature + is present. +- Update the Kyber test action. +- Refactor the Curve25519 Key Agreement support. +- Update the STM32Cube Pack. +- Increase the memory that Zephyr uses for a heap for testing. +- Add a macro wrapper to replace the ReadDir function. +- Add callback hook for keying completion. +- Add function to return strings for the names of algorithms. +- Add asynchronous server side user authentication. +- Add ssh-rsa (SHA-1) to the default user auth algorithm list when + sha1-soft-disable is disabled. +- Update Espressif examples using Managed Components. +- Add SCP test case. +- Refactor RSA sign and verify. +- Refresh the example echoserver with updates from wolfSSHd. +- Add callback hooks for most channel messages including open, close, success, + fail, and requests. +- Reduce the number of memory allocations SCP makes. +- Improve wolfSSHd’s behavior on closing a connection. It closes channels and + waits for the peer to close the channels. + +## Fixes + +- Refactor wolfSSHd service support for Windows to fix PowerShell + Write-Progress. +- Fix partial success case with public key user authentication. +- Fix the build guards with respect to cannedKeyAlgoNames. +- Error if unable to open the local file when doing a SCP send. +- Fix some IPv6 related build issues. +- Add better checks for SCP error returns for closed channels. +- In the example SCP client, move the public key check context after the + WOLFSSH object is created. +- Fix error reporting for wolfSSH_SFTP_STAT. +- In the example SCP client, fix error code checking on shutdown. +- Change return from wolfSSH_shutdown() to WS_CHANNEL_CLOSED. +- Fix SFTP symlink handling. +- Fix variable initialization warnings for Zephyr builds. +- Fix wolfSSHd case of non-console output handles. +- Fix testsuite for single threaded builds. Add single threaded test action. +- Fix wolfSSHd shutting down on fcntl() failure. +- Fix wolfSSHd on Windows handling virtual terminal sequences using exec + commands. +- Fix possible null dereference when matching MAC algos during key exchange. + +--- + +# wolfSSH v1.4.17 (March 25, 2024) + +## Vulnerabilities + +* Fixes a vulnerability where a properly crafted SSH client can bypass user + authentication in the wolfSSH server code. The added fix filters the + messages that are allowed during different operational states. + +## Notes + +* When building wolfSSL/wolfCrypt versions before v5.6.6 with CMake, + wolfSSH may have a problem with RSA keys. This is due to wolfSSH not + checking on the size of `___uint128_t`. wolfSSH sees the RSA structure + as the wrong size. You will have to define `HAVE___UINT128_T` if you + know you have it and are using it in wolfSSL. wolfSSL v5.6.6 exports that + define in options.h when using CMake. +* The example server in directory examples/server/server.c has been removed. + It was never kept up to date, the echoserver did its job as an example and + test server. + +## New Features + +* Added functions to set algorithms lists for KEX at run-time, and some + functions to inspect which algorithms are set or are available to use. +* In v1.4.15, we had disabled SHA-1 in the build by default. SHA-1 has been + re-enabled in the build and is now "soft" disabled, where algorithms using + it can be configured for KEX. +* Add Curve25519 KEX support for server/client key agreement. + +## Improvements + +* Clean up some issues when building for Nucleus. +* Clean up some issues when building for Windows. +* Clean up some issues when building for QNX. +* Added more wolfSSHd testing. +* Added more appropriate build option guard checking. +* General improvements for the ESP32 builds. +* Better terminal support in Windows. +* Better I/O pipes and return codes when running commands or scripts over an + SSH connection. + +## Fixes + +* Fix shell terminal window resizing and it sets up the environment better. +* Fix some corner cases with the SFTP testing. +* Fix some corner cases with SFTP in general. +* Fix verifying RSA signatures. +* Add masking of file mode bits for Zephyr. +* Fix leak of terminal modes cache. + +--- + # wolfSSH v1.4.15 (December 22, 2023) ## Vulnerabilities diff --git a/README.md b/README.md index 95ff39222..29376d0bf 100644 --- a/README.md +++ b/README.md @@ -396,11 +396,56 @@ or define `WOLFSSH_SHELL`: $ ./configure --enable-shell $ make +To try out this functionality, you can use the example echoserver and client. +In a terminal do the following to launch the server: + + $ ./examples/echoserver/echoserver -P <user>:junk + +And in another terminal do the following to launch the example client: + + $ ./examples/client/client -t -u <user> -P junk + +Note that `<user>` must be the user name of the current user that is logged in. + By default, the echoserver will try to start a shell. To use the echo testing behavior, give the echoserver the command line option `-f`. $ ./examples/echoserver/echoserver -f +To use the shell feature with wolfsshd add `--enable-sshd` to your configure +command and use the following command: + + $ sudo ./apps/wolfsshd/wolfsshd -D -h keys/gretel-key-ecc.pem -p 11111 + +If it complains about a bad `sshd_config` file, simply copy it to another file +and remove the offending line that it complains about and use the `-f` command +line parameter to point to the new file. + +You can then connect to the `wolfsshd` server with ssh: + + $ ssh <user>@localhost -p 11111 + +Note that `<user>` must be the user name of the current user that is logged in. + +CURVE25519 +========== + +wolfSSH now supports Curve25519 for key exchange. To enable this support simply +compile wolfSSL with support for wolfssh and Curve25519. + + $ cd wolfssl + $ ./configure --enable-wolfssh --enable-curve25519 + +After building and installing wolfSSL, you can simply configure with no options. + + $ cd wolfssh + $ ./configure + +The wolfSSH client and server will automatically negotiate using Curve25519. + + $ ./examples/echoserver/echoserver -f + + $ ./examples/client/client -u jill -P upthehill POST-QUANTUM ============ @@ -473,23 +518,27 @@ authenticating a user. To compile wolfSSH with X.509 support, use the `--enable-certs` build option or define `WOLFSSH_CERTS`: - $ ./configure --enable-certs + $ ./configure --enable-certs CPPFLAGS=-DWOLFSSH_NO_FPKI $ make +For this example, we are disabling the FPKI checking as the included +certificate for "fred" does not have the required FPKI extensions. If the +flag WOLFSSH_NO_FPKI is removed, you can see the certificate get rejected. + To provide a CA root certificate to validate a user's certificate, give the echoserver the command line option `-a`. $ ./examples/echoserver/echoserver -a ./keys/ca-cert-ecc.pem -The echoserver and client have a fake user named "john" whose certificate +The echoserver and client have a fake user named "fred" whose certificate will be used for authentication. An example echoserver / client connection using the example certificate -john-cert.der would be: +fred-cert.der would be: - $ ./examples/echoserver/echoserver -a ./keys/ca-cert-ecc.pem -K john:./keys/john-cert.der + $ ./examples/echoserver/echoserver -a ./keys/ca-cert-ecc.pem -K fred:./keys/fred-cert.der - $ ./examples/client/client -u john -J ./keys/john-cert.der -i ./keys/john-key.der + $ ./examples/client/client -u fred -J ./keys/fred-cert.der -i ./keys/fred-key.der WOLFSSH APPLICATIONS diff --git a/apps/wolfssh/common.c b/apps/wolfssh/common.c index f83d135f7..5d5a90d33 100644 --- a/apps/wolfssh/common.c +++ b/apps/wolfssh/common.c @@ -1,6 +1,6 @@ /* common.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -451,7 +451,8 @@ int ClientPublicKeyCheck(const byte* pubKey, word32 pubKeySz, void* ctx) current->ipString); WLOG(WS_LOG_DEBUG, "\texpecting host IP : %s", (char*)ctx); - if (XSTRCMP(ctx, current->ipString) == 0) { + if (XSTRCMP((const char*)ctx, + current->ipString) == 0) { WLOG(WS_LOG_DEBUG, "\tmatched!"); ipMatch = 1; } diff --git a/apps/wolfssh/common.h b/apps/wolfssh/common.h index 14d45dcba..0f7b84141 100644 --- a/apps/wolfssh/common.h +++ b/apps/wolfssh/common.h @@ -1,6 +1,6 @@ /* common.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/apps/wolfssh/wolfssh.c b/apps/wolfssh/wolfssh.c index 5e216cbe7..8a749c6c2 100644 --- a/apps/wolfssh/wolfssh.c +++ b/apps/wolfssh/wolfssh.c @@ -1,6 +1,6 @@ /* wolfssh.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -106,14 +106,6 @@ static const char* caCert = NULL; #endif -#if defined(WOLFSSH_AGENT) -static inline void ato32(const byte* c, word32* u32) -{ - *u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; -} -#endif - - static int NonBlockSSH_connect(WOLFSSH* ssh) { int ret; @@ -215,6 +207,13 @@ static void modes_reset(void) #if !defined(SINGLE_THREADED) && !defined(WOLFSSL_NUCLEUS) +#if defined(WOLFSSH_AGENT) +static inline void ato32(const byte* c, word32* u32) +{ + *u32 = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; +} +#endif + typedef struct thread_args { WOLFSSH* ssh; wolfSSL_Mutex lock; @@ -404,6 +403,26 @@ static THREAD_RET readPeer(void* in) FD_SET(fd, &errSet); #ifdef USE_WINDOWS_API + if (args->rawMode == 0) { + DWORD wrd; + + /* get console mode will fail on handles that are not a console, + * i.e. if the stdout is being redirected to a file */ + if (GetConsoleMode(stdoutHandle, &wrd) != FALSE) { + /* depend on the terminal to process VT characters */ + #ifndef _WIN32_WINNT_WIN10 + /* support for virtual terminal processing was introduced in windows 10 */ + #define _WIN32_WINNT_WIN10 0x0A00 + #endif + #if defined(WINVER) && (WINVER >= _WIN32_WINNT_WIN10) + wrd |= (ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT); + #endif + if (SetConsoleMode(stdoutHandle, wrd) == FALSE) { + err_sys("Unable to set console mode"); + } + } + } + /* set handle to use for window resize */ wc_LockMutex(&args->lock); wolfSSH_SetTerminalResizeCtx(args->ssh, stdoutHandle); @@ -482,22 +501,14 @@ static THREAD_RET readPeer(void* in) } } else { + #ifdef USE_WINDOWS_API + DWORD writtn = 0; + #endif buf[bufSz - 1] = '\0'; #ifdef USE_WINDOWS_API - if (args->rawMode == 0) { - ret = wolfSSH_ConvertConsole(args->ssh, stdoutHandle, buf, - ret); - if (ret != WS_SUCCESS && ret != WS_WANT_READ) { - err_sys("issue with print out"); - } - if (ret == WS_WANT_READ) { - ret = 0; - } - } - else { - printf("%s", buf); - fflush(stdout); + if (WriteFile(stdoutHandle, buf, bufSz, &writtn, NULL) == FALSE) { + err_sys("Failed to write to stdout handle"); } #else if (write(STDOUT_FILENO, buf, ret) < 0) { @@ -782,7 +793,7 @@ static int config_parse_command_line(struct config* config, free(config->user); } sz = WSTRLEN(cursor); - config->user = WMALLOC(sz + 1, NULL, 0); + config->user = (char*)WMALLOC(sz + 1, NULL, 0); strcpy(config->user, cursor); cursor = found + 1; } @@ -979,7 +990,8 @@ static THREAD_RETURN WOLFSSH_THREAD wolfSSH_Client(void* args) err_sys("Couldn't set the username."); build_addr(&clientAddr, config.hostname, config.port); - tcp_socket(&sockFd); + tcp_socket(&sockFd, ((struct sockaddr_in *)&clientAddr)->sin_family); + ret = connect(sockFd, (const struct sockaddr *)&clientAddr, clientAddrSz); if (ret != 0) err_sys("Couldn't connect to server."); @@ -1010,14 +1022,14 @@ static THREAD_RETURN WOLFSSH_THREAD wolfSSH_Client(void* args) if (ret != WS_SUCCESS) err_sys("Couldn't connect SSH stream."); + MODES_CLEAR(); + #if !defined(SINGLE_THREADED) && !defined(WOLFSSL_NUCLEUS) #if 0 if (keepOpen) /* set up for psuedo-terminal */ ClientSetEcho(2); #endif - MODES_CLEAR(); - if (config.command != NULL || keepOpen == 1) { #if defined(_POSIX_THREADS) thread_args arg; diff --git a/apps/wolfsshd/auth.c b/apps/wolfsshd/auth.c index 4be651626..f60a299ab 100644 --- a/apps/wolfsshd/auth.c +++ b/apps/wolfsshd/auth.c @@ -1,6 +1,6 @@ /* auth.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/apps/wolfsshd/auth.h b/apps/wolfsshd/auth.h index ddc6e90aa..53868da81 100644 --- a/apps/wolfsshd/auth.h +++ b/apps/wolfsshd/auth.h @@ -1,6 +1,6 @@ /* auth.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/apps/wolfsshd/configuration.c b/apps/wolfsshd/configuration.c index 76f6bef07..473b0e280 100644 --- a/apps/wolfsshd/configuration.c +++ b/apps/wolfsshd/configuration.c @@ -1,6 +1,6 @@ /* configuration.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -349,9 +349,10 @@ enum { OPT_HOST_CERT = 20, OPT_TRUSTED_USER_CA_KEYS = 21, OPT_PIDFILE = 22, + OPT_BANNER = 23, }; enum { - NUM_OPTIONS = 23 + NUM_OPTIONS = 24 }; static const CONFIG_OPTION options[NUM_OPTIONS] = { @@ -378,6 +379,7 @@ static const CONFIG_OPTION options[NUM_OPTIONS] = { {OPT_HOST_CERT, "HostCertificate"}, {OPT_TRUSTED_USER_CA_KEYS, "TrustedUserCAKeys"}, {OPT_PIDFILE, "PidFile"}, + {OPT_BANNER, "Banner"}, }; /* returns WS_SUCCESS on success */ @@ -1022,6 +1024,9 @@ static int HandleConfigOption(WOLFSSHD_CONFIG** conf, int opt, case OPT_PIDFILE: ret = SetFileString(&(*conf)->pidFile, value, (*conf)->heap); break; + case OPT_BANNER: + ret = SetFileString(&(*conf)->banner, value, (*conf)->heap); + break; default: break; } diff --git a/apps/wolfsshd/configuration.h b/apps/wolfsshd/configuration.h index 68807975d..e39d9fa20 100644 --- a/apps/wolfsshd/configuration.h +++ b/apps/wolfsshd/configuration.h @@ -1,6 +1,6 @@ /* configuration.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index a7ef2f0a5..ce0567595 100644 --- a/apps/wolfsshd/wolfsshd.c +++ b/apps/wolfsshd/wolfsshd.c @@ -1,6 +1,6 @@ /* wolfsshd.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -103,7 +103,6 @@ static WFILE* logFile = NULL; /* catch interrupts and close down gracefully */ static volatile byte quit = 0; -static const char defaultBanner[] = "wolfSSHD\n"; /* Initial connection information to pass on to threads/forks */ typedef struct WOLFSSHD_CONNECTION { @@ -111,7 +110,7 @@ typedef struct WOLFSSHD_CONNECTION { WOLFSSHD_AUTH* auth; int fd; int listenFd; - char ip[INET_ADDRSTRLEN]; + char ip[INET6_ADDRSTRLEN]; byte isThreaded; } WOLFSSHD_CONNECTION; @@ -152,6 +151,7 @@ static void SyslogCb(enum wolfSSH_LogLevel level, const char *const msgStr) #ifdef _WIN32 static void ServiceDebugCb(enum wolfSSH_LogLevel level, const char* const msgStr) +#ifdef UNICODE { WCHAR* wc; size_t szWord = WSTRLEN(msgStr) + 3; /* + 3 for null terminator and new @@ -171,7 +171,13 @@ static void ServiceDebugCb(enum wolfSSH_LogLevel level, const char* const msgStr } WOLFSSH_UNUSED(level); } +#else +{ + OutputDebugString(msgStr); + WOLFSSH_UNUSED(level); +} #endif +#endif /* _WIN32 */ static void ShowUsage(void) { @@ -216,16 +222,6 @@ static void wolfSSHDLoggingCb(enum wolfSSH_LogLevel lvl, const char *const str) } -/* Frees up the WOLFSSH_CTX struct */ -static void CleanupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx) -{ - if (ctx != NULL && *ctx != NULL) { - wolfSSH_CTX_free(*ctx); - *ctx = NULL; - } - (void)conf; -} - #ifndef NO_FILESYSTEM static void freeBufferFromFile(byte* buf, void* heap) { @@ -247,7 +243,7 @@ static byte* getBufferFromFile(const char* fileName, word32* bufSz, void* heap) if (WFOPEN(NULL, &file, fileName, "rb") != 0) return NULL; - WFSEEK(NULL, file, 0, XSEEK_END); + WFSEEK(NULL, file, 0, WSEEK_END); fileSz = (word32)WFTELL(NULL, file); WREWIND(NULL, file); @@ -259,7 +255,8 @@ static byte* getBufferFromFile(const char* fileName, word32* bufSz, void* heap) WFREE(buf, heap, DYNTYPE_SSHD); return NULL; } - *bufSz = readSz; + if (bufSz) + *bufSz = readSz; WFCLOSE(NULL, file); } @@ -273,13 +270,30 @@ static int UserAuthResult(byte result, WS_UserAuthData* authData, void* userAuthResultCtx); +/* Frees up the WOLFSSH_CTX struct */ +static void CleanupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx, + byte** banner) +{ + if (banner != NULL && *banner != NULL) { +#ifndef NO_FILESYSTEM + freeBufferFromFile(*banner, NULL); +#endif + *banner = NULL; + } + if (ctx != NULL && *ctx != NULL) { + wolfSSH_CTX_free(*ctx); + *ctx = NULL; + } + (void)conf; +} + /* Initializes and sets up the WOLFSSH_CTX struct based on the configure options * return WS_SUCCESS on success */ -static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx) +static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx, + byte** banner) { int ret = WS_SUCCESS; - const char* banner; DerBuffer* der = NULL; byte* privBuf; word32 privBufSz; @@ -304,11 +318,13 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx) /* set banner to display on connection */ if (ret == WS_SUCCESS) { - banner = wolfSSHD_ConfigGetBanner(conf); - if (banner == NULL) { - banner = defaultBanner; +#ifndef NO_FILESYSTEM + *banner = getBufferFromFile(wolfSSHD_ConfigGetBanner(conf), + NULL, heap); +#endif + if (*banner) { + wolfSSH_CTX_SetBanner(*ctx, (char*)*banner); } - wolfSSH_CTX_SetBanner(*ctx, banner); } /* Load in host private key */ @@ -665,7 +681,6 @@ static int SFTP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } if (ret == WS_SUCCESS) { - r[rSz] = '\0'; wolfSSH_Log(WS_LOG_INFO, "[SSHD] Using directory %s for SFTP connection", r); if (wolfSSH_SFTP_SetDefaultPath(ssh, r) != WS_SUCCESS) { @@ -806,8 +821,6 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, int cnt_r, cnt_w; HANDLE ptyIn = NULL, ptyOut = NULL; HANDLE cnslIn = NULL, cnslOut = NULL; - HPCON pCon = 0; - COORD cord; STARTUPINFOEX ext; PCWSTR sysCmd = L"c:\\windows\\system32\\cmd.exe"; #if 0 @@ -825,7 +838,6 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, /* @TODO check for conpty support LoadLibrary()and GetProcAddress(). */ - if (forcedCmd != NULL && WSTRCMP(forcedCmd, "internal-sftp") == 0) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Only SFTP connections allowed for user " @@ -865,7 +877,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } if (ret == WS_SUCCESS) { - swprintf(cmd, cmdSz, L"%s /C \"%s\"", sysCmd, tmp); + swprintf(cmd, cmdSz, L"%s /C %s", sysCmd, tmp); } if (tmp != NULL) { @@ -898,259 +910,241 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } } - if (ret == WS_SUCCESS) { - HRESULT err; - - CreatePipe(&cnslIn, &ptyIn, NULL, 0); - CreatePipe(&ptyOut, &cnslOut, NULL, 0); + if (ImpersonateLoggedOnUser(wolfSSHD_GetAuthToken(conn->auth)) == FALSE) { + ret = WS_FATAL_ERROR; + } - cord.X = ssh->widthChar; - cord.Y = ssh->heightRows; + if (ret == WS_SUCCESS) { + SECURITY_ATTRIBUTES saAttr; - /* Sanity check on cord values, if 0 than assume was not set. - * (can happen with exec and not req-pty message) - * If not set yet then use sane default values. */ - if (cord.X == 0) { - cord.X = 80; - } + ZeroMemory(&saAttr, sizeof(saAttr)); + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; - if (cord.Y == 0) { - cord.Y = 24; + if (CreatePipe(&cnslIn, &ptyIn, &saAttr, 0) != TRUE) { + ret = WS_FATAL_ERROR; } - err = CreatePseudoConsole(cord, cnslIn, cnslOut, 0, &pCon); - if (err != S_OK) { - wolfSSH_Log(WS_LOG_ERROR, - "[SSHD] Issue creating pseudo console"); + if (CreatePipe(&ptyOut, &cnslOut, &saAttr, 0) != TRUE) { ret = WS_FATAL_ERROR; } - else { - CloseHandle(cnslIn); - CloseHandle(cnslOut); - wolfSSH_SetTerminalResizeCtx(ssh, (void*)&pCon); - } } - /* setup startup extended info for pseudo terminal */ if (ret == WS_SUCCESS) { - ext.StartupInfo.cb = sizeof(STARTUPINFOEX); - (void)InitializeProcThreadAttributeList(NULL, 1, 0, &sz); - if (sz == 0) { - ret = WS_FATAL_ERROR; - } + STARTUPINFOW si; + PCWSTR conCmd = L"wolfsshd.exe -r "; + PWSTR conCmdPtr; + size_t conCmdSz; - if (ret == WS_SUCCESS) { - /* Using HeapAlloc for better support when possibly passing - memory between Windows Modules */ - ext.lpAttributeList = - (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, sz); - if (ext.lpAttributeList == NULL) { - wolfSSH_Log(WS_LOG_ERROR, - "[SSHD] Issue getting memory for attribute list"); - ret = WS_FATAL_ERROR; - } - } + SetHandleInformation(ptyIn, HANDLE_FLAG_INHERIT, 0); + SetHandleInformation(ptyOut, HANDLE_FLAG_INHERIT, 0); - if (ret == WS_SUCCESS) { - if (InitializeProcThreadAttributeList(ext.lpAttributeList, 1, 0, - &sz) != TRUE) { - wolfSSH_Log(WS_LOG_ERROR, - "[SSHD] Issue initializing proc thread attribute"); - ret = WS_FATAL_ERROR; - } - } + wolfSSH_SetTerminalResizeCtx(ssh, (void*)&ptyIn); - if (ret == WS_SUCCESS) { - if (UpdateProcThreadAttribute(ext.lpAttributeList, 0, - PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, - pCon, sizeof(HPCON), NULL, NULL) != TRUE) { - wolfSSH_Log(WS_LOG_ERROR, - "[SSHD] Issue updating proc thread attribute"); - ret = WS_FATAL_ERROR; - } + conCmdSz = wcslen(conCmd) + cmdSz + 3; + /* +1 for terminator, +2 for quotes */ + conCmdPtr = (PWSTR)WMALLOC(sizeof(wchar_t) * conCmdSz, + NULL, DYNTYPE_SSHD); + if (conCmdPtr == NULL) { + ret = WS_MEMORY_E; + } + else { + _snwprintf_s(conCmdPtr, conCmdSz, conCmdSz, + L"wolfsshd.exe -r \"%s\"", cmd); } - } + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); - if (ret == WS_SUCCESS) { -#if 1 - if (CreateProcessAsUserW(wolfSSHD_GetAuthToken(conn->auth), NULL, cmd, - NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, h, - &ext.StartupInfo, &processInfo) != TRUE) { + si.hStdInput = cnslIn; + si.hStdOutput = cnslOut; + si.hStdError = cnslOut; + si.dwFlags = STARTF_USESTDHANDLES; + si.lpDesktop = NULL; + + if (CreateProcessAsUserW(wolfSSHD_GetAuthToken(conn->auth), NULL, conCmdPtr, + NULL, NULL, TRUE, DETACHED_PROCESS, NULL, h, + &si, &processInfo) != TRUE) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue creating process, Windows error %d", GetLastError()); return WS_FATAL_ERROR; } -#else - /* Needs enabled when running as non-service, compiled out for now to - * make sure it can not accidentally be used since the permissions of - * the created process match the current process. */ - if (CreateProcessW(NULL, cmd, NULL, NULL, FALSE, - EXTENDED_STARTUPINFO_PRESENT, NULL, h, &ext.StartupInfo, &processInfo) - != TRUE) { - wolfSSH_Log(WS_LOG_ERROR, - "[SSHD] Issue creating process, windows error %d", WSAGetLastError()); - if (cmd != NULL) { - WFREE(cmd, NULL, DYNTYPE_SSHD); - } - return WS_FATAL_ERROR; - } -#endif - else { - SOCKET sshFd; - byte tmp[2]; - fd_set readFds; - WS_SOCKET_T maxFd; - int pending = 0; - int readPending = 0; - int rc = 0; - DWORD processState; - DWORD ava; - struct timeval t; - t.tv_sec = 0; - t.tv_usec = 800; + CloseHandle(cnslIn); + CloseHandle(cnslOut); - sshFd = wolfSSH_get_fd(ssh); - maxFd = sshFd; + WFREE(conCmdPtr, NULL, DYNTYPE_SSHD); + } - FD_ZERO(&readFds); - FD_SET(sshFd, &readFds); + if (ret == WS_SUCCESS) { + char cmdWSize[20]; + int cmdWSizeSz = 20; + DWORD wrtn = 0; - wolfSSH_Log(WS_LOG_INFO, "[SSHD] Successfully created process for " - "console, waiting for it to start"); + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Successfully created process for " + "console, waiting for it to start"); - WaitForInputIdle(processInfo.hProcess, 1000); + WaitForInputIdle(processInfo.hProcess, 1000); - do { - /* @TODO currently not blocking till data comes in */ - if (PeekNamedPipe(ptyOut, NULL, 0, NULL, &ava, NULL) == TRUE) { - if (ava > 0) { - readPending = 1; - } + /* Send initial terminal size to pseudo console with VT control sequence */ + cmdWSizeSz = snprintf(cmdWSize, cmdWSizeSz, "\x1b[8;%d;%dt", ssh->heightRows, ssh->widthChar); + if (WriteFile(ptyIn, cmdWSize, cmdWSizeSz, &wrtn, 0) != TRUE) { + WLOG(WS_LOG_ERROR, "Issue with pseudo console resize"); + ret = WS_FATAL_ERROR; + } + } + + if (ret == WS_SUCCESS) { + SOCKET sshFd; + byte tmp[2]; + fd_set readFds; + WS_SOCKET_T maxFd; + int pending = 0; + int readPending = 0; + int rc = 0; + DWORD processState; + DWORD ava; + struct timeval t; + + t.tv_sec = 0; + t.tv_usec = 800; + + sshFd = wolfSSH_get_fd(ssh); + maxFd = sshFd; + + FD_ZERO(&readFds); + FD_SET(sshFd, &readFds); + + do { + /* @TODO currently not blocking till data comes in */ + if (PeekNamedPipe(ptyOut, NULL, 0, NULL, &ava, NULL) == TRUE) { + if (ava > 0) { + readPending = 1; } + } - if (readPending == 0) { - /* check if process is still running before waiting to read */ - if (GetExitCodeProcess(processInfo.hProcess, &processState) + if (readPending == 0) { + /* check if process is still running before waiting to read */ + if (GetExitCodeProcess(processInfo.hProcess, &processState) + == TRUE) { + if (processState != STILL_ACTIVE) { + wolfSSH_Log(WS_LOG_INFO, + "[SSHD] Process has exited, exit state = %d, " + "close down SSH connection", processState); + Sleep(100); /* give the stdout/stderr of process a + * little time to write to pipe */ + if (PeekNamedPipe(ptyOut, NULL, 0, NULL, &ava, NULL) == TRUE) { - if (processState != STILL_ACTIVE) { - wolfSSH_Log(WS_LOG_INFO, - "[SSHD] Process has exited, exit state = %d, " - "close down SSH connection", processState); - Sleep(100); /* give the stdout/stderr of process a - * little time to write to pipe */ - if (PeekNamedPipe(ptyOut, NULL, 0, NULL, &ava, NULL) - == TRUE) { - if (ava > 0) { - /* if data still pending then continue - * sending it over SSH */ - readPending = 1; - continue; - } + if (ava > 0) { + /* if data still pending then continue + * sending it over SSH */ + readPending = 1; + continue; } - break; } + break; } - if (wolfSSH_stream_peek(ssh, tmp, 1) <= 0) { - rc = select((int)maxFd + 1, &readFds, NULL, NULL, &t); - if (rc == -1) { - wolfSSH_Log(WS_LOG_INFO, - "[SSHD] select call waiting on socket failed"); - break; - } - /* when select times out and no socket is set as ready - Windows overwrites readFds with 0. Reset the fd here - for next select call */ - if (rc == 0) { - FD_SET(sshFd, &readFds); - } + } + if (wolfSSH_stream_peek(ssh, tmp, 1) <= 0) { + rc = select((int)maxFd + 1, &readFds, NULL, NULL, &t); + if (rc == -1) { + wolfSSH_Log(WS_LOG_INFO, + "[SSHD] select call waiting on socket failed"); + break; } - else { - pending = 1; + /* when select times out and no socket is set as ready + Windows overwrites readFds with 0. Reset the fd here + for next select call */ + if (rc == 0) { + FD_SET(sshFd, &readFds); } } + else { + pending = 1; + } + } - if (rc != 0 && (pending || FD_ISSET(sshFd, &readFds))) { - word32 lastChannel = 0; - - /* The following tries to read from the first channel inside - the stream. If the pending data in the socket is for - another channel, this will return an error with id - WS_CHAN_RXD. That means the agent has pending data in its - channel. The additional channel is only used with the - agent. */ - cnt_r = wolfSSH_worker(ssh, &lastChannel); - if (cnt_r < 0) { - rc = wolfSSH_get_error(ssh); - if (rc == WS_CHAN_RXD) { - if (lastChannel == shellChannelId) { - cnt_r = wolfSSH_ChannelIdRead(ssh, - shellChannelId, shellBuffer, - sizeof shellBuffer); - if (cnt_r <= 0) - break; - pending = 0; - if (WriteFile(ptyIn, shellBuffer, cnt_r, &cnt_r, - NULL) != TRUE) { - wolfSSH_Log(WS_LOG_INFO, - "[SSHD] Error writing to pipe for " - "console"); - break; - } + if (rc != 0 && (pending || FD_ISSET(sshFd, &readFds))) { + word32 lastChannel = 0; + + /* The following tries to read from the first channel inside + the stream. If the pending data in the socket is for + another channel, this will return an error with id + WS_CHAN_RXD. That means the agent has pending data in its + channel. The additional channel is only used with the + agent. */ + cnt_r = wolfSSH_worker(ssh, &lastChannel); + if (cnt_r < 0) { + rc = wolfSSH_get_error(ssh); + if (rc == WS_CHAN_RXD) { + if (lastChannel == shellChannelId) { + cnt_r = wolfSSH_ChannelIdRead(ssh, + shellChannelId, shellBuffer, + sizeof shellBuffer); + if (cnt_r <= 0) + break; + pending = 0; + if (WriteFile(ptyIn, shellBuffer, cnt_r, &cnt_r, + NULL) != TRUE) { + wolfSSH_Log(WS_LOG_INFO, + "[SSHD] Error writing to pipe for " + "console"); + break; } } - else if (rc == WS_CHANNEL_CLOSED) { - continue; - } - else if (rc != WS_WANT_READ) { - break; - } + } + else if (rc == WS_CHANNEL_CLOSED) { + continue; + } + else if (rc != WS_WANT_READ) { + break; } } + } - if (readPending) { - WMEMSET(shellBuffer, 0, EXAMPLE_BUFFER_SZ); + if (readPending) { + WMEMSET(shellBuffer, 0, EXAMPLE_BUFFER_SZ); - if (ReadFile(ptyOut, shellBuffer, EXAMPLE_BUFFER_SZ, &cnt_r, - NULL) != TRUE) { - wolfSSH_Log(WS_LOG_INFO, - "[SSHD] Error reading from pipe for console"); - break; - } - else { - readPending = 0; - if (cnt_r > 0) { - cnt_w = wolfSSH_ChannelIdSend(ssh, shellChannelId, - shellBuffer, cnt_r); - if (cnt_w < 0) - break; - } + if (ReadFile(ptyOut, shellBuffer, EXAMPLE_BUFFER_SZ, &cnt_r, + NULL) != TRUE) { + wolfSSH_Log(WS_LOG_INFO, + "[SSHD] Error reading from pipe for console"); + break; + } + else { + readPending = 0; + if (cnt_r > 0) { + cnt_w = wolfSSH_ChannelIdSend(ssh, shellChannelId, + shellBuffer, cnt_r); + if (cnt_w < 0) + break; } } - } while (1); - - if (cmd != NULL) { - WFREE(cmd, NULL, DYNTYPE_SSHD); } - wolfSSH_Log(WS_LOG_INFO, - "[SSHD] Closing down process for console"); + } while (1); - if (ext.lpAttributeList != NULL) { - HeapFree(GetProcessHeap(), 0, ext.lpAttributeList); - } + if (cmd != NULL) { + WFREE(cmd, NULL, DYNTYPE_SSHD); + } + wolfSSH_Log(WS_LOG_INFO, + "[SSHD] Closing down process for console"); - if (wolfSSH_SetExitStatus(ssh, processState) != - WS_SUCCESS) { - wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue sending childs exit " - "status"); - } + if (ext.lpAttributeList != NULL) { + HeapFree(GetProcessHeap(), 0, ext.lpAttributeList); + } - ClosePseudoConsole(pCon); - CloseHandle(processInfo.hThread); - CloseHandle(wolfSSHD_GetAuthToken(conn->auth)); + if (wolfSSH_SetExitStatus(ssh, processState) != + WS_SUCCESS) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue sending childs exit " + "status"); } + + CloseHandle(processInfo.hThread); + CloseHandle(wolfSSHD_GetAuthToken(conn->auth)); } + + RevertToSelf(); return ret; } #else @@ -1180,7 +1174,14 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, byte channelBuffer[EXAMPLE_BUFFER_SZ]; char* forcedCmd; int windowFull = 0; - int idle = 0; + int peerConnected = 1; + int stdoutEmpty = 0; + + childFd = -1; + stdoutPipe[0] = -1; + stdoutPipe[1] = -1; + stderrPipe[0] = -1; + stderrPipe[1] = -1; forcedCmd = wolfSSHD_ConfigGetForcedCmd(usrConf); @@ -1190,7 +1191,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, forcedCmd = (char*)subCmd; } - if (forcedCmd != NULL && XSTRCMP(forcedCmd, "internal-sftp") == 0) { + if (forcedCmd != NULL && WSTRCMP(forcedCmd, "internal-sftp") == 0) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Only SFTP connections allowed for user " "%s", wolfSSH_GetUsername(ssh)); @@ -1238,6 +1239,8 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, if (forcedCmd) { close(stdoutPipe[0]); close(stderrPipe[0]); + stdoutPipe[0] = -1; + stderrPipe[0] = -1; if (dup2(stdoutPipe[1], STDOUT_FILENO) == -1) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error redirecting stdout pipe"); @@ -1310,9 +1313,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, setenv("SHELL", pPasswd->pw_shell, 1); if (pPasswd->pw_shell) { - word32 shellSz = (word32)WSTRLEN(pPasswd->pw_shell); - - if (shellSz < sizeof(shell)) { + if (WSTRLEN(pPasswd->pw_shell) < sizeof(shell)) { char* cursor; char* start; @@ -1335,12 +1336,11 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } /* default to /bin/sh if user shell is not set */ - WMEMSET(cmd, 0, sizeof(cmd)); - if (XSTRLEN(pPasswd->pw_shell) == 0) { - XSNPRINTF(cmd, sizeof(cmd), "%s", "/bin/sh"); + if (pPasswd->pw_shell && WSTRLEN(pPasswd->pw_shell)) { + WSNPRINTF(cmd, sizeof(cmd), "%s", pPasswd->pw_shell); } else { - XSNPRINTF(cmd, sizeof(cmd),"%s", pPasswd->pw_shell); + WSNPRINTF(cmd, sizeof(cmd), "%s", "/bin/sh"); } errno = 0; @@ -1391,8 +1391,9 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, #if defined(HAVE_SYS_IOCTL_H) wolfSSH_DoModes(ssh->modes, ssh->modesSz, childFd); { - struct winsize s = {0}; + struct winsize s; + WMEMSET(&s, 0, sizeof(s)); s.ws_col = ssh->widthChar; s.ws_row = ssh->heightRows; s.ws_xpixel = ssh->widthPixels; @@ -1408,20 +1409,24 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, close(stderrPipe[1]); } - while (idle < MAX_IDLE_COUNT) { + while (ChildRunning || windowFull || !stdoutEmpty || peerConnected) { byte tmp[2]; fd_set readFds; + fd_set writeFds; WS_SOCKET_T maxFd; int cnt_r; int cnt_w; int pending = 0; - idle++; /* increment idle count, gets reset if not idle */ - FD_ZERO(&readFds); FD_SET(sshFd, &readFds); maxFd = sshFd; + FD_ZERO(&writeFds); + if (windowFull) { + FD_SET(sshFd, &writeFds); + } + /* select on stdout/stderr pipes with forced commands */ if (forcedCmd) { FD_SET(stdoutPipe[0], &readFds); @@ -1439,18 +1444,18 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } if (wolfSSH_stream_peek(ssh, tmp, 1) <= 0) { - rc = select((int)maxFd + 1, &readFds, NULL, NULL, NULL); + rc = select((int)maxFd + 1, &readFds, &writeFds, NULL, NULL); if (rc == -1) break; } else { pending = 1; /* found some pending SSH data */ - idle = 0; } if (windowFull || pending || FD_ISSET(sshFd, &readFds)) { word32 lastChannel = 0; + windowFull = 0; /* The following tries to read from the first channel inside the stream. If the pending data in the socket is for another channel, this will return an error with id @@ -1461,7 +1466,6 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, if (cnt_r < 0) { rc = wolfSSH_get_error(ssh); if (rc == WS_CHAN_RXD) { - idle = 0; if (lastChannel == shellChannelId) { cnt_r = wolfSSH_ChannelIdRead(ssh, shellChannelId, channelBuffer, @@ -1475,6 +1479,11 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } } else if (rc == WS_CHANNEL_CLOSED) { + peerConnected = 0; + continue; + } + else if (rc == WS_WANT_WRITE) { + windowFull = 1; continue; } else if (rc != WS_WANT_READ) { @@ -1489,7 +1498,10 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, shellBuffer, cnt_r); if (cnt_w == WS_WINDOW_FULL) { windowFull = 1; - idle = 0; + continue; + } + else if (cnt_w == WS_WANT_WRITE) { + windowFull = 1; continue; } else { @@ -1510,13 +1522,16 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } else { if (cnt_r > 0) { - idle = 0; cnt_w = wolfSSH_extended_data_send(ssh, shellBuffer, cnt_r); if (cnt_w == WS_WINDOW_FULL) { windowFull = 1; continue; } + else if (cnt_w == WS_WANT_WRITE) { + windowFull = 1; + continue; + } else if (cnt_w < 0) break; } @@ -1528,23 +1543,31 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, cnt_r = (int)read(stdoutPipe[0], shellBuffer, sizeof shellBuffer); /* This read will return 0 on EOF */ - if (cnt_r <= 0) { + if (cnt_r < 0) { int err = errno; if (err != EAGAIN && err != 0) { break; } } + else if (cnt_r == 0) { + stdoutEmpty = 1; + } else { if (cnt_r > 0) { - idle = 0; cnt_w = wolfSSH_ChannelIdSend(ssh, shellChannelId, shellBuffer, cnt_r); if (cnt_w == WS_WINDOW_FULL) { windowFull = 1; continue; } - else if (cnt_w < 0) + else if (cnt_w == WS_WANT_WRITE) { + windowFull = 1; + continue; + } + else if (cnt_w < 0) { + kill(childPid, SIGINT); break; + } } } } @@ -1561,22 +1584,27 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } else { if (cnt_r > 0) { - idle = 0; cnt_w = wolfSSH_ChannelIdSend(ssh, shellChannelId, shellBuffer, cnt_r); if (cnt_w == WS_WINDOW_FULL) { windowFull = 1; continue; } - else if (cnt_w < 0) + else if (cnt_w == WS_WANT_WRITE) { + windowFull = 1; + continue; + } + else if (cnt_w < 0) { + kill(childPid, SIGINT); break; + } } } } } - if (ChildRunning && idle) { - idle = 0; /* waiting on child process */ + if (!ChildRunning && peerConnected && stdoutEmpty && !windowFull) { + peerConnected = 0; } } @@ -1889,7 +1917,7 @@ static void* HandleConnection(void* arg) #ifdef _WIN32 Sleep(1); #else - usleep(1); + usleep(100000); #endif } @@ -1903,6 +1931,13 @@ static void* HandleConnection(void* arg) /* check if there is a response to the shutdown */ wolfSSH_free(ssh); if (conn != NULL) { + byte sc[1024]; + shutdown(conn->fd, 1); + /* Spin until socket closes. */ + do { + ret = (int)recv(conn->fd, sc, 1024, 0); + } while (ret > 0); + WCLOSESOCKET(conn->fd); } wolfSSH_Log(WS_LOG_INFO, "[SSHD] Return from closing connection = %d", ret); @@ -2058,7 +2093,7 @@ static char* _convertHelper(WCHAR* in, void* heap) { if (ret != NULL) { size_t numConv = 0; if (wcstombs_s(&numConv, ret, retSz, in, retSz) != 0) { - XFREE(ret, heap, DYNTYPE_SSHD); + WFREE(ret, heap, DYNTYPE_SSHD); ret = NULL; } } @@ -2082,6 +2117,7 @@ static int StartSSHD(int argc, char** argv) const char* configFile = "/etc/ssh/sshd_config"; const char* hostKeyFile = NULL; + byte* banner = NULL; logFile = stderr; wolfSSH_SetLoggingCb(wolfSSHDLoggingCb); @@ -2256,7 +2292,7 @@ static int StartSSHD(int argc, char** argv) if (ret == WS_SUCCESS) { wolfSSH_Log(WS_LOG_INFO, "[SSHD] Starting wolfSSH SSHD application"); - ret = SetupCTX(conf, &ctx); + ret = SetupCTX(conf, &ctx, &banner); } if (ret == WS_SUCCESS) { @@ -2345,21 +2381,21 @@ static int StartSSHD(int argc, char** argv) wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue updating service status"); } } - - /* Create a stop event to watch on */ - serviceStop = CreateEvent(NULL, TRUE, FALSE, NULL); - if (serviceStop == NULL) { - serviceStatus.dwControlsAccepted = 0; - serviceStatus.dwCurrentState = SERVICE_STOPPED; - serviceStatus.dwWin32ExitCode = GetLastError(); - serviceStatus.dwCheckPoint = 1; - - if (SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE) { - wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue updating service status"); + if (ret == WS_SUCCESS) { + /* Create a stop event to watch on */ + serviceStop = CreateEvent(NULL, TRUE, FALSE, NULL); + if (serviceStop == NULL) { + serviceStatus.dwControlsAccepted = 0; + serviceStatus.dwCurrentState = SERVICE_STOPPED; + serviceStatus.dwWin32ExitCode = GetLastError(); + serviceStatus.dwCheckPoint = 1; + + if (SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue updating service status"); + } + return; } - return; } - if (cmdArgs != NULL) { LocalFree(cmdArgs); } @@ -2395,8 +2431,8 @@ static int StartSSHD(int argc, char** argv) #ifdef WOLFSSL_NUCLEUS struct addr_struct clientAddr; #else - SOCKADDR_IN_T clientAddr; - socklen_t clientAddrSz = sizeof(clientAddr); + struct sockaddr_in6 clientAddr; + socklen_t clientAddrSz = sizeof(clientAddr); #endif conn = (WOLFSSHD_CONNECTION*)WMALLOC(sizeof(WOLFSSHD_CONNECTION), NULL, DYNTYPE_SSHD); if (conn == NULL) { @@ -2417,8 +2453,16 @@ static int StartSSHD(int argc, char** argv) conn->fd = (int)accept(listenFd, (struct sockaddr*)&clientAddr, &clientAddrSz); if (conn->fd >= 0) { - inet_ntop(AF_INET, &clientAddr.sin_addr, conn->ip, - INET_ADDRSTRLEN); + if (clientAddr.sin6_family == AF_INET) { + struct sockaddr_in* addr4 = + (struct sockaddr_in*)&clientAddr; + inet_ntop(AF_INET, &addr4->sin_addr, conn->ip, + INET_ADDRSTRLEN); + } + else if (clientAddr.sin6_family == AF_INET6) { + inet_ntop(AF_INET6, &clientAddr.sin6_addr, conn->ip, + INET6_ADDRSTRLEN); + } } #endif @@ -2426,19 +2470,34 @@ static int StartSSHD(int argc, char** argv) #ifdef USE_WINDOWS_API unsigned long blocking = 1; if (ioctlsocket(conn->fd, FIONBIO, &blocking) - == SOCKET_ERROR) - err_sys("ioctlsocket failed"); + == SOCKET_ERROR) { + WLOG(WS_LOG_DEBUG, "wolfSSH non-fatal error: " + "ioctlsocket failed"); + WCLOSESOCKET(conn->fd); + WFREE(conn, NULL, DYNTYPE_SSHD); + continue; + } #elif defined(WOLFSSL_MDK_ARM) || defined(WOLFSSL_KEIL_TCP_NET) \ || defined (WOLFSSL_TIRTOS)|| defined(WOLFSSL_VXWORKS) || \ defined(WOLFSSL_NUCLEUS) /* non blocking not supported, for now */ #else int flags = fcntl(conn->fd, F_GETFL, 0); - if (flags < 0) - err_sys("fcntl get failed"); + if (flags < 0) { + WLOG(WS_LOG_DEBUG, "wolfSSH non-fatal error: " + "fcntl get failed"); + WCLOSESOCKET(conn->fd); + WFREE(conn, NULL, DYNTYPE_SSHD); + continue; + } flags = fcntl(conn->fd, F_SETFL, flags | O_NONBLOCK); - if (flags < 0) - err_sys("fcntl set failed"); + if (flags < 0) { + WLOG(WS_LOG_DEBUG, "wolfSSH non-fatal error: " + "fcntl set failed"); + WCLOSESOCKET(conn->fd); + WFREE(conn, NULL, DYNTYPE_SSHD); + continue; + } #endif } ret = NewConnection(conn); @@ -2469,7 +2528,10 @@ static int StartSSHD(int argc, char** argv) } #endif - CleanupCTX(conf, &ctx); + CleanupCTX(conf, &ctx, &banner); + if (banner) { + WFREE(banner, NULL, DYNTYPE_STRING); + } wolfSSHD_ConfigFree(conf); wolfSSHD_AuthFreeUser(auth); wolfSSH_Cleanup(); @@ -2487,6 +2549,159 @@ static int StartSSHD(int argc, char** argv) #endif } +#ifdef _WIN32 +/* Used to setup a console and run command as a user. + * returns the process exit value */ +static int SetupConsole(char* inCmd) +{ + HANDLE sOut; + HANDLE sIn; + HPCON pCon = 0; + COORD cord = { 80,24 }; /* Default to 80x24. Updated later. */ + STARTUPINFOEXW ext; + int ret = WS_SUCCESS; + PWSTR cmd = NULL; + size_t cmdSz = 0; + PROCESS_INFORMATION processInfo; + size_t sz = 0; + DWORD processState = 0; + PCSTR shellCmd = "c:\\windows\\system32\\cmd.exe"; + + if (inCmd == NULL) { + return -1; + } + + sIn = GetStdHandle(STD_INPUT_HANDLE); + + if (WSTRCMP(shellCmd, inCmd) != 0) { + /* if not opening a shell, pipe virtual terminal sequences to 'nul' */ + if (CreatePseudoConsole(cord, sIn, INVALID_HANDLE_VALUE, 0, &pCon) != S_OK) { + ret = WS_FATAL_ERROR; + } + else { + CloseHandle(sIn); + } + } + else + { + /* if opening a shell, pipe virtual terminal sequences back to calling process */ + sOut = GetStdHandle(STD_OUTPUT_HANDLE); + if (CreatePseudoConsole(cord, sIn, sOut, 0, &pCon) != S_OK) { + ret = WS_FATAL_ERROR; + } + else { + CloseHandle(sIn); + CloseHandle(sOut); + } + } + + /* setup startup extended info for pseudo terminal */ + ZeroMemory(&ext, sizeof(ext)); + if (ret == WS_SUCCESS) { + ext.StartupInfo.cb = sizeof(STARTUPINFOEX); + (void)InitializeProcThreadAttributeList(NULL, 1, 0, &sz); + if (sz == 0) { + ret = WS_FATAL_ERROR; + } + + if (ret == WS_SUCCESS) { + /* Using HeapAlloc for better support when possibly passing + memory between Windows Modules */ + ext.lpAttributeList = + (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, sz); + if (ext.lpAttributeList == NULL) { + ret = WS_FATAL_ERROR; + } + } + + if (ret == WS_SUCCESS) { + if (InitializeProcThreadAttributeList(ext.lpAttributeList, 1, 0, + &sz) != TRUE) { + ret = WS_FATAL_ERROR; + } + } + + if (ret == WS_SUCCESS) { + if (UpdateProcThreadAttribute(ext.lpAttributeList, 0, + PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, + pCon, sizeof(HPCON), NULL, NULL) != TRUE) { + ret = WS_FATAL_ERROR; + } + } + } + + if (ret == WS_SUCCESS) { + cmdSz = WSTRLEN(inCmd) + 1; /* +1 for terminator */ + cmd = (PWSTR)HeapAlloc(GetProcessHeap(), 0, sizeof(wchar_t) * cmdSz); + if (cmd == NULL) { + ret = WS_MEMORY_E; + } + else { + size_t numConv = 0; + + WMEMSET(cmd, 0, sizeof(wchar_t) * cmdSz); + mbstowcs_s(&numConv, cmd, cmdSz, inCmd, strlen(inCmd)); + } + } + + ZeroMemory(&processInfo, sizeof(processInfo)); + if (ret == WS_SUCCESS) { + if (CreateProcessW(NULL, cmd, + NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, + &ext.StartupInfo, &processInfo) != TRUE) { + return WS_FATAL_ERROR; + } + else { + DWORD ava = 0; + + WaitForInputIdle(processInfo.hProcess, 1000); + + do { + /* wait indefinitly for console process to exit */ + if (ava == 0) { + if (WaitForSingleObject(processInfo.hProcess, INFINITE) == WAIT_FAILED) { + break; + } + } + + /* check if process is still running and give time to drain pipes */ + if (GetExitCodeProcess(processInfo.hProcess, &processState) + == TRUE) { + if (processState != STILL_ACTIVE) { + Sleep(100); /* give the stdout/stderr of process a + * little time to write to pipe */ + if (PeekNamedPipe(GetStdHandle(STD_OUTPUT_HANDLE), NULL, 0, NULL, &ava, NULL) + == TRUE) { + if (ava > 0) { + /* if data still pending then continue + * sending it over SSH */ + continue; + } + } + break; + } + } + } while (1); + CloseHandle(processInfo.hThread); + } + } + + if (cmd != NULL) { + HeapFree(GetProcessHeap(), 0, cmd); + } + + if (ext.lpAttributeList != NULL) { + HeapFree(GetProcessHeap(), 0, ext.lpAttributeList); + } + + if (pCon != 0) { + ClosePseudoConsole(pCon); + } + + return processState; +} +#endif /* _WIN32 */ + int main(int argc, char** argv) { #ifdef _WIN32 @@ -2496,6 +2711,13 @@ int main(int argc, char** argv) if (WSTRCMP(argv[i], "-D") == 0) { isService = 0; } + if (WSTRCMP(argv[i], "-r") == 0) { + if (argc < i + 1) { + /* was expecting command to run after -r argument */ + return -1; + } + return SetupConsole(argv[i + 1]); + } } if (isService) { diff --git a/configure.ac b/configure.ac index 9e7b1abcc..617ff0523 100644 --- a/configure.ac +++ b/configure.ac @@ -1,9 +1,9 @@ # wolfssh -# Copyright (C) 2014-2023 wolfSSL Inc. +# Copyright (C) 2014-2024 wolfSSL Inc. # All right reserved. -AC_COPYRIGHT([Copyright (C) 2014-2023 wolfSSL Inc.]) -AC_INIT([wolfssh],[1.4.15],[support@wolfssl.com],[wolfssh],[https://www.wolfssl.com]) +AC_COPYRIGHT([Copyright (C) 2014-2024 wolfSSL Inc.]) +AC_INIT([wolfssh],[1.4.18],[support@wolfssl.com],[wolfssh],[https://www.wolfssl.com]) AC_PREREQ([2.63]) AC_CONFIG_AUX_DIR([build-aux]) @@ -18,18 +18,19 @@ AC_ARG_PROGRAM AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADERS([config.h]) -WOLFSSH_LIBRARY_VERSION=15:2:7 -# | | | -# +------+ | +---+ -# | | | +WOLFSSH_LIBRARY_VERSION=17:0:10 +# | | | +# +-----+ | +----+ +# | | | # current:revision:age -# | | | -# | | +- increment if interfaces have been added -# | | set to zero if interfaces have been removed -# | | or changed -# | +- increment if source code has changed -# | set to zero if current is incremented -# +- increment if interfaces have been added, removed or changed +# | | | +# | | +- increment if interfaces have been added +# | | +- set to zero if interfaces have been +# | | removed or changed +# | +- increment if source code has changed +# | +- set to zero if current is incremented +# +- increment if interfaces have been added, removed +# or changed AC_SUBST([WOLFSSH_LIBRARY_VERSION]) LT_PREREQ([2.2]) @@ -193,7 +194,7 @@ AC_ARG_ENABLE([fwd], # pseudo-terminal AC_ARG_ENABLE([term], [AS_HELP_STRING([--disable-term],[Disable pseudo-terminal support (default: enabled)])], - [ENABLED_PTERM=$enableval],[ENABLED_PTERM=yes]) + [ENABLED_TERM=$enableval],[ENABLED_TERM=yes]) # shell support AC_ARG_ENABLE([shell], @@ -250,7 +251,7 @@ AS_IF([test "x$ENABLED_SFTP" = "xyes"], [AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_SFTP"]) AS_IF([test "x$ENABLED_FWD" = "xyes"], [AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_FWD"]) -AS_IF([test "x$ENABLED_PTERM" = "xyes"], +AS_IF([test "x$ENABLED_TERM" = "xyes"], [AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_TERM"]) AS_IF([test "x$ENABLED_SHELL" = "xyes"], [AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_SHELL"]) @@ -354,7 +355,7 @@ AS_ECHO([" Features"]) AS_ECHO([" * Inline Code: $ENABLED_INLINE"]) AS_ECHO([" * Small stack: $ENABLED_SMALLSTACK"]) AS_ECHO([" * keygen: $ENABLED_KEYGEN"]) -AS_ECHO([" * psuedo-terminal: $ENABLED_PTERM"]) +AS_ECHO([" * psuedo-terminal: $ENABLED_TERM"]) AS_ECHO([" * echoserver shell support: $ENABLED_SHELL"]) AS_ECHO([" * scp: $ENABLED_SCP"]) AS_ECHO([" * sftp: $ENABLED_SFTP"]) diff --git a/examples/client/client.c b/examples/client/client.c index 4d56575f6..e37468c6f 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -1,6 +1,6 @@ /* client.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -117,6 +117,8 @@ static void ShowUsage(void) printf(" -A <filename> filename for DER CA certificate to verify host\n"); printf(" -X Ignore IP checks on peer vs peer certificate\n"); #endif + printf(" -E List all possible algos\n"); + printf(" -k set the list of key algos to use\n"); } @@ -365,6 +367,26 @@ static THREAD_RET readPeer(void* in) FD_SET(fd, &errSet); #ifdef USE_WINDOWS_API + if (args->rawMode == 0) { + DWORD wrd; + + /* get console mode will fail on handles that are not a console, + * i.e. if the stdout is being redirected to a file */ + if (GetConsoleMode(stdoutHandle, &wrd) != FALSE) { + /* depend on the terminal to process VT characters */ + #ifndef _WIN32_WINNT_WIN10 + /* support for virtual terminal processing was introduced in windows 10 */ + #define _WIN32_WINNT_WIN10 0x0A00 + #endif + #if defined(WINVER) && (WINVER >= _WIN32_WINNT_WIN10) + wrd |= (ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT); + #endif + if (SetConsoleMode(stdoutHandle, wrd) == FALSE) { + err_sys("Unable to set console mode"); + } + } + } + /* set handle to use for window resize */ wc_LockMutex(&args->lock); wolfSSH_SetTerminalResizeCtx(args->ssh, stdoutHandle); @@ -444,29 +466,21 @@ static THREAD_RET readPeer(void* in) } } else { + #ifdef USE_WINDOWS_API + DWORD writtn = 0; + #endif buf[bufSz - 1] = '\0'; #ifdef USE_WINDOWS_API - if (args->rawMode == 0) { - ret = wolfSSH_ConvertConsole(args->ssh, stdoutHandle, buf, - ret); - if (ret != WS_SUCCESS && ret != WS_WANT_READ) { - err_sys("issue with print out"); - } - if (ret == WS_WANT_READ) { - ret = 0; - } - } - else { - printf("%s", buf); - WFFLUSH(stdout); + if (WriteFile(stdoutHandle, buf, bufSz, &writtn, NULL) == FALSE) { + err_sys("Failed to write to stdout handle"); } #else if (write(STDOUT_FILENO, buf, ret) < 0) { perror("write to stdout error "); } - WFFLUSH(stdout); #endif + WFFLUSH(stdout); } if (wolfSSH_stream_peek(args->ssh, buf, bufSz) <= 0) { bytes = 0; /* read it all */ @@ -624,7 +638,9 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) const char* password = NULL; const char* cmd = NULL; const char* privKeyName = NULL; + const char* keyList = NULL; byte imExit = 0; + byte listAlgos = 0; byte nonBlock = 0; byte keepOpen = 0; #ifdef USE_WINDOWS_API @@ -641,7 +657,7 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) (void)keepOpen; - while ((ch = mygetopt(argc, argv, "?ac:h:i:j:p:tu:xzNP:RJ:A:Xe")) != -1) { + while ((ch = mygetopt(argc, argv, "?ac:h:i:j:p:tu:xzNP:RJ:A:XeEk:")) != -1) { switch (ch) { case 'h': host = myoptarg; @@ -701,6 +717,10 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) #endif #endif + case 'E': + listAlgos = 1; + break; + case 'x': /* exit after successful connection without read/write */ imExit = 1; @@ -710,6 +730,10 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) nonBlock = 1; break; + case 'k': + keyList = myoptarg; + break; + #if !defined(SINGLE_THREADED) && !defined(WOLFSSL_NUCLEUS) case 'c': cmd = myoptarg; @@ -756,7 +780,7 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) err_sys("If setting priv key, need pub key."); } - ret = ClientSetPrivateKey(privKeyName, userEcc); + ret = ClientSetPrivateKey(privKeyName, userEcc, NULL); if (ret != 0) { err_sys("Error setting private key"); } @@ -764,12 +788,12 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) #ifdef WOLFSSH_CERTS /* passed in certificate to use */ if (certName) { - ret = ClientUseCert(certName); + ret = ClientUseCert(certName, NULL); } else #endif if (pubKeyName) { - ret = ClientUsePubKey(pubKeyName, userEcc); + ret = ClientUsePubKey(pubKeyName, userEcc, NULL); } if (ret != 0) { err_sys("Error setting public key"); @@ -779,6 +803,12 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) if (ctx == NULL) err_sys("Couldn't create wolfSSH client context."); + if (keyList) { + if (wolfSSH_CTX_SetAlgoListKey(ctx, NULL) != WS_SUCCESS) { + err_sys("Error setting key list.\n"); + } + } + if (((func_args*)args)->user_auth == NULL) wolfSSH_SetUserAuth(ctx, ClientUserAuth); else @@ -825,8 +855,57 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) if (ret != WS_SUCCESS) err_sys("Couldn't set the username."); + if (listAlgos) { + word32 idx = 0; + const char* current = NULL; + + printf("KEX:\n"); + do { + current = wolfSSH_QueryKex(&idx); + if (current) { + printf("\t%d: %s\n", idx, current); + } + } while (current != NULL); + printf("Set KEX: %s\n\n", wolfSSH_GetAlgoListKex(ssh)); + + idx = 0; + printf("Key:\n"); + do { + current = wolfSSH_QueryKey(&idx); + if (current) { + printf("\t%d: %s\n", idx, current); + } + } while (current != NULL); + printf("Set Key: %s\n\n", wolfSSH_GetAlgoListKey(ssh)); + + idx = 0; + printf("Cipher:\n"); + do { + current = wolfSSH_QueryCipher(&idx); + if (current) { + printf("\t%d: %s\n", idx, current); + } + } while (current != NULL); + printf("Set Cipher: %s\n\n", wolfSSH_GetAlgoListCipher(ssh)); + + idx = 0; + printf("Mac:\n"); + do { + current = wolfSSH_QueryMac(&idx); + if (current) { + printf("\t%d: %s\n", idx, current); + } + } while (current != NULL); + printf("Set Mac: %s\n", wolfSSH_GetAlgoListMac(ssh)); + + wolfSSH_free(ssh); + wolfSSH_CTX_free(ctx); + WOLFSSL_RETURN_FROM_THREAD(0); + } + build_addr(&clientAddr, host, port); - tcp_socket(&sockFd); + tcp_socket(&sockFd, ((struct sockaddr_in *)&clientAddr)->sin_family); + ret = connect(sockFd, (const struct sockaddr *)&clientAddr, clientAddrSz); if (ret != 0) err_sys("Couldn't connect to server."); @@ -977,7 +1056,8 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) } ret = wolfSSH_shutdown(ssh); /* do not continue on with shutdown process if peer already disconnected */ - if (ret != WS_SOCKET_ERROR_E && wolfSSH_get_error(ssh) != WS_SOCKET_ERROR_E) { + if (ret != WS_SOCKET_ERROR_E && wolfSSH_get_error(ssh) != WS_SOCKET_ERROR_E + && wolfSSH_get_error(ssh) != WS_CHANNEL_CLOSED) { if (ret != WS_SUCCESS) { err_sys("Sending the shutdown messages failed."); } @@ -1000,7 +1080,7 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) err_sys("Closing client stream failed"); } - ClientFreeBuffers(pubKeyName, privKeyName); + ClientFreeBuffers(pubKeyName, privKeyName, NULL); #if !defined(WOLFSSH_NO_ECC) && defined(FP_ECC) && defined(HAVE_THREAD_LS) wc_ecc_fp_free(); /* free per thread cache */ #endif diff --git a/examples/client/client.h b/examples/client/client.h index 80aa61eeb..c02d80d9d 100644 --- a/examples/client/client.h +++ b/examples/client/client.h @@ -1,6 +1,6 @@ /* client.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/examples/client/common.c b/examples/client/common.c index 97051386c..c4281ab4f 100644 --- a/examples/client/common.c +++ b/examples/client/common.c @@ -1,6 +1,6 @@ /* common.c * - * Copyright (C) 2014-2022 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -241,7 +241,8 @@ static const unsigned int hanselPrivateEccSz = 223; #if defined(WOLFSSH_CERTS) -static int load_der_file(const char* filename, byte** out, word32* outSz) +static int load_der_file(const char* filename, byte** out, word32* outSz, + void* heap) { WFILE* file; byte* in; @@ -267,7 +268,7 @@ static int load_der_file(const char* filename, byte** out, word32* outSz) return -1; } - in = (byte*)WMALLOC(inSz, NULL, 0); + in = (byte*)WMALLOC(inSz, heap, 0); if (in == NULL) { WFCLOSE(NULL, file); return -1; @@ -276,7 +277,7 @@ static int load_der_file(const char* filename, byte** out, word32* outSz) ret = (int)WFREAD(NULL, in, 1, inSz, file); if (ret <= 0 || (word32)ret != inSz) { ret = -1; - WFREE(in, NULL, 0); + WFREE(in, heap, 0); in = 0; inSz = 0; } @@ -403,7 +404,8 @@ int ClientPublicKeyCheck(const byte* pubKey, word32 pubKeySz, void* ctx) current->ipString); WLOG(WS_LOG_DEBUG, "\texpecting host IP : %s", (char*)ctx); - if (XSTRCMP(ctx, current->ipString) == 0) { + if (XSTRCMP((const char*)ctx, + current->ipString) == 0) { WLOG(WS_LOG_DEBUG, "\tmatched!"); ipMatch = 1; } @@ -651,19 +653,20 @@ int ClientSetEcho(int type) /* Set certificate to use and public key. * returns 0 on success */ -int ClientUseCert(const char* certName) +int ClientUseCert(const char* certName, void* heap) { int ret = 0; if (certName != NULL) { #ifdef WOLFSSH_CERTS - ret = load_der_file(certName, &userPublicKey, &userPublicKeySz); + ret = load_der_file(certName, &userPublicKey, &userPublicKeySz, heap); if (ret == 0) { userPublicKeyType = publicKeyType; userPublicKeyTypeSz = (word32)WSTRLEN((const char*)publicKeyType); pubKeyLoaded = 1; } #else + (void)heap; fprintf(stderr, "Certificate support not compiled in"); ret = WS_NOT_COMPILED; #endif @@ -675,7 +678,7 @@ int ClientUseCert(const char* certName) /* Reads the private key to use from file name privKeyName. * returns 0 on success */ -int ClientSetPrivateKey(const char* privKeyName, int userEcc) +int ClientSetPrivateKey(const char* privKeyName, int userEcc, void* heap) { int ret = 0; @@ -684,14 +687,14 @@ int ClientSetPrivateKey(const char* privKeyName, int userEcc) #ifndef WOLFSSH_NO_ECC ret = wolfSSH_ReadKey_buffer(hanselPrivateEcc, hanselPrivateEccSz, WOLFSSH_FORMAT_ASN1, &userPrivateKey, &userPrivateKeySz, - &userPrivateKeyType, &userPrivateKeyTypeSz, NULL); + &userPrivateKeyType, &userPrivateKeyTypeSz, heap); #endif } else { #ifndef WOLFSSH_NO_RSA ret = wolfSSH_ReadKey_buffer(hanselPrivateRsa, hanselPrivateRsaSz, WOLFSSH_FORMAT_ASN1, &userPrivateKey, &userPrivateKeySz, - &userPrivateKeyType, &userPrivateKeyTypeSz, NULL); + &userPrivateKeyType, &userPrivateKeyTypeSz, heap); #endif } isPrivate = 1; @@ -702,7 +705,7 @@ int ClientSetPrivateKey(const char* privKeyName, int userEcc) ret = wolfSSH_ReadKey_file(privKeyName, (byte**)&userPrivateKey, &userPrivateKeySz, (const byte**)&userPrivateKeyType, &userPrivateKeyTypeSz, - &isPrivate, NULL); + &isPrivate, heap); #else printf("file system not compiled in!\n"); ret = NOT_COMPILED_IN; @@ -715,7 +718,7 @@ int ClientSetPrivateKey(const char* privKeyName, int userEcc) /* Set public key to use * returns 0 on success */ -int ClientUsePubKey(const char* pubKeyName, int userEcc) +int ClientUsePubKey(const char* pubKeyName, int userEcc, void* heap) { int ret = 0; @@ -728,7 +731,7 @@ int ClientUsePubKey(const char* pubKeyName, int userEcc) ret = wolfSSH_ReadKey_buffer((const byte*)hanselPublicEcc, (word32)strlen(hanselPublicEcc), WOLFSSH_FORMAT_SSH, &p, &userPublicKeySz, - &userPublicKeyType, &userPublicKeyTypeSz, NULL); + &userPublicKeyType, &userPublicKeyTypeSz, heap); #endif } else { @@ -736,7 +739,7 @@ int ClientUsePubKey(const char* pubKeyName, int userEcc) ret = wolfSSH_ReadKey_buffer((const byte*)hanselPublicRsa, (word32)strlen(hanselPublicRsa), WOLFSSH_FORMAT_SSH, &p, &userPublicKeySz, - &userPublicKeyType, &userPublicKeyTypeSz, NULL); + &userPublicKeyType, &userPublicKeyTypeSz, heap); #endif } isPrivate = 1; @@ -747,7 +750,7 @@ int ClientUsePubKey(const char* pubKeyName, int userEcc) ret = wolfSSH_ReadKey_file(pubKeyName, &userPublicKey, &userPublicKeySz, (const byte**)&userPublicKeyType, &userPublicKeyTypeSz, - &isPrivate, NULL); + &isPrivate, heap); #else printf("file system not compiled in!\n"); ret = -1; @@ -770,7 +773,7 @@ int ClientLoadCA(WOLFSSH_CTX* ctx, const char* caCert) byte* der = NULL; word32 derSz; - ret = load_der_file(caCert, &der, &derSz); + ret = load_der_file(caCert, &der, &derSz, ctx->heap); if (ret == 0) { if (wolfSSH_CTX_AddRootCert_buffer(ctx, der, derSz, WOLFSSH_FORMAT_ASN1) != WS_SUCCESS) { @@ -789,13 +792,14 @@ int ClientLoadCA(WOLFSSH_CTX* ctx, const char* caCert) } -void ClientFreeBuffers(const char* pubKeyName, const char* privKeyName) +void ClientFreeBuffers(const char* pubKeyName, const char* privKeyName, + void* heap) { if (pubKeyName != NULL && userPublicKey != NULL) { - WFREE(userPublicKey, NULL, DYNTYPE_PRIVKEY); + WFREE(userPublicKey, heap, DYNTYPE_PRIVKEY); } if (privKeyName != NULL && userPrivateKey != NULL) { - WFREE(userPrivateKey, NULL, DYNTYPE_PRIVKEY); + WFREE(userPrivateKey, heap, DYNTYPE_PRIVKEY); } } diff --git a/examples/client/common.h b/examples/client/common.h index 68c36efe2..395d4288a 100644 --- a/examples/client/common.h +++ b/examples/client/common.h @@ -1,6 +1,6 @@ /* common.h * - * Copyright (C) 2014-2022 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -21,16 +21,17 @@ #ifndef WOLFSSH_COMMON_H #define WOLFSSH_COMMON_H int ClientLoadCA(WOLFSSH_CTX* ctx, const char* caCert); -int ClientUsePubKey(const char* pubKeyName, int userEcc); -int ClientSetPrivateKey(const char* privKeyName, int userEcc); -int ClientUseCert(const char* certName); +int ClientUsePubKey(const char* pubKeyName, int userEcc, void* heap); +int ClientSetPrivateKey(const char* privKeyName, int userEcc, void* heap); +int ClientUseCert(const char* certName, void* heap); int ClientSetEcho(int type); int ClientUserAuth(byte authType, WS_UserAuthData* authData, void* ctx); int ClientPublicKeyCheck(const byte* pubKey, word32 pubKeySz, void* ctx); void ClientIPOverride(int flag); -void ClientFreeBuffers(const char* pubKeyName, const char* privKeyName); +void ClientFreeBuffers(const char* pubKeyName, const char* privKeyName, + void* heap); #endif /* WOLFSSH_COMMON_H */ diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index 3d9b542e0..2075d4858 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -1,6 +1,6 @@ /* echoserver.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -289,6 +289,7 @@ static int callbackReqFailure(WOLFSSH *ssh, void *buf, word32 sz, void *ctx) return WS_SUCCESS; } + static void *global_req(void *ctx) { int ret; @@ -328,6 +329,50 @@ static void *global_req(void *ctx) #endif +static void printKeyCompleteText(WOLFSSH* ssh, WS_Text id, const char* tag) +{ + char str[200]; + size_t strSz = sizeof(str); + size_t ret; + + ret = wolfSSH_GetText(ssh, id, str, strSz); + if (ret == strSz) { + printf("\tString size was not large enough for %s\n", tag); + } + printf("\t%-30s : %s\n", tag, str); +} + + +static void callbackKeyingComplete(void* ctx) +{ + WOLFSSH* ssh = (WOLFSSH*)ctx; + + if (ssh != NULL) { + printf("Keying Complete:\n"); + printKeyCompleteText(ssh, WOLFSSH_TEXT_KEX_ALGO, + "WOLFSSH_TEXT_KEX_ALGO"); + + printKeyCompleteText(ssh, WOLFSSH_TEXT_KEX_CURVE, + "WOLFSSH_TEXT_KEX_CURVE"); + + printKeyCompleteText(ssh, WOLFSSH_TEXT_KEX_HASH, + "WOLFSSH_TEXT_KEX_HASH"); + + printKeyCompleteText(ssh, WOLFSSH_TEXT_CRYPTO_IN_CIPHER, + "WOLFSSH_TEXT_CRYPTO_IN_CIPHER"); + + printKeyCompleteText(ssh, WOLFSSH_TEXT_CRYPTO_IN_MAC, + "WOLFSSH_TEXT_CRYPTO_IN_MAC"); + + printKeyCompleteText(ssh, WOLFSSH_TEXT_CRYPTO_OUT_CIPHER, + "WOLFSSH_TEXT_CRYPTO_OUT_CIPHER"); + + printKeyCompleteText(ssh, WOLFSSH_TEXT_CRYPTO_OUT_MAC, + "WOLFSSH_TEXT_CRYPTO_OUT_MAC"); + } +} + + #ifdef WOLFSSH_AGENT static const char EnvNameAuthPort[] = "SSH_AUTH_SOCK"; @@ -609,6 +654,87 @@ static int termios_show(int fd) #endif /* SHELL_DEBUG */ +#ifdef WOLFSSH_STATIC_MEMORY + #ifndef WOLFSSL_STATIC_MEMORY + #error Requires the static memory functions from wolfSSL + #endif + #if defined(WOLFSSH_SCP) || defined(WOLFSSH_SHELL) || defined(WOLFSSH_FWD) + #warning Static memory configuration for SFTP, results may vary. + #endif + typedef WOLFSSL_HEAP_HINT ES_HEAP_HINT; + + /* This static buffer is tuned for building with SFTP only. The static + * buffer size is calulated by multiplying the pairs of sizeList items + * and distList items and summing (32*64 + 128*118 + ...) and adding + * the sum of the distList values times the sizeof wc_Memory (rounded up + * to a word, 24). This total was 288kb plus change, rounded up to 289. */ + #ifndef ES_STATIC_SIZES + #define ES_STATIC_SIZES 32,128,384,800,3120,8400,17552,32846,131072 + #endif + #ifndef ES_STATIC_DISTS + #define ES_STATIC_DISTS 64,118,3,4,6,2,2,2,1 + #endif + #ifndef ES_STATIC_LISTSZ + #define ES_STATIC_LISTSZ 9 + #endif + #ifndef ES_STATIC_BUFSZ + #define ES_STATIC_BUFSZ (289*1024) + #endif + static const word32 static_sizeList[] = {ES_STATIC_SIZES}; + static const word32 static_distList[] = {ES_STATIC_DISTS}; + static byte static_buffer[ES_STATIC_BUFSZ]; + + static void wolfSSH_MemoryPrintStats(ES_HEAP_HINT* hint) + { + if (hint != NULL) { + word16 i; + WOLFSSL_MEM_STATS stats; + + wolfSSL_GetMemStats(hint->memory, &stats); + + /* print to stderr so is on the same pipe as WOLFSSL_DEBUG */ + fprintf(stderr, "Total mallocs = %d\n", stats.totalAlloc); + fprintf(stderr, "Total frees = %d\n", stats.totalFr); + fprintf(stderr, "Current mallocs = %d\n", stats.curAlloc); + fprintf(stderr, "Available IO = %d\n", stats.avaIO); + fprintf(stderr, "Max con. handshakes = %d\n", stats.maxHa); + fprintf(stderr, "Max con. IO = %d\n", stats.maxIO); + fprintf(stderr, "State of memory blocks: size : available\n"); + for (i = 0; i < WOLFMEM_MAX_BUCKETS; i++) { + fprintf(stderr, " %8d : %d\n", + stats.blockSz[i], stats.avaBlock[i]); + } + } + } + + static void wolfSSH_MemoryConnPrintStats(ES_HEAP_HINT* hint) + { + if (hint != NULL) { + WOLFSSL_MEM_CONN_STATS* stats = hint->stats; + + /* fill out statistics if wanted and WOLFMEM_TRACK_STATS flag */ + if (hint->memory->flag & WOLFMEM_TRACK_STATS + && hint->stats != NULL) { + fprintf(stderr, "peak connection memory = %d\n", + stats->peakMem); + fprintf(stderr, "current memory in use = %d\n", + stats->curMem); + fprintf(stderr, "peak connection allocs = %d\n", + stats->peakAlloc); + fprintf(stderr, "current connection allocs = %d\n", + stats->curAlloc); + fprintf(stderr, "total connection allocs = %d\n", + stats->totalAlloc); + fprintf(stderr, "total connection frees = %d\n\n", + stats->totalFr); + } + } + } +#else + typedef void ES_HEAP_HINT; +#endif + + int ChildRunning = 0; #ifdef WOLFSSH_SHELL @@ -738,6 +864,25 @@ static int ssh_worker(thread_ctx_t* threadCtx) ChildRunning = 1; #endif +#if defined(WOLFSSH_TERM) && defined(WOLFSSH_SHELL) + /* set initial size of terminal based on saved size */ +#if defined(HAVE_SYS_IOCTL_H) + wolfSSH_DoModes(ssh->modes, ssh->modesSz, childFd); + { + struct winsize s = {0}; + + s.ws_col = ssh->widthChar; + s.ws_row = ssh->heightRows; + s.ws_xpixel = ssh->widthPixels; + s.ws_ypixel = ssh->heightPixels; + + ioctl(childFd, TIOCSWINSZ, &s); + } +#endif /* HAVE_SYS_IOCTL_H */ + + wolfSSH_SetTerminalResizeCtx(ssh, (void*)&childFd); +#endif /* WOLFSSH_TERM && WOLFSSH_SHELL */ + while (ChildRunning) { fd_set readFds; WS_SOCKET_T maxFd; @@ -1196,11 +1341,8 @@ static int sftp_worker(thread_ctx_t* threadCtx) } 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) { + else if (selected == WS_SELECT_RECV_READY) { ret = wolfSSH_worker(ssh, NULL); error = wolfSSH_get_error(ssh); if (ret == WS_REKEYING) { @@ -1213,7 +1355,6 @@ static int sftp_worker(thread_ctx_t* threadCtx) error == WS_WINDOW_FULL) { timeout = TEST_SFTP_TIMEOUT; ret = error; - continue; } if (error == WS_EOF) { @@ -1278,7 +1419,8 @@ static int NonBlockSSH_accept(WOLFSSH* ssh) while ((ret != WS_SUCCESS && ret != WS_SCP_COMPLETE && ret != WS_SFTP_COMPLETE) - && (error == WS_WANT_READ || error == WS_WANT_WRITE)) { + && (error == WS_WANT_READ || error == WS_WANT_WRITE || + error == WS_AUTH_PENDING)) { if (error == WS_WANT_READ) printf("... server would read block\n"); @@ -1288,7 +1430,8 @@ static int NonBlockSSH_accept(WOLFSSH* ssh) select_ret = tcp_select(sockfd, 1); if (select_ret == WS_SELECT_RECV_READY || select_ret == WS_SELECT_ERROR_READY || - error == WS_WANT_WRITE) + error == WS_WANT_WRITE || + error == WS_AUTH_PENDING) { ret = wolfSSH_accept(ssh); error = wolfSSH_get_error(ssh); @@ -1310,11 +1453,16 @@ static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs) passwdRetry = MAX_PASSWD_RETRY; - if (!threadCtx->nonBlock) + if (!threadCtx->nonBlock) { ret = wolfSSH_accept(threadCtx->ssh); - else + if (wolfSSH_get_error(threadCtx->ssh) == WS_AUTH_PENDING) { + printf("Auth pending error, use -N for non blocking\n"); + printf("Trying to close down the connection\n"); + } + } + else { ret = NonBlockSSH_accept(threadCtx->ssh); - + } #ifdef WOLFSSH_SCP /* finish off SCP operation */ if (ret == WS_SCP_INIT) { @@ -1423,6 +1571,11 @@ static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs) threadCtx->fwdCbCtx.originName = NULL; } #endif + +#ifdef WOLFSSH_STATIC_MEMORY + wolfSSH_MemoryConnPrintStats(threadCtx->ssh->ctx->heap); +#endif + wolfSSH_free(threadCtx->ssh); if (ret != 0) { @@ -1456,21 +1609,19 @@ static int load_file(const char* fileName, byte* buf, word32* bufSz) fileSz = (word32)WFTELL(NULL, file); WREWIND(NULL, file); - if (fileSz > *bufSz) { - if (buf == NULL) - *bufSz = fileSz; + if (buf == NULL || fileSz > *bufSz) { + *bufSz = fileSz; WFCLOSE(NULL, file); return 0; } readSz = (word32)WFREAD(NULL, buf, 1, fileSz, file); + WFCLOSE(NULL, file); + if (readSz < fileSz) { - WFCLOSE(NULL, file); - return 0; + fileSz = 0; } - WFCLOSE(NULL, file); - return fileSz; } #endif /* NO_FILESYSTEM */ @@ -1928,6 +2079,7 @@ static int wsUserAuthResult(byte res, } +static int userAuthWouldBlock = 0; static int wsUserAuth(byte authType, WS_UserAuthData* authData, void* ctx) @@ -1941,6 +2093,12 @@ static int wsUserAuth(byte authType, return WOLFSSH_USERAUTH_FAILURE; } + if (userAuthWouldBlock > 0) { + printf("User Auth would block ....\n"); + userAuthWouldBlock--; + return WOLFSSH_USERAUTH_WOULD_BLOCK; + } + if (authType != WOLFSSH_USERAUTH_PASSWORD && #ifdef WOLFSSH_ALLOW_USERAUTH_NONE authType != WOLFSSH_USERAUTH_NONE && @@ -2156,6 +2314,8 @@ static void ShowUsage(void) #ifdef WOLFSSH_CERTS printf(" -a <file> load in a root CA certificate file\n"); #endif + printf(" -k set the list of key algos to use\n"); + printf(" -b <num> test user auth would block\n"); } @@ -2194,6 +2354,8 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) WS_SOCKET_T listenFd = WOLFSSH_SOCKET_INVALID; word32 defaultHighwater = EXAMPLE_HIGHWATER_MARK; word32 threadCount = 0; + const char* keyList = NULL; + ES_HEAP_HINT* heap = NULL; int multipleConnections = 1; int userEcc = 0; int peerEcc = 0; @@ -2215,7 +2377,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) serverArgs->return_code = EXIT_SUCCESS; if (argc > 0) { - const char* optlist = "?1a:d:efEp:R:Ni:j:I:J:K:P:"; + const char* optlist = "?1a:d:efEp:R:Ni:j:I:J:K:P:k:b:"; myoptind = 0; while ((ch = mygetopt(argc, argv, optlist)) != -1) { switch (ch) { @@ -2237,6 +2399,10 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) userEcc = 1; break; + case 'k' : + keyList = myoptarg; + break; + case 'E': peerEcc = 1; break; @@ -2295,6 +2461,10 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) passwdList = StrListAdd(passwdList, myoptarg); break; + case 'b': + userAuthWouldBlock = atoi(myoptarg); + break; + default: ShowUsage(); serverArgs->return_code = MY_EX_USAGE; @@ -2327,11 +2497,32 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) ES_ERROR("Couldn't initialize wolfSSH.\n"); } - ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL); + #ifdef WOLFSSH_STATIC_MEMORY + { + int ret; + + ret = wc_LoadStaticMemory_ex(&heap, + ES_STATIC_LISTSZ, static_sizeList, static_distList, + static_buffer, sizeof(static_buffer), + WOLFMEM_GENERAL|WOLFMEM_TRACK_STATS, 0); + if (ret != 0) { + ES_ERROR("Couldn't set up static memory pool.\n"); + } + } + #endif /* WOLFSSH_STATIC_MEMORY */ + + ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, heap); if (ctx == NULL) { ES_ERROR("Couldn't allocate SSH CTX data.\n"); } + wolfSSH_SetKeyingCompletionCb(ctx, callbackKeyingComplete); + if (keyList) { + if (wolfSSH_CTX_SetAlgoListKey(ctx, keyList) != WS_SUCCESS) { + ES_ERROR("Error setting key list.\n"); + } + } + WMEMSET(&pwMapList, 0, sizeof(pwMapList)); if (serverArgs->user_auth == NULL) wolfSSH_SetUserAuth(ctx, wsUserAuth); @@ -2565,7 +2756,11 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) WFREE(threadCtx, NULL, 0); ES_ERROR("Couldn't allocate SSH data.\n"); } + #ifdef WOLFSSH_STATIC_MEMORY + wolfSSH_MemoryConnPrintStats(heap); + #endif wolfSSH_SetUserAuthCtx(ssh, &pwMapList); + wolfSSH_SetKeyingCompletionCbCtx(ssh, (void*)ssh); /* Use the session object for its own highwater callback ctx */ if (defaultHighwater > 0) { wolfSSH_SetHighwaterCtx(ssh, (void*)ssh); @@ -2641,6 +2836,10 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) wc_FreeMutex(&doneLock); PwMapListDelete(&pwMapList); wolfSSH_CTX_free(ctx); +#ifdef WOLFSSH_STATIC_MEMORY + wolfSSH_MemoryPrintStats(heap); +#endif + if (wolfSSH_Cleanup() != WS_SUCCESS) { ES_ERROR("Couldn't clean up wolfSSH.\n"); } diff --git a/examples/echoserver/echoserver.h b/examples/echoserver/echoserver.h index 704206db9..45fcb4325 100644 --- a/examples/echoserver/echoserver.h +++ b/examples/echoserver/echoserver.h @@ -1,6 +1,6 @@ /* echoserver.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/examples/echoserver/include.am b/examples/echoserver/include.am index 532f0f7bb..4192d605c 100644 --- a/examples/echoserver/include.am +++ b/examples/echoserver/include.am @@ -7,5 +7,5 @@ examples_echoserver_echoserver_SOURCES = examples/echoserver/echoserver.c \ examples/echoserver/echoserver.h examples_echoserver_echoserver_LDADD = src/libwolfssh.la examples_echoserver_echoserver_DEPENDENCIES = src/libwolfssh.la -examples_echoserver_echoserver_CFLAGS = $(AM_CFLAGS) +examples_echoserver_echoserver_CFLAGS = $(AM_CFLAGS) ${AM_CPPFLAGS} endif diff --git a/examples/portfwd/portfwd.c b/examples/portfwd/portfwd.c index 173d31899..07bb95da9 100644 --- a/examples/portfwd/portfwd.c +++ b/examples/portfwd/portfwd.c @@ -1,6 +1,6 @@ /* portfwd.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -380,12 +380,14 @@ THREAD_RETURN WOLFSSH_THREAD portfwd_worker(void* args) if (ret != WS_SUCCESS) err_sys("Couldn't set the username."); + /* Socket to SSH peer. */ build_addr(&hostAddr, host, port); + tcp_socket(&sshFd, ((struct sockaddr_in *)&hostAddr)->sin_family); + + /* Receive from client application or connect to server application. */ build_addr(&fwdFromHostAddr, fwdFromHost, fwdFromPort); + tcp_socket(&listenFd, ((struct sockaddr_in *)&fwdFromHostAddr)->sin_family); - tcp_socket(&sshFd); /* Socket to SSH peer. */ - tcp_socket(&listenFd); /* Either receive from client application or connect - to server application. */ tcp_listen(&listenFd, &fwdFromPort, 1); printf("Connecting to the SSH server...\n"); diff --git a/examples/portfwd/wolfssh_portfwd.h b/examples/portfwd/wolfssh_portfwd.h index 3a3c5e47a..996360b29 100644 --- a/examples/portfwd/wolfssh_portfwd.h +++ b/examples/portfwd/wolfssh_portfwd.h @@ -1,6 +1,6 @@ /* wolfssh_portfwd.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/examples/scpclient/scpclient.c b/examples/scpclient/scpclient.c index a23fdef46..042a5b7f4 100644 --- a/examples/scpclient/scpclient.c +++ b/examples/scpclient/scpclient.c @@ -1,6 +1,6 @@ /* scpclient.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -217,7 +217,7 @@ THREAD_RETURN WOLFSSH_THREAD scp_client(void* args) err_sys("Empty path values"); } - ret = ClientSetPrivateKey(privKeyName, 0); + ret = ClientSetPrivateKey(privKeyName, 0, NULL); if (ret != 0) { err_sys("Error setting private key"); } @@ -225,12 +225,12 @@ THREAD_RETURN WOLFSSH_THREAD scp_client(void* args) #ifdef WOLFSSH_CERTS /* passed in certificate to use */ if (certName) { - ret = ClientUseCert(certName); + ret = ClientUseCert(certName, NULL); } else #endif { - ret = ClientUsePubKey(pubKeyName, 0); + ret = ClientUsePubKey(pubKeyName, 0, NULL); } if (ret != 0) { err_sys("Error setting public key"); @@ -253,13 +253,13 @@ THREAD_RETURN WOLFSSH_THREAD scp_client(void* args) #endif /* WOLFSSH_CERTS */ wolfSSH_CTX_SetPublicKeyCheck(ctx, ClientPublicKeyCheck); - wolfSSH_SetPublicKeyCheckCtx(ssh, (void*)host); - ssh = wolfSSH_new(ctx); if (ssh == NULL) err_sys("Couldn't create wolfSSH session."); + wolfSSH_SetPublicKeyCheckCtx(ssh, (void*)host); + if (password != NULL) wolfSSH_SetUserAuthCtx(ssh, (void*)password); @@ -280,8 +280,9 @@ THREAD_RETURN WOLFSSH_THREAD scp_client(void* args) { printf("IPV4 address\n"); build_addr(&clientAddr, host, port); - tcp_socket(&sockFd); - ret = connect(sockFd, (const struct sockaddr *)&clientAddr, clientAddrSz); + tcp_socket(&sockFd, ((struct sockaddr_in *)&clientAddr)->sin_family); + ret = connect(sockFd, (const struct sockaddr *)&clientAddr, + clientAddrSz); } if (ret != 0) @@ -312,7 +313,9 @@ THREAD_RETURN WOLFSSH_THREAD scp_client(void* args) ret = wolfSSH_shutdown(ssh); /* do not continue on with shutdown process if peer already disconnected */ - if (ret != WS_SOCKET_ERROR_E && wolfSSH_get_error(ssh) != WS_SOCKET_ERROR_E) { + if (ret != WS_CHANNEL_CLOSED && ret != WS_SOCKET_ERROR_E && + wolfSSH_get_error(ssh) != WS_SOCKET_ERROR_E && + wolfSSH_get_error(ssh) != WS_CHANNEL_CLOSED) { if (ret != WS_SUCCESS) { err_sys("Sending the shutdown messages failed."); } @@ -324,10 +327,12 @@ THREAD_RETURN WOLFSSH_THREAD scp_client(void* args) WCLOSESOCKET(sockFd); wolfSSH_free(ssh); wolfSSH_CTX_free(ctx); - if (ret != WS_SUCCESS && ret != WS_SOCKET_ERROR_E) + if (ret != WS_SUCCESS && ret != WS_SOCKET_ERROR_E && + ret != WS_CHANNEL_CLOSED) { err_sys("Closing scp stream failed. Connection could have been closed by peer"); + } - ClientFreeBuffers(pubKeyName, privKeyName); + ClientFreeBuffers(pubKeyName, privKeyName, NULL); #if !defined(WOLFSSH_NO_ECC) && defined(FP_ECC) && defined(HAVE_THREAD_LS) wc_ecc_fp_free(); /* free per thread cache */ #endif diff --git a/examples/scpclient/scpclient.h b/examples/scpclient/scpclient.h index dcbd9508b..c46e4ce27 100644 --- a/examples/scpclient/scpclient.h +++ b/examples/scpclient/scpclient.h @@ -1,6 +1,6 @@ /* scpclient.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/examples/sftpclient/sftpclient.c b/examples/sftpclient/sftpclient.c index 01a2308b6..eec4db1a4 100644 --- a/examples/sftpclient/sftpclient.c +++ b/examples/sftpclient/sftpclient.c @@ -1,6 +1,6 @@ /* sftpclient.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -63,6 +63,36 @@ static char* workingDir; #define AUTOPILOT_PUT 2 +#ifdef WOLFSSH_STATIC_MEMORY + #include <wolfssl/wolfcrypt/memory.h> + + typedef WOLFSSL_HEAP_HINT SFTPC_HEAP_HINT; + + /* This static buffer is tuned for building with SFTP only. The static + * buffer size is calulated by multiplying the pairs of sizeList items + * and distList items and summing (32*50 + 128*100 + ...) and adding + * the sum of the distList values times the sizeof wc_Memory (rounded up + * to a word, 24). This total was 268kb plus change, rounded up to 269. */ + #ifndef SFTPC_STATIC_SIZES + #define SFTPC_STATIC_SIZES 64,128,384,800,3120,8400,17552,33104,131072 + #endif + #ifndef SFTPC_STATIC_DISTS + #define SFTPC_STATIC_DISTS 60,100,4,6,5,2,1,2,1 + #endif + #ifndef SFTPC_STATIC_LISTSZ + #define SFTPC_STATIC_LISTSZ 9 + #endif + #ifndef SFTPC_STATIC_BUFSZ + #define SFTPC_STATIC_BUFSZ (269*1024) + #endif + static const word32 static_sizeList[] = {SFTPC_STATIC_SIZES}; + static const word32 static_distList[] = {SFTPC_STATIC_DISTS}; + static byte static_buffer[SFTPC_STATIC_BUFSZ]; +#else /* WOLFSSH_STATIC_MEMORY */ + typedef void SFTPC_HEAP_HINT; +#endif /* WOLFSSH_STATIC_MEMORY */ + + static void err_msg(const char* s) { printf("%s\n", s); @@ -1143,7 +1173,7 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) char* pubKeyName = NULL; char* certName = NULL; char* caCert = NULL; - + SFTPC_HEAP_HINT* heap = NULL; int argc = ((func_args*)args)->argc; char** argv = ((func_args*)args)->argv; @@ -1263,7 +1293,17 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) } #endif - ret = ClientSetPrivateKey(privKeyName, userEcc); +#ifdef WOLFSSH_STATIC_MEMORY + ret = wc_LoadStaticMemory_ex(&heap, + SFTPC_STATIC_LISTSZ, static_sizeList, static_distList, + static_buffer, sizeof(static_buffer), + WOLFMEM_GENERAL, 0); + if (ret != 0) { + err_sys("Couldn't set up static memory pool.\n"); + } +#endif /* WOLFSSH_STATIC_MEMORY */ + + ret = ClientSetPrivateKey(privKeyName, userEcc, heap); if (ret != 0) { err_sys("Error setting private key"); } @@ -1271,18 +1311,18 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) #ifdef WOLFSSH_CERTS /* passed in certificate to use */ if (certName) { - ret = ClientUseCert(certName); + ret = ClientUseCert(certName, heap); } else #endif { - ret = ClientUsePubKey(pubKeyName, 0); + ret = ClientUsePubKey(pubKeyName, 0, heap); } if (ret != 0) { err_sys("Error setting public key"); } - ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL); + ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, heap); if (ctx == NULL) err_sys("Couldn't create wolfSSH client context."); @@ -1326,7 +1366,8 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) err_sys("Couldn't set the username."); build_addr(&clientAddr, host, port); - tcp_socket(&sockFd); + tcp_socket(&sockFd, ((struct sockaddr_in *)&clientAddr)->sin_family); + ret = connect(sockFd, (const struct sockaddr *)&clientAddr, clientAddrSz); if (ret != 0) err_sys("Couldn't connect to server."); @@ -1394,7 +1435,7 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) ((func_args*)args)->return_code = ret; } - ClientFreeBuffers(pubKeyName, privKeyName); + ClientFreeBuffers(pubKeyName, privKeyName, heap); #if !defined(WOLFSSH_NO_ECC) && defined(FP_ECC) && defined(HAVE_THREAD_LS) wc_ecc_fp_free(); /* free per thread cache */ #endif diff --git a/examples/sftpclient/sftpclient.h b/examples/sftpclient/sftpclient.h index 1d515a695..03e1e55c9 100644 --- a/examples/sftpclient/sftpclient.h +++ b/examples/sftpclient/sftpclient.h @@ -1,6 +1,6 @@ /* sftpclient.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/ide/Espressif/ESP-IDF/default_espressif_options.h b/ide/Espressif/ESP-IDF/default_espressif_options.h index b1cac4f08..e77d81fff 100644 --- a/ide/Espressif/ESP-IDF/default_espressif_options.h +++ b/ide/Espressif/ESP-IDF/default_espressif_options.h @@ -1,7 +1,7 @@ /* wolfssl options.h * generated from configure options * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/CMakeLists.txt b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/CMakeLists.txt index 09e7badc4..c920d7cea 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/CMakeLists.txt +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/CMakeLists.txt @@ -1,22 +1,21 @@ # [wolfSSH Project]/CMakeLists.txt # -# Copyright (C) 2006-2023 WOLFSSL Inc. +# Copyright (C) 2014-2024 wolfSSL Inc. # -# This file is part of WOLFSSH. +# This file is part of wolfSSH. # -# WOLFSSH is free software; you can redistribute it and/or modify +# wolfSSH is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # -# WOLFSSH is distributed in the hope that it will be useful, +# wolfSSH is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA +# along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. # # cmake for WOLFSSH Espressif projects # diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/README.md b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/README.md index 8ed8996cc..770bce636 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/README.md +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/README.md @@ -1,4 +1,4 @@ -# wolfSSL Server Project +# wolfSSH Server Project This is an example wolfSSH Server based on the minimally viable wolfSSL [template](../wolfssh_template/README.md) @@ -8,8 +8,6 @@ and the instructions in [wolfssh README.md](https://github.com/wolfSSL/wolfssh#r To connect: ```bash -TODO - ssh -p 22222 jack@192.168.1.32 ``` diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssh/CMakeLists.txt b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssh/CMakeLists.txt index c3e5d37ab..11b8d6a49 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssh/CMakeLists.txt +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssh/CMakeLists.txt @@ -1,22 +1,21 @@ # [wolfSSL Project]/components/wolfssh/CMakeLists.txt # -# Copyright (C) 2006-2023 WOLFSSL Inc. +# Copyright (C) 2014-2024 wolfSSL Inc. # -# This file is part of WOLFSSH. +# This file is part of wolfSSH. # -# WOLFSSH is free software; you can redistribute it and/or modify +# wolfSSH is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # -# WOLFSSH is distributed in the hope that it will be useful, +# wolfSSH is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA +# along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. # # cmake for WOLFSSH Espressif projects v5.6.6 r1 # diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssl/CMakeLists.txt b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssl/CMakeLists.txt index d58704b84..6ee31d2bf 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssl/CMakeLists.txt +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssl/CMakeLists.txt @@ -1,25 +1,24 @@ # -# Copyright (C) 2006-2023 wolfSSL Inc. +# Copyright (C) 2014-2024 wolfSSL Inc. # -# This file is part of wolfSSL. +# This file is part of wolfSSH. # -# wolfSSL is free software; you can redistribute it and/or modify +# wolfSSH is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # -# wolfSSL is distributed in the hope that it will be useful, +# wolfSSH is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA +# along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. # # cmake for wolfssl Espressif projects # -# Version 5.6.4.016 for improved manual setting of WOLFSSL_ROOT + ESP8266 support; optional esp-timer / driver components +# Version 5.7.0 template update + THIS_IDF_PATH # # See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html # @@ -35,11 +34,18 @@ set(CMAKE_CURRENT_SOURCE_DIR ".") # set(COMPONENT_REQUIRES lwip) # we typically don't need lwip directly in wolfssl component # Optionally set your source to wolfSSL in your project CMakeLists.txt like this: -# set(WOLFSSL_ROOT "c:/test/blogtest/wolfssl" ) +# set(WOLFSSL_ROOT "c:/test/my_wolfssl" ) if ( "${WOLFSSL_ROOT}" STREQUAL "") set(WOLFSSL_ROOT "$ENV{WOLFSSL_ROOT}" ) endif() + +if( "$ENV{IDF_PATH}" STREQUAL "" ) + message(FATAL_ERROR "IDF_PATH Environment variable not set!") +else() + string(REPLACE "\\" "/" THIS_IDF_PATH "$ENV{IDF_PATH}") +endif() + # Optional compiler definitions to help with system name detection (typically printed by app diagnostics) if(VERBOSE_COMPONENT_MESSAGES) if(WIN32) @@ -195,16 +201,47 @@ function(FIND_WOLFSSL_DIRECTORY OUTPUT_FOUND_WOLFSSL_DIRECTORY) return() endif() + # Maintain CURRENT_SEARCH_DIR, but check various suffixes with CURRENT_SEARCH_DIR_ALT if( THIS_USER ) # Check for "wolfssl-[username]" subdirectory as we recurse up the directory tree set(CURRENT_SEARCH_DIR_ALT ${CURRENT_SEARCH_DIR}/wolfssl-${THIS_USER}) - message(STATUS "Looking in ${CURRENT_SEARCH_DIR}") + message(STATUS "Looking in ${CURRENT_SEARCH_DIR_ALT}") + + IS_WOLFSSL_SOURCE("${CURRENT_SEARCH_DIR_ALT}" FOUND_WOLFSSL ) + if ( FOUND_WOLFSSL ) + message(STATUS "Found wolfssl in user-suffix CURRENT_SEARCH_DIR_ALT = ${CURRENT_SEARCH_DIR_ALT}") + set(CURRENT_SEARCH_DIR "${CURRENT_SEARCH_DIR_ALT}") + set(${OUTPUT_FOUND_WOLFSSL_DIRECTORY} ${CURRENT_SEARCH_DIR} PARENT_SCOPE) + return() + endif() + endif() + + if ( FOUND_WOLFSSL ) + # if we already found the source, skip attempt of "wolfssl-master" + else() + set(CURRENT_SEARCH_DIR_ALT ${CURRENT_SEARCH_DIR}/wolfssl-master) + message(STATUS "Looking in ${CURRENT_SEARCH_DIR_ALT}") + + IS_WOLFSSL_SOURCE("${CURRENT_SEARCH_DIR_ALT}" FOUND_WOLFSSL ) + if ( FOUND_WOLFSSL ) + message(STATUS "Found wolfssl in master-suffix CURRENT_SEARCH_DIR_ALT = ${CURRENT_SEARCH_DIR_ALT}") + set(CURRENT_SEARCH_DIR "${CURRENT_SEARCH_DIR_ALT}") + set(${OUTPUT_FOUND_WOLFSSL_DIRECTORY} ${CURRENT_SEARCH_DIR} PARENT_SCOPE) + return() + endif() + endif() + + if ( FOUND_WOLFSSL ) + # if we already found the source, skip attempt of "wolfssl" + else() + set(CURRENT_SEARCH_DIR_ALT ${CURRENT_SEARCH_DIR}/wolfssl) + message(STATUS "Looking in ${CURRENT_SEARCH_DIR_ALT}") - #if(EXISTS ${CURRENT_SEARCH_DIR_ALT} AND IS_DIRECTORY ${CURRENT_SEARCH_DIR_ALT} AND EXISTS "${CURRENT_SEARCH_DIR_ALT}/wolfcrypt/src") IS_WOLFSSL_SOURCE("${CURRENT_SEARCH_DIR_ALT}" FOUND_WOLFSSL ) if ( FOUND_WOLFSSL ) - message(STATUS "Found wolfssl in user-suffix CURRENT_SEARCH_DIR_ALT = ${CURRENT_SEARCH_DIR_ALT}") - set(${OUTPUT_FOUND_WOLFSSL_DIRECTORY} ${CURRENT_SEARCH_DIR_ALT} PARENT_SCOPE) + message(STATUS "Found wolfssl in CURRENT_SEARCH_DIR_ALT = ${CURRENT_SEARCH_DIR_ALT}") + set(CURRENT_SEARCH_DIR "${CURRENT_SEARCH_DIR_ALT}") + set(${OUTPUT_FOUND_WOLFSSL_DIRECTORY} ${CURRENT_SEARCH_DIR} PARENT_SCOPE) return() endif() endif() @@ -224,7 +261,8 @@ function(FIND_WOLFSSL_DIRECTORY OUTPUT_FOUND_WOLFSSL_DIRECTORY) get_filename_component(CURRENT_SEARCH_DIR "${CURRENT_SEARCH_DIR}" DIRECTORY) message(STATUS "Next CURRENT_SEARCH_DIR = ${CURRENT_SEARCH_DIR}") if( "${PRIOR_SEARCH_DIR}" STREQUAL "${CURRENT_SEARCH_DIR}" ) - # when the search directory is empty, we'll give up + # When the parent is current directory, cannot go any further. We didn't find wolfssl. + # When the search directory is empty, we'll give up. set(CURRENT_SEARCH_DIR "") endif() endwhile() @@ -240,13 +278,42 @@ endfunction() # FIND_WOLFSSL_DIRECTORY(WOLFSSL_ROOT) # +message(STATUS "CONFIG_TARGET_PLATFORM = ${CONFIG_TARGET_PLATFORM}") + +if (0) + get_cmake_property(_variableNames VARIABLES) + list (SORT _variableNames) + message(STATUS "") + message(STATUS "ALL VARIABLES BEGIN") + message(STATUS "") + foreach (_variableName ${_variableNames}) + message(STATUS "${_variableName}=${${_variableName}}") + endforeach() + message(STATUS "") + message(STATUS "ALL VARIABLES END") + message(STATUS "") +endif() + +if ( ("${CONFIG_TARGET_PLATFORM}" STREQUAL "esp8266") OR ("${IDF_TARGET}" STREQUAL "esp8266") ) + # There's no esp_timer, no driver components for the ESP8266 + message(STATUS "Early expansion EXCLUDES esp_timer: ${THIS_INCLUDE_TIMER}") + message(STATUS "Early expansion EXCLUDES driver: ${THIS_INCLUDE_DRIVER}") + set(THIS_INCLUDE_TIMER "") + set(THIS_INCLUDE_DRIVER "") +else() + message(STATUS "Early expansion includes esp_timer: ${THIS_INCLUDE_TIMER}") + message(STATUS "Early expansion includes driver: ${THIS_INCLUDE_DRIVER}") + set(THIS_INCLUDE_TIMER "esp_timer") + set(THIS_INCLUDE_DRIVER "driver") +endif() + if(CMAKE_BUILD_EARLY_EXPANSION) message(STATUS "wolfssl component CMAKE_BUILD_EARLY_EXPANSION:") idf_component_register( REQUIRES "${COMPONENT_REQUIRES}" PRIV_REQUIRES # esp_hw_support - "${THIS_INCLUDE_TIMER}" - "${THIS_INCLUDE_DRIVER}" # this will typically only be needed for wolfSSL benchmark + ${THIS_INCLUDE_TIMER} + ${THIS_INCLUDE_DRIVER} # this will typically only be needed for wolfSSL benchmark ) else() @@ -255,18 +322,8 @@ else() message(STATUS "wolfssl component config:") message(STATUS "************************************************************************************************") - if ( "${CONFIG_TARGET_PLATFORM}" STREQUAL "esp8266") - # There's no esp_timer, no driver components for the ESP8266 - set(THIS_INCLUDE_TIMER "") - set(THIS_INCLUDE_DRIVER "") - else() - set(THIS_INCLUDE_TIMER "esp_timer") - set(THIS_INCLUDE_DRIVER "driver") - endif() - # search for wolfSSL - # TODO allow for cmake prior def - + FIND_WOLFSSL_DIRECTORY(WOLFSSL_ROOT) if(WOLFSSL_ROOT) IS_WOLFSSL_SOURCE("${WOLFSSL_ROOT}" FOUND_WOLFSSL) if(FOUND_WOLFSSL) @@ -288,8 +345,8 @@ else() else() message(STATUS "Failed: wolfssl directory not found.") # Abort. We need wolfssl _somewhere_. - message(FATAL_ERROR "Could not find wolfssl in ${WOLFSSL_ROOT}.\n" - "Try setting WOLFSSL_ROOT environment variable or git clone.") + message(FATAL_ERROR "Could not find wolfssl in any parent directory named wolfssl-${THIS_USER}, wolfssl-master, or wolfssl.\n" + "Try setting WOLFSSL_ROOT environment variable, cmake variable in project, copy source, or use managed components.") # Abort CMake after fatal error. endif() @@ -327,6 +384,7 @@ else() # wolfSSL user_settings.h is in the local project. set(WOLFSSL_PROJECT_DIR "${CMAKE_HOME_DIRECTORY}/components/wolfssl") + # add_definitions(-DWOLFSSL_USER_SETTINGS_DIR="${WOLFSSL_PROJECT_DIR}/include/user_settings.h") string(REPLACE "/" "//" STR_WOLFSSL_PROJECT_DIR "${WOLFSSL_PROJECT_DIR}") add_definitions(-DWOLFSSL_USER_SETTINGS_DIR="${STR_WOLFSSL_PROJECT_DIR}//include//user_settings.h") @@ -485,10 +543,10 @@ else() message(STATUS "Could not find RTOS path") endif() endif() - + message(STATUS "THIS_IDF_PATH = $THIS_IDF_PATH") # wolfSSL-specific include directories set(COMPONENT_ADD_INCLUDEDIRS - "./include" # this is the location of local project wolfssl user_settings.h + "./include" # this is the location of wolfssl user_settings.h "\"${WOLFSSL_ROOT}/\"" "\"${WOLFSSL_ROOT}/wolfssl/\"" "\"${WOLFSSL_ROOT}/wolfssl/wolfcrypt/\"" @@ -515,9 +573,14 @@ else() "\"${WOLFSSL_ROOT}/src/ssl_bn.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_certman.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_crypto.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_load.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_misc.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_p7p12.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_sess.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/x509.c\"" "\"${WOLFSSL_ROOT}/src/x509_str.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/ext_kyber.c\"" # external Kyber disabled by default + "\"${WOLFSSL_ROOT}/wolfssl/wolfcrypt/ext_kyber.h\"" # external Kyber disabled by default "\"${WOLFSSL_ROOT}/wolfcrypt/src/evp.c\"" "\"${WOLFSSL_ROOT}/wolfcrypt/src/misc.c\"" "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_arm32.c\"" diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssl/include/user_settings.h b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssl/include/user_settings.h index 70c35493c..d5509d72d 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssl/include/user_settings.h +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssl/include/user_settings.h @@ -1,22 +1,21 @@ /* user_settings.h * - * Copyright (C) 2006-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * - * This file is part of wolfSSL. + * This file is part of wolfSSH. * - * wolfSSL is free software; you can redistribute it and/or modify + * wolfSSH is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * - * wolfSSL is distributed in the hope that it will be useful, + * wolfSSH is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. */ #include <sdkconfig.h> /* essential to chip set detection */ diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/CMakeLists.txt b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/CMakeLists.txt index d58c2ae1c..0945f3222 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/CMakeLists.txt +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/CMakeLists.txt @@ -1,22 +1,21 @@ # [wolfSSL Project]/main/CMakeLists.txt # -# Copyright (C) 2006-2023 WOLFSSL Inc. +# Copyright (C) 2014-2024 wolfSSL Inc. # -# This file is part of WOLFSSH. +# This file is part of wolfSSH. # -# WOLFSSH is free software; you can redistribute it and/or modify +# wolfSSH is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # -# WOLFSSH is distributed in the hope that it will be useful, +# wolfSSH is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA +# along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. # # cmake for WOLFSSH Espressif projects # diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/echoserver.c b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/echoserver.c index 2eae60762..49c90d42d 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/echoserver.c +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/echoserver.c @@ -1,6 +1,6 @@ /* echoserver.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/echoserver.h b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/echoserver.h index ac7e17cf2..91a9bf2dc 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/echoserver.h +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/echoserver.h @@ -1,6 +1,6 @@ /* echoserver.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -25,7 +25,7 @@ #include <types.h> #ifndef WOLFSSH_THREAD - #define WOLFSSH_THREAD + #define WOLFSSH_THREAD WOLFSSL_THREAD #endif THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args); diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/main.h b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/main.h index 7e07ec1df..73d227693 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/main.h +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/main.h @@ -1,22 +1,21 @@ /* template main.h * - * Copyright (C) 2006-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * - * This file is part of wolfSSL. + * This file is part of wolfSSH. * - * wolfSSL is free software; you can redistribute it and/or modify + * wolfSSH is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * - * wolfSSL is distributed in the hope that it will be useful, + * wolfSSH is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _MAIN_H_ #define _MAIN_H_ diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/time_helper.h b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/time_helper.h index a47f94001..e244ddd17 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/time_helper.h +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/time_helper.h @@ -1,21 +1,20 @@ /* - * Copyright (C) 2006-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * - * This file is part of wolfSSL. + * This file is part of wolfSSH. * - * wolfSSL is free software; you can redistribute it and/or modify + * wolfSSH is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * - * wolfSSL is distributed in the hope that it will be useful, + * wolfSSH is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. */ /* common Espressif time_helper v5.6.3.001 */ diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/wifi_connect.h b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/wifi_connect.h index a0014d4c3..9ac4d7f58 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/wifi_connect.h +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/wifi_connect.h @@ -1,22 +1,21 @@ /* wifi_connect.h * - * Copyright (C) 2006-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * - * This file is part of wolfSSL. + * This file is part of wolfSSH. * - * wolfSSL is free software; you can redistribute it and/or modify + * wolfSSH is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * - * wolfSSL is distributed in the hope that it will be useful, + * wolfSSH is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _WIFI_CONNECT_H_ #define _WIFI_CONNECT_H_ diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/main.c b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/main.c index 238720af9..b1c9835a7 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/main.c +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/main.c @@ -1,22 +1,21 @@ /* main.c * - * Copyright (C) 2006-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * - * wolfSSL is free software; you can redistribute it and/or modify + * wolfSSH is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * - * wolfSSL is distributed in the hope that it will be useful, + * wolfSSH is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. */ #include "sdkconfig.h" #include "main.h" @@ -35,16 +34,18 @@ #warning "Check components/wolfssl/include" #endif +/* wolfSSH */ +#include <wolfssh/test.h> + /* this project */ #include "wifi_connect.h" #include "time_helper.h" static const char* const TAG = "My Project"; - void app_main(void) { - void* args = {0}; + func_args args = {0}; int ret = ESP_OK; ESP_LOGI(TAG, "------------ wolfSSL wolfSSH template Example ----------"); @@ -158,6 +159,7 @@ void app_main(void) /* TODO: Consider pulling in wolfSSH server.c example source automatically: * Keep in mind the nature of this example as an Espressif Component. * See https://github.com/wolfSSL/wolfssh/tree/master/examples/server */ + memset(&args, 0, sizeof(func_args)); echoserver_test(&args); ESP_LOGI(TAG, "\n\nDone!" diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/time_helper.c b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/time_helper.c index 0abf70c5a..498c53d78 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/time_helper.c +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/time_helper.c @@ -1,22 +1,21 @@ /* time_helper.c * - * Copyright (C) 2006-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * - * This file is part of wolfSSL. + * This file is part of wolfSSH. * - * wolfSSL is free software; you can redistribute it and/or modify + * wolfSSH is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * - * wolfSSL is distributed in the hope that it will be useful, + * wolfSSH is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. */ /* common Espressif time_helper v5.6.3.002 */ diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/wifi_connect.c b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/wifi_connect.c index 384a86274..973eb4fff 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/wifi_connect.c +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/wifi_connect.c @@ -1,22 +1,21 @@ /* wifi_connect.c * - * Copyright (C) 2006-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * - * This file is part of wolfSSL. + * This file is part of wolfSSH. * - * wolfSSL is free software; you can redistribute it and/or modify + * wolfSSH is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * - * wolfSSL is distributed in the hope that it will be useful, + * wolfSSH is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. */ #include "wifi_connect.h" diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssh/CMakeLists.txt b/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssh/CMakeLists.txt index c3e5d37ab..11b8d6a49 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssh/CMakeLists.txt +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssh/CMakeLists.txt @@ -1,22 +1,21 @@ # [wolfSSL Project]/components/wolfssh/CMakeLists.txt # -# Copyright (C) 2006-2023 WOLFSSL Inc. +# Copyright (C) 2014-2024 wolfSSL Inc. # -# This file is part of WOLFSSH. +# This file is part of wolfSSH. # -# WOLFSSH is free software; you can redistribute it and/or modify +# wolfSSH is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # -# WOLFSSH is distributed in the hope that it will be useful, +# wolfSSH is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA +# along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. # # cmake for WOLFSSH Espressif projects v5.6.6 r1 # diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssl/CMakeLists.txt b/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssl/CMakeLists.txt index d58704b84..6ee31d2bf 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssl/CMakeLists.txt +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssl/CMakeLists.txt @@ -1,25 +1,24 @@ # -# Copyright (C) 2006-2023 wolfSSL Inc. +# Copyright (C) 2014-2024 wolfSSL Inc. # -# This file is part of wolfSSL. +# This file is part of wolfSSH. # -# wolfSSL is free software; you can redistribute it and/or modify +# wolfSSH is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # -# wolfSSL is distributed in the hope that it will be useful, +# wolfSSH is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA +# along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. # # cmake for wolfssl Espressif projects # -# Version 5.6.4.016 for improved manual setting of WOLFSSL_ROOT + ESP8266 support; optional esp-timer / driver components +# Version 5.7.0 template update + THIS_IDF_PATH # # See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html # @@ -35,11 +34,18 @@ set(CMAKE_CURRENT_SOURCE_DIR ".") # set(COMPONENT_REQUIRES lwip) # we typically don't need lwip directly in wolfssl component # Optionally set your source to wolfSSL in your project CMakeLists.txt like this: -# set(WOLFSSL_ROOT "c:/test/blogtest/wolfssl" ) +# set(WOLFSSL_ROOT "c:/test/my_wolfssl" ) if ( "${WOLFSSL_ROOT}" STREQUAL "") set(WOLFSSL_ROOT "$ENV{WOLFSSL_ROOT}" ) endif() + +if( "$ENV{IDF_PATH}" STREQUAL "" ) + message(FATAL_ERROR "IDF_PATH Environment variable not set!") +else() + string(REPLACE "\\" "/" THIS_IDF_PATH "$ENV{IDF_PATH}") +endif() + # Optional compiler definitions to help with system name detection (typically printed by app diagnostics) if(VERBOSE_COMPONENT_MESSAGES) if(WIN32) @@ -195,16 +201,47 @@ function(FIND_WOLFSSL_DIRECTORY OUTPUT_FOUND_WOLFSSL_DIRECTORY) return() endif() + # Maintain CURRENT_SEARCH_DIR, but check various suffixes with CURRENT_SEARCH_DIR_ALT if( THIS_USER ) # Check for "wolfssl-[username]" subdirectory as we recurse up the directory tree set(CURRENT_SEARCH_DIR_ALT ${CURRENT_SEARCH_DIR}/wolfssl-${THIS_USER}) - message(STATUS "Looking in ${CURRENT_SEARCH_DIR}") + message(STATUS "Looking in ${CURRENT_SEARCH_DIR_ALT}") + + IS_WOLFSSL_SOURCE("${CURRENT_SEARCH_DIR_ALT}" FOUND_WOLFSSL ) + if ( FOUND_WOLFSSL ) + message(STATUS "Found wolfssl in user-suffix CURRENT_SEARCH_DIR_ALT = ${CURRENT_SEARCH_DIR_ALT}") + set(CURRENT_SEARCH_DIR "${CURRENT_SEARCH_DIR_ALT}") + set(${OUTPUT_FOUND_WOLFSSL_DIRECTORY} ${CURRENT_SEARCH_DIR} PARENT_SCOPE) + return() + endif() + endif() + + if ( FOUND_WOLFSSL ) + # if we already found the source, skip attempt of "wolfssl-master" + else() + set(CURRENT_SEARCH_DIR_ALT ${CURRENT_SEARCH_DIR}/wolfssl-master) + message(STATUS "Looking in ${CURRENT_SEARCH_DIR_ALT}") + + IS_WOLFSSL_SOURCE("${CURRENT_SEARCH_DIR_ALT}" FOUND_WOLFSSL ) + if ( FOUND_WOLFSSL ) + message(STATUS "Found wolfssl in master-suffix CURRENT_SEARCH_DIR_ALT = ${CURRENT_SEARCH_DIR_ALT}") + set(CURRENT_SEARCH_DIR "${CURRENT_SEARCH_DIR_ALT}") + set(${OUTPUT_FOUND_WOLFSSL_DIRECTORY} ${CURRENT_SEARCH_DIR} PARENT_SCOPE) + return() + endif() + endif() + + if ( FOUND_WOLFSSL ) + # if we already found the source, skip attempt of "wolfssl" + else() + set(CURRENT_SEARCH_DIR_ALT ${CURRENT_SEARCH_DIR}/wolfssl) + message(STATUS "Looking in ${CURRENT_SEARCH_DIR_ALT}") - #if(EXISTS ${CURRENT_SEARCH_DIR_ALT} AND IS_DIRECTORY ${CURRENT_SEARCH_DIR_ALT} AND EXISTS "${CURRENT_SEARCH_DIR_ALT}/wolfcrypt/src") IS_WOLFSSL_SOURCE("${CURRENT_SEARCH_DIR_ALT}" FOUND_WOLFSSL ) if ( FOUND_WOLFSSL ) - message(STATUS "Found wolfssl in user-suffix CURRENT_SEARCH_DIR_ALT = ${CURRENT_SEARCH_DIR_ALT}") - set(${OUTPUT_FOUND_WOLFSSL_DIRECTORY} ${CURRENT_SEARCH_DIR_ALT} PARENT_SCOPE) + message(STATUS "Found wolfssl in CURRENT_SEARCH_DIR_ALT = ${CURRENT_SEARCH_DIR_ALT}") + set(CURRENT_SEARCH_DIR "${CURRENT_SEARCH_DIR_ALT}") + set(${OUTPUT_FOUND_WOLFSSL_DIRECTORY} ${CURRENT_SEARCH_DIR} PARENT_SCOPE) return() endif() endif() @@ -224,7 +261,8 @@ function(FIND_WOLFSSL_DIRECTORY OUTPUT_FOUND_WOLFSSL_DIRECTORY) get_filename_component(CURRENT_SEARCH_DIR "${CURRENT_SEARCH_DIR}" DIRECTORY) message(STATUS "Next CURRENT_SEARCH_DIR = ${CURRENT_SEARCH_DIR}") if( "${PRIOR_SEARCH_DIR}" STREQUAL "${CURRENT_SEARCH_DIR}" ) - # when the search directory is empty, we'll give up + # When the parent is current directory, cannot go any further. We didn't find wolfssl. + # When the search directory is empty, we'll give up. set(CURRENT_SEARCH_DIR "") endif() endwhile() @@ -240,13 +278,42 @@ endfunction() # FIND_WOLFSSL_DIRECTORY(WOLFSSL_ROOT) # +message(STATUS "CONFIG_TARGET_PLATFORM = ${CONFIG_TARGET_PLATFORM}") + +if (0) + get_cmake_property(_variableNames VARIABLES) + list (SORT _variableNames) + message(STATUS "") + message(STATUS "ALL VARIABLES BEGIN") + message(STATUS "") + foreach (_variableName ${_variableNames}) + message(STATUS "${_variableName}=${${_variableName}}") + endforeach() + message(STATUS "") + message(STATUS "ALL VARIABLES END") + message(STATUS "") +endif() + +if ( ("${CONFIG_TARGET_PLATFORM}" STREQUAL "esp8266") OR ("${IDF_TARGET}" STREQUAL "esp8266") ) + # There's no esp_timer, no driver components for the ESP8266 + message(STATUS "Early expansion EXCLUDES esp_timer: ${THIS_INCLUDE_TIMER}") + message(STATUS "Early expansion EXCLUDES driver: ${THIS_INCLUDE_DRIVER}") + set(THIS_INCLUDE_TIMER "") + set(THIS_INCLUDE_DRIVER "") +else() + message(STATUS "Early expansion includes esp_timer: ${THIS_INCLUDE_TIMER}") + message(STATUS "Early expansion includes driver: ${THIS_INCLUDE_DRIVER}") + set(THIS_INCLUDE_TIMER "esp_timer") + set(THIS_INCLUDE_DRIVER "driver") +endif() + if(CMAKE_BUILD_EARLY_EXPANSION) message(STATUS "wolfssl component CMAKE_BUILD_EARLY_EXPANSION:") idf_component_register( REQUIRES "${COMPONENT_REQUIRES}" PRIV_REQUIRES # esp_hw_support - "${THIS_INCLUDE_TIMER}" - "${THIS_INCLUDE_DRIVER}" # this will typically only be needed for wolfSSL benchmark + ${THIS_INCLUDE_TIMER} + ${THIS_INCLUDE_DRIVER} # this will typically only be needed for wolfSSL benchmark ) else() @@ -255,18 +322,8 @@ else() message(STATUS "wolfssl component config:") message(STATUS "************************************************************************************************") - if ( "${CONFIG_TARGET_PLATFORM}" STREQUAL "esp8266") - # There's no esp_timer, no driver components for the ESP8266 - set(THIS_INCLUDE_TIMER "") - set(THIS_INCLUDE_DRIVER "") - else() - set(THIS_INCLUDE_TIMER "esp_timer") - set(THIS_INCLUDE_DRIVER "driver") - endif() - # search for wolfSSL - # TODO allow for cmake prior def - + FIND_WOLFSSL_DIRECTORY(WOLFSSL_ROOT) if(WOLFSSL_ROOT) IS_WOLFSSL_SOURCE("${WOLFSSL_ROOT}" FOUND_WOLFSSL) if(FOUND_WOLFSSL) @@ -288,8 +345,8 @@ else() else() message(STATUS "Failed: wolfssl directory not found.") # Abort. We need wolfssl _somewhere_. - message(FATAL_ERROR "Could not find wolfssl in ${WOLFSSL_ROOT}.\n" - "Try setting WOLFSSL_ROOT environment variable or git clone.") + message(FATAL_ERROR "Could not find wolfssl in any parent directory named wolfssl-${THIS_USER}, wolfssl-master, or wolfssl.\n" + "Try setting WOLFSSL_ROOT environment variable, cmake variable in project, copy source, or use managed components.") # Abort CMake after fatal error. endif() @@ -327,6 +384,7 @@ else() # wolfSSL user_settings.h is in the local project. set(WOLFSSL_PROJECT_DIR "${CMAKE_HOME_DIRECTORY}/components/wolfssl") + # add_definitions(-DWOLFSSL_USER_SETTINGS_DIR="${WOLFSSL_PROJECT_DIR}/include/user_settings.h") string(REPLACE "/" "//" STR_WOLFSSL_PROJECT_DIR "${WOLFSSL_PROJECT_DIR}") add_definitions(-DWOLFSSL_USER_SETTINGS_DIR="${STR_WOLFSSL_PROJECT_DIR}//include//user_settings.h") @@ -485,10 +543,10 @@ else() message(STATUS "Could not find RTOS path") endif() endif() - + message(STATUS "THIS_IDF_PATH = $THIS_IDF_PATH") # wolfSSL-specific include directories set(COMPONENT_ADD_INCLUDEDIRS - "./include" # this is the location of local project wolfssl user_settings.h + "./include" # this is the location of wolfssl user_settings.h "\"${WOLFSSL_ROOT}/\"" "\"${WOLFSSL_ROOT}/wolfssl/\"" "\"${WOLFSSL_ROOT}/wolfssl/wolfcrypt/\"" @@ -515,9 +573,14 @@ else() "\"${WOLFSSL_ROOT}/src/ssl_bn.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_certman.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_crypto.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_load.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/ssl_misc.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_p7p12.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/ssl_sess.c\"" # included by ssl.c "\"${WOLFSSL_ROOT}/src/x509.c\"" "\"${WOLFSSL_ROOT}/src/x509_str.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/ext_kyber.c\"" # external Kyber disabled by default + "\"${WOLFSSL_ROOT}/wolfssl/wolfcrypt/ext_kyber.h\"" # external Kyber disabled by default "\"${WOLFSSL_ROOT}/wolfcrypt/src/evp.c\"" "\"${WOLFSSL_ROOT}/wolfcrypt/src/misc.c\"" "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_arm32.c\"" diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssl/include/user_settings.h b/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssl/include/user_settings.h index 41f588a01..6d0e197ef 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssl/include/user_settings.h +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssl/include/user_settings.h @@ -1,22 +1,21 @@ /* user_settings.h * - * Copyright (C) 2006-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * - * This file is part of wolfSSL. + * This file is part of wolfSSH. * - * wolfSSL is free software; you can redistribute it and/or modify + * wolfSSH is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * - * wolfSSL is distributed in the hope that it will be useful, + * wolfSSH is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. */ #include <sdkconfig.h> /* essential to chip set detection */ diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/CMakeLists.txt b/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/CMakeLists.txt index 9ae9d6bf7..0021fd7e3 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/CMakeLists.txt +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/CMakeLists.txt @@ -1,22 +1,21 @@ # [wolfSSL Project]/main/CMakeLists.txt # -# Copyright (C) 2006-2023 WOLFSSL Inc. +# Copyright (C) 2014-2024 wolfSSL Inc. # -# This file is part of WOLFSSH. +# This file is part of wolfSSH. # -# WOLFSSH is free software; you can redistribute it and/or modify +# wolfSSH is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # -# WOLFSSH is distributed in the hope that it will be useful, +# wolfSSH is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA +# along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. # # cmake for WOLFSSH Espressif projects # diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/include/main.h b/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/include/main.h index 7e07ec1df..73d227693 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/include/main.h +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/include/main.h @@ -1,22 +1,21 @@ /* template main.h * - * Copyright (C) 2006-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * - * This file is part of wolfSSL. + * This file is part of wolfSSH. * - * wolfSSL is free software; you can redistribute it and/or modify + * wolfSSH is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * - * wolfSSL is distributed in the hope that it will be useful, + * wolfSSH is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. */ #ifndef _MAIN_H_ #define _MAIN_H_ diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/main.c b/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/main.c index 6204cc398..af6f87cce 100644 --- a/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/main.c +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/main.c @@ -1,22 +1,21 @@ /* main.c * - * Copyright (C) 2006-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * - * This file is part of wolfSSL. + * This file is part of wolfSSH. * - * wolfSSL is free software; you can redistribute it and/or modify + * wolfSSH is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * - * wolfSSL is distributed in the hope that it will be useful, + * wolfSSH is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + * along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. */ #include "main.h" diff --git a/ide/IAR-EWARM/Projects/lib/myFilesystem.h b/ide/IAR-EWARM/Projects/lib/myFilesystem.h index 0fcdacc87..0a38ea469 100644 --- a/ide/IAR-EWARM/Projects/lib/myFilesystem.h +++ b/ide/IAR-EWARM/Projects/lib/myFilesystem.h @@ -1,6 +1,6 @@ /* dummy_filesystem.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/ide/Renesas/cs+/common/strings.h b/ide/Renesas/cs+/common/strings.h index 0c46b4f10..efe786a23 100644 --- a/ide/Renesas/cs+/common/strings.h +++ b/ide/Renesas/cs+/common/strings.h @@ -1,6 +1,6 @@ /* strings.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/ide/Renesas/cs+/common/unistd.h b/ide/Renesas/cs+/common/unistd.h index 71943bce1..d108f898a 100644 --- a/ide/Renesas/cs+/common/unistd.h +++ b/ide/Renesas/cs+/common/unistd.h @@ -1,6 +1,6 @@ /* unistd.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/ide/Renesas/cs+/common/user_settings.h b/ide/Renesas/cs+/common/user_settings.h index 8553ce715..5e43a8264 100644 --- a/ide/Renesas/cs+/common/user_settings.h +++ b/ide/Renesas/cs+/common/user_settings.h @@ -1,6 +1,6 @@ /* user_settings.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/ide/Renesas/cs+/common/wolfssh_csplus_usersettings.h b/ide/Renesas/cs+/common/wolfssh_csplus_usersettings.h index 2a54ccaea..c37ec20f8 100644 --- a/ide/Renesas/cs+/common/wolfssh_csplus_usersettings.h +++ b/ide/Renesas/cs+/common/wolfssh_csplus_usersettings.h @@ -1,6 +1,6 @@ /* wolfssh_csplus_usersettings..h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/ide/Renesas/cs+/demo_server/wolfssh_demo.c b/ide/Renesas/cs+/demo_server/wolfssh_demo.c index b9f6b0aea..866be2f76 100644 --- a/ide/Renesas/cs+/demo_server/wolfssh_demo.c +++ b/ide/Renesas/cs+/demo_server/wolfssh_demo.c @@ -1,6 +1,6 @@ /* wolfssh_demo.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/ide/Renesas/cs+/demo_server/wolfssh_demo.h b/ide/Renesas/cs+/demo_server/wolfssh_demo.h index 2eeb34e02..e9becd139 100644 --- a/ide/Renesas/cs+/demo_server/wolfssh_demo.h +++ b/ide/Renesas/cs+/demo_server/wolfssh_demo.h @@ -1,6 +1,6 @@ /* wolfssh_demo.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/ide/Renesas/cs+/demo_server/wolfssh_dummy.c b/ide/Renesas/cs+/demo_server/wolfssh_dummy.c index 4ccac07a8..3edaff78e 100644 --- a/ide/Renesas/cs+/demo_server/wolfssh_dummy.c +++ b/ide/Renesas/cs+/demo_server/wolfssh_dummy.c @@ -1,6 +1,6 @@ /* wolfssh_dummy.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/ide/STM32CUBE/default_conf.ftl b/ide/STM32CUBE/default_conf.ftl index 0de5bf134..78e70f564 100644 --- a/ide/STM32CUBE/default_conf.ftl +++ b/ide/STM32CUBE/default_conf.ftl @@ -106,6 +106,7 @@ extern ${variable.value} ${variable.name}; #define WOLFSSH_LOG_PRINTF #define WOLFSSL_LOG_PRINTF #define fprintf(err, ... ) printf(__VA_ARGS__) +#define WFFLUSH fflush #define BENCH_EMBEDDED #define NO_WRITEV @@ -138,8 +139,6 @@ extern ${variable.value} ${variable.name}; #define HAVE_AESGCM #define WOLFSSL_SHA512 #define HAVE_ECC -#define HAVE_CURVE25519 -#define CURVE25519_SMALL #define HAVE_ED25519 #define WOLFSSH_IGNORE_FILE_WARN diff --git a/ide/STM32CUBE/main.c b/ide/STM32CUBE/main.c index 76155abd0..3827fd826 100644 --- a/ide/STM32CUBE/main.c +++ b/ide/STM32CUBE/main.c @@ -1,6 +1,6 @@ /* main.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/ide/STM32CUBE/myFilesystem.h b/ide/STM32CUBE/myFilesystem.h index 31eefd454..cfacbc9dc 100644 --- a/ide/STM32CUBE/myFilesystem.h +++ b/ide/STM32CUBE/myFilesystem.h @@ -1,6 +1,6 @@ /* myFilesystem.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/ide/STM32CUBE/userio_template.h b/ide/STM32CUBE/userio_template.h index 4b8144288..049335e00 100644 --- a/ide/STM32CUBE/userio_template.h +++ b/ide/STM32CUBE/userio_template.h @@ -1,6 +1,6 @@ /* userio_template.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/ide/STM32CUBE/wolfssh_test.c b/ide/STM32CUBE/wolfssh_test.c index ba9c5a44c..1090dff5e 100644 --- a/ide/STM32CUBE/wolfssh_test.c +++ b/ide/STM32CUBE/wolfssh_test.c @@ -1,6 +1,6 @@ /* wolfssh_test.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -47,8 +47,10 @@ void wolfSSHTest(const void* argument) printf("Running wolfSSH Tests...\n"); - if (wolfSSH_TestsuiteTest(0, NULL)) - ret = -1; + /* TODO: Uncomment once proper threading abstractions have been implemented + * in wolfSSL */ + /* if (wolfSSH_TestsuiteTest(0, NULL)) + ret = -1; */ if (wolfSSH_UnitTest(0, NULL)) ret = -1; if (wolfSSH_ApiTest(0, NULL)) diff --git a/ide/STM32CUBE/wolfssh_test.h b/ide/STM32CUBE/wolfssh_test.h index 063027b2c..fc88dc6a5 100644 --- a/ide/STM32CUBE/wolfssh_test.h +++ b/ide/STM32CUBE/wolfssh_test.h @@ -1,6 +1,6 @@ /* wolfssh_test.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/keys/id_barney b/keys/id_barney new file mode 100644 index 000000000..07c504bb3 --- /dev/null +++ b/keys/id_barney @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACBs8gsipHiL/VP0nvJOeDeR0EYF9AXtXnjGlGmqHru5NQAAAJghFgrDIRYK +wwAAAAtzc2gtZWQyNTUxOQAAACBs8gsipHiL/VP0nvJOeDeR0EYF9AXtXnjGlGmqHru5NQ +AAAEDuTSTiIfkHZlxI+gjjETACk3F3PPU7jgOHG6NH/THSXWzyCyKkeIv9U/Se8k54N5HQ +RgX0Be1eeMaUaaoeu7k1AAAAEGJhcm5leUBsb2NhbGhvc3QBAgMEBQ== +-----END OPENSSH PRIVATE KEY----- diff --git a/keys/id_barney.pub b/keys/id_barney.pub new file mode 100644 index 000000000..64a15f34b --- /dev/null +++ b/keys/id_barney.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGzyCyKkeIv9U/Se8k54N5HQRgX0Be1eeMaUaaoeu7k1 barney@localhost diff --git a/keys/putty_rsa.ppk b/keys/putty_rsa.ppk new file mode 100644 index 000000000..c12c5fbea --- /dev/null +++ b/keys/putty_rsa.ppk @@ -0,0 +1,26 @@ +PuTTY-User-Key-File-3: ssh-rsa +Encryption: none +Comment: rsa-key-20240604 +Public-Lines: 6 +AAAAB3NzaC1yc2EAAAADAQABAAABAQDEbENolVsJ9W/mfKF1G+j/xKiL0g+BhVLH +JP3fOYpXRur5x5kdselmlnklpnzqxQcp+5uv89XfqhILDMNJRhffIKvOYa2AHdEg +ML/FjtLwgiruM6sCA+NZ1MbBHRUqzsPdMlEqZp0kMBpldtUgcwNoyT3TD0zxPNk7 +ZaVl5KTZi3c5KBr11SpT5HsxPLRGN0XwjEZpxu6nfPAdg4R1/rW1vJDHJfU/ZvJb +GcJvDls5OWvFMbaGzhq/JgWmrSRYjYlKpNBnGpvCm61ZbABBoUVyWUGbNgWjeVjw +apW/Ycw9Mb9+u3jVtFPquU3loMXDyXGslclhwH/k8pJjt+g7jAN1 +Private-Lines: 14 +AAABAGyMC8Bq8VGSkhFEhJFMKDnX+vCx2CHShMlKtwU6LipHJal9VS9k1z/7Hd3h +oJy431mjEwlsbZ/Zw3jZx73hf2WuD2PQ9OmdEKmCZygM4qNIu+LBKNrHPUeyX1fu +83ihpPnDSblt1Z9e+edigSsahCLPO1w8019pKf86D+o8LaGOCgWrgAhxzlESQSHj +d5c7C08qOTjOTfSCrUGX6X8vbuVN62sejd7stw/hznNSfKXxGNS36U4PAFA3ISkD +TD3ZYKNDHogfxWbnQdQBykw90OQCn/k05U1ibih4dE7o2C+1Nd+gJBfoUFoz0DcT +LILn9MC7TazgFvfsZ/8eV9hPZm0AAACBAOiNzN6TJvvE2rE0/NFTjXw6Rr0DpCDE +px3IOHaX6sDR+w8h7/Hu1VdnAhNPZndslzW8B0x+yfIE3jxUds3rl5sF4Q54/POj +PnPSNrdP6xFFznxen6TyLxg4DNnlirBBQRPFg6dqtv3SKenVyGLWuzOgCV+oajBh +vnXHJIIMSFRHAAAAgQDYOeymt6Ubi5shUNHpTfvbRMh08Uhlb6R2wkDDBLcDJEHd +h0+4nlNC3I/5OMyGrtPa0zwdEdUNTOKXT3sHC5g/mCOvh3Nk2pcMBr2kK4nR2jKK +oDY6czAlHk3Egd1WAz00Vm+DRKlKOzkPbnYk66cbtmIOPfyBoMv3Ce/wtWM0YwAA +AIEA2hkI2Px9OgtDRjl9Q/ACzTrEytucBtr8sbfDEB9xJo6KfQSvSM+JTs6ZwyDq +xGYnAgfExL6jAziHuDoPOY2ypk9narnVvbT7YnR/unI7w2hKOA4wzwDg2ttjTd2H +p/TeCUiHrrVPe6Q9KkfXMFngbYnt11nN5p6JFKOuzMLg224= +Private-MAC: 8eead3c876b6feb64a80d9d7573ffc1ab89bb272091a38fe85c962d47400c7cb diff --git a/keys/putty_rsa.pub b/keys/putty_rsa.pub new file mode 100644 index 000000000..447b7cc45 --- /dev/null +++ b/keys/putty_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDEbENolVsJ9W/mfKF1G+j/xKiL0g+BhVLHJP3fOYpXRur5x5kdselmlnklpnzqxQcp+5uv89XfqhILDMNJRhffIKvOYa2AHdEgML/FjtLwgiruM6sCA+NZ1MbBHRUqzsPdMlEqZp0kMBpldtUgcwNoyT3TD0zxPNk7ZaVl5KTZi3c5KBr11SpT5HsxPLRGN0XwjEZpxu6nfPAdg4R1/rW1vJDHJfU/ZvJbGcJvDls5OWvFMbaGzhq/JgWmrSRYjYlKpNBnGpvCm61ZbABBoUVyWUGbNgWjeVjwapW/Ycw9Mb9+u3jVtFPquU3loMXDyXGslclhwH/k8pJjt+g7jAN1 rsa-key-20240604 diff --git a/scripts/scp.test b/scripts/scp.test index 093db6845..84e228fab 100755 --- a/scripts/scp.test +++ b/scripts/scp.test @@ -133,6 +133,22 @@ else exit 1 fi +echo "Test of sending a file that does not exist" +touch $PWD/scripts/empty +./examples/echoserver/echoserver -1 -R $ready_file & +server_pid=$! +create_port +./examples/scpclient/wolfscp -u jill -P upthehill -p $port -L $PWD/does-not-exist:$PWD/empty +RESULT=$? +remove_ready_file +rm -f $PWD/scripts/empty + +if test $RESULT -eq 0; then + echo -e "\n\nshould fail out sending a file that does not exist" + do_cleanup + exit 1 +fi + echo -e "\nALL Tests Passed" exit 0 diff --git a/src/agent.c b/src/agent.c index 78fc73c06..bfda4930f 100644 --- a/src/agent.c +++ b/src/agent.c @@ -1,6 +1,6 @@ /* agent.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/src/certman.c b/src/certman.c index 584f95525..40b8eba7a 100644 --- a/src/certman.c +++ b/src/certman.c @@ -1,6 +1,6 @@ /* certman.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/src/internal.c b/src/internal.c index d4db4265c..b2d46ac40 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1,6 +1,6 @@ /* internal.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -33,17 +33,19 @@ #include <wolfssh/ssh.h> #include <wolfssh/internal.h> #include <wolfssh/log.h> +#include <wolfssl/version.h> #include <wolfssl/wolfcrypt/asn.h> #ifndef WOLFSSH_NO_DH #include <wolfssl/wolfcrypt/dh.h> #endif +#include <wolfssl/wolfcrypt/curve25519.h> +#include <wolfssl/wolfcrypt/ed25519.h> #ifdef WOLFSSH_CERTS #include <wolfssl/wolfcrypt/error-crypt.h> #endif #include <wolfssl/wolfcrypt/rsa.h> #include <wolfssl/wolfcrypt/ecc.h> #include <wolfssl/wolfcrypt/hmac.h> -#include <wolfssl/wolfcrypt/integer.h> #include <wolfssl/wolfcrypt/signature.h> #ifdef WOLFSSH_HAVE_LIBOQS @@ -69,6 +71,11 @@ use of the function if the flag isn't set. If using wolfCrypt v4.5.0 or later, and not building with configure, set this flag. default: off + WOLFSSH_NO_SHA1_SOFT_DISABLE + SHA-1 is normally soft-disabled. The default configuration will not + advertise the availability of SHA-1 based algorithms during KEX. SHA-1 + algorithms still work. Setting this flag will advertise SHA-1 based + algorithms during KEX by default. WOLFSSH_NO_SHA1 Set when SHA1 is disabled. Set to disable use of SHA1 in HMAC and digital signature support. @@ -97,9 +104,6 @@ WOLFSSH_NO_ECDH_SHA2_NISTP521 Set when ECC or SHA2-512 are disabled. Set to disable use of ECDHE key exchange with prime NISTP521. - WOLFSSH_NO_ECDH_SHA2_ED25519 - Set when ED25519 or SHA2-256 are disabled. Set to disable use of ECDHE key - exchange with prime ED25519. (It just decodes the ID for output.) WOLFSSH_NO_RSA Set when RSA is disabled. Set to disable use of RSA server and user authentication. @@ -143,6 +147,9 @@ algorithms off. WOLFSSH_KEY_QUANTITY_REQ Number of keys required to be in an OpenSSH-style key wrapper. + WOLFSSH_NO_CURVE25519_SHA256 + Set when Curve25519 or SHA2-256 are disabled in wolfSSL. Set to disable use + of Curve25519 key exchange. */ static const char sshProtoIdStr[] = "SSH-2.0-wolfSSHv" @@ -436,6 +443,15 @@ const char* GetErrorString(int err) case WS_SFTP_NOT_FILE_E: return "not a regular file"; + case WS_MSGID_NOT_ALLOWED_E: + return "message not allowed before user authentication"; + + case WS_ED25519_E: + return "Ed25519 buffer error"; + + case WS_AUTH_PENDING: + return "userauth is still pending (callback would block)"; + default: return "Unknown error code"; } @@ -552,17 +568,224 @@ static void HandshakeInfoFree(HandshakeInfo* hs, void* heap) } -#ifdef DEBUG_WOLFSSH +#ifndef NO_WOLFSSH_SERVER +INLINE static int IsMessageAllowedServer(WOLFSSH *ssh, byte msg) +{ + /* Has client userauth started? */ + if (ssh->acceptState < ACCEPT_KEYED) { + if (msg > MSGID_KEXDH_LIMIT) { + return 0; + } + } + /* Is server userauth complete? */ + if (ssh->acceptState < ACCEPT_SERVER_USERAUTH_SENT) { + /* Explicitly check for messages not allowed before user + * authentication has comleted. */ + if (msg >= MSGID_USERAUTH_LIMIT) { + WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by server " + "before user authentication is complete", msg); + return 0; + } + /* Explicitly check for the user authentication messages that + * only the server sends, it shouldn't receive them. */ + if (msg > MSGID_USERAUTH_RESTRICT) { + WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by server " + "during user authentication", msg); + return 0; + } + } + else { + if (msg >= MSGID_USERAUTH_RESTRICT && msg < MSGID_USERAUTH_LIMIT) { + WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by server " + "after user authentication", msg); + return 0; + } + } + + return 1; +} +#endif /* NO_WOLFSSH_SERVER */ + + +#ifndef NO_WOLFSSH_CLIENT +INLINE static int IsMessageAllowedClient(WOLFSSH *ssh, byte msg) +{ + /* Has client userauth started? */ + if (ssh->connectState < CONNECT_CLIENT_KEXDH_INIT_SENT) { + if (msg >= MSGID_KEXDH_LIMIT) { + return 0; + } + } + /* Is client userauth complete? */ + if (ssh->connectState < CONNECT_SERVER_USERAUTH_ACCEPT_DONE) { + /* Explicitly check for messages not allowed before user + * authentication has comleted. */ + if (msg >= MSGID_USERAUTH_LIMIT) { + WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by client " + "before user authentication is complete", msg); + return 0; + } + /* Explicitly check for the user authentication message that + * only the client sends, it shouldn't receive it. */ + if (msg == MSGID_USERAUTH_RESTRICT) { + WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by client " + "during user authentication", msg); + return 0; + } + } + else { + if (msg >= MSGID_USERAUTH_RESTRICT && msg < MSGID_USERAUTH_LIMIT) { + WLOG(WS_LOG_DEBUG, "Message ID %u not allowed by client " + "after user authentication", msg); + return 0; + } + } + return 1; +} +#endif /* NO_WOLFSSH_CLIENT */ + + +INLINE static int IsMessageAllowed(WOLFSSH *ssh, byte msg) +{ +#ifndef NO_WOLFSSH_SERVER + if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER) { + return IsMessageAllowedServer(ssh, msg); + } +#endif /* NO_WOLFSSH_SERVER */ +#ifndef NO_WOLFSSH_CLIENT + if (ssh->ctx->side == WOLFSSH_ENDPOINT_CLIENT) { + return IsMessageAllowedClient(ssh, msg); + } +#endif /* NO_WOLFSSH_CLIENT */ + return 0; +} + + +static const char cannedKexAlgoNames[] = +#if !defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256) + "ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org," +#endif +#ifndef WOLFSSH_NO_CURVE25519_SHA256 + "curve25519-sha256," +#endif +#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP521) + "ecdh-sha2-nistp521," +#endif +#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP384) + "ecdh-sha2-nistp384," +#endif +#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP256) + "ecdh-sha2-nistp256," +#endif +#if !defined(WOLFSSH_NO_DH_GEX_SHA256) + "diffie-hellman-group-exchange-sha256," +#endif +#ifdef WOLFSSH_NO_SHA1_SOFT_DISABLE + #if !defined(WOLFSSH_NO_DH_GROUP14_SHA1) + "diffie-hellman-group14-sha1," + #endif + #if !defined(WOLFSSH_NO_DH_GROUP1_SHA1) + "diffie-hellman-group1-sha1," + #endif +#endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ + ""; + +#ifndef WOLFSSH_NO_SSH_RSA_SHA1 + #ifdef WOLFSSH_CERTS + static const char cannedKeyAlgoX509RsaNames[] = "x509v3-ssh-rsa"; + #endif +#endif +#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 + static const char cannedKeyAlgoEcc256Names[] = "ecdsa-sha2-nistp256"; + #ifdef WOLFSSH_CERTS + static const char cannedKeyAlgoX509Ecc256Names[] = + "x509v3-ecdsa-sha2-nistp256"; + #endif +#endif +#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 + static const char cannedKeyAlgoEcc384Names[] = "ecdsa-sha2-nistp384"; + #ifdef WOLFSSH_CERTS + static const char cannedKeyAlgoX509Ecc384Names[] = + "x509v3-ecdsa-sha2-nistp384"; + #endif +#endif +#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 + static const char cannedKeyAlgoEcc521Names[] = "ecdsa-sha2-nistp521"; + #ifdef WOLFSSH_CERTS + static const char cannedKeyAlgoX509Ecc521Names[] = + "x509v3-ecdsa-sha2-nistp521"; + #endif +#endif +#ifndef WOLFSSH_NO_SSH_RSA_SHA1 + /* Used for both the signature algorithm and the RSA key format. */ + static const char cannedKeyAlgoSshRsaNames[] = "ssh-rsa"; +#endif +#ifndef WOLFSSH_NO_RSA_SHA2_256 + static const char cannedKeyAlgoRsaSha2_256Names[] = "rsa-sha2-256"; +#endif +#ifndef WOLFSSH_NO_RSA_SHA2_512 + static const char cannedKeyAlgoRsaSha2_512Names[] = "rsa-sha2-512"; +#endif +#ifndef WOLFSSH_NO_ED25519 + static const char cannedKeyAlgoEd25519Name[] = "ssh-ed25519"; +#endif + +static const char cannedKeyAlgoNames[] = +#ifndef WOLFSSH_NO_ED25519 + "ssh-ed25519," +#endif /* WOLFSSH_NO_ED25519 */ +#ifndef WOLFSSH_NO_RSA_SHA2_256 + "rsa-sha2-256," +#endif/* WOLFSSH_NO_RSA_SHA2_256 */ +#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 + "ecdsa-sha2-nistp256," +#endif /* WOLFSSH_NO_ECDSA_SHA2_NISTP256 */ +#ifdef WOLFSSH_CERTS + #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 + "x509v3-ecdsa-sha2-nistp256," + #endif /* WOLFSSH_NO_ECDSA_SHA2_NISTP256 */ + #ifdef WOLFSSH_NO_SHA1_SOFT_DISABLE + "x509v3-ssh-rsa," + #endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ +#endif /* WOLFSSH_CERTS */ +#ifdef WOLFSSH_NO_SHA1_SOFT_DISABLE + "ssh-rsa," +#endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ + ""; + +static const char cannedEncAlgoNames[] = +#if !defined(WOLFSSH_NO_AES_GCM) + "aes256-gcm@openssh.com," + "aes192-gcm@openssh.com," + "aes128-gcm@openssh.com," +#endif +#if !defined(WOLFSSH_NO_AES_CTR) + "aes256-ctr," + "aes192-ctr," + "aes128-ctr," +#endif +#if !defined(WOLFSSH_NO_AES_CBC) + "aes256-cbc," + "aes192-cbc," + "aes128-cbc," +#endif + ""; -static const char cannedBanner[] = - "CANNED BANNER\r\n" - "This server is an example test server. " - "It should have its own banner, but\r\n" - "it is currently using a canned one in " - "the library. Be happy or not.\r\n"; -static const word32 cannedBannerSz = (word32)sizeof(cannedBanner) - 1; +static const char cannedMacAlgoNames[] = +#if !defined(WOLFSSH_NO_HMAC_SHA2_256) + "hmac-sha2-256," +#endif +#if defined(WOLFSSH_NO_SHA1_SOFT_DISABLE) + #if !defined(WOLFSSH_NO_HMAC_SHA1_96) + "hmac-sha1-96," + #endif + #if !defined(WOLFSSH_NO_HMAC_SHA1) + "hmac-sha1," + #endif +#endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ + ""; -#endif /* DEBUG_WOLFSSH */ +static const char cannedNoneNames[] = "none"; WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, byte side, void* heap) @@ -590,10 +813,8 @@ WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, byte side, void* heap) ctx->scpRecvCb = wsScpRecvCallback; ctx->scpSendCb = wsScpSendCallback; #endif /* WOLFSSH_SCP */ -#ifdef DEBUG_WOLFSSH - ctx->banner = cannedBanner; - ctx->bannerSz = cannedBannerSz; -#endif /* DEBUG_WOLFSSH */ + ctx->banner = NULL; + ctx->bannerSz = 0; #ifdef WOLFSSH_CERTS ctx->certMan = wolfSSH_CERTMAN_new(ctx->heap); if (ctx->certMan == NULL) @@ -602,6 +823,13 @@ WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, byte side, void* heap) ctx->windowSz = DEFAULT_WINDOW_SZ; ctx->maxPacketSz = DEFAULT_MAX_PACKET_SZ; ctx->sshProtoIdStr = sshProtoIdStr; + ctx->algoListKex = cannedKexAlgoNames; + if (side == WOLFSSH_ENDPOINT_CLIENT) { + ctx->algoListKey = cannedKeyAlgoNames; + } + ctx->algoListCipher = cannedEncAlgoNames; + ctx->algoListMac = cannedMacAlgoNames; + ctx->algoListKeyAccepted = cannedKeyAlgoNames; count = (word32)(sizeof(ctx->privateKey) / sizeof(ctx->privateKey[0])); @@ -660,17 +888,17 @@ void CtxResourceFree(WOLFSSH_CTX* ctx) static int WS_TermResize(WOLFSSH* ssh, word32 col, word32 row, word32 colP, word32 rowP, void* usrCtx) { - HPCON* term = (HPCON*)usrCtx; + HANDLE* term = (HANDLE*)usrCtx; int ret = WS_SUCCESS; if (term != NULL) { - HRESULT ret; - COORD sz; + char cmd[20]; + int cmdSz = 20; + DWORD wrtn = 0; - sz.X = col; - sz.Y = row; - ret = ResizePseudoConsole(*term, sz); - if (ret != S_OK) { + /* VT control sequence for resizing window */ + cmdSz = snprintf(cmd, cmdSz, "\x1b[8;%d;%dt", row, col); + if (WriteFile(*term, cmd, cmdSz, &wrtn, 0) != TRUE) { WLOG(WS_LOG_ERROR, "Issue with pseudo console resize"); ret = WS_FATAL_ERROR; } @@ -726,6 +954,30 @@ WOLFSSH* SshInit(WOLFSSH* ssh, WOLFSSH_CTX* ctx) return ssh; heap = ctx->heap; +#ifdef WOLFSSH_STATIC_MEMORY + if (heap != NULL) { + WOLFSSL_HEAP_HINT* hint = (WOLFSSL_HEAP_HINT*)heap; + + if (hint->memory->flag & WOLFMEM_TRACK_STATS) { + WOLFSSL_MEM_CONN_STATS* stats = NULL; + + stats = (WOLFSSL_MEM_CONN_STATS*)WMALLOC( + sizeof(WOLFSSL_MEM_CONN_STATS), + heap, DYNTYPE_SSH); + if (stats == NULL) { + WLOG(WS_LOG_DEBUG, "SshInit: Cannot track memory stats.\n"); + return NULL; + } + + XMEMSET(stats, 0, sizeof(WOLFSSL_MEM_CONN_STATS)); + if (hint->stats != NULL) { + WFREE(hint->stats, heap, DYNTYPE_SSH); + } + hint->stats = stats; + } + } +#endif /* WOLFSSH_STATIC_MEMORY */ + handshake = HandshakeInfoNew(heap); rng = (WC_RNG*)WMALLOC(sizeof(WC_RNG), heap, DYNTYPE_RNG); if (handshake == NULL || rng == NULL) { @@ -777,10 +1029,17 @@ WOLFSSH* SshInit(WOLFSSH* ssh, WOLFSSH_CTX* ctx) ssh->kSz = (word32)sizeof(ssh->k); ssh->handshake = handshake; ssh->connectChannelId = WOLFSSH_SESSION_SHELL; + ssh->algoListKex = ctx->algoListKex; + ssh->algoListKey = ctx->algoListKey; + ssh->algoListCipher = ctx->algoListCipher; + ssh->algoListMac = ctx->algoListMac; + ssh->algoListKeyAccepted = ctx->algoListKeyAccepted; #ifdef WOLFSSH_SCP ssh->scpRequestState = SCP_PARSE_COMMAND; ssh->scpConfirmMsg = NULL; ssh->scpConfirmMsgSz = 0; + ssh->scpRecvMsg = NULL; + ssh->scpRecvMsgSz = 0; ssh->scpRecvCtx = NULL; #if !defined(WOLFSSH_SCP_USER_CALLBACKS) && !defined(NO_FILESYSTEM) ssh->scpSendCtx = &(ssh->scpSendCbCtx); @@ -813,6 +1072,8 @@ WOLFSSH* SshInit(WOLFSSH* ssh, WOLFSSH_CTX* ctx) #endif #endif + ssh->keyingCompletionCtx = (void*)ssh; + if (BufferInit(&ssh->inputBuffer, 0, ctx->heap) != WS_SUCCESS || BufferInit(&ssh->outputBuffer, 0, ctx->heap) != WS_SUCCESS || BufferInit(&ssh->extDataBuffer, 0, ctx->heap) != WS_SUCCESS) { @@ -898,6 +1159,22 @@ void SshResourceFree(WOLFSSH* ssh, void* heap) ssh->sftpDefaultPath = NULL; } #endif +#ifdef WOLFSSH_TERM + if (ssh->modes) { + WFREE(ssh->modes, ssh->ctx->heap, DYNTYPE_STRING); + ssh->modesSz = 0; + } +#endif +#ifdef WOLFSSH_STATIC_MEMORY + if (heap) { + WOLFSSL_HEAP_HINT* hint = (WOLFSSL_HEAP_HINT*)heap; + if (hint->memory->flag & WOLFMEM_TRACK_STATS + && hint->stats != NULL) { + WFREE(hint->stats, heap, DYNTYPE_SSH); + hint->stats = NULL; + } + } +#endif } @@ -905,6 +1182,7 @@ typedef struct WS_KeySignature { byte keySigId; word32 sigSz; const char *name; + void *heap; word32 nameSz; union { #ifndef WOLFSSH_NO_RSA @@ -916,6 +1194,11 @@ typedef struct WS_KeySignature { struct { ecc_key key; } ecc; +#endif +#ifndef WOLFSSH_NO_ED25519 + struct { + ed25519_key key; + } ed25519; #endif } ks; } WS_KeySignature; @@ -1029,6 +1312,31 @@ int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap) wc_ecc_free(&key->ks.ecc.key); } #endif /* WOLFSSH_NO_ECDSA */ +#if !defined(WOLFSSH_NO_ED25519) + if (key != NULL) { + if (key->keySigId == ID_UNKNOWN) { + idx = 0; + ret = wc_ed25519_init_ex(&key->ks.ed25519.key, heap, INVALID_DEVID); + + if(ret == 0) { + if (isPrivate) { + ret = wc_Ed25519PrivateKeyDecode(in, &idx, + &key->ks.ed25519.key, inSz); + } + else { + ret = wc_Ed25519PublicKeyDecode(in, &idx, + &key->ks.ed25519.key, inSz); + } + } + + /* If decode was successful, this is a Ed25519 key. */ + if(ret == 0) + key->keySigId = ID_ED25519; + + wc_ed25519_free(&key->ks.ed25519.key); + } + } +#endif /* WOLFSSH_NO_ED25519 */ if (key->keySigId == ID_UNKNOWN) { ret = WS_UNIMPLEMENTED_E; @@ -1045,10 +1353,57 @@ int IdentifyAsn1Key(const byte* in, word32 inSz, int isPrivate, void* heap) #ifndef WOLFSSH_NO_RSA + +#if (LIBWOLFSSL_VERSION_HEX > WOLFSSL_V5_7_0) && !defined(HAVE_FIPS) +/* + * The function wc_RsaPrivateKeyDecodeRaw() is available + * from wolfSSL after v5.7.0. + */ + +/* + * Utility for GetOpenSshKey() to read in RSA keys. + */ +static int GetOpenSshKeyRsa(RsaKey* key, + const byte* buf, word32 len, word32* idx) +{ + const byte *n, *e, *d, *u, *p, *q; + word32 nSz, eSz, dSz, uSz, pSz, qSz; + int ret; + + ret = wc_InitRsaKey(key, NULL); + if (ret == WS_SUCCESS) + ret = GetMpint(&nSz, &n, buf, len, idx); + if (ret == WS_SUCCESS) + ret = GetMpint(&eSz, &e, buf, len, idx); + if (ret == WS_SUCCESS) + ret = GetMpint(&dSz, &d, buf, len, idx); + if (ret == WS_SUCCESS) + ret = GetMpint(&uSz, &u, buf, len, idx); + if (ret == WS_SUCCESS) + ret = GetMpint(&pSz, &p, buf, len, idx); + if (ret == WS_SUCCESS) + ret = GetMpint(&qSz, &q, buf, len, idx); + if (ret == WS_SUCCESS) + ret = wc_RsaPrivateKeyDecodeRaw(n, nSz, e, eSz, d, dSz, + u, uSz, p, pSz, q, qSz, NULL, 0, NULL, 0, key); + + if (ret != WS_SUCCESS) + ret = WS_RSA_E; + + return ret; +} + +#else /* LIBWOLFSSL_VERSION_HEX > WOLFSSL_V5_7_0 */ + +#include <wolfssl/wolfcrypt/wolfmath.h> + /* * Utility function to read an Mpint from the stream directly into a mp_int. + * The RsaKey members u, dP, and dQ do not exist when wolfCrypt is built + * with RSA_LOW_MEM. (That mode of wolfCrypt isn't using the extra values + * for the Chinese Remainder Theorem.) */ -static INLINE int GetMpintToMp(mp_int* mp, +static int GetMpintToMp(mp_int* mp, const byte* buf, word32 len, word32* idx) { const byte* val = NULL; @@ -1063,12 +1418,13 @@ static INLINE int GetMpintToMp(mp_int* mp, } +#ifndef RSA_LOW_MEM /* - * 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. + * For the given RSA key, calculate d mod(p-1) and d mod(q-1). + * wolfCrypt's RSA code expects them, but the OpenSSH format key + * doesn't store them. */ -static INLINE int CalcRsaInverses(RsaKey* key) +static int CalcRsaDX(RsaKey* key) { mp_int m; int ret; @@ -1087,6 +1443,7 @@ static INLINE int CalcRsaInverses(RsaKey* key) return ret; } +#endif /* * Utility for GetOpenSshKey() to read in RSA keys. @@ -1103,26 +1460,37 @@ static int GetOpenSshKeyRsa(RsaKey* key, ret = GetMpintToMp(&key->e, buf, len, idx); if (ret == WS_SUCCESS) ret = GetMpintToMp(&key->d, buf, len, idx); +#ifndef RSA_LOW_MEM if (ret == WS_SUCCESS) ret = GetMpintToMp(&key->u, buf, len, idx); +#else + /* Skipping the u value in the key. */ + if (ret == WS_SUCCESS) + ret = GetSkip(buf, len, idx); +#endif if (ret == WS_SUCCESS) ret = GetMpintToMp(&key->p, buf, len, idx); if (ret == WS_SUCCESS) ret = GetMpintToMp(&key->q, buf, len, idx); +#ifndef RSA_LOW_MEM /* Calculate dP and dQ for wolfCrypt. */ if (ret == WS_SUCCESS) - ret = CalcRsaInverses(key); + ret = CalcRsaDX(key); +#endif if (ret != WS_SUCCESS) ret = WS_RSA_E; return ret; } -#endif + +#endif /* LIBWOLFSSL_VERSION_HEX > WOLFSSL_V5_7_0 */ + +#endif /* WOLFSSH_NO_RSA */ -#if !defined(WOLFSSH_NO_ECDSA) && !defined(WOLFSSH_NO_ECC) +#ifndef WOLFSSH_NO_ECDSA /* * Utility for GetOpenSshKey() to read in ECDSA keys. */ @@ -1152,6 +1520,36 @@ static int GetOpenSshKeyEcc(ecc_key* key, } #endif +#ifndef WOLFSSH_NO_ED25519 +/* + * Utility for GetOpenSshKey() to read in Ed25519 keys. + */ +static int GetOpenSshKeyEd25519(ed25519_key* key, + const byte* buf, word32 len, word32* idx) +{ + const byte *priv = NULL, *pub = NULL; + word32 privSz = 0, pubSz = 0; + int ret; + + ret = wc_ed25519_init_ex(key, key->heap, INVALID_DEVID); + + /* OpenSSH key formatting stores the public key, ENC(A), and the + * private key (k) concatenated with the public key, k || ENC(A). */ + if (ret == WS_SUCCESS) + ret = GetStringRef(&pubSz, &pub, buf, len, idx); /* ENC(A) */ + if (ret == WS_SUCCESS) + ret = GetStringRef(&privSz, &priv, buf, len, idx); /* k || ENC(A) */ + + if (ret == WS_SUCCESS) + ret = wc_ed25519_import_private_key(priv, privSz - pubSz, + pub, pubSz, key); + + if (ret != WS_SUCCESS) + ret = WS_ECC_E; + + return ret; +} +#endif /* * Decodes an OpenSSH format key. */ @@ -1234,11 +1632,19 @@ static int GetOpenSshKey(WS_KeySignature *key, str, strSz, &subIdx); break; #endif - #if !defined(WOLFSSH_NO_ECDSA) && !defined(WOLFSSH_NO_ECC) + #ifndef WOLFSSH_NO_ECDSA case ID_ECDSA_SHA2_NISTP256: + case ID_ECDSA_SHA2_NISTP384: + case ID_ECDSA_SHA2_NISTP521: ret = GetOpenSshKeyEcc(&key->ks.ecc.key, str, strSz, &subIdx); break; + #endif + #ifndef WOLFSSH_NO_ED25519 + case ID_ED25519: + ret = GetOpenSshKeyEd25519(&key->ks.ed25519.key, + str, strSz, &subIdx); + break; #endif default: ret = WS_UNIMPLEMENTED_E; @@ -1303,6 +1709,7 @@ int IdentifyOpenSshKey(const byte* in, word32 inSz, void* heap) } else { WMEMSET(key, 0, sizeof(*key)); + key->heap = heap; key->keySigId = ID_NONE; ret = GetOpenSshKey(key, in, inSz, &idx); @@ -1411,13 +1818,15 @@ static void RefreshPublicKeyAlgo(WOLFSSH_CTX* ctx) publicKeyAlgoCount++; } #endif - #ifndef WOLFSSH_NO_SSH_RSA_SHA1 - if (publicKeyAlgoCount < WOLFSSH_MAX_PUB_KEY_ALGO) { - *publicKeyAlgo = ID_SSH_RSA; - publicKeyAlgo++; - publicKeyAlgoCount++; - } - #endif + #ifdef WOLFSSH_NO_SHA1_SOFT_DISABLE + #ifndef WOLFSSH_NO_SSH_RSA_SHA1 + if (publicKeyAlgoCount < WOLFSSH_MAX_PUB_KEY_ALGO) { + *publicKeyAlgo = ID_SSH_RSA; + publicKeyAlgo++; + publicKeyAlgoCount++; + } + #endif /* WOLFSSH_NO_SSH_RSA_SHA1 */ + #endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ } else { if (publicKeyAlgoCount < WOLFSSH_MAX_PUB_KEY_ALGO) { @@ -1955,140 +2364,144 @@ static int GenerateKeys(WOLFSSH* ssh, byte hashId, byte doKeyPad) typedef struct { byte id; + byte type; const char* name; } NameIdPair; static const NameIdPair NameIdMap[] = { - { ID_NONE, "none" }, + { ID_NONE, TYPE_OTHER, "none" }, /* Encryption IDs */ #ifndef WOLFSSH_NO_AES_CBC - { ID_AES128_CBC, "aes128-cbc" }, - { ID_AES192_CBC, "aes192-cbc" }, - { ID_AES256_CBC, "aes256-cbc" }, + { ID_AES128_CBC, TYPE_CIPHER, "aes128-cbc" }, + { ID_AES192_CBC, TYPE_CIPHER, "aes192-cbc" }, + { ID_AES256_CBC, TYPE_CIPHER, "aes256-cbc" }, #endif #ifndef WOLFSSH_NO_AES_CTR - { ID_AES128_CTR, "aes128-ctr" }, - { ID_AES192_CTR, "aes192-ctr" }, - { ID_AES256_CTR, "aes256-ctr" }, + { ID_AES128_CTR, TYPE_CIPHER, "aes128-ctr" }, + { ID_AES192_CTR, TYPE_CIPHER, "aes192-ctr" }, + { ID_AES256_CTR, TYPE_CIPHER, "aes256-ctr" }, #endif #ifndef WOLFSSH_NO_AES_GCM - { ID_AES128_GCM, "aes128-gcm@openssh.com" }, - { ID_AES192_GCM, "aes192-gcm@openssh.com" }, - { ID_AES256_GCM, "aes256-gcm@openssh.com" }, + { ID_AES128_GCM, TYPE_CIPHER, "aes128-gcm@openssh.com" }, + { ID_AES192_GCM, TYPE_CIPHER, "aes192-gcm@openssh.com" }, + { ID_AES256_GCM, TYPE_CIPHER, "aes256-gcm@openssh.com" }, #endif /* Integrity IDs */ #ifndef WOLFSSH_NO_HMAC_SHA1 - { ID_HMAC_SHA1, "hmac-sha1" }, + { ID_HMAC_SHA1, TYPE_MAC, "hmac-sha1" }, #endif #ifndef WOLFSSH_NO_HMAC_SHA1_96 - { ID_HMAC_SHA1_96, "hmac-sha1-96" }, + { ID_HMAC_SHA1_96, TYPE_MAC, "hmac-sha1-96" }, #endif #ifndef WOLFSSH_NO_HMAC_SHA2_256 - { ID_HMAC_SHA2_256, "hmac-sha2-256" }, + { ID_HMAC_SHA2_256, TYPE_MAC, "hmac-sha2-256" }, #endif /* Key Exchange IDs */ #ifndef WOLFSSH_NO_DH_GROUP1_SHA1 - { ID_DH_GROUP1_SHA1, "diffie-hellman-group1-sha1" }, + { ID_DH_GROUP1_SHA1, TYPE_KEX, "diffie-hellman-group1-sha1" }, #endif #ifndef WOLFSSH_NO_DH_GROUP14_SHA1 - { ID_DH_GROUP14_SHA1, "diffie-hellman-group14-sha1" }, + { ID_DH_GROUP14_SHA1, TYPE_KEX, "diffie-hellman-group14-sha1" }, #endif #ifndef WOLFSSH_NO_DH_GEX_SHA256 - { ID_DH_GEX_SHA256, "diffie-hellman-group-exchange-sha256" }, + { ID_DH_GEX_SHA256, TYPE_KEX, "diffie-hellman-group-exchange-sha256" }, #endif #ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256 - { ID_ECDH_SHA2_NISTP256, "ecdh-sha2-nistp256" }, + { ID_ECDH_SHA2_NISTP256, TYPE_KEX, "ecdh-sha2-nistp256" }, #endif #ifndef WOLFSSH_NO_ECDH_SHA2_NISTP384 - { ID_ECDH_SHA2_NISTP384, "ecdh-sha2-nistp384" }, + { ID_ECDH_SHA2_NISTP384, TYPE_KEX, "ecdh-sha2-nistp384" }, #endif #ifndef WOLFSSH_NO_ECDH_SHA2_NISTP521 - { ID_ECDH_SHA2_NISTP521, "ecdh-sha2-nistp521" }, -#endif -#ifndef WOLFSSH_NO_ECDH_SHA2_ED25519 - { ID_ECDH_SHA2_ED25519, "curve25519-sha256" }, - { ID_ECDH_SHA2_ED25519_LIBSSH, "curve25519-sha256@libssh.org" }, + { ID_ECDH_SHA2_NISTP521, TYPE_KEX, "ecdh-sha2-nistp521" }, #endif #ifndef WOLFSSH_NO_DH_GEX_SHA256 - { ID_DH_GROUP14_SHA256, "diffie-hellman-group14-sha256" }, + { ID_DH_GROUP14_SHA256, TYPE_KEX, "diffie-hellman-group14-sha256" }, #endif #ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 /* We use kyber-512 here to achieve interop with OQS's fork. */ - { ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256, + { ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256, TYPE_KEX, "ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org" }, #endif - { ID_EXTINFO_S, "ext-info-s" }, - { ID_EXTINFO_C, "ext-info-c" }, +#ifndef WOLFSSH_NO_CURVE25519_SHA256 + /* See RFC 8731 */ + { ID_CURVE25519_SHA256, TYPE_KEX, "curve25519-sha256" }, +#endif + { ID_EXTINFO_S, TYPE_OTHER, "ext-info-s" }, + { ID_EXTINFO_C, TYPE_OTHER, "ext-info-c" }, /* Public Key IDs */ #ifndef WOLFSSH_NO_RSA - { ID_SSH_RSA, "ssh-rsa" }, + { ID_SSH_RSA, TYPE_KEY, "ssh-rsa" }, #ifndef WOLFSSH_NO_RSA_SHA2_256 - { ID_RSA_SHA2_256, "rsa-sha2-256" }, + { ID_RSA_SHA2_256, TYPE_KEY, "rsa-sha2-256" }, #endif #ifndef WOLFSSH_NO_RSA_SHA2_512 - { ID_RSA_SHA2_512, "rsa-sha2-512" }, + { ID_RSA_SHA2_512, TYPE_KEY, "rsa-sha2-512" }, #endif #endif /* WOLFSSH_NO_RSA */ #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 - { ID_ECDSA_SHA2_NISTP256, "ecdsa-sha2-nistp256" }, + { ID_ECDSA_SHA2_NISTP256, TYPE_KEY, "ecdsa-sha2-nistp256" }, #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 - { ID_ECDSA_SHA2_NISTP384, "ecdsa-sha2-nistp384" }, + { ID_ECDSA_SHA2_NISTP384, TYPE_KEY, "ecdsa-sha2-nistp384" }, #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 - { ID_ECDSA_SHA2_NISTP521, "ecdsa-sha2-nistp521" }, + { ID_ECDSA_SHA2_NISTP521, TYPE_KEY, "ecdsa-sha2-nistp521" }, +#endif +#ifndef WOLFSSH_NO_ED25519 + { ID_ED25519, TYPE_KEY, "ssh-ed25519" }, #endif #ifdef WOLFSSH_CERTS #ifndef WOLFSSH_NO_SSH_RSA_SHA1 - { ID_X509V3_SSH_RSA, "x509v3-ssh-rsa" }, + { ID_X509V3_SSH_RSA, TYPE_KEY, "x509v3-ssh-rsa" }, #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 - { ID_X509V3_ECDSA_SHA2_NISTP256, "x509v3-ecdsa-sha2-nistp256" }, + { ID_X509V3_ECDSA_SHA2_NISTP256, TYPE_KEY, "x509v3-ecdsa-sha2-nistp256" }, #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 - { ID_X509V3_ECDSA_SHA2_NISTP384, "x509v3-ecdsa-sha2-nistp384" }, + { ID_X509V3_ECDSA_SHA2_NISTP384, TYPE_KEY, "x509v3-ecdsa-sha2-nistp384" }, #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 - { ID_X509V3_ECDSA_SHA2_NISTP521, "x509v3-ecdsa-sha2-nistp521" }, + { ID_X509V3_ECDSA_SHA2_NISTP521, TYPE_KEY, "x509v3-ecdsa-sha2-nistp521" }, #endif #endif /* WOLFSSH_CERTS */ /* Service IDs */ - { ID_SERVICE_USERAUTH, "ssh-userauth" }, - { ID_SERVICE_CONNECTION, "ssh-connection" }, + { ID_SERVICE_USERAUTH, TYPE_OTHER, "ssh-userauth" }, + { ID_SERVICE_CONNECTION, TYPE_OTHER, "ssh-connection" }, /* UserAuth IDs */ - { ID_USERAUTH_PASSWORD, "password" }, - { ID_USERAUTH_PUBLICKEY, "publickey" }, + { ID_USERAUTH_PASSWORD, TYPE_OTHER, "password" }, + { ID_USERAUTH_PUBLICKEY, TYPE_OTHER, "publickey" }, /* Channel Type IDs */ - { ID_CHANTYPE_SESSION, "session" }, + { ID_CHANTYPE_SESSION, TYPE_OTHER, "session" }, #ifdef WOLFSSH_FWD - { ID_CHANTYPE_TCPIP_FORWARD, "forwarded-tcpip" }, - { ID_CHANTYPE_TCPIP_DIRECT, "direct-tcpip" }, + { ID_CHANTYPE_TCPIP_FORWARD, TYPE_OTHER, "forwarded-tcpip" }, + { ID_CHANTYPE_TCPIP_DIRECT, TYPE_OTHER, "direct-tcpip" }, #endif /* WOLFSSH_FWD */ #ifdef WOLFSSH_AGENT - { ID_CHANTYPE_AUTH_AGENT, "auth-agent@openssh.com" }, + { ID_CHANTYPE_AUTH_AGENT, TYPE_OTHER, "auth-agent@openssh.com" }, #endif /* WOLFSSH_AGENT */ /* Global Request IDs */ #ifdef WOLFSSH_FWD - { ID_GLOBREQ_TCPIP_FWD, "tcpip-forward" }, - { ID_GLOBREQ_TCPIP_FWD_CANCEL, "cancel-tcpip-forward" }, + { ID_GLOBREQ_TCPIP_FWD, TYPE_OTHER, "tcpip-forward" }, + { ID_GLOBREQ_TCPIP_FWD_CANCEL, TYPE_OTHER, "cancel-tcpip-forward" }, #endif /* WOLFSSH_FWD */ /* Ext Info IDs */ - { ID_EXTINFO_SERVER_SIG_ALGS, "server-sig-algs" }, + { ID_EXTINFO_SERVER_SIG_ALGS, TYPE_OTHER, "server-sig-algs" }, /* Curve Name IDs */ - { ID_CURVE_NISTP256, "nistp256" }, - { ID_CURVE_NISTP384, "nistp384" }, - { ID_CURVE_NISTP521, "nistp521" }, + { ID_CURVE_NISTP256, TYPE_OTHER, "nistp256" }, + { ID_CURVE_NISTP384, TYPE_OTHER, "nistp384" }, + { ID_CURVE_NISTP521, TYPE_OTHER, "nistp521" }, }; @@ -2126,6 +2539,29 @@ const char* IdToName(byte id) } +const char* NameByIndexType(byte type, word32* index) +{ + const char* name = NULL; + + if (index != NULL) { + word32 i, mapSz; + + mapSz = (word32)(sizeof(NameIdMap)/sizeof(NameIdPair)); + + for (i = *index; i < mapSz; i++) { + if (NameIdMap[i].type == type) { + name = NameIdMap[i].name; + break; + } + } + + *index = i + 1; + } + + return name; +} + + WOLFSSH_CHANNEL* ChannelNew(WOLFSSH* ssh, byte channelType, word32 initialWindowSz, word32 maxPacketSz) { @@ -2568,7 +3004,7 @@ static int GetInputText(WOLFSSH* ssh, byte** pEol) int gotLine = 0; int inSz = 255; int in; - char *eol; + char *eol = NULL; if (GrowBuffer(&ssh->inputBuffer, inSz) < 0) return WS_MEMORY_E; @@ -3013,51 +3449,23 @@ static int GetNameList(byte* idList, word32* idListSz, return ret; } -static const byte cannedEncAlgo[] = { -#ifndef WOLFSSH_NO_AES_GCM - ID_AES256_GCM, - ID_AES192_GCM, - ID_AES128_GCM, -#endif -#ifndef WOLFSSH_NO_AES_CTR - ID_AES256_CTR, - ID_AES192_CTR, - ID_AES128_CTR, -#endif -#ifndef WOLFSSH_NO_AES_CBC - ID_AES256_CBC, - ID_AES192_CBC, - ID_AES128_CBC, -#endif -}; - -static const byte cannedMacAlgo[] = { -#ifndef WOLFSSH_NO_HMAC_SHA2_256 - ID_HMAC_SHA2_256, -#endif -#ifndef WOLFSSH_NO_HMAC_SHA1_96 - ID_HMAC_SHA1_96, -#endif -#ifndef WOLFSSH_NO_HMAC_SHA1 - ID_HMAC_SHA1, -#endif -}; - static const byte cannedKeyAlgoClient[] = { #ifdef WOLFSSH_CERTS -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 - ID_X509V3_ECDSA_SHA2_NISTP521, -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 - ID_X509V3_ECDSA_SHA2_NISTP384, -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 - ID_X509V3_ECDSA_SHA2_NISTP256, -#endif -#ifndef WOLFSSH_NO_SSH_RSA_SHA1 - ID_X509V3_SSH_RSA, -#endif -#endif + #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 + ID_X509V3_ECDSA_SHA2_NISTP521, + #endif + #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 + ID_X509V3_ECDSA_SHA2_NISTP384, + #endif + #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 + ID_X509V3_ECDSA_SHA2_NISTP256, + #endif + #ifdef WOLFSSH_NO_SHA1_SOFT_DISABLE + #ifndef WOLFSSH_NO_SSH_RSA_SHA1 + ID_X509V3_SSH_RSA, + #endif /* WOLFSSH_NO_SSH_RSA_SHA1 */ + #endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ +#endif /* WOLFSSH_CERTS */ #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 ID_ECDSA_SHA2_NISTP521, #endif @@ -3073,39 +3481,17 @@ static const byte cannedKeyAlgoClient[] = { #ifndef WOLFSSH_NO_RSA_SHA2_256 ID_RSA_SHA2_256, #endif -#ifndef WOLFSSH_NO_SSH_RSA_SHA1 - ID_SSH_RSA, -#endif -}; - -static const byte cannedKexAlgo[] = { -#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 - ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256, -#endif -#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP521 - ID_ECDH_SHA2_NISTP521, -#endif -#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP384 - ID_ECDH_SHA2_NISTP384, -#endif -#ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256 - ID_ECDH_SHA2_NISTP256, -#endif -#ifndef WOLFSSH_NO_DH_GEX_SHA256 - ID_DH_GEX_SHA256, -#endif -#ifndef WOLFSSH_NO_DH_GROUP14_SHA1 - ID_DH_GROUP14_SHA1, -#endif -#ifndef WOLFSSH_NO_DH_GROUP1_SHA1 - ID_DH_GROUP1_SHA1, +#ifdef WOLFSSH_NO_SHA1_SOFT_DISABLE + #ifndef WOLFSSH_NO_SSH_RSA_SHA1 + ID_SSH_RSA, + #endif /* WOLFSSH_NO_SSH_RSA_SHA1 */ +#endif /* WOLFSSH_NO_SHA1_SOFT_DISABLE */ +#ifndef WOLFSSH_NO_ED25519 + ID_ED25519, #endif }; -static const word32 cannedEncAlgoSz = (word32)sizeof(cannedEncAlgo); -static const word32 cannedMacAlgoSz = (word32)sizeof(cannedMacAlgo); static const word32 cannedKeyAlgoClientSz = (word32)sizeof(cannedKeyAlgoClient); -static const word32 cannedKexAlgoSz = (word32)sizeof(cannedKexAlgo); static byte MatchIdLists(int side, const byte* left, word32 leftSz, @@ -3234,8 +3620,7 @@ static INLINE byte KeySzForId(byte id) } } - -static INLINE enum wc_HashType HashForId(byte id) +INLINE enum wc_HashType HashForId(byte id) { switch (id) { @@ -3276,11 +3661,19 @@ static INLINE enum wc_HashType HashForId(byte id) case ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256: return WC_HASH_TYPE_SHA256; #endif +#ifndef WOLFSSH_NO_CURVE25519_SHA256 + case ID_CURVE25519_SHA256: + return WC_HASH_TYPE_SHA256; +#endif #ifndef WOLFSSH_NO_RSA_SHA2_256 case ID_RSA_SHA2_256: return WC_HASH_TYPE_SHA256; #endif +#ifndef WOLFSSH_NO_ED25519 + case ID_ED25519: + return WC_HASH_TYPE_SHA512; +#endif /* SHA2-384 */ #ifndef WOLFSSH_NO_ECDH_SHA2_NISTP384 case ID_ECDH_SHA2_NISTP384: @@ -3318,7 +3711,7 @@ static INLINE enum wc_HashType HashForId(byte id) #if !defined(WOLFSSH_NO_ECDSA) || !defined(WOLFSSH_NO_ECDH) -static INLINE int wcPrimeForId(byte id) +int wcPrimeForId(byte id) { switch (id) { #ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 @@ -3341,6 +3734,10 @@ static INLINE int wcPrimeForId(byte id) case ID_ECDSA_SHA2_NISTP384: return ECC_SECP384R1; #endif +#ifndef WOLFSSH_NO_CURVE25519_SHA256 + case ID_CURVE25519_SHA256: + return ECC_X25519; +#endif #ifndef WOLFSSH_NO_ECDH_SHA2_NISTP521 case ID_ECDH_SHA2_NISTP521: return ECC_SECP521R1; @@ -3368,6 +3765,10 @@ static INLINE const char *PrimeNameForId(byte id) #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 case ID_ECDSA_SHA2_NISTP521: return "nistp521"; +#endif +#ifndef WOLFSSH_NO_ED25519 + case ID_ED25519: + return "ed25519"; #endif default: return "unknown"; @@ -3391,13 +3792,29 @@ static INLINE byte AeadModeForId(byte id) } +static word32 AlgoListSz(const char* algoList) +{ + word32 algoListSz; + + algoListSz = (word32)WSTRLEN(algoList); + if (algoList[algoListSz-1] == ',') { + --algoListSz; + } + + return algoListSz; +} + + static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) { int ret = WS_SUCCESS; int side = WOLFSSH_ENDPOINT_SERVER; byte algoId; byte list[24] = {ID_NONE}; + byte cannedList[24] = {ID_NONE}; word32 listSz; + word32 cannedListSz; + word32 cannedAlgoNamesSz; word32 skipSz; word32 begin; @@ -3447,32 +3864,37 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) WLOG(WS_LOG_DEBUG, "DKI: KEX Algorithms"); listSz = (word32)sizeof(list); ret = GetNameList(list, &listSz, buf, len, &begin); - if (ret == WS_SUCCESS) { - ssh->handshake->kexIdGuess = list[0]; - algoId = MatchIdLists(side, list, listSz, - cannedKexAlgo, cannedKexAlgoSz); - if (algoId == ID_UNKNOWN) { - WLOG(WS_LOG_DEBUG, "Unable to negotiate KEX Algo"); - ret = WS_MATCH_KEX_ALGO_E; - } - else { - ssh->handshake->kexId = algoId; - ssh->handshake->kexHashId = HashForId(algoId); - } + } + if (ret == WS_SUCCESS) { + cannedAlgoNamesSz = AlgoListSz(ssh->algoListKex); + cannedListSz = (word32)sizeof(cannedList); + ret = GetNameListRaw(cannedList, &cannedListSz, + (const byte*)ssh->algoListKex, cannedAlgoNamesSz); + } + if (ret == WS_SUCCESS) { + ssh->handshake->kexIdGuess = list[0]; + algoId = MatchIdLists(side, list, listSz, + cannedList, cannedListSz); + if (algoId == ID_UNKNOWN) { + WLOG(WS_LOG_DEBUG, "Unable to negotiate KEX Algo"); + ret = WS_MATCH_KEX_ALGO_E; } + } + if (ret == WS_SUCCESS) { + ssh->kexId = ssh->handshake->kexId = algoId; + ssh->handshake->kexHashId = HashForId(algoId); + } + /* Extension Info Flag */ + if (ret == WS_SUCCESS) { + /* Only checking for this is we are server. Our client does + * not have anything to say to a server, yet. */ + if (side == WOLFSSH_ENDPOINT_SERVER) { + byte extInfo; - /* Extension Info Flag */ - if (ret == WS_SUCCESS) { - /* Only checking for this is we are server. Our client does - * not have anything to say to a server, yet. */ - if (side == WOLFSSH_ENDPOINT_SERVER) { - byte extInfo; - - /* Match the client accepts extInfo. */ - algoId = ID_EXTINFO_C; - extInfo = MatchIdLists(side, list, listSz, &algoId, 1); - ssh->sendExtInfo = extInfo == algoId; - } + /* Match the client accepts extInfo. */ + algoId = ID_EXTINFO_C; + extInfo = MatchIdLists(side, list, listSz, &algoId, 1); + ssh->sendExtInfo = extInfo == algoId; } } @@ -3481,27 +3903,27 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) WLOG(WS_LOG_DEBUG, "DKI: Server Host Key Algorithms"); listSz = (word32)sizeof(list); ret = GetNameList(list, &listSz, buf, len, &begin); - if (ret == WS_SUCCESS) { - const byte *cannedKeyAlgo = NULL; - word32 cannedKeyAlgoSz = 0; - - if (side == WOLFSSH_ENDPOINT_SERVER) { - cannedKeyAlgo = ssh->ctx->publicKeyAlgo; - cannedKeyAlgoSz = ssh->ctx->publicKeyAlgoCount; - } - else { - cannedKeyAlgo = cannedKeyAlgoClient; - cannedKeyAlgoSz = cannedKeyAlgoClientSz; - } - algoId = MatchIdLists(side, list, listSz, - cannedKeyAlgo, cannedKeyAlgoSz); - if (algoId == ID_UNKNOWN) { - WLOG(WS_LOG_DEBUG, "Unable to negotiate Server Host Key Algo"); - return WS_MATCH_KEY_ALGO_E; - } - else { - ssh->handshake->pubKeyId = algoId; - } + } + if (ret == WS_SUCCESS) { + if (side == WOLFSSH_ENDPOINT_SERVER && !ssh->algoListKey) { + cannedListSz = ssh->ctx->publicKeyAlgoCount; + WMEMCPY(cannedList, ssh->ctx->publicKeyAlgo, cannedListSz); + } + else { + cannedAlgoNamesSz = AlgoListSz(ssh->algoListKey); + cannedListSz = (word32)sizeof(cannedList); + ret = GetNameListRaw(cannedList, &cannedListSz, + (const byte*)ssh->algoListKey, cannedAlgoNamesSz); + } + } + if (ret == WS_SUCCESS) { + algoId = MatchIdLists(side, list, listSz, cannedList, cannedListSz); + if (algoId == ID_UNKNOWN) { + WLOG(WS_LOG_DEBUG, "Unable to negotiate Server Host Key Algo"); + return WS_MATCH_KEY_ALGO_E; + } + else { + ssh->handshake->pubKeyId = algoId; } } @@ -3510,13 +3932,18 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) WLOG(WS_LOG_DEBUG, "DKI: Enc Algorithms - Client to Server"); listSz = (word32)sizeof(list); ret = GetNameList(list, &listSz, buf, len, &begin); - if (ret == WS_SUCCESS) { - algoId = MatchIdLists(side, list, listSz, - cannedEncAlgo, cannedEncAlgoSz); - if (algoId == ID_UNKNOWN) { - WLOG(WS_LOG_DEBUG, "Unable to negotiate Encryption Algo C2S"); - ret = WS_MATCH_ENC_ALGO_E; - } + } + if (ret == WS_SUCCESS) { + cannedAlgoNamesSz = AlgoListSz(ssh->algoListCipher); + cannedListSz = (word32)sizeof(cannedList); + ret = GetNameListRaw(cannedList, &cannedListSz, + (const byte*)ssh->algoListCipher, cannedAlgoNamesSz); + } + if (ret == WS_SUCCESS) { + algoId = MatchIdLists(side, list, listSz, cannedList, cannedListSz); + if (algoId == ID_UNKNOWN) { + WLOG(WS_LOG_DEBUG, "Unable to negotiate Encryption Algo C2S"); + ret = WS_MATCH_ENC_ALGO_E; } } @@ -3525,30 +3952,33 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) WLOG(WS_LOG_DEBUG, "DKI: Enc Algorithms - Server to Client"); listSz = (word32)sizeof(list); ret = GetNameList(list, &listSz, buf, len, &begin); - if (MatchIdLists(side, list, listSz, &algoId, 1) == ID_UNKNOWN) { + } + if (ret == WS_SUCCESS) { + algoId = MatchIdLists(side, list, listSz, &algoId, 1); + if (algoId == ID_UNKNOWN) { WLOG(WS_LOG_DEBUG, "Unable to negotiate Encryption Algo S2C"); ret = WS_MATCH_ENC_ALGO_E; } + } + if (ret == WS_SUCCESS) { + ssh->handshake->encryptId = algoId; + ssh->handshake->aeadMode = AeadModeForId(algoId); + ssh->handshake->blockSz = BlockSzForId(algoId); + ssh->handshake->keys.encKeySz = + ssh->handshake->peerKeys.encKeySz = + KeySzForId(algoId); + if (!ssh->handshake->aeadMode) { + ssh->handshake->keys.ivSz = + ssh->handshake->peerKeys.ivSz = + ssh->handshake->blockSz; + } else { - ssh->handshake->encryptId = algoId; - ssh->handshake->aeadMode = AeadModeForId(algoId); - ssh->handshake->blockSz = BlockSzForId(algoId); - ssh->handshake->keys.encKeySz = - ssh->handshake->peerKeys.encKeySz = - KeySzForId(algoId); - if (!ssh->handshake->aeadMode) { - ssh->handshake->keys.ivSz = - ssh->handshake->peerKeys.ivSz = - ssh->handshake->blockSz; - } - else { #ifndef WOLFSSH_NO_AEAD - ssh->handshake->keys.ivSz = - ssh->handshake->peerKeys.ivSz = - AEAD_NONCE_SZ; - ssh->handshake->macSz = ssh->handshake->blockSz; + ssh->handshake->keys.ivSz = + ssh->handshake->peerKeys.ivSz = + AEAD_NONCE_SZ; + ssh->handshake->macSz = ssh->handshake->blockSz; #endif - } } } @@ -3557,9 +3987,15 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) WLOG(WS_LOG_DEBUG, "DKI: MAC Algorithms - Client to Server"); listSz = (word32)sizeof(list); ret = GetNameList(list, &listSz, buf, len, &begin); - if (ret == WS_SUCCESS && !ssh->aeadMode) { + } + if (ret == WS_SUCCESS && !ssh->handshake->aeadMode) { + cannedAlgoNamesSz = AlgoListSz(ssh->algoListMac); + cannedListSz = (word32)sizeof(cannedList); + ret = GetNameListRaw(cannedList, &cannedListSz, + (const byte*)ssh->algoListMac, cannedAlgoNamesSz); + if (ret == WS_SUCCESS) { algoId = MatchIdLists(side, list, listSz, - cannedMacAlgo, cannedMacAlgoSz); + cannedList, cannedListSz); if (algoId == ID_UNKNOWN) { WLOG(WS_LOG_DEBUG, "Unable to negotiate MAC Algo C2S"); ret = WS_MATCH_MAC_ALGO_E; @@ -3572,18 +4008,19 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) WLOG(WS_LOG_DEBUG, "DKI: MAC Algorithms - Server to Client"); listSz = (word32)sizeof(list); ret = GetNameList(list, &listSz, buf, len, &begin); - if (ret == WS_SUCCESS && !ssh->handshake->aeadMode) { - if (MatchIdLists(side, list, listSz, &algoId, 1) == ID_UNKNOWN) { - WLOG(WS_LOG_DEBUG, "Unable to negotiate MAC Algo S2C"); - ret = WS_MATCH_MAC_ALGO_E; - } - else { - ssh->handshake->macId = algoId; - ssh->handshake->macSz = MacSzForId(algoId); - ssh->handshake->keys.macKeySz = - ssh->handshake->peerKeys.macKeySz = - KeySzForId(algoId); - } + } + if (ret == WS_SUCCESS && !ssh->handshake->aeadMode) { + algoId = MatchIdLists(side, list, listSz, &algoId, 1); + if (algoId == ID_UNKNOWN) { + WLOG(WS_LOG_DEBUG, "Unable to negotiate MAC Algo S2C"); + ret = WS_MATCH_MAC_ALGO_E; + } + else { + ssh->handshake->macId = algoId; + ssh->handshake->macSz = MacSzForId(algoId); + ssh->handshake->keys.macKeySz = + ssh->handshake->peerKeys.macKeySz = + KeySzForId(algoId); } } @@ -3595,11 +4032,12 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) WLOG(WS_LOG_DEBUG, "DKI: Compression Algorithms - Client to Server"); listSz = (word32)sizeof(list); ret = GetNameList(list, &listSz, buf, len, &begin); - if (ret == WS_SUCCESS) { - if (MatchIdLists(side, list, listSz, &algoId, 1) == ID_UNKNOWN) { - WLOG(WS_LOG_DEBUG, "Unable to negotiate Compression Algo C2S"); - ret = WS_INVALID_ALGO_ID; - } + } + if (ret == WS_SUCCESS) { + algoId = MatchIdLists(side, list, listSz, &algoId, 1); + if (algoId == ID_UNKNOWN) { + WLOG(WS_LOG_DEBUG, "Unable to negotiate Compression Algo C2S"); + ret = WS_INVALID_ALGO_ID; } } @@ -3608,11 +4046,12 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) WLOG(WS_LOG_DEBUG, "DKI: Compression Algorithms - Server to Client"); listSz = (word32)sizeof(list); ret = GetNameList(list, &listSz, buf, len, &begin); - if (ret == WS_SUCCESS) { - if (MatchIdLists(side, list, listSz, &algoId, 1) == ID_UNKNOWN) { - WLOG(WS_LOG_DEBUG, "Unable to negotiate Compression Algo S2C"); - ret = WS_INVALID_ALGO_ID; - } + } + if (ret == WS_SUCCESS) { + algoId = MatchIdLists(side, list, listSz, &algoId, 1); + if (algoId == ID_UNKNOWN) { + WLOG(WS_LOG_DEBUG, "Unable to negotiate Compression Algo S2C"); + ret = WS_INVALID_ALGO_ID; } } @@ -3654,7 +4093,7 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) wc_HashAlg* hash = &ssh->handshake->kexHash; enum wc_HashType hashId = (enum wc_HashType)ssh->handshake->kexHashId; byte scratchLen[LENGTH_SZ]; - word32 strSz; + word32 strSz = 0; if (!ssh->isKeying) { WLOG(WS_LOG_DEBUG, "Keying initiated"); @@ -3681,7 +4120,8 @@ static int DoKexInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) } if (ret == WS_SUCCESS) { - ret = HashUpdate(hash, hashId, (const byte*)ssh->ctx->sshProtoIdStr, strSz); + ret = HashUpdate(hash, hashId, + (const byte*)ssh->ctx->sshProtoIdStr, strSz); } if (ret == WS_SUCCESS) { @@ -3913,7 +4353,10 @@ static int DoKexDhInit(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) struct wolfSSH_sigKeyBlock { - byte useRsa; + byte useRsa:1; + byte useEcc:1; + byte useEd25519:1; + byte keyAllocated:1; word32 keySz; union { #ifndef WOLFSSH_NO_RSA @@ -3925,6 +4368,11 @@ struct wolfSSH_sigKeyBlock { struct { ecc_key key; } ecc; +#endif +#ifndef WOLFSSH_NO_ED25519 + struct { + ed25519_key key; + } ed25519; #endif } sk; }; @@ -3968,8 +4416,10 @@ static int ParseRSAPubKey(WOLFSSH *ssh, &sigKeyBlock_ptr->sk.rsa.key); } - if (ret == 0) + if (ret == 0) { sigKeyBlock_ptr->keySz = (word32)sizeof(sigKeyBlock_ptr->sk.rsa.key); + sigKeyBlock_ptr->keyAllocated = 1; + } else ret = WS_RSA_E; #else @@ -3990,7 +4440,7 @@ static int ParseECCPubKey(WOLFSSH *ssh, #ifndef WOLFSSH_NO_ECDSA const byte* q; word32 qSz, pubKeyIdx = 0; - int primeId; + int primeId = 0; word32 scratch; ret = wc_ecc_init_ex(&sigKeyBlock_ptr->sk.ecc.key, ssh->ctx->heap, @@ -4030,6 +4480,7 @@ static int ParseECCPubKey(WOLFSSH *ssh, if (ret == 0) { sigKeyBlock_ptr->keySz = (word32)sizeof(sigKeyBlock_ptr->sk.ecc.key); + sigKeyBlock_ptr->keyAllocated = 1; } else ret = WS_ECC_E; @@ -4045,61 +4496,105 @@ static int ParseECCPubKey(WOLFSSH *ssh, } +/* Parse out a RAW Ed25519 public key from buffer */ +static int ParseEd25519PubKey(WOLFSSH *ssh, + struct wolfSSH_sigKeyBlock *sigKeyBlock_ptr, + byte *pubKey, word32 pubKeySz) +#ifndef WOLFSSH_NO_ED25519 +{ + int ret; + const byte* encA; + word32 encASz, pubKeyIdx = 0; + + ret = wc_ed25519_init_ex(&sigKeyBlock_ptr->sk.ed25519.key, + ssh->ctx->heap, INVALID_DEVID); + if (ret != 0) + ret = WS_ED25519_E; + + /* Skip the algo name */ + if (ret == WS_SUCCESS) { + ret = GetSkip(pubKey, pubKeySz, &pubKeyIdx); + } + + if (ret == WS_SUCCESS) { + ret = GetStringRef(&encASz, &encA, pubKey, pubKeySz, &pubKeyIdx); + } + + if (ret == WS_SUCCESS) { + ret = wc_ed25519_import_public(encA, encASz, + &sigKeyBlock_ptr->sk.ed25519.key); + if (ret != 0) + ret = WS_ED25519_E; + } + return ret; +} +#else +{ + WOLFSSH_UNUSED(ssh); + WOLFSSH_UNUSED(sigKeyBlock_ptr); + WOLFSSH_UNUSED(pubKey); + WOLFSSH_UNUSED(pubKeySz); + return WS_INVALID_ALGO_ID; +} +#endif + + #ifdef WOLFSSH_CERTS -/* finds the leaf certificate and verifies it with known CA's +/* finds the leaf certificate and optionally the bounds of the cert chain, * returns WS_SUCCESS on success */ -static int ParseAndVerifyCert(WOLFSSH* ssh, byte* in, word32 inSz, - byte** leafOut, word32* leafOutSz) +static int ParseCertChain(byte* in, word32 inSz, + byte** certChain, word32* certChainSz, word32* certCount, + byte** leafOut, word32* leafOutSz) { int ret; - word32 l = 0, m = 0; + word32 sz = 0, idx = 0; word32 ocspCount = 0; - word32 certCount = 0; - byte* certChain = NULL; - word32 certChainSz = 0; - word32 count; + byte* chain = NULL; + word32 chainSz = 0; + word32 count, countIdx; /* Skip the name */ - ret = GetSize(&l, in, inSz, &m); - m += l; + ret = GetSize(&sz, in, inSz, &idx); if (ret == WS_SUCCESS) { + idx += sz; + /* Get the cert count */ - ret = GetUint32(&certCount, in, inSz, &m); + ret = GetUint32(&count, in, inSz, &idx); } if (ret == WS_SUCCESS) { - WLOG(WS_LOG_INFO, "Peer sent certificate count of %d", certCount); - certChain = in + m; - - for (count = certCount; count > 0; count--) { - word32 certSz = 0; + WLOG(WS_LOG_INFO, "Peer sent certificate count of %d", count); + chain = in + idx; - ret = GetSize(&certSz, in, inSz, &m); + for (countIdx = count; countIdx > 0; countIdx--) { + ret = GetSize(&sz, in, inSz, &idx); if (ret != WS_SUCCESS) { break; } - WLOG(WS_LOG_INFO, "Adding certificate size %u", certSz); + WLOG(WS_LOG_INFO, "Adding certificate size %u", sz); /* store leaf cert size to present to user callback */ - if (count == certCount && leafOut != NULL) { - *leafOutSz = certSz; - *leafOut = in + m; + if (countIdx == count) { + if (leafOut != NULL && leafOutSz != NULL) { + *leafOutSz = sz; + *leafOut = in + idx; + } } - certChainSz += certSz + UINT32_SZ; - m += certSz; + chainSz += sz + UINT32_SZ; + idx += sz; } /* get OCSP count */ if (ret == WS_SUCCESS) { - ret = GetUint32(&ocspCount, in, inSz, &m); + ret = GetUint32(&ocspCount, in, inSz, &idx); } if (ret == WS_SUCCESS) { WLOG(WS_LOG_INFO, "Peer sent OCSP count of %u", ocspCount); /* RFC 6187 section 2.1 OCSP count must not exceed cert count */ - if (ocspCount > certCount) { + if (ocspCount > count) { WLOG(WS_LOG_ERROR, "Error more OCSP then Certs"); ret = WS_FATAL_ERROR; } @@ -4113,7 +4608,36 @@ static int ParseAndVerifyCert(WOLFSSH* ssh, byte* in, word32 inSz, } } - /* verify the certificate chain */ + if (ret == WS_SUCCESS) { + if (certChain != NULL && certChainSz != NULL && certCount != NULL) { + *certChain = chain; + *certChainSz = chainSz; + *certCount = count; + } + } + + return ret; +} + + +static int ParseLeafCert(byte* in, word32 inSz, + byte** leafOut, word32* leafOutSz) +{ + return ParseCertChain(in, inSz, NULL, NULL, NULL, leafOut, leafOutSz); +} + + +static int ParseCertChainVerify(WOLFSSH* ssh, byte* in, word32 inSz, + byte** leafOut, word32* leafOutSz) +{ + byte *certChain = NULL; + word32 certChainSz = 0, certCount = 0; + int ret; + + ret = ParseCertChain(in, inSz, + &certChain, &certChainSz, &certCount, + leafOut, leafOutSz); + if (ret == WS_SUCCESS) { ret = wolfSSH_CERTMAN_VerifyCerts_buffer(ssh->ctx->certMan, certChain, certChainSz, certCount); @@ -4134,7 +4658,7 @@ static int ParsePubKeyCert(WOLFSSH* ssh, byte* in, word32 inSz, byte** out, byte* leaf = NULL; word32 leafSz = 0; - ret = ParseAndVerifyCert(ssh, in, inSz, &leaf, &leafSz); + ret = ParseCertChainVerify(ssh, in, inSz, &leaf, &leafSz); if (ret == WS_SUCCESS) { int error = 0; struct DecodedCert dCert; @@ -4190,8 +4714,10 @@ static int ParseECCPubKeyCert(WOLFSSH *ssh, if (error == 0) error = wc_EccPublicKeyDecode(der, &idx, &sigKeyBlock_ptr->sk.ecc.key, derSz); - if (error == 0) + if (error == 0) { sigKeyBlock_ptr->keySz = (word32)sizeof(sigKeyBlock_ptr->sk.ecc.key); + sigKeyBlock_ptr->keyAllocated = 1; + } if (error != 0) ret = error; WFREE(der, NULL, 0); @@ -4228,6 +4754,7 @@ static int ParseRSAPubKeyCert(WOLFSSH *ssh, if (error == 0) { sigKeyBlock_ptr->keySz = (word32)sizeof(sigKeyBlock_ptr->sk.rsa.key); + sigKeyBlock_ptr->keyAllocated = 1; } if (error != 0) ret = error; @@ -4271,7 +4798,7 @@ static int ParsePubKey(WOLFSSH *ssh, case ID_ECDSA_SHA2_NISTP256: case ID_ECDSA_SHA2_NISTP384: case ID_ECDSA_SHA2_NISTP521: - sigKeyBlock_ptr->useRsa = 0; + sigKeyBlock_ptr->useEcc = 1; ret = ParseECCPubKey(ssh, sigKeyBlock_ptr, pubKey, pubKeySz); break; @@ -4279,11 +4806,16 @@ static int ParsePubKey(WOLFSSH *ssh, case ID_X509V3_ECDSA_SHA2_NISTP256: case ID_X509V3_ECDSA_SHA2_NISTP384: case ID_X509V3_ECDSA_SHA2_NISTP521: - sigKeyBlock_ptr->useRsa = 0; + sigKeyBlock_ptr->useEcc = 1; ret = ParseECCPubKeyCert(ssh, sigKeyBlock_ptr, pubKey, pubKeySz); break; #endif + case ID_ED25519: + sigKeyBlock_ptr->useEd25519 = 1; + ret = ParseEd25519PubKey(ssh, sigKeyBlock_ptr, pubKey, pubKeySz); + break; + default: ret = WS_INVALID_ALGO_ID; } @@ -4292,38 +4824,375 @@ static int ParsePubKey(WOLFSSH *ssh, } -static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) +static void FreePubKey(struct wolfSSH_sigKeyBlock *p) { - struct wolfSSH_sigKeyBlock *sigKeyBlock_ptr = NULL; - wc_HashAlg* hash = NULL; - byte* pubKey = NULL; - byte* f = NULL; - byte* sig; - word32 pubKeySz; - word32 fSz; - word32 sigSz; - word32 scratch; - word32 begin; - int ret = WS_SUCCESS; - enum wc_HashType hashId; - byte scratchLen[LENGTH_SZ]; - byte kPad = 0; - byte keyAllocated = 0; + if (p && p->keyAllocated) { + if (p->useRsa) { + #ifndef WOLFSSH_NO_RSA + wc_FreeRsaKey(&p->sk.rsa.key); + #endif + } + else if (p->useEcc) { + #ifndef WOLFSSH_NO_ECDSA + wc_ecc_free(&p->sk.ecc.key); + #endif + } + p->keyAllocated = 0; + } +} + + +/* KeyAgreeDh_client + * hashId - wolfCrypt hash type ID used + * f - peer public key + * fSz - peer public key size + */ +static int KeyAgreeDh_client(WOLFSSH* ssh, byte hashId, + const byte* f, word32 fSz) +#ifndef WOLFSSH_NO_DH +{ + int ret; + + WLOG(WS_LOG_DEBUG, "Entering KeyAgreeDh_client()"); + WOLFSSH_UNUSED(hashId); + + PRIVATE_KEY_UNLOCK(); + ret = wc_DhAgree(&ssh->handshake->privKey.dh, + ssh->k, &ssh->kSz, + ssh->handshake->x, ssh->handshake->xSz, + f, fSz); + PRIVATE_KEY_LOCK(); + if (ret != 0) { + WLOG(WS_LOG_ERROR, + "Generate DH shared secret failed, %d", ret); + ret = WS_CRYPTO_FAILED; + } + ForceZero(ssh->handshake->x, ssh->handshake->xSz); + wc_FreeDhKey(&ssh->handshake->privKey.dh); + + WLOG(WS_LOG_DEBUG, "Leaving KeyAgreeDh_client(), ret = %d", ret); + return ret; +} +#else /* WOLFSSH_NO_DH */ +{ + WOLFSSH_UNUSED(ssh); + WOLFSSH_UNUSED(hashId); + WOLFSSH_UNUSED(f); + WOLFSSH_UNUSED(fSz); + return WS_INVALID_ALGO_ID; +} +#endif /* WOLFSSH_NO_DH */ + + +/* KeyAgreeEcdh_client + * hashId - wolfCrypt hash type ID used + * f - peer public key + * fSz - peer public key size + */ +static int KeyAgreeEcdh_client(WOLFSSH* ssh, byte hashId, + const byte* f, word32 fSz) #ifndef WOLFSSH_NO_ECDH +{ + int ret = WS_SUCCESS; ecc_key *key_ptr = NULL; #ifndef WOLFSSH_SMALL_STACK ecc_key key_s; #endif -#endif -#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 - byte sharedSecretHashSz = 0; - byte *sharedSecretHash = NULL; -#endif - WLOG(WS_LOG_DEBUG, "Entering DoKexDhReply()"); + WLOG(WS_LOG_DEBUG, "Entering KeyAgreeEcdh_client()"); + WOLFSSH_UNUSED(hashId); - if (ssh == NULL || ssh->handshake == NULL || buf == NULL || - len == 0 || idx == NULL) { + #ifdef WOLFSSH_SMALL_STACK + key_ptr = (ecc_key*)WMALLOC(sizeof(ecc_key), + ssh->ctx->heap, DYNTYPE_PRIVKEY); + if (key_ptr == NULL) { + ret = WS_MEMORY_E; + } + #else /* ! WOLFSSH_SMALL_STACK */ + key_ptr = &key_s; + #endif /* WOLFSSH_SMALL_STACK */ + ret = wc_ecc_init(key_ptr); + #ifdef HAVE_WC_ECC_SET_RNG + if (ret == 0) + ret = wc_ecc_set_rng(key_ptr, ssh->rng); + #endif + if (ret == 0) + ret = wc_ecc_import_x963(f, fSz, key_ptr); + if (ret == 0) { + PRIVATE_KEY_UNLOCK(); + ret = wc_ecc_shared_secret(&ssh->handshake->privKey.ecc, + key_ptr, ssh->k, &ssh->kSz); + PRIVATE_KEY_LOCK(); + if (ret != 0) { + WLOG(WS_LOG_ERROR, + "Generate ECC shared secret failed, %d", ret); + ret = WS_CRYPTO_FAILED; + } + } + wc_ecc_free(key_ptr); + #ifdef WOLFSSH_SMALL_STACK + if (key_ptr) { + WFREE(key_ptr, ssh->ctx->heap, DYNTYPE_PRIVKEY); + } + #endif + wc_ecc_free(&ssh->handshake->privKey.ecc); + + WLOG(WS_LOG_DEBUG, "Leaving KeyAgreeEcdh_client(), ret = %d", ret); + return ret; +} +#else /* WOLFSSH_NO_ECDH */ +{ + WOLFSSH_UNUSED(ssh); + WOLFSSH_UNUSED(hashId); + WOLFSSH_UNUSED(f); + WOLFSSH_UNUSED(fSz); + return WS_INVALID_ALGO_ID; +} +#endif /* WOLFSSH_NO_ECDH */ + + +/* KeyAgreeCurve25519_client + * hashId - wolfCrypt hash type ID used + * f - peer public key + * fSz - peer public key size + */ +static int KeyAgreeCurve25519_client(WOLFSSH* ssh, byte hashId, + const byte* f, word32 fSz) +#ifndef WOLFSSH_NO_CURVE25519_SHA256 +{ + int ret; + curve25519_key pub; + + WLOG(WS_LOG_DEBUG, "Entering KeyAgreeCurve25519_client()"); + WOLFSSH_UNUSED(hashId); + + ret = wc_curve25519_init(&pub); + if (ret == 0) { + ret = wc_curve25519_check_public(f, fSz, + EC25519_LITTLE_ENDIAN); + } + + if (ret == 0) { + ret = wc_curve25519_import_public_ex(f, fSz, &pub, + EC25519_LITTLE_ENDIAN); + } + + if (ret == 0) { + PRIVATE_KEY_UNLOCK(); + ret = wc_curve25519_shared_secret_ex( + &ssh->handshake->privKey.curve25519, &pub, + ssh->k, &ssh->kSz, EC25519_LITTLE_ENDIAN); + PRIVATE_KEY_LOCK(); + if (ret != 0) { + WLOG(WS_LOG_ERROR, + "Gen curve25519 shared secret failed, %d", ret); + ret = WS_CRYPTO_FAILED; + } + } + + wc_curve25519_free(&pub); + wc_curve25519_free(&ssh->handshake->privKey.curve25519); + + WLOG(WS_LOG_DEBUG, "Leaving KeyAgreeCurve25519_client(), ret = %d", ret); + return ret; +} +#else /* WOLFSSH_NO_CURVE25519_SHA256 */ +{ + WOLFSSH_UNUSED(ssh); + WOLFSSH_UNUSED(hashId); + WOLFSSH_UNUSED(f); + WOLFSSH_UNUSED(fSz); + return WS_INVALID_ALGO_ID; +} +#endif /* WOLFSSH_NO_CURVE25519_SHA256 */ + + +/* KeyAgreeEcdhKyber1_client + * hashId - wolfCrypt hash type ID used + * f - peer public key + * fSz - peer public key size + */ +static int KeyAgreeEcdhKyber1_client(WOLFSSH* ssh, byte hashId, + const byte* f, word32 fSz) +#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 +{ + int ret = WS_SUCCESS; + byte sharedSecretHashSz = 0; + byte *sharedSecretHash = NULL; + ecc_key *key_ptr = NULL; + OQS_KEM *kem; + + #ifndef WOLFSSH_SMALL_STACK + ecc_key key_s; + #endif + #ifdef WOLFSSH_SMALL_STACK + key_ptr = (ecc_key*)WMALLOC(sizeof(ecc_key), + ssh->ctx->heap, DYNTYPE_PRIVKEY); + if (key_ptr == NULL) { + ret = WS_MEMORY_E; + } + #else /* ! WOLFSSH_SMALL_STACK */ + key_ptr = &key_s; + #endif /* WOLFSSH_SMALL_STACK */ + + WLOG(WS_LOG_DEBUG, "Entering KeyAgreeEcdhKyber1_client()"); + + /* This is a a hybrid of ECDHE and a post-quantum KEM. In this + * case, I need to generated the ECC shared secret and + * decapsulate the ciphertext of the post-quantum KEM. */ + kem = OQS_KEM_new(OQS_KEM_alg_kyber_512); + if (kem == NULL) { + ret = WS_MEMORY_E; + } + + if ((ret == 0) && (fSz <= (word32)kem->length_ciphertext)) { + ret = WS_BUFFER_E; + } + + if (ret == 0) { + ret = wc_ecc_init(key_ptr); + } + #ifdef HAVE_WC_ECC_SET_RNG + if (ret == 0) { + ret = wc_ecc_set_rng(key_ptr, ssh->rng); + } + #endif + if (ret == 0) { + ret = wc_ecc_import_x963(f + kem->length_ciphertext, + fSz - (word32)kem->length_ciphertext, + key_ptr); + } + + if (ret == 0) { + PRIVATE_KEY_UNLOCK(); + ret = wc_ecc_shared_secret(&ssh->handshake->privKey.ecc, + key_ptr, ssh->k + kem->length_shared_secret, + &ssh->kSz); + PRIVATE_KEY_LOCK(); + } + wc_ecc_free(key_ptr); + #ifdef WOLFSSH_SMALL_STACK + if (key_ptr) { + WFREE(key_ptr, ssh->ctx->heap, DYNTYPE_PRIVKEY); + } + #endif + wc_ecc_free(&ssh->handshake->privKey.ecc); + + if (ret == 0) { + if (OQS_KEM_decaps(kem, ssh->k, f, ssh->handshake->x) + != OQS_SUCCESS) { + ret = WS_ERROR; + } + } + + if (ret == 0) { + ssh->kSz += kem->length_shared_secret; + } else { + ssh->kSz = 0; + WLOG(WS_LOG_ERROR, + "Generate ECC-kyber (decap) shared secret failed, %d", + ret); + } + + if (kem != NULL) { + OQS_KEM_free(kem); + } + + /* Replace the concatenated shared secrets with the hash. That + * will become the new shared secret. */ + if (ret == 0) { + sharedSecretHashSz = wc_HashGetDigestSize(hashId); + sharedSecretHash = (byte *)WMALLOC(sharedSecretHashSz, + ssh->ctx->heap, + DYNTYPE_PRIVKEY); + if (sharedSecretHash == NULL) { + ret = WS_MEMORY_E; + } + } + + if (ret == 0) { + ret = wc_Hash(hashId, ssh->k, ssh->kSz, sharedSecretHash, + sharedSecretHashSz); + } + + if (ret == 0) { + XMEMCPY(ssh->k, sharedSecretHash, sharedSecretHashSz); + ssh->kSz = sharedSecretHashSz; + } + + if (sharedSecretHash) { + ForceZero(sharedSecretHash, sharedSecretHashSz); + WFREE(sharedSecretHash, ssh->ctx->heap, DYNTYPE_PRIVKEY); + } + + WLOG(WS_LOG_DEBUG, "Leaving KeyAgreeEcdhKyber1_client(), ret = %d", ret); + return ret; +} +#else /* WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 */ +{ + WOLFSSH_UNUSED(ssh); + WOLFSSH_UNUSED(hashId); + WOLFSSH_UNUSED(f); + WOLFSSH_UNUSED(fSz); + return WS_INVALID_ALGO_ID; +} +#endif /* WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 */ + + +/* KeyAgree_client + * hashId - wolfCrypt hash type ID used + * f - peer public key + * fSz - peer public key size + */ +static int KeyAgree_client(WOLFSSH* ssh, byte hashId, const byte* f, word32 fSz) +{ + int ret; + + /* reset size here because a previous shared secret could + * potentially be smaller by a byte than usual and cause buffer + * issues with re-key */ + ssh->kSz = MAX_KEX_KEY_SZ; + + if (ssh->handshake->useDh) { + ret = KeyAgreeDh_client(ssh, hashId, f, fSz); + } + else if (ssh->handshake->useEcc) { + ret = KeyAgreeEcdh_client(ssh, hashId, f, fSz); + } + else if (ssh->handshake->useCurve25519) { + ret = KeyAgreeCurve25519_client(ssh, hashId, f, fSz); + } + else if (ssh->handshake->useEccKyber) { + ret = KeyAgreeEcdhKyber1_client(ssh, hashId, f, fSz); + } + else { + ret = WS_INVALID_ALGO_ID; + } + return ret; +} + + +static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) +{ + struct wolfSSH_sigKeyBlock *sigKeyBlock_ptr = NULL; + wc_HashAlg* hash = NULL; + byte* pubKey = NULL; + byte* f = NULL; + byte* sig; + word32 pubKeySz; + word32 fSz; + word32 sigSz; + word32 scratch; + word32 begin; + int ret = WS_SUCCESS; + enum wc_HashType hashId; + byte scratchLen[LENGTH_SZ]; + byte kPad = 0; + + WLOG(WS_LOG_DEBUG, "Entering DoKexDhReply()"); + + if (ssh == NULL || ssh->handshake == NULL || buf == NULL || + len == 0 || idx == NULL) { ret = WS_BAD_ARGUMENT; WLOG(WS_LOG_DEBUG, "Leaving DoKexDhReply(), ret = %d", ret); return ret; @@ -4494,24 +5363,10 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) if (sigKeyBlock_ptr == NULL) { ret = WS_MEMORY_E; } - -#ifdef WOLFSSH_SMALL_STACK -#ifndef WOLFSSH_NO_ECDSA - key_ptr = (ecc_key*)WMALLOC(sizeof(ecc_key), ssh->ctx->heap, - DYNTYPE_PRIVKEY); - if (key_ptr == NULL) { - ret = WS_MEMORY_E; - } -#endif /* WOLFSSH_NO_ECDSA */ - -#else /* ! WOLFSSH_SMALL_STACK */ -#ifndef WOLFSSH_NO_ECDSA - key_ptr = &key_s; -#endif -#endif } if (ret == WS_SUCCESS) { + WMEMSET(sigKeyBlock_ptr, 0, sizeof(*sigKeyBlock_ptr)); sig = buf + begin; begin += sigSz; *idx = begin; @@ -4519,151 +5374,14 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) ret = ParsePubKey(ssh, sigKeyBlock_ptr, pubKey, pubKeySz); /* Generate and hash in the shared secret */ if (ret == WS_SUCCESS) { - /* Remember that the key needs to be freed */ - keyAllocated = 1; - /* reset size here because a previous shared secret could - * potentially be smaller by a byte than usual and cause buffer - * issues with re-key */ - ssh->kSz = MAX_KEX_KEY_SZ; - if (!ssh->handshake->useEcc -#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 - && !ssh->handshake->useEccKyber -#endif - ) { -#ifndef WOLFSSH_NO_DH - PRIVATE_KEY_UNLOCK(); - ret = wc_DhAgree(&ssh->handshake->privKey.dh, - ssh->k, &ssh->kSz, - ssh->handshake->x, ssh->handshake->xSz, - f, fSz); - PRIVATE_KEY_LOCK(); - ForceZero(ssh->handshake->x, ssh->handshake->xSz); - wc_FreeDhKey(&ssh->handshake->privKey.dh); - if (ret != 0) { - WLOG(WS_LOG_ERROR, - "Generate DH shared secret failed, %d", ret); - } -#else - ret = WS_INVALID_ALGO_ID; -#endif - } - else if (ssh->handshake->useEcc) { -#ifndef WOLFSSH_NO_ECDH - ret = wc_ecc_init(key_ptr); -#ifdef HAVE_WC_ECC_SET_RNG - if (ret == 0) - ret = wc_ecc_set_rng(key_ptr, ssh->rng); -#endif - if (ret == 0) - ret = wc_ecc_import_x963(f, fSz, key_ptr); - if (ret == 0) { - PRIVATE_KEY_UNLOCK(); - ret = wc_ecc_shared_secret(&ssh->handshake->privKey.ecc, - key_ptr, ssh->k, &ssh->kSz); - PRIVATE_KEY_LOCK(); - } - wc_ecc_free(key_ptr); - wc_ecc_free(&ssh->handshake->privKey.ecc); - if (ret != 0) { - WLOG(WS_LOG_ERROR, - "Generate ECC shared secret failed, %d", ret); - } -#else - ret = WS_INVALID_ALGO_ID; -#endif - } -#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 - else if (ssh->handshake->useEccKyber) { - /* This is a a hybrid of ECDHE and a post-quantum KEM. In this - * case, I need to generated the ECC shared secret and - * decapsulate the ciphertext of the post-quantum KEM. */ - OQS_KEM* kem = OQS_KEM_new(OQS_KEM_alg_kyber_512); - if (kem == NULL) { - ret = WS_INVALID_ALGO_ID; - } - - if ((ret == 0) && (fSz <= (word32)kem->length_ciphertext)) { - ret = WS_BUFFER_E; - } - - if (ret == 0) { - ret = wc_ecc_init(key_ptr); - } -#ifdef HAVE_WC_ECC_SET_RNG - if (ret == 0) { - ret = wc_ecc_set_rng(key_ptr, ssh->rng); - } -#endif - if (ret == 0) { - ret = wc_ecc_import_x963(f + kem->length_ciphertext, - fSz - (word32)kem->length_ciphertext, key_ptr); - } - - if (ret == 0) { - PRIVATE_KEY_UNLOCK(); - ret = wc_ecc_shared_secret(&ssh->handshake->privKey.ecc, - key_ptr, ssh->k + kem->length_shared_secret, - &ssh->kSz); - PRIVATE_KEY_LOCK(); - } - wc_ecc_free(key_ptr); - wc_ecc_free(&ssh->handshake->privKey.ecc); - - if (ret == 0) { - if (OQS_KEM_decaps(kem, ssh->k, f, ssh->handshake->x) - != OQS_SUCCESS) { - ret = WS_ERROR; - } - } - - if (ret == 0) { - ssh->kSz += kem->length_shared_secret; - } else { - ssh->kSz = 0; - WLOG(WS_LOG_ERROR, - "Generate ECC-kyber (decap) shared secret failed, %d", - ret); - } - - if (kem != NULL) { - OQS_KEM_free(kem); - } - - /* Replace the concatenated shared secrets with the hash. That - * will become the new shared secret. */ - if (ret == 0) { - sharedSecretHashSz = wc_HashGetDigestSize(hashId); - sharedSecretHash = (byte *)WMALLOC(sharedSecretHashSz, - ssh->ctx->heap, - DYNTYPE_PRIVKEY); - if (sharedSecretHash == NULL) { - ret = WS_MEMORY_E; - } - } - - if (ret == 0) { - ret = wc_Hash(hashId, ssh->k, ssh->kSz, sharedSecretHash, - sharedSecretHashSz); - } - - if (ret == 0) { - XMEMCPY(ssh->k, sharedSecretHash, sharedSecretHashSz); - ssh->kSz = sharedSecretHashSz; - } - } -#endif /* !WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 */ - else { - ret = WS_INVALID_ALGO_ID; - } + ret = KeyAgree_client(ssh, hashId, f, fSz); } /* Hash in the shared secret K. */ - if (ret == 0 -#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 - && !ssh->handshake->useEccKyber -#endif - ) { - ret = CreateMpint(ssh->k, &ssh->kSz, &kPad); + if (ret == WS_SUCCESS) { + if (!ssh->handshake->useEccKyber) { + ret = CreateMpint(ssh->k, &ssh->kSz, &kPad); + } } if (ret == 0) { @@ -4727,12 +5445,12 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) } } if (ret == WS_SUCCESS) { + sig = sig + begin; + /* In the fuzz, sigSz ends up 1 and it has issues. */ + sigSz = scratch; + if (sigKeyBlock_ptr->useRsa) { #ifndef WOLFSSH_NO_RSA - sig = sig + begin; - /* In the fuzz, sigSz ends up 1 and it has issues. */ - sigSz = scratch; - if (sigSz < MIN_RSA_SIG_SZ) { WLOG(WS_LOG_DEBUG, "Provided signature is too small."); ret = WS_RSA_E; @@ -4759,15 +5477,13 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) } #endif } - else { + else if (sigKeyBlock_ptr->useEcc) { #ifndef WOLFSSH_NO_ECDSA const byte* r; const byte* s; word32 rSz, sSz, asnSigSz; byte asnSig[256]; - sig = sig + begin; - sigSz = scratch; begin = 0; asnSigSz = (word32)sizeof(asnSig); XMEMSET(asnSig, 0, asnSigSz); @@ -4795,29 +5511,32 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) } #endif } + else if (sigKeyBlock_ptr->useEd25519) { +#ifndef WOLFSSH_NO_ED25519 + int res = 0; + + ret = wc_ed25519_verify_msg(sig, sigSz, + ssh->h, ssh->hSz, &res, + &sigKeyBlock_ptr->sk.ed25519.key); + if (ret != 0 || res != 1) { + WLOG(WS_LOG_DEBUG, + "DoKexDhReply: Signature Verify fail (%d)", + ret); + ret = WS_ED25519_E; + } +#endif /* WOLFSSH_NO_ED25519 */ + } + else { + ret = WS_INVALID_ALGO_ID; + } } } - - if (keyAllocated) { - if (sigKeyBlock_ptr->useRsa) { -#ifndef WOLFSSH_NO_RSA - wc_FreeRsaKey(&sigKeyBlock_ptr->sk.rsa.key); -#endif - } - else { -#ifndef WOLFSSH_NO_ECDSA - wc_ecc_free(&sigKeyBlock_ptr->sk.ecc.key); -#endif - } - } - } + FreePubKey(sigKeyBlock_ptr); + } if (ret == WS_SUCCESS) { - int useKeyPadding = 1; -#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 - useKeyPadding = !ssh->handshake->useEccKyber; -#endif - ret = GenerateKeys(ssh, hashId, useKeyPadding); + /* If we aren't using EccKyber, use padding. */ + ret = GenerateKeys(ssh, hashId, !ssh->handshake->useEccKyber); } if (ret == WS_SUCCESS) @@ -4825,12 +5544,6 @@ static int DoKexDhReply(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) if (sigKeyBlock_ptr) WFREE(sigKeyBlock_ptr, ssh->ctx->heap, DYNTYPE_PRIVKEY); -#ifdef WOLFSSH_SMALL_STACK - #ifndef WOLFSSH_NO_ECDSA - if (key_ptr) - WFREE(key_ptr, ssh->ctx->heap, DYNTYPE_PRIVKEY); - #endif -#endif WLOG(WS_LOG_DEBUG, "Leaving DoKexDhReply(), ret = %d", ret); return ret; } @@ -4911,6 +5624,9 @@ static int DoNewKeys(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) HandshakeInfoFree(ssh->handshake, ssh->ctx->heap); ssh->handshake = NULL; WLOG(WS_LOG_DEBUG, "Keying completed"); + + if (ssh->ctx->keyingCompletionCb) + ssh->ctx->keyingCompletionCb(ssh->keyingCompletionCtx); } return ret; @@ -5392,6 +6108,10 @@ static int DoUserAuthRequestNone(WOLFSSH* ssh, WS_UserAuthData* authData, ret = WS_USER_AUTH_E; #endif } + else if (ret == WOLFSSH_USERAUTH_WOULD_BLOCK) { + WLOG(WS_LOG_DEBUG, "DUARN: userauth callback would block"); + ret = WS_AUTH_PENDING; + } else { WLOG(WS_LOG_DEBUG, "DUARN: none check failed, retry"); ret = SendUserAuthFailure(ssh, 0); @@ -5477,6 +6197,10 @@ static int DoUserAuthRequestPassword(WOLFSSH* ssh, WS_UserAuthData* authData, #endif ret = WS_USER_AUTH_E; } + else if (ret == WOLFSSH_USERAUTH_WOULD_BLOCK) { + WLOG(WS_LOG_DEBUG, "DUARPW: userauth callback would block"); + ret = WS_AUTH_PENDING; + } else { WLOG(WS_LOG_DEBUG, "DUARPW: password check failed, retry"); authFailure = 1; @@ -5495,7 +6219,7 @@ static int DoUserAuthRequestPassword(WOLFSSH* ssh, WS_UserAuthData* authData, if (authFailure || partialSuccess) { ret = SendUserAuthFailure(ssh, partialSuccess); } - else { + else if (ret == WS_SUCCESS) { ssh->clientState = CLIENT_USERAUTH_DONE; } @@ -5510,24 +6234,19 @@ static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, enum wc_HashType hashId, byte* digest, word32 digestSz) { - enum wc_HashType enmhashId = hashId; - byte *checkDigest = NULL; - byte *encDigest = NULL; - int checkDigestSz; const byte* publicKeyType; - word32 publicKeyTypeSz = 0; - const byte* n; - word32 nSz = 0; - const byte* e = NULL; - word32 eSz = 0; const byte* sig; + word32 publicKeyTypeSz = 0; word32 sigSz; + word32 encDigestSz; word32 i = 0; int ret = WS_SUCCESS; - RsaKey *key_ptr = NULL; - -#ifndef WOLFSSH_SMALL_STACK - byte s_checkDigest[MAX_ENCODED_SIG_SZ]; +#ifdef WOLFSSH_SMALL_STACK + byte* encDigest = NULL; + RsaKey* key = NULL; +#else + byte encDigest[MAX_ENCODED_SIG_SZ]; + RsaKey key[1]; #endif WLOG(WS_LOG_DEBUG, "Entering DoUserAuthRequestRsa()"); @@ -5538,24 +6257,22 @@ static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, ret = WS_BAD_ARGUMENT; } - if (ret == WS_SUCCESS) { #ifdef WOLFSSH_SMALL_STACK - checkDigest = (byte*)WMALLOC(MAX_ENCODED_SIG_SZ, ssh->ctx->heap, - DYNTYPE_BUFFER); - if (checkDigest == NULL) + if (ret == WS_SUCCESS) { + encDigest = (byte*)WMALLOC(MAX_ENCODED_SIG_SZ, + ssh->ctx->heap, DYNTYPE_BUFFER); + if (encDigest == NULL) ret = WS_MEMORY_E; -#else - checkDigest = s_checkDigest; -#endif - key_ptr = (RsaKey*)WMALLOC(sizeof(RsaKey), ssh->ctx->heap, - DYNTYPE_PUBKEY); - if (key_ptr == NULL) + } + if (ret == WS_SUCCESS) { + key = (RsaKey*)WMALLOC(sizeof(RsaKey), ssh->ctx->heap, DYNTYPE_PUBKEY); + if (key == NULL) ret = WS_MEMORY_E; } +#endif if (ret == WS_SUCCESS) { - WMEMSET(checkDigest, 0, MAX_ENCODED_SIG_SZ); - ret = wc_InitRsaKey(key_ptr, ssh->ctx->heap); + ret = wc_InitRsaKey(key, ssh->ctx->heap); if (ret == 0) { ret = WS_SUCCESS; } @@ -5577,19 +6294,27 @@ static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, } } + /* Load up the key. */ if (ret == WS_SUCCESS) { - ret = GetMpint(&eSz, &e, pk->publicKey, pk->publicKeySz, &i); - } + const byte* n = NULL; + word32 nSz = 0; + const byte* e = NULL; + word32 eSz = 0; - if (ret == WS_SUCCESS) { - ret = GetMpint(&nSz, &n, pk->publicKey, pk->publicKeySz, &i); - } + if (ret == WS_SUCCESS) { + ret = GetMpint(&eSz, &e, pk->publicKey, pk->publicKeySz, &i); + } - if (ret == WS_SUCCESS) { - ret = wc_RsaPublicKeyDecodeRaw(n, nSz, e, eSz, key_ptr); - if (ret != 0) { - WLOG(WS_LOG_DEBUG, "Could not decode public key"); - ret = WS_CRYPTO_FAILED; + if (ret == WS_SUCCESS) { + ret = GetMpint(&nSz, &n, pk->publicKey, pk->publicKeySz, &i); + } + + if (ret == WS_SUCCESS) { + ret = wc_RsaPublicKeyDecodeRaw(n, nSz, e, eSz, key); + if (ret != 0) { + WLOG(WS_LOG_DEBUG, "Could not decode public key"); + ret = WS_CRYPTO_FAILED; + } } } @@ -5615,55 +6340,22 @@ static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, } if (ret == WS_SUCCESS) { - checkDigestSz = wc_RsaSSL_Verify(sig, sigSz, checkDigest, - MAX_ENCODED_SIG_SZ, key_ptr); - if (checkDigestSz <= 0) { - WLOG(WS_LOG_DEBUG, "Could not verify signature"); - ret = WS_CRYPTO_FAILED; - } + encDigestSz = wc_EncodeSignature(encDigest, + digest, digestSz, wc_HashGetOID(hashId)); + ret = wolfSSH_RsaVerify(sig, sigSz, encDigest, encDigestSz, + key, ssh->ctx->heap, "DoUserAuthRequestRsa"); } - if (ret == WS_SUCCESS) { - word32 encDigestSz; - volatile int compare; - volatile int sizeCompare; + wc_FreeRsaKey(key); #ifdef WOLFSSH_SMALL_STACK - encDigest = (byte*)WMALLOC(MAX_ENCODED_SIG_SZ, ssh->ctx->heap, - DYNTYPE_BUFFER); - if (encDigest == NULL) - ret = WS_MEMORY_E; - - if (ret == WS_SUCCESS) -#else - byte s_encDigest[MAX_ENCODED_SIG_SZ]; - encDigest = s_encDigest; -#endif - { - WMEMSET(encDigest, 0, MAX_ENCODED_SIG_SZ); - encDigestSz = wc_EncodeSignature(encDigest, digest, - wc_HashGetDigestSize(enmhashId), - wc_HashGetOID(enmhashId)); - - compare = ConstantCompare(encDigest, checkDigest, - encDigestSz); - sizeCompare = encDigestSz != (word32)checkDigestSz; - - if ((compare == 0) && (sizeCompare == 0)) - ret = WS_SUCCESS; - else - ret = WS_RSA_E; - } - } - if (key_ptr != NULL) { - wc_FreeRsaKey(key_ptr); - WFREE(key_ptr, ssh->ctx->heap, DYNTYPE_PUBKEY); + if (key) { + WFREE(key, ssh->ctx->heap, DYNTYPE_PUBKEY); } -#ifdef WOLFSSH_SMALL_STACK - if (checkDigest) - WFREE(checkDigest, ssh->ctx->heap, DYNTYPE_BUFFER); - if (encDigest) + if (encDigest) { WFREE(encDigest, ssh->ctx->heap, DYNTYPE_BUFFER); + } #endif + WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthRequestRsa(), ret = %d", ret); return ret; } @@ -5675,21 +6367,19 @@ static int DoUserAuthRequestRsaCert(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, enum wc_HashType hashId, byte* digest, word32 digestSz) { - enum wc_HashType enmhashId = hashId; - byte *checkDigest = NULL; - byte *encDigest = NULL; - int checkDigestSz; const byte* publicKeyType; - word32 publicKeyTypeSz = 0; const byte* sig; - word32 sigSz = 0; + word32 publicKeyTypeSz = 0; + word32 sigSz; + word32 encDigestSz; word32 i = 0; int ret = WS_SUCCESS; - RsaKey *key_ptr = NULL; - -#ifndef WOLFSSH_SMALL_STACK - byte s_checkDigest[MAX_ENCODED_SIG_SZ]; - RsaKey s_key; +#ifdef WOLFSSH_SMALL_STACK + byte* encDigest = NULL; + RsaKey* key = NULL; +#else + byte encDigest[MAX_ENCODED_SIG_SZ]; + RsaKey key[1]; #endif WLOG(WS_LOG_DEBUG, "Entering DoUserAuthRequestRsaCert()"); @@ -5700,27 +6390,28 @@ static int DoUserAuthRequestRsaCert(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, ret = WS_BAD_ARGUMENT; } - if (ret == WS_SUCCESS) { #ifdef WOLFSSH_SMALL_STACK - checkDigest = (byte*)WMALLOC(MAX_ENCODED_SIG_SZ, ssh->ctx->heap, - DYNTYPE_BUFFER); - key_ptr = (RsaKey*)WMALLOC(sizeof(RsaKey), ssh->ctx->heap, - DYNTYPE_PUBKEY); - if (checkDigest == NULL || key_ptr == NULL) - ret = WS_MEMORY_E; -#else - checkDigest = s_checkDigest; - key_ptr = &s_key; -#endif + if (ret == WS_SUCCESS) { + encDigest = (byte*)WMALLOC(MAX_ENCODED_SIG_SZ, + ssh->ctx->heap, DYNTYPE_BUFFER); + if (encDigest == NULL) + ret = WS_MEMORY_E; } + if (ret == WS_SUCCESS) { + key = (RsaKey*)WMALLOC(sizeof(RsaKey), ssh->ctx->heap, DYNTYPE_PUBKEY); + if (key == NULL) + ret = WS_MEMORY_E; + } +#endif if (ret == WS_SUCCESS) { - ret = wc_InitRsaKey(key_ptr, ssh->ctx->heap); + ret = wc_InitRsaKey(key, ssh->ctx->heap); if (ret == 0) { ret = WS_SUCCESS; } } + /* Load up the key. */ if (ret == WS_SUCCESS) { byte* pub = NULL; word32 pubSz; @@ -5743,8 +6434,12 @@ static int DoUserAuthRequestRsaCert(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, } if (ret == 0) { - word32 idx = 0; - ret = wc_RsaPublicKeyDecode(pub, &idx, key_ptr, pubSz); + i = 0; + ret = wc_RsaPublicKeyDecode(pub, &i, key, pubSz); + if (ret != 0) { + WLOG(WS_LOG_DEBUG, "Could not decode public key"); + ret = WS_CRYPTO_FAILED; + } } if (pub != NULL) @@ -5752,13 +6447,8 @@ static int DoUserAuthRequestRsaCert(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, wc_FreeDecodedCert(&cert); } - if (ret != 0) { - WLOG(WS_LOG_DEBUG, "Could not decode public key"); - ret = WS_CRYPTO_FAILED; - } - if (ret == WS_SUCCESS) { - int keySz = wc_RsaEncryptSize(key_ptr) * 8; + int keySz = wc_RsaEncryptSize(key) * 8; if (keySz < 2048) { WLOG(WS_LOG_DEBUG, "Key size too small (%d)", keySz); ret = WS_CERT_KEY_SIZE_E; @@ -5767,69 +6457,42 @@ static int DoUserAuthRequestRsaCert(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, if (ret == WS_SUCCESS) { i = 0; - /* First check that the signature's public key type matches the one - * we are expecting. */ - ret = GetSize(&publicKeyTypeSz, pk->signature, pk->signatureSz, &i); + /* Check that the signature's pubkey type matches the expected one. */ + ret = GetStringRef(&publicKeyTypeSz, &publicKeyType, + pk->signature, pk->signatureSz, &i); } if (ret == WS_SUCCESS) { - publicKeyType = pk->signature + i; - i += publicKeyTypeSz; - WOLFSSH_UNUSED(publicKeyType); - } - - if (ret == WS_SUCCESS) - ret = GetSize(&sigSz, pk->signature, pk->signatureSz, &i); + if (publicKeyTypeSz != pk->publicKeyTypeSz && + WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) { - if (ret == WS_SUCCESS) { - sig = pk->signature + i; - checkDigestSz = wc_RsaSSL_Verify(sig, sigSz, checkDigest, - MAX_ENCODED_SIG_SZ, key_ptr); - if (checkDigestSz <= 0) { - WLOG(WS_LOG_DEBUG, "Could not verify signature"); - ret = WS_CRYPTO_FAILED; + WLOG(WS_LOG_DEBUG, + "Signature's type does not match public key type"); + ret = WS_INVALID_ALGO_ID; } } if (ret == WS_SUCCESS) { - word32 encDigestSz; - volatile int compare; - volatile int sizeCompare; -#ifdef WOLFSSH_SMALL_STACK - encDigest = (byte*)WMALLOC(MAX_ENCODED_SIG_SZ, ssh->ctx->heap, - DYNTYPE_BUFFER); - if (encDigest == NULL) - ret = WS_MEMORY_E; - - if (ret == WS_SUCCESS) -#else - byte s_encDigest[MAX_ENCODED_SIG_SZ]; - encDigest = s_encDigest; -#endif - { - encDigestSz = wc_EncodeSignature(encDigest, digest, - wc_HashGetDigestSize(enmhashId), - wc_HashGetOID(enmhashId)); - - compare = ConstantCompare(encDigest, checkDigest, - encDigestSz); - sizeCompare = encDigestSz != (word32)checkDigestSz; + ret = GetMpint(&sigSz, &sig, pk->signature, pk->signatureSz, &i); + } - if ((compare == 0) && (sizeCompare == 0)) - ret = WS_SUCCESS; - else - ret = WS_RSA_E; - } + if (ret == WS_SUCCESS) { + encDigestSz = wc_EncodeSignature(encDigest, + digest, digestSz, wc_HashGetOID(hashId)); + ret = wolfSSH_RsaVerify(sig, sigSz, encDigest, encDigestSz, + key, ssh->ctx->heap, "DoUserAuthRequestRsaCert"); } - if (key_ptr) - wc_FreeRsaKey(key_ptr); + wc_FreeRsaKey(key); #ifdef WOLFSSH_SMALL_STACK - if (key_ptr) - WFREE(key_ptr, ssh->ctx->heap, DYNTYPE_PUBKEY); - if (checkDigest) - WFREE(checkDigest, ssh->ctx->heap, DYNTYPE_BUFFER); + if (key) { + WFREE(key, ssh->ctx->heap, DYNTYPE_PUBKEY); + } + if (encDigest) { + WFREE(encDigest, ssh->ctx->heap, DYNTYPE_BUFFER); + } #endif + WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthRequestRsaCert(), ret = %d", ret); return ret; } @@ -6162,6 +6825,154 @@ static int DoUserAuthRequestEccCert(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, #endif /* ! WOLFSSH_NO_ECDSA */ +#ifndef WOLFSSH_NO_ED25519 +static int DoUserAuthRequestEd25519(WOLFSSH* ssh, + WS_UserAuthData_PublicKey* pk, WS_UserAuthData* authData) +{ + const byte* publicKeyType; + byte temp[32]; + word32 publicKeyTypeSz = 0; + word32 sz, qSz; + word32 i = 0; + int ret = WS_SUCCESS; + ed25519_key *key_ptr = NULL; +#ifndef WOLFSSH_SMALL_STACK + ed25519_key s_key; +#endif + + WLOG(WS_LOG_DEBUG, "Entering DoUserAuthRequestEd25519()"); + + if (ssh == NULL || ssh->ctx == NULL || pk == NULL || authData == NULL) { + ret = WS_BAD_ARGUMENT; + } + + if (ret == WS_SUCCESS) { +#ifdef WOLFSSH_SMALL_STACK + key_ptr = (ed25519_key*)WMALLOC(sizeof(ed25519_key), ssh->ctx->heap, + DYNTYPE_PUBKEY); + if (key_ptr == NULL) + ret = WS_MEMORY_E; +#else + key_ptr = &s_key; +#endif + } + + if (ret == WS_SUCCESS) { + ret = wc_ed25519_init_ex(key_ptr, ssh->ctx->heap, INVALID_DEVID); + if (ret == 0) { + ret = WS_SUCCESS; + } + } + + /* First check that the public key's type matches the one we are + * expecting. */ + if (ret == WS_SUCCESS) + ret = GetSize(&publicKeyTypeSz, pk->publicKey, pk->publicKeySz, &i); + + if (ret == WS_SUCCESS) { + publicKeyType = pk->publicKey + i; + i += publicKeyTypeSz; + if (publicKeyTypeSz != pk->publicKeyTypeSz + && WMEMCMP(publicKeyType, + pk->publicKeyType, publicKeyTypeSz) != 0) { + WLOG(WS_LOG_DEBUG, + "Public Key's type does not match public key type"); + ret = WS_INVALID_ALGO_ID; + } + } + if (ret == WS_SUCCESS) { + ret = GetSize(&qSz, pk->publicKey, pk->publicKeySz, &i); + } + + if (ret == WS_SUCCESS) { + ret = wc_ed25519_import_public(pk->publicKey + i, qSz, key_ptr); + } + + if (ret != 0) { + WLOG(WS_LOG_DEBUG, "Could not decode public key"); + ret = WS_CRYPTO_FAILED; + } + + if (ret == WS_SUCCESS) { + i = 0; + /* First check that the signature's public key type matches the one + * we are expecting. */ + ret = GetSize(&publicKeyTypeSz, pk->signature, pk->signatureSz, &i); + } + + if (ret == WS_SUCCESS) { + publicKeyType = pk->signature + i; + i += publicKeyTypeSz; + + if (publicKeyTypeSz != pk->publicKeyTypeSz && + WMEMCMP(publicKeyType, pk->publicKeyType, publicKeyTypeSz) != 0) { + + WLOG(WS_LOG_DEBUG, + "Signature's type does not match public key type"); + ret = WS_INVALID_ALGO_ID; + } + } + + if (ret == WS_SUCCESS) { + /* Get the size of the signature blob. */ + ret = GetSize(&sz, pk->signature, pk->signatureSz, &i); + } + + if (ret == WS_SUCCESS) { + ret = wc_ed25519_verify_msg_init(pk->signature + i, sz, + key_ptr, (byte)Ed25519, NULL, 0); + } + + if (ret == WS_SUCCESS) { + c32toa(ssh->sessionIdSz, temp); + ret = wc_ed25519_verify_msg_update(temp, UINT32_SZ, key_ptr); + } + + if (ret == WS_SUCCESS) { + ret = wc_ed25519_verify_msg_update(ssh->sessionId, ssh->sessionIdSz, + key_ptr); + } + + if(ret == WS_SUCCESS) { + temp[0] = MSGID_USERAUTH_REQUEST; + ret = wc_ed25519_verify_msg_update(temp, MSG_ID_SZ, key_ptr); + } + + /* The rest of the fields in the signature are already + * in the buffer. Just need to account for the sizes. */ + if(ret == WS_SUCCESS) { + ret = wc_ed25519_verify_msg_update(pk->dataToSign, + authData->usernameSz + + authData->serviceNameSz + + authData->authNameSz + BOOLEAN_SZ + + pk->publicKeyTypeSz + pk->publicKeySz + + (UINT32_SZ * 5), key_ptr); + } + + if(ret == WS_SUCCESS) { + int status = 0; + ret = wc_ed25519_verify_msg_final(pk->signature + i, sz, + &status, key_ptr); + if (ret != 0) { + WLOG(WS_LOG_DEBUG, "Could not verify signature"); + ret = WS_CRYPTO_FAILED; + } + else + ret = status ? WS_SUCCESS : WS_ED25519_E; + } + + if (key_ptr) { + wc_ed25519_free(key_ptr); +#ifdef WOLFSSH_SMALL_STACK + WFREE(key_ptr, ssh->ctx->heap, DYNTYPE_PUBKEY); +#endif + } + + WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthRequestEd25519(), ret = %d", ret); + return ret; +} +#endif /* !WOLFSSH_NO_ED25519 */ + #if !defined(WOLFSSH_NO_RSA) || !defined(WOLFSSH_NO_ECDSA) /* Utility for DoUserAuthRequest() */ static int DoUserAuthRequestPublicKey(WOLFSSH* ssh, WS_UserAuthData* authData, @@ -6261,22 +7072,29 @@ static int DoUserAuthRequestPublicKey(WOLFSSH* ssh, WS_UserAuthData* authData, #ifdef WOLFSSH_CERTS if (ret == WS_SUCCESS && !authFailure) { - if (pkTypeId == ID_X509V3_SSH_RSA || - pkTypeId == ID_X509V3_ECDSA_SHA2_NISTP256 || - pkTypeId == ID_X509V3_ECDSA_SHA2_NISTP384 || - pkTypeId == ID_X509V3_ECDSA_SHA2_NISTP521) { - byte *cert = NULL; + if (pkTypeId == ID_X509V3_SSH_RSA + || pkTypeId == ID_X509V3_ECDSA_SHA2_NISTP256 + || pkTypeId == ID_X509V3_ECDSA_SHA2_NISTP384 + || pkTypeId == ID_X509V3_ECDSA_SHA2_NISTP521) { + byte *cert = NULL; word32 certSz = 0; - ret = ParseAndVerifyCert(ssh, (byte*)pubKeyBlob, pubKeyBlobSz, - &cert, &certSz); - if (ret == WS_SUCCESS) { - authData->sf.publicKey.publicKey = cert; + if (hasSig) { + ret = ParseCertChainVerify(ssh, + (byte*)pubKeyBlob, pubKeyBlobSz, &cert, &certSz); + } + else { + ret = ParseLeafCert((byte*)pubKeyBlob, pubKeyBlobSz, + &cert, &certSz); + } + if (ret == WS_SUCCESS) { + authData->sf.publicKey.publicKey = cert; authData->sf.publicKey.publicKeySz = certSz; authData->sf.publicKey.isCert = 1; } else { - WLOG(WS_LOG_DEBUG, "DUARPK: client cert not verified"); + WLOG(WS_LOG_DEBUG, "DUARPK: cannot parse client cert chain"); + ret = WS_SUCCESS; authFailure = 1; } } @@ -6289,6 +7107,7 @@ static int DoUserAuthRequestPublicKey(WOLFSSH* ssh, WS_UserAuthData* authData, ret = ssh->ctx->userAuthCb(WOLFSSH_USERAUTH_PUBLICKEY, authData, ssh->userAuthCtx); WLOG(WS_LOG_DEBUG, "DUARPK: callback result = %d", ret); + #ifdef DEBUG_WOLFSSH switch (ret) { case WOLFSSH_USERAUTH_SUCCESS: @@ -6319,19 +7138,28 @@ static int DoUserAuthRequestPublicKey(WOLFSSH* ssh, WS_UserAuthData* authData, WLOG(WS_LOG_DEBUG, "DUARPK: user auth partial success"); break; + case WOLFSSH_USERAUTH_WOULD_BLOCK: + WLOG(WS_LOG_DEBUG, "DUARPK: userauth callback would block"); + break; + default: WLOG(WS_LOG_DEBUG, "Unexpected return value from Auth callback"); } #endif - if (ret == WOLFSSH_USERAUTH_PARTIAL_SUCCESS) { - partialSuccess = 1; + if (ret == WOLFSSH_USERAUTH_WOULD_BLOCK) { + ret = WS_AUTH_PENDING; } - else if (ret != WOLFSSH_USERAUTH_SUCCESS) { - authFailure = 1; + else { + if (ret == WOLFSSH_USERAUTH_PARTIAL_SUCCESS) { + partialSuccess = 1; + } + else if (ret != WOLFSSH_USERAUTH_SUCCESS) { + authFailure = 1; + } + ret = WS_SUCCESS; } - ret = WS_SUCCESS; } else { WLOG(WS_LOG_DEBUG, "DUARPK: no userauth callback set"); @@ -6346,98 +7174,107 @@ static int DoUserAuthRequestPublicKey(WOLFSSH* ssh, WS_UserAuthData* authData, pubKeyAlgo, pubKeyAlgoSz, pubKeyBlob, pubKeyBlobSz); } else { - wc_HashAlg hash; - byte digest[WC_MAX_DIGEST_SIZE]; - word32 digestSz = 0; - enum wc_HashType hashId = WC_HASH_TYPE_SHA; + if (pkTypeId == ID_ED25519) { +#ifndef WOLFSSH_NO_ED25519 + ret = DoUserAuthRequestEd25519(ssh, + &authData->sf.publicKey, authData); +#else + ret = WS_INVALID_ALGO_ID; +#endif + } else { + wc_HashAlg hash; + byte digest[WC_MAX_DIGEST_SIZE]; + word32 digestSz = 0; + enum wc_HashType hashId = WC_HASH_TYPE_SHA; - if (ret == WS_SUCCESS) { - hashId = HashForId(pkTypeId); - WMEMSET(digest, 0, sizeof(digest)); - ret = wc_HashGetDigestSize(hashId); - if (ret > 0) { - digestSz = ret; - ret = 0; + if (ret == WS_SUCCESS) { + hashId = HashForId(pkTypeId); + WMEMSET(digest, 0, sizeof(digest)); + ret = wc_HashGetDigestSize(hashId); + if (ret > 0) { + digestSz = ret; + ret = 0; + } } - } - if (ret == 0) - ret = wc_HashInit(&hash, hashId); + if (ret == 0) + ret = wc_HashInit(&hash, hashId); - if (ret == 0) { - c32toa(ssh->sessionIdSz, digest); - ret = HashUpdate(&hash, hashId, digest, UINT32_SZ); - } + if (ret == 0) { + c32toa(ssh->sessionIdSz, digest); + ret = HashUpdate(&hash, hashId, digest, UINT32_SZ); + } - if (ret == 0) - ret = HashUpdate(&hash, hashId, - ssh->sessionId, ssh->sessionIdSz); + if (ret == 0) + ret = HashUpdate(&hash, hashId, + ssh->sessionId, ssh->sessionIdSz); - if (ret == 0) { - digest[0] = MSGID_USERAUTH_REQUEST; - ret = HashUpdate(&hash, hashId, digest, MSG_ID_SZ); - } + if (ret == 0) { + digest[0] = MSGID_USERAUTH_REQUEST; + ret = HashUpdate(&hash, hashId, digest, MSG_ID_SZ); + } - /* The rest of the fields in the signature are already - * in the buffer. Just need to account for the sizes, which total - * the length of the buffer minus the signature and size of - * signature. */ - if (ret == 0) { - ret = HashUpdate(&hash, hashId, - authData->sf.publicKey.dataToSign, - len - sigSz - LENGTH_SZ); - } - if (ret == 0) { - ret = wc_HashFinal(&hash, hashId, digest); + /* The rest of the fields in the signature are already + * in the buffer. Just need to account for the sizes, which + * total the length of the buffer minus the signature and + * size of signature. */ + if (ret == 0) { + ret = HashUpdate(&hash, hashId, + authData->sf.publicKey.dataToSign, + len - sigSz - LENGTH_SZ); + } + if (ret == 0) { + ret = wc_HashFinal(&hash, hashId, digest); - if (ret != 0) - ret = WS_CRYPTO_FAILED; - else - ret = WS_SUCCESS; - } - wc_HashFree(&hash, hashId); + if (ret != 0) + ret = WS_CRYPTO_FAILED; + else + ret = WS_SUCCESS; + } + wc_HashFree(&hash, hashId); - if (ret == WS_SUCCESS) { - WLOG(WS_LOG_DEBUG, "Verify user signature type: %s", - IdToName(pkTypeId)); - - switch (pkTypeId) { - #ifndef WOLFSSH_NO_RSA - case ID_SSH_RSA: - case ID_RSA_SHA2_256: - case ID_RSA_SHA2_512: - ret = DoUserAuthRequestRsa(ssh, - &authData->sf.publicKey, - hashId, digest, digestSz); - break; - #ifdef WOLFSSH_CERTS - case ID_X509V3_SSH_RSA: - ret = DoUserAuthRequestRsaCert(ssh, - &authData->sf.publicKey, - hashId, digest, digestSz); - break; - #endif - #endif - #ifndef WOLFSSH_NO_ECDSA - case ID_ECDSA_SHA2_NISTP256: - case ID_ECDSA_SHA2_NISTP384: - case ID_ECDSA_SHA2_NISTP521: - ret = DoUserAuthRequestEcc(ssh, - &authData->sf.publicKey, - hashId, digest, digestSz); - break; - #ifdef WOLFSSH_CERTS - case ID_X509V3_ECDSA_SHA2_NISTP256: - case ID_X509V3_ECDSA_SHA2_NISTP384: - case ID_X509V3_ECDSA_SHA2_NISTP521: - ret = DoUserAuthRequestEccCert(ssh, - &authData->sf.publicKey, - hashId, digest, digestSz); - break; - #endif - #endif - default: - ret = WS_INVALID_ALGO_ID; + if (ret == WS_SUCCESS) { + WLOG(WS_LOG_DEBUG, "Verify user signature type: %s", + IdToName(pkTypeId)); + + switch (pkTypeId) { + #ifndef WOLFSSH_NO_RSA + case ID_SSH_RSA: + case ID_RSA_SHA2_256: + case ID_RSA_SHA2_512: + ret = DoUserAuthRequestRsa(ssh, + &authData->sf.publicKey, + hashId, digest, digestSz); + break; + #ifdef WOLFSSH_CERTS + case ID_X509V3_SSH_RSA: + ret = DoUserAuthRequestRsaCert(ssh, + &authData->sf.publicKey, + hashId, digest, digestSz); + break; + #endif + #endif + #ifndef WOLFSSH_NO_ECDSA + case ID_ECDSA_SHA2_NISTP256: + case ID_ECDSA_SHA2_NISTP384: + case ID_ECDSA_SHA2_NISTP521: + ret = DoUserAuthRequestEcc(ssh, + &authData->sf.publicKey, + hashId, digest, digestSz); + break; + #ifdef WOLFSSH_CERTS + case ID_X509V3_ECDSA_SHA2_NISTP256: + case ID_X509V3_ECDSA_SHA2_NISTP384: + case ID_X509V3_ECDSA_SHA2_NISTP521: + ret = DoUserAuthRequestEccCert(ssh, + &authData->sf.publicKey, + hashId, digest, digestSz); + break; + #endif + #endif + default: + ret = WS_INVALID_ALGO_ID; + } } } @@ -6458,24 +7295,19 @@ static int DoUserAuthRequestPublicKey(WOLFSSH* ssh, WS_UserAuthData* authData, WLOG(WS_LOG_DEBUG, "DUARPK: user overriding success"); authFailure = 1; } - else { - ssh->clientState = CLIENT_USERAUTH_DONE; - } } - else { + if (!authFailure && !partialSuccess) { ssh->clientState = CLIENT_USERAUTH_DONE; } } } } - if (ret == WS_SUCCESS) { - if (authFailure) { - ret = SendUserAuthFailure(ssh, 0); - } - else if (partialSuccess && hasSig) { - ret = SendUserAuthFailure(ssh, 1); - } + if (authFailure) { + ret = SendUserAuthFailure(ssh, 0); + } + else if (partialSuccess && hasSig) { + ret = SendUserAuthFailure(ssh, 1); } WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthRequestPublicKey(), ret = %d", ret); @@ -6923,6 +7755,9 @@ static int DoChannelOpen(WOLFSSH* ssh, else { ChannelUpdatePeer(newChannel, peerChannelId, peerInitialWindowSz, peerMaxPacketSz); + if (ssh->ctx->channelOpenCb) { + ret = ssh->ctx->channelOpenCb(newChannel, ssh->channelOpenCtx); + } if (ssh->channelListSz == 0) ssh->defaultPeerChannelId = peerChannelId; #ifdef WOLFSSH_FWD @@ -6953,16 +7788,18 @@ static int DoChannelOpen(WOLFSSH* ssh, const char *description = NULL; if (fail_reason == OPEN_ADMINISTRATIVELY_PROHIBITED) - description = "Each session cannot have more than one channel open."; + description = "Administratively prohibited."; else if (fail_reason == OPEN_UNKNOWN_CHANNEL_TYPE) description = "Channel type not supported."; else if (fail_reason == OPEN_RESOURCE_SHORTAGE) description = "Not enough resources."; - if (description != NULL) - ret = SendChannelOpenFail(ssh, peerChannelId, fail_reason, description, "en"); + if (description != NULL) { + ret = SendChannelOpenFail(ssh, peerChannelId, + fail_reason, description, "en"); + } else - ret = SendRequestSuccess(ssh, 0); + ret = SendRequestSuccess(ssh, 0); /* XXX Is this right? */ } #ifdef WOLFSSH_FWD @@ -7018,6 +7855,12 @@ static int DoChannelOpenConf(WOLFSSH* ssh, ret = ChannelUpdatePeer(channel, peerChannelId, peerInitialWindowSz, peerMaxPacketSz); + if (ret == WS_SUCCESS) { + if (ssh->ctx->channelOpenConfCb != NULL) { + ret = ssh->ctx->channelOpenConfCb(channel, ssh->channelOpenCtx); + } + } + if (ret == WS_SUCCESS) { ssh->serverState = SERVER_CHANNEL_OPEN_DONE; ssh->defaultPeerChannelId = peerChannelId; @@ -7031,6 +7874,7 @@ static int DoChannelOpenConf(WOLFSSH* ssh, static int DoChannelOpenFail(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) { + WOLFSSH_CHANNEL* channel = NULL; char desc[80]; word32 begin, channelId, reasonId, descSz, langSz; int ret = WS_SUCCESS; @@ -7064,6 +7908,19 @@ static int DoChannelOpenFail(WOLFSSH* ssh, WLOG(WS_LOG_INFO, "description: %s", desc); } + if (ssh->ctx->channelOpenFailCb != NULL) { + channel = ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF); + + if (channel != NULL) { + ret = ssh->ctx->channelOpenFailCb(channel, ssh->channelOpenCtx); + } + else { + ret = WS_INVALID_CHANID; + } + } + } + + if (ret == WS_SUCCESS) { ret = ChannelRemove(ssh, channelId, WS_CHANNEL_ID_SELF); } @@ -7095,6 +7952,12 @@ static int DoChannelEof(WOLFSSH* ssh, ret = WS_INVALID_CHANID; } + if (ret == WS_SUCCESS) { + if (ssh->ctx->channelEofCb) { + ssh->ctx->channelEofCb(channel, ssh->channelEofCtx); + } + } + if (ret == WS_SUCCESS) { channel->eofRxd = 1; if (!channel->eofTxd) { @@ -7128,6 +7991,12 @@ static int DoChannelClose(WOLFSSH* ssh, ret = WS_INVALID_CHANID; } + if (ret == WS_SUCCESS) { + if (ssh->ctx->channelCloseCb) { + ssh->ctx->channelCloseCb(channel, ssh->channelCloseCtx); + } + } + if (ret == WS_SUCCESS) { if (!channel->closeTxd) { ret = SendChannelClose(ssh, channel->peerChannel); @@ -7345,7 +8214,8 @@ int wolfSSH_DoModes(const byte* modes, word32 modesSz, int fd) TTY_SET_FLAG(term.c_lflag, ONLCR, arg); break; case WOLFSSH_OCRNL: - TTY_SET_FLAG(term.c_lflag, OCRNL, arg); + /* keep as default, adjusting removes echo over shell */ + /* TTY_SET_FLAG(term.c_lflag, OCRNL, arg); */ break; case WOLFSSH_ONOCR: TTY_SET_FLAG(term.c_lflag, ONOCR, arg); @@ -7400,7 +8270,7 @@ static int DoChannelRequest(WOLFSSH* ssh, word32 typeSz; char type[32]; byte wantReply; - int ret; + int ret, rej = 0; WLOG(WS_LOG_DEBUG, "Entering DoChannelRequest()"); @@ -7429,8 +8299,53 @@ static int DoChannelRequest(WOLFSSH* ssh, WLOG(WS_LOG_DEBUG, " type = %s", type); WLOG(WS_LOG_DEBUG, " wantReply = %u", wantReply); -#ifdef WOLFSSH_TERM - if (WSTRNCMP(type, "pty-req", typeSz) == 0) { + if (WSTRNCMP(type, "env", typeSz) == 0) { + char name[WOLFSSH_MAX_NAMESZ]; + word32 nameSz; + char value[32]; + word32 valueSz; + + name[0] = 0; + value[0] = 0; + nameSz = (word32)sizeof(name); + valueSz = (word32)sizeof(value); + ret = GetString(name, &nameSz, buf, len, &begin); + if (ret == WS_SUCCESS) + ret = GetString(value, &valueSz, buf, len, &begin); + + WLOG(WS_LOG_DEBUG, " %s = %s", name, value); + } + else if (WSTRNCMP(type, "shell", typeSz) == 0) { + channel->sessionType = WOLFSSH_SESSION_SHELL; + if (ssh->ctx->channelReqShellCb) { + rej = ssh->ctx->channelReqShellCb(channel, ssh->channelReqCtx); + } + ssh->clientState = CLIENT_DONE; + } + else if (WSTRNCMP(type, "exec", typeSz) == 0) { + ret = GetStringAlloc(ssh->ctx->heap, &channel->command, + buf, len, &begin); + channel->sessionType = WOLFSSH_SESSION_EXEC; + if (ssh->ctx->channelReqExecCb) { + rej = ssh->ctx->channelReqExecCb(channel, ssh->channelReqCtx); + } + ssh->clientState = CLIENT_DONE; + + WLOG(WS_LOG_DEBUG, " command = %s", channel->command); + } + else if (WSTRNCMP(type, "subsystem", typeSz) == 0) { + ret = GetStringAlloc(ssh->ctx->heap, &channel->command, + buf, len, &begin); + channel->sessionType = WOLFSSH_SESSION_SUBSYSTEM; + if (ssh->ctx->channelReqSubsysCb) { + rej = ssh->ctx->channelReqSubsysCb(channel, ssh->channelReqCtx); + } + ssh->clientState = CLIENT_DONE; + + WLOG(WS_LOG_DEBUG, " subsystem = %s", channel->command); + } + #ifdef WOLFSSH_TERM + else if (WSTRNCMP(type, "pty-req", typeSz) == 0) { char term[32]; const byte* modes; word32 termSz, modesSz = 0; @@ -7449,7 +8364,8 @@ static int DoChannelRequest(WOLFSSH* ssh, if (ret == WS_SUCCESS) ret = GetStringRef(&modesSz, &modes, buf, len, &begin); if (ret == WS_SUCCESS) { - ssh->modes = (byte*)WMALLOC(modesSz, ssh->ctx->heap, 0); + ssh->modes = (byte*)WMALLOC(modesSz, + ssh->ctx->heap, DYNTYPE_STRING); if (ssh->modes == NULL) ret = WS_MEMORY_E; } @@ -7474,54 +8390,8 @@ static int DoChannelRequest(WOLFSSH* ssh, } } } - else -#endif /* WOLFSSH_TERM */ - if (WSTRNCMP(type, "env", typeSz) == 0) { - char name[WOLFSSH_MAX_NAMESZ]; - word32 nameSz; - char value[32]; - word32 valueSz; - - name[0] = 0; - value[0] = 0; - nameSz = (word32)sizeof(name); - valueSz = (word32)sizeof(value); - ret = GetString(name, &nameSz, buf, len, &begin); - if (ret == WS_SUCCESS) - ret = GetString(value, &valueSz, buf, len, &begin); - - WLOG(WS_LOG_DEBUG, " %s = %s", name, value); - } - else if (WSTRNCMP(type, "shell", typeSz) == 0) { - channel->sessionType = WOLFSSH_SESSION_SHELL; - ssh->clientState = CLIENT_DONE; - } - else if (WSTRNCMP(type, "exec", typeSz) == 0) { - ret = GetStringAlloc(ssh->ctx->heap, &channel->command, - buf, len, &begin); - channel->sessionType = WOLFSSH_SESSION_EXEC; - ssh->clientState = CLIENT_DONE; - - WLOG(WS_LOG_DEBUG, " command = %s", channel->command); - } - else if (WSTRNCMP(type, "subsystem", typeSz) == 0) { - ret = GetStringAlloc(ssh->ctx->heap, &channel->command, - buf, len, &begin); - channel->sessionType = WOLFSSH_SESSION_SUBSYSTEM; - ssh->clientState = CLIENT_DONE; - - WLOG(WS_LOG_DEBUG, " subsystem = %s", channel->command); - } -#ifdef WOLFSSH_AGENT - else if (WSTRNCMP(type, "auth-agent-req@openssh.com", typeSz) == 0) { - WLOG(WS_LOG_AGENT, " ssh-agent"); - if (ssh->ctx->agentCb != NULL) - ssh->useAgent = 1; - else - WLOG(WS_LOG_AGENT, "Agent callback not set, not using."); - } -#endif /* WOLFSSH_AGENT */ -#if defined(WOLFSSH_SHELL) && defined(WOLFSSH_TERM) + #endif /* WOLFSSH_TERM */ + #if defined(WOLFSSH_SHELL) && defined(WOLFSSH_TERM) else if (WSTRNCMP(type, "window-change", typeSz) == 0) { word32 widthChar, heightRows, widthPixels, heightPixels; @@ -7551,8 +8421,8 @@ static int DoChannelRequest(WOLFSSH* ssh, } } } -#endif /* WOLFSSH_SHELL && WOLFSSH_TERM */ -#if defined(WOLFSSH_TERM) || defined(WOLFSSH_SHELL) + #endif /* WOLFSSH_SHELL && WOLFSSH_TERM */ + #if defined(WOLFSSH_TERM) || defined(WOLFSSH_SHELL) else if (WSTRNCMP(type, "exit-status", typeSz) == 0) { ret = GetUint32(&ssh->exitStatus, buf, len, &begin); WLOG(WS_LOG_AGENT, "Got exit status %u.", ssh->exitStatus); @@ -7585,16 +8455,30 @@ static int DoChannelRequest(WOLFSSH* ssh, ret = GetString(sig, &sigSz, buf, len, &begin); } } -#endif + #endif /* WOLFSSH_TERM or WOLFSSH_SHELL */ + #ifdef WOLFSSH_AGENT + else if (WSTRNCMP(type, "auth-agent-req@openssh.com", typeSz) == 0) { + WLOG(WS_LOG_AGENT, " ssh-agent"); + if (ssh->ctx->agentCb != NULL) + ssh->useAgent = 1; + else + WLOG(WS_LOG_AGENT, "Agent callback not set, not using."); + } + #endif /* WOLFSSH_AGENT */ } - if (ret == WS_SUCCESS) + if (ret == WS_SUCCESS) { *idx = len; + } if (wantReply) { int replyRet; - replyRet = SendChannelSuccess(ssh, channelId, (ret == WS_SUCCESS)); + if (rej) { + WLOG(WS_LOG_DEBUG, "Callback rejecting channel request."); + } + replyRet = SendChannelSuccess(ssh, channelId, + (ret == WS_SUCCESS && !rej)); if (replyRet != WS_SUCCESS) ret = replyRet; } @@ -7825,6 +8709,10 @@ static int DoPacket(WOLFSSH* ssh, byte* bufferConsumed) return WS_OVERFLOW_E; } + if (!IsMessageAllowed(ssh, msg)) { + return WS_MSGID_NOT_ALLOWED_E; + } + switch (msg) { case MSGID_DISCONNECT: @@ -8020,18 +8908,21 @@ static int DoPacket(WOLFSSH* ssh, byte* bufferConsumed) ret = SendUnimplemented(ssh); } - if (payloadSz > 0) { - idx += payloadIdx; - if (idx + padSz > len) { - WLOG(WS_LOG_DEBUG, "Not enough data in buffer for pad."); - ret = WS_BUFFER_E; + /* if the auth is still pending, don't discard the packet data */ + if (ret != WS_AUTH_PENDING) { + if (payloadSz > 0) { + idx += payloadIdx; + if (idx + padSz > len) { + WLOG(WS_LOG_DEBUG, "Not enough data in buffer for pad."); + ret = WS_BUFFER_E; + } } - } - idx += padSz; - ssh->inputBuffer.idx = idx; - ssh->peerSeq++; - *bufferConsumed = 1; + idx += padSz; + ssh->inputBuffer.idx = idx; + ssh->peerSeq++; + *bufferConsumed = 1; + } return ret; } @@ -8804,6 +9695,24 @@ static INLINE void CopyNameList(byte* buf, word32* idx, } +static INLINE void CopyNameListPlus(byte* buf, word32* idx, + const char* src, word32 srcSz, const char* plus, word32 plusSz) +{ + word32 begin = *idx; + + c32toa(srcSz + plusSz, buf + begin); + begin += LENGTH_SZ; + WMEMCPY(buf + begin, src, srcSz); + begin += srcSz; + if (plusSz) { + WMEMCPY(buf + begin, plus, plusSz); + } + begin += plusSz; + + *idx = begin; +} + + /* * Iterates over a list of ID values and builds a string of names. * @@ -8852,179 +9761,20 @@ static int BuildNameList(char* buf, word32 bufSz, } -static const char cannedEncAlgoNames[] = -#if !defined(WOLFSSH_NO_AES_GCM) - "aes256-gcm@openssh.com," - "aes192-gcm@openssh.com," - "aes128-gcm@openssh.com," -#endif -#if !defined(WOLFSSH_NO_AES_CTR) - "aes256-ctr," - "aes192-ctr," - "aes128-ctr," -#endif -#if !defined(WOLFSSH_NO_AES_CBC) - "aes256-cbc," - "aes192-cbc," - "aes128-cbc," -#endif - ""; +int SendKexInit(WOLFSSH* ssh) +{ + byte* output = NULL; + byte* payload = NULL; + char* keyAlgoNames = NULL; + const char* kexAlgoNamesPlus = NULL; + word32 idx = 0, payloadSz = 0, + kexAlgoNamesSz = 0, kexAlgoNamesPlusSz = 0, + keyAlgoNamesSz = 0, encAlgoNamesSz = 0, + macAlgoNamesSz = 0, noneNamesSz = 0; -static const char cannedMacAlgoNames[] = -#if !defined(WOLFSSH_NO_HMAC_SHA2_256) - "hmac-sha2-256," -#endif -#if !defined(WOLFSSH_NO_HMAC_SHA1_96) - "hmac-sha1-96," -#endif -#if !defined(WOLFSSH_NO_HMAC_SHA1) - "hmac-sha1," -#endif - ""; + int ret = WS_SUCCESS; - -#ifndef WOLFSSH_NO_SSH_RSA_SHA1 - #ifdef WOLFSSH_CERTS - static const char cannedKeyAlgoX509RsaNames[] = "x509v3-ssh-rsa"; - #endif -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 - static const char cannedKeyAlgoEcc256Names[] = "ecdsa-sha2-nistp256"; - #ifdef WOLFSSH_CERTS - static const char cannedKeyAlgoX509Ecc256Names[] = - "x509v3-ecdsa-sha2-nistp256"; - #endif -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 - static const char cannedKeyAlgoEcc384Names[] = "ecdsa-sha2-nistp384"; - #ifdef WOLFSSH_CERTS - static const char cannedKeyAlgoX509Ecc384Names[] = - "x509v3-ecdsa-sha2-nistp384"; - #endif -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 - static const char cannedKeyAlgoEcc521Names[] = "ecdsa-sha2-nistp521"; - #ifdef WOLFSSH_CERTS - static const char cannedKeyAlgoX509Ecc521Names[] = - "x509v3-ecdsa-sha2-nistp521"; - #endif -#endif -#ifndef WOLFSSH_NO_SSH_RSA_SHA1 - /* Used for both the signature algorithm and the RSA key format. */ - static const char cannedKeyAlgoSshRsaNames[] = "ssh-rsa"; -#endif -#ifndef WOLFSSH_NO_RSA_SHA2_256 - static const char cannedKeyAlgoRsaSha2_256Names[] = "rsa-sha2-256"; -#endif -#ifndef WOLFSSH_NO_RSA_SHA2_512 - static const char cannedKeyAlgoRsaSha2_512Names[] = "rsa-sha2-512"; -#endif - -#ifdef WOLFSSH_CERTS -static const char cannedKeyAlgoNames[] = - "rsa-sha2-256,x509v3-ssh-rsa,ecdsa-sha2-nistp256,x509v3-ecdsa-sha2-nistp256"; -#else -static const char cannedKeyAlgoNames[] = "rsa-sha2-256,ecdsa-sha2-nistp256"; -#endif - -#if 0 -static const char cannedKexAlgoNames[] = -#if !defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256) - "ecdh-nistp256-kyber-512r3-sha256-d00@openquantumsafe.org," -#endif -#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP521) - "ecdh-sha2-nistp521," -#endif -#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP384) - "ecdh-sha2-nistp384," -#endif -#if !defined(WOLFSSH_NO_ECDH_SHA2_NISTP256) - "ecdh-sha2-nistp256," -#endif -#if !defined(WOLFSSH_NO_DH_GEX_SHA256) - "diffie-hellman-group-exchange-sha256," -#endif -#if !defined(WOLFSSH_NO_DH_GROUP14_SHA1) - "diffie-hellman-group14-sha1," -#endif -#if !defined(WOLFSSH_NO_DH_GROUP1_SHA1) - "diffie-hellman-group1-sha1," -#endif - ""; -#endif - - -static const char cannedNoneNames[] = "none"; - -/* -1 for the null, some are -2 for the null and comma */ -static const word32 cannedEncAlgoNamesSz = - (word32)sizeof(cannedEncAlgoNames) - 2; -static const word32 cannedMacAlgoNamesSz = - (word32)sizeof(cannedMacAlgoNames) - 2; -#if 0 -static const word32 cannedKexAlgoNamesSz = - (word32)sizeof(cannedKexAlgoNames) - 2; -#endif -static const word32 cannedNoneNamesSz = - (word32)sizeof(cannedNoneNames) - 1; - -#define KEY_ALGO_SIZE_GUESS 28 - -#ifndef WOLFSSH_NO_SSH_RSA_SHA1 - static const word32 cannedKeyAlgoSshRsaNamesSz = - (word32)sizeof(cannedKeyAlgoSshRsaNames) - 1; -#endif -#ifndef WOLFSSH_NO_RSA_SHA2_256 - static const word32 cannedKeyAlgoRsaSha2_256NamesSz = - (word32)sizeof(cannedKeyAlgoRsaSha2_256Names) - 1; -#endif -#ifndef WOLFSSH_NO_RSA_SHA2_512 - static const word32 cannedKeyAlgoRsaSha2_512NamesSz = - (word32)sizeof(cannedKeyAlgoRsaSha2_512Names) - 1; -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 - static const word32 cannedKeyAlgoEcc256NamesSz = - (word32)sizeof(cannedKeyAlgoEcc256Names) - 1; -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 - static const word32 cannedKeyAlgoEcc384NamesSz = - (word32)sizeof(cannedKeyAlgoEcc384Names) - 1; -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 - static const word32 cannedKeyAlgoEcc521NamesSz = - (word32)sizeof(cannedKeyAlgoEcc521Names) - 1; -#endif -#ifdef WOLFSSH_CERTS -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 - static const word32 cannedKeyAlgoX509Ecc256NamesSz = - (word32)sizeof(cannedKeyAlgoX509Ecc256Names) - 1; -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 - static const word32 cannedKeyAlgoX509Ecc384NamesSz = - (word32)sizeof(cannedKeyAlgoX509Ecc384Names) - 1; -#endif -#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 - static const word32 cannedKeyAlgoX509Ecc521NamesSz = - (word32)sizeof(cannedKeyAlgoX509Ecc521Names) - 1; -#endif -#endif /* WOLFSSH_CERTS */ - -static const word32 cannedKeyAlgoNamesSz = - (word32)sizeof(cannedKeyAlgoNames) - 1; - - -int SendKexInit(WOLFSSH* ssh) -{ - byte* output = NULL; - byte* payload = NULL; - char* kexAlgoNames = NULL; - char* keyAlgoNames = NULL; - const byte* algo = NULL; - word32 algoCount = 0, idx = 0, payloadSz = 0, - kexAlgoNamesSz = 0, keyAlgoNamesSz = 0; - int ret = WS_SUCCESS; - - WLOG(WS_LOG_DEBUG, "Entering SendKexInit()"); + WLOG(WS_LOG_DEBUG, "Entering SendKexInit()"); if (ssh == NULL) ret = WS_BAD_ARGUMENT; @@ -9047,64 +9797,47 @@ int SendKexInit(WOLFSSH* ssh) } if (ret == WS_SUCCESS) { - byte algoList[8]; - word32 algoListSz; - - WMEMCPY(algoList, cannedKexAlgo, cannedKexAlgoSz); - algoListSz = cannedKexAlgoSz; - if (ssh->ctx->side == WOLFSSH_ENDPOINT_CLIENT) { - algoList[cannedKexAlgoSz] = ID_EXTINFO_C; - algoListSz++; - } - - kexAlgoNamesSz = BuildNameList(NULL, 0, algoList, algoListSz) + 1; - kexAlgoNames = (char*)WMALLOC(kexAlgoNamesSz, - ssh->ctx->heap, DYNTYPE_STRING); - if (kexAlgoNames == NULL) { - ret = WS_MEMORY_E; - } - - if (ret == WS_SUCCESS) { - ret = BuildNameList(kexAlgoNames, kexAlgoNamesSz, - algoList, algoListSz); - if (ret > 0) { - kexAlgoNamesSz = (word32)ret; - ret = WS_SUCCESS; + if (!ssh->algoListKey && ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER) { + keyAlgoNamesSz = BuildNameList(NULL, 0, + ssh->ctx->publicKeyAlgo, + ssh->ctx->publicKeyAlgoCount) + + 1; + keyAlgoNames = (char*)WMALLOC(keyAlgoNamesSz, + ssh->ctx->heap, DYNTYPE_STRING); + if (keyAlgoNames) { + ret = BuildNameList(keyAlgoNames, keyAlgoNamesSz, + ssh->ctx->publicKeyAlgo, + ssh->ctx->publicKeyAlgoCount); + if (ret > 0) { + keyAlgoNamesSz = (word32)ret; + ret = WS_SUCCESS; + } + } + else { + ret = WS_MEMORY_E; } } } if (ret == WS_SUCCESS) { - if (ssh->ctx->side == WOLFSSH_ENDPOINT_SERVER) { - algoCount = ssh->ctx->publicKeyAlgoCount; - algo = ssh->ctx->publicKeyAlgo; - } - else { - algoCount = cannedKeyAlgoClientSz; - algo = cannedKeyAlgoClient; - } - keyAlgoNamesSz = BuildNameList(NULL, 0, algo, algoCount) + 1; - keyAlgoNames = (char*)WMALLOC(keyAlgoNamesSz, - ssh->ctx->heap, DYNTYPE_STRING); - if (keyAlgoNames == NULL) { - ret = WS_MEMORY_E; + if (ssh->ctx->side == WOLFSSH_ENDPOINT_CLIENT) { + kexAlgoNamesPlus = ",ext-info-c"; + kexAlgoNamesPlusSz = (word32)WSTRLEN(kexAlgoNamesPlus); } - } - if (ret == WS_SUCCESS) { - ret = BuildNameList(keyAlgoNames, keyAlgoNamesSz, algo, algoCount); - if (ret > 0) { - keyAlgoNamesSz = (word32)ret; - ret = WS_SUCCESS; + kexAlgoNamesSz = AlgoListSz(ssh->algoListKex); + encAlgoNamesSz = AlgoListSz(ssh->algoListCipher); + if (!keyAlgoNames) { + keyAlgoNamesSz = AlgoListSz(ssh->algoListKey); } - } - - if (ret == WS_SUCCESS) { + else { + keyAlgoNamesSz = AlgoListSz(keyAlgoNames); + } + macAlgoNamesSz = AlgoListSz(ssh->algoListMac); + noneNamesSz = AlgoListSz(cannedNoneNames); payloadSz = MSG_ID_SZ + COOKIE_SZ + (LENGTH_SZ * 11) + BOOLEAN_SZ + - kexAlgoNamesSz + keyAlgoNamesSz + - (cannedEncAlgoNamesSz * 2) + - (cannedMacAlgoNamesSz * 2) + - (cannedNoneNamesSz * 2); + + kexAlgoNamesSz + kexAlgoNamesPlusSz + keyAlgoNamesSz + + (encAlgoNamesSz * 2) + (macAlgoNamesSz * 2) + (noneNamesSz * 2); ret = PreparePacket(ssh, payloadSz); } @@ -9124,14 +9857,21 @@ int SendKexInit(WOLFSSH* ssh) idx += COOKIE_SZ; - CopyNameList(output, &idx, kexAlgoNames, kexAlgoNamesSz); - CopyNameList(output, &idx, keyAlgoNames, keyAlgoNamesSz); - CopyNameList(output, &idx, cannedEncAlgoNames, cannedEncAlgoNamesSz); - CopyNameList(output, &idx, cannedEncAlgoNames, cannedEncAlgoNamesSz); - CopyNameList(output, &idx, cannedMacAlgoNames, cannedMacAlgoNamesSz); - CopyNameList(output, &idx, cannedMacAlgoNames, cannedMacAlgoNamesSz); - CopyNameList(output, &idx, cannedNoneNames, cannedNoneNamesSz); - CopyNameList(output, &idx, cannedNoneNames, cannedNoneNamesSz); + CopyNameListPlus(output, &idx, + ssh->algoListKex, kexAlgoNamesSz, + kexAlgoNamesPlus, kexAlgoNamesPlusSz); + if (!keyAlgoNames) { + CopyNameList(output, &idx, ssh->algoListKey, keyAlgoNamesSz); + } + else { + CopyNameList(output, &idx, keyAlgoNames, keyAlgoNamesSz); + } + CopyNameList(output, &idx, ssh->algoListCipher, encAlgoNamesSz); + CopyNameList(output, &idx, ssh->algoListCipher, encAlgoNamesSz); + CopyNameList(output, &idx, ssh->algoListMac, macAlgoNamesSz); + CopyNameList(output, &idx, ssh->algoListMac, macAlgoNamesSz); + CopyNameList(output, &idx, cannedNoneNames, noneNamesSz); + CopyNameList(output, &idx, cannedNoneNames, noneNamesSz); c32toa(0, output + idx); /* Languages - Client To Server (0) */ idx += LENGTH_SZ; c32toa(0, output + idx); /* Languages - Server To Client (0) */ @@ -9159,8 +9899,9 @@ int SendKexInit(WOLFSSH* ssh) } } - WFREE(kexAlgoNames, ssh->ctx->heap, DYNTYPE_STRING); - WFREE(keyAlgoNames, ssh->ctx->heap, DYNTYPE_STRING); + if (keyAlgoNames) { + WFREE(keyAlgoNames, ssh->ctx->heap, DYNTYPE_STRING); + } if (ret == WS_SUCCESS) { /* increase amount to be sent only if BundlePacket will be called */ @@ -9211,6 +9952,18 @@ struct wolfSSH_sigKeyBlockFull { const char *primeName; word32 primeNameSz; } ecc; + +#ifndef WOLFSSH_NO_ED25519 + struct { + ed25519_key key; + word32 keyBlobSz; + const char *keyBlobName; + word32 keyBlobNameSz; + byte q[ED25519_PUB_KEY_SIZE+1]; + word32 qSz; + byte qPad; + } ed; +#endif #endif } sk; }; @@ -9569,6 +10322,58 @@ static int SendKexGetSigningKey(WOLFSSH* ssh, sigKeyBlock_ptr->sk.ecc.qSz); } break; + + #ifndef WOLFSSH_NO_ED25519 + case ID_ED25519: + WLOG(WS_LOG_DEBUG, "Using Ed25519 Host key"); + + /* Decode the user-configured ED25519 private key. */ + sigKeyBlock_ptr->sk.ed.qSz = sizeof(sigKeyBlock_ptr->sk.ed.q); + + ret = wc_ed25519_init(&sigKeyBlock_ptr->sk.ed.key); + + scratch = 0; + if (ret == 0) + ret = wc_Ed25519PrivateKeyDecode(ssh->ctx->privateKey[keyIdx].key, &scratch, &sigKeyBlock_ptr->sk.ed.key, ssh->ctx->privateKey[keyIdx].keySz); + + if (ret == 0) + ret = wc_ed25519_export_public(&sigKeyBlock_ptr->sk.ed.key, + sigKeyBlock_ptr->sk.ed.q, + &sigKeyBlock_ptr->sk.ed.qSz ); + + /* Hash in the length of the public key block. */ + if (ret == 0) { + sigKeyBlock_ptr->sz = (LENGTH_SZ * 2) + + sigKeyBlock_ptr->pubKeyFmtNameSz + + sigKeyBlock_ptr->sk.ed.qSz; + c32toa(sigKeyBlock_ptr->sz, scratchLen); + ret = wc_HashUpdate(hash, hashId, + scratchLen, LENGTH_SZ); + } + /* Hash in the length of the key type string. */ + if (ret == 0) { + c32toa(sigKeyBlock_ptr->pubKeyFmtNameSz, scratchLen); + ret = wc_HashUpdate(hash, hashId, + scratchLen, LENGTH_SZ); + } + /* Hash in the key type string. */ + if (ret == 0) + ret = wc_HashUpdate(hash, hashId, + (byte*)sigKeyBlock_ptr->pubKeyFmtName, + sigKeyBlock_ptr->pubKeyFmtNameSz); + /* Hash in the length of the public key. */ + if (ret == 0) { + c32toa(sigKeyBlock_ptr->sk.ed.qSz, scratchLen); + ret = wc_HashUpdate(hash, hashId, + scratchLen, LENGTH_SZ); + } + /* Hash in the public key. */ + if (ret == 0) + ret = wc_HashUpdate(hash, hashId, + sigKeyBlock_ptr->sk.ed.q, + sigKeyBlock_ptr->sk.ed.qSz); + break; + #endif #endif default: @@ -9725,100 +10530,808 @@ static INLINE byte SigTypeForId(byte id) /* * wolfSSH_RsaVerify * sig - signature to verify - * sigSz - signature to verify size - * digest - encoded digest for verification - * digestSz - encoded digest size + * sigSz - signature size + * encDigest - encoded digest for verification + * encDigestSz - encoded digest size * key - key used to sign and verify signature * heap - allocation heap * loc - calling function for logging + * + * Takes the provided digest of type digestId and converts it to an + * encoded digest. Then verifies the signature, comparing the output + * digest and compares it. */ -int wolfSSH_RsaVerify(byte *sig, word32 sigSz, - const byte* digest, word32 digestSz, +int wolfSSH_RsaVerify(const byte *sig, word32 sigSz, + const byte* encDigest, word32 encDigestSz, RsaKey* key, void* heap, const char* loc) { - byte* check; + byte* checkSig = NULL; + int checkDigestSz; + word32 keySz; int ret = WS_SUCCESS; +#ifdef WOLFSSH_SMALL_STACK + byte* checkDigest = NULL; +#else + byte checkDigest[MAX_ENCODED_SIG_SZ]; +#endif - check = (byte*)WMALLOC(digestSz, heap, DYNTYPE_TEMP); - if (check == NULL) { - ret = WS_MEMORY_E; + keySz = (word32)wc_RsaEncryptSize(key); + + if (ret == WS_SUCCESS) { + checkSig = (byte*)WMALLOC(keySz, heap, DYNTYPE_TEMP); + if (checkSig == NULL) + ret = WS_MEMORY_E; } - else { - int checkSz; +#ifdef WOLFSSH_SMALL_STACK + if (ret == WS_SUCCESS) { + checkDigest = (byte*)WMALLOC(MAX_ENCODED_SIG_SZ, heap, DYNTYPE_TEMP); + if (checkDigest == NULL) + ret = WS_MEMORY_E; + } +#endif + + /* Normalize the peer's signature. Some SSH implementations remove + * leading zeros on the signatures they encode. We need to pad the + * front of the signature to the key size. */ + if (ret == WS_SUCCESS) { + word32 offset; - checkSz = wc_RsaSSL_Verify(sig, sigSz, check, digestSz, key); - if (checkSz < 0 - || (word32)checkSz != digestSz - || WMEMCMP(digest, check, digestSz) != 0) { - WLOG(WS_LOG_DEBUG, "%s: %s", loc, "Bad RSA Sign Verify"); + if (keySz > sigSz) { + offset = keySz - sigSz; + } + else { + sigSz = keySz; + offset = 0; + } + + WMEMSET(checkSig, 0, offset); + WMEMCPY(checkSig + offset, sig, sigSz); + } + + if (ret == WS_SUCCESS) { + volatile int sizeCompare; + volatile int compare; + + checkDigestSz = wc_RsaSSL_Verify(checkSig, keySz, + checkDigest, MAX_ENCODED_SIG_SZ, key); + + sizeCompare = checkDigestSz > 0 && encDigestSz != (word32)checkDigestSz; + compare = ConstantCompare(encDigest, checkDigest, encDigestSz); + + if (checkDigestSz < 0 || sizeCompare || compare) { + WLOG(WS_LOG_DEBUG, "%s: %s", loc, "Bad RSA Verify"); ret = WS_RSA_E; } - ForceZero(check, digestSz); - WFREE(check, heap, DYNTYPE_TEMP); } +#ifdef WOLFSSH_SMALL_STACK + if (checkDigest) + WFREE(checkDigest, heap, DYNTYPE_TEMP); +#endif + if (checkSig) + WFREE(checkSig, heap, DYNTYPE_TEMP); return ret; } #endif /* WOLFSSH_NO_RSA */ -/* SendKexDhReply() - * It is also the funciton used for MSGID_KEXECDH_REPLY. The parameters - * are analogous between the two messages. Where MSGID_KEXDH_REPLY has - * server's public host key (K_S), f, and the signature of H; - * MSGID_KEXECDH_REPLY has K_S, the server'e ephemeral public key (Q_S), - * and the signature of H. This also applies to the GEX version of this. - * H is calculated the same for KEXDH and KEXECDH, and has some exceptions - * for GEXDH. */ -int SendKexDhReply(WOLFSSH* ssh) +/* KeyAgreeDh_server + * hashId - wolfCrypt hash type ID used + * f - peer public key + * fSz - peer public key size + */ +static int KeyAgreeDh_server(WOLFSSH* ssh, byte hashId, byte* f, word32* fSz) +#ifndef WOLFSSH_NO_DH { int ret = WS_SUCCESS; - void *heap = NULL; - byte *f_ptr = NULL, *sig_ptr = NULL; - byte scratchLen[LENGTH_SZ]; - word32 fSz = KEX_F_SIZE; - word32 sigSz = KEX_SIG_SIZE; - byte useEcc = 0; -#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 - byte useEccKyber = 0; - byte sharedSecretHashSz = 0; - byte *sharedSecretHash = NULL; -#endif - byte fPad = 0; - byte kPad = 0; - word32 sigBlockSz = 0; - word32 payloadSz = 0; - byte* output = NULL; - word32 idx = 0; - word32 keyIdx = 0; - byte msgId = MSGID_KEXDH_REPLY; - enum wc_HashType hashId = WC_HASH_TYPE_NONE; - wc_HashAlg* hash = NULL; - struct wolfSSH_sigKeyBlockFull *sigKeyBlock_ptr = NULL; -#ifndef WOLFSSH_SMALL_STACK - byte f_s[KEX_F_SIZE]; - byte sig_s[KEX_SIG_SIZE]; + byte *y_ptr = NULL; + const byte* primeGroup = NULL; + const byte* generator = NULL; + word32 ySz = MAX_KEX_KEY_SZ; + word32 primeGroupSz = 0; + word32 generatorSz = 0; + #ifdef WOLFSSH_SMALL_STACK + DhKey *privKey = (DhKey*)WMALLOC(sizeof(DhKey), ssh->ctx->heap, + DYNTYPE_PRIVKEY); + y_ptr = (byte*)WMALLOC(ySz, ssh->ctx->heap, DYNTYPE_PRIVKEY); + if (privKey == NULL || y_ptr == NULL) + ret = WS_MEMORY_E; + #else + DhKey privKey[1]; + byte y_s[MAX_KEX_KEY_SZ]; + y_ptr = y_s; + #endif - f_ptr = f_s; - sig_ptr = sig_s; -#endif - WLOG(WS_LOG_DEBUG, "Entering SendKexDhReply()"); + WLOG(WS_LOG_DEBUG, "Entering KeyAgreeDh_server()"); + WOLFSSH_UNUSED(hashId); if (ret == WS_SUCCESS) { - if (ssh == NULL || ssh->ctx == NULL || ssh->handshake == NULL) { - ret = WS_BAD_ARGUMENT; + ret = GetDHPrimeGroup(ssh->handshake->kexId, &primeGroup, + &primeGroupSz, &generator, &generatorSz); + + if (ret == WS_SUCCESS) { + ssh->primeGroupSz = primeGroupSz; + ret = wc_InitDhKey(privKey); + } + if (ret == 0) + ret = wc_DhSetKey(privKey, primeGroup, primeGroupSz, + generator, generatorSz); + if (ret == 0) + ret = wc_DhGenerateKeyPair(privKey, ssh->rng, + y_ptr, &ySz, f, fSz); + if (ret == 0) { + PRIVATE_KEY_UNLOCK(); + ret = wc_DhAgree(privKey, ssh->k, &ssh->kSz, y_ptr, ySz, + ssh->handshake->e, ssh->handshake->eSz); + PRIVATE_KEY_LOCK(); } + ForceZero(y_ptr, ySz); + wc_FreeDhKey(privKey); } - - if (ret == WS_SUCCESS) { - heap = ssh->ctx->heap; + #ifdef WOLFSSH_SMALL_STACK + if (y_ptr) + WFREE(y_ptr, ssh->ctx->heap, DYNTYPE_PRIVKEY); + if (privKey) { + WFREE(privKey, ssh->ctx->heap, DYNTYPE_PRIVKEY); } - -#ifdef WOLFSSH_SMALL_STACK - f_ptr = (byte*)WMALLOC(KEX_F_SIZE, heap, DYNTYPE_BUFFER); - sig_ptr = (byte*)WMALLOC(KEX_SIG_SIZE, heap, DYNTYPE_BUFFER); + #endif + WLOG(WS_LOG_DEBUG, "Leaving KeyAgreeDh_server(), ret = %d", ret); + return ret; +} +#else /* WOLFSSH_NO_DH */ +{ + WOLFSSH_UNUSED(ssh); + WOLFSSH_UNUSED(hashId); + WOLFSSH_UNUSED(f); + WOLFSSH_UNUSED(fSz); + return WS_INVALID_ALGO_ID; +} +#endif /* WOLFSSH_NO_DH */ + + +/* KeyAgreeEcdh_server + * hashId - wolfCrypt hash type ID used + * f - peer public key + * fSz - peer public key size + */ +static int KeyAgreeEcdh_server(WOLFSSH* ssh, byte hashId, byte* f, word32* fSz) +#ifndef WOLFSSH_NO_ECDH +{ + int ret = WS_SUCCESS; + void* heap; +#ifdef WOLFSSH_SMALL_STACK + ecc_key *pubKey = NULL, *privKey = NULL; + pubKey = (ecc_key*)WMALLOC(sizeof(ecc_key), heap, + DYNTYPE_PUBKEY); + privKey = (ecc_key*)WMALLOC(sizeof(ecc_key), heap, + DYNTYPE_PRIVKEY); + if (pubKey == NULL || privKey == NULL) { + ret = WS_MEMORY_E; + } +#else + ecc_key pubKey[1]; + ecc_key privKey[1]; +#endif + int primeId; + + WLOG(WS_LOG_DEBUG, "Entering KeyAgreeEcdh_server()"); + WOLFSSH_UNUSED(hashId); + + heap = ssh->ctx->heap; + primeId = wcPrimeForId(ssh->handshake->kexId); + if (primeId == ECC_CURVE_INVALID) + ret = WS_INVALID_PRIME_CURVE; + + if (ret == 0) + ret = wc_ecc_init_ex(pubKey, heap, INVALID_DEVID); + if (ret == 0) + ret = wc_ecc_init_ex(privKey, heap, INVALID_DEVID); +#ifdef HAVE_WC_ECC_SET_RNG + if (ret == 0) + ret = wc_ecc_set_rng(privKey, ssh->rng); +#endif + + if (ret == 0) + ret = wc_ecc_import_x963_ex(ssh->handshake->e, + ssh->handshake->eSz, + pubKey, primeId); + + if (ret == 0) + ret = wc_ecc_make_key_ex(ssh->rng, + wc_ecc_get_curve_size_from_id(primeId), + privKey, primeId); + if (ret == 0) { + PRIVATE_KEY_UNLOCK(); + ret = wc_ecc_export_x963(privKey, f, fSz); + PRIVATE_KEY_LOCK(); + } + if (ret == 0) { + PRIVATE_KEY_UNLOCK(); + ret = wc_ecc_shared_secret(privKey, pubKey, + ssh->k, &ssh->kSz); + PRIVATE_KEY_LOCK(); + } + wc_ecc_free(privKey); + wc_ecc_free(pubKey); +#ifdef WOLFSSH_SMALL_STACK + WFREE(pubKey, heap, DYNTYPE_PUBKEY); + WFREE(privKey, heap, DYNTYPE_PRIVKEY); + pubKey = NULL; + privKey = NULL; +#endif + WLOG(WS_LOG_DEBUG, "Leaving KeyAgreeEcdh_server(), ret = %d", ret); + return ret; +} +#else /* WOLFSSH_NO_ECDH */ +{ + WOLFSSH_UNUSED(ssh); + WOLFSSH_UNUSED(hashId); + WOLFSSH_UNUSED(f); + WOLFSSH_UNUSED(fSz); + return WS_INVALID_ALGO_ID; +} +#endif /* WOLFSSH_NO_ECDH */ + + +/* KeyAgreeCurve25519_server + * hashId - wolfCrypt hash type ID used + * f - peer public key + * fSz - peer public key size + */ +static int KeyAgreeCurve25519_server(WOLFSSH* ssh, byte hashId, + byte* f, word32* fSz) +#ifndef WOLFSSH_NO_CURVE25519_SHA256 +{ + int ret = WS_SUCCESS; + void* heap = ssh->ctx->heap; +#ifdef WOLFSSH_SMALL_STACK + curve25519_key *pubKey = NULL, *privKey = NULL; + pubKey = (curve25519_key*)WMALLOC(sizeof(curve25519_key), + heap, DYNTYPE_PUBKEY); + privKey = (curve25519_key*)WMALLOC(sizeof(curve25519_key), + heap, DYNTYPE_PRIVKEY); + if (pubKey == NULL || privKey == NULL) { + ret = WS_MEMORY_E; + } +#else + curve25519_key pubKey[1], privKey[1]; +#endif + + WLOG(WS_LOG_DEBUG, "Entering KeyAgreeCurve25519_server()"); + WOLFSSH_UNUSED(hashId); + + if (ret == 0) + ret = wc_curve25519_init_ex(pubKey, heap, INVALID_DEVID); + if (ret == 0) + ret = wc_curve25519_init_ex(privKey, heap, INVALID_DEVID); + if (ret == 0) + ret = wc_curve25519_check_public(ssh->handshake->e, + ssh->handshake->eSz, EC25519_LITTLE_ENDIAN); + if (ret == 0) + ret = wc_curve25519_import_public_ex( + ssh->handshake->e, ssh->handshake->eSz, + pubKey, EC25519_LITTLE_ENDIAN); + + if (ret == 0) + ret = wc_curve25519_make_key(ssh->rng, CURVE25519_KEYSIZE, privKey); + + if (ret == 0) { + PRIVATE_KEY_UNLOCK(); + ret = wc_curve25519_export_public_ex(privKey, + f, fSz, EC25519_LITTLE_ENDIAN); + PRIVATE_KEY_LOCK(); + } + + if (ret == 0) { + PRIVATE_KEY_UNLOCK(); + ret = wc_curve25519_shared_secret_ex(privKey, pubKey, + ssh->k, &ssh->kSz, EC25519_LITTLE_ENDIAN); + PRIVATE_KEY_LOCK(); + } + wc_curve25519_free(privKey); + wc_curve25519_free(pubKey); +#ifdef WOLFSSH_SMALL_STACK + WFREE(pubKey, heap, DYNTYPE_PUBKEY); + WFREE(privKey, heap, DYNTYPE_PRIVKEY); + pubKey = NULL; + privKey = NULL; +#endif + WLOG(WS_LOG_DEBUG, "Leaving KeyAgreeCurve25519_server(), ret = %d", ret); + return ret; +} +#else /* WOLFSSH_NO_CURVE25519_SHA256 */ +{ + WOLFSSH_UNUSED(ssh); + WOLFSSH_UNUSED(hashId); + WOLFSSH_UNUSED(f); + WOLFSSH_UNUSED(fSz); + return WS_INVALID_ALGO_ID; +} +#endif /* WOLFSSH_NO_CURVE25519_SHA256 */ + + +/* KeyAgreeEcdhKyber1_server + * hashId - wolfCrypt hash type ID used + * f - peer public key + * fSz - peer public key size + * + * This is a hybrid KEM. In this case, I need to generate my ECC + * keypair, send the public one, use the private one to generate + * the shared secret, use the post-quantum public key to + * generate and encapsulate the shared secret and send the + * ciphertext. + */ +static int KeyAgreeEcdhKyber1_server(WOLFSSH* ssh, byte hashId, + byte* f, word32* fSz) +#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 +{ + int ret = WS_SUCCESS; + byte sharedSecretHashSz = 0; + byte *sharedSecretHash = NULL; + OQS_KEM* kem = NULL; + ecc_key* pubKey = NULL; + ecc_key* privKey = NULL; + int primeId; +#ifndef WOLFSSH_SMALL_STACK + ecc_key eccKeys[2]; +#endif + + WLOG(WS_LOG_DEBUG, "Entering KeyAgreeEcdhKyber1_server()"); + +#ifdef WOLFSSH_SMALL_STACK + pubKey = (ecc_key*)WMALLOC(sizeof(ecc_key), + ssh->ctx->heap, DYNTYPE_PUBKEY); + privKey = (ecc_key*)WMALLOC(sizeof(ecc_key), + ssh->ctx->heap, DYNTYPE_PRIVKEY); + if (pubKey == NULL || privKey == NULL) { + ret = WS_MEMORY_E; + } +#else + pubKey = &eccKeys[0]; + privKey = &eccKeys[1]; +#endif + + if (ret == 0) { + XMEMSET(pubKey, 0, sizeof(*pubKey)); + XMEMSET(privKey, 0, sizeof(*privKey)); + + primeId = wcPrimeForId(ssh->handshake->kexId); + if (primeId == ECC_CURVE_INVALID) + ret = WS_INVALID_PRIME_CURVE; + } + + if (ret == 0) { + kem = OQS_KEM_new(OQS_KEM_alg_kyber_512); + if (kem == NULL) { + ret = WS_MEMORY_E; + } + } + + if ((ret == 0) && + (ssh->handshake->eSz <= (word32)kem->length_public_key)) { + ret = WS_BUFFER_E; + } + + if (ret == 0) { + if (OQS_KEM_encaps(kem, f, ssh->k, ssh->handshake->e) != OQS_SUCCESS) { + ret = WS_PUBKEY_REJECTED_E; + WLOG(WS_LOG_ERROR, + "Generate ECC-kyber (encap) shared secret failed, %d", + ret); + *fSz = 0; + ssh->kSz = 0; + } + } + + if (ret == 0) { + *fSz -= kem->length_ciphertext; + ssh->kSz -= kem->length_shared_secret; + } + else { + *fSz = 0; + ssh->kSz = 0; + WLOG(WS_LOG_ERROR, + "Generate ECC-kyber (encap) shared secret failed, %d", + ret); + } + + if (ret == 0) { + ret = wc_ecc_init_ex(pubKey, ssh->ctx->heap, INVALID_DEVID); + } + if (ret == 0) { + ret = wc_ecc_init_ex(privKey, ssh->ctx->heap, INVALID_DEVID); + } +#ifdef HAVE_WC_ECC_SET_RNG + if (ret == 0) { + ret = wc_ecc_set_rng(privKey, ssh->rng); + } +#endif + if (ret == 0) { + ret = wc_ecc_import_x963_ex( + ssh->handshake->e + kem->length_public_key, + ssh->handshake->eSz - (word32)kem->length_public_key, + pubKey, primeId); + } + if (ret == 0) { + ret = wc_ecc_make_key_ex(ssh->rng, + wc_ecc_get_curve_size_from_id(primeId), + privKey, primeId); + } + if (ret == 0) { + PRIVATE_KEY_UNLOCK(); + ret = wc_ecc_export_x963(privKey, f + kem->length_ciphertext, fSz); + PRIVATE_KEY_LOCK(); + *fSz += kem->length_ciphertext; + } + if (ret == 0) { + word32 tmp_kSz = ssh->kSz; + PRIVATE_KEY_UNLOCK(); + ret = wc_ecc_shared_secret(privKey, pubKey, + ssh->k + kem->length_shared_secret, &tmp_kSz); + PRIVATE_KEY_LOCK(); + ssh->kSz = (word32)kem->length_shared_secret + tmp_kSz; + } + wc_ecc_free(privKey); + wc_ecc_free(pubKey); +#ifdef WOLFSSH_SMALL_STACK + if (pubKey) + WFREE(pubKey, ssh->ctx->heap, DYNTYPE_PUBKEY); + if (privKey) + WFREE(privKey, ssh->ctx->heap, DYNTYPE_PUBKEY); +#endif + if (kem != NULL) { + OQS_KEM_free(kem); + kem = NULL; + } + + /* Replace the concatenated shared secrets with the hash. That + * will become the new shared secret.*/ + if (ret == 0) { + sharedSecretHashSz = wc_HashGetDigestSize(hashId); + sharedSecretHash = (byte *)WMALLOC(sharedSecretHashSz, + ssh->ctx->heap, DYNTYPE_PRIVKEY); + if (sharedSecretHash == NULL) { + ret = WS_MEMORY_E; + } + } + if (ret == 0) { + ret = wc_Hash(hashId, ssh->k, ssh->kSz, sharedSecretHash, + sharedSecretHashSz); + } + if (ret == 0) { + XMEMCPY(ssh->k, sharedSecretHash, sharedSecretHashSz); + ssh->kSz = sharedSecretHashSz; + } + + if (sharedSecretHash) { + ForceZero(sharedSecretHash, sharedSecretHashSz); + WFREE(sharedSecretHash, ssh->ctx->heap, DYNTYPE_PRIVKEY); + } + + WLOG(WS_LOG_DEBUG, "Leaving KeyAgreeEcdhKyber1_server(), ret = %d", ret); + return ret; +} +#else /* WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 */ +{ + WOLFSSH_UNUSED(ssh); + WOLFSSH_UNUSED(hashId); + WOLFSSH_UNUSED(f); + WOLFSSH_UNUSED(fSz); + return WS_INVALID_ALGO_ID; +} +#endif /* WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 */ + + +static int SignHRsa(WOLFSSH* ssh, byte* sig, word32* sigSz, + struct wolfSSH_sigKeyBlockFull *sigKey) +#ifndef WOLFSSH_NO_RSA +{ + void* heap; + byte* encSig = NULL; + byte digest[WC_MAX_DIGEST_SIZE]; + word32 digestSz = (word32)sizeof(digest); + word32 encSigSz; + int ret = WS_SUCCESS; + enum wc_HashType hashId; +#ifndef WOLFSSH_SMALL_STACK + byte encSig_s[MAX_ENCODED_SIG_SZ]; +#endif + + WLOG(WS_LOG_DEBUG, "Entering SignHRsa()"); + + heap = ssh->ctx->heap; +#ifdef WOLFSSH_SMALL_STACK + encSig = (byte*)WMALLOC(MAX_ENCODED_SIG_SZ, heap, DYNTYPE_TEMP); + if (encSig == NULL) { + ret = WS_MEMORY_E; + } +#else + encSig = encSig_s; +#endif + + if (ret == WS_SUCCESS) { + hashId = HashForId(ssh->handshake->pubKeyId); + digestSz = wc_HashGetDigestSize(hashId); + + ret = wc_Hash(hashId, ssh->h, ssh->hSz, digest, digestSz); + if (ret != 0) { + ret = WS_CRYPTO_FAILED; + } + } + + if (ret == WS_SUCCESS) { + ret = wc_EncodeSignature(encSig, digest, digestSz, + wc_HashGetOID(hashId)); + if (ret <= 0) { + WLOG(WS_LOG_DEBUG, "SignHRsa: Bad Encode Sig"); + ret = WS_CRYPTO_FAILED; + } + else { + encSigSz = (word32)ret; + ret = WS_SUCCESS; + } + } + + if (ret == WS_SUCCESS) { + WLOG(WS_LOG_INFO, "Signing hash with %s.", + IdToName(ssh->handshake->pubKeyId)); + ret = wc_RsaSSL_Sign(encSig, encSigSz, sig, + KEX_SIG_SIZE, &sigKey->sk.rsa.key, + ssh->rng); + if (ret <= 0) { + WLOG(WS_LOG_DEBUG, "SignHRsa: Bad RSA Sign"); + ret = WS_RSA_E; + } + else { + *sigSz = (word32)ret; + ret = WS_SUCCESS; + } + } + + if (ret == WS_SUCCESS) { + ret = wolfSSH_RsaVerify(sig, *sigSz, encSig, encSigSz, + &sigKey->sk.rsa.key, heap, "SignHRsa"); + } + + #ifdef WOLFSSH_SMALL_STACK + if (encSig != NULL) + WFREE(encSig, heap, DYNTYPE_TEMP); + #endif + WLOG(WS_LOG_DEBUG, "Leaving SignHRsa(), ret = %d", ret); + return ret; +} +#else /* WOLFSSH_NO_RSA */ +{ + WOLFSSH_UNUSED(ssh); + WOLFSSH_UNUSED(sig); + WOLFSSH_UNUSED(sigSz); + WOLFSSH_UNUSED(sigKey); + return WS_INVALID_ALGO_ID; +} +#endif /* WOLFSSH_NO_RSA */ + + +static int SignHEcdsa(WOLFSSH* ssh, byte* sig, word32* sigSz, + struct wolfSSH_sigKeyBlockFull *sigKey) +#ifndef WOLFSSH_NO_ECDSA +{ +#ifdef WOLFSSH_SMALL_STACK + void* heap = NULL; +#endif + byte *r = NULL, *s = NULL; + byte digest[WC_MAX_DIGEST_SIZE]; + word32 digestSz = (word32)sizeof(digest); + int ret = WS_SUCCESS; + enum wc_HashType hashId; + word32 rSz = MAX_ECC_BYTES + ECC_MAX_PAD_SZ, + sSz = MAX_ECC_BYTES + ECC_MAX_PAD_SZ; + byte rPad, sPad; +#ifndef WOLFSSH_SMALL_STACK + byte r_s[MAX_ECC_BYTES + ECC_MAX_PAD_SZ]; + byte s_s[MAX_ECC_BYTES + ECC_MAX_PAD_SZ]; +#endif + + WLOG(WS_LOG_DEBUG, "Entering SignHEcdsa()"); + + hashId = HashForId(ssh->handshake->pubKeyId); + digestSz = wc_HashGetDigestSize(hashId); + + ret = wc_Hash(hashId, ssh->h, ssh->hSz, digest, digestSz); + if (ret != 0) { + ret = WS_CRYPTO_FAILED; + } + + if (ret == WS_SUCCESS) { + WLOG(WS_LOG_INFO, "Signing hash with %s.", + IdToName(ssh->handshake->pubKeyId)); + ret = wc_ecc_sign_hash(digest, digestSz, sig, sigSz, ssh->rng, + &sigKey->sk.ecc.key); + if (ret != MP_OKAY) { + WLOG(WS_LOG_DEBUG, "SignHEcdsa: Bad ECDSA Sign"); + ret = WS_ECC_E; + } + else { + ret = WS_SUCCESS; + } + } + + if (ret == WS_SUCCESS) { +#ifdef WOLFSSH_SMALL_STACK + heap = ssh->ctx->heap; + r = (byte*)WMALLOC(rSz, heap, DYNTYPE_BUFFER); + s = (byte*)WMALLOC(sSz, heap, DYNTYPE_BUFFER); + if (r == NULL || s == NULL) { + ret = WS_MEMORY_E; + } +#else + r = r_s; + s = s_s; +#endif + } + + if (ret == WS_SUCCESS) { + ret = wc_ecc_sig_to_rs(sig, *sigSz, r, &rSz, s, &sSz); + if (ret != 0) { + ret = WS_ECC_E; + } + } + + if (ret == WS_SUCCESS) { + int idx = 0; + rPad = (r[0] & 0x80) ? 1 : 0; + sPad = (s[0] & 0x80) ? 1 : 0; + *sigSz = (LENGTH_SZ * 2) + rSz + rPad + sSz + sPad; + + c32toa(rSz + rPad, sig + idx); + idx += LENGTH_SZ; + if (rPad) + sig[idx++] = 0; + WMEMCPY(sig + idx, r, rSz); + idx += rSz; + c32toa(sSz + sPad, sig + idx); + idx += LENGTH_SZ; + if (sPad) + sig[idx++] = 0; + WMEMCPY(sig + idx, s, sSz); + } + + #ifdef WOLFSSH_SMALL_STACK + if (r) + WFREE(r, heap, DYNTYPE_BUFFER); + if (s) + WFREE(s, heap, DYNTYPE_BUFFER); + #endif + + WLOG(WS_LOG_DEBUG, "Leaving SignHEcdsa(), ret = %d", ret); + return ret; +} +#else /* WOLFSSH_NO_ECDSA */ +{ + WOLFSSH_UNUSED(ssh); + WOLFSSH_UNUSED(sig); + WOLFSSH_UNUSED(sigSz); + WOLFSSH_UNUSED(sigKey); + return WS_INVALID_ALGO_ID; +} +#endif /* WOLFSSH_NO_ECDSA */ + + +static int SignHEd25519(WOLFSSH* ssh, byte* sig, word32* sigSz, + struct wolfSSH_sigKeyBlockFull *sigKey) +#ifndef WOLFSSH_NO_ED25519 +{ + int ret; + + WLOG(WS_LOG_DEBUG, "Entering SignHEd25519()"); + + ret = wc_ed25519_sign_msg(ssh->h, ssh->hSz, sig, sigSz, &sigKey->sk.ed.key); + if (ret != 0) { + WLOG(WS_LOG_DEBUG, + "SignHEd5519: Bad ED25519 Sign (error: %d)", ret); + ret = WS_ECC_E; + } + + WLOG(WS_LOG_DEBUG, "Leaving SignHEd25519(), ret = %d", ret); + return ret; +} +#else /* WOLFSSH_NO_ED25519 */ +{ + WOLFSSH_UNUSED(ssh); + WOLFSSH_UNUSED(sig); + WOLFSSH_UNUSED(sigSz); + WOLFSSH_UNUSED(sigKey); + return WS_INVALID_ALGO_ID; +} +#endif /* WOLFSSH_NO_ED25519 */ + + +static int SignH(WOLFSSH* ssh, byte* sig, word32* sigSz, + struct wolfSSH_sigKeyBlockFull *sigKey) +{ + int ret; + + switch (sigKey->pubKeyId) { + case ID_SSH_RSA: + case ID_X509V3_SSH_RSA: + case ID_RSA_SHA2_256: + case ID_RSA_SHA2_512: + ret = SignHRsa(ssh, sig, sigSz, sigKey); + break; + case ID_ECDSA_SHA2_NISTP256: + case ID_ECDSA_SHA2_NISTP384: + case ID_ECDSA_SHA2_NISTP521: + case ID_X509V3_ECDSA_SHA2_NISTP256: + case ID_X509V3_ECDSA_SHA2_NISTP384: + case ID_X509V3_ECDSA_SHA2_NISTP521: + ret = SignHEcdsa(ssh, sig, sigSz, sigKey); + break; + case ID_ED25519: + ret = SignHEd25519(ssh, sig, sigSz, sigKey); + break; + default: + ret = WS_INVALID_ALGO_ID; + } + + return ret; +} + + +/* SendKexDhReply() + * It is also the funciton used for MSGID_KEXECDH_REPLY. The parameters + * are analogous between the two messages. Where MSGID_KEXDH_REPLY has + * server's public host key (K_S), f, and the signature of H; + * MSGID_KEXECDH_REPLY has K_S, the server'e ephemeral public key (Q_S), + * and the signature of H. This also applies to the GEX version of this. + * H is calculated the same for KEXDH and KEXECDH, and has some exceptions + * for GEXDH. */ +int SendKexDhReply(WOLFSSH* ssh) +{ + int ret = WS_SUCCESS; + void *heap = NULL; + byte *f_ptr = NULL, *sig_ptr = NULL; + byte scratchLen[LENGTH_SZ]; + word32 fSz = KEX_F_SIZE; + word32 sigSz = KEX_SIG_SIZE; + byte fPad = 0; + byte kPad = 0; + word32 sigBlockSz = 0; + word32 payloadSz = 0; + byte* output = NULL; + word32 idx = 0; + word32 keyIdx = 0; + enum wc_HashType hashId = WC_HASH_TYPE_NONE; + wc_HashAlg* hash = NULL; + struct wolfSSH_sigKeyBlockFull *sigKeyBlock_ptr = NULL; +#ifndef WOLFSSH_SMALL_STACK + byte f_s[KEX_F_SIZE]; + byte sig_s[KEX_SIG_SIZE]; +#endif + byte msgId = 0; + byte useDh = 0; + byte useEcc = 0; + byte useCurve25519 = 0; + byte useEccKyber = 0; + + WLOG(WS_LOG_DEBUG, "Entering SendKexDhReply()"); + + if (ret == WS_SUCCESS) { + if (ssh == NULL || ssh->ctx == NULL || ssh->handshake == NULL) { + ret = WS_BAD_ARGUMENT; + } + } + + if (ret == WS_SUCCESS) { + heap = ssh->ctx->heap; + } + +#ifdef WOLFSSH_SMALL_STACK + f_ptr = (byte*)WMALLOC(KEX_F_SIZE, heap, DYNTYPE_BUFFER); + sig_ptr = (byte*)WMALLOC(KEX_SIG_SIZE, heap, DYNTYPE_BUFFER); if (f_ptr == NULL || sig_ptr == NULL) ret = WS_MEMORY_E; +#else + f_ptr = f_s; + sig_ptr = sig_s; #endif sigKeyBlock_ptr = (struct wolfSSH_sigKeyBlockFull*)WMALLOC( @@ -9848,6 +11361,24 @@ int SendKexDhReply(WOLFSSH* ssh) (word32)WSTRLEN(sigKeyBlock_ptr->pubKeyFmtName); switch (ssh->handshake->kexId) { +#ifndef WOLFSSH_NO_DH_GROUP1_SHA1 + case ID_DH_GROUP1_SHA1: + useDh = 1; + msgId = MSGID_KEXDH_REPLY; + break; +#endif +#ifndef WOLFSSH_NO_DH_GROUP14_SHA1 + case ID_DH_GROUP14_SHA1: + useDh = 1; + msgId = MSGID_KEXDH_REPLY; + break; +#endif +#ifndef WOLFSSH_NO_DH_GEX_SHA256 + case ID_DH_GEX_SHA256: + useDh = 1; + msgId = MSGID_KEXDH_GEX_REPLY; + break; +#endif #ifndef WOLFSSH_NO_ECDH_SHA2_NISTP256 case ID_ECDH_SHA2_NISTP256: useEcc = 1; @@ -9866,313 +11397,69 @@ int SendKexDhReply(WOLFSSH* ssh) msgId = MSGID_KEXDH_REPLY; break; #endif +#ifndef WOLFSSH_NO_CURVE25519_SHA256 + case ID_CURVE25519_SHA256: + useCurve25519 = 1; + msgId = MSGID_KEXDH_REPLY; + break; +#endif #ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 case ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256: useEccKyber = 1; /* Only support level 1 for now. */ msgId = MSGID_KEXKEM_REPLY; break; #endif + default: + ret = WS_INVALID_ALGO_ID; } + } + if (ret == WS_SUCCESS) { hash = &ssh->handshake->kexHash; hashId = (enum wc_HashType)ssh->handshake->kexHashId; - } - if (ret == WS_SUCCESS) { for (keyIdx = 0; keyIdx < ssh->ctx->privateKeyCount; keyIdx++) { - if (ssh->ctx->privateKey[keyIdx].publicKeyFmt - == sigKeyBlock_ptr->pubKeyFmtId) { - break; - } - } - if (keyIdx == ssh->ctx->privateKeyCount) { - ret = WS_INVALID_ALGO_ID; - } - } - - /* At this point, the exchange hash, H, includes items V_C, V_S, I_C, - * and I_S. Next add K_S, the server's public host key. K_S will - * either be RSA or ECDSA public key blob. */ - if (ret == WS_SUCCESS) { - ret = SendKexGetSigningKey(ssh, sigKeyBlock_ptr, hashId, hash, keyIdx); - } - - if (ret == WS_SUCCESS) { - /* reset size here because a previous shared secret could potentially be - * smaller by a byte than usual and cause buffer issues with re-key */ - if (ret == 0) - ssh->kSz = MAX_KEX_KEY_SZ; - - /* Make the server's DH f-value and the shared secret K. */ - /* Or make the server's ECDH private value, and the shared secret K. */ - if (ret == 0) { - if (!useEcc -#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 - && !useEccKyber -#endif - ) { -#ifndef WOLFSSH_NO_DH - byte *y_ptr = NULL; - const byte* primeGroup = NULL; - const byte* generator = NULL; - word32 ySz = MAX_KEX_KEY_SZ; - word32 primeGroupSz = 0; - word32 generatorSz = 0; - #ifdef WOLFSSH_SMALL_STACK - DhKey *privKey = (DhKey*)WMALLOC(sizeof(DhKey), heap, - DYNTYPE_PRIVKEY); - y_ptr = (byte*)WMALLOC(ySz, heap, DYNTYPE_PRIVKEY); - if (privKey == NULL || y_ptr == NULL) - ret = WS_MEMORY_E; - #else - DhKey privKey[1]; - byte y_s[MAX_KEX_KEY_SZ]; - y_ptr = y_s; - #endif - if (ret == WS_SUCCESS) { - ret = GetDHPrimeGroup(ssh->handshake->kexId, &primeGroup, - &primeGroupSz, &generator, &generatorSz); - #ifndef WOLFSSH_NO_DH_GEX_SHA256 - if (ssh->handshake->kexId == ID_DH_GEX_SHA256) - msgId = MSGID_KEXDH_GEX_REPLY; - #endif - - if (ret == WS_SUCCESS) { - ret = wc_InitDhKey(privKey); - } - if (ret == 0) - ret = wc_DhSetKey(privKey, primeGroup, primeGroupSz, - generator, generatorSz); - if (ret == 0) - ret = wc_DhGenerateKeyPair(privKey, ssh->rng, - y_ptr, &ySz, f_ptr, &fSz); - if (ret == 0) { - PRIVATE_KEY_UNLOCK(); - ret = wc_DhAgree(privKey, ssh->k, &ssh->kSz, y_ptr, ySz, - ssh->handshake->e, ssh->handshake->eSz); - PRIVATE_KEY_LOCK(); - } - ForceZero(y_ptr, ySz); - wc_FreeDhKey(privKey); - } - #ifdef WOLFSSH_SMALL_STACK - if (y_ptr) - WFREE(y_ptr, heap, DYNTYPE_PRIVKEY); - if (privKey) { - WFREE(privKey, heap, DYNTYPE_PRIVKEY); - } - #endif -#endif /* ! WOLFSSH_NO_DH */ - } - else if (useEcc) { -#if !defined(WOLFSSH_NO_ECDH) - #ifdef WOLFSSH_SMALL_STACK - ecc_key *pubKey = NULL, *privKey = NULL; - pubKey = (ecc_key*)WMALLOC(sizeof(ecc_key), heap, - DYNTYPE_PUBKEY); - privKey = (ecc_key*)WMALLOC(sizeof(ecc_key), heap, - DYNTYPE_PRIVKEY); - if (pubKey == NULL || privKey == NULL) { - ret = WS_MEMORY_E; - } - #else - ecc_key pubKey[1]; - ecc_key privKey[1]; - #endif - int primeId; - - primeId = wcPrimeForId(ssh->handshake->kexId); - if (primeId == ECC_CURVE_INVALID) - ret = WS_INVALID_PRIME_CURVE; - - if (ret == 0) - ret = wc_ecc_init_ex(pubKey, heap, INVALID_DEVID); - if (ret == 0) - ret = wc_ecc_init_ex(privKey, heap, INVALID_DEVID); -#ifdef HAVE_WC_ECC_SET_RNG - if (ret == 0) - ret = wc_ecc_set_rng(privKey, ssh->rng); -#endif - - if (ret == 0) - ret = wc_ecc_import_x963_ex(ssh->handshake->e, - ssh->handshake->eSz, - pubKey, primeId); - - if (ret == 0) - ret = wc_ecc_make_key_ex(ssh->rng, - wc_ecc_get_curve_size_from_id(primeId), - privKey, primeId); - if (ret == 0) { - PRIVATE_KEY_UNLOCK(); - ret = wc_ecc_export_x963(privKey, f_ptr, &fSz); - PRIVATE_KEY_LOCK(); - } - if (ret == 0) { - PRIVATE_KEY_UNLOCK(); - ret = wc_ecc_shared_secret(privKey, pubKey, - ssh->k, &ssh->kSz); - PRIVATE_KEY_LOCK(); - } - wc_ecc_free(privKey); - wc_ecc_free(pubKey); - #ifdef WOLFSSH_SMALL_STACK - WFREE(pubKey, heap, DYNTYPE_PUBKEY); - WFREE(privKey, heap, DYNTYPE_PRIVKEY); - pubKey = NULL; - privKey = NULL; - #endif -#endif /* !defined(WOLFSSH_NO_ECDH) */ - } -#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 - else if (useEccKyber) { - /* This is a hybrid KEM. In this case, I need to generate my ECC - * keypair, send the public one, use the private one to generate - * the shared secret, use the post-quantum public key to - * generate and encapsulate the shared secret and send the - * ciphertext. */ - OQS_KEM* kem = NULL; - int primeId; - ret = 0; - #ifdef WOLFSSH_SMALL_STACK - ecc_key *pubKey = NULL, *privKey = NULL; - pubKey = (ecc_key*)WMALLOC(sizeof(ecc_key), heap, - DYNTYPE_PUBKEY); - privKey = (ecc_key*)WMALLOC(sizeof(ecc_key), heap, - DYNTYPE_PRIVKEY); - if (pubKey == NULL || privKey == NULL) { - ret = WS_MEMORY_E; - } - #else - ecc_key pubKey[1]; - ecc_key privKey[1]; - #endif - - if (ret == 0) { - XMEMSET(pubKey, 0, sizeof(*pubKey)); - XMEMSET(privKey, 0, sizeof(*privKey)); - - primeId = wcPrimeForId(ssh->handshake->kexId); - if (primeId == ECC_CURVE_INVALID) - ret = WS_INVALID_PRIME_CURVE; - } - - if (ret == 0) { - kem = OQS_KEM_new(OQS_KEM_alg_kyber_512); - if (kem == NULL) { - ret = WS_INVALID_ALGO_ID; - } - } - - if ((ret == 0) && - (ssh->handshake->eSz <= (word32)kem->length_public_key)) { - ret = WS_BUFFER_E; - } - - if (ret == 0) { - if (OQS_KEM_encaps(kem, f_ptr, ssh->k, - ssh->handshake->e) != OQS_SUCCESS) { - ret = WS_PUBKEY_REJECTED_E; - } - } - - if (ret == 0) { - fSz -= kem->length_ciphertext; - ssh->kSz -= kem->length_shared_secret; - } - else { - fSz = 0; - ssh->kSz = 0; - WLOG(WS_LOG_ERROR, - "Generate ECC-kyber (encap) shared secret failed, %d", - ret); - } - - if (ret == 0) { - ret = wc_ecc_init_ex(pubKey, heap, INVALID_DEVID); - } - if (ret == 0) { - ret = wc_ecc_init_ex(privKey, heap, INVALID_DEVID); - } -#ifdef HAVE_WC_ECC_SET_RNG - if (ret == 0) { - ret = wc_ecc_set_rng(privKey, ssh->rng); - } -#endif - if (ret == 0) { - ret = wc_ecc_import_x963_ex( - ssh->handshake->e + kem->length_public_key, - ssh->handshake->eSz - (word32)kem->length_public_key, - pubKey, primeId); - } - if (ret == 0) { - ret = wc_ecc_make_key_ex(ssh->rng, - wc_ecc_get_curve_size_from_id(primeId), - privKey, primeId); - } - if (ret == 0) { - PRIVATE_KEY_UNLOCK(); - ret = wc_ecc_export_x963(privKey, - f_ptr + kem->length_ciphertext, &fSz); - fSz += kem->length_ciphertext; - PRIVATE_KEY_LOCK(); - } - if (ret == 0) { - word32 tmp_kSz = ssh->kSz; - PRIVATE_KEY_UNLOCK(); - ret = wc_ecc_shared_secret(privKey, pubKey, - ssh->k + kem->length_shared_secret, &tmp_kSz); - PRIVATE_KEY_LOCK(); - ssh->kSz = (word32)kem->length_shared_secret + tmp_kSz; - } - wc_ecc_free(privKey); - wc_ecc_free(pubKey); - #ifdef WOLFSSH_SMALL_STACK - WFREE(pubKey, heap, DYNTYPE_PUBKEY); - WFREE(privKey, heap, DYNTYPE_PRIVKEY); - pubKey = NULL; - privKey = NULL; - #endif - if (kem != NULL) { - OQS_KEM_free(kem); - kem = NULL; - } + if (ssh->ctx->privateKey[keyIdx].publicKeyFmt + == sigKeyBlock_ptr->pubKeyFmtId) { + break; + } + } + if (keyIdx == ssh->ctx->privateKeyCount) { + ret = WS_INVALID_ALGO_ID; + } + } - /* Replace the concatenated shared secrets with the hash. That - * will become the new shared secret.*/ - if (ret == 0) { - sharedSecretHashSz = wc_HashGetDigestSize(hashId); - sharedSecretHash = (byte *)WMALLOC(sharedSecretHashSz, heap, - DYNTYPE_PRIVKEY); - if (sharedSecretHash == NULL) { - ret = WS_MEMORY_E; - } - } - if (ret == 0) { - ret = wc_Hash(hashId, ssh->k, ssh->kSz, sharedSecretHash, - sharedSecretHashSz); - } - if (ret == 0) { - XMEMCPY(ssh->k, sharedSecretHash, sharedSecretHashSz); - ssh->kSz = sharedSecretHashSz; - } + /* At this point, the exchange hash, H, includes items V_C, V_S, I_C, + * and I_S. Next add K_S, the server's public host key. K_S will + * either be RSA or ECDSA public key blob. */ + if (ret == WS_SUCCESS) { + ret = SendKexGetSigningKey(ssh, sigKeyBlock_ptr, hashId, hash, keyIdx); + } + + if (ret == WS_SUCCESS) { + /* reset size here because a previous shared secret could potentially be + * smaller by a byte than usual and cause buffer issues with re-key */ + ssh->kSz = MAX_KEX_KEY_SZ; - WFREE(sharedSecretHash, heap, DYNTYPE_PRIVKEY); - sharedSecretHash = NULL; + /* Make the server's DH f-value and the shared secret K. */ + /* Or make the server's ECDH private value, and the shared secret K. */ + if (ret == 0) { + if (useDh) { + ret = KeyAgreeDh_server(ssh, hashId, f_ptr, &fSz); } -#endif /* !WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 */ - else { - /* This should never happen */ - ret = WS_ERROR; + else if (useEcc) { + ret = KeyAgreeEcdh_server(ssh, hashId, f_ptr, &fSz); + } + if (useCurve25519) { + ret = KeyAgreeCurve25519_server(ssh, hashId, f_ptr, &fSz); + } + else if (useEccKyber) { + ret = KeyAgreeEcdhKyber1_server(ssh, hashId, f_ptr, &fSz); } } /* Hash in the server's DH f-value. */ - if (ret == 0 -#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 - && !useEccKyber -#endif - ) { + if (ret == 0 && (useDh || useEcc)) { ret = CreateMpint(f_ptr, &fSz, &fPad); } if (ret == 0) { @@ -10188,11 +11475,7 @@ int SendKexDhReply(WOLFSSH* ssh) } /* Hash in the shared secret K. */ - if (ret == 0 -#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 - && !useEccKyber -#endif - ) { + if (ret == 0 && !useEccKyber) { ret = CreateMpint(ssh->k, &ssh->kSz, &kPad); } if (ret == 0) { @@ -10233,142 +11516,7 @@ int SendKexDhReply(WOLFSSH* ssh) /* Sign h with the server's private key. */ if (ret == WS_SUCCESS) { - wc_HashAlg digestHash; - byte digest[WC_MAX_DIGEST_SIZE]; - enum wc_HashType sigHashId; - - sigHashId = HashForId(ssh->handshake->pubKeyId); - ret = wc_HashInit(&digestHash, sigHashId); - if (ret == 0) - ret = HashUpdate(&digestHash, sigHashId, ssh->h, ssh->hSz); - if (ret == 0) - ret = wc_HashFinal(&digestHash, sigHashId, digest); - if (ret != 0) - ret = WS_CRYPTO_FAILED; - wc_HashFree(&digestHash, sigHashId); - - if (ret == WS_SUCCESS) { - if (sigKeyBlock_ptr->pubKeyId == ID_SSH_RSA - #ifdef WOLFSSH_CERTS - || sigKeyBlock_ptr->pubKeyId == ID_X509V3_SSH_RSA - #endif - || sigKeyBlock_ptr->pubKeyId == ID_RSA_SHA2_256 - || sigKeyBlock_ptr->pubKeyId == ID_RSA_SHA2_512 - ) { -#ifndef WOLFSSH_NO_RSA - word32 encSigSz; - #ifdef WOLFSSH_SMALL_STACK - byte *encSig = (byte*)WMALLOC(MAX_ENCODED_SIG_SZ, heap, - DYNTYPE_TEMP); - if (encSig == NULL) { - ret = WS_MEMORY_E; - } - - if (ret == WS_SUCCESS) - #else - byte encSig[MAX_ENCODED_SIG_SZ]; - #endif - { - encSigSz = wc_EncodeSignature(encSig, digest, - wc_HashGetDigestSize(sigHashId), - wc_HashGetOID(sigHashId)); - if (encSigSz == 0) { - WLOG(WS_LOG_DEBUG, "SendKexDhReply: Bad Encode Sig"); - ret = WS_CRYPTO_FAILED; - } - else { - WLOG(WS_LOG_INFO, "Signing hash with %s.", - IdToName(ssh->handshake->pubKeyId)); - sigSz = wc_RsaSSL_Sign(encSig, encSigSz, sig_ptr, - KEX_SIG_SIZE, &sigKeyBlock_ptr->sk.rsa.key, - ssh->rng); - if (sigSz <= 0) { - WLOG(WS_LOG_DEBUG, "SendKexDhReply: Bad RSA Sign"); - ret = WS_RSA_E; - } - else { - ret = wolfSSH_RsaVerify(sig_ptr, sigSz, - encSig, encSigSz, - &sigKeyBlock_ptr->sk.rsa.key, - heap, "SendKexDhReply"); - } - } - #ifdef WOLFSSH_SMALL_STACK - WFREE(encSig, heap, DYNTYPE_TEMP); - #endif - } -#endif /* WOLFSSH_NO_RSA */ - } - else if (sigKeyBlock_ptr->pubKeyId == ID_ECDSA_SHA2_NISTP256 - || sigKeyBlock_ptr->pubKeyId == ID_ECDSA_SHA2_NISTP384 - || sigKeyBlock_ptr->pubKeyId == ID_ECDSA_SHA2_NISTP521 -#ifdef WOLFSSH_CERTS - || sigKeyBlock_ptr->pubKeyId == ID_X509V3_ECDSA_SHA2_NISTP256 - || sigKeyBlock_ptr->pubKeyId == ID_X509V3_ECDSA_SHA2_NISTP384 - || sigKeyBlock_ptr->pubKeyId == ID_X509V3_ECDSA_SHA2_NISTP521 -#endif - ) { -#ifndef WOLFSSH_NO_ECDSA - WLOG(WS_LOG_INFO, "Signing hash with %s.", - IdToName(ssh->handshake->pubKeyId)); - sigSz = KEX_SIG_SIZE; - ret = wc_ecc_sign_hash(digest, wc_HashGetDigestSize(sigHashId), - sig_ptr, &sigSz, - ssh->rng, &sigKeyBlock_ptr->sk.ecc.key); - if (ret != MP_OKAY) { - WLOG(WS_LOG_DEBUG, "SendKexDhReply: Bad ECDSA Sign"); - ret = WS_ECC_E; - } - else { - byte *r_ptr = NULL, *s_ptr = NULL; - word32 rSz = MAX_ECC_BYTES + ECC_MAX_PAD_SZ; - word32 sSz = MAX_ECC_BYTES + ECC_MAX_PAD_SZ; - byte rPad; - byte sPad; - - #ifdef WOLFSSH_SMALL_STACK - r_ptr = (byte*)WMALLOC(rSz, heap, DYNTYPE_BUFFER); - s_ptr = (byte*)WMALLOC(sSz, heap, DYNTYPE_BUFFER); - if (r_ptr == NULL || s_ptr == NULL) - ret = WS_MEMORY_E; - #else - byte r_s[MAX_ECC_BYTES + ECC_MAX_PAD_SZ]; - byte s_s[MAX_ECC_BYTES + ECC_MAX_PAD_SZ]; - r_ptr = r_s; - s_ptr = s_s; - #endif - if (ret == WS_SUCCESS) { - ret = wc_ecc_sig_to_rs(sig_ptr, sigSz, - r_ptr, &rSz, s_ptr, &sSz); - } - if (ret == 0) { - idx = 0; - rPad = (r_ptr[0] & 0x80) ? 1 : 0; - sPad = (s_ptr[0] & 0x80) ? 1 : 0; - sigSz = (LENGTH_SZ * 2) + rSz + rPad + sSz + sPad; - - c32toa(rSz + rPad, sig_ptr + idx); - idx += LENGTH_SZ; - if (rPad) - sig_ptr[idx++] = 0; - WMEMCPY(sig_ptr + idx, r_ptr, rSz); - idx += rSz; - c32toa(sSz + sPad, sig_ptr + idx); - idx += LENGTH_SZ; - if (sPad) - sig_ptr[idx++] = 0; - WMEMCPY(sig_ptr + idx, s_ptr, sSz); - } - #ifdef WOLFSSH_SMALL_STACK - if (r_ptr) - WFREE(r_ptr, heap, DYNTYPE_BUFFER); - if (s_ptr) - WFREE(s_ptr, heap, DYNTYPE_BUFFER); - #endif - } -#endif /* WOLFSSH_NO_ECDSA */ - } - } + ret = SignH(ssh, sig_ptr, &sigSz, sigKeyBlock_ptr); } if (sigKeyBlock_ptr != NULL) { @@ -10382,16 +11530,18 @@ int SendKexDhReply(WOLFSSH* ssh) || sigKeyBlock_ptr->pubKeyFmtId == ID_ECDSA_SHA2_NISTP521) { #ifndef WOLFSSH_NO_ECDSA wc_ecc_free(&sigKeyBlock_ptr->sk.ecc.key); +#endif + } + else if (sigKeyBlock_ptr->pubKeyId == ID_ED25519) { +#if !defined(WOLFSSH_NO_ED25519) + wc_ed25519_free(&sigKeyBlock_ptr->sk.ed.key); #endif } } if (ret == WS_SUCCESS) { - int doKeyPadding = 1; -#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 - doKeyPadding = !useEccKyber; -#endif - ret = GenerateKeys(ssh, hashId, doKeyPadding); + /* If we aren't using EccKyber, use padding. */ + ret = GenerateKeys(ssh, hashId, !useEccKyber); } /* Get the buffer, copy the packet data, once f is laid into the buffer, @@ -10409,21 +11559,22 @@ int SendKexDhReply(WOLFSSH* ssh) output[idx++] = msgId; + /* Copy the key block size into the buffer */ + c32toa(sigKeyBlock_ptr->sz, output + idx); + idx += LENGTH_SZ; + + /* Copy the key name into the buffer */ + c32toa(sigKeyBlock_ptr->pubKeyFmtNameSz, output + idx); + idx += LENGTH_SZ; + WMEMCPY(output + idx, sigKeyBlock_ptr->pubKeyFmtName, sigKeyBlock_ptr->pubKeyFmtNameSz); + idx += sigKeyBlock_ptr->pubKeyFmtNameSz; + /* add host public key */ switch (sigKeyBlock_ptr->pubKeyFmtId) { case ID_SSH_RSA: { #ifndef WOLFSSH_NO_RSA /* Copy the rsaKeyBlock into the buffer. */ - c32toa(sigKeyBlock_ptr->sz, output + idx); - idx += LENGTH_SZ; - c32toa(sigKeyBlock_ptr->pubKeyFmtNameSz, output + idx); - idx += LENGTH_SZ; - WMEMCPY(output + idx, - sigKeyBlock_ptr->pubKeyFmtName, - sigKeyBlock_ptr->pubKeyFmtNameSz); - idx += sigKeyBlock_ptr->pubKeyFmtNameSz; - c32toa(sigKeyBlock_ptr->sk.rsa.eSz + sigKeyBlock_ptr->sk.rsa.ePad, output + idx); idx += LENGTH_SZ; @@ -10448,15 +11599,6 @@ int SendKexDhReply(WOLFSSH* ssh) { #ifndef WOLFSSH_NO_ECDSA /* Copy the ecdsaKeyBlock into the buffer. */ - c32toa(sigKeyBlock_ptr->sz, output + idx); - idx += LENGTH_SZ; - c32toa(sigKeyBlock_ptr->pubKeyFmtNameSz, output + idx); - idx += LENGTH_SZ; - WMEMCPY(output + idx, - sigKeyBlock_ptr->pubKeyFmtName, - sigKeyBlock_ptr->pubKeyFmtNameSz); - idx += sigKeyBlock_ptr->pubKeyFmtNameSz; - c32toa(sigKeyBlock_ptr->sk.ecc.primeNameSz, output + idx); idx += LENGTH_SZ; WMEMCPY(output + idx, sigKeyBlock_ptr->sk.ecc.primeName, @@ -10471,6 +11613,19 @@ int SendKexDhReply(WOLFSSH* ssh) } break; + case ID_ED25519: + { +#if !defined(WOLFSSH_NO_ED25519) + /* Copy the edKeyBlock into the buffer. */ + c32toa(sigKeyBlock_ptr->sk.ed.qSz, output + idx); + idx += LENGTH_SZ; + WMEMCPY(output + idx, sigKeyBlock_ptr->sk.ed.q, + sigKeyBlock_ptr->sk.ed.qSz); + idx += sigKeyBlock_ptr->sk.ed.qSz; +#endif + } + break; + #ifdef WOLFSSH_CERTS case ID_X509V3_SSH_RSA: case ID_X509V3_ECDSA_SHA2_NISTP256: @@ -10762,6 +11917,7 @@ int SendKexDhInit(WOLFSSH* ssh) switch (ssh->handshake->kexId) { #ifndef WOLFSSH_NO_DH_GROUP1_SHA1 case ID_DH_GROUP1_SHA1: + ssh->handshake->useDh = 1; primeGroup = dhPrimeGroup1; primeGroupSz = dhPrimeGroup1Sz; generator = dhGenerator; @@ -10770,6 +11926,7 @@ int SendKexDhInit(WOLFSSH* ssh) #endif #ifndef WOLFSSH_NO_DH_GROUP14_SHA1 case ID_DH_GROUP14_SHA1: + ssh->handshake->useDh = 1; primeGroup = dhPrimeGroup14; primeGroupSz = dhPrimeGroup14Sz; generator = dhGenerator; @@ -10778,6 +11935,7 @@ int SendKexDhInit(WOLFSSH* ssh) #endif #ifndef WOLFSSH_NO_DH_GEX_SHA256 case ID_DH_GEX_SHA256: + ssh->handshake->useDh = 1; primeGroup = ssh->handshake->primeGroup; primeGroupSz = ssh->handshake->primeGroupSz; generator = ssh->handshake->generator; @@ -10803,6 +11961,12 @@ int SendKexDhInit(WOLFSSH* ssh) msgId = MSGID_KEXECDH_INIT; break; #endif +#ifndef WOLFSSH_NO_CURVE25519_SHA256 + case ID_CURVE25519_SHA256: + ssh->handshake->useCurve25519 = 1; + msgId = MSGID_KEXECDH_INIT; + break; +#endif #ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 case ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256: /* Only support level 1 for now. */ @@ -10821,6 +11985,9 @@ int SendKexDhInit(WOLFSSH* ssh) #ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 && !ssh->handshake->useEccKyber #endif +#ifndef WOLFSSH_NO_CURVE25519_SHA256 + && !ssh->handshake->useCurve25519 +#endif ) { #ifndef WOLFSSH_NO_DH DhKey* privKey = &ssh->handshake->privKey.dh; @@ -10836,6 +12003,23 @@ int SendKexDhInit(WOLFSSH* ssh) e, &eSz); #endif } +#ifndef WOLFSSH_NO_CURVE25519_SHA256 + else if (ssh->handshake->useCurve25519) { + curve25519_key* privKey = &ssh->handshake->privKey.curve25519; + if (ret == 0) + ret = wc_curve25519_init_ex(privKey, ssh->ctx->heap, + INVALID_DEVID); + if (ret == 0) + ret = wc_curve25519_make_key(ssh->rng, CURVE25519_KEYSIZE, + privKey); + if (ret == 0) { + PRIVATE_KEY_UNLOCK(); + ret = wc_curve25519_export_public_ex(privKey, e, &eSz, + EC25519_LITTLE_ENDIAN); + PRIVATE_KEY_LOCK(); + } + } +#endif /* ! WOLFSSH_NO_CURVE25519_SHA256 */ else if (ssh->handshake->useEcc #ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 || ssh->handshake->useEccKyber @@ -10907,6 +12091,10 @@ int SendKexDhInit(WOLFSSH* ssh) #ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 && !ssh->handshake->useEccKyber #endif +#ifndef WOLFSSH_NO_CURVE25519_SHA256 + && !ssh->handshake->useCurve25519 +#endif + ) { ret = CreateMpint(e, &eSz, &ePad); } @@ -11243,12 +12431,14 @@ int SendServiceAccept(WOLFSSH* ssh, byte serviceId) #define WS_EXTINFO_EXTENSION_COUNT 1 static const char serverSigAlgsName[] = "server-sig-algs"; -static word32 serverSigAlgsNameSz = (word32)sizeof(serverSigAlgsName) - 1; + int SendExtInfo(WOLFSSH* ssh) { byte* output; word32 idx; + word32 keyAlgoNamesSz = 0; + word32 serverSigAlgsNameSz = 0; int ret = WS_SUCCESS; WLOG(WS_LOG_DEBUG, "Entering SendExtInfo()"); @@ -11258,8 +12448,10 @@ int SendExtInfo(WOLFSSH* ssh) } if (ret == WS_SUCCESS) { + keyAlgoNamesSz = AlgoListSz(ssh->algoListKeyAccepted); + serverSigAlgsNameSz = AlgoListSz(serverSigAlgsName); ret = PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ + (LENGTH_SZ * 2) - + serverSigAlgsNameSz + cannedKeyAlgoNamesSz); + + serverSigAlgsNameSz + keyAlgoNamesSz); } if (ret == WS_SUCCESS) { @@ -11275,10 +12467,10 @@ int SendExtInfo(WOLFSSH* ssh) WMEMCPY(output + idx, serverSigAlgsName, serverSigAlgsNameSz); idx += serverSigAlgsNameSz; - c32toa(cannedKeyAlgoNamesSz, output + idx); + c32toa(keyAlgoNamesSz, output + idx); idx += LENGTH_SZ; - WMEMCPY(output + idx, cannedKeyAlgoNames, cannedKeyAlgoNamesSz); - idx += cannedKeyAlgoNamesSz; + WMEMCPY(output + idx, ssh->algoListKeyAccepted, keyAlgoNamesSz); + idx += keyAlgoNamesSz; ssh->outputBuffer.length = idx; @@ -11475,19 +12667,16 @@ static int BuildUserAuthRequestRsa(WOLFSSH* ssh, #ifndef WOLFSSH_NO_SSH_RSA_SHA1 case ID_SSH_RSA: names = cannedKeyAlgoSshRsaNames; - namesSz = cannedKeyAlgoSshRsaNamesSz; break; #endif #ifndef WOLFSSH_NO_RSA_SHA2_256 case ID_RSA_SHA2_256: names = cannedKeyAlgoRsaSha2_256Names; - namesSz = cannedKeyAlgoRsaSha2_256NamesSz; break; #endif #ifndef WOLFSSH_NO_RSA_SHA2_512 case ID_RSA_SHA2_512: names = cannedKeyAlgoRsaSha2_512Names; - namesSz = cannedKeyAlgoRsaSha2_512NamesSz; break; #endif default: @@ -11496,6 +12685,7 @@ static int BuildUserAuthRequestRsa(WOLFSSH* ssh, } if (ret == WS_SUCCESS) { + namesSz = (word32)WSTRLEN(names); c32toa(keySig->sigSz + namesSz + LENGTH_SZ * 2, output + begin); begin += LENGTH_SZ; c32toa(namesSz, output + begin); @@ -11909,19 +13099,16 @@ static int BuildUserAuthRequestEcc(WOLFSSH* ssh, #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 case ID_ECDSA_SHA2_NISTP256: names = cannedKeyAlgoEcc256Names; - namesSz = cannedKeyAlgoEcc256NamesSz; break; #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 case ID_ECDSA_SHA2_NISTP384: names = cannedKeyAlgoEcc384Names; - namesSz = cannedKeyAlgoEcc384NamesSz; break; #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 case ID_ECDSA_SHA2_NISTP521: names = cannedKeyAlgoEcc521Names; - namesSz = cannedKeyAlgoEcc521NamesSz; break; #endif default: @@ -11930,6 +13117,8 @@ static int BuildUserAuthRequestEcc(WOLFSSH* ssh, } if (ret == WS_SUCCESS) { + namesSz = (word32)WSTRLEN(names); + c32toa(rSz + rPad + sSz + sPad + namesSz + LENGTH_SZ * 4, output + begin); begin += LENGTH_SZ; @@ -12153,37 +13342,31 @@ static int BuildUserAuthRequestEccCert(WOLFSSH* ssh, #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 case ID_ECDSA_SHA2_NISTP256: names = cannedKeyAlgoEcc256Names; - namesSz = cannedKeyAlgoEcc256NamesSz; break; #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 case ID_ECDSA_SHA2_NISTP384: names = cannedKeyAlgoEcc384Names; - namesSz = cannedKeyAlgoEcc384NamesSz; break; #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 case ID_ECDSA_SHA2_NISTP521: names = cannedKeyAlgoEcc521Names; - namesSz = cannedKeyAlgoEcc521NamesSz; break; #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 case ID_X509V3_ECDSA_SHA2_NISTP256: names = cannedKeyAlgoX509Ecc256Names; - namesSz = cannedKeyAlgoX509Ecc256NamesSz; break; #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP384 case ID_X509V3_ECDSA_SHA2_NISTP384: names = cannedKeyAlgoX509Ecc384Names; - namesSz = cannedKeyAlgoX509Ecc384NamesSz; break; #endif #ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP521 case ID_X509V3_ECDSA_SHA2_NISTP521: names = cannedKeyAlgoX509Ecc521Names; - namesSz = cannedKeyAlgoX509Ecc521NamesSz; break; #endif default: @@ -12192,6 +13375,8 @@ static int BuildUserAuthRequestEccCert(WOLFSSH* ssh, } if (ret == WS_SUCCESS) { + namesSz = (word32)WSTRLEN(names); + c32toa(rSz + rPad + sSz + sPad + namesSz+ LENGTH_SZ * 4, output + begin); begin += LENGTH_SZ; @@ -12242,7 +13427,168 @@ static int BuildUserAuthRequestEccCert(WOLFSSH* ssh, #endif /* WOLFSSH_NO_ECDSA */ -#if !defined(WOLFSSH_NO_RSA) || !defined(WOLFSSH_NO_ECDSA) +#ifndef WOLFSSH_NO_ED25519 + +static int PrepareUserAuthRequestEd25519(WOLFSSH* ssh, word32* payloadSz, + const WS_UserAuthData* authData, WS_KeySignature* keySig) +{ + int ret = WS_SUCCESS; + + WLOG(WS_LOG_DEBUG, "Entering PrepareUserAuthRequestEd25519()"); + if (ssh == NULL || payloadSz == NULL || authData == NULL || keySig == NULL) + ret = WS_BAD_ARGUMENT; + + if (ret == WS_SUCCESS) + ret = wc_ed25519_init_ex(&keySig->ks.ed25519.key, + keySig->heap, INVALID_DEVID); + + if (ret == 0) { + word32 idx = 0; + #ifdef WOLFSSH_AGENT + if (ssh->agentEnabled) { + /* XXX: Pending */ + } + else + #endif + { + ret = GetOpenSshKey(keySig, + authData->sf.publicKey.privateKey, + authData->sf.publicKey.privateKeySz, &idx); + } + } + + if (ret == WS_SUCCESS) { + if (authData->sf.publicKey.hasSignature) { + int sigSz = wc_ed25519_sig_size(&keySig->ks.ed25519.key); + + if (sigSz >= 0) { + *payloadSz += (LENGTH_SZ * 3) + (word32)sigSz + + authData->sf.publicKey.publicKeyTypeSz; + keySig->sigSz = sigSz; + } + else + ret = sigSz; + } + } + + WLOG(WS_LOG_DEBUG, + "Leaving PrepareUserAuthRequestEd25519(), ret = %d", ret); + return ret; +} + + +static int BuildUserAuthRequestEd25519(WOLFSSH* ssh, + byte* output, word32* idx, + const WS_UserAuthData* authData, + const byte* sigStart, word32 sigStartIdx, + WS_KeySignature* keySig) +{ + word32 begin; + int ret = WS_SUCCESS; + byte* sig; + word32 sigSz = ED25519_SIG_SIZE; + byte* checkData = NULL; + word32 checkDataSz = 0; +#ifndef WOLFSSH_SMALL_STACK + byte sig_s[ED25519_SIG_SIZE]; +#endif + + WLOG(WS_LOG_DEBUG, "Entering BuildUserAuthRequestEd25519()"); + if (ssh == NULL || output == NULL || idx == NULL || authData == NULL || + sigStart == NULL || keySig == NULL) { + ret = WS_BAD_ARGUMENT; + return ret; + } + +#ifdef WOLFSSH_SMALL_STACK + sig = (byte*)WMALLOC(sigSz, keySig->heap, DYNTYPE_BUFFER); + if (sig == NULL) + ret = WS_MEMORY_E; +#else + sig = sig_s; +#endif + + begin = *idx; + + if (ret == WS_SUCCESS) { + checkDataSz = LENGTH_SZ + ssh->sessionIdSz + (begin - sigStartIdx); + checkData = (byte*)WMALLOC(checkDataSz, keySig->heap, DYNTYPE_TEMP); + if (checkData == NULL) + ret = WS_MEMORY_E; + } + + if (ret == WS_SUCCESS) { + word32 i = 0; + + c32toa(ssh->sessionIdSz, checkData + i); + i += LENGTH_SZ; + WMEMCPY(checkData + i, ssh->sessionId, ssh->sessionIdSz); + i += ssh->sessionIdSz; + WMEMCPY(checkData + i, sigStart, begin - sigStartIdx); + } + + #ifdef WOLFSSH_AGENT + if (ssh->agentEnabled) { + /* XXX: Pending */ + } + else + #endif + { + if (ret == WS_SUCCESS) { + WLOG(WS_LOG_INFO, "Signing with Ed25519."); + ret = wc_ed25519_sign_msg(checkData, checkDataSz, + sig, &sigSz, &keySig->ks.ed25519.key); + + if (ret != WS_SUCCESS) { + WLOG(WS_LOG_DEBUG, "SUAR: Bad ED25519 Sign"); + ret = WS_ED25519_E; + } + } + + if (ret == WS_SUCCESS) { + const char* name = cannedKeyAlgoEd25519Name; + word32 nameSz = (word32)WSTRLEN(name); + + c32toa(LENGTH_SZ * 2 + nameSz + sigSz, output + begin); + begin += LENGTH_SZ; + + c32toa(nameSz, output + begin); + begin += LENGTH_SZ; + + WMEMCPY(output + begin, name, nameSz); + begin += nameSz; + + c32toa(sigSz, output + begin); + begin += LENGTH_SZ; + + WMEMCPY(output + begin, sig, sigSz); + begin += sigSz; + } + } + + if (ret == WS_SUCCESS) + *idx = begin; + + if (checkData != NULL) { + ForceZero(checkData, checkDataSz); + WFREE(checkData, keySig->heap, DYNTYPE_TEMP); + } + +#ifdef WOLFSSH_SMALL_STACK + if (sig) + WFREE(sig, keySig->heap, DYNTYPE_BUFFER); +#endif + + WLOG(WS_LOG_DEBUG, + "Leaving BuildUserAuthRequestEd25519(), ret = %d", ret); + return ret; +} + +#endif /* WOLFSSH_NO_ED25519 */ + + +#if !defined(WOLFSSH_NO_RSA) || !defined(WOLFSSH_NO_ECDSA) \ + || !defined(WOLFSSH_NO_ED25519) static int PrepareUserAuthRequestPublicKey(WOLFSSH* ssh, word32* payloadSz, const WS_UserAuthData* authData, WS_KeySignature* keySig) { @@ -12268,7 +13614,8 @@ static int PrepareUserAuthRequestPublicKey(WOLFSSH* ssh, word32* payloadSz, #ifndef WOLFSSH_NO_RSA_SHA2_256 algoId[algoIdSz++] = ID_RSA_SHA2_256; #endif - #ifndef WOLFSSH_NO_SSH_RSA_SHA1 + #if !defined(WOLFSSH_NO_SSH_RSA_SHA1) \ + && defined(WOLFSSH_NO_SHA1_SOFT_DISABLE) algoId[algoIdSz++] = ID_SSH_RSA; #endif } @@ -12280,7 +13627,7 @@ static int PrepareUserAuthRequestPublicKey(WOLFSSH* ssh, word32* payloadSz, matchId = MatchIdLists(WOLFSSH_ENDPOINT_CLIENT, algoId, algoIdSz, ssh->peerSigId, ssh->peerSigIdSz); if (matchId == ID_UNKNOWN) { - ret = WS_MATCH_KEX_ALGO_E; + ret = WS_MATCH_KEY_ALGO_E; } keySig->keySigId = matchId; keySig->name = IdToName(matchId); @@ -12325,6 +13672,12 @@ static int PrepareUserAuthRequestPublicKey(WOLFSSH* ssh, word32* payloadSz, break; #endif #endif + #ifndef WOLFSSH_NO_ED25519 + case ID_ED25519: + ret = PrepareUserAuthRequestEd25519(ssh, + payloadSz, authData, keySig); + break; + #endif default: ret = WS_INVALID_ALGO_ID; } @@ -12434,6 +13787,21 @@ static int BuildUserAuthRequestPublicKey(WOLFSSH* ssh, break; #endif #endif + #ifndef WOLFSSH_NO_ED25519 + case ID_ED25519: + c32toa(pk->publicKeyTypeSz, output + begin); + begin += LENGTH_SZ; + WMEMCPY(output + begin, + pk->publicKeyType, pk->publicKeyTypeSz); + begin += pk->publicKeyTypeSz; + c32toa(pk->publicKeySz, output + begin); + begin += LENGTH_SZ; + WMEMCPY(output + begin, pk->publicKey, pk->publicKeySz); + begin += pk->publicKeySz; + ret = BuildUserAuthRequestEd25519(ssh, output, &begin, + authData, sigStart, sigStartIdx, keySig); + break; + #endif default: ret = WS_INVALID_ALGO_ID; } @@ -12486,6 +13854,7 @@ int SendUserAuthRequest(WOLFSSH* ssh, byte authType, int addSig) if (ret == WS_SUCCESS) { WMEMSET(keySig_ptr, 0, sizeof(WS_KeySignature)); keySig_ptr->keySigId = ID_NONE; + keySig_ptr->heap = ssh->ctx->heap; if (ssh->ctx->userAuthCb != NULL) { WLOG(WS_LOG_DEBUG, "SUAR: Calling the userauth callback"); @@ -12655,7 +14024,7 @@ int SendUserAuthFailure(WOLFSSH* ssh, byte partialSuccess) byte* output; word32 idx; int ret = WS_SUCCESS; - int authSz; + int authSz = 0; char authStr[MAX_AUTH_STRING]; WLOG(WS_LOG_DEBUG, "Entering SendUserAuthFailure()"); @@ -13178,7 +14547,7 @@ int SendChannelEow(WOLFSSH* ssh, word32 peerChannelId) byte* output; const char* str = "eow@openssh.com"; word32 idx; - word32 strSz; + word32 strSz = 0; int ret = WS_SUCCESS; WOLFSSH_CHANNEL* channel = NULL; @@ -13235,7 +14604,7 @@ int SendChannelExit(WOLFSSH* ssh, word32 peerChannelId, int status) byte* output; const char* str = "exit-status"; word32 idx; - word32 strSz; + word32 strSz = 0; int ret = WS_SUCCESS; WOLFSSH_CHANNEL* channel = NULL; diff --git a/src/io.c b/src/io.c index a3e6af1cd..fb25ec37d 100644 --- a/src/io.c +++ b/src/io.c @@ -1,6 +1,6 @@ /* io.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/src/keygen.c b/src/keygen.c index 46b0431ee..2fb4b3a98 100644 --- a/src/keygen.c +++ b/src/keygen.c @@ -1,6 +1,6 @@ /* keygen.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/src/log.c b/src/log.c index 2f66d5a9c..2c96c5d9d 100644 --- a/src/log.c +++ b/src/log.c @@ -1,6 +1,6 @@ /* log.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/src/misc.c b/src/misc.c index f78eb72a3..5e4579b8e 100644 --- a/src/misc.c +++ b/src/misc.c @@ -1,6 +1,6 @@ /* misc.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/src/port.c b/src/port.c index 035019080..b38d498a1 100644 --- a/src/port.c +++ b/src/port.c @@ -1,6 +1,6 @@ /* port.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -476,7 +476,8 @@ int WS_DeleteFileA(const char* fileName, void* heap) #endif /* USE_WINDOWS_API WOLFSSH_SFTP WOLFSSH_SCP */ -#if defined(WOLFSSH_ZEPHYR) && (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) +#if !defined(NO_FILESYSTEM) && \ + defined(WOLFSSH_ZEPHYR) && (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) int wssh_z_fstat(const char *p, struct fs_dirent *b) { diff --git a/src/ssh.c b/src/ssh.c index 99edfd898..2f7def5fb 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -1,6 +1,6 @@ /* ssh.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -75,7 +75,8 @@ int wolfSSH_Init(void) #ifdef WC_RNG_SEED_CB wc_SetSeed_Cb(wc_GenerateSeed); #endif -#if defined(WOLFSSH_ZEPHYR) && (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) +#if !defined(NO_FILESYSTEM) && defined(WOLFSSH_ZEPHYR) && \ + (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) if (wssh_z_fds_init() != 0) ret = WS_CRYPTO_FAILED; #endif @@ -93,7 +94,8 @@ int wolfSSH_Cleanup(void) if (wolfCrypt_Cleanup() != 0) ret = WS_CRYPTO_FAILED; -#if defined(WOLFSSH_ZEPHYR) && (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) +#if !defined(NO_FILESYSTEM) && defined(WOLFSSH_ZEPHYR) && \ + (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) if (wssh_z_fds_cleanup() != 0) ret = WS_CRYPTO_FAILED; #endif @@ -416,7 +418,7 @@ int wolfSSH_accept(WOLFSSH* ssh) return WS_BAD_ARGUMENT; /* clear want read/writes for retry */ - if (ssh->error == WS_WANT_READ || ssh->error == WS_WANT_WRITE) + if (ssh->error == WS_WANT_READ || ssh->error == WS_WANT_WRITE || ssh->error == WS_AUTH_PENDING) ssh->error = 0; if (ssh->error != 0) { @@ -1002,7 +1004,7 @@ int wolfSSH_shutdown(WOLFSSH* ssh) if (ssh != NULL && ssh->channelList == NULL) { WLOG(WS_LOG_DEBUG, "channel list was already removed"); - ret = WS_SUCCESS; + ret = WS_CHANNEL_CLOSED; } WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_shutdown(), ret = %d", ret); @@ -1691,7 +1693,7 @@ static int DoAsn1Key(const byte* in, word32 inSz, byte** out, ret = WS_SUCCESS; } else { - WLOG(WS_LOG_DEBUG, "unable to identify key"); + WLOG(WS_LOG_DEBUG, "Unable to identify ASN.1 key"); if (*out == NULL) { WFREE(newKey, heap, DYNTYPE_PRIVKEY); } @@ -1748,7 +1750,7 @@ static int DoPemKey(const byte* in, word32 inSz, byte** out, ret = WS_SUCCESS; } else { - WLOG(WS_LOG_DEBUG, "unable to identify key"); + WLOG(WS_LOG_DEBUG, "Unable to identify PEM key"); if (*out == NULL) { WFREE(newKey, heap, DYNTYPE_PRIVKEY); } @@ -1804,7 +1806,7 @@ static int DoOpenSshKey(const byte* in, word32 inSz, byte** out, ret = WS_SUCCESS; } else { - WLOG(WS_LOG_DEBUG, "unable to identify key"); + WLOG(WS_LOG_DEBUG, "Unable to identify key"); if (*out == NULL) { WFREE(newKey, heap, DYNTYPE_PRIVKEY); } @@ -1899,18 +1901,15 @@ int wolfSSH_ReadKey_file(const char* name, ret = WS_BAD_FILE_E; } else { - if (WSTRNSTR((const char*)in, - "ssh-rsa", inSz) == (const char*)in || - WSTRNSTR((const char*)in, - "ecdsa-sha2-nistp", inSz) == (const char*)in) { + if (WSTRNSTR((const char*)in, "ssh-rsa", inSz) == (const char*)in + || WSTRNSTR((const char*)in, + "ecdsa-sha2-nistp", inSz) == (const char*)in + || WSTRNSTR((const char*)in, + "ssh-ed25519", inSz) == (const char*)in) { *isPrivate = 0; format = WOLFSSH_FORMAT_SSH; in[inSz] = 0; } -#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; @@ -1939,6 +1938,296 @@ int wolfSSH_ReadKey_file(const char* name, #endif + +int wolfSSH_CTX_SetAlgoListKex(WOLFSSH_CTX* ctx, const char* list) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx) { + ctx->algoListKex = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_CTX_GetAlgoListKex(WOLFSSH_CTX* ctx) +{ + const char* list = NULL; + + if (ctx) { + list = ctx->algoListKex; + } + + return list; +} + + +int wolfSSH_SetAlgoListKex(WOLFSSH* ssh, const char* list) +{ + int ret = WS_SSH_NULL_E; + + if (ssh) { + ssh->algoListKex = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_GetAlgoListKex(WOLFSSH* ssh) +{ + const char* list = NULL; + + if (ssh) { + list = ssh->algoListKex; + } + + return list; +} + + +int wolfSSH_CTX_SetAlgoListKey(WOLFSSH_CTX* ctx, const char* list) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx) { + ctx->algoListKey = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_CTX_GetAlgoListKey(WOLFSSH_CTX* ctx) +{ + const char* list = NULL; + + if (ctx) { + list = ctx->algoListKey; + } + + return list; +} + + +int wolfSSH_SetAlgoListKey(WOLFSSH* ssh, const char* list) +{ + int ret = WS_SSH_NULL_E; + + if (ssh) { + ssh->algoListKey = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_GetAlgoListKey(WOLFSSH* ssh) +{ + const char* list = NULL; + + if (ssh) { + list = ssh->algoListKey; + } + + return list; +} + + +int wolfSSH_CTX_SetAlgoListCipher(WOLFSSH_CTX* ctx, const char* list) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx) { + ctx->algoListCipher = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_CTX_GetAlgoListCipher(WOLFSSH_CTX* ctx) +{ + const char* list = NULL; + + if (ctx) { + list = ctx->algoListCipher; + } + + return list; +} + + +int wolfSSH_SetAlgoListCipher(WOLFSSH* ssh, const char* list) +{ + int ret = WS_SSH_NULL_E; + + if (ssh) { + ssh->algoListCipher = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_GetAlgoListCipher(WOLFSSH* ssh) +{ + const char* list = NULL; + + if (ssh) { + list = ssh->algoListCipher; + } + + return list; +} + + +int wolfSSH_CTX_SetAlgoListMac(WOLFSSH_CTX* ctx, const char* list) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx) { + ctx->algoListMac = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_CTX_GetAlgoListMac(WOLFSSH_CTX* ctx) +{ + const char* list = NULL; + + if (ctx) { + list = ctx->algoListMac; + } + + return list; +} + + +int wolfSSH_SetAlgoListMac(WOLFSSH* ssh, const char* list) +{ + int ret = WS_SSH_NULL_E; + + if (ssh) { + ssh->algoListMac = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_GetAlgoListMac(WOLFSSH* ssh) +{ + const char* list = NULL; + + if (ssh) { + list = ssh->algoListMac; + } + + return list; +} + + +int wolfSSH_CTX_SetAlgoListKeyAccepted(WOLFSSH_CTX* ctx, const char* list) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx) { + ctx->algoListKeyAccepted = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_CTX_GetAlgoListKeyAccepted(WOLFSSH_CTX* ctx) +{ + const char* list = NULL; + + if (ctx) { + list = ctx->algoListKeyAccepted; + } + + return list; +} + + +int wolfSSH_SetAlgoListKeyAccepted(WOLFSSH* ssh, const char* list) +{ + int ret = WS_SSH_NULL_E; + + if (ssh) { + ssh->algoListKeyAccepted = list; + ret = WS_SUCCESS; + } + + return ret; +} + + +const char* wolfSSH_GetAlgoListKeyAccepted(WOLFSSH* ssh) +{ + const char* list = NULL; + + if (ssh) { + list = ssh->algoListKeyAccepted; + } + + return list; +} + + +int wolfSSH_CheckAlgoName(const char* name) +{ + int ret = WS_INVALID_ALGO_ID; + + if (name) { + word32 nameSz = (word32)WSTRLEN(name); + if (NameToId(name, nameSz) != ID_UNKNOWN) { + ret = WS_SUCCESS; + } + } + + return ret; +} + + +const char* wolfSSH_QueryKex(word32* index) +{ + return NameByIndexType(TYPE_KEX, index); +} + + +const char* wolfSSH_QueryKey(word32* index) +{ + return NameByIndexType(TYPE_KEY, index); +} + + +const char* wolfSSH_QueryCipher(word32* index) +{ + return NameByIndexType(TYPE_CIPHER, index); +} + + +const char* wolfSSH_QueryMac(word32* index) +{ + return NameByIndexType(TYPE_MAC, index); +} + + int wolfSSH_CTX_SetBanner(WOLFSSH_CTX* ctx, const char* newBanner) { @@ -2549,6 +2838,444 @@ int wolfSSH_ChannelGetEof(WOLFSSH_CHANNEL* channel) return eof; } +static const char* HashNameForId(byte id) +{ + enum wc_HashType hash = HashForId(id); + + if (hash == WC_HASH_TYPE_SHA) + return "SHA-1"; + + if (hash == WC_HASH_TYPE_SHA256) + return "SHA-256"; + + if (hash == WC_HASH_TYPE_SHA384) + return "SHA-384"; + + if (hash == WC_HASH_TYPE_SHA512) + return "SHA-512"; + + return ""; +} + +static const char* CurveNameForId(byte id) +{ +#if !defined(WOLFSSH_NO_ECDSA) || !defined(WOLFSSH_NO_ECDH) + switch (wcPrimeForId(id)) { + case ECC_SECP256R1: + return "nistp256"; + + case ECC_SECP384R1: + return "nistp384"; + + case ECC_SECP521R1: + return "nistp521"; + +#ifdef HAVE_CURVE25519 + case ECC_X25519: + return "Curve25519"; +#endif + } +#endif + return ""; +} + +static const char* CipherNameForId(byte id) +{ + switch (id) { + case ID_AES128_CBC: + return "AES-128 CBC"; + + case ID_AES192_CBC: + return "AES-192 CBC"; + + case ID_AES256_CBC: + return "AES-256 CBC"; + + case ID_AES128_CTR: + return "AES-128 SDCTR"; + + case ID_AES192_CTR: + return "AES-192 SDCTR"; + + case ID_AES256_CTR: + return "AES-256 SDCTR"; + + case ID_AES128_GCM: + return "AES-128 GCM"; + + case ID_AES192_GCM: + return "AES-192 GCM"; + + case ID_AES256_GCM: + return "AES-256 GCM"; + } + + return ""; +} + +static const char* MacNameForId(byte macid, byte cipherid) +{ + if (macid != ID_NONE) { + switch (macid) { + case ID_HMAC_SHA1: + return "HMAC-SHA-1"; + + case ID_HMAC_SHA1_96: + return "HMAC-SHA-1-96"; + + case ID_HMAC_SHA2_256: + return "HMAC-SHA-256"; + } + } + else { + switch (cipherid) { + case ID_AES128_GCM: + return "AES128 GCM (in ETM mode)"; + + case ID_AES192_GCM: + return "AES192 GCM (in ETM mode)"; + + case ID_AES256_GCM: + return "AES256 GCM (in ETM mode)"; + } + } + + return ""; +} + +size_t wolfSSH_GetText(WOLFSSH *ssh, WS_Text id, char *str, size_t strSz) +{ + int ret = 0; + +#ifndef WOLFSSH_NO_DH + static const char standard_dh_format[] = + "%d-bit Diffie-Hellman with standard group %d"; +#endif + + if (!ssh || str == NULL || strSz <= 0) + return 0; + + switch (id) { + case WOLFSSH_TEXT_KEX_HASH: + ret = WSNPRINTF(str, strSz, "%s", HashNameForId(ssh->kexId)); + break; + + case WOLFSSH_TEXT_KEX_CURVE: + ret = WSNPRINTF(str, strSz, "%s", CurveNameForId(ssh->kexId)); + break; + + case WOLFSSH_TEXT_CRYPTO_IN_CIPHER: + ret = WSNPRINTF(str, strSz, "%s", + CipherNameForId(ssh->peerEncryptId)); + break; + + case WOLFSSH_TEXT_CRYPTO_OUT_CIPHER: + ret = WSNPRINTF(str, strSz, "%s", CipherNameForId(ssh->encryptId)); + break; + + case WOLFSSH_TEXT_CRYPTO_IN_MAC: + ret = WSNPRINTF(str, strSz, "%s", MacNameForId(ssh->peerMacId, + ssh->peerEncryptId)); + break; + + case WOLFSSH_TEXT_CRYPTO_OUT_MAC: + ret = WSNPRINTF(str, strSz, "%s", MacNameForId(ssh->macId, + ssh->encryptId)); + break; + + case WOLFSSH_TEXT_KEX_ALGO: + switch (ssh->kexId) { + case ID_ECDH_SHA2_NISTP256: + case ID_ECDH_SHA2_NISTP384: + case ID_ECDH_SHA2_NISTP521: + case ID_ECDH_SHA2_ED25519: + case ID_ECDH_SHA2_ED25519_LIBSSH: + #ifndef WOLFSSH_NO_CURVE25519_SHA256 + case ID_CURVE25519_SHA256: + #endif + ret = WSNPRINTF(str, strSz, "%s", "ECDH"); + break; + + #ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 + case ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256: + ret = WSNPRINTF(str, strSz, "%s", "Kyber1"); + break; + #endif + + #ifndef WOLFSSH_NO_DH + case ID_DH_GROUP1_SHA1: + ret = WSNPRINTF(str, strSz, standard_dh_format, + ssh->primeGroupSz*8, 1); + break; + + case ID_DH_GROUP14_SHA1: + case ID_DH_GROUP14_SHA256: + ret = WSNPRINTF(str, strSz, standard_dh_format, + ssh->primeGroupSz*8, 14); + break; + + case ID_DH_GEX_SHA256: + ret = WSNPRINTF(str, strSz, + "%d-bit Diffie-Hellman with server-supplied group", + ssh->primeGroupSz*8); + break; + #endif /* !WOLFSSH_NO_DH */ + + case ID_EXTINFO_S: + ret = WSNPRINTF(str, strSz, "Server extensions KEX"); + break; + + case ID_EXTINFO_C: + ret = WSNPRINTF(str, strSz, "Client extensions KEX"); + break; + + } + break; + } + + return ret < 0 ? 0 : (size_t)ret; +} + +void wolfSSH_SetKeyingCompletionCb(WOLFSSH_CTX* ctx, WS_CallbackKeyingCompletion cb) +{ + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_SetKeyingCompletionCb()"); + + if (ctx) + ctx->keyingCompletionCb = cb; +} + +void wolfSSH_SetKeyingCompletionCbCtx(WOLFSSH* ssh, void* ctx) +{ + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_SetKeyingCompletionCbCtx()"); + + if (ssh) + ssh->keyingCompletionCtx = ctx; +} + + +WS_SessionType wolfSSH_ChannelGetSessionType(const WOLFSSH_CHANNEL* channel) +{ + WS_SessionType type = WOLFSSH_SESSION_UNKNOWN; + + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_ChannelGetType()"); + + if (channel) { + type = (WS_SessionType)channel->sessionType; + } + + return type; +} + + +const char* wolfSSH_ChannelGetSessionCommand(const WOLFSSH_CHANNEL* channel) +{ + const char* cmd = NULL; + + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_ChannelGetCommand()"); + + if (channel) { + cmd = channel->command; + } + + return cmd; +} + + +int wolfSSH_CTX_SetChannelOpenCb(WOLFSSH_CTX* ctx, WS_CallbackChannelOpen cb) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx != NULL) { + ctx->channelOpenCb = cb; + ret = WS_SUCCESS; + } + + return ret; +} + + +int wolfSSH_CTX_SetChannelOpenRespCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelOpen confCb, WS_CallbackChannelOpen failCb) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx != NULL) { + ctx->channelOpenConfCb = confCb; + ctx->channelOpenFailCb = failCb; + ret = WS_SUCCESS; + } + + return ret; +} + + +int wolfSSH_CTX_SetChannelReqShellCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelReq cb) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx != NULL) { + ctx->channelReqShellCb = cb; + ret = WS_SUCCESS; + } + + return ret; +} + + +int wolfSSH_CTX_SetChannelReqExecCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelReq cb) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx != NULL) { + ctx->channelReqExecCb = cb; + ret = WS_SUCCESS; + } + + return ret; +} + + +int wolfSSH_CTX_SetChannelReqSubsysCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelReq cb) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx != NULL) { + ctx->channelReqSubsysCb = cb; + ret = WS_SUCCESS; + } + + return ret; +} + + +int wolfSSH_SetChannelOpenCtx(WOLFSSH* ssh, void* ctx) +{ + int ret = WS_SSH_NULL_E; + + if (ssh != NULL) { + ssh->channelOpenCtx = ctx; + ret = WS_SUCCESS; + } + + return ret; +} + + +void* wolfSSH_GetChannelOpenCtx(WOLFSSH* ssh) +{ + void* ctx = NULL; + + if (ssh != NULL) { + ctx = ssh->channelOpenCtx; + } + + return ctx; +} + + +int wolfSSH_SetChannelReqCtx(WOLFSSH* ssh, void* ctx) +{ + int ret = WS_SSH_NULL_E; + + if (ssh != NULL) { + ssh->channelReqCtx = ctx; + ret = WS_SUCCESS; + } + + return ret; +} + + +void* wolfSSH_GetChannelReqCtx(WOLFSSH* ssh) +{ + void* ctx = NULL; + + if (ssh != NULL) { + ctx = ssh->channelReqCtx; + } + + return ctx; +} + + +int wolfSSH_CTX_SetChannelEofCb(WOLFSSH_CTX* ctx, WS_CallbackChannelEof cb) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx != NULL) { + ctx->channelEofCb = cb; + ret = WS_SUCCESS; + } + + return ret; +} + + +int wolfSSH_SetChannelEofCtx(WOLFSSH* ssh, void* ctx) +{ + int ret = WS_SSH_NULL_E; + + if (ssh != NULL) { + ssh->channelEofCtx = ctx; + ret = WS_SUCCESS; + } + + return ret; +} + + +void* wolfSSH_GetChannelEofCtx(WOLFSSH* ssh) +{ + void* ctx = NULL; + + if (ssh != NULL) { + ctx = ssh->channelEofCtx; + } + + return ctx; +} + + +int wolfSSH_CTX_SetChannelCloseCb(WOLFSSH_CTX* ctx, WS_CallbackChannelClose cb) +{ + int ret = WS_SSH_CTX_NULL_E; + + if (ctx != NULL) { + ctx->channelCloseCb = cb; + ret = WS_SUCCESS; + } + + return ret; +} + + +int wolfSSH_SetChannelCloseCtx(WOLFSSH* ssh, void* ctx) +{ + int ret = WS_SSH_NULL_E; + + if (ssh != NULL) { + ssh->channelCloseCtx = ctx; + ret = WS_SUCCESS; + } + + return ret; +} + + +void* wolfSSH_GetChannelCloseCtx(WOLFSSH* ssh) +{ + void* ctx = NULL; + + if (ssh != NULL) { + ctx = ssh->channelCloseCtx; + } + + return ctx; +} + #if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \ !defined(NO_WOLFSSH_SERVER) diff --git a/src/wolfscp.c b/src/wolfscp.c index d51912cfc..26beaa9c7 100644 --- a/src/wolfscp.c +++ b/src/wolfscp.c @@ -1,6 +1,6 @@ /* wolfscp.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -57,6 +57,8 @@ static int ScpPushDir(void *fs, ScpSendCtx* ctx, const char* path, void* heap); static int ScpPopDir(void *fs, ScpSendCtx* ctx, void* heap); #endif +#define WOLFSSH_MODE_MASK 0777 + const char scpError[] = "scp error: %s, %d"; const char scpState[] = "scp state: %s"; @@ -96,7 +98,8 @@ int DoScpSink(WOLFSSH* ssh) ssh->scpConfirm = ssh->ctx->scpRecvCb(ssh, WOLFSSH_SCP_NEW_REQUEST, ssh->scpBasePath, - NULL, 0, 0, 0, 0, NULL, 0, 0, wolfSSH_GetScpRecvCtx(ssh)); + NULL, 0, 0, 0, 0, NULL, 0, 0, + wolfSSH_GetScpRecvCtx(ssh)); continue; case SCP_RECEIVE_MESSAGE: @@ -186,12 +189,9 @@ int DoScpSink(WOLFSSH* ssh) ssh->scpATime, ssh->scpFileSz, ssh->scpFileBuffer, ssh->scpFileBufferSz, ssh->scpFileOffset, wolfSSH_GetScpRecvCtx(ssh)); - ssh->scpFileOffset += ssh->scpFileBufferSz; - /* shrink and reset recv buffer */ - WFREE(ssh->scpFileBuffer, ssh->ctx->heap, DYNTYPE_BUFFER); - ssh->scpFileBuffer = NULL; + /* reset recv buffer */ ssh->scpFileBufferSz = 0; if (ssh->scpConfirm != WS_SCP_CONTINUE) { @@ -315,7 +315,8 @@ static int SendScpFileHeader(WOLFSSH* ssh) #ifndef WSCPFILEHDR WMEMSET(buf, 0, sizeof(buf)); WSNPRINTF(buf, sizeof(buf), "C%04o %u %s\n", - ssh->scpFileMode, ssh->scpFileSz, ssh->scpFileName); + ssh->scpFileMode & WOLFSSH_MODE_MASK, + ssh->scpFileSz, ssh->scpFileName); filehdr = buf; #else filehdr = WSCPFILEHDR(ssh); @@ -350,8 +351,9 @@ static int SendScpEnterDirectory(WOLFSSH* ssh) WMEMSET(buf, 0, sizeof(buf)); - WSNPRINTF(buf, sizeof(buf), "D%04o 0 %s\n", ssh->scpFileMode, - ssh->scpFileName); + WSNPRINTF(buf, sizeof(buf), "D%04o 0 %s\n", + ssh->scpFileMode & WOLFSSH_MODE_MASK, + ssh->scpFileName); bufSz = (int)WSTRLEN(buf); @@ -726,7 +728,11 @@ int DoScpRequest(WOLFSSH* ssh) /* Peer MUST send back a SSH_MSG_CHANNEL_CLOSE unless already sent*/ ret = wolfSSH_stream_read(ssh, buf, 1); - if (ret != WS_EOF) { + if (ret == WS_SOCKET_ERROR_E || ret == WS_CHANNEL_CLOSED) { + WLOG(WS_LOG_DEBUG, scpState, "Peer hung up, but SCP is done"); + ret = WS_SUCCESS; + } + else if (ret != WS_EOF) { WLOG(WS_LOG_DEBUG, scpState, "Did not receive EOF packet"); } else { @@ -1437,8 +1443,6 @@ int ReceiveScpMessage(WOLFSSH* ssh) break; } - WFREE(ssh->scpRecvMsg, ssh->ctx->heap, DYNTYPE_STRING); - ssh->scpRecvMsg = NULL; ssh->scpRecvMsgSz = 0; return ret; @@ -1447,34 +1451,28 @@ int ReceiveScpMessage(WOLFSSH* ssh) int ReceiveScpFile(WOLFSSH* ssh) { int partSz, ret = WS_SUCCESS; - byte* part; if (ssh == NULL) return WS_BAD_ARGUMENT; + /* We don't want to over-read the buffer. The file data is + * terminated by the sender with a nul which is checked later. */ partSz = min(ssh->scpFileSz - ssh->scpFileOffset, DEFAULT_SCP_BUFFER_SZ); /* don't even bother reading if read size is 0 */ if (partSz == 0) return ret; - part = (byte*)WMALLOC(partSz, ssh->ctx->heap, DYNTYPE_BUFFER); - if (part == NULL) - ret = WS_MEMORY_E; + if (ssh->scpFileBuffer == NULL) { + ssh->scpFileBuffer = (byte*)WMALLOC(DEFAULT_SCP_BUFFER_SZ, + ssh->ctx->heap, DYNTYPE_BUFFER); + if (ssh->scpFileBuffer == NULL) + ret = WS_MEMORY_E; + } if (ret == WS_SUCCESS) { - WMEMSET(part, 0, partSz); - - ret = wolfSSH_stream_read(ssh, part, partSz); + ret = wolfSSH_stream_read(ssh, ssh->scpFileBuffer, partSz); if (ret > 0) { - if (ssh->scpFileBuffer != NULL) { - WFREE(ssh->scpFileBuffer, ssh->ctx->heap, DYNTYPE_BUFFER); - ssh->scpFileBuffer = NULL; - ssh->scpFileBufferSz = 0; - } - ssh->scpFileBuffer = part; ssh->scpFileBufferSz = ret; - } else { - WFREE(part, ssh->ctx->heap, DYNTYPE_BUFFER); } } @@ -1657,70 +1655,107 @@ int wolfSSH_SCP_connect(WOLFSSH* ssh, byte* cmd) return ret; } -static int wolfSSH_SCP_cmd(WOLFSSH* ssh, const char* localName, - const char* remoteName, byte dir) + +static char* MakeScpCmd(const char* name, char dir, void* heap) +{ + char* cmd; + int sz; + + sz = WSNPRINTF(NULL, 0, "scp -%c %s", dir, name) + 1; + if (sz <= 0) { + return NULL; + } + cmd = (char*)WMALLOC(sz, heap, DYNTYPE_STRING); + if (cmd == NULL) { + return NULL; + } + sz = WSNPRINTF(cmd, sz, "scp -%c %s", dir, name); + if (sz <= 0) { + WFREE(cmd, heap, DYNTYPE_STRING); + return NULL; + } + + return cmd; +} + + +int wolfSSH_SCP_to(WOLFSSH* ssh, const char* src, const char* dst) { - char* cmd = NULL; - word32 remoteNameSz, cmdSz; int ret = WS_SUCCESS; - if (ssh == NULL || localName == NULL || remoteName == NULL) - return WS_BAD_ARGUMENT; + /* dst is passed to the server in the scp -t command */ + /* src is used locally to fopen and read for copy to */ - if (dir != 't' && dir != 'f') + if (ssh == NULL || src == NULL || dst == NULL) return WS_BAD_ARGUMENT; - remoteNameSz = (word32)WSTRLEN(remoteName); - cmdSz = remoteNameSz + (word32)WSTRLEN("scp -5 ") + 1; - cmd = (char*)WMALLOC(cmdSz, ssh->ctx->heap, DYNTYPE_STRING); - - /* Need to set up the context for the local interaction callback. */ + if (ssh->scpState == SCP_SETUP) { + char* cmd = MakeScpCmd(dst, 't', ssh->ctx->heap); + if (cmd == NULL) { + WLOG(WS_LOG_SCP, "Cannot allocate scp command"); + ssh->error = WS_MEMORY_E; + return WS_ERROR; + } - if (cmd != NULL) { - WSNPRINTF(cmd, cmdSz, "scp -%c %s", dir, remoteName); - ssh->scpBasePath = localName; + ssh->scpBasePath = src; ret = wolfSSH_SCP_connect(ssh, (byte*)cmd); if (ret == WS_SUCCESS) { - if (dir == 't') { - ssh->scpState = SCP_SOURCE_BEGIN; - ssh->scpRequestState = SCP_SOURCE; - ret = DoScpSource(ssh); - } - else { - cmdSz = (word32)WSTRLEN(localName); - ret = ParseBasePathHelper(ssh, cmdSz); - if (ret == WS_SUCCESS) { - ssh->scpState = SCP_SINK_BEGIN; - ssh->scpRequestState = SCP_SINK; - ret = DoScpSink(ssh); - } - } + ssh->scpState = SCP_SOURCE_BEGIN; + ssh->scpRequestState = SCP_SOURCE; + } + if (cmd) { + WFREE(cmd, ssh->ctx->heap, DYNTYPE_STRING); } - WFREE(cmd, ssh->ctx->heap, DYNTYPE_STRING); } - else { - WLOG(WS_LOG_SCP, "Cannot build scp command"); - ssh->error = WS_MEMORY_E; - ret = WS_ERROR; + if (ssh->scpState != SCP_SETUP) { + if (ret == WS_SUCCESS) { + ret = DoScpSource(ssh); + } } return ret; } -int wolfSSH_SCP_to(WOLFSSH* ssh, const char* src, const char* dst) -{ - return wolfSSH_SCP_cmd(ssh, src, dst, 't'); - /* dst is passed to the server in the scp -t command */ - /* src is used locally to fopen and read for copy to */ -} - - int wolfSSH_SCP_from(WOLFSSH* ssh, const char* src, const char* dst) { - return wolfSSH_SCP_cmd(ssh, dst, src, 'f'); + int ret = WS_SUCCESS; + /* src is passed to the server in the scp -f command */ /* dst is used locally to fopen and write for copy from */ + + if (ssh == NULL || src == NULL || dst == NULL) + return WS_BAD_ARGUMENT; + + if (ssh->scpState == SCP_SETUP) { + char* cmd = MakeScpCmd(src, 'f', ssh->ctx->heap); + if (cmd == NULL) { + WLOG(WS_LOG_SCP, "Cannot allocate scp command"); + ssh->error = WS_MEMORY_E; + return WS_ERROR; + } + + ssh->scpBasePath = dst; + ret = wolfSSH_SCP_connect(ssh, (byte*)cmd); + if (ret == WS_SUCCESS) { + word32 srcSz = (word32)WSTRLEN(src); + ret = ParseBasePathHelper(ssh, srcSz); + } + if (ret == WS_SUCCESS) { + ssh->scpState = SCP_SINK_BEGIN; + ssh->scpRequestState = SCP_SINK; + } + if (cmd) { + WFREE(cmd, ssh->ctx->heap, DYNTYPE_STRING); + } + } + if (ssh->scpState != SCP_SETUP) { + if (ret == WS_SUCCESS) { + ret = DoScpSink(ssh); + } + } + + return ret; } #endif /* ! NO_WOLFSSH_CLIENT */ @@ -2114,7 +2149,7 @@ static int GetFileStats(void *fs, ScpSendCtx* ctx, const char* fileName, word64* mTime, word64* aTime, int* fileMode) { int ret = WS_SUCCESS; - + WOLFSSH_UNUSED(fs); if (ctx == NULL || fileName == NULL || mTime == NULL || @@ -2630,6 +2665,7 @@ static int ScpProcessEntry(WOLFSSH* ssh, char* fileName, word64* mTime, * WS_SCP_EXIT_DIR_FINAL - return when recursive directory transfer * is complete. * WS_SCP_ABORT - abort file transfer request + * WS_BAD_FILE_E - local file open error hit */ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest, char* fileName, word32 fileNameSz, word64* mTime, word64* aTime, @@ -2668,7 +2704,7 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest, WLOG(WS_LOG_ERROR, "scp: unable to open file, abort"); wolfSSH_SetScpErrorMsg(ssh, "unable to open file for reading"); - ret = WS_SCP_ABORT; + ret = WS_BAD_FILE_E; } if (ret == WS_SUCCESS) { @@ -2690,17 +2726,21 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest, if (ret == WS_SUCCESS) ret = ExtractFileName(peerRequest, fileName, fileNameSz); - if (ret == WS_SUCCESS && sendCtx != NULL && sendCtx->fp != NULL) { - /* If it is an empty file, do not read. */ - if (*totalFileSz != 0) { - ret = (word32)WFREAD(ssh->fs, buf, 1, bufSz, sendCtx->fp); - if (ret == 0) { /* handle unexpected case */ - ret = WS_EOF; + if (ret == WS_SUCCESS) { + if (sendCtx != NULL && sendCtx->fp != NULL) { + /* If it is an empty file, do not read. */ + if (*totalFileSz != 0) { + ret = (word32)WFREAD(ssh->fs, buf, 1, bufSz, + sendCtx->fp); + if (ret == 0) { /* handle unexpected case */ + ret = WS_EOF; + } } + } else { + WLOG(WS_LOG_ERROR, + "scp: error extracting file name, abort"); + ret = WS_SCP_ABORT; } - } else { - WLOG(WS_LOG_ERROR, "scp: error extracting file name, abort"); - ret = WS_SCP_ABORT; } /* keep fp open if no errors and transfer will continue */ @@ -2841,9 +2881,10 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath, recvBuffer->mode = fileMode; if (recvBuffer->status) { if (recvBuffer->status(ssh, fileName, WOLFSSH_SCP_NEW_FILE, - recvBuffer) != WS_SUCCESS) + recvBuffer) != WS_SUCCESS) { WLOG(WS_LOG_ERROR, "scp: status of new file failed, abort"); ret = WS_SCP_ABORT; + } } break; @@ -2865,9 +2906,10 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath, recvBuffer->fileSz += sz; if (recvBuffer->status) { if (recvBuffer->status(ssh, recvBuffer->name, - WOLFSSH_SCP_FILE_PART, recvBuffer) != WS_SUCCESS) + WOLFSSH_SCP_FILE_PART, recvBuffer) != WS_SUCCESS) { WLOG(WS_LOG_ERROR, "scp: bad status, abort"); ret = WS_SCP_ABORT; + } } break; @@ -2876,9 +2918,10 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath, recvBuffer->mTime = 0; /* @TODO set time if wanted */ if (recvBuffer->status) { if (recvBuffer->status(ssh, recvBuffer->name, - WOLFSSH_SCP_FILE_DONE, recvBuffer) != WS_SUCCESS) + WOLFSSH_SCP_FILE_DONE, recvBuffer) != WS_SUCCESS) { WLOG(WS_LOG_ERROR, "scp: bad status, abort"); ret = WS_SCP_ABORT; + } } break; diff --git a/src/wolfsftp.c b/src/wolfsftp.c index b2ecf1fd6..2638e15ff 100644 --- a/src/wolfsftp.c +++ b/src/wolfsftp.c @@ -1,6 +1,6 @@ /* wolfsftp.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -611,9 +611,9 @@ static int wolfSSH_SFTP_buffer_create(WOLFSSH* ssh, WS_SFTP_BUFFER* buffer, } -/* Used to clear and free all states. Should be when returning errors or success - * Must be called when free'ing the SFTP. For now static since only used in - * wolfsftp.c +/* Used to clear and free all states. Should be when returning errors or + * success. Must be called when free'ing the SFTP. For now static since only + * used in wolfsftp.c * * Note: Most cases an error will free all states and a success will free * specific state ID. @@ -1017,7 +1017,8 @@ static int SFTP_ServerRecvInit(WOLFSSH* ssh) { state = ssh->recvInitState; if (state == NULL) { - state = (WS_SFTP_RECV_INIT_STATE*)WMALLOC(sizeof(WS_SFTP_RECV_INIT_STATE), + state = (WS_SFTP_RECV_INIT_STATE*)WMALLOC( + sizeof(WS_SFTP_RECV_INIT_STATE), ssh->ctx->heap, DYNTYPE_SFTP_STATE); if (state == NULL) { ssh->error = WS_MEMORY_E; @@ -1029,7 +1030,8 @@ static int SFTP_ServerRecvInit(WOLFSSH* ssh) { switch (ssh->sftpState) { case SFTP_BEGIN: - ret = wolfSSH_SFTP_buffer_read(ssh, &state->buffer, RECV_INIT_SIZE); + ret = wolfSSH_SFTP_buffer_read(ssh, + &state->buffer, RECV_INIT_SIZE); if (ret < 0) { return WS_FATAL_ERROR; } @@ -1039,8 +1041,8 @@ static int SFTP_ServerRecvInit(WOLFSSH* ssh) { return WS_FATAL_ERROR; } - if (SFTP_GetSz(state->buffer.data, &sz, - MSG_ID_SZ + UINT32_SZ, WOLFSSH_MAX_SFTP_RECV) != WS_SUCCESS) { + if (SFTP_GetSz(state->buffer.data, &sz, MSG_ID_SZ + UINT32_SZ, + WOLFSSH_MAX_SFTP_RECV) != WS_SUCCESS) { wolfSSH_SFTP_ClearState(ssh, STATE_ID_ALL); return WS_BUFFER_E; } @@ -1054,11 +1056,12 @@ static int SFTP_ServerRecvInit(WOLFSSH* ssh) { } ato32(state->buffer.data + LENGTH_SZ + MSG_ID_SZ, &version); - /* versions greater than WOLFSSH_SFTP_VERSION should fall back to ours - * versions less than WOLFSSH_SFTP_VERSION we should bail out on or - * implement a fall back */ + /* versions greater than WOLFSSH_SFTP_VERSION should fall back to + * ours versions less than WOLFSSH_SFTP_VERSION we should bail out + * on or implement a fall back */ if (version < WOLFSSH_SFTP_VERSION) { - WLOG(WS_LOG_SFTP, "Unsupported SFTP version, sending version 3"); + WLOG(WS_LOG_SFTP, + "Unsupported SFTP version, sending version 3"); wolfSSH_SFTP_ClearState(ssh, STATE_ID_ALL); return WS_VERSION_E; } @@ -1072,7 +1075,8 @@ static int SFTP_ServerRecvInit(WOLFSSH* ssh) { case SFTP_EXT: /* silently ignore extensions if not supported */ if (state->extSz > 0) { - ret = wolfSSH_SFTP_buffer_read(ssh, &state->buffer, (int)state->extSz); + ret = wolfSSH_SFTP_buffer_read(ssh, + &state->buffer, (int)state->extSz); if (ret < 0) { return WS_FATAL_ERROR; } @@ -1505,8 +1509,10 @@ int wolfSSH_SFTP_read(WOLFSSH* ssh) WLOG(WS_LOG_SFTP, "Unknown packet type [%d] received", state->type); if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, - state->reqId, "Unknown/Unsupported packet type", - "English", NULL, (word32*)&maxSz) != WS_SIZE_ONLY) { + state->reqId, + "Unknown/Unsupported packet type", + "English", NULL, (word32*)&maxSz) + != WS_SIZE_ONLY) { wolfSSH_SFTP_ClearState(ssh, STATE_ID_RECV); return WS_FATAL_ERROR; } @@ -1533,7 +1539,7 @@ int wolfSSH_SFTP_read(WOLFSSH* ssh) } if (ret == WS_SUCCESS) { - /* set send out buffer, "state->data" is taken by ssh */ + /* set send out buffer, state data is taken by ssh */ wolfSSH_SFTP_RecvSetSend(ssh, wolfSSH_SFTP_buffer_data(&state->buffer), wolfSSH_SFTP_buffer_size(&state->buffer)); @@ -2042,11 +2048,12 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) } { - WS_SFTP_FILEATRB fileAtr = { 0 }; + WS_SFTP_FILEATRB fileAtr; + WMEMSET(&fileAtr, 0, sizeof(fileAtr)); 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"); + dir, &fileAtr, 0, ssh->ctx->heap) == WS_SUCCESS) { + if ((fileAtr.per & FILEATRB_PER_MASK_TYPE) + != FILEATRB_PER_FILE) { ssh->error = WS_SFTP_NOT_FILE_E; res = naf; @@ -2079,7 +2086,8 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) #ifdef WOLFSSH_STOREHANDLE if (ret == WS_SUCCESS) { - if ((ret = SFTP_AddHandleNode(ssh, (byte*)&fd, sizeof(WFD), dir)) != WS_SUCCESS) { + if ((ret = SFTP_AddHandleNode(ssh, (byte*)&fd, sizeof(WFD), dir)) + != WS_SUCCESS) { WLOG(WS_LOG_SFTP, "Unable to store handle"); res = ier; if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, res, @@ -2599,7 +2607,15 @@ static int SFTP_CreateLongName(WS_SFTPNAME* name) word32 tmp = atr->per; i = 0; - perm[i++] = (tmp & 0x4000)?'d':'-'; + if (tmp & FILEATRB_PER_DIR) { + perm[i++] = 'd'; + } + else if (tmp & FILEATRB_PER_LINK) { + perm[i++] = 'l'; + } + else { + perm[i++] = '-'; + } perm[i++] = (tmp & 0x100)?'r':'-'; perm[i++] = (tmp & 0x080)?'w':'-'; perm[i++] = (tmp & 0x040)?'x':'-'; @@ -2618,7 +2634,8 @@ static int SFTP_CreateLongName(WS_SFTPNAME* name) totalSz += name->fSz; /* size of file name */ totalSz += 7; /* for all ' ' spaces */ totalSz += 3 + 8 + 8; /* linkCount + uid + gid */ - WSNPRINTF(sizeStr, sizeof(sizeStr) - 1, "%8lld", ((long long int)atr->sz[1] << 32) + (long long int)(atr->sz[0])); + WSNPRINTF(sizeStr, sizeof(sizeStr) - 1, "%8lld", + ((long long int)atr->sz[1] << 32) + (long long int)(atr->sz[0])); totalSz += (int)WSTRLEN(sizeStr); #else totalSz = name->fSz; @@ -2642,11 +2659,45 @@ static int SFTP_CreateLongName(WS_SFTPNAME* name) return WS_SUCCESS; } +#if defined(WOLFSSH_SFTP_NAME_READDIR) +/* helper function that gets file information from reading directory. + * Internally uses SFTP_Name_readdir to delegate the work to the User + * Filesystem. + * + * returns WS_SUCCESS on success + */ +static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out, + char* dirName) +{ + WOLFSSH_UNUSED(dirName); + int res; -#ifdef WOLFSSL_NUCLEUS + if (dir == NULL || ssh == NULL || out == NULL) { + return WS_BAD_ARGUMENT; + } + + res = SFTP_Name_readdir(ssh->fs, dir, out); + if (res != WS_SUCCESS) { + return res; + } + + if (out->fName == NULL) { + return WS_MEMORY_E; + } + + /* Use attributes and fName to create long name */ + if (SFTP_CreateLongName(out) != WS_SUCCESS) { + WLOG(WS_LOG_DEBUG, "Error creating long name for %s", out->fName); + WFREE(out->fName, out->heap, DYNTYPE_SFTP); + return WS_FATAL_ERROR; + } + + return WS_SUCCESS; +} + +#elif defined(WOLFSSL_NUCLEUS) /* For Nucleus port * helper function that gets file information from reading directory - * @TODO allow user to override * * returns WS_SUCCESS on success */ @@ -2687,8 +2738,8 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out, special = 1; } - /* use long name on Nucleus because sfname has only the file name and in all - * caps */ + /* use long name on Nucleus because sfname has only the file name and in + * all caps */ sz = (int)WSTRLEN(dir->lfname); out->fName = (char*)WMALLOC(sz + 1, out->heap, DYNTYPE_SFTP); if (out->fName == NULL) { @@ -2756,7 +2807,6 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out, #elif defined(FREESCALE_MQX) /* Freescale MQX 4.2 * helper function that gets file information from reading directory - * @TODO allow user to override * * returns WS_SUCCESS on success */ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out, @@ -2835,7 +2885,6 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out, #elif defined(USE_WINDOWS_API) /* helper function that gets file information from reading directory -* @TODO allow user to override * * returns WS_SUCCESS on success */ @@ -3066,7 +3115,6 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out, #else /* helper function that gets file information from reading directory - * @TODO allow user to override * * returns WS_SUCCESS on success */ @@ -3113,7 +3161,7 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out, return WS_FATAL_ERROR; } - if (SFTP_GetAttributes(ssh->fs, s, &out->atrb, 0, ssh->ctx->heap) + if (SFTP_GetAttributes(ssh->fs, s, &out->atrb, 1, ssh->ctx->heap) != WS_SUCCESS) { WLOG(WS_LOG_SFTP, "Unable to get attribute values for %s", out->fName); @@ -4195,7 +4243,8 @@ static WS_HANDLE_LIST* SFTP_GetHandleNode(WOLFSSH* ssh, byte* handle, /* for Nucleus need to find name from handle */ while (cur != NULL) { - if(handleSz == cur->handleSz && WMEMCMP(handle, cur->handle, handleSz) == 0) { + if (handleSz == cur->handleSz + && WMEMCMP(handle, cur->handle, handleSz) == 0) { break; /* found handle */ } cur = cur->next; @@ -4256,7 +4305,8 @@ int SFTP_RemoveHandleNode(WOLFSSH* ssh, byte* handle, word32 handleSz) cur = SFTP_GetHandleNode(ssh, handle, handleSz); if (cur == NULL) { - WLOG(WS_LOG_SFTP, "Fatal Error! Trying to remove a handle that was not in the list"); + WLOG(WS_LOG_SFTP, + "Fatal Error! Trying to remove a handle that was not in the list"); return WS_FATAL_ERROR; } @@ -4488,9 +4538,9 @@ int SFTP_GetAttributes(void* fs, const char* fileName, WS_SFTP_FILEATRB* atr, atr->flags |= WOLFSSH_FILEATRB_PERM; atr->per = 0555 | - (stats.dwFileAttributes | FILE_ATTRIBUTE_READONLY ? 0 : 0200); - atr->per |= (stats.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 0x4000: - FILEATRB_PER_FILE; + ((stats.dwFileAttributes | FILE_ATTRIBUTE_READONLY) ? 0 : 0200); + atr->per |= ((stats.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + ? FILEATRB_PER_DIR : FILEATRB_PER_FILE); #if 0 /* @TODO handle the constellation of possible Windows FILETIMEs */ @@ -4944,7 +4994,8 @@ int wolfSSH_SFTP_RecvFSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) } if (ret == WS_SUCCESS) { - if (SFTP_SetHeader(ssh, reqId, WOLFSSH_FTP_ATTRS, sz, out) != WS_SUCCESS) { + if (SFTP_SetHeader(ssh, reqId, WOLFSSH_FTP_ATTRS, sz, out) + != WS_SUCCESS) { return WS_FATAL_ERROR; } SFTP_SetAttributes(ssh, out + WOLFSSH_SFTP_HEADER, sz, &atr); @@ -5035,7 +5086,8 @@ int wolfSSH_SFTP_RecvSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) } } else { - if (SFTP_SetHeader(ssh, reqId, WOLFSSH_FTP_ATTRS, sz, out) != WS_SUCCESS) { + if (SFTP_SetHeader(ssh, reqId, WOLFSSH_FTP_ATTRS, sz, out) + != WS_SUCCESS) { WFREE(out, ssh->ctx->heap, DYNTYPE_BUFFER); return WS_FATAL_ERROR; } @@ -5121,7 +5173,8 @@ int wolfSSH_SFTP_RecvLSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) } } else { - if (SFTP_SetHeader(ssh, reqId, WOLFSSH_FTP_ATTRS, sz, out) != WS_SUCCESS) { + if (SFTP_SetHeader(ssh, reqId, WOLFSSH_FTP_ATTRS, sz, out) + != WS_SUCCESS) { WFREE(out, ssh->ctx->heap, DYNTYPE_BUFFER); return WS_FATAL_ERROR; } @@ -5133,7 +5186,8 @@ int wolfSSH_SFTP_RecvLSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz) return ret; } -#if !defined(USE_WINDOWS_API) && !defined(WOLFSSH_ZEPHYR) && !defined(WOLFSSH_SFTP_SETMODE) +#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(void* fs, char* name, word32 mode) { @@ -5145,7 +5199,8 @@ static int SFTP_SetMode(void* fs, char* name, word32 mode) { } #endif -#if !defined(USE_WINDOWS_API) && !defined(WOLFSSH_ZEPHYR) && !defined(WOLFSSH_SFTP_SETMODEHANDLE) +#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) { @@ -5161,7 +5216,8 @@ static int SFTP_SetModeHandle(void* fs, WFD handle, word32 mode) { /* sets a files attributes * returns WS_SUCCESS on success */ -static int SFTP_SetFileAttributes(WOLFSSH* ssh, char* name, WS_SFTP_FILEATRB* atr) +static int SFTP_SetFileAttributes(WOLFSSH* ssh, + char* name, WS_SFTP_FILEATRB* atr) { int ret = WS_SUCCESS; @@ -5201,7 +5257,8 @@ static int SFTP_SetFileAttributes(WOLFSSH* ssh, char* name, WS_SFTP_FILEATRB* at /* sets a files attributes * returns WS_SUCCESS on success */ -static int SFTP_SetFileAttributesHandle(WOLFSSH* ssh, WFD handle, WS_SFTP_FILEATRB* atr) +static int SFTP_SetFileAttributesHandle(WOLFSSH* ssh, + WFD handle, WS_SFTP_FILEATRB* atr) { int ret = WS_SUCCESS; @@ -6153,7 +6210,8 @@ static WS_SFTPNAME* wolfSSH_SFTP_DoName(WOLFSSH* ssh) count--; if (tmp == NULL) { /* error case free list and exit */ - WLOG(WS_LOG_SFTP, "Memory error when creating new name structure"); + WLOG(WS_LOG_SFTP, + "Memory error when creating new name structure"); ret = WS_MEMORY_E; break; } @@ -6170,7 +6228,8 @@ static WS_SFTPNAME* wolfSSH_SFTP_DoName(WOLFSSH* ssh) } tmp->fSz = sz; if (sz > 0) { - tmp->fName = (char*)WMALLOC(sz + 1, tmp->heap, DYNTYPE_SFTP); + tmp->fName = (char*)WMALLOC(sz + 1, + tmp->heap, DYNTYPE_SFTP); if (tmp->fName == NULL) { ret = WS_MEMORY_E; break; @@ -6439,8 +6498,9 @@ WS_SFTPNAME* wolfSSH_SFTP_LS(WOLFSSH* ssh, char* dir) case STATE_LS_REALPATH: state->name = wolfSSH_SFTP_RealPath(ssh, dir); if (state->name == NULL) { - if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE && - ssh->error != WS_REKEYING) { + if (ssh->error != WS_WANT_READ + && ssh->error != WS_WANT_WRITE + && ssh->error != WS_REKEYING) { wolfSSH_SFTP_ClearState(ssh, STATE_ID_LS); } return NULL; @@ -6452,8 +6512,9 @@ WS_SFTPNAME* wolfSSH_SFTP_LS(WOLFSSH* ssh, char* dir) if (wolfSSH_SFTP_OpenDir(ssh, (byte*)state->name->fName, state->name->fSz) != WS_SUCCESS) { WLOG(WS_LOG_SFTP, "Unable to open directory"); - if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE && - ssh->error != WS_REKEYING) { + if (ssh->error != WS_WANT_READ + && ssh->error != WS_WANT_WRITE + && ssh->error != WS_REKEYING) { wolfSSH_SFTPNAME_list_free(state->name); state->name = NULL; wolfSSH_SFTP_ClearState(ssh, STATE_ID_LS); } @@ -6469,8 +6530,9 @@ WS_SFTPNAME* wolfSSH_SFTP_LS(WOLFSSH* ssh, char* dir) if (wolfSSH_SFTP_GetHandle(ssh, state->handle, (word32*)&state->sz) != WS_SUCCESS) { WLOG(WS_LOG_SFTP, "Unable to get handle"); - if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE && - ssh->error != WS_REKEYING) { + if (ssh->error != WS_WANT_READ + && ssh->error != WS_WANT_WRITE + && ssh->error != WS_REKEYING) { wolfSSH_SFTP_ClearState(ssh, STATE_ID_LS); } return NULL; @@ -6483,8 +6545,9 @@ WS_SFTPNAME* wolfSSH_SFTP_LS(WOLFSSH* ssh, char* dir) * times so we have to assign to state->name later. */ names = wolfSSH_SFTP_ReadDir(ssh, state->handle, state->sz); if (names == NULL) { - if (ssh->error == WS_WANT_READ || ssh->error == WS_WANT_WRITE || - ssh->error == WS_REKEYING) { + if (ssh->error == WS_WANT_READ + || ssh->error == WS_WANT_WRITE + || ssh->error == WS_REKEYING) { return NULL; } WLOG(WS_LOG_SFTP, "Error reading directory"); @@ -6508,12 +6571,12 @@ WS_SFTPNAME* wolfSSH_SFTP_LS(WOLFSSH* ssh, char* dir) if (ssh->error == WS_WANT_READ || ssh->error == WS_WANT_WRITE || ssh->error == WS_REKEYING) { - /* State does not change so we will get back to this case - * clause in non-blocking mode. */ + /* State does not change so we will get back to this + * case clause in non-blocking mode. */ return NULL; } WLOG(WS_LOG_SFTP, "Error reading directory"); - /* fall through because the handle should always be closed. */ + /* fall through, the handle should always be closed */ } } @@ -6525,8 +6588,9 @@ WS_SFTPNAME* wolfSSH_SFTP_LS(WOLFSSH* ssh, char* dir) if (wolfSSH_SFTP_Close(ssh, state->handle, state->sz) != WS_SUCCESS) { WLOG(WS_LOG_SFTP, "Error closing handle"); - if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE && - ssh->error != WS_REKEYING) { + if (ssh->error != WS_WANT_READ + && ssh->error != WS_WANT_WRITE + && ssh->error != WS_REKEYING) { wolfSSH_SFTPNAME_list_free(state->name); state->name = NULL; wolfSSH_SFTP_ClearState(ssh, STATE_ID_LS); @@ -6576,7 +6640,8 @@ int wolfSSH_SFTP_CHMOD(WOLFSSH* ssh, char* n, char* oct) case STATE_CHMOD_GET: /* get current attributes of path */ if ((ret = wolfSSH_SFTP_STAT(ssh, n, &state->atr)) != WS_SUCCESS) { - if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE) { + if (ssh->error != WS_WANT_READ + && ssh->error != WS_WANT_WRITE) { break; } return ret; @@ -6618,6 +6683,7 @@ static int SFTP_STAT(WOLFSSH* ssh, char* dir, WS_SFTP_FILEATRB* atr, byte type) { WS_SFTP_LSTAT_STATE* state = NULL; int ret; + int ret_fatal = 0; word32 localIdx; WLOG(WS_LOG_SFTP, "Entering SFTP_STAT()"); @@ -6659,6 +6725,7 @@ static int SFTP_STAT(WOLFSSH* ssh, char* dir, WS_SFTP_FILEATRB* atr, byte type) ssh->error == WS_WANT_WRITE) return WS_FATAL_ERROR; else { + ret_fatal = 1; state->state = STATE_LSTAT_CLEANUP; continue; } @@ -6677,13 +6744,14 @@ static int SFTP_STAT(WOLFSSH* ssh, char* dir, WS_SFTP_FILEATRB* atr, byte type) return WS_FATAL_ERROR; else { state->state = STATE_LSTAT_CLEANUP; + ret_fatal = 1; continue; } } state->state = STATE_LSTAT_CHECK_REQ_ID; - if (wolfSSH_SFTP_buffer_create(ssh, &state->buffer, ret) != - WS_SUCCESS) { + if (wolfSSH_SFTP_buffer_create(ssh, &state->buffer, ret) + != WS_SUCCESS) { ssh->error = WS_MEMORY_E; return WS_FATAL_ERROR; } @@ -6758,7 +6826,10 @@ static int SFTP_STAT(WOLFSSH* ssh, char* dir, WS_SFTP_FILEATRB* atr, byte type) WFREE(ssh->lstatState, ssh->ctx->heap, DYNTYPE_SFTP_STATE); ssh->lstatState = NULL; } - return WS_SUCCESS; + if(ret_fatal) + return WS_FATAL_ERROR; + else + return WS_SUCCESS; default: WLOG(WS_LOG_SFTP, "Bad SFTP LSTAT state, program error"); @@ -6871,7 +6942,8 @@ int wolfSSH_SFTP_SetSTAT(WOLFSSH* ssh, char* dir, WS_SFTP_FILEATRB* atr) /* send header and type specific data */ case STATE_SET_ATR_SEND: if (wolfSSH_SFTP_buffer_send(ssh, &state->buffer) < 0) { - if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE) { + if (ssh->error != WS_WANT_READ + && ssh->error != WS_WANT_WRITE) { ret = WS_FATAL_ERROR; break; } @@ -6888,7 +6960,8 @@ int wolfSSH_SFTP_SetSTAT(WOLFSSH* ssh, char* dir, WS_SFTP_FILEATRB* atr) case STATE_SET_ATR_GET: maxSz = SFTP_GetHeader(ssh, &state->reqId, &type, &state->buffer); if (maxSz <= 0) { - if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE) { + if (ssh->error != WS_WANT_READ + && ssh->error != WS_WANT_WRITE) { ret = WS_FATAL_ERROR; break; } @@ -6901,8 +6974,8 @@ int wolfSSH_SFTP_SetSTAT(WOLFSSH* ssh, char* dir, WS_SFTP_FILEATRB* atr) break; } - if (wolfSSH_SFTP_buffer_create(ssh, &state->buffer, maxSz) != - WS_SUCCESS) { + if (wolfSSH_SFTP_buffer_create(ssh, &state->buffer, maxSz) + != WS_SUCCESS) { ret = WS_MEMORY_E; break; } @@ -6915,7 +6988,8 @@ int wolfSSH_SFTP_SetSTAT(WOLFSSH* ssh, char* dir, WS_SFTP_FILEATRB* atr) ret = wolfSSH_SFTP_buffer_read(ssh, &state->buffer, wolfSSH_SFTP_buffer_size(&state->buffer)); if (ret < 0) { - if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE) { + if (ssh->error != WS_WANT_READ + && ssh->error != WS_WANT_WRITE) { ret = WS_FATAL_ERROR; break; } @@ -7264,7 +7338,8 @@ int wolfSSH_SFTP_SendWritePacket(WOLFSSH* ssh, byte* handle, word32 handleSz, case STATE_SEND_WRITE_DO_STATUS: WLOG(WS_LOG_SFTP, "SFTP SEND_WRITE STATE: DO_STATUS"); - status = wolfSSH_SFTP_DoStatus(ssh, state->reqId, &state->buffer); + status = wolfSSH_SFTP_DoStatus(ssh, + state->reqId, &state->buffer); if (status < 0) { ret = WS_FATAL_ERROR; } @@ -7521,7 +7596,8 @@ int wolfSSH_SFTP_SendReadPacket(WOLFSSH* ssh, byte* handle, word32 handleSz, return WS_FATAL_ERROR; } wolfSSH_SFTP_buffer_rewind(&state->buffer); - ret = wolfSSH_SFTP_DoStatus(ssh, state->reqId, &state->buffer); + ret = wolfSSH_SFTP_DoStatus(ssh, + state->reqId, &state->buffer); wolfSSH_SFTP_buffer_free(ssh, &state->buffer); if (ret == WOLFSSH_FTP_OK || ret == WOLFSSH_FTP_EOF) { WLOG(WS_LOG_SFTP, "OK or EOF found"); @@ -7742,7 +7818,8 @@ WS_SFTPNAME* wolfSSH_SFTP_ReadDir(WOLFSSH* ssh, byte* handle, case STATE_READDIR_NAME: name = wolfSSH_SFTP_DoName(ssh); if (name == NULL) { - if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE) { + if (ssh->error != WS_WANT_READ + && ssh->error != WS_WANT_WRITE) { wolfSSH_SFTP_ClearState(ssh, STATE_ID_READDIR); } return NULL; @@ -8003,7 +8080,8 @@ int wolfSSH_SFTP_Rename(WOLFSSH* ssh, const char* old, const char* nw) /* add old name to the packet */ wolfSSH_SFTP_buffer_seek(&state->buffer, 0, WOLFSSH_SFTP_HEADER); - wolfSSH_SFTP_buffer_c32toa(&state->buffer, (word32)WSTRLEN(old)); + wolfSSH_SFTP_buffer_c32toa(&state->buffer, + (word32)WSTRLEN(old)); WMEMCPY(wolfSSH_SFTP_buffer_data(&state->buffer) + wolfSSH_SFTP_buffer_idx(&state->buffer), (byte*)old, WSTRLEN(old)); @@ -8012,7 +8090,8 @@ int wolfSSH_SFTP_Rename(WOLFSSH* ssh, const char* old, const char* nw) (word32)WSTRLEN(old)); /* add new name to the packet */ - wolfSSH_SFTP_buffer_c32toa(&state->buffer, (word32)WSTRLEN(nw)); + wolfSSH_SFTP_buffer_c32toa(&state->buffer, + (word32)WSTRLEN(nw)); WMEMCPY(wolfSSH_SFTP_buffer_data(&state->buffer) + wolfSSH_SFTP_buffer_idx(&state->buffer), (byte*)nw, WSTRLEN(nw)); @@ -8051,7 +8130,8 @@ int wolfSSH_SFTP_Rename(WOLFSSH* ssh, const char* old, const char* nw) case STATE_RENAME_GET_HEADER: WLOG(WS_LOG_SFTP, "SFTP RENAME STATE: GET_HEADER"); /* Get response */ - ret = SFTP_GetHeader(ssh, &state->reqId, &type, &state->buffer); + ret = SFTP_GetHeader(ssh, &state->reqId, + &type, &state->buffer); if (ret <= 0) { if (ssh->error == WS_WANT_READ || ssh->error == WS_WANT_WRITE) { @@ -8179,7 +8259,8 @@ int wolfSSH_SFTP_Remove(WOLFSSH* ssh, char* f) case STATE_RM_LSTAT: /* check file is there to be removed */ if ((ret = wolfSSH_SFTP_LSTAT(ssh, f, &atrb)) != WS_SUCCESS) { - if (ssh->error != WS_WANT_WRITE && ssh->error != WS_WANT_READ) { + if (ssh->error != WS_WANT_WRITE + && ssh->error != WS_WANT_READ) { WLOG(WS_LOG_SFTP, "Error verifying file"); wolfSSH_SFTP_ClearState(ssh, STATE_ID_RM); } @@ -8192,7 +8273,8 @@ int wolfSSH_SFTP_Remove(WOLFSSH* ssh, char* f) ret = SendPacketType(ssh, WOLFSSH_FTP_REMOVE, (byte*)f, (word32)WSTRLEN(f)); if (ret != WS_SUCCESS) { - if (ssh->error != WS_WANT_WRITE && ssh->error != WS_WANT_READ) { + if (ssh->error != WS_WANT_WRITE + && ssh->error != WS_WANT_READ) { wolfSSH_SFTP_ClearState(ssh, STATE_ID_RM); } return ret; @@ -8203,7 +8285,8 @@ int wolfSSH_SFTP_Remove(WOLFSSH* ssh, char* f) case STATE_RM_GET: ret = SFTP_GetHeader(ssh, &state->reqId, &type, &state->buffer); if (ret <= 0 || type != WOLFSSH_FTP_STATUS) { - if (ssh->error != WS_WANT_WRITE && ssh->error != WS_WANT_READ) { + if (ssh->error != WS_WANT_WRITE + && ssh->error != WS_WANT_READ) { WLOG(WS_LOG_SFTP, "Unexpected packet type"); wolfSSH_SFTP_ClearState(ssh, STATE_ID_RM); } @@ -8221,7 +8304,8 @@ int wolfSSH_SFTP_Remove(WOLFSSH* ssh, char* f) ret = wolfSSH_SFTP_buffer_read(ssh, &state->buffer, wolfSSH_SFTP_buffer_size(&state->buffer)); if (ret < 0) { - if (ssh->error != WS_WANT_WRITE && ssh->error != WS_WANT_READ) { + if (ssh->error != WS_WANT_WRITE + && ssh->error != WS_WANT_READ) { WLOG(WS_LOG_SFTP, "Unexpected packet type"); wolfSSH_SFTP_ClearState(ssh, STATE_ID_RM); } @@ -8282,7 +8366,8 @@ int wolfSSH_SFTP_RMDIR(WOLFSSH* ssh, char* dir) ret = SendPacketType(ssh, WOLFSSH_FTP_RMDIR, (byte*)dir, (word32)WSTRLEN(dir)); if (ret != WS_SUCCESS) { - if (ssh->error != WS_WANT_READ && ssh->error != WS_WANT_WRITE) { + if (ssh->error != WS_WANT_READ + && ssh->error != WS_WANT_WRITE) { wolfSSH_SFTP_ClearState(ssh, STATE_ID_RMDIR); } return ret; @@ -8515,8 +8600,8 @@ int wolfSSH_SFTP_Get(WOLFSSH* ssh, char* from, NO_BREAK; case STATE_GET_LSTAT: - WLOG(WS_LOG_SFTP, "SFTP GET STATE: LSTAT"); - ret = wolfSSH_SFTP_LSTAT(ssh, from, &state->attrib); + WLOG(WS_LOG_SFTP, "SFTP GET STATE: STAT"); + ret = wolfSSH_SFTP_STAT(ssh, from, &state->attrib); if (ret != WS_SUCCESS) { if (ssh->error == WS_WANT_READ || ssh->error == WS_WANT_WRITE) @@ -8526,7 +8611,9 @@ int wolfSSH_SFTP_Get(WOLFSSH* ssh, char* from, continue; } if ((state->attrib.per & FILEATRB_PER_MASK_TYPE) - != FILEATRB_PER_FILE) { + != FILEATRB_PER_FILE + && (state->attrib.per & FILEATRB_PER_MASK_TYPE) + != FILEATRB_PER_LINK) { WLOG(WS_LOG_SFTP, "Not a file"); ssh->error = WS_SFTP_NOT_FILE_E; ret = WS_FATAL_ERROR; @@ -8627,8 +8714,8 @@ int wolfSSH_SFTP_Get(WOLFSSH* ssh, char* from, { DWORD bytesWritten = 0; if ((WriteFile(state->fileHandle, state->r, sz, - &bytesWritten, &state->offset) == 0) || - ((DWORD)sz != bytesWritten)) + &bytesWritten, &state->offset) == 0) + || ((DWORD)sz != bytesWritten)) { WLOG(WS_LOG_SFTP, "Error writing to file"); ssh->error = WS_BAD_FILE_E; @@ -8767,7 +8854,8 @@ int wolfSSH_SFTP_Put(WOLFSSH* ssh, char* from, char* to, byte resume, WLOG(WS_LOG_SFTP, "SFTP PUT STATE: OPEN LOCAL"); #ifndef USE_WINDOWS_API { - WS_SFTP_FILEATRB fileAtr = { 0 }; + WS_SFTP_FILEATRB fileAtr; + WMEMSET(&fileAtr, 0, sizeof(fileAtr)); if (SFTP_GetAttributes(ssh->fs, from, &fileAtr, 1, ssh->ctx->heap) == WS_SUCCESS) { diff --git a/src/wolfterm.c b/src/wolfterm.c index 659256838..691ff388a 100644 --- a/src/wolfterm.c +++ b/src/wolfterm.c @@ -1,6 +1,6 @@ /* wolfterm.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/tests/api.c b/tests/api.c index 0e483e204..ce6a02ab7 100644 --- a/tests/api.c +++ b/tests/api.c @@ -1,6 +1,6 @@ /* api.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -28,6 +28,7 @@ #include <wolfssl/options.h> #endif #include <wolfssl/wolfcrypt/wc_port.h> +#include <wolfssh/port.h> #include <stdio.h> #include <wolfssh/ssh.h> @@ -38,8 +39,9 @@ #ifdef WOLFSSH_SFTP #define WOLFSSH_TEST_LOCKING - #define WOLFSSH_TEST_THREADING - + #ifndef SINGLE_THREADED + #define WOLFSSH_TEST_THREADING + #endif #define WOLFSSH_TEST_SERVER #define WOLFSSH_TEST_ECHOSERVER #endif @@ -120,13 +122,13 @@ char* myoptarg = NULL; #define AssertStrLE(x, y) AssertStr(x, y, <=, >) #define AssertPtr(x, y, op, er) do { \ - PRAGMA_GCC_DIAG_PUSH; \ + PRAGMA_GCC_DIAG_PUSH \ /* remarkably, without this inhibition, */ \ /* the _Pragma()s make the declarations warn. */ \ - PRAGMA_GCC("GCC diagnostic ignored \"-Wdeclaration-after-statement\""); \ + PRAGMA_GCC("GCC diagnostic ignored \"-Wdeclaration-after-statement\"") \ /* inhibit "ISO C forbids conversion of function pointer */ \ /* to object pointer type [-Werror=pedantic]" */ \ - PRAGMA_GCC("GCC diagnostic ignored \"-Wpedantic\""); \ + PRAGMA_GCC("GCC diagnostic ignored \"-Wpedantic\"") \ void* _x = (void*)(x); \ void* _y = (void*)(y); \ Assert(_x op _y, ("%s " #op " %s", #x, #y), ("%p " #er " %p", _x, _y)); \ @@ -921,7 +923,7 @@ static void sftp_client_connect(WOLFSSH_CTX** ctx, WOLFSSH** ssh, int port) } build_addr(&clientAddr, host, port); - tcp_socket(&sockFd); + tcp_socket(&sockFd, ((struct sockaddr_in *)&clientAddr)->sin_family); ret = connect(sockFd, (const struct sockaddr *)&clientAddr, clientAddrSz); if (ret != 0){ wolfSSH_free(*ssh); @@ -954,7 +956,7 @@ static void test_wolfSSH_SFTP_SendReadPacket(void) func_args ser; tcp_ready ready; int argsCount; - int clientFd; + WS_SOCKET_T clientFd; const char* args[10]; WOLFSSH_CTX* ctx = NULL; @@ -1065,7 +1067,7 @@ static void test_wolfSSH_SFTP_SendReadPacket(void) /* close client socket down */ clientFd = wolfSSH_get_fd(ssh); - close(clientFd); + WCLOSESOCKET(clientFd); wolfSSH_free(ssh); wolfSSH_CTX_free(ctx); @@ -1305,8 +1307,258 @@ static void test_wolfSSH_RealPath(void) #else static void test_wolfSSH_RealPath(void) { ; } #endif + + +static void test_wolfSSH_SetAlgoList(void) +{ + const char* newKexList = "diffie-hellman-group1-sha1,ecdh-sha2-nistp521"; + const char* newKeyList = "rsa-sha2-512,ecdsa-sha2-nistp521"; + const char* newCipherList = "aes128-ctr,aes128-cbc"; + const char* newMacList = "hmac-sha1"; + const char* newKeyAccList = "ssh-rsa"; + const char* defaultKexList = NULL; + const char* defaultKeyList = NULL; + const char* defaultCipherList = NULL; + const char* defaultMacList = NULL; + const char* defaultKeyAccList = NULL; + const char* checkKexList = NULL; + const char* checkKeyList = NULL; + const char* checkCipherList = NULL; + const char* checkMacList = NULL; + const char* checkKeyAccList = NULL; + const char* rawKey = NULL; + WOLFSSH_CTX* ctx; + WOLFSSH* ssh; + byte* key; + word32 keySz; + + /* Create a ctx object. */ + ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL); + AssertNotNull(ctx); + + /* Check that the ctx's default algo lists are not null */ + defaultKexList = wolfSSH_CTX_GetAlgoListKex(ctx); + AssertNotNull(defaultKexList); + + defaultKeyList = wolfSSH_CTX_GetAlgoListKey(ctx); + AssertNotNull(defaultKeyList); + + defaultCipherList = wolfSSH_CTX_GetAlgoListCipher(ctx); + AssertNotNull(defaultCipherList); + + defaultMacList = wolfSSH_CTX_GetAlgoListMac(ctx); + AssertNotNull(defaultMacList); + + defaultKeyAccList = wolfSSH_CTX_GetAlgoListKeyAccepted(ctx); + AssertNotNull(defaultKeyAccList); + + /* Create a new ssh object. */ + ssh = wolfSSH_new(ctx); + AssertNotNull(ssh); + + /* Check that the ssh's default algo lists match the ctx's algo lists. */ + checkKexList = wolfSSH_GetAlgoListKex(ssh); + AssertPtrEq(checkKexList, defaultKexList); + + checkKeyList = wolfSSH_GetAlgoListKey(ssh); + AssertPtrEq(checkKeyList, defaultKeyList); + + checkCipherList = wolfSSH_GetAlgoListCipher(ssh); + AssertPtrEq(checkCipherList, defaultCipherList); + + checkMacList = wolfSSH_GetAlgoListMac(ssh); + AssertPtrEq(checkMacList, defaultMacList); + + checkKeyAccList = wolfSSH_GetAlgoListKeyAccepted(ssh); + AssertPtrEq(checkKeyAccList, defaultKeyAccList); + + /* Set the ssh's algo lists, check they match new value. */ + wolfSSH_SetAlgoListKex(ssh, newKexList); + checkKexList = wolfSSH_GetAlgoListKex(ssh); + AssertPtrEq(checkKexList, newKexList); + + wolfSSH_SetAlgoListKey(ssh, newKeyList); + checkKeyList = wolfSSH_GetAlgoListKey(ssh); + AssertPtrEq(checkKeyList, newKeyList); + + wolfSSH_SetAlgoListCipher(ssh, newCipherList); + checkCipherList = wolfSSH_GetAlgoListCipher(ssh); + AssertPtrEq(checkCipherList, newCipherList); + + wolfSSH_SetAlgoListMac(ssh, newMacList); + checkMacList = wolfSSH_GetAlgoListMac(ssh); + AssertPtrEq(checkMacList, newMacList); + + wolfSSH_SetAlgoListKeyAccepted(ssh, newKeyAccList); + checkKeyAccList = wolfSSH_GetAlgoListKeyAccepted(ssh); + AssertPtrEq(checkKeyAccList, newKeyAccList); + + /* Delete the ssh. */ + wolfSSH_free(ssh); + + /* Set new algo lists on the ctx. */ + wolfSSH_CTX_SetAlgoListKex(ctx, newKexList); + defaultKexList = wolfSSH_CTX_GetAlgoListKex(ctx); + AssertPtrEq(defaultKexList, newKexList); + + wolfSSH_CTX_SetAlgoListKey(ctx, newKeyList); + defaultKeyList = wolfSSH_CTX_GetAlgoListKey(ctx); + AssertPtrEq(checkKeyList, newKeyList); + + wolfSSH_CTX_SetAlgoListCipher(ctx, newCipherList); + defaultCipherList = wolfSSH_CTX_GetAlgoListCipher(ctx); + AssertNotNull(defaultCipherList); + + wolfSSH_CTX_SetAlgoListMac(ctx, newMacList); + defaultMacList = wolfSSH_CTX_GetAlgoListMac(ctx); + AssertNotNull(defaultMacList); + + wolfSSH_CTX_SetAlgoListKeyAccepted(ctx, newKeyAccList); + defaultKeyAccList = wolfSSH_CTX_GetAlgoListKeyAccepted(ctx); + AssertNotNull(defaultKeyAccList); + + /* Create a new ssh object. */ + ssh = wolfSSH_new(ctx); + AssertNotNull(ssh); + + /* Check that the ssh's default algo lists match the ctx's algo lists. */ + checkKexList = wolfSSH_GetAlgoListKex(ssh); + AssertPtrEq(checkKexList, defaultKexList); + + checkKeyList = wolfSSH_GetAlgoListKey(ssh); + AssertPtrEq(checkKeyList, defaultKeyList); + + checkCipherList = wolfSSH_GetAlgoListCipher(ssh); + AssertPtrEq(checkCipherList, defaultCipherList); + + checkMacList = wolfSSH_GetAlgoListMac(ssh); + AssertPtrEq(checkMacList, defaultMacList); + + checkKeyAccList = wolfSSH_GetAlgoListKeyAccepted(ssh); + AssertPtrEq(checkKeyAccList, defaultKeyAccList); + + /* Cleanup */ + wolfSSH_free(ssh); + wolfSSH_CTX_free(ctx); + + /* Create a ctx object. */ + ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL); + AssertNotNull(ctx); + + /* Check server ctx's key list is NULL. */ + defaultKeyList = wolfSSH_CTX_GetAlgoListKey(ctx); + AssertNull(defaultKeyList); + defaultKeyAccList = wolfSSH_CTX_GetAlgoListKeyAccepted(ctx); + AssertNotNull(defaultKeyAccList); + + /* Create a new ssh object. */ + ssh = wolfSSH_new(ctx); + AssertNotNull(ssh); + + /* Check server ssh's key list is NULL. */ + checkKeyList = wolfSSH_GetAlgoListKey(ssh); + AssertNull(checkKeyList); + + /* Delete the ssh. */ + wolfSSH_free(ssh); + + /* Set key on ctx. */ +#if !defined(WOLFSSH_NO_ECDSA) + rawKey = serverKeyEccDer; +#elif !defined(WOLFSSH_NO_RSA) + rawKey = serverKeyRsaDer; +#endif + AssertNotNull(rawKey); + AssertIntEQ(0, + ConvertHexToBin(rawKey, &key, &keySz, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)); + AssertIntEQ(WS_SUCCESS, + wolfSSH_CTX_UsePrivateKey_buffer(ctx, + key, keySz, WOLFSSH_FORMAT_ASN1)); + + /* Check ctx's key algo list is still null. */ + checkKeyList = wolfSSH_CTX_GetAlgoListKey(ctx); + AssertNull(checkKeyList); + + /* Create a new ssh object. */ + ssh = wolfSSH_new(ctx); + AssertNotNull(ssh); + + /* Check ssh's key algo list is null. */ + checkKeyList = wolfSSH_GetAlgoListKey(ssh); + AssertNull(checkKeyList); + + /* Set a new list on ssh. */ + wolfSSH_SetAlgoListKey(ssh, newKeyList); + checkKeyList = wolfSSH_GetAlgoListKey(ssh); + AssertPtrEq(checkKeyList, newKeyList); + + /* Cleanup */ + wolfSSH_free(ssh); + wolfSSH_CTX_free(ctx); + FreeBins(key, NULL, NULL, NULL); +} + + +static void test_wolfSSH_QueryAlgoList(void) +{ + const char* name; + word32 i, j; + int k; + + i = 0; + name = NULL; + do { + name = wolfSSH_QueryKex(&i); + AssertIntNE(i, 0); + } while (name != NULL); + + i = 0; + name = NULL; + do { + name = wolfSSH_QueryKey(&i); + AssertIntNE(i, 0); + } while (name != NULL); + + i = 0; + name = NULL; + do { + name = wolfSSH_QueryCipher(&i); + AssertIntNE(i, 0); + } while (name != NULL); + + i = 0; + name = NULL; + do { + name = wolfSSH_QueryMac(&i); + AssertIntNE(i, 0); + } while (name != NULL); + + /* This test case picks up where the index left off. */ + j = i; + name = wolfSSH_QueryKex(&i); + AssertNull(name); + i = j; + name = wolfSSH_QueryKey(&i); + AssertNull(name); + i = j; + name = wolfSSH_QueryCipher(&i); + AssertNull(name); + i = j; + name = wolfSSH_QueryMac(&i); + AssertNull(name); + + k = wolfSSH_CheckAlgoName("ssh-rsa"); + AssertIntEQ(WS_SUCCESS, k); + + k = wolfSSH_CheckAlgoName("not-an-algo@wolfssl.com"); + AssertIntEQ(WS_INVALID_ALGO_ID, k); +} + + #endif /* WOLFSSH_TEST_BLOCK */ + int wolfSSH_ApiTest(int argc, char** argv) { (void)argc; @@ -1337,6 +1589,8 @@ int wolfSSH_ApiTest(int argc, char** argv) test_wolfSSH_CTX_UseCert_buffer(); test_wolfSSH_CertMan(); test_wolfSSH_ReadKey(); + test_wolfSSH_QueryAlgoList(); + test_wolfSSH_SetAlgoList(); /* SCP tests */ test_wolfSSH_SCP_CB(); diff --git a/tests/api.h b/tests/api.h index a59be0814..8c8142561 100644 --- a/tests/api.h +++ b/tests/api.h @@ -1,6 +1,6 @@ /* api.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/tests/include.am b/tests/include.am index c3d7e7508..e8b1b548e 100644 --- a/tests/include.am +++ b/tests/include.am @@ -18,6 +18,9 @@ endif if BUILD_SFTP tests_unit_test_CPPFLAGS += -DWOLFSSH_SFTP endif +if BUILD_TERM +tests_unit_test_CPPFLAGS += -DWOLFSSH_TERM +endif if BUILD_SHELL tests_unit_test_CPPFLAGS += -DWOLFSSH_SHELL endif @@ -45,6 +48,9 @@ endif if BUILD_SFTP tests_api_test_CPPFLAGS += -DWOLFSSH_SFTP endif +if BUILD_TERM +tests_api_test_CPPFLAGS += -DWOLFSSH_TERM +endif if BUILD_SHELL tests_api_test_CPPFLAGS += -DWOLFSSH_SHELL endif @@ -77,6 +83,9 @@ endif if BUILD_SFTP tests_testsuite_test_CPPFLAGS += -DWOLFSSH_SFTP endif +if BUILD_TERM +tests_testsuite_test_CPPFLAGS += -DWOLFSSH_TERM +endif if BUILD_SHELL tests_testsuite_test_CPPFLAGS += -DWOLFSSH_SHELL endif diff --git a/tests/sftp.c b/tests/sftp.c index 1e4aa067e..b0aa3a751 100644 --- a/tests/sftp.c +++ b/tests/sftp.c @@ -1,6 +1,6 @@ /* sftp.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -23,6 +23,11 @@ #endif #include <stdio.h> +#ifdef WOLFSSL_USER_SETTINGS + #include <wolfssl/wolfcrypt/settings.h> +#else + #include <wolfssl/options.h> +#endif #include <wolfssh/settings.h> #if defined(WOLFSSH_SFTP) && !defined(SINGLE_THREADED) @@ -181,7 +186,9 @@ int wolfSSH_SftpTest(int flag) int argsCount; const char* args[10]; +#ifndef USE_WINDOWS_API char portNumber[8]; +#endif THREAD_TYPE serThread; diff --git a/tests/sftp.h b/tests/sftp.h index cb1860ba3..d69e2433a 100644 --- a/tests/sftp.h +++ b/tests/sftp.h @@ -1,6 +1,6 @@ /* sftp.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/tests/testsuite.c b/tests/testsuite.c index c9441b24d..6ab4a8507 100644 --- a/tests/testsuite.c +++ b/tests/testsuite.c @@ -1,6 +1,6 @@ /* testsuite.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -22,12 +22,6 @@ #include <config.h> #endif -#define WOLFSSH_TEST_CLIENT -#define WOLFSSH_TEST_SERVER -#define WOLFSSH_TEST_THREADING -#define WOLFSSH_TEST_LOCKING - - #include <stdio.h> #ifdef WOLFSSL_USER_SETTINGS @@ -36,6 +30,13 @@ #include <wolfssl/options.h> #endif +#define WOLFSSH_TEST_CLIENT +#define WOLFSSH_TEST_SERVER +#ifndef SINGLE_THREADED + #define WOLFSSH_TEST_THREADING +#endif +#define WOLFSSH_TEST_LOCKING + #include <wolfssh/settings.h> #include <wolfssh/ssh.h> #include <wolfssh/test.h> diff --git a/tests/testsuite.h b/tests/testsuite.h index 7391237fa..c40bd09ec 100644 --- a/tests/testsuite.h +++ b/tests/testsuite.h @@ -1,6 +1,6 @@ /* testsuite.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/tests/unit.c b/tests/unit.c index 5c9898d3f..335813b6d 100644 --- a/tests/unit.c +++ b/tests/unit.c @@ -1,6 +1,6 @@ /* unit.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/tests/unit.h b/tests/unit.h index 39a1767ab..364a1925d 100644 --- a/tests/unit.h +++ b/tests/unit.h @@ -1,6 +1,6 @@ /* unit.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/wolfssh/agent.h b/wolfssh/agent.h index 97f3220a7..c3d6412aa 100644 --- a/wolfssh/agent.h +++ b/wolfssh/agent.h @@ -1,6 +1,6 @@ /* agent.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/wolfssh/certman.h b/wolfssh/certman.h index a4fe2c016..63e4542de 100644 --- a/wolfssh/certman.h +++ b/wolfssh/certman.h @@ -1,6 +1,6 @@ /* certman.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/wolfssh/certs_test.h b/wolfssh/certs_test.h index a5de5752a..1d60530ff 100644 --- a/wolfssh/certs_test.h +++ b/wolfssh/certs_test.h @@ -1,6 +1,6 @@ /* certs_test.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/wolfssh/error.h b/wolfssh/error.h index d1fdfdd27..9d3832fa3 100644 --- a/wolfssh/error.h +++ b/wolfssh/error.h @@ -1,6 +1,6 @@ /* error.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -132,8 +132,11 @@ enum WS_ErrorCodes { 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 = -1093 /* Update this to indicate last error */ + WS_MSGID_NOT_ALLOWED_E = -1094, /* Message not allowed before userauth */ + WS_ED25519_E = -1095, /* Ed25519 failure */ + WS_AUTH_PENDING = -1096, /* User authentication still pending */ + + WS_LAST_E = -1096 /* Update this to indicate last error */ }; diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 8b8c41ec7..286acaf9d 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -1,6 +1,6 @@ /* internal.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -37,6 +37,7 @@ #include <wolfssl/wolfcrypt/dh.h> #include <wolfssl/wolfcrypt/ecc.h> #include <wolfssl/wolfcrypt/rsa.h> +#include <wolfssl/wolfcrypt/curve25519.h> #ifdef WOLFSSH_SCP #include <wolfssh/wolfscp.h> #endif @@ -67,14 +68,9 @@ extern "C" { /* - * Force some options. Do not want ssh-rsa with SHA1 at anymore. Not ready - * for rsa-sha2-512 yet. + * Not ready for rsa-sha2-512 yet. */ -#undef WOLFSSH_NO_SSH_RSA_SHA1 -#ifndef WOLFSSH_YES_SSH_RSA_SHA1 - #define WOLFSSH_NO_SSH_RSA_SHA1 -#endif #undef WOLFSSH_NO_RSA_SHA2_512 #ifndef WOLFSSH_YES_RSA_SHA2_512 #define WOLFSSH_NO_RSA_SHA2_512 @@ -109,6 +105,13 @@ extern "C" { #define WOLFSSH_NO_SHA1 #endif +#if !defined(HAVE_ED25519) \ + || !defined(WOLFSSL_ED25519_STREAMING_VERIFY) \ + || !defined(HAVE_ED25519_KEY_IMPORT) \ + || !defined(HAVE_ED25519_KEY_EXPORT) + #undef WOLFSSH_NO_ED25519 + #define WOLFSSH_NO_ED25519 +#endif #if defined(NO_HMAC) || defined(WOLFSSH_NO_SHA1) #undef WOLFSSH_NO_HMAC_SHA1 @@ -156,15 +159,15 @@ extern "C" { #undef WOLFSSH_NO_ECDH_SHA2_NISTP521 #define WOLFSSH_NO_ECDH_SHA2_NISTP521 #endif -#if !defined(HAVE_ED25519) || defined(NO_SHA256) || 1 - /* ED25519 isn't supported yet. Force disabled. */ - #undef WOLFSSH_NO_ECDH_SHA2_ED25519 - #define WOLFSSH_NO_ECDH_SHA2_ED25519 -#endif -#if !defined(WOLFSSH_HAVE_LIBOQS) || defined(NO_SHA256) +#if !defined(WOLFSSH_HAVE_LIBOQS) || defined(NO_SHA256) \ + || defined(WOLFSSH_NO_ECDH_SHA2_NISTP256) #undef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 #define WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 #endif +#if !defined(HAVE_CURVE25519) || defined(NO_SHA256) + #undef WOLFSSH_NO_CURVE25519_SHA256 + #define WOLFSSH_NO_CURVE25519_SHA256 +#endif #if defined(WOLFSSH_NO_DH_GROUP1_SHA1) && \ defined(WOLFSSH_NO_DH_GROUP14_SHA1) && \ @@ -172,8 +175,8 @@ extern "C" { defined(WOLFSSH_NO_ECDH_SHA2_NISTP256) && \ defined(WOLFSSH_NO_ECDH_SHA2_NISTP384) && \ defined(WOLFSSH_NO_ECDH_SHA2_NISTP521) && \ - defined(WOLFSSH_NO_ECDH_SHA2_ED25519) && \ - defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256) + defined(WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256) && \ + defined(WOLFSSH_NO_CURVE25519_SHA256) #error "You need at least one key agreement algorithm." #endif @@ -223,7 +226,8 @@ extern "C" { defined(WOLFSSH_NO_RSA_SHA2_512) && \ defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256) && \ defined(WOLFSSH_NO_ECDSA_SHA2_NISTP384) && \ - defined(WOLFSSH_NO_ECDSA_SHA2_NISTP521) + defined(WOLFSSH_NO_ECDSA_SHA2_NISTP521) && \ + defined(WOLFSSH_NO_ED25519) #error "You need at least one signing algorithm." #endif @@ -312,6 +316,9 @@ enum { ID_DH_GROUP14_SHA256, #ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 ID_ECDH_NISTP256_KYBER_LEVEL1_SHA256, +#endif +#ifndef WOLFSSH_NO_CURVE25519_SHA256 + ID_CURVE25519_SHA256, #endif ID_EXTINFO_S, /* Pseudo-KEX to indicate server extensions. */ ID_EXTINFO_C, /* Pseudo-KEX to indicate client extensions. */ @@ -323,6 +330,7 @@ enum { ID_ECDSA_SHA2_NISTP256, ID_ECDSA_SHA2_NISTP384, ID_ECDSA_SHA2_NISTP521, + ID_ED25519, ID_X509V3_SSH_RSA, ID_X509V3_ECDSA_SHA2_NISTP256, ID_X509V3_ECDSA_SHA2_NISTP384, @@ -356,6 +364,11 @@ enum { }; +enum NameIdType { + TYPE_KEX, TYPE_KEY, TYPE_CIPHER, TYPE_MAC, TYPE_OTHER +}; + + #define WOLFSSH_MAX_NAMESZ 32 #ifndef WOLFSSH_MAX_CHN_NAMESZ @@ -430,8 +443,10 @@ enum { #define WOLFSSH_KEY_QUANTITY_REQ 1 #endif -WOLFSSH_LOCAL byte NameToId(const char*, word32); -WOLFSSH_LOCAL const char* IdToName(byte); + +WOLFSSH_LOCAL byte NameToId(const char* name, word32 nameSz); +WOLFSSH_LOCAL const char* IdToName(byte id); +WOLFSSH_LOCAL const char* NameByIndexType(byte type, word32* index); #define STATIC_BUFFER_LEN AES_BLOCK_SIZE @@ -483,6 +498,14 @@ struct WOLFSSH_CTX { WS_CallbackGlobalReq globalReqCb; /* Global Request Callback */ WS_CallbackReqSuccess reqSuccessCb; /* Global Request Success Callback */ WS_CallbackReqSuccess reqFailureCb; /* Global Request Failure Callback */ + WS_CallbackChannelOpen channelOpenCb; /* Channel Open Requested */ + WS_CallbackChannelOpen channelOpenConfCb; /* Channel Open Confirm */ + WS_CallbackChannelOpen channelOpenFailCb; /* Channel Open Fail */ + WS_CallbackChannelReq channelReqShellCb; /* Channel Request "Shell" */ + WS_CallbackChannelReq channelReqExecCb; /* Channel Request "Exec" */ + WS_CallbackChannelReq channelReqSubsysCb; /* Channel Request "Subsystem" */ + WS_CallbackChannelEof channelEofCb; /* Channel Eof Callback */ + WS_CallbackChannelClose channelCloseCb; /* Channel Close Callback */ #ifdef WOLFSSH_SCP WS_CallbackScpRecv scpRecvCb; /* SCP receive callback */ WS_CallbackScpSend scpSendCb; /* SCP send callback */ @@ -507,6 +530,11 @@ struct WOLFSSH_CTX { word32 highwaterMark; const char* banner; const char* sshProtoIdStr; + const char* algoListKex; + const char* algoListKey; + const char* algoListCipher; + const char* algoListMac; + const char* algoListKeyAccepted; word32 bannerSz; word32 windowSz; word32 maxPacketSz; @@ -515,6 +543,7 @@ struct WOLFSSH_CTX { #ifdef WOLFSSH_AGENT byte agentEnabled; #endif /* WOLFSSH_AGENT */ + WS_CallbackKeyingCompletion keyingCompletionCb; }; @@ -567,17 +596,20 @@ typedef struct HandshakeInfo { word32 generatorSz; #endif - byte useEcc; -#ifndef WOLFSSH_NO_ECDH_NISTP256_KYBER_LEVEL1_SHA256 - byte useEccKyber; -#endif + byte useDh:1; + byte useEcc:1; + byte useEccKyber:1; + byte useCurve25519:1; union { #ifndef WOLFSSH_NO_DH DhKey dh; #endif -#if !defined(WOLFSSH_NO_ECDSA) && !defined(WOLFSSH_NO_ECDH) +#ifndef WOLFSSH_NO_ECDH ecc_key ecc; +#endif +#ifndef WOLFSSH_NO_CURVE25519_SHA256 + curve25519_key curve25519; #endif } privKey; } HandshakeInfo; @@ -634,15 +666,24 @@ struct WOLFSSH { word32 rxCount; word32 highwaterMark; byte highwaterFlag; /* Set when highwater CB called */ - void* highwaterCtx; + void* highwaterCtx; /* Highwater CB context */ void* globalReqCtx; /* Global Request CB context */ void* reqSuccessCtx; /* Global Request Sucess CB context */ void* reqFailureCtx; /* Global Request Failure CB context */ + void* channelOpenCtx; /* Channel Open CB context */ + void* channelReqCtx; /* Channel Request CB context */ + void* channelEofCtx; /* Channel EOF CB context */ + void* channelCloseCtx; /* Channel Close CB context */ void* fs; /* File system handle */ word32 curSz; word32 seq; word32 peerSeq; word32 packetStartIdx; /* Current send packet start index */ + const char* algoListKex; + const char* algoListKey; + const char* algoListCipher; + const char* algoListMac; + const char* algoListKeyAccepted; byte acceptState; byte connectState; byte clientState; @@ -697,6 +738,7 @@ struct WOLFSSH { byte isClosed; byte clientOpenSSH; + byte kexId; byte blockSz; byte encryptId; byte macId; @@ -707,6 +749,9 @@ struct WOLFSSH { byte peerMacId; byte peerMacSz; byte peerAeadMode; +#ifndef WOLFSSH_NO_DH + word32 primeGroupSz; +#endif Ciphers encryptCipher; Ciphers decryptCipher; @@ -825,6 +870,7 @@ struct WOLFSSH { #if defined(WOLFSSH_TERM) || defined(WOLFSSH_SHELL) word32 exitStatus; #endif + void* keyingCompletionCtx; }; @@ -961,6 +1007,10 @@ WOLFSSH_LOCAL int SendChannelExitStatus(WOLFSSH* ssh, word32 channelId, word32 exitStatus); WOLFSSH_LOCAL int GenerateKey(byte, byte, byte*, word32, const byte*, word32, const byte*, word32, const byte*, word32, byte doKeyPad); +#if !defined(WOLFSSH_NO_ECDSA) || !defined(WOLFSSH_NO_ECDH) +WOLFSSH_LOCAL int wcPrimeForId(byte); +#endif +WOLFSSH_LOCAL enum wc_HashType HashForId(byte); enum AcceptStates { @@ -1096,6 +1146,21 @@ enum WS_MessageIds { }; +/* Allows the server to receive up to KEXDH GEX Request during KEX. */ +#define MSGID_KEXDH_LIMIT MSGID_KEXDH_GEX_REQUEST + +/* The endpoints should not allow message IDs greater than or + * equal to msgid 80 before user authentication is complete. + * Per RFC 4252 section 6. */ +#define MSGID_USERAUTH_LIMIT 80 + +/* The client should only send the user auth request message + * (50), it should not accept it. The server should only receive + * the user auth request message, it should not accept the other + * user auth messages, it sends them. (>50) */ +#define MSGID_USERAUTH_RESTRICT 50 + + #define CHANNEL_EXTENDED_DATA_STDERR WOLFSSH_EXT_DATA_STDERR @@ -1149,7 +1214,8 @@ enum WS_BufferTypes { #define SCP_CONFIRM_FATAL 0x02 /* binary 2 */ enum WS_ScpStates { - SCP_PARSE_COMMAND = 0, + SCP_SETUP = 0, + SCP_PARSE_COMMAND, SCP_SINK, SCP_SINK_BEGIN, SCP_TRANSFER, @@ -1206,8 +1272,9 @@ WOLFSSH_LOCAL int wsScpSendCallback(WOLFSSH*, int, const char*, char*, word32, WOLFSSH_LOCAL int wolfSSH_CleanPath(WOLFSSH* ssh, char* in); #ifndef WOLFSSH_NO_RSA -WOLFSSH_LOCAL int wolfSSH_RsaVerify(byte *sig, word32 sigSz, - const byte* digest, word32 digestSz, +WOLFSSH_LOCAL int wolfSSH_RsaVerify( + const byte *sig, word32 sigSz, + const byte* encDigest, word32 encDigestSz, RsaKey* key, void* heap, const char* loc); #endif WOLFSSH_LOCAL void DumpOctetString(const byte*, word32); @@ -1278,6 +1345,10 @@ enum TerminalModes { }; #endif /* WOLFSSH_TERM */ + +#define WOLFSSL_V5_7_0 0x05007000 + + #ifdef __cplusplus } #endif diff --git a/wolfssh/keygen.h b/wolfssh/keygen.h index 52b4f34bb..9cf58e7c7 100644 --- a/wolfssh/keygen.h +++ b/wolfssh/keygen.h @@ -1,6 +1,6 @@ /* keygen.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/wolfssh/log.h b/wolfssh/log.h index a51d37835..26f202124 100644 --- a/wolfssh/log.h +++ b/wolfssh/log.h @@ -1,6 +1,6 @@ /* log.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/wolfssh/misc.h b/wolfssh/misc.h index d0501cf8a..55dd6cf80 100644 --- a/wolfssh/misc.h +++ b/wolfssh/misc.h @@ -1,6 +1,6 @@ /* misc.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/wolfssh/port.h b/wolfssh/port.h index 3a4820efd..b65d32fd6 100644 --- a/wolfssh/port.h +++ b/wolfssh/port.h @@ -1,6 +1,6 @@ /* port.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/wolfssh/settings.h b/wolfssh/settings.h index e4aa01664..12e7527df 100644 --- a/wolfssh/settings.h +++ b/wolfssh/settings.h @@ -1,6 +1,6 @@ /* settings.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index 218a44484..8f6a2a115 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -1,6 +1,6 @@ /* ssh.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -90,11 +90,87 @@ WOLFSSH_API int wolfSSH_ReadKey_file(const char* name, byte** out, word32* outSz, const byte** outType, word32* outTypeSz, byte* isPrivate, void* heap); +WOLFSSH_API int wolfSSH_CTX_SetAlgoListKex(WOLFSSH_CTX* ctx, const char* list); +WOLFSSH_API const char* wolfSSH_CTX_GetAlgoListKex(WOLFSSH_CTX* ctx); +WOLFSSH_API int wolfSSH_SetAlgoListKex(WOLFSSH* ssh, const char* list); +WOLFSSH_API const char* wolfSSH_GetAlgoListKex(WOLFSSH* ssh); + +WOLFSSH_API int wolfSSH_CTX_SetAlgoListKey(WOLFSSH_CTX* ctx, const char* list); +WOLFSSH_API const char* wolfSSH_CTX_GetAlgoListKey(WOLFSSH_CTX* ctx); +WOLFSSH_API int wolfSSH_SetAlgoListKey(WOLFSSH* ssh, const char* list); +WOLFSSH_API const char* wolfSSH_GetAlgoListKey(WOLFSSH* ssh); + +WOLFSSH_API int wolfSSH_CTX_SetAlgoListCipher(WOLFSSH_CTX* ctx, + const char* list); +WOLFSSH_API const char* wolfSSH_CTX_GetAlgoListCipher(WOLFSSH_CTX* ctx); +WOLFSSH_API int wolfSSH_SetAlgoListCipher(WOLFSSH* ssh, const char* list); +WOLFSSH_API const char* wolfSSH_GetAlgoListCipher(WOLFSSH* ssh); + +WOLFSSH_API int wolfSSH_CTX_SetAlgoListMac(WOLFSSH_CTX* ctx, const char* list); +WOLFSSH_API const char* wolfSSH_CTX_GetAlgoListMac(WOLFSSH_CTX* ctx); +WOLFSSH_API int wolfSSH_SetAlgoListMac(WOLFSSH* ssh, const char* list); +WOLFSSH_API const char* wolfSSH_GetAlgoListMac(WOLFSSH* ssh); + +WOLFSSH_API int wolfSSH_CTX_SetAlgoListKeyAccepted(WOLFSSH_CTX* ctx, + const char* list); +WOLFSSH_API const char* wolfSSH_CTX_GetAlgoListKeyAccepted(WOLFSSH_CTX* ctx); +WOLFSSH_API int wolfSSH_SetAlgoListKeyAccepted(WOLFSSH* ssh, const char* list); +WOLFSSH_API const char* wolfSSH_GetAlgoListKeyAccepted(WOLFSSH* ssh); + +WOLFSSH_API int wolfSSH_CheckAlgoName(const char* name); + +WOLFSSH_API const char* wolfSSH_QueryKex(word32* index); +WOLFSSH_API const char* wolfSSH_QueryKey(word32* index); +WOLFSSH_API const char* wolfSSH_QueryCipher(word32* index); +WOLFSSH_API const char* wolfSSH_QueryMac(word32* index); + +typedef enum WS_Text { + WOLFSSH_TEXT_KEX_ALGO, + WOLFSSH_TEXT_KEX_CURVE, + WOLFSSH_TEXT_KEX_HASH, + + WOLFSSH_TEXT_CRYPTO_IN_CIPHER, + WOLFSSH_TEXT_CRYPTO_IN_MAC, + WOLFSSH_TEXT_CRYPTO_OUT_CIPHER, + WOLFSSH_TEXT_CRYPTO_OUT_MAC, +} WS_Text; + +/* + * Outputs the c-string representation of the data entry identified by the id to + * the character string str, writing no more than strSz bytes, including the + * terminating null byte ('\0'). + * + * Returns the number of characters written (excluding the null byte used to end + * output to strings), unless the output was truncated, in which case the return + * value is the number of characters (excluding the terminating null byte) which + * would have been written to the final string if enough space had been + * available. + * + * Thus, a return value of strSz or more means that the output was truncated. + */ + +WOLFSSH_API size_t wolfSSH_GetText(WOLFSSH *ssh, WS_Text id, char *str, + size_t strSz); + +typedef void (*WS_CallbackKeyingCompletion)(void *); +WOLFSSH_API void wolfSSH_SetKeyingCompletionCb(WOLFSSH_CTX*, + WS_CallbackKeyingCompletion); +WOLFSSH_API void wolfSSH_SetKeyingCompletionCbCtx(WOLFSSH*, + void*); #define WS_CHANNEL_ID_SELF 0 #define WS_CHANNEL_ID_PEER 1 +typedef enum { + WOLFSSH_SESSION_UNKNOWN = 0, + WOLFSSH_SESSION_SHELL, + WOLFSSH_SESSION_EXEC, + WOLFSSH_SESSION_SUBSYSTEM, + WOLFSSH_SESSION_TERMINAL, +} WS_SessionType; + + typedef enum WS_FwdCbAction { WOLFSSH_FWD_LOCAL_SETUP, WOLFSSH_FWD_LOCAL_CLEANUP, @@ -142,7 +218,41 @@ WOLFSSH_API int wolfSSH_ChannelRead(WOLFSSH_CHANNEL*, byte*, word32); WOLFSSH_API int wolfSSH_ChannelSend(WOLFSSH_CHANNEL*, const byte*, word32); WOLFSSH_API int wolfSSH_ChannelExit(WOLFSSH_CHANNEL*); WOLFSSH_API int wolfSSH_ChannelGetEof(WOLFSSH_CHANNEL*); - +WOLFSSH_API WS_SessionType wolfSSH_ChannelGetSessionType( + const WOLFSSH_CHANNEL* channel); +WOLFSSH_API const char* wolfSSH_ChannelGetSessionCommand( + const WOLFSSH_CHANNEL* channel); + +/* Channel callbacks */ +typedef int (*WS_CallbackChannelOpen)(WOLFSSH_CHANNEL* channel, void* ctx); +WOLFSSH_API int wolfSSH_CTX_SetChannelOpenCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelOpen cb); +WOLFSSH_API int wolfSSH_CTX_SetChannelOpenRespCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelOpen confCb, WS_CallbackChannelOpen failCb); +WOLFSSH_API int wolfSSH_SetChannelOpenCtx(WOLFSSH* ssh, void* ctx); +WOLFSSH_API void* wolfSSH_GetChannelOpenCtx(WOLFSSH* ssh); + +typedef int (*WS_CallbackChannelReq)(WOLFSSH_CHANNEL* channel, void* ctx); +WOLFSSH_API int wolfSSH_CTX_SetChannelReqShellCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelReq cb); +WOLFSSH_API int wolfSSH_CTX_SetChannelReqExecCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelReq cb); +WOLFSSH_API int wolfSSH_CTX_SetChannelReqSubsysCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelReq cb); +WOLFSSH_API int wolfSSH_SetChannelReqCtx(WOLFSSH* ssh, void* ctx); +WOLFSSH_API void* wolfSSH_GetChannelReqCtx(WOLFSSH* ssh); + +typedef int (*WS_CallbackChannelEof)(WOLFSSH_CHANNEL* channel, void* ctx); +WOLFSSH_API int wolfSSH_CTX_SetChannelEofCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelEof cb); +WOLFSSH_API int wolfSSH_SetChannelEofCtx(WOLFSSH* ssh, void* ctx); +WOLFSSH_API void* wolfSSH_GetChannelEofCtx(WOLFSSH* ssh); + +typedef int (*WS_CallbackChannelClose)(WOLFSSH_CHANNEL* channel, void* ctx); +WOLFSSH_API int wolfSSH_CTX_SetChannelCloseCb(WOLFSSH_CTX* ctx, + WS_CallbackChannelClose cb); +WOLFSSH_API int wolfSSH_SetChannelCloseCtx(WOLFSSH* ssh, void* ctx); +WOLFSSH_API void* wolfSSH_GetChannelCloseCtx(WOLFSSH* ssh); WOLFSSH_API int wolfSSH_get_error(const WOLFSSH*); WOLFSSH_API const char* wolfSSH_get_error_name(const WOLFSSH*); @@ -275,13 +385,6 @@ WOLFSSH_API int wolfSSH_KDF(byte, byte, byte*, word32, const byte*, word32, WOLFSSH_API int wolfSSH_ConvertConsole(WOLFSSH*, WOLFSSH_HANDLE, byte*, word32); #endif -typedef enum { - WOLFSSH_SESSION_UNKNOWN = 0, - WOLFSSH_SESSION_SHELL, - WOLFSSH_SESSION_EXEC, - WOLFSSH_SESSION_SUBSYSTEM, - WOLFSSH_SESSION_TERMINAL, -} WS_SessionType; WOLFSSH_API int wolfSSH_DoModes(const byte* modes, word32 modesSz, int fd); WOLFSSH_API WS_SessionType wolfSSH_GetSessionType(const WOLFSSH*); @@ -333,7 +436,8 @@ enum WS_UserAuthResults WOLFSSH_USERAUTH_INVALID_PASSWORD, WOLFSSH_USERAUTH_REJECTED, WOLFSSH_USERAUTH_INVALID_PUBLICKEY, - WOLFSSH_USERAUTH_PARTIAL_SUCCESS + WOLFSSH_USERAUTH_PARTIAL_SUCCESS, + WOLFSSH_USERAUTH_WOULD_BLOCK }; enum WS_DisconnectReasonCodes { diff --git a/wolfssh/test.h b/wolfssh/test.h index d1b6ac100..c0467a9bf 100644 --- a/wolfssh/test.h +++ b/wolfssh/test.h @@ -1,6 +1,6 @@ /* test.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -221,7 +221,7 @@ #ifdef USE_WINDOWS_API #define WCLOSESOCKET(s) closesocket(s) - #define WSTARTTCP() do { WSADATA wsd; WSAStartup(0x0002, &wsd); } while(0) + #define WSTARTTCP() do { WSADATA wsd; (void)WSAStartup(0x0002, &wsd); } while(0) #elif defined(MICROCHIP_TCPIP) || defined(MICROCHIP_MPLAB_HARMONY) #ifdef MICROCHIP_MPLAB_HARMONY #define WCLOSESOCKET(s) TCPIP_TCP_Close((s)) @@ -519,7 +519,7 @@ static INLINE void build_addr(SOCKADDR_IN_T* addr, const char* peer, memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET_V; + hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; @@ -546,8 +546,10 @@ static INLINE void build_addr(SOCKADDR_IN_T* addr, const char* peer, #endif -static INLINE void tcp_socket(WS_SOCKET_T* sockFd) +static INLINE void tcp_socket(WS_SOCKET_T* sockFd, int targetProtocol) { + /* targetProtocol is only used if none of these platforms are defined. */ + WOLFSSH_UNUSED(targetProtocol); #ifdef MICROCHIP_MPLAB_HARMONY /* creates socket in listen or connect */ *sockFd = 0; @@ -558,7 +560,7 @@ static INLINE void tcp_socket(WS_SOCKET_T* sockFd) #elif defined(WOLFSSL_NUCLEUS) *sockFd = NU_Socket(NU_FAMILY_IP, NU_TYPE_STREAM, 0); #else - *sockFd = socket(AF_INET_V, SOCK_STREAM, 0); + *sockFd = socket(targetProtocol, SOCK_STREAM, 0); #endif #ifdef USE_WINDOWS_API @@ -637,8 +639,7 @@ static INLINE void tcp_listen(WS_SOCKET_T* sockfd, word16* port, int useAnyAddr) /* don't use INADDR_ANY by default, firewall may block, make user switch on */ build_addr(&addr, (useAnyAddr ? INADDR_ANY : wolfSshIp), *port); - tcp_socket(sockfd); - + tcp_socket(sockfd, ((struct sockaddr_in *)&addr)->sin_family); #if !defined(USE_WINDOWS_API) && !defined(WOLFSSL_MDK_ARM) \ && !defined(WOLFSSL_KEIL_TCP_NET) \ && !defined(WOLFSSL_NUCLEUS) \ @@ -933,7 +934,9 @@ static INLINE void WaitTcpReady(tcp_ready* ready) #endif #endif #else - #define WOLFSSH_THREAD WOLFSSL_THREAD + #ifndef WOLFSSH_THREAD + #define WOLFSSH_THREAD WOLFSSL_THREAD + #endif #endif #if (LIBWOLFSSL_VERSION_HEX < WOLFSSL_V5_6_4) \ @@ -1133,6 +1136,9 @@ static int Base16_Decode(const byte* in, word32 inLen, word32 inIdx = 0; word32 outIdx = 0; + if (in == NULL || out == NULL || outLen == NULL) + return WS_BAD_ARGUMENT; + if (inLen == 1 && *outLen && in) { byte b = in[inIdx] - 0x30; /* 0 starts at 0x30 */ diff --git a/wolfssh/version.h b/wolfssh/version.h index 3c3e9cfdc..2ec51af01 100644 --- a/wolfssh/version.h +++ b/wolfssh/version.h @@ -1,6 +1,6 @@ /* version.h.in * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -35,8 +35,8 @@ extern "C" { #endif -#define LIBWOLFSSH_VERSION_STRING "1.4.15" -#define LIBWOLFSSH_VERSION_HEX 0x01004015 +#define LIBWOLFSSH_VERSION_STRING "1.4.18" +#define LIBWOLFSSH_VERSION_HEX 0x01004018 #ifdef __cplusplus } diff --git a/wolfssh/version.h.in b/wolfssh/version.h.in index e9a5cf04b..b44be3403 100644 --- a/wolfssh/version.h.in +++ b/wolfssh/version.h.in @@ -1,6 +1,6 @@ /* version.h.in * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/wolfssh/visibility.h b/wolfssh/visibility.h index ae41a312b..fa9da6819 100644 --- a/wolfssh/visibility.h +++ b/wolfssh/visibility.h @@ -1,6 +1,6 @@ /* visibility.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/wolfssh/wolfscp.h b/wolfssh/wolfscp.h index fedf57719..eba468dc2 100644 --- a/wolfssh/wolfscp.h +++ b/wolfssh/wolfscp.h @@ -1,6 +1,6 @@ /* wolfscp.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/wolfssh/wolfsftp.h b/wolfssh/wolfsftp.h index 8fbbdbb77..48dc90e4d 100644 --- a/wolfssh/wolfsftp.h +++ b/wolfssh/wolfsftp.h @@ -1,6 +1,6 @@ /* wolfsftp.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -128,6 +128,7 @@ struct WS_SFTP_FILEATRB_EX { #define FILEATRB_PER_MASK_TYPE 0770000 #define FILEATRB_PER_FILE 0100000 +#define FILEATRB_PER_LINK 0120000 #define FILEATRB_PER_DEV_CHAR 0020000 #define FILEATRB_PER_DIR 0040000 #define FILEATRB_PER_DEV_BLOCK 0060000 diff --git a/zephyr/samples/tests/prj.conf b/zephyr/samples/tests/prj.conf index 8bdd3f29b..6b679071a 100644 --- a/zephyr/samples/tests/prj.conf +++ b/zephyr/samples/tests/prj.conf @@ -2,11 +2,11 @@ CONFIG_MAIN_STACK_SIZE=32768 CONFIG_ENTROPY_GENERATOR=y CONFIG_INIT_STACKS=y -CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=131072 +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=524288 # Enable wolfSSH CONFIG_WOLFSSH=y -CONFIG_WOLFSSH_SETTINGS_FILE="samples/tests/user_settings.h" +CONFIG_WOLFSSH_SETTINGS_FILE="samples/tests/wolfssh_user_settings.h" CONFIG_WOLFSSH_SFTP_DEFAULT_DIR="/RAM:" # Pthreads diff --git a/zephyr/samples/tests/prj_nofs.conf b/zephyr/samples/tests/prj_nofs.conf new file mode 100644 index 000000000..4b628e8e8 --- /dev/null +++ b/zephyr/samples/tests/prj_nofs.conf @@ -0,0 +1,66 @@ +# Kernel options +CONFIG_MAIN_STACK_SIZE=32768 +CONFIG_ENTROPY_GENERATOR=y +CONFIG_INIT_STACKS=y +CONFIG_COMMON_LIBC_MALLOC_ARENA_SIZE=131072 + +# Enable wolfSSH +CONFIG_WOLFSSH=y +CONFIG_WOLFSSH_SETTINGS_FILE="samples/tests/wolfssh_user_settings_nofs.h" + +# Pthreads +CONFIG_PTHREAD_IPC=y + +# Clock for time() +CONFIG_POSIX_CLOCK=y + +# Networking +CONFIG_NETWORKING=y +CONFIG_NET_TEST=y +CONFIG_NET_IPV4=y +CONFIG_NET_IPV6=n +CONFIG_NET_TCP=y +CONFIG_NET_SOCKETS=y +CONFIG_NET_SOCKETS_POSIX_NAMES=y + +CONFIG_NET_TEST=y +CONFIG_NET_LOOPBACK=y + +# Network driver config +CONFIG_TEST_RANDOM_GENERATOR=y + +# Network address config +CONFIG_NET_CONFIG_SETTINGS=y +CONFIG_NET_CONFIG_NEED_IPV4=y +CONFIG_NET_CONFIG_MY_IPV4_ADDR="192.0.2.1" +CONFIG_NET_CONFIG_PEER_IPV4_ADDR="192.0.2.2" +CONFIG_NET_CONFIG_MY_IPV4_GW="192.0.2.2" + +CONFIG_NET_PKT_TX_COUNT=10 + +# Logging +CONFIG_PRINTK=y +CONFIG_LOG=y +CONFIG_LOG_MODE_IMMEDIATE=y +#CONFIG_WOLFSSH_DEBUG=y +#CONFIG_WOLFSSL_DEBUG=y +#CONFIG_DEBUG=y + +# Enable logging using RTT and UART +#CONFIG_CBPRINTF_LIBC_SUBSTS=y +#CONFIG_CBPRINTF_FP_SUPPORT=y +#CONFIG_CONSOLE=y +#CONFIG_LOG_BACKEND_UART=y +#CONFIG_LOG_BUFFER_SIZE=15360 + +# TLS configuration +CONFIG_WOLFSSL=y +CONFIG_WOLFSSL_BUILTIN=y +CONFIG_WOLFSSL_SETTINGS_FILE="samples/tests/wolfssl_user_settings_nofs.h" + +CONFIG_WOLFSSL_TLS_VERSION_1_2=y +CONFIG_WOLFSSL_KEY_EXCHANGE_ALL_ENABLED=y +CONFIG_WOLFSSL_CIPHER_ALL_ENABLED=y +CONFIG_WOLFSSL_MAC_ALL_ENABLED=y +CONFIG_WOLFSSL_HMAC_DRBG_ENABLED=y + diff --git a/zephyr/samples/tests/sample.yaml b/zephyr/samples/tests/sample.yaml index 4f6f359cf..23abc38b9 100644 --- a/zephyr/samples/tests/sample.yaml +++ b/zephyr/samples/tests/sample.yaml @@ -13,3 +13,9 @@ tests: platform_allow: qemu_x86 integration_platforms: - qemu_x86 + sample.lib.wolfssh_nofs_tests: + timeout: 200 + platform_allow: qemu_x86 + extra_args: CONF_FILE="prj_nofs.conf" + integration_platforms: + - qemu_x86 diff --git a/zephyr/samples/tests/tests.c b/zephyr/samples/tests/tests.c index 56d18c91b..69a8e3b26 100644 --- a/zephyr/samples/tests/tests.c +++ b/zephyr/samples/tests/tests.c @@ -1,6 +1,6 @@ /* tests.c * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * @@ -37,14 +37,15 @@ #include <stdio.h> #include <wolfssh/settings.h> #include <wolfssh/ssh.h> -#include <zephyr/fs/fs.h> -#include <zephyr/storage/disk_access.h> -#include <ff.h> - +#ifndef NO_FILESYSTEM #ifndef CONFIG_FAT_FILESYSTEM_ELM #error "This test is designed for FAT FS" #endif +#include <zephyr/fs/fs.h> +#include <zephyr/storage/disk_access.h> +#include <ff.h> +#endif #define CHECK_TEST_RETURN(func) do { \ printf("\tRunning %s... ", #func); \ @@ -60,6 +61,7 @@ int main(void) { int ret = 0; +#ifndef NO_FILESYSTEM static FATFS fat_fs; static struct fs_mount_t mnt_point = { .type = FS_FATFS, @@ -89,6 +91,7 @@ int main(void) < 0); CHECK_TEST_RETURN(fs_close(&zfp)); +#endif CHECK_TEST_RETURN(wolfSSH_UnitTest(0, NULL)); CHECK_TEST_RETURN(wolfSSH_TestsuiteTest(0, NULL)); diff --git a/zephyr/samples/tests/user_settings.h b/zephyr/samples/tests/wolfssh_user_settings.h similarity index 97% rename from zephyr/samples/tests/user_settings.h rename to zephyr/samples/tests/wolfssh_user_settings.h index 0f755a549..1cfbb585f 100644 --- a/zephyr/samples/tests/user_settings.h +++ b/zephyr/samples/tests/wolfssh_user_settings.h @@ -1,6 +1,6 @@ /* user_settings.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/zephyr/samples/tests/wolfssh_user_settings_nofs.h b/zephyr/samples/tests/wolfssh_user_settings_nofs.h new file mode 100644 index 000000000..5df7f407c --- /dev/null +++ b/zephyr/samples/tests/wolfssh_user_settings_nofs.h @@ -0,0 +1,68 @@ +/* user_settings.h + * + * Copyright (C) 2014-2024 wolfSSL Inc. + * + * This file is part of wolfSSH. + * + * wolfSSH is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef WOLFSSH_USER_SETTINGS_H +#define WOLFSSH_USER_SETTINGS_H + + +#ifdef __cplusplus +extern "C" { +#endif + +#include <wolfssl/wolfcrypt/types.h> + +#undef WOLFSSH_SCP +#define WOLFSSH_SCP + +#undef NO_APITEST_MAIN_DRIVER +#define NO_APITEST_MAIN_DRIVER + +#undef NO_TESTSUITE_MAIN_DRIVER +#define NO_TESTSUITE_MAIN_DRIVER + +#undef NO_UNITTEST_MAIN_DRIVER +#define NO_UNITTEST_MAIN_DRIVER + +#undef NO_MAIN_DRIVER +#define NO_MAIN_DRIVER + +#undef WS_NO_SIGNAL +#define WS_NO_SIGNAL + +#undef WS_USE_TEST_BUFFERS +#define WS_USE_TEST_BUFFERS + +#undef NO_WOLFSSL_DIR +#define NO_WOLFSSL_DIR + +#undef WOLFSSH_NO_NONBLOCKING +#define WOLFSSH_NO_NONBLOCKING + +#define DEFAULT_WINDOW_SZ (128 * 128) +#define WOLFSSH_MAX_SFTP_RW 8192 + +#undef NO_FILESYSTEM +#define NO_FILESYSTEM + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/zephyr/samples/tests/wolfssl_user_settings.h b/zephyr/samples/tests/wolfssl_user_settings.h index 35cd345f6..03b12c94f 100644 --- a/zephyr/samples/tests/wolfssl_user_settings.h +++ b/zephyr/samples/tests/wolfssl_user_settings.h @@ -1,6 +1,6 @@ /* wolfssl_user_settings.h * - * Copyright (C) 2014-2023 wolfSSL Inc. + * Copyright (C) 2014-2024 wolfSSL Inc. * * This file is part of wolfSSH. * diff --git a/zephyr/samples/tests/wolfssl_user_settings_nofs.h b/zephyr/samples/tests/wolfssl_user_settings_nofs.h new file mode 100644 index 000000000..881b6b689 --- /dev/null +++ b/zephyr/samples/tests/wolfssl_user_settings_nofs.h @@ -0,0 +1,137 @@ +/* wolfssl_user_settings.h + * + * Copyright (C) 2014-2024 wolfSSL Inc. + * + * This file is part of wolfSSH. + * + * wolfSSH is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSH is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfSSH. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef WOLFSSL_USER_SETTINGS_H +#define WOLFSSL_USER_SETTINGS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#undef WOLFSSL_ZEPHYR +#define WOLFSSL_ZEPHYR + +#undef TFM_TIMING_RESISTANT +#define TFM_TIMING_RESISTANT + +#undef ECC_TIMING_RESISTANT +#define ECC_TIMING_RESISTANT + +#undef WC_RSA_BLINDING +#define WC_RSA_BLINDING + +#undef HAVE_AESGCM +#define HAVE_AESGCM + +#undef WOLFSSL_SHA512 +#define WOLFSSL_SHA512 + +#undef WOLFSSL_SHA384 +#define WOLFSSL_SHA384 + +#undef NO_DSA +#define NO_DSA + +#undef HAVE_ECC +#define HAVE_ECC + +#undef TFM_ECC256 +#define TFM_ECC256 + +#undef WOLFSSL_BASE64_ENCODE +#define WOLFSSL_BASE64_ENCODE + +#undef NO_RC4 +#define NO_RC4 + +#undef WOLFSSL_SHA224 +#define WOLFSSL_SHA224 + +#undef WOLFSSL_SHA3 +#define WOLFSSL_SHA3 + +#undef HAVE_POLY1305 +#define HAVE_POLY1305 + +#undef HAVE_ONE_TIME_AUTH +#define HAVE_ONE_TIME_AUTH + +#undef HAVE_CHACHA +#define HAVE_CHACHA + +#undef HAVE_HASHDRBG +#define HAVE_HASHDRBG + +#undef HAVE_TLS_EXTENSIONS +#define HAVE_TLS_EXTENSIONS + +#undef HAVE_SUPPORTED_CURVES +#define HAVE_SUPPORTED_CURVES + +#undef HAVE_EXTENDED_MASTER +#define HAVE_EXTENDED_MASTER + +#undef NO_PSK +#define NO_PSK + +#undef NO_MD4 +#define NO_MD4 + +#undef NO_PWDBASED +#define NO_PWDBASED + +#undef USE_FAST_MATH +#define USE_FAST_MATH + +#undef WOLFSSL_NO_ASM +#define WOLFSSL_NO_ASM + +#undef WOLFSSL_X86_BUILD +#define WOLFSSL_X86_BUILD + +#undef WC_NO_ASYNC_THREADING +#define WC_NO_ASYNC_THREADING + +#undef NO_DES3 +#define NO_DES3 + +#undef WOLFSSL_STATIC_MEMORY +#define WOLFSSL_STATIC_MEMORY + +#undef WOLFSSL_TLS13 +#define WOLFSSL_TLS13 + +#undef HAVE_HKDF +#define HAVE_HKDF + +#undef WC_RSA_PSS +#define WC_RSA_PSS + +#undef HAVE_FFDHE_2048 +#define HAVE_FFDHE_2048 + +#undef NO_FILESYSTEM +#define NO_FILESYSTEM + +#ifdef __cplusplus +} +#endif + +#endif /* WOLFSSL_USER_SETTINGS_H */