From a4e3cbb63066a66cf628fcce188a72821df72bf6 Mon Sep 17 00:00:00 2001 From: gojimmypi Date: Sat, 30 Dec 2023 10:44:22 -0800 Subject: [PATCH 01/11] Initial Espressif ESP32 template and echo server examples --- ide/Espressif/ESP-IDF/examples/README.md | 5 + .../wolfssh_echoserver/CMakeLists.txt | 129 + .../examples/wolfssh_echoserver/README.md | 75 + .../wolfssh_echoserver_IDF_v5.1_ESP32.sln | 37 + ...wolfssh_echoserver_IDF_v5.1_ESP32.vgdbproj | 269 ++ .../components/wolfssh/CMakeLists.txt | 545 ++++ .../components/wolfssl/CMakeLists.txt | 676 ++++ .../components/wolfssl/README.md | 9 + .../wolfssl/include/user_settings.h | 508 +++ .../wolfssh_echoserver/main/CMakeLists.txt | 155 + .../wolfssh_echoserver/main/echoserver.c | 2737 +++++++++++++++++ .../main/include/echoserver.h | 35 + .../wolfssh_echoserver/main/include/main.h | 38 + .../main/include/time_helper.h | 54 + .../main/include/wifi_connect.h | 96 + .../examples/wolfssh_echoserver/main/main.c | 182 ++ .../wolfssh_echoserver/main/time_helper.c | 360 +++ .../wolfssh_echoserver/main/wifi_connect.c | 274 ++ .../partitions_singleapp_large.csv | 31 + .../wolfssh_echoserver/sdkconfig.defaults | 38 + .../examples/wolfssh_template/CMakeLists.txt | 83 + .../examples/wolfssh_template/README.md | 64 + .../wolfssh_template_IDF_v5.1_ESP32.sln | 54 + .../wolfssh_template_IDF_v5.1_ESP32.vgdbproj | 269 ++ .../components/wolfssh/CMakeLists.txt | 508 +++ .../components/wolfssl/CMakeLists.txt | 676 ++++ .../components/wolfssl/README.md | 9 + .../wolfssl/include/user_settings.h | 508 +++ .../wolfssh_template/main/CMakeLists.txt | 154 + .../wolfssh_template/main/include/main.h | 38 + .../examples/wolfssh_template/main/main.c | 79 + .../partitions_singleapp_large.csv | 31 + .../wolfssh_template/sdkconfig.defaults | 38 + 33 files changed, 8764 insertions(+) create mode 100644 ide/Espressif/ESP-IDF/examples/README.md create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/CMakeLists.txt create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/README.md create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/VisualGDB/wolfssh_echoserver_IDF_v5.1_ESP32.sln create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/VisualGDB/wolfssh_echoserver_IDF_v5.1_ESP32.vgdbproj create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssh/CMakeLists.txt create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssl/CMakeLists.txt create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssl/README.md create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssl/include/user_settings.h create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/CMakeLists.txt create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/echoserver.c create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/echoserver.h create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/main.h create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/time_helper.h create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/wifi_connect.h create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/main.c create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/time_helper.c create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/wifi_connect.c create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/partitions_singleapp_large.csv create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/sdkconfig.defaults create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_template/CMakeLists.txt create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_template/README.md create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_template/VisualGDB/wolfssh_template_IDF_v5.1_ESP32.sln create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_template/VisualGDB/wolfssh_template_IDF_v5.1_ESP32.vgdbproj create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssh/CMakeLists.txt create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssl/CMakeLists.txt create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssl/README.md create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssl/include/user_settings.h create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_template/main/CMakeLists.txt create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_template/main/include/main.h create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_template/main/main.c create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_template/partitions_singleapp_large.csv create mode 100644 ide/Espressif/ESP-IDF/examples/wolfssh_template/sdkconfig.defaults diff --git a/ide/Espressif/ESP-IDF/examples/README.md b/ide/Espressif/ESP-IDF/examples/README.md new file mode 100644 index 000000000..63ebbdd7f --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/README.md @@ -0,0 +1,5 @@ +# wolfSSL Espressif Managed Component examples + +[wolfssh_template](./wolfssh_template/README.md) + +[wolfssh_echoserver](./wolfssh_echoserver/README.md) \ No newline at end of file diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/CMakeLists.txt b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/CMakeLists.txt new file mode 100644 index 000000000..2b754ab8f --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/CMakeLists.txt @@ -0,0 +1,129 @@ +# [wolfSSL Project]/CMakeLists.txt +# +# Copyright (C) 2006-2023 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 2 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA +# +# cmake for WOLFSSH Espressif projects +# +# See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html + +# wolfSSL Espressif Example Project CMakeLists.txt +# v1.0 +# +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +# enable wolfssl user_settings.h project-wide +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_USER_SETTINGS") +set(WOLFSSL_USER_SETTINGS ON) + +# Assume we have a ESP_ENABLE_WOLFSSH section in user_settings.h +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DESP_ENABLE_WOLFSSH") + +# The wolfSSL CMake file should be able to find the source code. +# Otherwise, assign an environment variable or set it here: +# +# set(WOLFSSL_ROOT "~/workspace/wolfssl-other-source") +# set(WOLFSSH_ROOT "~/workspace/wolfssh-other-source") +# set(WOLFSSL_ROOT "C:/workspace/wolfssl-master") + +# Optional WOLFSSL_CMAKE_SYSTEM_NAME detection to find +# USE_MY_PRIVATE_CONFIG path for my_private_config.h +# +# Expected path varies: +# +# WSL: /mnt/c/workspace +# Linux: ~/workspace +# Windows: C:\workspace +# +if(WIN32) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_WINDOWS") + message("Detected Windows") +endif() +if(CMAKE_HOST_UNIX) + message("Detected UNIX") +endif() +if(APPLE) + message("Detected APPLE") +endif() +if(CMAKE_HOST_UNIX AND (NOT APPLE) AND EXISTS "/proc/sys/fs/binfmt_misc/WSLInterop") + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_WSL") + message("Detected WSL") +endif() +if(CMAKE_HOST_UNIX AND (NOT APPLE) AND (NOT WIN32)) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_LINUX") + message("Detected Linux") +endif() +if(APPLE) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_APPLE") + message("Detected Apple") +endif() +# End optional WOLFSSL_CMAKE_SYSTEM_NAME + +# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. +set (PROTOCOL_EXAMPLES_DIR $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) + +if (EXISTS "${PROTOCOL_EXAMPLES_DIR}") + message("Found PROTOCOL_EXAMPLES_DIR=${PROTOCOL_EXAMPLES_DIR}") + set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFOUND_PROTOCOL_EXAMPLES_DIR") +else() + message("NOT FOUND: PROTOCOL_EXAMPLES_DIR=${PROTOCOL_EXAMPLES_DIR}") +endif() + +# Check that there are not conflicting wolfSSL components +# The ESP Registry Component will be in ./managed_components/wolfssl__wolfssl +# The local component wolfSSL directory will be in ./components/wolfssl +if( EXISTS "${CMAKE_HOME_DIRECTORY}/managed_components/wolfssl__wolfssl" AND EXISTS "${CMAKE_HOME_DIRECTORY}/components/wolfssl" ) + # These exclude statements don't seem to be honored by the $ENV{IDF_PATH}/tools/cmake/project.cmake' + # add_subdirectory("${CMAKE_HOME_DIRECTORY}/managed_components/wolfssl__wolfssl" EXCLUDE_FROM_ALL) + # add_subdirectory("${CMAKE_HOME_DIRECTORY}/managed_components/wolfssl__wolfssl/include" EXCLUDE_FROM_ALL) + # So we'll error out and let the user decide how to proceed: + message(WARNING "\nFound wolfSSL components in\n" + "./managed_components/wolfssl__wolfssl\n" + "and\n" + "./components/wolfssl\n" + "in project directory: \n" + "${CMAKE_HOME_DIRECTORY}") + message(FATAL_ERROR "\nPlease use either the ESP Registry Managed Component or the wolfSSL component directory but not both.\n" + "If removing the ./managed_components/wolfssl__wolfssl directory, remember to also remove " + "or rename the idf_component.yml file typically found in ./main/") +else() + message(STATUS "No conflicting wolfSSL components found.") +endif() + + +# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. +set (PROTOCOL_EXAMPLES_DIR $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) + +if (EXISTS "${PROTOCOL_EXAMPLES_DIR}") + message("Found PROTOCOL_EXAMPLES_DIR=${PROTOCOL_EXAMPLES_DIR}") + set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DFOUND_PROTOCOL_EXAMPLES_DIR") +else() + message("NOT FOUND: PROTOCOL_EXAMPLES_DIR=${PROTOCOL_EXAMPLES_DIR}") +endif() + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +project(wolfssh_echoserver) diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/README.md b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/README.md new file mode 100644 index 000000000..8ed8996cc --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/README.md @@ -0,0 +1,75 @@ +# wolfSSL Server Project + +This is an example wolfSSH Server based on the minimally viable wolfSSL [template](../wolfssh_template/README.md) + +See the [command line example client](https://github.com/wolfSSL/wolfssh/tree/master/examples/client) +and the instructions in [wolfssh README.md](https://github.com/wolfSSL/wolfssh#readme) + +To connect: + +```bash +TODO + +ssh -p 22222 jack@192.168.1.32 +``` + +### Prerequisites + +It is assumed the [ESP-IDF environment](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/) has been installed. + +### Files Included + +- [main.c](./main/main.c) with a simple call to an Espressif library (`ESP_LOGI`) and a call to a wolfSSL library (`esp_ShowExtendedSystemInfo`) . + +- See [components/wolfssl/include](./components/wolfssl/include/user_settings.h) directory to edit the wolfSSL `user_settings.h`. + +- Edit [main/CMakeLists.txt](./main/CMakeLists.txt) to add/remove source files. + +- The [components/wolfssl/CMakeLists.txt](./components/wolfssl/CMakeLists.txt) typically does not need to be changed. + +- Optional [VisualGDB Project](./VisualGDB/wolfssl_template_IDF_v5.1_ESP32.vgdbproj) for Visual Studio using ESP32 and ESP-IDF v5.1. + +- Edit the project [CMakeLists.txt](./CMakeLists.txt) to optionally point this project's wolfSSL component source code at a different directory: + +``` +set(WOLFSSL_ROOT "~/workspace/wolfssl-other-source") +``` + + +## Getting Started: + +Here's an example using the command-line [idf.py](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-py.html). + +Edit your `WRK_IDF_PATH`to point to your ESP-IDF install directory. + +``` +WRK_IDF_PATH=/mnt/c/SysGCC/esp32/esp-idf/v5.1 + +echo "Run export.sh from ${WRK_IDF_PATH}" +. ${WRK_IDF_PATH}/export.sh + +# build the example: +idf.py build + +# flash the code onto the serial device at /dev/ttyS19 +idf.py flash -p /dev/ttyS19 -b 115200 + +# build, flash, and view UART output with one command: +idf.py flash -p /dev/ttyS19 -b 115200 monitor +``` + +Press `Ctrl+]` to exit `idf.py monitor`. See [additional monitor keyboard commands](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-monitor.html). + +## Other Examples: + +For examples, see: + +- [TLS Client](../wolfssl_client/README.md) +- [TLS Server](../wolfssl_server/README.md) +- [Benchmark](../wolfssl_benchmark/README.md) +- [Test](../wolfssl_test/README.md) +- [wolfssl-examples](https://github.com/wolfSSL/wolfssl-examples/tree/master/ESP32) +- [wolfssh-examples](https://github.com/wolfSSL/wolfssh-examples/tree/main/Espressif) + + + diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/VisualGDB/wolfssh_echoserver_IDF_v5.1_ESP32.sln b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/VisualGDB/wolfssh_echoserver_IDF_v5.1_ESP32.sln new file mode 100644 index 000000000..562cdb3f7 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/VisualGDB/wolfssh_echoserver_IDF_v5.1_ESP32.sln @@ -0,0 +1,37 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.7.34031.279 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{803FD0C6-D64E-4E16-9DC3-1DAEC859A3D2}") = "wolfssh_echoserver_IDF_v5.1_ESP32", "wolfssh_echoserver_IDF_v5.1_ESP32.vgdbproj", "{EADCC9AB-72B3-4B51-A838-593E5D80DDF7}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{510C1DEE-DFFB-4C38-864E-DCE7A172ABB7}" + ProjectSection(SolutionItems) = preProject + ..\..\..\..\..\..\..\wolfssl-gojimmypi\wolfssl\wolfcrypt\port\Espressif\esp32-crypt.h = ..\..\..\..\..\..\..\wolfssl-gojimmypi\wolfssl\wolfcrypt\port\Espressif\esp32-crypt.h + ..\README.md = ..\README.md + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|VisualGDB = Debug|VisualGDB + Release|VisualGDB = Release|VisualGDB + Tests (Debug)|VisualGDB = Tests (Debug)|VisualGDB + Tests (Release)|VisualGDB = Tests (Release)|VisualGDB + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EADCC9AB-72B3-4B51-A838-593E5D80DDF7}.Debug|VisualGDB.ActiveCfg = Debug|VisualGDB + {EADCC9AB-72B3-4B51-A838-593E5D80DDF7}.Debug|VisualGDB.Build.0 = Debug|VisualGDB + {EADCC9AB-72B3-4B51-A838-593E5D80DDF7}.Release|VisualGDB.ActiveCfg = Release|VisualGDB + {EADCC9AB-72B3-4B51-A838-593E5D80DDF7}.Release|VisualGDB.Build.0 = Release|VisualGDB + {EADCC9AB-72B3-4B51-A838-593E5D80DDF7}.Tests (Debug)|VisualGDB.ActiveCfg = Tests (Debug)|VisualGDB + {EADCC9AB-72B3-4B51-A838-593E5D80DDF7}.Tests (Debug)|VisualGDB.Build.0 = Tests (Debug)|VisualGDB + {EADCC9AB-72B3-4B51-A838-593E5D80DDF7}.Tests (Release)|VisualGDB.ActiveCfg = Tests (Release)|VisualGDB + {EADCC9AB-72B3-4B51-A838-593E5D80DDF7}.Tests (Release)|VisualGDB.Build.0 = Tests (Release)|VisualGDB + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C3DD3774-E396-475C-B78D-604D7CD9B732} + EndGlobalSection +EndGlobal diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/VisualGDB/wolfssh_echoserver_IDF_v5.1_ESP32.vgdbproj b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/VisualGDB/wolfssh_echoserver_IDF_v5.1_ESP32.vgdbproj new file mode 100644 index 000000000..2b846751e --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/VisualGDB/wolfssh_echoserver_IDF_v5.1_ESP32.vgdbproj @@ -0,0 +1,269 @@ + + + + + + Unknown + + true + + 7bbd1486-d457-4e49-92ba-0cfc9d80849e + true + true + SourceDirs + + + + + + com.visualgdb.xtensa-esp32-elf + + 12.2.0 + 12.1 + 1 + + + .. + DEBUG + build/$(PlatformName)/$(ConfigurationName) + + false + $(ToolchainNinja) + $(BuildDir) + + + + false + $(SYSPROGS_CMAKE_PATH) + + + true + false + false + Ninja + false + RemoveBuildDirectory + false + + + true + true + true + false + true + false + true + HideOuterProjectTargets + true + false + true + + + true + eadcc9ab-72b3-4b51-a838-593e5d80ddf7 + + Upper + HeaderDirectoryAndSubdirectories + true + + + release/v5.1 + esp-idf/v5.1 + ESPIDF + + COM19 + false + false + ESP32 + + + + + + + + + + + + + + + Default + + + + COM19 + + 115200 + 8 + None + One + None + + + 0 + false + true + false + ASCII + + + 255 + 0 + 0 + 0 + + + 255 + 169 + 169 + 169 + + + 255 + 211 + 211 + 211 + + + 255 + 144 + 238 + 144 + + + 255 + 169 + 169 + 169 + + + + 16 + true + true + true + true + 0 + + LF + false + false + false + + + + true + + + + + Unknown + + true + true + true + + + + false + + + + + Debug + + + + Release + + + + + + + + + false + false + false + false + false + false + false + false + false + + false + false + false + false + false + false + true + false + None + false + false + app_main + true + false + false + true + 0 + false + 0 + true + false + + + openocd + + -f interface/ftdi/tigard.cfg -c "adapter_khz 15000" -f target/esp32.cfg + + + + false + + 131072 + Enabled + + set remotetimeout 60 + target remote :$$SYS:GDB_PORT$$ + mon gdb_breakpoint_override hard + mon reset halt + load + + false + 0 + 0 + false + + 5000 + 1 + true + + size2MB + freq40M + DIO + + true + + + true + Disabled + 0 + false + false + true + false + false + + _estack + 0 + false + + true + + \ No newline at end of file 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 new file mode 100644 index 000000000..c3e5d37ab --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssh/CMakeLists.txt @@ -0,0 +1,545 @@ +# [wolfSSL Project]/components/wolfssh/CMakeLists.txt +# +# Copyright (C) 2006-2023 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 2 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA +# +# cmake for WOLFSSH Espressif projects v5.6.6 r1 +# +# See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html +# + +cmake_minimum_required(VERSION 3.16) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSH_USER_SETTINGS") + +# find the user name to search for possible "wolfssh-username" +message(STATUS "USERNAME = $ENV{USERNAME}") +if( "$ENV{USER}" STREQUAL "" ) # the bash user + if( "$ENV{USERNAME}" STREQUAL "" ) # the Windows user + message(STATUS "could not find USER or USERNAME") + else() + # the bash user is not blank, so we'll use it. + set(THIS_USER "$ENV{USERNAME}") + endif() +else() + # the bash user is not blank, so we'll use it. + set(THIS_USER "$ENV{USER}") +endif() +message(STATUS "THIS_USER = ${THIS_USER}") + +# Attention! +# +# When editing component CMake files, consider the following : +# +# NO Managed Componenets: Normal stand-alone app, "as cloned" from github. +# There's no notion of staging names (e.g. mywolfssh) regardless of environment settings. +# All of the component source is locall. See settings such s WOLFSSL_ROOT=[your path] +# +# Partially Managed Components. This one is tricky. When publishing a component with examples, +# those examples will have a chicken-and-egg problem: the required component is not yet published. +# Adding to the complexity is the notion of staging components, that are purposely prefixed with +# "my" (e.g. mywolfssh) to distinguish from production, live components (e.g. wolfssh) +# +# Partially Managed Component Examples are typically only encountered by the component publisher +# and only at publish time, such as when performing the pre-publish build check. +# +# A partially managed component may also be manually created, when adding a managed component to +# and existing project. For example: +# +# idf.py add-dependency "wolfssl/wolfssh^1.4.15-stable" +# +# Fully Managaged Componenets. This is the typical example as created from the Component Registry: +# For example: +# +# idf.py create-project-from-example "wolfssl/wolfssh^1.4.15-stable:wolfssh_server" +# +# In all cases, keep in mind that components other than wolfssl will depend on the wolfssl component. +# +message(STATUS "CMAKE_CURRENT_LIST_DIR = ${CMAKE_CURRENT_LIST_DIR}") + +get_filename_component(THIS_DIR "${CMAKE_CURRENT_LIST_DIR}" ABSOLUTE) +message(STATUS "THIS_DIR = ${THIS_DIR}") + +# The root of the project is two directories up from here. (we are typically in [project name]components/mywolfssh) +get_filename_component(PROJECT_ROOT "${THIS_DIR}" DIRECTORY) # Up one directory from here is "components" +get_filename_component(PROJECT_ROOT "${PROJECT_ROOT}" DIRECTORY) # up one more directory should be the root of our project +message(STATUS "PROJECT_ROOT = ${PROJECT_ROOT}") + + +# Component naming is only adjusted when using Managed Components, and only when using staging site. +if( "$ENV{IDF_COMPONENT_REGISTRY_URL}" STREQUAL "https://components-staging.espressif.com" ) + # TODO: Is checking these two variables really the best way to detect an active Component Manager? + message(STATUS "component_manager_interface_version = ${component_manager_interface_version}") + message(STATUS "managed_components = ${managed_components}") + message(STATUS "Checking if wolfssl is in ${PROJECT_ROOT}/managed_components/${THIS_USER}__mywolfssl") + + if(EXISTS "${PROJECT_ROOT}/managed_components/${THIS_USER}__mywolfssl/CMakeLists.txt") + message(STATUS "Found user-specific, managed, staging component. The wolfssl component will be named mywolfssl.") + set(WOLFSSL_COMPONENT_NAME "mywolfssl") + elseif( ("${managed_components}" STREQUAL "") AND ("${component_manager_interface_version}" STREQUAL "") ) + # We've found a staging component, but did not detect the component manager + message(STATUS "No component manager interface component wolfssl ${CMAKE_HOME_DIRECTORY}") + set(WOLFSSL_COMPONENT_NAME "wolfssl") + else() + message(STATUS "else mywolfssl") + set(WOLFSSL_COMPONENT_NAME "mywolfssl") + endif() +elseif(EXISTS "${CMAKE_HOME_DIRECTORY}/managed_components/${THIS_USER}__mywolfssl/CMakeLists.txt") + message(STATUS "Found managed_components mywolfssl") + set(WOLFSSL_COMPONENT_NAME "mywolfssl") +else() + message(STATUS "Not staging environment, no managed_components wolfssl") + set(WOLFSSL_COMPONENT_NAME "wolfssl") +endif() + +set(COMPONENT_REQUIRES lwip "${WOLFSSL_COMPONENT_NAME}") + +# function: IS_WOLFSSH_SOURCE +# parameter: DIRECTORY_PARAMETER - the directory to test +# output: RESULT = contains contents of DIRECTORY_PARAMETER for wolfssh directory, otherwise blank. +function(IS_WOLFSSH_SOURCE DIRECTORY_PARAMETER RESULT) + if (EXISTS "${DIRECTORY_PARAMETER}/wolfssh/ssh.h") + if (EXISTS "${DIRECTORY_PARAMETER}/wolfssh") + message(STATUS "1") + endif() + if (EXISTS "${DIRECTORY_PARAMETER}") + message(STATUS "2") + endif() + if (EXISTS "${DIRECTORY_PARAMETER}/src") + message(STATUS "3") + endif() + set(${RESULT} "${DIRECTORY_PARAMETER}" PARENT_SCOPE) + else() + set(${RESULT} "" PARENT_SCOPE) + endif() +endfunction() + +# function: FIND_WOLFSSH_DIRECTORY +# parameter: OUTPUT_FOUND_WOLFSSH_DIRECTORY contains root of source code, otherwise blank +# +function(FIND_WOLFSSH_DIRECTORY OUTPUT_FOUND_WOLFSSH_DIRECTORY) + message(STATUS "Starting FIND_WOLFSSH_DIRECTORY") + set(CURRENT_SEARCH_DIR "$ENV{WOLFSSH_ROOT}") + if( "${CURRENT_SEARCH_DIR}" STREQUAL "" ) + message(STATUS "The WOLFSSH_ROOT environment variable is not set. Searching...") + else() + # There's a non-blank WOLFSSH_ROOT environment variable. Is it a valid wolfssh directory? + get_filename_component(CURRENT_SEARCH_DIR "$ENV{WOLFSSH_ROOT}" ABSOLUTE) + IS_WOLFSSH_SOURCE("${CURRENT_SEARCH_DIR}" FOUND_WOLFSSH) + if("${FOUND_WOLFSSH}") + message(STATUS "Found WOLFSSH_ROOT via Environment Variable:") + else() + message(FATAL_ERROR "WOLFSSH_ROOT Environment Variable defined, but path not found: $ENV{WOLFSSH_ROOT}") + message(STATUS "Exit CMake") + endif() + endif() + + # we'll start in the THIS_CMAKE_CURRENT_SOURCE_DIR, typically [something]/projectname/components/WOLFSSH + message(STATUS "THIS_CMAKE_CURRENT_SOURCE_DIR = ${THIS_CMAKE_CURRENT_SOURCE_DIR}") + get_filename_component(CURRENT_SEARCH_DIR "${THIS_CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE) + message(STATUS "CURRENT_SEARCH_DIR = ${CURRENT_SEARCH_DIR}") + string(LENGTH ${CURRENT_SEARCH_DIR} CURRENT_SEARCH_DIR_LENGTH) + + # loop through all the parents, looking for wolfssh + while(NOT CURRENT_SEARCH_DIR STREQUAL "/" AND NOT CURRENT_SEARCH_DIR STREQUAL "" ) + string(LENGTH ${CURRENT_SEARCH_DIR} CURRENT_SEARCH_DIR_LENGTH) + # wolfssh may simply be in a parent directory, such as for local examples in WOLFSSH repo + IS_WOLFSSH_SOURCE("${CURRENT_SEARCH_DIR}" FOUND_WOLFSSH) + if( FOUND_WOLFSSH ) + message(STATUS "Found wolfssh in CURRENT_SEARCH_DIR = ${CURRENT_SEARCH_DIR}") + set(${OUTPUT_FOUND_WOLFSSH_DIRECTORY} ${CURRENT_SEARCH_DIR} PARENT_SCOPE) + return() + endif() + + if( THIS_USER ) + # Check for "wolfssh-[username]" subdirectory as we recurse up the directory tree + set(CURRENT_SEARCH_DIR_ALT "${CURRENT_SEARCH_DIR}/wolfssh-${THIS_USER}") + message(STATUS "Looking in ${CURRENT_SEARCH_DIR}") + + #if(EXISTS ${CURRENT_SEARCH_DIR_ALT} AND IS_DIRECTORY ${CURRENT_SEARCH_DIR_ALT} AND EXISTS "${CURRENT_SEARCH_DIR_ALT}/wolfcrypt/src") + IS_WOLFSSH_SOURCE("${CURRENT_SEARCH_DIR_ALT}" FOUND_WOLFSSH ) + if ( FOUND_WOLFSSH ) + message(STATUS "Found wolfssh in user-suffix CURRENT_SEARCH_DIR_ALT = ${CURRENT_SEARCH_DIR_ALT}") + set(${OUTPUT_FOUND_WOLFSSH_DIRECTORY} ${CURRENT_SEARCH_DIR_ALT} PARENT_SCOPE) + return() + endif() + endif() + + # Next check for no user suffix "WOLFSSH" subdirectory as we recurse up the directory tree + set(CURRENT_SEARCH_DIR_ALT ${CURRENT_SEARCH_DIR}/wolfssh) + # if(EXISTS ${CURRENT_SEARCH_DIR} AND IS_DIRECTORY ${CURRENT_SEARCH_DIR} AND EXISTS "${CURRENT_SEARCH_DIR}/wolfcrypt/src") + IS_WOLFSSH_SOURCE("${CURRENT_SEARCH_DIR_ALT}" FOUND_WOLFSSH ) + if ( FOUND_WOLFSSH ) + message(STATUS "Found wolfssh in CURRENT_SEARCH_DIR = ${CURRENT_SEARCH_DIR}") + set(${OUTPUT_FOUND_WOLFSSH_DIRECTORY} ${CURRENT_SEARCH_DIR} PARENT_SCOPE) + return() + endif() + + # Move up one directory level + set(PRIOR_SEARCH_DIR "${CURRENT_SEARCH_DIR}") + 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 + set(CURRENT_SEARCH_DIR "") + endif() + endwhile() + + # If not found, set the output variable to empty before exiting + set(${OUTPUT_FOUND_WOLFSSH_DIRECTORY} "" PARENT_SCOPE) +endfunction() + +# COMPONENT_NAME = wolfssh +# The component name is the directory name. "No feature to change this". +# See https://github.com/espressif/esp-idf/issues/8978#issuecomment-1129892685 + +# set the root of WOLFSSH in top-level project CMakelists.txt: +# set(WOLFSSH_ROOT "C:/some path/with/spaces") +# set(WOLFSSH_ROOT "c:/workspace/WOLFSSH-[username]") +# set(WOLFSSH_ROOT "/mnt/c/some path/with/spaces") +# or use this logic to assign value from Environment Variable WOLFSSH_ROOT, +# or assume this is an example 7 subdirectories below: + +# We are typically in [root]/IDE/Espressif/ESP-IDF/examples/WOLFSSH_test/components/WOLFSSH +# The root of WOLFSSH is 7 directories up from here: + +if(CMAKE_BUILD_EARLY_EXPANSION) + message(STATUS "WOLFSSH component CMAKE_BUILD_EARLY_EXPANSION:") + idf_component_register( + REQUIRES "${COMPONENT_REQUIRES}" + PRIV_REQUIRES + esp_timer + driver + "${WOLFSSL_COMPONENT_NAME}" # either wolfssl or mywolfssl as a staging component + ) + +else() + # not CMAKE_BUILD_EARLY_EXPANSION + message(STATUS "************************************************************************************************") + message(STATUS "wolfssh component config:") + message(STATUS "************************************************************************************************") + FIND_WOLFSSH_DIRECTORY(WOLFSSH_ROOT) + + set(WOLFSSH_ROOT "${WOLFSSH_ROOT}" CACHE STRING "WOLFSSH_ROOT") + if(WOLFSSH_ROOT) + message(STATUS "Found wolfssh directory at: ${WOLFSSH_ROOT}") + else() + message(STATUS "wolfssh directory not found.") + # Abort. We need wolfmqtt _somewhere_. + message(FATAL_ERROR "Could not find wolfssh in ${WOLFSSH_ROOT}.\n" + "Try setting WOLFSSH_ROOT environment variable or git clone.") + endif() + + + # After all the logic above, does our WOLFSSH_ROOT actually exist? + if( EXISTS "${WOLFSSH_ROOT}" ) + message(STATUS "WOLFSSH_ROOT = ${WOLFSSH_ROOT}") + else() + # Abort. We need WOLFSSH _somewhere_. + message(FATAL_ERROR "Could not find WOLFSSH in ${WOLFSSH_ROOT}. Try setting environment variable or git clone.") + endif() + + + set(INCLUDE_PATH ${WOLFSSH_ROOT}) + + set(COMPONENT_SRCDIRS + "\"${WOLFSSH_ROOT}/src/\"" + ) # COMPONENT_SRCDIRS + message(STATUS "This COMPONENT_SRCDIRS = ${COMPONENT_SRCDIRS}") + + set(WOLFSSH_PROJECT_DIR "${CMAKE_HOME_DIRECTORY}/components/wolfssh") + + # Espressif may take several passes through this makefile. Check to see if we found IDF + string(COMPARE EQUAL "${PROJECT_SOURCE_DIR}" "" WOLFSSH_FOUND_IDF) + + message(STATUS "IDF_PATH = $ENV{IDF_PATH}") + message(STATUS "PROJECT_SOURCE_DIR = ${PROJECT_SOURCE_DIR}") + message(STATUS "EXCLUDE_ASM = ${EXCLUDE_ASM}") + + # + # Check to see if there's both a local copy and EDP-IDF copy of the WOLFSSH and/or wolfssh components. + # + if( EXISTS "${WOLFSSH_PROJECT_DIR}" AND EXISTS "$ENV{IDF_PATH}/components/WOLFSSH/" ) + # + # WOLFSSH found in both ESP-IDF and local project - needs to be resolved by user + # + message(STATUS "") + message(STATUS "**************************************************************************************") + message(STATUS "") + message(STATUS "Error: Found components/WOLFSSH in both local project and IDF_PATH") + message(STATUS "") + message(STATUS "To proceed: ") + message(STATUS "") + message(STATUS "Remove either the local project component: ${WOLFSSH_PROJECT_DIR} ") + message(STATUS "or the Espressif shared component installed at: $ENV{IDF_PATH}/components/WOLFSSH/ ") + message(STATUS "") + message(FATAL_ERROR "Please use WOLFSSH in either local project or Espressif components, but not both.") + message(STATUS "") + message(STATUS "**************************************************************************************") + message(STATUS "") + + # Optional: if you change the above FATAL_ERROR to STATUS you can warn at runtime with this macro definition: + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSH_MULTI_INSTALL_WARNING") + + else() + if( EXISTS "$ENV{IDF_PATH}/components/WOLFSSH/" ) + # + # WOLFSSH found in ESP-IDF components and is assumed to be already configured in user_settings.h via setup. + # + message(STATUS "") + message(STATUS "Using components/WOLFSSH in IDF_PATH = $ENV{IDF_PATH}") + message(STATUS "") + else() + # + # WOLFSSH is not an ESP-IDF component. + # We need to now determine if it is local and if so if it is part of the WOLFSSH repo, + # or if WOLFSSH is simply installed as a local component. + # + + if( EXISTS "${WOLFSSH_PROJECT_DIR}" ) + # + # WOLFSSH found in local project. + # + if( EXISTS "${WOLFSSH_PROJECT_DIR}/wolfcrypt/" ) + message(STATUS "") + message(STATUS "Using installed project ./components/WOLFSSH in CMAKE_HOME_DIRECTORY = ${CMAKE_HOME_DIRECTORY}") + message(STATUS "") + # + # Note we already checked above and confirmed there's not another WOLFSSH installed in the ESP-IDF components. + # + # We won't do anything else here, as it will be assumed the original install completed successfully. + # + else() # full WOLFSSH not installed in local project + # + # This is the developer repo mode. WOLFSSH will be assumed to be not installed to ESP-IDF nor local project + # In this configuration, we are likely running a WOLFSSH example found directly in the repo. + # + message(STATUS "") + message(STATUS "Using developer repo ./components/WOLFSSH in CMAKE_HOME_DIRECTORY = ${CMAKE_HOME_DIRECTORY}") + message(STATUS "") + + message(STATUS "************************************************************************************************") + # When in developer mode, we are typically running WOLFSSH examples such as benchmark or test directories. + # However, the as-cloned or distributed WOLFSSH does not have the ./include/ directory, so we'll add it as needed. + # + # first check if there's a [root]/include/user_settings.h + if( EXISTS "${WOLFSSH_ROOT}/include/user_settings.h" ) + message(FATAL_ERROR "Found stray WOLFSSH user_settings.h in " + "${WOLFSSH_ROOT}/include/user_settings.h " + " (please move it to ${WOLFSSH_PROJECT_DIR}/include/user_settings.h )") + else() + # we won't overwrite an existing user settings file, just note that we already have one: + if( EXISTS "${WOLFSSH_PROJECT_DIR}/include/user_settings.h" ) + message(STATUS "Using existing WOLFSSH user_settings.h in " + "${WOLFSSH_PROJECT_DIR}/include/user_settings.h") + else() + message(STATUS "Installing WOLFSSH user_settings.h to " + "${WOLFSSH_PROJECT_DIR}/include/user_settings.h") + # file(COPY "${WOLFSSH_ROOT}/IDE/Espressif/ESP-IDF/user_settings.h" + # DESTINATION "${CMAKE_HOME_DIRECTORY}/WOLFSSH/include/") + endif() + endif() # user_settings.h + + message(STATUS "************************************************************************************************") + message(STATUS "") + endif() + + else() + # we did not find a ./components/WOLFSSH/include/ directory from this pass of cmake. + if($WOLFSSH_FOUND_IDF) + message(STATUS "") + message(STATUS "WARNING: WOLFSSH not found.") + message(STATUS "") + else() + # probably needs to be re-parsed by Espressif + message(STATUS "WOLFSSH found IDF. Project Source:${PROJECT_SOURCE_DIR}") + endif() # else we have not found ESP-IDF yet + endif() # else not a local WOLFSSH component + + endif() #else not an ESP-IDF component + endif() # else not local copy and EDP-IDF WOLFSSH + + + # RTOS_IDF_PATH is typically: + # "/Users/{username}/Desktop/esp-idf/components/freertos/include/freertos" + # depending on the environment, we may need to swap backslashes with forward slashes + string(REPLACE "\\" "/" RTOS_IDF_PATH "$ENV{IDF_PATH}/components/freertos/FreeRTOS-Kernel/include/freertos") + + string(REPLACE "\\" "/" WOLFSSH_ROOT ${WOLFSSH_ROOT}) + + if(IS_DIRECTORY "${RTOS_IDF_PATH}") + message(STATUS "Found current RTOS path: ${RTOS_IDF_PATH}") + else() + # ESP-IDF prior version 4.4x has a different RTOS directory structure + string(REPLACE "\\" "/" RTOS_IDF_PATH "$ENV{IDF_PATH}/components/freertos/include/freertos") + if(IS_DIRECTORY "${RTOS_IDF_PATH}") + message(STATUS "Found legacy RTOS path: ${RTOS_IDF_PATH}") + else() + message(STATUS "Could not find RTOS path") + endif() + endif() + + + set(COMPONENT_ADD_INCLUDEDIRS + # "./include" # not used! See wolfSSL include/user_settings.h + "\"${WOLFSSH_ROOT}/\"" + "\"${WOLFSSH_ROOT}/wolfssh/\"" + "\"${RTOS_IDF_PATH}/\"" + ) + + + if(IS_DIRECTORY ${IDF_PATH}/components/cryptoauthlib) + list(APPEND COMPONENT_ADD_INCLUDEDIRS "../cryptoauthlib/lib") + endif() + + list(APPEND COMPONENT_ADD_INCLUDEDIRS "\"${WOLFSSH_ROOT}/wolfssh/\"") + + + + set(COMPONENT_SRCEXCLUDE + # wolfSSH + # TODO: we likely need to check #if !defined(WOLFSSH_MISC_INCLUDED) && !defined(NO_INLINE) && !defined(WOLFSSH_IGNORE_FILE_WARN) + # here in cmake if we actually want to always exclude wolfssh misc.c file. (see source; ok for demo) + "\"${WOLFSSH_ROOT}/src/misc.c\"" # misc.c does not need to be compiled when using inline (NO_INLINE not defined)) + ) + + spaces2list(COMPONENT_REQUIRES) + + separate_arguments(COMPONENT_SRCDIRS NATIVE_COMMAND "${COMPONENT_SRCDIRS}") + separate_arguments(COMPONENT_SRCEXCLUDE NATIVE_COMMAND "${COMPONENT_SRCEXCLUDE}") + separate_arguments(COMPONENT_ADD_INCLUDEDIRS NATIVE_COMMAND "${COMPONENT_ADD_INCLUDEDIRS}") + + # + # See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html#example-component-requirements + # + message(STATUS "COMPONENT_SRCDIRS = ${COMPONENT_SRCDIRS}") + message(STATUS "COMPONENT_ADD_INCLUDEDIRS = ${COMPONENT_ADD_INCLUDEDIRS}") + message(STATUS "COMPONENT_REQUIRES = ${COMPONENT_REQUIRES}") + message(STATUS "COMPONENT_SRCEXCLUDE = ${COMPONENT_SRCEXCLUDE}") + + # + # see https://docs.espressif.com/projects/esp-idf/en/stable/esp32/migration-guides/release-5.x/build-system.html?highlight=space%20path + # + set(EXTRA_COMPONENT_DIRS "${COMPONENT_SRCDIRS}") + idf_component_register( + SRC_DIRS "${COMPONENT_SRCDIRS}" + INCLUDE_DIRS "${COMPONENT_ADD_INCLUDEDIRS}" + REQUIRES "${COMPONENT_REQUIRES}" + EXCLUDE_SRCS "${COMPONENT_SRCEXCLUDE}" + PRIV_REQUIRES + esp_timer + driver + "${WOLFSSL_COMPONENT_NAME}" # either wolfssl or mywolfssl as a staging component + ) + # some optional diagnostics + if (1) + 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() + + # target_sources(WOLFSSH PRIVATE "\"${WOLFSSH_ROOT}/WOLFSSH/\"" "\"${WOLFSSH_ROOT}/WOLFSSH/wolfcrypt\"") +endif() # CMAKE_BUILD_EARLY_EXPANSION + + + +# check to see if there's both a local copy and EDP-IDF copy of the WOLFSSH components +if( EXISTS "${WOLFSSH_PROJECT_DIR}" AND EXISTS "$ENV{IDF_PATH}/components/WOLFSSH/" ) + message(STATUS "") + message(STATUS "") + message(STATUS "********************************************************************") + message(STATUS "WARNING: Found components/WOLFSSH in both local project and IDF_PATH") + message(STATUS "********************************************************************") + message(STATUS "") +endif() +# end multiple component check + + +# +# LIBWOLFSSH_SAVE_INFO(VAR_OUPUT THIS_VAR VAR_RESULT) +# +# Save the THIS_VAR as a string in a macro called VAR_OUPUT +# +# VAR_OUPUT: the name of the macro to define +# THIS_VAR: the OUTPUT_VARIABLE result from a execute_process() +# VAR_RESULT: the RESULT_VARIABLE from a execute_process(); "0" if successful. +# +function ( LIBWOLFSSH_SAVE_INFO VAR_OUPUT THIS_VAR VAR_RESULT ) + # is the RESULT_VARIABLE output value 0? If so, IS_VALID_VALUE is true. + string(COMPARE EQUAL "${VAR_RESULT}" "0" IS_VALID_VALUE) + + # if we had a successful operation, save the THIS_VAR in VAR_OUPUT + if(${IS_VALID_VALUE}) + # strip newline chars in THIS_VAR parameter and save in VAR_VALUE + string(REPLACE "\n" "" VAR_VALUE ${THIS_VAR}) + + # we'll could percolate the value to the parent for possible later use + # set(${VAR_OUPUT} ${VAR_VALUE} PARENT_SCOPE) + + # but we're only using it here in this function + set(${VAR_OUPUT} ${VAR_VALUE}) + + # we'll print what we found to the console + message(STATUS "Found ${VAR_OUPUT}=${VAR_VALUE}") + + # the interesting part is defining the VAR_OUPUT name a value to use in the app + add_definitions(-D${VAR_OUPUT}=\"${VAR_VALUE}\") + else() + # if we get here, check the execute_process command and parameters. + message(STATUS "LIBWOLFSSH_SAVE_INFO encountered a non-zero VAR_RESULT") + set(${VAR_OUPUT} "Unknown") + endif() +endfunction() # LIBWOLFSSH_SAVE_INFO + +# create some programmatic #define values that will be used by ShowExtendedSystemInfo(). +# see wolfcrypt\src\port\Espressif\esp32_utl.c +if(NOT CMAKE_BUILD_EARLY_EXPANSION) + set (git_cmd "git") + message(STATUS "Adding macro definitions:") + + # LIBWOLFSSH_VERSION_GIT_ORIGIN: git config --get remote.origin.url + execute_process(WORKING_DIRECTORY ${WOLFSSH_ROOT} COMMAND ${git_cmd} "config" "--get" "remote.origin.url" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSH_SAVE_INFO(LIBWOLFSSH_VERSION_GIT_ORIGIN "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSH_VERSION_GIT_BRANCH: git rev-parse --abbrev-ref HEAD + execute_process(WORKING_DIRECTORY ${WOLFSSH_ROOT} COMMAND ${git_cmd} "rev-parse" "--abbrev-ref" "HEAD" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSH_SAVE_INFO(LIBWOLFSSH_VERSION_GIT_BRANCH "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSH_VERSION_GIT_HASH: git rev-parse HEAD + execute_process(WORKING_DIRECTORY ${WOLFSSH_ROOT} COMMAND ${git_cmd} "rev-parse" "HEAD" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSH_SAVE_INFO(LIBWOLFSSH_VERSION_GIT_HASH "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSH_VERSION_GIT_SHORT_HASH: git rev-parse --short HEAD + execute_process(WORKING_DIRECTORY ${WOLFSSH_ROOT} COMMAND ${git_cmd} "rev-parse" "--short" "HEAD" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSH_SAVE_INFO(LIBWOLFSSH_VERSION_GIT_SHORT_HASH "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSH_VERSION_GIT_HASH_DATE git show --no-patch --no-notes --pretty=\'\%cd\' + execute_process(WORKING_DIRECTORY ${WOLFSSH_ROOT} COMMAND ${git_cmd} "show" "--no-patch" "--no-notes" "--pretty=\'\%cd\'" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ) + LIBWOLFSSH_SAVE_INFO(LIBWOLFSSH_VERSION_GIT_HASH_DATE "${TMP_OUT}" "${TMP_RES}") + + message(STATUS "************************************************************************************************") + message(STATUS "WOLFSSH component config complete!") + message(STATUS "************************************************************************************************") +endif() 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 new file mode 100644 index 000000000..d58704b84 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssl/CMakeLists.txt @@ -0,0 +1,676 @@ +# +# Copyright (C) 2006-2023 wolfSSL Inc. +# +# This file is part of wolfSSL. +# +# wolfSSL 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 +# (at your option) any later version. +# +# wolfSSL 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 +# +# cmake for wolfssl Espressif projects +# +# Version 5.6.4.016 for improved manual setting of WOLFSSL_ROOT + ESP8266 support; optional esp-timer / driver components +# +# See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html +# + +cmake_minimum_required(VERSION 3.16) + +set(VERBOSE_COMPONENT_MESSAGES 1) + +# The scope of this CMAKE_C_FLAGS is just this component: +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_USER_SETTINGS") + +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" ) + +if ( "${WOLFSSL_ROOT}" STREQUAL "") + set(WOLFSSL_ROOT "$ENV{WOLFSSL_ROOT}" ) +endif() +# Optional compiler definitions to help with system name detection (typically printed by app diagnostics) +if(VERBOSE_COMPONENT_MESSAGES) + if(WIN32) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_WINDOWS") + message("Detected Windows") + endif() + if(CMAKE_HOST_UNIX) + message("Detected UNIX") + endif() + if(APPLE) + message("Detected APPLE") + endif() + if(CMAKE_HOST_UNIX AND (NOT APPLE) AND EXISTS "/proc/sys/fs/binfmt_misc/WSLInterop") + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_WSL") + message("Detected WSL") + endif() + if(CMAKE_HOST_UNIX AND (NOT APPLE) AND (NOT WIN32)) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_LINUX") + message("Detected Linux") + endif() + if(APPLE) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_APPLE") + message("Detected Apple") + endif() +endif() # End optional WOLFSSL_CMAKE_SYSTEM_NAME + +message(STATUS "CONFIG_TARGET_PLATFORM = ${CONFIG_TARGET_PLATFORM}") + +# Check that there are not conflicting wolfSSL components +# The ESP Registry Component will be in ./managed_components/wolfssl__wolfssl +# The local component wolfSSL directory will be in ./components/wolfssl +if( EXISTS "${CMAKE_HOME_DIRECTORY}/managed_components/wolfssl__wolfssl" AND EXISTS "${CMAKE_HOME_DIRECTORY}/components/wolfssl" ) + # These exclude statements don't seem to be honored by the $ENV{IDF_PATH}/tools/cmake/project.cmake' + # add_subdirectory("${CMAKE_HOME_DIRECTORY}/managed_components/wolfssl__wolfssl" EXCLUDE_FROM_ALL) + # add_subdirectory("${CMAKE_HOME_DIRECTORY}/managed_components/wolfssl__wolfssl/include" EXCLUDE_FROM_ALL) + # So we'll error out and let the user decide how to proceed: + message(WARNING "\nFound wolfSSL components in\n" + "./managed_components/wolfssl__wolfssl\n" + "and\n" + "./components/wolfssl\n" + "in project directory: \n" + "${CMAKE_HOME_DIRECTORY}") + message(FATAL_ERROR "\nPlease use either the ESP Registry Managed Component or the wolfSSL component directory but not both.\n" + "If removing the ./managed_components/wolfssl__wolfssl directory, remember to also remove " + "or rename the idf_component.yml file typically found in ./main/") +else() + message(STATUS "No conflicting wolfSSL components found.") +endif() + + +# Don't include lwip requirement for benchmark and test apps. +if( ("${CMAKE_PROJECT_NAME}" STREQUAL "wolfssl_benchmark") OR ("${CMAKE_PROJECT_NAME}" STREQUAL "wolfssl_test") ) + message(STATUS "Not including lwip for ${CMAKE_PROJECT_NAME}") +else() + # benchmark and test do not need wifi, everything else probably does: + set(COMPONENT_REQUIRES lwip) # we typically don't need lwip directly in wolfssl component +endif() + +# find the user name to search for possible "wolfssl-username" +message(STATUS "USERNAME = $ENV{USERNAME}") +if( "$ENV{USER}" STREQUAL "" ) # the bash user + if( "$ENV{USERNAME}" STREQUAL "" ) # the Windows user + message(STATUS "could not find USER or USERNAME") + else() + # the bash user is not blank, so we'll use it. + set(THIS_USER "$ENV{USERNAME}") + endif() +else() + # the bash user is not blank, so we'll use it. + set(THIS_USER "$ENV{USER}") +endif() +message(STATUS "THIS_USER = ${THIS_USER}") + + +# COMPONENT_NAME = wolfssl +# The component name is the directory name. "No feature to change this". +# See https://github.com/espressif/esp-idf/issues/8978#issuecomment-1129892685 + +# set the root of wolfSSL in top-level project CMakelists.txt: +# set(WOLFSSL_ROOT "C:/some path/with/spaces") +# set(WOLFSSL_ROOT "c:/workspace/wolfssl-[username]") +# set(WOLFSSL_ROOT "/mnt/c/some path/with/spaces") +# or use this logic to assign value from Environment Variable WOLFSSL_ROOT, +# or assume this is an example 7 subdirectories below: + +# We are typically in [root]/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl +# The root of wolfSSL is 7 directories up from here: + +# function: IS_WOLFSSL_SOURCE +# parameter: DIRECTORY_PARAMETER - the directory to test +# output: RESULT = contains contents of DIRECTORY_PARAMETER for wolfssl directory, otherwise blank. +function(IS_WOLFSSL_SOURCE DIRECTORY_PARAMETER RESULT) + if (EXISTS "${DIRECTORY_PARAMETER}/wolfcrypt/src") + set(${RESULT} "${DIRECTORY_PARAMETER}" PARENT_SCOPE) + else() + set(${RESULT} "" PARENT_SCOPE) + endif() +endfunction() + +# ********************************************************************************************* +# function: FIND_WOLFSSL_DIRECTORY +# parameter: OUTPUT_FOUND_WOLFSSL_DIRECTORY contains root of source code, otherwise blank +# +# Example usage: +# FIND_WOLFSSL_DIRECTORY(WOLFSSL_ROOT) +# ********************************************************************************************* +function(FIND_WOLFSSL_DIRECTORY OUTPUT_FOUND_WOLFSSL_DIRECTORY) + message(STATUS "Starting FIND_WOLFSSL_DIRECTORY: ${${OUTPUT_FOUND_WOLFSSL_DIRECTORY}}") + + if ( "${${OUTPUT_FOUND_WOLFSSL_DIRECTORY}}" STREQUAL "" ) + set(CURRENT_SEARCH_DIR "$ENV{WOLFSSL_ROOT}") + if( "${CURRENT_SEARCH_DIR}" STREQUAL "" ) + message(STATUS "The WOLFSSL_ROOT environment variable is not set. Searching...") + else() + get_filename_component(CURRENT_SEARCH_DIR "$ENV{WOLFSSL_ROOT}" ABSOLUTE) + IS_WOLFSSL_SOURCE("${CURRENT_SEARCH_DIR}" FOUND_WOLFSSL) + if( FOUND_WOLFSSL ) + message(STATUS "Found WOLFSSL_ROOT via Environment Variable:") + else() + message(FATAL_ERROR "WOLFSSL_ROOT Environment Variable defined, but path not found:") + message(STATUS "$ENV{WOLFSSL_ROOT}") + endif() + endif() + else() + get_filename_component(CURRENT_SEARCH_DIR "${${OUTPUT_FOUND_WOLFSSL_DIRECTORY}}" ABSOLUTE) + IS_WOLFSSL_SOURCE("${CURRENT_SEARCH_DIR}" FOUND_WOLFSSL) + if( FOUND_WOLFSSL ) + message(STATUS "Found WOLFSSL_ROOT via prior specification.") + else() + message(FATAL_ERROR "WOLFSSL_ROOT Variable defined, but path not found: ${${OUTPUT_FOUND_WOLFSSL_DIRECTORY}}") + endif() + endif() + + + # we'll start in the CMAKE_CURRENT_SOURCE_DIR, typically [something]/projectname/components/wolfssl + message(STATUS "CMAKE_CURRENT_SOURCE_DIR = ${CMAKE_CURRENT_SOURCE_DIR}") + get_filename_component(CURRENT_SEARCH_DIR "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE) + message(STATUS "CURRENT_SEARCH_DIR = ${CURRENT_SEARCH_DIR}") + string(LENGTH ${CURRENT_SEARCH_DIR} CURRENT_SEARCH_DIR_LENGTH) + + # loop through all the parents, looking for wolfssl + while(NOT CURRENT_SEARCH_DIR STREQUAL "/" AND NOT CURRENT_SEARCH_DIR STREQUAL "" ) + string(LENGTH ${CURRENT_SEARCH_DIR} CURRENT_SEARCH_DIR_LENGTH) + # wolfSSL may simply be in a parent directory, such as for local examples in wolfssl repo + IS_WOLFSSL_SOURCE("${CURRENT_SEARCH_DIR}" FOUND_WOLFSSL) + if( FOUND_WOLFSSL ) + message(STATUS "Found wolfssl in CURRENT_SEARCH_DIR = ${CURRENT_SEARCH_DIR}") + set(${OUTPUT_FOUND_WOLFSSL_DIRECTORY} ${CURRENT_SEARCH_DIR} PARENT_SCOPE) + return() + endif() + + 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}") + + #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) + return() + endif() + endif() + + # Next check for no user suffix "wolfssl" subdirectory as we recurse up the directory tree + set(CURRENT_SEARCH_DIR_ALT ${CURRENT_SEARCH_DIR}/wolfssl) + # if(EXISTS ${CURRENT_SEARCH_DIR} AND IS_DIRECTORY ${CURRENT_SEARCH_DIR} AND EXISTS "${CURRENT_SEARCH_DIR}/wolfcrypt/src") + IS_WOLFSSL_SOURCE("${CURRENT_SEARCH_DIR_ALT}" FOUND_WOLFSSL ) + if ( FOUND_WOLFSSL ) + message(STATUS "Found wolfssl in CURRENT_SEARCH_DIR = ${CURRENT_SEARCH_DIR}") + set(${OUTPUT_FOUND_WOLFSSL_DIRECTORY} ${CURRENT_SEARCH_DIR} PARENT_SCOPE) + return() + endif() + + # Move up one directory level + set(PRIOR_SEARCH_DIR "${CURRENT_SEARCH_DIR}") + 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 + set(CURRENT_SEARCH_DIR "") + endif() + endwhile() + + # If not found, set the output variable to empty before exiting + set(${OUTPUT_FOUND_WOLFSSL_DIRECTORY} "" PARENT_SCOPE) +endfunction() + + +# Example usage: +# +# Simply find the WOLFSSL_DIRECTORY by searching parent directories: +# FIND_WOLFSSL_DIRECTORY(WOLFSSL_ROOT) +# + +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 + ) + +else() + # not CMAKE_BUILD_EARLY_EXPANSION + message(STATUS "************************************************************************************************") + 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 + + if(WOLFSSL_ROOT) + IS_WOLFSSL_SOURCE("${WOLFSSL_ROOT}" FOUND_WOLFSSL) + if(FOUND_WOLFSSL) + message(STATUS "Found WOLFSSL_ROOT via CMake specification.") + else() + # WOLFSSL_ROOT Path specified in CMakeLists.txt is not a valid path + message(FATAL_ERROR "WOLFSSL_ROOT CMake Variable defined, but path not found: ${WOLFSSL_ROOT}\n" + "Try correcting WOLFSSL_ROOT in your project CMakeFile.txt or setting environment variable.") + # Abort CMake after fatal error. + endif() + else() + message(STATUS "Searching for wolfSL source code...") + FIND_WOLFSSL_DIRECTORY(WOLFSSL_ROOT) + endif() + + + if(WOLFSSL_ROOT) + message(STATUS "Confirmed wolfssl directory at: ${WOLFSSL_ROOT}") + 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.") + # Abort CMake after fatal error. + endif() + + set(INCLUDE_PATH ${WOLFSSL_ROOT}) + + set(WOLFSSL_EXTRA_PROJECT_DIR "${WOLFSSL_ROOT}/src/") + + # During regression tests, optionally copy source locally and use: set(USE_LOCAL_TEST_BENCH 1) + set(USE_LOCAL_TEST_BENCH 0) + if(NOT USE_LOCAL_TEST_BENCH) + if( "${CMAKE_PROJECT_NAME}" STREQUAL "hello-world" ) + message(STATUS "Include ${WOLFSSL_ROOT}/wolfcrypt/benchmark") + set(WOLFSSL_EXTRA_PROJECT_DIR "${WOLFSSL_ROOT}/wolfcrypt/benchmark") + endif() + + if( "${CMAKE_PROJECT_NAME}" STREQUAL "wolfssl_benchmark" ) + message(STATUS "Include ${WOLFSSL_ROOT}/wolfcrypt/benchmark") + set(WOLFSSL_EXTRA_PROJECT_DIR "${WOLFSSL_ROOT}/wolfcrypt/benchmark") + endif() + + if( "${CMAKE_PROJECT_NAME}" STREQUAL "wolfssl_test" ) + message(STATUS "Include ${WOLFSSL_ROOT}/wolfcrypt/test") + set(WOLFSSL_EXTRA_PROJECT_DIR "${WOLFSSL_ROOT}/wolfcrypt/test") + endif() + endif() + + set(COMPONENT_SRCDIRS "\"${WOLFSSL_ROOT}/src/\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/port/Espressif\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/port/atmel\"" + "\"${WOLFSSL_EXTRA_PROJECT_DIR}\"" + ) # COMPONENT_SRCDIRS + + message(STATUS "This COMPONENT_SRCDIRS = ${COMPONENT_SRCDIRS}") + + # wolfSSL user_settings.h is in the local project. + set(WOLFSSL_PROJECT_DIR "${CMAKE_HOME_DIRECTORY}/components/wolfssl") + + string(REPLACE "/" "//" STR_WOLFSSL_PROJECT_DIR "${WOLFSSL_PROJECT_DIR}") + add_definitions(-DWOLFSSL_USER_SETTINGS_DIR="${STR_WOLFSSL_PROJECT_DIR}//include//user_settings.h") + + # Espressif may take several passes through this makefile. Check to see if we found IDF + string(COMPARE EQUAL "${PROJECT_SOURCE_DIR}" "" WOLFSSL_FOUND_IDF) + + # get a list of all wolfcrypt assembly files; we'll exclude them as they don't target Xtensa + file(GLOB EXCLUDE_ASM *.S) + file(GLOB EXCLUDE_ASM ${CMAKE_SOURCE_DIR} "${WOLFSSL_ROOT}/wolfcrypt/src/*.S") + + message(STATUS "IDF_PATH = $ENV{IDF_PATH}") + message(STATUS "PROJECT_SOURCE_DIR = ${PROJECT_SOURCE_DIR}") + message(STATUS "EXCLUDE_ASM = ${EXCLUDE_ASM}") + + # + # Check to see if there's both a local copy and EDP-IDF copy of the wolfssl and/or wolfssh components. + # + if( EXISTS "${WOLFSSL_PROJECT_DIR}" AND EXISTS "$ENV{IDF_PATH}/components/wolfssl/" ) + # + # wolfSSL found in both ESP-IDF and local project - needs to be resolved by user + # + message(STATUS "") + message(STATUS "**************************************************************************************") + message(STATUS "") + message(STATUS "Error: Found components/wolfssl in both local project and IDF_PATH") + message(STATUS "") + message(STATUS "To proceed: ") + message(STATUS "") + message(STATUS "Remove either the local project component: ${WOLFSSL_PROJECT_DIR} ") + message(STATUS "or the Espressif shared component installed at: $ENV{IDF_PATH}/components/wolfssl/ ") + message(STATUS "") + message(STATUS "") + message(STATUS "**************************************************************************************") + message(STATUS "") + + message(FATAL_ERROR "Please use wolfSSL in either local project or Espressif components, but not both.") + # Abort CMake after fatal error. + + # Optional: if you change the above FATAL_ERROR to STATUS you can warn at runtime with this macro definition: + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_MULTI_INSTALL_WARNING") + + else() + if( EXISTS "$ENV{IDF_PATH}/components/wolfssl/" ) + # + # wolfSSL found in ESP-IDF components and is assumed to be already configured in user_settings.h via setup. + # + message(STATUS "") + message(STATUS "Using components/wolfssl in IDF_PATH = $ENV{IDF_PATH}") + message(STATUS "") + else() + # + # wolfSSL is not an ESP-IDF component. + # We need to now determine if it is local and if so if it is part of the wolfSSL repo, + # or if wolfSSL is simply installed as a local component. + # + + if( EXISTS "${WOLFSSL_PROJECT_DIR}" ) + # + # wolfSSL found in local project. + # + if( EXISTS "${WOLFSSL_PROJECT_DIR}/wolfcrypt/" ) + message(STATUS "") + message(STATUS "Using installed project ./components/wolfssl in CMAKE_HOME_DIRECTORY = ${CMAKE_HOME_DIRECTORY}") + message(STATUS "") + # + # Note we already checked above and confirmed there's not another wolfSSL installed in the ESP-IDF components. + # + # We won't do anything else here, as it will be assumed the original install completed successfully. + # + else() # full wolfSSL not installed in local project + # + # This is the developer repo mode. wolfSSL will be assumed to be not installed to ESP-IDF nor local project + # In this configuration, we are likely running a wolfSSL example found directly in the repo. + # + message(STATUS "") + message(STATUS "Using developer repo ./components/wolfssl in CMAKE_HOME_DIRECTORY = ${CMAKE_HOME_DIRECTORY}") + message(STATUS "") + + message(STATUS "************************************************************************************************") + # When in developer mode, we are typically running wolfSSL examples such as benchmark or test directories. + # However, the as-cloned or distributed wolfSSL does not have the ./include/ directory, so we'll add it as needed. + # + # first check if there's a [root]/include/user_settings.h + if( EXISTS "${WOLFSSL_ROOT}/include/user_settings.h" ) + message(FATAL_ERROR "Found stray wolfSSL user_settings.h in " + "${WOLFSSL_ROOT}/include/user_settings.h " + " (please move it to ${WOLFSSL_PROJECT_DIR}/include/user_settings.h )") + # Abort CMake after fatal error. + else() + # we won't overwrite an existing user settings file, just note that we already have one: + if( EXISTS "${WOLFSSL_PROJECT_DIR}/include/user_settings.h" ) + message(STATUS "Using existing wolfSSL user_settings.h in " + "${WOLFSSL_PROJECT_DIR}/include/user_settings.h") + else() + message(STATUS "Installing wolfSSL user_settings.h to " + "${WOLFSSL_PROJECT_DIR}/include/user_settings.h") + file(COPY "${WOLFSSL_ROOT}/IDE/Espressif/ESP-IDF/user_settings.h" + DESTINATION "${CMAKE_HOME_DIRECTORY}/wolfssl/include/") + endif() + endif() # user_settings.h + + # next check if there's a [root]/include/config.h + if( EXISTS "${WOLFSSL_ROOT}/include/config.h" ) + message(STATUS "******************************************************************************") + message(STATUS "******************************************************************************") + message(STATUS "Found stray wolfSSL config.h in ${WOLFSSL_ROOT}/include/config.h" ) + message(STATUS " Please move it to ${WOLFSSL_PROJECT_DIR}/include/config.h" ) + message(STATUS "******************************************************************************") + message(STATUS "******************************************************************************") + else() + # we won't overwrite an existing user settings file, just note that we already have one: + if( EXISTS "${WOLFSSL_PROJECT_DIR}/include/config.h" ) + message(STATUS "Using existing wolfSSL config.h ${WOLFSSL_PROJECT_DIR}/include/config.h") + else() + message(STATUS "Installing wolfSSL config.h to ${WOLFSSL_PROJECT_DIR}/include/config.h") + file(COPY "${WOLFSSL_ROOT}/IDE/Espressif/ESP-IDF/dummy_config_h" DESTINATION "${WOLFSSL_PROJECT_DIR}/include/") + file(RENAME "${WOLFSSL_PROJECT_DIR}/include/dummy_config_h" "${WOLFSSL_PROJECT_DIR}/include/config.h") + endif() # Project config.h + endif() # WOLFSSL_ROOT config.h + message(STATUS "************************************************************************************************") + message(STATUS "") + endif() + + else() + # we did not find a ./components/wolfssl/include/ directory from this pass of cmake. + if($WOLFSSL_FOUND_IDF) + message(STATUS "") + message(STATUS "WARNING: wolfSSL not found.") + message(STATUS "") + else() + # probably needs to be re-parsed by Espressif + message(STATUS "wolfSSL found IDF. Project Source:${PROJECT_SOURCE_DIR}") + endif() # else we have not found ESP-IDF yet + endif() # else not a local wolfSSL component + + endif() #else not an ESP-IDF component + endif() # else not local copy and EDP-IDF wolfSSL + + + # RTOS_IDF_PATH is typically: + # "/Users/{username}/Desktop/esp-idf/components/freertos/include/freertos" + # depending on the environment, we may need to swap backslashes with forward slashes + string(REPLACE "\\" "/" RTOS_IDF_PATH "$ENV{IDF_PATH}/components/freertos/FreeRTOS-Kernel/include/freertos") + + string(REPLACE "\\" "/" WOLFSSL_ROOT ${WOLFSSL_ROOT}) + + if(IS_DIRECTORY "${RTOS_IDF_PATH}") + message(STATUS "Found current RTOS path: ${RTOS_IDF_PATH}") + else() + # ESP-IDF prior version 4.4x has a different RTOS directory structure + string(REPLACE "\\" "/" RTOS_IDF_PATH "$ENV{IDF_PATH}/components/freertos/include/freertos") + if(IS_DIRECTORY "${RTOS_IDF_PATH}") + message(STATUS "Found legacy RTOS path: ${RTOS_IDF_PATH}") + else() + message(STATUS "Could not find RTOS path") + endif() + endif() + + # wolfSSL-specific include directories + set(COMPONENT_ADD_INCLUDEDIRS + "./include" # this is the location of local project wolfssl user_settings.h + "\"${WOLFSSL_ROOT}/\"" + "\"${WOLFSSL_ROOT}/wolfssl/\"" + "\"${WOLFSSL_ROOT}/wolfssl/wolfcrypt/\"" + "\"${WOLFSSL_ROOT}/wolfssl/wolfcrypt/port/Espressif\"" + "\"${RTOS_IDF_PATH}/\"" + ) + + # Optionally include cryptoauthlib if present + if(IS_DIRECTORY ${IDF_PATH}/components/cryptoauthlib) + list(APPEND COMPONENT_ADD_INCLUDEDIRS "../cryptoauthlib/lib") + endif() + + list(APPEND COMPONENT_ADD_INCLUDEDIRS "\"${WOLFSSL_ROOT}/wolfssl/\"") + list(APPEND COMPONENT_ADD_INCLUDEDIRS "\"${WOLFSSL_ROOT}/wolfssl/wolfcrypt/\"") + + + # Some files are known to be included elsewhere, or not used for Espressif + set(COMPONENT_SRCEXCLUDE + "\"${WOLFSSL_ROOT}/src/bio.c\"" + "\"${WOLFSSL_ROOT}/src/conf.c\"" + "\"${WOLFSSL_ROOT}/src/misc.c\"" + "\"${WOLFSSL_ROOT}/src/pk.c\"" + "\"${WOLFSSL_ROOT}/src/ssl_asn1.c\"" # included by ssl.c + "\"${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_misc.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/x509.c\"" + "\"${WOLFSSL_ROOT}/src/x509_str.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/evp.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/misc.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_arm32.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_arm64.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_armthumb.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_c32.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_c64.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_cortexm.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_x86_64.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_x86_64_asm.S\"" + "\"${EXCLUDE_ASM}\"" + ) + + spaces2list(COMPONENT_REQUIRES) + + separate_arguments(COMPONENT_SRCDIRS NATIVE_COMMAND "${COMPONENT_SRCDIRS}") + separate_arguments(COMPONENT_SRCEXCLUDE NATIVE_COMMAND "${COMPONENT_SRCEXCLUDE}") + separate_arguments(COMPONENT_ADD_INCLUDEDIRS NATIVE_COMMAND "${COMPONENT_ADD_INCLUDEDIRS}") + + # + # See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html#example-component-requirements + # + message(STATUS "COMPONENT_SRCDIRS = ${COMPONENT_SRCDIRS}") + message(STATUS "COMPONENT_ADD_INCLUDEDIRS = ${COMPONENT_ADD_INCLUDEDIRS}") + message(STATUS "COMPONENT_REQUIRES = ${COMPONENT_REQUIRES}") + message(STATUS "COMPONENT_SRCEXCLUDE = ${COMPONENT_SRCEXCLUDE}") + + # + # see https://docs.espressif.com/projects/esp-idf/en/stable/esp32/migration-guides/release-5.x/build-system.html?highlight=space%20path + # + set(EXTRA_COMPONENT_DIRS "${COMPONENT_SRCDIRS}") + idf_component_register( + SRC_DIRS "${COMPONENT_SRCDIRS}" + INCLUDE_DIRS "${COMPONENT_ADD_INCLUDEDIRS}" + REQUIRES "${COMPONENT_REQUIRES}" + EXCLUDE_SRCS "${COMPONENT_SRCEXCLUDE}" + PRIV_REQUIRES + "${THIS_INCLUDE_TIMER}" + "${THIS_INCLUDE_DRIVER}" # this will typically only be needed for wolfSSL benchmark + ) + + # Some optional diagnostics. Verbose ones are truncated. + if (VERBOSE_COMPONENT_MESSAGES) + get_cmake_property(_variableNames VARIABLES) + list (SORT _variableNames) + message(STATUS "") + message(STATUS "ALL VARIABLES BEGIN") + message(STATUS "") + foreach (_variableName ${_variableNames}) + if ( ("${_variableName}" STREQUAL "bootloader_binary_files") + OR ("${_variableName}" STREQUAL "Component paths") + OR ("${_variableName}" STREQUAL "component_targets") + OR ("${_variableName}" STREQUAL "__COMPONENT_TARGETS") + OR ("${_variableName}" STREQUAL "CONFIGS_LIST") + OR ("${_variableName}" STREQUAL "__CONFIG_VARIABLES") + OR ("${_variableName}" STREQUAL "val") + OR ("${_variableName}" MATCHES "^__idf_") + ) + # Truncate the displayed value: + string(SUBSTRING "${${_variableName}}" 0 70 truncatedValue) + message(STATUS "${_variableName} = ${truncatedValue} ... (truncated)") + else() + message(STATUS "${_variableName}=${${_variableName}}") + endif() + endforeach() + message(STATUS "") + message(STATUS "ALL VARIABLES END") + message(STATUS "") + endif() + + # target_sources(wolfssl PRIVATE "\"${WOLFSSL_ROOT}/wolfssl/\"" "\"${WOLFSSL_ROOT}/wolfssl/wolfcrypt\"") + +endif() # CMAKE_BUILD_EARLY_EXPANSION + + + +# check to see if there's both a local copy and EDP-IDF copy of the wolfssl components +if( EXISTS "${WOLFSSL_PROJECT_DIR}" AND EXISTS "$ENV{IDF_PATH}/components/wolfssl/" ) + message(STATUS "") + message(STATUS "") + message(STATUS "********************************************************************") + message(STATUS "WARNING: Found components/wolfssl in both local project and IDF_PATH") + message(STATUS "********************************************************************") + message(STATUS "") +endif() +# end multiple component check + + +# +# LIBWOLFSSL_SAVE_INFO(VAR_OUPUT THIS_VAR VAR_RESULT) +# +# Save the THIS_VAR as a string in a macro called VAR_OUPUT +# +# VAR_OUPUT: the name of the macro to define +# THIS_VAR: the OUTPUT_VARIABLE result from a execute_process() +# VAR_RESULT: the RESULT_VARIABLE from a execute_process(); "0" if successful. +# +function ( LIBWOLFSSL_SAVE_INFO VAR_OUPUT THIS_VAR VAR_RESULT ) + # is the RESULT_VARIABLE output value 0? If so, IS_VALID_VALUE is true. + string(COMPARE EQUAL "${VAR_RESULT}" "0" IS_VALID_VALUE) + + # if we had a successful operation, save the THIS_VAR in VAR_OUPUT + if(${IS_VALID_VALUE}) + # strip newline chars in THIS_VAR parameter and save in VAR_VALUE + string(REPLACE "\n" "" VAR_VALUE ${THIS_VAR}) + + # we'll could percolate the value to the parent for possible later use + # set(${VAR_OUPUT} ${VAR_VALUE} PARENT_SCOPE) + + # but we're only using it here in this function + set(${VAR_OUPUT} ${VAR_VALUE}) + + # we'll print what we found to the console + message(STATUS "Found ${VAR_OUPUT}=${VAR_VALUE}") + + # the interesting part is defining the VAR_OUPUT name a value to use in the app + add_definitions(-D${VAR_OUPUT}=\"${VAR_VALUE}\") + else() + # if we get here, check the execute_process command and parameters. + message(STATUS "LIBWOLFSSL_SAVE_INFO encountered a non-zero VAR_RESULT") + set(${VAR_OUPUT} "Unknown") + endif() +endfunction() # LIBWOLFSSL_SAVE_INFO + +# create some programmatic #define values that will be used by ShowExtendedSystemInfo(). +# see wolfcrypt\src\port\Espressif\esp32_utl.c +if(NOT CMAKE_BUILD_EARLY_EXPANSION) + set (git_cmd "git") + message(STATUS "Adding macro definitions:") + + # LIBWOLFSSL_VERSION_GIT_ORIGIN: git config --get remote.origin.url + execute_process(WORKING_DIRECTORY ${WOLFSSL_ROOT} COMMAND ${git_cmd} "config" "--get" "remote.origin.url" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_GIT_ORIGIN "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSL_VERSION_GIT_BRANCH: git rev-parse --abbrev-ref HEAD + execute_process(WORKING_DIRECTORY ${WOLFSSL_ROOT} COMMAND ${git_cmd} "rev-parse" "--abbrev-ref" "HEAD" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_GIT_BRANCH "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSL_VERSION_GIT_HASH: git rev-parse HEAD + execute_process(WORKING_DIRECTORY ${WOLFSSL_ROOT} COMMAND ${git_cmd} "rev-parse" "HEAD" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_GIT_HASH "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSL_VERSION_GIT_SHORT_HASH: git rev-parse --short HEAD + execute_process(WORKING_DIRECTORY ${WOLFSSL_ROOT} COMMAND ${git_cmd} "rev-parse" "--short" "HEAD" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_GIT_SHORT_HASH "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSL_VERSION_GIT_HASH_DATE git show --no-patch --no-notes --pretty=\'\%cd\' + execute_process(WORKING_DIRECTORY ${WOLFSSL_ROOT} COMMAND ${git_cmd} "show" "--no-patch" "--no-notes" "--pretty=\'\%cd\'" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ) + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_GIT_HASH_DATE "${TMP_OUT}" "${TMP_RES}") + + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_WOLFSSL_ROOT "${WOLFSSL_ROOT}" "${TMP_RES}") + + message(STATUS "************************************************************************************************") + message(STATUS "wolfssl component config complete!") + message(STATUS "************************************************************************************************") +endif() diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssl/README.md b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssl/README.md new file mode 100644 index 000000000..040c8c0ba --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssl/README.md @@ -0,0 +1,9 @@ +# Component wolfSSL + +This `wolfssl` directory exists only for the stand-alone examples. + +The only files of interest are the [CMakeLists.txt](./CMakeLists.txt) that should point +to the wolfSSL source code and the respective [include/user_settings.h](./include/user_settings.h). + +This directory is _not_ included in the publish to the Espressif Registry, as that +mechanism copies the published source code to the local component directory as needed. 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 new file mode 100644 index 000000000..41f588a01 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/components/wolfssl/include/user_settings.h @@ -0,0 +1,508 @@ +/* user_settings.h + * + * Copyright (C) 2006-2023 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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 + * (at your option) any later version. + * + * wolfSSL 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 + */ + +#include /* essential to chip set detection */ + +#undef WOLFSSL_ESPIDF +#undef WOLFSSL_ESP32 +#undef WOLFSSL_ESPWROOM32SE +#undef WOLFSSL_ESP32 +#undef WOLFSSL_ESP8266 + +#define WOLFSSL_ESPIDF + +/* The Espressif sdkconfig will have chipset info. +** +** Possible values: +** +** CONFIG_IDF_TARGET_ESP32 +** CONFIG_IDF_TARGET_ESP32S2 +** CONFIG_IDF_TARGET_ESP32S3 +** CONFIG_IDF_TARGET_ESP32C3 +** CONFIG_IDF_TARGET_ESP32C6 +*/ + +/* Optionally enable some wolfSSH settings */ +#ifdef ESP_ENABLE_WOLFSSH + /* The default SSH Windows size is massive for an embedded target. Limit it: */ + #define DEFAULT_WINDOW_SZ 2000 + + /* These may be defined in cmake for other examples: */ + #undef WOLFSSH_TERM + #define WOLFSSH_TERM + + #undef DEBUG_WOLFSSH + #define DEBUG_WOLFSSH + + #undef WOLFSSL_KEY_GEN + #define WOLFSSL_KEY_GEN + + #undef WOLFSSL_PTHREADS + #define WOLFSSL_PTHREADS + + #define WOLFSSH_TEST_SERVER + #define WOLFSSH_TEST_THREADING + +#endif /* ESP_ENABLE_WOLFSSH */ + +/* when you want to use SINGLE THREAD */ +/* #define SINGLE_THREADED */ + +/* + * choose ONE of these Espressif chips to define: + * + * WOLFSSL_ESP32 + * WOLFSSL_ESPWROOM32SE + * WOLFSSL_ESP8266 + */ + +#define WOLFSSL_ESP32 + +/* optionally turn off SHA512/224 SHA512/256 */ +/* #define WOLFSSL_NOSHA512_224 */ +/* #define WOLFSSL_NOSHA512_256 */ + +/* when you want to use SINGLE THREAD. Note Default ESP-IDF is FreeRTOS */ +/* #define SINGLE_THREADED */ + +/* When you don't want to use the old SHA */ +/* #define NO_SHA */ +/* #define NO_OLD_TLS */ + +#define BENCH_EMBEDDED +#define USE_CERT_BUFFERS_2048 + +#define NO_OLD_TLS +/* TLS 1.3 + #define WOLFSSL_TLS13 + #define HAVE_TLS_EXTENSIONS + #define WC_RSA_PSS + #define HAVE_SUPPORTED_CURVES +*/ + +#define HAVE_HKDF +#define HAVE_AEAD + +#define NO_FILESYSTEM + +#define HAVE_AESGCM + +#define WOLFSSL_RIPEMD +/* when you want to use SHA224 */ +/* #define WOLFSSL_SHA224 */ + + +/* when you want to use SHA384 */ +/* #define WOLFSSL_SHA384 */ + +/* #define WOLFSSL_SHA3 */ + +#define WOLFSSL_SHA512 + +#define MY_USE_ECC 1 +#define MY_USE_RSA 0 + +/* We can use either or both ECC and RSA, but must use at least one. */ +#if MY_USE_ECC || MY_USE_RSA + #if MY_USE_ECC + /* ---- ECDSA / ECC ---- */ + #define HAVE_ECC + #define HAVE_CURVE25519 + #define HAVE_ED25519 + + /* + #define HAVE_ECC384 + #define CURVE25519_SMALL + */ + #else + #define WOLFSSH_NO_ECC + /* WOLFSSH_NO_ECDSA is typically defined automatically, + * here for clarity: */ + #define WOLFSSH_NO_ECDSA + #endif + + #if MY_USE_RSA + /* ---- RSA ----- */ + /* #define RSA_LOW_MEM */ + + /* DH disabled by default, needed if ECDSA/ECC also turned off */ + #define HAVE_DH + #else + #define WOLFSSH_NO_RSA + #endif +#else + #error "Either RSA or ECC must be enabled" +#endif + + +/* when you want to use pkcs7 */ +/* #define HAVE_PKCS7 */ + +#if defined(HAVE_PKCS7) + #define HAVE_AES_KEYWRAP + #define HAVE_X963_KDF + #define WOLFSSL_AES_DIRECT +#endif + +/* when you want to use aes counter mode */ +/* #define WOLFSSL_AES_DIRECT */ +/* #define WOLFSSL_AES_COUNTER */ + +/* debug options */ +/* #define DEBUG_WOLFSSL */ +/* #define WOLFSSL_ESP32_CRYPT_DEBUG */ +/* #define WOLFSSL_ATECC508A_DEBUG */ + +/* date/time */ +/* if it cannot adjust time in the device, */ +/* enable macro below */ +/* #define NO_ASN_TIME */ +/* #define XTIME time */ + +/* adjust wait-timeout count if you see timeout in RSA HW acceleration */ +#define ESP_RSA_TIMEOUT_CNT 0x249F00 + + +/* USE_FAST_MATH is default */ +#define USE_FAST_MATH + +/***** Use SP_MATH *****/ +/* #undef USE_FAST_MATH */ +/* #define SP_MATH */ +/* #define WOLFSSL_SP_MATH_ALL */ +/* #define WOLFSSL_SP_RISCV32 */ + +/***** Use Integer Heap Math *****/ +/* #undef USE_FAST_MATH */ +/* #define USE_INTEGER_HEAP_MATH */ + + +#define WOLFSSL_SMALL_STACK + +/* The ESP32 has some detailed statup information available:*/ +#define HAVE_VERSION_EXTENDED_INFO + +/* optional SM4 Ciphers. See https://github.com/wolfSSL/wolfsm */ +/* +#define WOLFSSL_SM2 +#define WOLFSSL_SM3 +#define WOLFSSL_SM4 +*/ + +#if defined(WOLFSSL_SM2) || defined(WOLFSSL_SM3) || defined(WOLFSSL_SM4) + /* SM settings, possible cipher suites: + + TLS13-AES128-GCM-SHA256 + TLS13-CHACHA20-POLY1305-SHA256 + TLS13-SM4-GCM-SM3 + TLS13-SM4-CCM-SM3 + + #define WOLFSSL_ESP32_CIPHER_SUITE "TLS13-SM4-GCM-SM3" + #define WOLFSSL_ESP32_CIPHER_SUITE "TLS13-SM4-CCM-SM3" + #define WOLFSSL_ESP32_CIPHER_SUITE "ECDHE-ECDSA-SM4-CBC-SM3" + #define WOLFSSL_ESP32_CIPHER_SUITE "ECDHE-ECDSA-SM4-GCM-SM3" + #define WOLFSSL_ESP32_CIPHER_SUITE "ECDHE-ECDSA-SM4-CCM-SM3" + #define WOLFSSL_ESP32_CIPHER_SUITE "TLS13-SM4-GCM-SM3:" \ + "TLS13-SM4-CCM-SM3:" + */ + + #undef WOLFSSL_BASE16 + #define WOLFSSL_BASE16 /* required for WOLFSSL_SM2 */ + + #undef WOLFSSL_SM4_ECB + #define WOLFSSL_SM4_ECB + + #undef WOLFSSL_SM4_CBC + #define WOLFSSL_SM4_CBC + + #undef WOLFSSL_SM4_CTR + #define WOLFSSL_SM4_CTR + + #undef WOLFSSL_SM4_GCM + #define WOLFSSL_SM4_GCM + + #undef WOLFSSL_SM4_CCM + #define WOLFSSL_SM4_CCM + + #define HAVE_POLY1305 + #define HAVE_CHACHA + + #undef HAVE_AESGCM + #define HAVE_AESGCM +#else + /* default settings */ + #define USE_CERT_BUFFERS_2048 +#endif + +/* esp32-wroom-32se specific definition */ +#if defined(WOLFSSL_ESPWROOM32SE) + #define WOLFSSL_ATECC508A + #define HAVE_PK_CALLBACKS + /* when you want to use a custom slot allocation for ATECC608A */ + /* unless your configuration is unusual, you can use default */ + /* implementation. */ + /* #define CUSTOM_SLOT_ALLOCATION */ +#endif + +/* Default is HW enabled unless turned off. +** Uncomment these lines to force SW instead of HW acceleration */ + +#if defined(CONFIG_IDF_TARGET_ESP32) || defined(WOLFSSL_ESPWROOM32SE) + /* wolfSSL HW Acceleration supported on ESP32. Uncomment to disable: */ + /* #define NO_ESP32_CRYPT */ + /* #define NO_WOLFSSL_ESP32_CRYPT_HASH */ + /* #define NO_WOLFSSL_ESP32_CRYPT_AES */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD */ + + /* These are defined automatically in esp32-crypt.h, here for clarity: */ + /* no SHA224 HW on ESP32 */ + #define NO_WOLFSSL_ESP32_CRYPT_HASH_SHA224 + + /* Define USE_FAST_MATH and SMALL_STACK */ + #define ESP32_USE_RSA_PRIMITIVE + + /* threshold for performance adjustment for HW primitive use */ + /* X bits of G^X mod P greater than */ + #define EPS_RSA_EXPT_XBTIS 32 + + /* X and Y of X * Y mod P greater than */ + #undef ESP_RSA_MULM_BITS + #define ESP_RSA_MULM_BITS 16 + + /***** END CONFIG_IDF_TARGET_ESP32 *****/ + +#elif defined(CONFIG_IDF_TARGET_ESP32S2) + /* wolfSSL HW Acceleration supported on ESP32-S2. Uncomment to disable: */ + /* #define NO_ESP32_CRYPT */ + /* #define NO_WOLFSSL_ESP32_CRYPT_HASH */ + /* Note: There's no AES192 HW on the ESP32-S2; falls back to SW */ + /* #define NO_WOLFSSL_ESP32_CRYPT_AES */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD */ + /***** END CONFIG_IDF_TARGET_ESP32S2 *****/ + +#elif defined(CONFIG_IDF_TARGET_ESP32S3) + /* wolfSSL HW Acceleration supported on ESP32-S3. Uncomment to disable: */ + /* #define NO_ESP32_CRYPT */ + /* #define NO_WOLFSSL_ESP32_CRYPT_HASH */ + /* Note: There's no AES192 HW on the ESP32-S3; falls back to SW */ + /* #define NO_WOLFSSL_ESP32_CRYPT_AES */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD */ + /***** END CONFIG_IDF_TARGET_ESP32S3 *****/ + +#elif defined(CONFIG_IDF_TARGET_ESP32C2) || \ + defined(CONFIG_IDF_TARGET_ESP8684) + /* ESP8684 is essentially ESP32-C2 chip + flash embedded together in a + * single QFN 4x4 mm package. Out of released documentation, Technical + * Reference Manual as well as ESP-IDF Programming Guide is applicable + * to both ESP32-C2 and ESP8684. + * + * See: https://www.esp32.com/viewtopic.php?f=5&t=27926#:~:text=ESP8684%20is%20essentially%20ESP32%2DC2,both%20ESP32%2DC2%20and%20ESP8684. */ + + /* wolfSSL HW Acceleration supported on ESP32-C2. Uncomment to disable: */ + /* #define NO_ESP32_CRYPT */ + /* #define NO_WOLFSSL_ESP32_CRYPT_HASH */ /* to disable all SHA HW */ + + /* These are defined automatically in esp32-crypt.h, here for clarity */ + #define NO_WOLFSSL_ESP32_CRYPT_HASH_SHA384 /* no SHA384 HW on C2 */ + #define NO_WOLFSSL_ESP32_CRYPT_HASH_SHA512 /* no SHA512 HW on C2 */ + + /* There's no AES or RSA/Math accelerator on the ESP32-C2 + * Auto defined with NO_WOLFSSL_ESP32_CRYPT_RSA_PRI, for clarity: */ + #define NO_WOLFSSL_ESP32_CRYPT_AES + #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI + #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL + #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD + #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD + /***** END CONFIG_IDF_TARGET_ESP32C2 *****/ + +#elif defined(CONFIG_IDF_TARGET_ESP32C3) + /* wolfSSL HW Acceleration supported on ESP32-C3. Uncomment to disable: */ + + /* #define NO_ESP32_CRYPT */ + /* #define NO_WOLFSSL_ESP32_CRYPT_HASH */ /* to disable all SHA HW */ + + /* These are defined automatically in esp32-crypt.h, here for clarity: */ + #define NO_WOLFSSL_ESP32_CRYPT_HASH_SHA384 /* no SHA384 HW on C6 */ + #define NO_WOLFSSL_ESP32_CRYPT_HASH_SHA512 /* no SHA512 HW on C6 */ + + /* #define NO_WOLFSSL_ESP32_CRYPT_AES */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD */ + /***** END CONFIG_IDF_TARGET_ESP32C3 *****/ + +#elif defined(CONFIG_IDF_TARGET_ESP32C6) + /* wolfSSL HW Acceleration supported on ESP32-C6. Uncomment to disable: */ + + /* #define NO_ESP32_CRYPT */ + /* #define NO_WOLFSSL_ESP32_CRYPT_HASH */ + /* These are defined automatically in esp32-crypt.h, here for clarity: */ + #define NO_WOLFSSL_ESP32_CRYPT_HASH_SHA384 /* no SHA384 HW on C6 */ + #define NO_WOLFSSL_ESP32_CRYPT_HASH_SHA512 /* no SHA512 HW on C6 */ + + /* #define NO_WOLFSSL_ESP32_CRYPT_AES */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD */ + /***** END CONFIG_IDF_TARGET_ESP32C6 *****/ + +#elif defined(CONFIG_IDF_TARGET_ESP32H2) + /* wolfSSL Hardware Acceleration not yet implemented */ + #define NO_ESP32_CRYPT + #define NO_WOLFSSL_ESP32_CRYPT_HASH + #define NO_WOLFSSL_ESP32_CRYPT_AES + #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI + /***** END CONFIG_IDF_TARGET_ESP32H2 *****/ + +#elif defined(CONFIG_IDF_TARGET_ESP8266) + /* TODO: Revisit ESP8266 */ + #define NO_ESP32_CRYPT + #define NO_WOLFSSL_ESP32_CRYPT_HASH + #define NO_WOLFSSL_ESP32_CRYPT_AES + #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI + /***** END CONFIG_IDF_TARGET_ESP266 *****/ + +#elif defined(CONFIG_IDF_TARGET_ESP8684) + /* There's no Hardware Acceleration available on ESP8684 */ + #define NO_ESP32_CRYPT + #define NO_WOLFSSL_ESP32_CRYPT_HASH + #define NO_WOLFSSL_ESP32_CRYPT_AES + #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI + /***** END CONFIG_IDF_TARGET_ESP8684 *****/ + +#else + /* Anything else encountered, disable HW accleration */ + #define NO_ESP32_CRYPT + #define NO_WOLFSSL_ESP32_CRYPT_HASH + #define NO_WOLFSSL_ESP32_CRYPT_AES + #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI +#endif /* CONFIG_IDF_TARGET Check */ + +/* Debug options: + +#define ESP_VERIFY_MEMBLOCK +#define DEBUG_WOLFSSL +#define DEBUG_WOLFSSL_VERBOSE +#define DEBUG_WOLFSSL_SHA_MUTEX +#define WOLFSSL_ESP32_CRYPT_DEBUG +#define WOLFSSL_ESP32_CRYPT_HASH_SHA224_DEBUG +#define NO_RECOVER_SOFTWARE_CALC +#define WOLFSSL_TEST_STRAY 1 +#define USE_ESP_DPORT_ACCESS_READ_BUFFER +#define WOLFSSL_ESP32_HW_LOCK_DEBUG +#define WOLFSSL_DEBUG_ESP_RSA_MULM_BITS +#define ESP_DISABLE_HW_TASK_LOCK +*/ + +/* Pause in a loop rather than exit. */ +#define WOLFSSL_ESPIDF_ERROR_PAUSE + +/* #define WOLFSSL_HW_METRICS */ + +/* for test.c */ +/* #define HASH_SIZE_LIMIT */ + +/* Optionally turn off HW math checks */ +/* #define NO_HW_MATH_TEST */ + +/* Optionally include alternate HW test library: alt_hw_test.h */ +/* When enabling, the ./components/wolfssl/CMakeLists.txt file + * will need the name of the library in the idf_component_register + * for the PRIV_REQUIRES list. */ +/* #define INCLUDE_ALT_HW_TEST */ + +/* optionally turn off individual math HW acceleration features */ + +/* Turn off Large Number ESP32 HW Multiplication: +** [Z = X * Y] in esp_mp_mul() */ +/* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL */ + +/* Turn off Large Number ESP32 HW Modular Exponentiation: +** [Z = X^Y mod M] in esp_mp_exptmod() */ +/* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD */ + +/* Turn off Large Number ESP32 HW Modular Multiplication +** [Z = X * Y mod M] in esp_mp_mulmod() */ +/* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD */ + +#define WOLFSSL_PUBLIC_MP /* used by benchmark */ +#define USE_CERT_BUFFERS_2048 + +/* when turning on ECC508 / ECC608 support +#define WOLFSSL_ESPWROOM32SE +#define HAVE_PK_CALLBACKS +#define WOLFSSL_ATECC508A +#define ATCA_WOLFSSL +*/ + +/* optional SM4 Ciphers. See https://github.com/wolfSSL/wolfsm +#define WOLFSSL_SM2 +#define WOLFSSL_SM3 +#define WOLFSSL_SM4 +*/ + +#if defined(WOLFSSL_SM2) || defined(WOLFSSL_SM3) || defined(WOLFSSL_SM4) + #include + #define CTX_CA_CERT root_sm2 + #define CTX_CA_CERT_SIZE sizeof_root_sm2 + #define CTX_CA_CERT_TYPE WOLFSSL_FILETYPE_PEM + #define CTX_SERVER_CERT server_sm2 + #define CTX_SERVER_CERT_SIZE sizeof_server_sm2 + #define CTX_SERVER_CERT_TYPE WOLFSSL_FILETYPE_PEM + #define CTX_SERVER_KEY server_sm2_priv + #define CTX_SERVER_KEY_SIZE sizeof_server_sm2_priv + #define CTX_SERVER_KEY_TYPE WOLFSSL_FILETYPE_PEM + + #undef WOLFSSL_BASE16 + #define WOLFSSL_BASE16 +#else + #define USE_CERT_BUFFERS_2048 + #define USE_CERT_BUFFERS_256 + #define CTX_CA_CERT ca_cert_der_2048 + #define CTX_CA_CERT_SIZE sizeof_ca_cert_der_2048 + #define CTX_CA_CERT_TYPE WOLFSSL_FILETYPE_ASN1 + #define CTX_SERVER_CERT server_cert_der_2048 + #define CTX_SERVER_CERT_SIZE sizeof_server_cert_der_2048 + #define CTX_SERVER_CERT_TYPE WOLFSSL_FILETYPE_ASN1 + #define CTX_SERVER_KEY server_key_der_2048 + #define CTX_SERVER_KEY_SIZE sizeof_server_key_der_2048 + #define CTX_SERVER_KEY_TYPE WOLFSSL_FILETYPE_ASN1 +#endif + +/* See settings.h for some of the possible hardening options: + * + * #define NO_ESPIDF_DEFAULT + * #define WC_NO_CACHE_RESISTANT + * #define WC_AES_BITSLICED + * #define HAVE_AES_ECB + * #define HAVE_AES_DIRECT + */ diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/CMakeLists.txt b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/CMakeLists.txt new file mode 100644 index 000000000..d58c2ae1c --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/CMakeLists.txt @@ -0,0 +1,155 @@ +# [wolfSSL Project]/main/CMakeLists.txt +# +# Copyright (C) 2006-2023 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 2 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA +# +# cmake for WOLFSSH Espressif projects +# +# See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html +# wolfSSL wolfSSH Espressif Example Project/main/CMakeLists.txt +# v1.0 +# +message(STATUS "main cmake found WOLFSSL_COMPONENT_NAME = ${WOLFSSL_COMPONENT_NAME}") + +if(WIN32) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_WINDOWS") + message("Detected Windows") +endif() +if(CMAKE_HOST_UNIX) + message("Detected UNIX") +endif() +if(APPLE) + message("Detected APPLE") +endif() +if(CMAKE_HOST_UNIX AND (NOT APPLE) AND EXISTS "/proc/sys/fs/binfmt_misc/WSLInterop") + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_WSL") + message("Detected WSL") +endif() +if(CMAKE_HOST_UNIX AND (NOT APPLE) AND (NOT WIN32)) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_LINUX") + message("Detected Linux") +endif() +if(APPLE) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_APPLE") + message("Detected Apple") +endif() +set (git_cmd "git") + +if( EXISTS "${CMAKE_HOME_DIRECTORY}/components/wolfssl/" AND EXISTS "$ENV{IDF_PATH}/components/wolfssl/" ) + # + # wolfSSL found in both ESP-IDF and local project - needs to be resolved by user + # + message(STATUS "") + message(STATUS "WARNING: Found components/wolfssl in both local project and IDF_PATH") + message(STATUS "") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_MULTI_INSTALL_WARNING") +endif() + +if( "$ENV{IDF_COMPONENT_REGISTRY_URL}" STREQUAL "https://components-staging.espressif.com" ) + if( ("${managed_components}" STREQUAL "") AND ("${component_manager_interface_version}" STREQUAL "") ) + # We've found a staging component, but did not detect the component manager + if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/../components/mywolfssh/CMakeLists.txt) + # This is typically during publish-time build test + message(STATUS "Set name mywolfssh (1)") + set(WOLFSSL_COMPONENT_NAME "mywolfssl") + set(WOLFSSH_COMPONENT_NAME "mywolfssh") + else() + if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/../managed_components/gojimmypi__mywolfmqtt/CMakeLists.txt) + # This is typically upon creating a project from managed component examples + message(STATUS "Set name mywolfssh (2)") + set(WOLFSSL_COMPONENT_NAME "mywolfssl") + set(WOLFSSH_COMPONENT_NAME "mywolfssh") + else() + message(STATUS "Set name wolfmqtt (1) CMAKE_CURRENT_LIST_DIR = ${CMAKE_CURRENT_LIST_DIR}") + set(WOLFSSL_COMPONENT_NAME "wolfssl") + set(WOLFSSH_COMPONENT_NAME "wolfssh") + endif() + endif() + else() + message(STATUS "Set name mywolfssh (3)") + set(WOLFSSL_COMPONENT_NAME "mywolfssl") + set(WOLFSSH_COMPONENT_NAME "mywolfssh") + endif() +else() + message(STATUS "Set name wolfssh (2)") + set(WOLFSSL_COMPONENT_NAME "wolfssl") + set(WOLFSSH_COMPONENT_NAME "wolfssh") +endif() + +## register_component() +idf_component_register( + SRCS main.c echoserver.c time_helper.c wifi_connect.c + INCLUDE_DIRS "." "./include") +# + +# +# LIBWOLFSSL_SAVE_INFO(VAR_OUPUT THIS_VAR VAR_RESULT) +# +# Save the THIS_VAR as a string in a macro called VAR_OUPUT +# +# VAR_OUPUT: the name of the macro to define +# THIS_VAR: the OUTPUT_VARIABLE result from a execute_process() +# VAR_RESULT: the RESULT_VARIABLE from a execute_process(); "0" if successful. +# +function ( LIBWOLFSSL_SAVE_INFO VAR_OUPUT THIS_VAR VAR_RESULT ) + # is the RESULT_VARIABLE output value 0? If so, IS_VALID_VALUE is true. + string(COMPARE EQUAL "${VAR_RESULT}" "0" IS_VALID_VALUE) + + # if we had a successful operation, save the THIS_VAR in VAR_OUPUT + if(${IS_VALID_VALUE}) + # strip newline chars in THIS_VAR parameter and save in VAR_VALUE + string(REPLACE "\n" "" VAR_VALUE ${THIS_VAR}) + + # we'll could percolate the value to the parent for possible later use + # set(${VAR_OUPUT} ${VAR_VALUE} PARENT_SCOPE) + + # but we're only using it here in this function + set(${VAR_OUPUT} ${VAR_VALUE}) + + # we'll print what we found to the console + message(STATUS "Found ${VAR_OUPUT}=${VAR_VALUE}") + + # the interesting part is defining the VAR_OUPUT name a value to use in the app + add_definitions(-D${VAR_OUPUT}=\"${VAR_VALUE}\") + else() + # if we get here, check the execute_process command and parameters. + message(STATUS "LIBWOLFSSL_SAVE_INFO encountered a non-zero VAR_RESULT") + set(${VAR_OUPUT} "Unknown") + endif() +endfunction() # LIBWOLFSSL_SAVE_INFO + +if(NOT CMAKE_BUILD_EARLY_EXPANSION) + # LIBWOLFSSL_VERSION_GIT_HASH + execute_process(COMMAND ${git_cmd} "rev-parse" "HEAD" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_GIT_HASH "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSL_VERSION_GIT_SHORT_HASH + execute_process(COMMAND ${git_cmd} "rev-parse" "--short" "HEAD" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_GIT_SHORT_HASH "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSL_VERSION_GIT_HASH_DATE + execute_process(COMMAND ${git_cmd} "show" "--no-patch" "--no-notes" "--pretty=\'\%cd\'" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ) + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_GIT_HASH_DATE "${TMP_OUT}" "${TMP_RES}") +endif() + +message(STATUS "") + diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/echoserver.c b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/echoserver.c new file mode 100644 index 000000000..2eae60762 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/echoserver.c @@ -0,0 +1,2737 @@ +/* echoserver.c + * + * Copyright (C) 2014-2023 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 . + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#define WOLFSSH_TEST_SERVER +#define WOLFSSH_TEST_ECHOSERVER + +#ifdef WOLFSSL_USER_SETTINGS + #include +#else + #include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "echoserver.h" + +#if defined(WOLFSSL_PTHREADS) && defined(WOLFSSL_TEST_GLOBAL_REQ) + #include +#endif + +#if defined(WOLFSSH_SHELL) && defined(USE_WINDOWS_API) +#pragma message ("echoserver with shell on windows is not supported, use wolfSSHd instead") +#undef WOLFSSH_SHELL +#endif + +#if defined(WOLFSSL_NUCLEUS) || defined(WOLFSSH_ZEPHYR) + /* use buffers for keys with server */ + #define NO_FILESYSTEM + #define WOLFSSH_NO_EXIT +#endif + +#ifdef NO_FILESYSTEM + #include +#endif + +#ifdef WOLFSSH_SHELL + #ifdef HAVE_PTY_H + #include + #endif + #ifdef HAVE_UTIL_H + #include + #endif + #ifdef HAVE_TERMIOS_H + #include + #endif +#ifndef USE_WINDOWS_API + #include +#endif + #include +#if defined(__QNX__) || defined(__QNXNTO__) + #include + #include + +#elif defined(USE_WINDOWS_API) + #include +#else + #include +#endif +#endif /* WOLFSSH_SHELL */ + +#ifdef WOLFSSH_AGENT + #include + #include + #include +#endif /* WOLFSSH_AGENT */ + +#ifdef HAVE_SYS_SELECT_H + #include +#endif + +#ifndef USE_WINDOWS_API + #include + #define SOCKET_ERRNO errno + #define SOCKET_ECONNRESET ECONNRESET + #define SOCKET_ECONNABORTED ECONNABORTED + #define SOCKET_EWOULDBLOCK EWOULDBLOCK +#else + #include + #define SOCKET_ERRNO WSAGetLastError() + #define SOCKET_ECONNRESET WSAECONNRESET + #define SOCKET_ECONNABORTED WSAECONNABORTED + #define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK +#endif + + +#ifndef NO_WOLFSSH_SERVER + +static const char echoserverBanner[] = "wolfSSH Example Echo Server\n"; + +static int quit = 0; +wolfSSL_Mutex doneLock; +#define MAX_PASSWD_RETRY 3 +static int passwdRetry = MAX_PASSWD_RETRY; + + +#ifndef EXAMPLE_HIGHWATER_MARK + #define EXAMPLE_HIGHWATER_MARK 0x3FFF8000 /* 1GB - 32kB */ +#endif + +#ifndef EXAMPLE_BUFFER_SZ + #define EXAMPLE_BUFFER_SZ 4096 +#endif + +#ifndef EXAMPLE_KEYLOAD_BUFFER_SZ + #define EXAMPLE_KEYLOAD_BUFFER_SZ 1200 +#endif + + +#ifdef WOLFSSH_AGENT +typedef struct WS_AgentCbActionCtx { + struct sockaddr_un name; + WS_SOCKET_T listenFd; + WS_SOCKET_T fd; + pid_t pid; + int state; +} WS_AgentCbActionCtx; +#endif + + +#ifdef WOLFSSH_FWD +enum FwdStates { + FWD_STATE_INIT, + FWD_STATE_LISTEN, + FWD_STATE_CONNECT, + FWD_STATE_CONNECTED, + FWD_STATE_DIRECT, +}; + +typedef struct WS_FwdCbActionCtx { + void* heap; + char* hostName; + char* originName; + word16 hostPort; + word16 originPort; + WS_SOCKET_T listenFd; + WS_SOCKET_T appFd; + int error; + int state; + int isDirect; + word32 channelId; +} WS_FwdCbActionCtx; +#endif + + +typedef struct { + WOLFSSH* ssh; + WS_SOCKET_T fd; + word32 id; + int echo; + char nonBlock; +#if defined(WOLFSSL_PTHREADS) && defined(WOLFSSL_TEST_GLOBAL_REQ) + WOLFSSH_CTX *ctx; +#endif +#ifdef WOLFSSH_AGENT + WS_AgentCbActionCtx agentCbCtx; + byte agentBuffer[EXAMPLE_BUFFER_SZ]; +#endif +#ifdef WOLFSSH_FWD + WS_FwdCbActionCtx fwdCbCtx; + byte fwdBuffer[EXAMPLE_BUFFER_SZ]; +#endif +#ifdef WOLFSSH_SHELL + byte shellBuffer[EXAMPLE_BUFFER_SZ]; +#endif + byte channelBuffer[EXAMPLE_BUFFER_SZ]; + char statsBuffer[EXAMPLE_BUFFER_SZ]; +} thread_ctx_t; + + +static byte find_char(const byte* str, const byte* buf, word32 bufSz) +{ + const byte* cur; + + while (bufSz) { + cur = str; + while (*cur != '\0') { + if (*cur == *buf) + return *cur; + cur++; + } + buf++; + bufSz--; + } + + return 0; +} + + +static int dump_stats(thread_ctx_t* ctx) +{ + word32 statsSz; + word32 txCount, rxCount, seq, peerSeq; + + wolfSSH_GetStats(ctx->ssh, &txCount, &rxCount, &seq, &peerSeq); + + WSNPRINTF(ctx->statsBuffer, sizeof ctx->statsBuffer, + "Statistics for Thread #%u:\r\n" + " txCount = %u\r\n rxCount = %u\r\n" + " seq = %u\r\n peerSeq = %u\r\n", + ctx->id, txCount, rxCount, seq, peerSeq); + statsSz = (word32)WSTRLEN(ctx->statsBuffer); + + fprintf(stderr, "%s", ctx->statsBuffer); + return wolfSSH_stream_send(ctx->ssh, (byte*)ctx->statsBuffer, statsSz); +} + + +static int process_bytes(thread_ctx_t* threadCtx, + const byte* buffer, word32 bufferSz) +{ + int stop = 0; + byte c; + const byte matches[] = { 0x03, 0x05, 0x06, 0x00 }; + + c = find_char(matches, buffer, bufferSz); + switch (c) { + case 0x03: + stop = 1; + break; + case 0x05: + if (dump_stats(threadCtx) <= 0) + stop = 1; + break; + case 0x06: + if (wolfSSH_TriggerKeyExchange(threadCtx->ssh) != WS_SUCCESS) + stop = 1; + break; + } + return stop; +} + + +#if defined(WOLFSSL_PTHREADS) && defined(WOLFSSL_TEST_GLOBAL_REQ) + +#define SSH_TIMEOUT 10 + +static int callbackReqSuccess(WOLFSSH *ssh, void *buf, word32 sz, void *ctx) +{ + if ((WOLFSSH *)ssh != *(WOLFSSH **)ctx){ + printf("ssh(%x) != ctx(%x)\n", (unsigned int)ssh, + (unsigned int)*(WOLFSSH **)ctx); + return WS_FATAL_ERROR; + } + printf("Global Request Success[%d]: %s\n", sz, sz>0?buf:"No payload"); + return WS_SUCCESS; +} + +static int callbackReqFailure(WOLFSSH *ssh, void *buf, word32 sz, void *ctx) +{ + if ((WOLFSSH *)ssh != *(WOLFSSH **)ctx) + { + printf("ssh(%x) != ctx(%x)\n", (unsigned int)ssh, + (unsigned int)*(WOLFSSH **)ctx); + return WS_FATAL_ERROR; + } + printf("Global Request Failure[%d]: %s\n", sz, sz > 0 ? buf : "No payload"); + return WS_SUCCESS; +} + +static void *global_req(void *ctx) +{ + int ret; + const char str[] = "SampleRequest"; + thread_ctx_t *threadCtx = (thread_ctx_t *)ctx; + byte buf[0]; + + wolfSSH_SetReqSuccess(threadCtx->ctx, callbackReqSuccess); + wolfSSH_SetReqSuccessCtx(threadCtx->ssh, &threadCtx->ssh); /* dummy ctx */ + wolfSSH_SetReqFailure(threadCtx->ctx, callbackReqFailure); + wolfSSH_SetReqFailureCtx(threadCtx->ssh, &threadCtx->ssh); /* dummy ctx */ + + while(1){ + + sleep(SSH_TIMEOUT); + + ret = wolfSSH_global_request(threadCtx->ssh, (const unsigned char *)str, + WSTRLEN(str), 1); + if (ret != WS_SUCCESS) + { + printf("Global Request Failed.\n"); + wolfSSH_shutdown(threadCtx->ssh); + return NULL; + } + + wolfSSH_stream_read(threadCtx->ssh, buf, 0); + if (ret != WS_SUCCESS) + { + printf("wolfSSH_stream_read Failed.\n"); + wolfSSH_shutdown(threadCtx->ssh); + return NULL; + } + } + return NULL; +} + +#endif + + +#ifdef WOLFSSH_AGENT + +static const char EnvNameAuthPort[] = "SSH_AUTH_SOCK"; + +static int wolfSSH_AGENT_DefaultActions(WS_AgentCbAction action, void* vCtx) +{ + WS_AgentCbActionCtx* ctx = (WS_AgentCbActionCtx*)vCtx; + int ret = 0; + + if (action == WOLFSSH_AGENT_LOCAL_SETUP) { + struct sockaddr_un* name = &ctx->name; + size_t size; + + WMEMSET(name, 0, sizeof(struct sockaddr_un)); + ctx->pid = getpid(); + name->sun_family = AF_LOCAL; + + ret = snprintf(name->sun_path, sizeof(name->sun_path), + "/tmp/wolfserver.%d", ctx->pid); + + if (ret == 0) { + name->sun_path[sizeof(name->sun_path) - 1] = '\0'; + size = WSTRLEN(name->sun_path) + + offsetof(struct sockaddr_un, sun_path); + ctx->listenFd = socket(AF_UNIX, SOCK_STREAM, 0); + if (ctx->listenFd == -1) { + ret = -1; + } + } + + if (ret == 0) { + ret = bind(ctx->listenFd, + (struct sockaddr *)name, (socklen_t)size); + } + + if (ret == 0) { + ret = setenv(EnvNameAuthPort, name->sun_path, 1); + } + + if (ret == 0) { + ret = listen(ctx->listenFd, 5); + } + + if (ret == 0) { + ctx->state = AGENT_STATE_LISTEN; + } + else { + ret = WS_AGENT_SETUP_E; + } + } + else if (action == WOLFSSH_AGENT_LOCAL_CLEANUP) { + WCLOSESOCKET(ctx->listenFd); + unlink(ctx->name.sun_path); + unsetenv(EnvNameAuthPort); + } + else + ret = WS_AGENT_INVALID_ACTION; + + return ret; +} + +#endif + + +#ifdef WOLFSSH_FWD + +static WS_SOCKET_T connect_addr(const char* name, word16 port) +{ + WS_SOCKET_T newSocket = -1; + int ret; + struct addrinfo hints, *hint, *hint0 = NULL; + char portStr[6]; + + WMEMSET(&hints, 0, sizeof hints); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + snprintf(portStr, sizeof portStr, "%u", port); + + ret = getaddrinfo(name, portStr, &hints, &hint0); + if (ret) + return -1; + + for (hint = hint0; hint != NULL; hint = hint->ai_next) { + newSocket = socket(hint->ai_family, + hint->ai_socktype, hint->ai_protocol); + + if (newSocket < 0) + continue; + + if (connect(newSocket, hint->ai_addr, + (WS_SOCKLEN_T)hint->ai_addrlen) < 0) { + WCLOSESOCKET(newSocket); + newSocket = -1; + continue; + } + + break; + } + + freeaddrinfo(hint0); + + return newSocket; +} + + +static int wolfSSH_FwdDefaultActions(WS_FwdCbAction action, void* vCtx, + const char* name, word32 port) +{ + WS_FwdCbActionCtx* ctx = (WS_FwdCbActionCtx*)vCtx; + int ret = 0; + + if (action == WOLFSSH_FWD_LOCAL_SETUP) { + ctx->hostName = WSTRDUP(name, NULL, 0); + ctx->hostPort = port; + ctx->isDirect = 1; + ctx->state = FWD_STATE_DIRECT; + } + else if (action == WOLFSSH_FWD_LOCAL_CLEANUP) { + WCLOSESOCKET(ctx->appFd); + if (ctx->hostName) { + WFREE(ctx->hostName, NULL, 0); + ctx->hostName = NULL; + } + if (ctx->originName) { + WFREE(ctx->originName, NULL, 0); + ctx->originName = NULL; + } + ctx->state = FWD_STATE_INIT; + } + else if (action == WOLFSSH_FWD_REMOTE_SETUP) { + struct sockaddr_in addr; + socklen_t addrSz = 0; + + ctx->hostName = WSTRDUP(name, NULL, 0); + ctx->hostPort = port; + + ctx->listenFd = socket(AF_INET, SOCK_STREAM, 0); + if (ctx->listenFd == -1) { + ret = -1; + } + + if (ret == 0) { + + WMEMSET(&addr, 0, sizeof addr); + if (WSTRCMP(name, "") == 0 || + WSTRCMP(name, "0.0.0.0") == 0 || + WSTRCMP(name, "localhost") == 0 || + WSTRCMP(name, "127.0.0.1") == 0) { + + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_family = AF_INET; + addr.sin_port = htons((word16)port); + addrSz = sizeof addr; + } + else { + printf("Not using IPv6 yet.\n"); + ret = WS_FWD_SETUP_E; + } + } + + if (ret == 0) { + ret = bind(ctx->listenFd, + (const struct sockaddr*)&addr, addrSz); + } + + if (ret == 0) { + ret = listen(ctx->listenFd, 5); + } + + if (ret == 0) { + ctx->state = FWD_STATE_LISTEN; + } + else { + if (ctx->hostName != NULL) { + WFREE(ctx->hostName, NULL, 0); + ctx->hostName = NULL; + } + if (ctx->listenFd != -1) { + WCLOSESOCKET(ctx->listenFd); + ctx->listenFd = -1; + } + ret = WS_FWD_SETUP_E; + } + } + else if (action == WOLFSSH_FWD_REMOTE_CLEANUP) { + if (ctx->hostName) { + WFREE(ctx->hostName, NULL, 0); + ctx->hostName = NULL; + } + if (ctx->originName) { + WFREE(ctx->originName, NULL, 0); + ctx->originName = NULL; + } + if (ctx->listenFd != -1) { + WCLOSESOCKET(ctx->listenFd); + ctx->listenFd = -1; + } + ctx->state = FWD_STATE_INIT; + } + else if (action == WOLFSSH_FWD_CHANNEL_ID) { + ctx->channelId = port; + } + else + ret = WS_FWD_INVALID_ACTION; + + return ret; +} + +#endif /* WOLFSSH_FWD */ + + +#ifdef SHELL_DEBUG + +static void display_ascii(char *p_buf, + int count) +{ + int i; + + printf(" *"); + for (i = 0; i < count; i++) { + char tmp_char = p_buf[i]; + + if ((isalnum(tmp_char) || ispunct(tmp_char)) && (tmp_char > 0)) + printf("%c", tmp_char); + else + printf("."); + } + printf("*\n"); +} + + +static void buf_dump(unsigned char *buf, int len) +{ + int i; + + printf("\n"); + for (i = 0; issh; + if (ssh == NULL) + return WS_FATAL_ERROR; + + sshFd = wolfSSH_get_fd(ssh); + +#if defined(WOLFSSL_PTHREADS) && defined(WOLFSSL_TEST_GLOBAL_REQ) + /* submit Global Request for keep-alive */ + rc = pthread_create(&globalReq_th, NULL, global_req, threadCtx); + if (rc != 0) + printf("pthread_create() failed.\n"); +#endif + +#ifdef WOLFSSH_SHELL + if (!threadCtx->echo) { + + userName = wolfSSH_GetUsername(ssh); + p_passwd = getpwnam((const char *)userName); + if (p_passwd == NULL) { + /* Not actually a user on the system. */ + #ifdef SHELL_DEBUG + fprintf(stderr, "user %s does not exist\n", userName); + #endif + return WS_FATAL_ERROR; + } + + ChildRunning = 1; + childPid = forkpty(&childFd, NULL, NULL, NULL); + + if (childPid < 0) { + /* forkpty failed, so return */ + ChildRunning = 0; + return WS_FATAL_ERROR; + } + else if (childPid == 0) { + /* Child process */ + const char *args[] = {"-sh", NULL}; + + signal(SIGINT, SIG_DFL); + + #ifdef SHELL_DEBUG + printf("userName is %s\n", userName); + system("env"); + #endif + + setenv("HOME", p_passwd->pw_dir, 1); + setenv("LOGNAME", p_passwd->pw_name, 1); + rc = chdir(p_passwd->pw_dir); + if (rc != 0) { + return WS_FATAL_ERROR; + } + + execv("/bin/sh", (char **)args); + } + } +#endif + { + /* Parent process */ +#ifdef WOLFSSH_SHELL + struct termios tios; +#endif + word32 shellChannelId = 0; +#ifdef WOLFSSH_AGENT + WS_SOCKET_T agentFd = -1; + WS_SOCKET_T agentListenFd = threadCtx->agentCbCtx.listenFd; + word32 agentChannelId = -1; +#endif +#ifdef WOLFSSH_FWD + WS_SOCKET_T fwdFd = -1; + WS_SOCKET_T fwdListenFd = threadCtx->fwdCbCtx.listenFd; + word32 fwdBufferIdx = 0; +#endif + +#ifdef WOLFSSH_SHELL + if (!threadCtx->echo) { + #ifdef SHELL_DEBUG + printf("In childPid > 0; getpid=%d\n", (int)getpid()); + #endif + signal(SIGCHLD, ChildSig); + + rc = tcgetattr(childFd, &tios); + if (rc != 0) { + printf("tcgetattr failed: rc =%d,errno=%x\n", rc, errno); + return WS_FATAL_ERROR; + } + rc = tcsetattr(childFd, TCSAFLUSH, &tios); + if (rc != 0) { + printf("tcsetattr failed: rc =%d,errno=%x\n", rc, errno); + return WS_FATAL_ERROR; + } + + #ifdef SHELL_DEBUG + termios_show(childFd); + #endif + } + else + ChildRunning = 1; +#else + ChildRunning = 1; +#endif + + while (ChildRunning) { + fd_set readFds; + WS_SOCKET_T maxFd; + int cnt_r; + int cnt_w; + + FD_ZERO(&readFds); + FD_SET(sshFd, &readFds); + maxFd = sshFd; + +#ifdef WOLFSSH_SHELL + if (!threadCtx->echo) { + FD_SET(childFd, &readFds); + if (childFd > maxFd) + maxFd = childFd; + } +#endif +#ifdef WOLFSSH_AGENT + if (threadCtx->agentCbCtx.state == AGENT_STATE_LISTEN) { + FD_SET(agentListenFd, &readFds); + if (agentListenFd > maxFd) + maxFd = agentListenFd; + } + if (agentFd >= 0 && threadCtx->agentCbCtx.state == AGENT_STATE_CONNECTED) { + FD_SET(agentFd, &readFds); + if (agentFd > maxFd) + maxFd = agentFd; + } +#endif +#ifdef WOLFSSH_FWD + if (threadCtx->fwdCbCtx.state == FWD_STATE_LISTEN) { + FD_SET(fwdListenFd, &readFds); + if (fwdListenFd > maxFd) + maxFd = fwdListenFd; + } + if (fwdFd >= 0 && threadCtx->fwdCbCtx.state == FWD_STATE_CONNECTED) { + FD_SET(fwdFd, &readFds); + if (fwdFd > maxFd) + maxFd = fwdFd; + } +#endif + rc = select((int)maxFd + 1, &readFds, NULL, NULL, NULL); + if (rc == -1) + break; + + if (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, + threadCtx->channelBuffer, + sizeof threadCtx->channelBuffer); + if (cnt_r <= 0) + break; + #ifdef SHELL_DEBUG + buf_dump(threadCtx->channelBuffer, cnt_r); + #endif + #ifdef WOLFSSH_SHELL + if (!threadCtx->echo) { + cnt_w = (int)write(childFd, + threadCtx->channelBuffer, cnt_r); + } + else { + cnt_w = wolfSSH_ChannelIdSend(ssh, + shellChannelId, + threadCtx->channelBuffer, cnt_r); + if (cnt_r > 0) { + int doStop = process_bytes(threadCtx, + threadCtx->channelBuffer, + cnt_r); + ChildRunning = !doStop; + } + } + #else + cnt_w = wolfSSH_ChannelIdSend(ssh, shellChannelId, + threadCtx->channelBuffer, cnt_r); + if (cnt_r > 0) { + int doStop = process_bytes(threadCtx, + threadCtx->channelBuffer, cnt_r); + ChildRunning = !doStop; + } + #endif + if (cnt_w <= 0) + break; + } + #ifdef WOLFSSH_AGENT + if (lastChannel == agentChannelId) { + cnt_r = wolfSSH_ChannelIdRead(ssh, agentChannelId, + threadCtx->channelBuffer, + sizeof threadCtx->channelBuffer); + if (cnt_r <= 0) + break; + #ifdef SHELL_DEBUG + buf_dump(threadCtx->channelBuffer, cnt_r); + #endif + cnt_w = (int)send(agentFd, + threadCtx->channelBuffer, cnt_r, 0); + if (cnt_w <= 0) + break; + } + #endif + #ifdef WOLFSSH_FWD + if (threadCtx->fwdCbCtx.state == FWD_STATE_CONNECTED && + lastChannel == threadCtx->fwdCbCtx.channelId) { + + cnt_r = wolfSSH_ChannelIdRead(ssh, + threadCtx->fwdCbCtx.channelId, + threadCtx->channelBuffer, + sizeof threadCtx->channelBuffer); + if (cnt_r <= 0) + break; + #ifdef SHELL_DEBUG + buf_dump(threadCtx->channelBuffer, cnt_r); + #endif + cnt_w = (int)send(fwdFd, threadCtx->channelBuffer, + cnt_r, 0); + if (cnt_w <= 0) + break; + } + #endif + } + else if (rc == WS_CHANNEL_CLOSED) { + #ifdef WOLFSSH_FWD + if (threadCtx->fwdCbCtx.state == FWD_STATE_CONNECTED && + lastChannel == threadCtx->fwdCbCtx.channelId) { + /* Read zero-returned. Socket is closed. Go back + to listening. */ + if (fwdFd != -1) { + WCLOSESOCKET(fwdFd); + fwdFd = -1; + } + if (threadCtx->fwdCbCtx.originName != NULL) { + WFREE(threadCtx->fwdCbCtx.originName, + NULL, 0); + threadCtx->fwdCbCtx.originName = NULL; + } + threadCtx->fwdCbCtx.state = FWD_STATE_LISTEN; + } + #endif + continue; + } + else if (rc != WS_WANT_READ) { + #ifdef SHELL_DEBUG + printf("Break:read sshFd returns %d: errno =%x\n", + cnt_r, errno); + #endif + break; + } + } + } + + #ifdef WOLFSSH_SHELL + if (!threadCtx->echo) { + if (FD_ISSET(childFd, &readFds)) { + cnt_r = (int)read(childFd, + threadCtx->shellBuffer, + sizeof threadCtx->shellBuffer); + /* This read will return 0 on EOF */ + if (cnt_r <= 0) { + int err = errno; + if (err != EAGAIN) { + #ifdef SHELL_DEBUG + printf("Break:read childFd returns %d: " + "errno =%x\n", + cnt_r, err); + #endif + break; + } + } + else { + #ifdef SHELL_DEBUG + buf_dump(threadCtx->shellBuffer, cnt_r); + #endif + if (cnt_r > 0) { + cnt_w = wolfSSH_ChannelIdSend(ssh, shellChannelId, + threadCtx->shellBuffer, cnt_r); + if (cnt_w < 0) + break; + } + } + } + } + #endif + #ifdef WOLFSSH_AGENT + if (agentFd >= 0 && threadCtx->agentCbCtx.state == AGENT_STATE_CONNECTED) { + if (FD_ISSET(agentFd, &readFds)) { + #ifdef SHELL_DEBUG + printf("agentFd set in readfd\n"); + #endif + cnt_r = (int)recv(agentFd, + threadCtx->agentBuffer, + sizeof threadCtx->agentBuffer, 0); + if (cnt_r == 0) { + /* Read zero-returned. Socket is closed. Go back + to listening. */ + threadCtx->agentCbCtx.state = AGENT_STATE_LISTEN; + continue; + } + else if (cnt_r < 0) { + int err = SOCKET_ERRNO; + #ifdef SHELL_DEBUG + printf("Break:read agentFd returns %d: " + "errno = %d\n", cnt_r, err); + #endif + if (err == SOCKET_ECONNRESET || + err == SOCKET_ECONNABORTED) { + /* Connection reset. Socket is closed. + * Go back to listening. */ + threadCtx->agentCbCtx.state = AGENT_STATE_LISTEN; + continue; + } + break; + } + else { + #ifdef SHELL_DEBUG + buf_dump(threadCtx->agentBuffer, cnt_r); + #endif + cnt_w = wolfSSH_ChannelIdSend(ssh, agentChannelId, + threadCtx->agentBuffer, cnt_r); + if (cnt_w <= 0) { + break; + } + } + } + } + if (threadCtx->agentCbCtx.state == AGENT_STATE_LISTEN) { + if (FD_ISSET(agentListenFd, &readFds)) { + #ifdef SHELL_DEBUG + printf("accepting agent connection\n"); + #endif + agentFd = accept(agentListenFd, NULL, NULL); + if (agentFd == -1) { + rc = errno; + if (rc != SOCKET_EWOULDBLOCK) { + break; + } + } + else { + threadCtx->agentCbCtx.state = AGENT_STATE_CONNECTED; + threadCtx->agentCbCtx.fd = agentFd; + } + } + } + #endif + #ifdef WOLFSSH_FWD + if (fwdFd >= 0 && threadCtx->fwdCbCtx.state == FWD_STATE_CONNECTED) { + if (FD_ISSET(fwdFd, &readFds)) { + #ifdef SHELL_DEBUG + printf("fwdFd set in readfd\n"); + #endif + cnt_r = (int)recv(fwdFd, + threadCtx->fwdBuffer + fwdBufferIdx, + sizeof threadCtx->fwdBuffer - fwdBufferIdx, 0); + if (cnt_r == 0) { + /* Read zero-returned. Socket is closed. Go back + to listening. */ + WCLOSESOCKET(fwdFd); + fwdFd = -1; + if (threadCtx->fwdCbCtx.hostName != NULL) { + WFREE(threadCtx->fwdCbCtx.hostName, + NULL, 0); + threadCtx->fwdCbCtx.hostName = NULL; + } + threadCtx->fwdCbCtx.state = FWD_STATE_LISTEN; + continue; + } + else if (cnt_r < 0) { + int err = SOCKET_ERRNO; + + #ifdef SHELL_DEBUG + printf("Break:read fwdFd returns %d: " + "errno = %d\n", cnt_r, err); + #endif + if (err == SOCKET_ECONNRESET || + err == SOCKET_ECONNABORTED) { + /* Connection reset. Socket is closed. + * Go back to listening. */ + WCLOSESOCKET(fwdFd); + threadCtx->fwdCbCtx.state = FWD_STATE_LISTEN; + continue; + } + break; + } + else { + #ifdef SHELL_DEBUG + buf_dump(threadCtx->fwdBuffer, cnt_r); + #endif + fwdBufferIdx += cnt_r; + } + } + if (fwdBufferIdx > 0) { + cnt_w = wolfSSH_ChannelIdSend(ssh, + threadCtx->fwdCbCtx.channelId, + threadCtx->fwdBuffer, fwdBufferIdx); + if (cnt_w > 0) { + fwdBufferIdx = 0; + } + else if (cnt_w == WS_CHANNEL_NOT_CONF || + cnt_w == WS_CHAN_RXD) { + #ifdef SHELL_DEBUG + printf("Waiting for channel open confirmation.\n"); + #endif + } + else { + break; + } + } + } + if (threadCtx->fwdCbCtx.state == FWD_STATE_LISTEN) { + if (FD_ISSET(fwdListenFd, &readFds)) { + #ifdef SHELL_DEBUG + printf("accepting fwd connection\n"); + #endif + fwdFd = accept(fwdListenFd, NULL, NULL); + if (fwdFd == -1) { + rc = errno; + if (rc != SOCKET_EWOULDBLOCK) { + break; + } + } + else { + struct sockaddr_in6 originAddr; + socklen_t originAddrSz; + const char* out = NULL; + char addr[200]; + + threadCtx->fwdCbCtx.state = FWD_STATE_CONNECT; + threadCtx->fwdCbCtx.appFd = fwdFd; + originAddrSz = sizeof originAddr; + WMEMSET(&originAddr, 0, originAddrSz); + if (getpeername(fwdFd, + (struct sockaddr*)&originAddr, + &originAddrSz) == 0) { + + if (originAddr.sin6_family == AF_INET) { + struct sockaddr_in* addr4 = + (struct sockaddr_in*)&originAddr; + out = inet_ntop(AF_INET, + &addr4->sin_addr, + addr, sizeof addr); + } + else if (originAddr.sin6_family == AF_INET6) { + out = inet_ntop(AF_INET6, + &originAddr.sin6_addr, + addr, sizeof addr); + } + } + if (out != NULL) { + threadCtx->fwdCbCtx.originName = + WSTRDUP(addr, NULL, 0); + threadCtx->fwdCbCtx.originPort = + ntohs(originAddr.sin6_port); + } + } + } + } + if (threadCtx->fwdCbCtx.state == FWD_STATE_CONNECT) { + WOLFSSH_CHANNEL* newChannel; + + newChannel = wolfSSH_ChannelFwdNewRemote(ssh, + threadCtx->fwdCbCtx.hostName, + threadCtx->fwdCbCtx.hostPort, + threadCtx->fwdCbCtx.originName, + threadCtx->fwdCbCtx.originPort); + if (newChannel != NULL) { + threadCtx->fwdCbCtx.state = FWD_STATE_CONNECTED; + } + } + if (threadCtx->fwdCbCtx.state == FWD_STATE_DIRECT) { + fwdFd = connect_addr(threadCtx->fwdCbCtx.hostName, + threadCtx->fwdCbCtx.hostPort); + + if (fwdFd > 0) { + threadCtx->fwdCbCtx.state = FWD_STATE_CONNECTED; + } + } + #endif + } +#ifdef WOLFSSH_SHELL + if (!threadCtx->echo) + WCLOSESOCKET(childFd); +#endif + } + +#if defined(WOLFSSL_PTHREADS) && defined(WOLFSSL_TEST_GLOBAL_REQ) + pthread_join(globalReq_th, NULL); +#endif + + return 0; +} + + +#ifdef WOLFSSH_SFTP + +#define TEST_SFTP_TIMEOUT_SHORT 0 +#define TEST_SFTP_TIMEOUT 1 +#define TEST_SFTP_TIMEOUT_LONG 60 + +/* handle SFTP operations + * returns 0 on success + */ +static int sftp_worker(thread_ctx_t* threadCtx) +{ + WOLFSSH* ssh = threadCtx->ssh; + WS_SOCKET_T s; + int ret = WS_SUCCESS; + int error = -1; + int selected; + unsigned char peek_buf[1]; + int timeout = TEST_SFTP_TIMEOUT; + + s = (WS_SOCKET_T)wolfSSH_get_fd(ssh); + + do { + if (wolfSSH_SFTP_PendingSend(ssh)) { + /* Yes, process the SFTP data. */ + ret = wolfSSH_SFTP_read(ssh); + error = wolfSSH_get_error(ssh); + + if (ret == WS_REKEYING) { + timeout = TEST_SFTP_TIMEOUT; + } + else if (error == WS_WINDOW_FULL) { + timeout = TEST_SFTP_TIMEOUT_LONG; + } + else { + timeout = TEST_SFTP_TIMEOUT_SHORT; + } + + if (error == WS_WANT_READ || error == WS_WANT_WRITE || + error == WS_CHAN_RXD || error == WS_REKEYING || + error == WS_WINDOW_FULL) + ret = error; + if (error == WS_WANT_WRITE && wolfSSH_SFTP_PendingSend(ssh)) { + continue; /* no need to spend time attempting to pull data + * if there is still pending sends */ + } + if (error == WS_EOF) { + break; + } + } + + selected = tcp_select(s, timeout); + if (selected == WS_SELECT_ERROR_READY) { + break; + } + else if (selected == WS_SELECT_TIMEOUT) { + timeout = TEST_SFTP_TIMEOUT_LONG; + continue; + } + + if (ret == WS_WANT_READ || ret == WS_WANT_WRITE || + selected == WS_SELECT_RECV_READY) { + ret = wolfSSH_worker(ssh, NULL); + error = wolfSSH_get_error(ssh); + if (ret == WS_REKEYING) { + /* In a rekey, keeping turning the crank. */ + timeout = TEST_SFTP_TIMEOUT; + continue; + } + + if (error == WS_WANT_READ || error == WS_WANT_WRITE || + error == WS_WINDOW_FULL) { + timeout = TEST_SFTP_TIMEOUT; + ret = error; + continue; + } + + if (error == WS_EOF) { + break; + } + if (ret != WS_SUCCESS && ret != WS_CHAN_RXD) { + /* If not successful and no channel data, leave. */ + break; + } + } + + ret = wolfSSH_stream_peek(ssh, peek_buf, sizeof(peek_buf)); + if (ret > 0) { + /* Yes, process the SFTP data. */ + ret = wolfSSH_SFTP_read(ssh); + error = wolfSSH_get_error(ssh); + timeout = (ret == WS_REKEYING) ? + TEST_SFTP_TIMEOUT : TEST_SFTP_TIMEOUT_SHORT; + if (error == WS_WANT_READ || error == WS_WANT_WRITE || + error == WS_CHAN_RXD || error == WS_REKEYING || + error == WS_WINDOW_FULL) + ret = error; + if (error == WS_EOF) + break; + continue; + } + else if (ret == WS_REKEYING) { + timeout = TEST_SFTP_TIMEOUT; + continue; + } + else if (ret < 0) { + error = wolfSSH_get_error(ssh); + if (error == WS_EOF) + break; + } + + if (ret == WS_FATAL_ERROR && error == 0) { + WOLFSSH_CHANNEL* channel = + wolfSSH_ChannelNext(ssh, NULL); + if (channel && wolfSSH_ChannelGetEof(channel)) { + ret = 0; + break; + } + } + + } while (ret != WS_FATAL_ERROR); + + return ret; +} +#endif + +static int NonBlockSSH_accept(WOLFSSH* ssh) +{ + int ret; + int error; + WS_SOCKET_T sockfd; + int select_ret = 0; + + ret = wolfSSH_accept(ssh); + error = wolfSSH_get_error(ssh); + sockfd = (WS_SOCKET_T)wolfSSH_get_fd(ssh); + + while ((ret != WS_SUCCESS + && ret != WS_SCP_COMPLETE && ret != WS_SFTP_COMPLETE) + && (error == WS_WANT_READ || error == WS_WANT_WRITE)) { + + if (error == WS_WANT_READ) + printf("... server would read block\n"); + else if (error == WS_WANT_WRITE) + printf("... server would write block\n"); + + select_ret = tcp_select(sockfd, 1); + if (select_ret == WS_SELECT_RECV_READY || + select_ret == WS_SELECT_ERROR_READY || + error == WS_WANT_WRITE) + { + ret = wolfSSH_accept(ssh); + error = wolfSSH_get_error(ssh); + } + else if (select_ret == WS_SELECT_TIMEOUT) + error = WS_WANT_READ; + else + error = WS_FATAL_ERROR; + } + + return ret; +} + + +static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs) +{ + int ret = 0, error = 0; + thread_ctx_t* threadCtx = (thread_ctx_t*)vArgs; + + passwdRetry = MAX_PASSWD_RETRY; + + if (!threadCtx->nonBlock) + ret = wolfSSH_accept(threadCtx->ssh); + else + ret = NonBlockSSH_accept(threadCtx->ssh); + +#ifdef WOLFSSH_SCP + /* finish off SCP operation */ + if (ret == WS_SCP_INIT) { + if (!threadCtx->nonBlock) + ret = wolfSSH_accept(threadCtx->ssh); + else + ret = NonBlockSSH_accept(threadCtx->ssh); + } +#endif + + switch (ret) { + case WS_SCP_COMPLETE: + printf("scp file transfer completed\n"); + ret = 0; + break; + + #ifdef WOLFSSH_SFTP + case WS_SFTP_COMPLETE: + ret = sftp_worker(threadCtx); + break; + #endif + + case WS_SUCCESS: + ret = ssh_worker(threadCtx); + break; + } + + if (ret == WS_FATAL_ERROR) { + const char* errorStr; + error = wolfSSH_get_error(threadCtx->ssh); + + errorStr = wolfSSH_ErrorToName(error); + + if (error == WS_VERSION_E) { + ret = 0; /* don't break out of loop with version miss match */ + printf("%s\n", errorStr); + } + else if (error == WS_USER_AUTH_E) { + wolfSSH_SendDisconnect(threadCtx->ssh, + WOLFSSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE); + ret = 0; /* don't break out of loop with user auth error */ + printf("%s\n", errorStr); + } + else if (error == WS_SOCKET_ERROR_E) { + ret = 0; + printf("%s\n", errorStr); + } + } + + if (error != WS_SOCKET_ERROR_E && error != WS_FATAL_ERROR) { + ret = wolfSSH_shutdown(threadCtx->ssh); + + /* peer hung up, stop shutdown */ + if (ret == WS_SOCKET_ERROR_E) { + ret = 0; + } + + error = wolfSSH_get_error(threadCtx->ssh); + if (error != WS_SOCKET_ERROR_E && + (error == WS_WANT_READ || error == WS_WANT_WRITE)) { + int maxAttempt = 10; /* make 10 attempts max before giving up */ + int attempt; + + for (attempt = 0; attempt < maxAttempt; attempt++) { + ret = wolfSSH_worker(threadCtx->ssh, NULL); + error = wolfSSH_get_error(threadCtx->ssh); + + /* peer succesfully closed down gracefully */ + if (ret == WS_CHANNEL_CLOSED) { + ret = 0; + break; + } + + /* peer hung up, stop shutdown */ + if (ret == WS_SOCKET_ERROR_E) { + ret = 0; + break; + } + + if (error == WS_WANT_READ || error == WS_WANT_WRITE) { + /* Wanting read or wanting write. Clear ret. */ + ret = 0; + } + else { + break; + } + } + + if (attempt == maxAttempt) { + printf("Gave up on gracefull shutdown, closing the socket\n"); + } + } + } + + if (threadCtx->fd != -1) { + WCLOSESOCKET(threadCtx->fd); + threadCtx->fd = -1; + } +#ifdef WOLFSSH_FWD + if (threadCtx->fwdCbCtx.hostName != NULL) { + WFREE(threadCtx->fwdCbCtx.hostName, NULL, 0); + threadCtx->fwdCbCtx.hostName = NULL; + } + if (threadCtx->fwdCbCtx.originName != NULL) { + WFREE(threadCtx->fwdCbCtx.originName, NULL, 0); + threadCtx->fwdCbCtx.originName = NULL; + } +#endif + wolfSSH_free(threadCtx->ssh); + + if (ret != 0) { + fprintf(stderr, "Error [%d] \"%s\" with handling connection.\n", ret, + wolfSSH_ErrorToName(error)); + #ifndef WOLFSSH_NO_EXIT + wc_LockMutex(&doneLock); + quit = 1; + wc_UnLockMutex(&doneLock); + #endif + } + + WFREE(threadCtx, NULL, 0); + + WOLFSSL_RETURN_FROM_THREAD(0); +} + +#ifndef NO_FILESYSTEM +/* set bufSz to size wanted if too small and buf is null */ +static int load_file(const char* fileName, byte* buf, word32* bufSz) +{ + WFILE* file; + word32 fileSz; + word32 readSz; + + if (fileName == NULL) return 0; + + if (WFOPEN(NULL, &file, fileName, "rb") != 0) + return 0; + WFSEEK(NULL, file, 0, WSEEK_END); + fileSz = (word32)WFTELL(NULL, file); + WREWIND(NULL, file); + + if (fileSz > *bufSz) { + if (buf == NULL) + *bufSz = fileSz; + WFCLOSE(NULL, file); + return 0; + } + + readSz = (word32)WFREAD(NULL, buf, 1, fileSz, file); + if (readSz < fileSz) { + WFCLOSE(NULL, file); + return 0; + } + + WFCLOSE(NULL, file); + + return fileSz; +} +#endif /* NO_FILESYSTEM */ + +#ifdef WOLFSSH_NO_ECDSA_SHA2_NISTP256 + #define ECC_PATH "./keys/server-key-ecc-521.der" +#else + #define ECC_PATH "./keys/server-key-ecc.der" +#endif + +/* returns buffer size on success */ +static int load_key(byte isEcc, byte* buf, word32 bufSz) +{ + word32 sz = 0; + +#ifndef NO_FILESYSTEM + const char* bufName; + bufName = isEcc ? ECC_PATH : "./keys/server-key-rsa.der" ; + sz = load_file(bufName, buf, &bufSz); +#else + /* using buffers instead */ + if (isEcc) { + if ((word32)sizeof_ecc_key_der_256 > bufSz) { + return 0; + } + WMEMCPY(buf, ecc_key_der_256, sizeof_ecc_key_der_256); + sz = sizeof_ecc_key_der_256; + } + else { + if ((word32)sizeof_rsa_key_der_2048 > bufSz) { + return 0; + } + WMEMCPY(buf, (byte*)rsa_key_der_2048, sizeof_rsa_key_der_2048); + sz = sizeof_rsa_key_der_2048; + } +#endif + + return sz; +} + + +typedef struct StrList { + const char* str; + struct StrList* next; +} StrList; + + +static StrList* StrListAdd(StrList* list, const char* str) +{ + if (str != NULL) { + StrList* newStr = (StrList*)WMALLOC(sizeof *newStr, NULL, 0); + + if (newStr != NULL) { + newStr->str = str; + newStr->next = list; + list = newStr; + } + } + + return list; +} + +static void StrListFree(StrList* list) +{ + StrList* curStr; + + while (list != NULL) { + curStr = list; + list = list->next; + WFREE(curStr, NULL, 0); + } +} + + +/* Map user names to passwords */ +/* Use arrays for username and p. The password or public key can + * be hashed and the hash stored here. Then I won't need the type. */ +typedef struct PwMap { + byte type; + byte username[32]; + word32 usernameSz; + byte p[WC_SHA256_DIGEST_SIZE]; + struct PwMap* next; +} PwMap; + + +typedef struct PwMapList { + PwMap* head; +} PwMapList; + + +static PwMap* PwMapNew(PwMapList* list, byte type, const byte* username, + word32 usernameSz, const byte* p, word32 pSz) +{ + PwMap* map; + + map = (PwMap*)WMALLOC(sizeof(PwMap), NULL, 0); + if (map != NULL) { + map->type = type; + if (usernameSz >= sizeof(map->username)) + usernameSz = sizeof(map->username) - 1; + WMEMCPY(map->username, username, usernameSz + 1); + map->username[usernameSz] = 0; + map->usernameSz = usernameSz; + + if (type != WOLFSSH_USERAUTH_NONE) { + wc_Sha256Hash(p, pSz, map->p); + } + + map->next = list->head; + list->head = map; + } + + return map; +} + + +static void PwMapListDelete(PwMapList* list) +{ + if (list != NULL) { + PwMap* head = list->head; + + while (head != NULL) { + PwMap* cur = head; + head = head->next; + WMEMSET(cur, 0, sizeof(PwMap)); + WFREE(cur, NULL, 0); + } + } +} + + +static const char samplePasswordBuffer[] = + "jill:upthehill\n" + "jack:fetchapail\n"; + + +#ifndef WOLFSSH_NO_ECC +#ifndef WOLFSSH_NO_ECDSA_SHA2_NISTP256 +static const char samplePublicKeyEccBuffer[] = + "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAA" + "BBBNkI5JTP6D0lF42tbxX19cE87hztUS6FSDoGvPfiU0CgeNSbI+aFdKIzTP5CQEJSvm25" + "qUzgDtH7oyaQROUnNvk= hansel\n" + "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAA" + "BBBKAtH8cqaDbtJFjtviLobHBmjCtG56DMkP6A4M2H9zX2/YCg1h9bYS7WHd9UQDwXO1Hh" + "IZzRYecXh7SG9P4GhRY= gretel\n"; +#elif !defined(WOLFSSH_NO_ECDSA_SHA2_NISTP521) +static const char samplePublicKeyEccBuffer[] = + "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAA" + "CFBAET/BOzBb9Jx9b52VIHFP4g/uk5KceDpz2M+/Ln9WiDjsMfb4NgNCAB+EMNJUX/TNBL" + "FFmqr7c6+zUH+QAo2qstvQDsReyFkETRB2vZD//nCZfcAe0RMtKZmgtQLKXzSlimUjXBM4" + "/zE5lwE05aXADp88h8nuaT/X4bll9cWJlH0fUykA== hansel\n" + "ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAA" + "CFBAD3gANmzvkxOBN8MYwRBYO6B//7TTCtA2vwG/W5bqiVVxznXWj0xiFrgayApvH7FDpL" + "HiJ8+c1vUsRVEa8PY5QPsgFow+xv0P2WSrRkn4/UUquftPs1ZHPhdr06LjS19ObvWM8xFZ" + "YU6n0i28UWCUR5qE+BCTzZDWYT8V24YD8UhpaYIw== gretel\n"; +#else + #error "Enable an ECC Curve or disable ECC." +#endif +#endif + +#ifndef WOLFSSH_NO_RSA +static const char samplePublicKeyRsaBuffer[] = + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9P3ZFowOsONXHD5MwWiCciXytBRZGho" + "MNiisWSgUs5HdHcACuHYPi2W6Z1PBFmBWT9odOrGRjoZXJfDDoPi+j8SSfDGsc/hsCmc3G" + "p2yEhUZUEkDhtOXyqjns1ickC9Gh4u80aSVtwHRnJZh9xPhSq5tLOhId4eP61s+a5pwjTj" + "nEhBaIPUJO2C/M0pFnnbZxKgJlX7t1Doy7h5eXxviymOIvaCZKU+x5OopfzM/wFkey0EPW" + "NmzI5y/+pzU5afsdeEWdiQDIQc80H6Pz8fsoFPvYSG+s4/wz0duu7yeeV1Ypoho65Zr+pE" + "nIf7dO0B8EblgWt+ud+JI8wrAhfE4x hansel\n" + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqDwRVTRVk/wjPhoo66+Mztrc31KsxDZ" + "+kAV0139PHQ+wsueNpba6jNn5o6mUTEOrxrz0LMsDJOBM7CmG0983kF4gRIihECpQ0rcjO" + "P6BSfbVTE9mfIK5IsUiZGd8SoE9kSV2pJ2FvZeBQENoAxEFk0zZL9tchPS+OCUGbK4SDjz" + "uNZl/30Mczs73N3MBzi6J1oPo7sFlqzB6ecBjK2Kpjus4Y1rYFphJnUxtKvB0s+hoaadru" + "biE57dK6BrH5iZwVLTQKux31uCJLPhiktI3iLbdlGZEctJkTasfVSsUizwVIyRjhVKmbdI" + "RGwkU38D043AR1h0mUoGCPIKuqcFMf gretel\n"; +#endif + + +#ifdef WOLFSSH_ALLOW_USERAUTH_NONE + +static const char sampleNoneBuffer[] = + "holmes\n" + "watson\n"; + + +static int LoadNoneBuffer(byte* buf, word32 bufSz, PwMapList* list) +{ + char* str = (char*)buf; + char* username; + + /* Each line of none list is in the format + * username\n + * This function modifies the passed-in buffer. */ + + if (list == NULL) + return -1; + + if (buf == NULL || bufSz == 0) + return 0; + + while (*str != 0) { + username = str; + str = WSTRCHR(username, '\n'); + if (str == NULL) { + return -1; + } + *str = 0; + str++; + if (PwMapNew(list, WOLFSSH_USERAUTH_NONE, + (byte*)username, (word32)WSTRLEN(username), + NULL, 0) == NULL ) { + + return -1; + } + } + + return 0; +} + +#endif /* WOLFSSH_ALLOW_USERAUTH_NONE */ + +static int LoadPasswordBuffer(byte* buf, word32 bufSz, PwMapList* list) +{ + char* str = (char*)buf; + char* delimiter; + char* username; + char* password; + + /* Each line of passwd.txt is in the format + * username:password\n + * This function modifies the passed-in buffer. */ + + if (list == NULL) + return -1; + + if (buf == NULL || bufSz == 0) + return 0; + + while (*str != 0) { + delimiter = WSTRCHR(str, ':'); + if (delimiter == NULL) { + return -1; + } + username = str; + *delimiter = 0; + password = delimiter + 1; + str = WSTRCHR(password, '\n'); + if (str == NULL) { + return -1; + } + *str = 0; + str++; + if (PwMapNew(list, WOLFSSH_USERAUTH_PASSWORD, + (byte*)username, (word32)WSTRLEN(username), + (byte*)password, (word32)WSTRLEN(password)) == NULL ) { + + return -1; + } + } + + return 0; +} + + +static int LoadPublicKeyBuffer(byte* buf, word32 bufSz, PwMapList* list) +{ + char* str = (char*)buf; + char* delimiter; + char* end = (char*)buf + bufSz; + byte* publicKey64; + word32 publicKey64Sz; + byte* username; + word32 usernameSz; + byte* publicKey; + word32 publicKeySz; + + /* Each line of passwd.txt is in the format + * ssh-rsa AAAB3BASE64ENCODEDPUBLICKEYBLOB username\n + * This function modifies the passed-in buffer. */ + if (list == NULL) + return -1; + + if (buf == NULL || bufSz == 0) + return 0; + + while (str < end && *str != 0) { + /* Skip the public key type. This example will always be ssh-rsa. */ + delimiter = WSTRCHR(str, ' '); + if (delimiter == NULL) { + return -1; + } + if (str >= end) + break; + str = delimiter + 1; + delimiter = WSTRCHR(str, ' '); + if (delimiter == NULL) { + return -1; + } + publicKey64 = (byte*)str; + *delimiter = 0; + publicKey64Sz = (word32)(delimiter - str); + if (str >= end) + break; + str = delimiter + 1; + delimiter = WSTRCHR(str, '\n'); + if (delimiter == NULL) { + return -1; + } + username = (byte*)str; + *delimiter = 0; + usernameSz = (word32)(delimiter - str); + str = delimiter + 1; + + /* more than enough space for base64 decode + * not using WMALLOC because internal.h is not included for DYNTYPE_* */ + publicKey = (byte*)WMALLOC(publicKey64Sz, NULL, 0); + if (publicKey == NULL) { + fprintf(stderr, "error with WMALLOC\n"); + return -1; + } + publicKeySz = publicKey64Sz; + + if (Base64_Decode(publicKey64, publicKey64Sz, + publicKey, &publicKeySz) != 0) { + + WFREE(publicKey, NULL, 0); + return -1; + } + + #ifdef DEBUG_WOLFSSH + printf("Adding public key for user : %s\n", username); + #endif + + if (PwMapNew(list, WOLFSSH_USERAUTH_PUBLICKEY, + username, usernameSz, + publicKey, publicKeySz) == NULL ) { + + WFREE(publicKey, NULL, 0); + return -1; + } + WFREE(publicKey, NULL, 0); + } + + return 0; +} + + +static int LoadPasswdList(StrList* strList, PwMapList* mapList) +{ + char names[256]; + char* passwd; + int count = 0; + + while (strList) { + WSTRNCPY(names, strList->str, sizeof names - 1); + passwd = WSTRCHR(names, ':'); + if (passwd != NULL) { + *passwd = 0; + passwd++; + + PwMapNew(mapList, WOLFSSH_USERAUTH_PASSWORD, + (byte*)names, (word32)WSTRLEN(names), + (byte*)passwd, (word32)WSTRLEN(passwd)); + } + else { + fprintf(stderr, "Ignoring password: %s\n", names); + } + + strList = strList->next; + count++; + } + + return count; +} + +#ifndef NO_FILESYSTEM +static int LoadPubKeyList(StrList* strList, int format, PwMapList* mapList) +{ + char names[256]; + char* fileName; + byte* buf; + word32 bufSz; + int count = 0; + + while (strList) { + buf = NULL; + bufSz = 0; + + WSTRNCPY(names, strList->str, sizeof names - 1); + fileName = WSTRCHR(names, ':'); + if (fileName != NULL) { + *fileName = 0; + fileName++; + + load_file(fileName, NULL, &bufSz); + buf = (byte*)WMALLOC(bufSz, NULL, 0); + bufSz = load_file(fileName, buf, &bufSz); + if (bufSz > 0) { + if (format == WOLFSSH_FORMAT_SSH) { + const byte* type = NULL; + byte* out = NULL; + word32 typeSz, outSz; + + wolfSSH_ReadKey_buffer(buf, bufSz, WOLFSSH_FORMAT_SSH, + &out, &outSz, &type, &typeSz, NULL); + + (void)type; + (void)typeSz; + + WFREE(buf, NULL, 0); + buf = out; + bufSz = outSz; + } + else if (format == WOLFSSH_FORMAT_PEM) { + byte* out = NULL; + word32 outSz; + + out = (byte*)WMALLOC(bufSz, NULL, 0); + outSz = wc_CertPemToDer(buf, bufSz, out, bufSz, CERT_TYPE); + + WFREE(buf, NULL, 0); + buf = out; + bufSz = outSz; + } + + PwMapNew(mapList, WOLFSSH_USERAUTH_PUBLICKEY, + (byte*)names, (word32)WSTRLEN(names), buf, bufSz); + } + else { + fprintf(stderr, "File error: %s\n", names); + } + } + else { + fprintf(stderr, "Ignoring key: %s\n", names); + } + + WFREE(buf, NULL, 0); + strList = strList->next; + count++; + } + + return count; +} +#endif + +static int wsUserAuthResult(byte res, + WS_UserAuthData* authData, + void* ctx) +{ + printf("In auth result callback, auth = %s\n", + (res == WOLFSSH_USERAUTH_SUCCESS) ? "Success" : "Failure"); + (void)authData; + (void)ctx; + return WS_SUCCESS; +} + + +static int wsUserAuth(byte authType, + WS_UserAuthData* authData, + void* ctx) +{ + PwMapList* list; + PwMap* map; + byte authHash[WC_SHA256_DIGEST_SIZE]; + + if (ctx == NULL) { + fprintf(stderr, "wsUserAuth: ctx not set"); + return WOLFSSH_USERAUTH_FAILURE; + } + + if (authType != WOLFSSH_USERAUTH_PASSWORD && +#ifdef WOLFSSH_ALLOW_USERAUTH_NONE + authType != WOLFSSH_USERAUTH_NONE && +#endif + authType != WOLFSSH_USERAUTH_PUBLICKEY) { + + return WOLFSSH_USERAUTH_FAILURE; + } + + if (authType == WOLFSSH_USERAUTH_PASSWORD) { + wc_Sha256Hash(authData->sf.password.password, + authData->sf.password.passwordSz, + authHash); + } + else if (authType == WOLFSSH_USERAUTH_PUBLICKEY) { + wc_Sha256Hash(authData->sf.publicKey.publicKey, + authData->sf.publicKey.publicKeySz, + authHash); + #if defined(WOLFSSH_CERTS) && !defined(WOLFSSH_NO_FPKI) && \ + defined(WOLFSSL_FPKI) + /* Display FPKI info UUID and FASC-N, getter function for FASC-N and + * UUID are dependent on wolfSSL version newer than 5.3.0 so gatting + * on the macro WOLFSSL_FPKI here too */ + if (authData->sf.publicKey.isCert) { + DecodedCert cert; + byte* uuid = NULL; + word32 fascnSz; + word32 uuidSz; + word32 i; + int ret; + + printf("Peer connected with FPKI certificate\n"); + wc_InitDecodedCert(&cert, authData->sf.publicKey.publicKey, + authData->sf.publicKey.publicKeySz, NULL); + ret = wc_ParseCert(&cert, CERT_TYPE, 0, NULL); + + /* some profiles supported due not require FASC-N */ + if (ret == 0 && + wc_GetFASCNFromCert(&cert, NULL, &fascnSz) == LENGTH_ONLY_E) { + byte* fascn; + + fascn = (byte*)WMALLOC(fascnSz, NULL, 0); + if (fascn != NULL && + wc_GetFASCNFromCert(&cert, fascn, &fascnSz) == 0) { + printf("HEX of FASC-N :"); + for (i = 0; i < fascnSz; i++) + printf("%02X", fascn[i]); + printf("\n"); + } + if (fascn != NULL) + WFREE(fascn, NULL, 0); + } + + /* all profiles supported must have a UUID */ + if (ret == 0) { + ret = wc_GetUUIDFromCert(&cert, NULL, &uuidSz); + if (ret == LENGTH_ONLY_E) { /* expected error value */ + ret = 0; + } + + if (ret == 0 ) { + uuid = (byte*)WMALLOC(uuidSz, NULL, 0); + if (uuid == NULL) { + ret = WS_MEMORY_E; + } + } + + if (ret == 0) { + ret = wc_GetUUIDFromCert(&cert, uuid, &uuidSz); + printf("UUID string : "); + for (i = 0; i < uuidSz; i++) + printf("%c", uuid[i]); + printf("\n"); + } + + if (uuid != NULL) + WFREE(uuid, NULL, 0); + } + + /* failed to at least get UUID string */ + if (ret != 0) { + return WOLFSSH_USERAUTH_INVALID_PUBLICKEY; + } + } + #endif /* WOLFSSH_CERTS && !WOLFSSH_NO_FPKI */ + } + + list = (PwMapList*)ctx; + map = list->head; + + while (map != NULL) { + if (authData->usernameSz == map->usernameSz && + WMEMCMP(authData->username, map->username, map->usernameSz) == 0 && + authData->type == map->type) { + + if (authData->type == WOLFSSH_USERAUTH_PUBLICKEY) { + if (WMEMCMP(map->p, authHash, WC_SHA256_DIGEST_SIZE) == 0) { + return WOLFSSH_USERAUTH_SUCCESS; + } + else { + return WOLFSSH_USERAUTH_INVALID_PUBLICKEY; + } + } + else if (authData->type == WOLFSSH_USERAUTH_PASSWORD) { + if (WMEMCMP(map->p, authHash, WC_SHA256_DIGEST_SIZE) == 0) { + return WOLFSSH_USERAUTH_SUCCESS; + } + else { + passwdRetry--; + return (passwdRetry > 0) ? + WOLFSSH_USERAUTH_INVALID_PASSWORD : + WOLFSSH_USERAUTH_REJECTED; + } + } + #ifdef WOLFSSH_ALLOW_USERAUTH_NONE + else if (authData->type == WOLFSSH_USERAUTH_NONE) { + return WOLFSSH_USERAUTH_SUCCESS; + } + #endif /* WOLFSSH_ALLOW_USERAUTH_NONE */ + else { + return WOLFSSH_USERAUTH_INVALID_AUTHTYPE; + } + } + map = map->next; + } + + return WOLFSSH_USERAUTH_INVALID_USER; +} + + +#ifdef WOLFSSH_SFTP +/* + * Sets the WOLFSSH object's default SFTP path to the value provided by + * defaultSftpPath, or uses the current working directory from where the + * echoserver is run. The new default path is cleaned up with the real + * path function. + * + * @param ssh WOLFSSH object to update + * @param defaultSftpPath command line provided default SFTP path + * @return 0 for success or error code + */ +static int SetDefaultSftpPath(WOLFSSH* ssh, const char* defaultSftpPath) +{ + char path[WOLFSSH_MAX_FILENAME]; + char realPath[WOLFSSH_MAX_FILENAME]; + int ret = 0; + + if (defaultSftpPath == NULL) { + #ifndef NO_FILESYSTEM + #ifdef USE_WINDOWS_API + if (GetCurrentDirectoryA(sizeof(path)-1, path) == 0) { + ret = WS_INVALID_PATH_E; + } + #else + if (getcwd(path, sizeof(path)-1) == NULL) { + ret = WS_INVALID_PATH_E; + } + #endif + #elif defined(WOLFSSH_ZEPHYR) + WSTRNCPY(path, CONFIG_WOLFSSH_SFTP_DEFAULT_DIR, WOLFSSH_MAX_FILENAME); + #else + ret = WS_INVALID_PATH_E; + #endif + } + else { + if (WSTRLEN(defaultSftpPath) >= sizeof(path)) { + ret = WS_INVALID_PATH_E; + } + else { + WSTRNCPY(path, defaultSftpPath, sizeof(path)); + } + } + + if (ret == 0) { + path[sizeof(path) - 1] = 0; + ret = wolfSSH_RealPath(NULL, path, realPath, sizeof(realPath)); + } + + if (ret == WS_SUCCESS) { + ret = wolfSSH_SFTP_SetDefaultPath(ssh, realPath); + } + + return ret; +} +#endif + + +static void ShowUsage(void) +{ + printf("echoserver %s\n", LIBWOLFSSH_VERSION_STRING); + printf(" -? display this help and exit\n"); + printf(" -1 exit after single (one) connection\n"); + printf(" -e expect ECC public key from client\n"); + printf(" -E load ECC private key first\n"); +#ifdef WOLFSSH_SHELL + printf(" -f echo input\n"); +#endif + printf(" -p port to connect on, default %d\n", wolfSshPort); + printf(" -N use non-blocking sockets\n"); +#ifdef WOLFSSH_SFTP + printf(" -d set the home directory for SFTP connections\n"); +#endif + printf(" -j load in a SSH public key to accept from peer\n" + " (user assumed in comment)\n"); + printf(" -I :\n" + " load in a SSH public key to accept from peer\n"); + printf(" -J :\n" + " load in an X.509 PEM cert to accept from peer\n"); + printf(" -K :\n" + " load in an X.509 DER cert to accept from peer\n"); + printf(" -P :\n" + " add password to accept from peer\n"); +#ifdef WOLFSSH_CERTS + printf(" -a load in a root CA certificate file\n"); +#endif +} + + +static INLINE void SignalTcpReady(func_args* serverArgs, word16 port) +{ +#if defined(_POSIX_THREADS) && defined(NO_MAIN_DRIVER) && \ + !defined(__MINGW32__) && !defined(SINGLE_THREADED) + tcp_ready* ready = serverArgs->signal; + if (ready != NULL) { + pthread_mutex_lock(&ready->mutex); + ready->ready = 1; + ready->port = port; + pthread_cond_signal(&ready->cond); + pthread_mutex_unlock(&ready->mutex); + } +#else + (void)serverArgs; + (void)port; +#endif +} + +#define ES_ERROR(...) do { \ + fprintf(stderr, __VA_ARGS__); \ + serverArgs->return_code = EXIT_FAILURE; \ + WOLFSSL_RETURN_FROM_THREAD(0); \ +} while(0) + +THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) +{ + func_args* serverArgs = (func_args*)args; + WOLFSSH_CTX* ctx = NULL; + PwMapList pwMapList; + #ifndef NO_FILESYSTEM + StrList* sshPubKeyList = NULL; + StrList* pemPubKeyList = NULL; + StrList* derPubKeyList = NULL; + #endif + StrList* passwdList = NULL; + WS_SOCKET_T listenFd = WOLFSSH_SOCKET_INVALID; + word32 defaultHighwater = EXAMPLE_HIGHWATER_MARK; + word32 threadCount = 0; + int multipleConnections = 1; + int userEcc = 0; + int peerEcc = 0; + int echo = 0; + int ch; + word16 port = wolfSshPort; + char* readyFile = NULL; + const char* defaultSftpPath = NULL; + char nonBlock = 0; + #ifndef NO_FILESYSTEM + char* userPubKey = NULL; + #endif + #ifdef WOLFSSH_CERTS + char* caCert = NULL; + #endif + + int argc = serverArgs->argc; + char** argv = serverArgs->argv; + serverArgs->return_code = EXIT_SUCCESS; + + if (argc > 0) { + const char* optlist = "?1a:d:efEp:R:Ni:j:I:J:K:P:"; + myoptind = 0; + while ((ch = mygetopt(argc, argv, optlist)) != -1) { + switch (ch) { + case '?' : + ShowUsage(); + serverArgs->return_code = MY_EX_USAGE; + WOLFSSL_RETURN_FROM_THREAD(0); + + case '1': + multipleConnections = 0; + break; + + case 'a': + #ifdef WOLFSSH_CERTS + caCert = myoptarg; + #endif + break; + case 'e' : + userEcc = 1; + break; + + case 'E': + peerEcc = 1; + break; + + case 'f': + #ifdef WOLFSSH_SHELL + echo = 1; + #endif + break; + + case 'p': + if (myoptarg == NULL) { + ES_ERROR("NULL port value"); + } + else { + port = (word16)atoi(myoptarg); + #if !defined(NO_MAIN_DRIVER) || defined(USE_WINDOWS_API) + if (port == 0) { + ES_ERROR("port number cannot be 0"); + } + #endif + } + break; + + case 'R': + readyFile = myoptarg; + break; + + case 'N': + nonBlock = 1; + break; + + case 'd': + defaultSftpPath = myoptarg; + break; + +#ifndef NO_FILESYSTEM + case 'j': + userPubKey = myoptarg; + break; + + case 'I': + sshPubKeyList = StrListAdd(sshPubKeyList, myoptarg); + break; + + case 'J': + pemPubKeyList = StrListAdd(pemPubKeyList, myoptarg); + break; + + case 'K': + derPubKeyList = StrListAdd(derPubKeyList, myoptarg); + break; +#endif + + case 'P': + passwdList = StrListAdd(passwdList, myoptarg); + break; + + default: + ShowUsage(); + serverArgs->return_code = MY_EX_USAGE; + WOLFSSL_RETURN_FROM_THREAD(0); + } + } + } + myoptind = 0; /* reset for test cases */ + wc_InitMutex(&doneLock); + +#ifdef WOLFSSH_TEST_BLOCK + if (!nonBlock) { + ES_ERROR("Use -N when testing forced non blocking"); + } +#endif + +#ifdef WOLFSSH_NO_RSA + /* If wolfCrypt isn't built with RSA, force ECC on. */ + userEcc = 1; + peerEcc = 1; +#endif +#ifdef WOLFSSH_NO_ECC + /* If wolfCrypt isn't built with ECC, force ECC off. */ + userEcc = 0; + peerEcc = 0; +#endif + (void)userEcc; + + if (wolfSSH_Init() != WS_SUCCESS) { + ES_ERROR("Couldn't initialize wolfSSH.\n"); + } + + ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL); + if (ctx == NULL) { + ES_ERROR("Couldn't allocate SSH CTX data.\n"); + } + + WMEMSET(&pwMapList, 0, sizeof(pwMapList)); + if (serverArgs->user_auth == NULL) + wolfSSH_SetUserAuth(ctx, wsUserAuth); + else + wolfSSH_SetUserAuth(ctx, ((func_args*)args)->user_auth); + wolfSSH_SetUserAuthResult(ctx, wsUserAuthResult); + wolfSSH_CTX_SetBanner(ctx, echoserverBanner); +#ifdef WOLFSSH_AGENT + wolfSSH_CTX_set_agent_cb(ctx, wolfSSH_AGENT_DefaultActions, NULL); +#endif +#ifdef WOLFSSH_FWD + wolfSSH_CTX_SetFwdCb(ctx, wolfSSH_FwdDefaultActions, NULL); +#endif + +#ifndef NO_FILESYSTEM + if (sshPubKeyList) { + LoadPubKeyList(sshPubKeyList, WOLFSSH_FORMAT_SSH, &pwMapList); + StrListFree(sshPubKeyList); + sshPubKeyList = NULL; + } + if (pemPubKeyList) { + LoadPubKeyList(pemPubKeyList, WOLFSSH_FORMAT_PEM, &pwMapList); + StrListFree(pemPubKeyList); + pemPubKeyList = NULL; + } + if (derPubKeyList) { + LoadPubKeyList(derPubKeyList, WOLFSSH_FORMAT_ASN1, &pwMapList); + StrListFree(derPubKeyList); + derPubKeyList = NULL; + } +#endif + if (passwdList) { + LoadPasswdList(passwdList, &pwMapList); + StrListFree(passwdList); + passwdList = NULL; + } + + { + const char* bufName = NULL; + #ifndef WOLFSSH_SMALL_STACK + byte buf[EXAMPLE_KEYLOAD_BUFFER_SZ]; + #endif + byte* keyLoadBuf; + word32 bufSz; + + #ifdef WOLFSSH_SMALL_STACK + keyLoadBuf = (byte*)WMALLOC(EXAMPLE_KEYLOAD_BUFFER_SZ, + NULL, 0); + if (keyLoadBuf == NULL) { + ES_ERROR("Error allocating keyLoadBuf"); + } + #else + keyLoadBuf = buf; + #endif + bufSz = EXAMPLE_KEYLOAD_BUFFER_SZ; + + bufSz = load_key(peerEcc, keyLoadBuf, bufSz); + if (bufSz == 0) { + ES_ERROR("Couldn't load first key file.\n"); + } + if (wolfSSH_CTX_UsePrivateKey_buffer(ctx, keyLoadBuf, bufSz, + WOLFSSH_FORMAT_ASN1) < 0) { + ES_ERROR("Couldn't use first key buffer.\n"); + } + + #if !defined(WOLFSSH_NO_RSA) && !defined(WOLFSSH_NO_ECC) + peerEcc = !peerEcc; + bufSz = EXAMPLE_KEYLOAD_BUFFER_SZ; + + bufSz = load_key(peerEcc, keyLoadBuf, bufSz); + if (bufSz == 0) { + ES_ERROR("Couldn't load second key file.\n"); + } + if (wolfSSH_CTX_UsePrivateKey_buffer(ctx, keyLoadBuf, bufSz, + WOLFSSH_FORMAT_ASN1) < 0) { + ES_ERROR("Couldn't use second key buffer.\n"); + } + #endif + + #ifndef NO_FILESYSTEM + if (userPubKey) { + byte* userBuf = NULL; + word32 userBufSz = 0; + + /* get the files size */ + load_file(userPubKey, NULL, &userBufSz); + + /* create temp buffer and load in file */ + if (userBufSz == 0) { + ES_ERROR("Couldn't find size of file %s.\n", userPubKey); + } + + userBuf = (byte*)WMALLOC(userBufSz, NULL, 0); + if (userBuf == NULL) { + ES_ERROR("WMALLOC failed\n"); + } + load_file(userPubKey, userBuf, &userBufSz); + LoadPublicKeyBuffer(userBuf, userBufSz, &pwMapList); + WFREE(userBuf, NULL, 0); + } + #endif + + #ifdef WOLFSSH_CERTS + if (caCert) { + byte* certBuf = NULL; + word32 certBufSz = 0; + int ret = 0; + + load_file(caCert, NULL, &certBufSz); + + if (certBufSz == 0) { + ES_ERROR("Couldn't find size of file %s.\n", caCert); + } + + certBuf = (byte*)WMALLOC(certBufSz, NULL, 0); + if (certBuf == NULL) { + ES_ERROR("WMALLOC failed\n"); + } + load_file(caCert, certBuf, &certBufSz); + ret = wolfSSH_CTX_AddRootCert_buffer(ctx, certBuf, certBufSz, + WOLFSSH_FORMAT_PEM); + if (ret != 0) { + ES_ERROR("Couldn't add root cert\n"); + } + WFREE(certBuf, NULL, 0); + } + #endif + + bufSz = (word32)WSTRLEN(samplePasswordBuffer); + WMEMCPY(keyLoadBuf, samplePasswordBuffer, bufSz); + keyLoadBuf[bufSz] = 0; + LoadPasswordBuffer(keyLoadBuf, bufSz, &pwMapList); + + if (userEcc) { + #ifndef WOLFSSH_NO_ECC + bufName = samplePublicKeyEccBuffer; + #endif + } + else { + #ifndef WOLFSSH_NO_RSA + bufName = samplePublicKeyRsaBuffer; + #endif + } + if (bufName != NULL) { + bufSz = (word32)WSTRLEN(bufName); + WMEMCPY(keyLoadBuf, bufName, bufSz); + keyLoadBuf[bufSz] = 0; + LoadPublicKeyBuffer(keyLoadBuf, bufSz, &pwMapList); + } + + #ifdef WOLFSSH_ALLOW_USERAUTH_NONE + bufSz = (word32)WSTRLEN(sampleNoneBuffer); + WMEMCPY(keyLoadBuf, sampleNoneBuffer, bufSz); + keyLoadBuf[bufSz] = 0; + LoadNoneBuffer(keyLoadBuf, bufSz, &pwMapList); + #endif /* WOLFSSH_ALLOW_USERAUTH_NONE */ + + #ifdef WOLFSSH_SMALL_STACK + WFREE(keyLoadBuf, NULL, 0); + #endif + } +#ifdef WOLFSSL_NUCLEUS + { + int i; + int ret = !NU_SUCCESS; + + /* wait for network and storage device */ + if (NETBOOT_Wait_For_Network_Up(NU_SUSPEND) != NU_SUCCESS) { + ES_ERROR("Couldn't find network.\r\n"); + } + + for(i = 0; i < 15 && ret != NU_SUCCESS; i++) + { + fprintf(stdout, "Checking for storage device\r\n"); + + ret = NU_Storage_Device_Wait(NU_NULL, NU_PLUS_TICKS_PER_SEC); + } + + if (ret != NU_SUCCESS) { + ES_ERROR("Couldn't find storage device.\r\n"); + } + } +#endif + + /* if creating a ready file with port then override port to be 0 */ + if (readyFile != NULL) { + #ifdef NO_FILESYSTEM + ES_ERROR("cannot create readyFile with no file system.\r\n"); + #else + port = 0; + #endif + } + tcp_listen(&listenFd, &port, 1); + /* write out port number listing to, to user set ready file */ + if (readyFile != NULL) { + #ifndef NO_FILESYSTEM + WFILE* f = NULL; + int ret; + ret = WFOPEN(NULL, &f, readyFile, "w"); + if (f != NULL && ret == 0) { + char portStr[10]; + int l = WSNPRINTF(portStr, sizeof(portStr), "%d\n", (int)port); + WFWRITE(NULL, portStr, MIN((size_t)l, sizeof(portStr)), 1, f); + WFCLOSE(NULL, f); + } + #endif + } + + do { + WS_SOCKET_T clientFd = WOLFSSH_SOCKET_INVALID; + #ifdef WOLFSSL_NUCLEUS + struct addr_struct clientAddr; + #else + SOCKADDR_IN_T clientAddr; + socklen_t clientAddrSz = sizeof(clientAddr); + #endif + WOLFSSH* ssh; + thread_ctx_t* threadCtx; + + threadCtx = (thread_ctx_t*)WMALLOC(sizeof(thread_ctx_t), + NULL, 0); + if (threadCtx == NULL) { + ES_ERROR("Couldn't allocate thread context data.\n"); + } + WMEMSET(threadCtx, 0, sizeof *threadCtx); + + ssh = wolfSSH_new(ctx); + if (ssh == NULL) { + WFREE(threadCtx, NULL, 0); + ES_ERROR("Couldn't allocate SSH data.\n"); + } + wolfSSH_SetUserAuthCtx(ssh, &pwMapList); + /* Use the session object for its own highwater callback ctx */ + if (defaultHighwater > 0) { + wolfSSH_SetHighwaterCtx(ssh, (void*)ssh); + wolfSSH_SetHighwater(ssh, defaultHighwater); + } + + #ifdef WOLFSSH_SFTP + if (SetDefaultSftpPath(ssh, defaultSftpPath) != 0) { + ES_ERROR("Couldn't store default sftp path.\n"); + } + #endif + + #ifdef WOLFSSL_NUCLEUS + { + byte ipaddr[MAX_ADDRESS_SIZE]; + char buf[16]; + short addrLength; + struct sockaddr_struct sock; + + addrLength = sizeof(struct sockaddr_struct); + + /* Get the local IP address for the socket. + * 0.0.0.0 if ip adder any */ + if (NU_Get_Sock_Name(listenFd, &sock, &addrLength) != NU_SUCCESS) { + ES_ERROR("Couldn't find network.\r\n"); + } + + WMEMCPY(ipaddr, &sock.ip_num, MAX_ADDRESS_SIZE); + NU_Inet_NTOP(NU_FAMILY_IP, &ipaddr[0], buf, 16); + fprintf(stdout, "Listening on %s:%d\r\n", buf, port); + } + #endif + + SignalTcpReady(serverArgs, port); + + #ifdef WOLFSSL_NUCLEUS + clientFd = NU_Accept(listenFd, &clientAddr, 0); + #else + clientFd = accept(listenFd, (struct sockaddr*)&clientAddr, + &clientAddrSz); + #endif + if (clientFd == -1) { + ES_ERROR("tcp accept failed"); + } + + if (nonBlock) + tcp_set_nonblocking(&clientFd); + + wolfSSH_set_fd(ssh, (int)clientFd); + +#if defined(WOLFSSL_PTHREADS) && defined(WOLFSSL_TEST_GLOBAL_REQ) + threadCtx->ctx = ctx; +#endif + threadCtx->ssh = ssh; + threadCtx->fd = clientFd; + threadCtx->id = threadCount++; + threadCtx->nonBlock = nonBlock; + threadCtx->echo = echo; +#ifdef WOLFSSH_AGENT + wolfSSH_set_agent_cb_ctx(ssh, &threadCtx->agentCbCtx); +#endif +#ifdef WOLFSSH_FWD + threadCtx->fwdCbCtx.state = FWD_STATE_INIT; + threadCtx->fwdCbCtx.listenFd = -1; + threadCtx->fwdCbCtx.appFd = -1; + wolfSSH_SetFwdCbCtx(ssh, &threadCtx->fwdCbCtx); +#endif + server_worker(threadCtx); + + } while (multipleConnections && !quit); + + if (listenFd != WOLFSSH_SOCKET_INVALID) { + WCLOSESOCKET(listenFd); + } + wc_FreeMutex(&doneLock); + PwMapListDelete(&pwMapList); + wolfSSH_CTX_free(ctx); + if (wolfSSH_Cleanup() != WS_SUCCESS) { + ES_ERROR("Couldn't clean up wolfSSH.\n"); + } +#if !defined(WOLFSSH_NO_ECC) && defined(FP_ECC) && defined(HAVE_THREAD_LS) + wc_ecc_fp_free(); /* free per thread cache */ +#endif + + (void)defaultSftpPath; + WOLFSSL_RETURN_FROM_THREAD(0); +} + +#endif /* NO_WOLFSSH_SERVER */ + + +void wolfSSL_Debugging_ON(void); + +int wolfSSH_Echoserver(int argc, char** argv) +{ + func_args args; + + WMEMSET(&args, 0, sizeof(args)); + args.argc = argc; + args.argv = argv; + + WSTARTTCP(); + + #ifdef DEBUG_WOLFSSH + wolfSSL_Debugging_ON(); + wolfSSH_Debugging_ON(); + #endif + +#if !defined(WOLFSSL_NUCLEUS) && !defined(INTEGRITY) && !defined(__INTEGRITY) + ChangeToWolfSshRoot(); +#endif +#ifndef NO_WOLFSSH_SERVER + echoserver_test(&args); +#else + printf("wolfSSH compiled without server support\n"); +#endif + + wolfSSH_Cleanup(); + + return args.return_code; +} + + +#ifndef NO_MAIN_DRIVER + + int main(int argc, char** argv) + { + return wolfSSH_Echoserver(argc, argv); + } + + int myoptind = 0; + char* myoptarg = NULL; + +#endif /* NO_MAIN_DRIVER */ + +#ifdef WOLFSSL_NUCLEUS + + #define WS_TASK_SIZE 200000 + #define WS_TASK_PRIORITY 31 + static NU_TASK serverTask; + + /* expecting void return on main function */ + static VOID main_nucleus(UNSIGNED argc, VOID* argv) + { + main((int)argc, (char**)argv); + } + + + /* using port 8080 because it was an open port on QEMU */ + VOID Application_Initialize (NU_MEMORY_POOL* memPool, + NU_MEMORY_POOL* uncachedPool) + { + void* pt; + int ret; + + UNUSED_PARAMETER(uncachedPool); + + ret = NU_Allocate_Memory(memPool, &pt, WS_TASK_SIZE, NU_NO_SUSPEND); + if (ret == NU_SUCCESS) { + ret = NU_Create_Task(&serverTask, "wolfSSH Server", main_nucleus, 0, + NU_NULL, pt, WS_TASK_SIZE, WS_TASK_PRIORITY, 0, + NU_PREEMPT, NU_START); + if (ret != NU_SUCCESS) { + NU_Deallocate_Memory(pt); + } + } + } +#endif /* WOLFSSL_NUCLEUS */ 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 new file mode 100644 index 000000000..ac7e17cf2 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/echoserver.h @@ -0,0 +1,35 @@ +/* echoserver.h + * + * Copyright (C) 2014-2023 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 . + */ + + +#ifndef _WOLFSSH_EXAMPLES_ECHOSERVER_H_ +#define _WOLFSSH_EXAMPLES_ECHOSERVER_H_ + +#include + +#ifndef WOLFSSH_THREAD + #define WOLFSSH_THREAD +#endif + +THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args); +int wolfSSH_Echoserver(int argc, char** argv); + + +#endif /* _WOLFSSH_EXAMPLES_ECHOSERVER_H_ */ 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 new file mode 100644 index 000000000..7e07ec1df --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/main.h @@ -0,0 +1,38 @@ +/* template main.h + * + * Copyright (C) 2006-2023 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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 + * (at your option) any later version. + * + * wolfSSL 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 + */ +#ifndef _MAIN_H_ +#define _MAIN_H_ + +/* Espressif libraries */ +#include "sdkconfig.h" +#include +#include + +/* wolfSSL */ +#include "user_settings.h" /* always include wolfSSL user_settings.h first */ +#include +#include + +/* wolfSSH */ +#include +#include + +#endif 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 new file mode 100644 index 000000000..a47f94001 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/time_helper.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2006-2023 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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 + * (at your option) any later version. + * + * wolfSSL 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 + */ + +/* common Espressif time_helper v5.6.3.001 */ + +#ifndef _TIME_HELPER_H +#define _TIME_HELPER_H + +/* ESP-IDF uses a 64-bit signed integer to represent time_t starting from release v5.0 + * See: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/system_time.html#year-2036-and-2038-overflow-issues + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* a function to show the current data and time */ +int esp_show_current_datetime(); + +/* worst case, if GitHub time not available, used fixed time */ +int set_fixed_default_time(void); + +/* set time from string (e.g. GitHub commit time) */ +int set_time_from_string(char* time_buffer); + +/* set time from NTP servers, + * also initially calls set_fixed_default_time or set_time_from_string */ +int set_time(void); + +/* wait NTP_RETRY_COUNT seconds before giving up on NTP time */ +int set_time_wait_for_ntp(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* #ifndef _TIME_HELPER_H */ 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 new file mode 100644 index 000000000..a0014d4c3 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/include/wifi_connect.h @@ -0,0 +1,96 @@ +/* wifi_connect.h + * + * Copyright (C) 2006-2023 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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 + * (at your option) any later version. + * + * wolfSSL 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 + */ +#ifndef _WIFI_CONNECT_H_ +#define _WIFI_CONNECT_H_ + +#include +#include + +/* ESP lwip */ +#define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY + +#define TLS_SMP_SERVER_TASK_NAME "tls_sever_example" +#define TLS_SMP_SERVER_TASK_WORDS 22240 +#define TLS_SMP_SERVER_TASK_PRIORITY 8 + +#define TLS_SMP_WIFI_SSID CONFIG_WIFI_SSID +#define TLS_SMP_WIFI_PASS CONFIG_WIFI_PASSWORD + +#define USE_WIFI_EXAMPLE +#ifdef USE_WIFI_EXAMPLE + #include /* see project CMakeLists.txt */ +#endif + +/** + ****************************************************************************** + ****************************************************************************** + ** USER APPLICATION SETTINGS BEGIN + ****************************************************************************** + ****************************************************************************** + **/ + +/* when using a private config with plain text passwords, + * file my_private_config.h should be excluded from git updates */ +/* #define USE_MY_PRIVATE_CONFIG */ + +#ifdef USE_MY_PRIVATE_CONFIG + #if defined(WOLFSSL_CMAKE_SYSTEM_NAME_WINDOWS) + #include "/workspace/my_private_config.h" + #elif defined(WOLFSSL_CMAKE_SYSTEM_NAME_WSL) + #include "/mnt/c/workspace/my_private_config.h" + #elif defined(WOLFSSL_CMAKE_SYSTEM_NAME_LINUX) + #include "~/workspace/my_private_config.h" + #elif defined(WOLFSSL_CMAKE_SYSTEM_NAME_APPLE) + #include "~/Documents/my_private_config.h" + #else + #warning "did not detect environment. using ~/my_private_config.h" + #include "~/my_private_config.h" + #endif +#else + + /* + ** The examples use WiFi configuration that you can set via project + ** configuration menu + ** + ** If you'd rather not, just change the below entries to strings with + ** the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" + */ + #ifdef CONFIG_ESP_WIFI_SSID + #define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID + #else + #define EXAMPLE_ESP_WIFI_SSID "MYSSID_WIFI_CONNECT" + #endif + + #ifdef CONFIG_ESP_WIFI_PASSWORD + #define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD + #else + #define EXAMPLE_ESP_WIFI_PASS "MYPASSWORD_WIFI_CONNECT" + #endif +#endif + +/* ESP lwip */ +#define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY + +int wifi_init_sta(void); + +int wifi_show_ip(void); + +#endif /* _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 new file mode 100644 index 000000000..7781f4281 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/main.c @@ -0,0 +1,182 @@ +/* main.c + * + * Copyright (C) 2006-2023 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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 + * (at your option) any later version. + * + * wolfSSL 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 + */ +#include "sdkconfig.h" +#include "main.h" +#include "echoserver.h" + +/* ESP specific */ +#include +#include +#include + +/* wolfSSL */ +#include /* includes wolfSSL user-settings.h */ +#include +#ifndef WOLFSSL_ESPIDF + #warning "Problem with wolfSSL user_settings." + #warning "Check components/wolfssl/include" +#endif + +/* this project */ +#include "wifi_connect.h" +#include "time_helper.h" + +static const char* const TAG = "My Project"; + + +void app_main(void) +{ + void* args = {0}; + int ret = ESP_OK; + + ESP_LOGI(TAG, "------------ wolfSSL wolfSSH template Example ----------"); + ESP_LOGI(TAG, "--------------------------------------------------------"); + ESP_LOGI(TAG, "--------------------------------------------------------"); + ESP_LOGI(TAG, "---------------------- BEGIN MAIN ----------------------"); + ESP_LOGI(TAG, "--------------------------------------------------------"); + ESP_LOGI(TAG, "--------------------------------------------------------"); + + ESP_LOGI(TAG, "Hello wolfSSL!"); + +#ifdef DEBUG_WOLFSSH + wolfSSH_Debugging_ON(); +#else + ESP_LOGI(TAG, "DEBUG_WOLFSSH is not defined, " + "so nothing will happen for the next statement"); +#endif + +#ifdef HAVE_VERSION_EXTENDED_INFO + // esp_ShowExtendedSystemInfo(); +#endif + + /* Set time for cert validation. + * Some lwIP APIs, including SNTP functions, are not thread safe. */ + ret = set_time(); /* need to setup NTP before WiFi */ + ESP_LOGI(TAG, "set_time done."); + + /* Optionally erase flash */ + /* ESP_ERROR_CHECK(nvs_flash_erase()); */ +#ifdef INCLUDE_uxTaskGetStackHighWaterMark + ESP_LOGI(TAG, "Stack HWM: %d", uxTaskGetStackHighWaterMark(NULL)); + + ESP_LOGI(TAG, "Stack used: %d", CONFIG_ESP_MAIN_TASK_STACK_SIZE + - (uxTaskGetStackHighWaterMark(NULL))); +#endif + +/* the simplest check of the wolfSSL library presence: */ +#ifdef LIBWOLFSSL_VERSION_STRING + ESP_LOGI(TAG, ""); + ESP_LOGI(TAG, "Found wolfSSL Version %s\n", LIBWOLFSSL_VERSION_STRING); +#else + ESP_LOGW(TAG, "Warning: Could not find wolfSSL Version"); +#endif + +#ifdef FOUND_PROTOCOL_EXAMPLES_DIR + ESP_LOGI(TAG, "FOUND_PROTOCOL_EXAMPLES_DIR active, using example code."); + ESP_ERROR_CHECK(nvs_flash_init()); + + #if defined(CONFIG_IDF_TARGET_ESP32H2) + ESP_LOGE(TAG, "There's no WiFi on ESP32-H2."); + #else + #ifdef CONFIG_EXAMPLE_WIFI_SSID + if (XSTRCMP(CONFIG_EXAMPLE_WIFI_SSID, "myssid") == 0) { + ESP_LOGW(TAG, "WARNING: CONFIG_EXAMPLE_WIFI_SSID is myssid."); + ESP_LOGW(TAG, " Do you have a WiFi AP called myssid, or "); + ESP_LOGW(TAG, " did you forget the ESP-IDF configuration?"); + } + #else + #define CONFIG_EXAMPLE_WIFI_SSID "myssid" + ESP_LOGW(TAG, "WARNING: CONFIG_EXAMPLE_WIFI_SSID not defined."); + #endif + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + ESP_ERROR_CHECK(example_connect()); + #endif +#else + ESP_ERROR_CHECK(nvs_flash_init()); + + /* Initialize NVS */ + ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || + ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + #if defined(CONFIG_IDF_TARGET_ESP32H2) + ESP_LOGE(TAG, "There's no WiFi on ESP32-H2. "); + #else + /* Initialize WiFi */ + ESP_LOGI(TAG, "ESP_WIFI_MODE_STA"); + ret = wifi_init_sta(); + while (ret != 0) { + ESP_LOGI(TAG, "Waiting..."); + vTaskDelay(60000 / portTICK_PERIOD_MS); + ESP_LOGI(TAG, "Trying WiFi again..."); + ret = wifi_init_sta(); + } + #endif +#endif + + /* Once we are connected to the network, start & wait for NTP time */ + // ret = set_time_wait_for_ntp(); + + if (ret < -1) { + /* a value of -1 means there was no NTP server, so no need to wait */ + ESP_LOGI(TAG, "Waiting 10 more seconds for NTP to complete." ); + vTaskDelay(10000 / portTICK_PERIOD_MS); /* brute-force solution */ + esp_show_current_datetime(); + } + + /* HWM is maximum amount of stack space that has been unused, in bytes + * not words (unlike vanilla freeRTOS). */ + ESP_LOGI(TAG, "Initial Stack Used (before wolfSSL Server): %d bytes", + CONFIG_ESP_MAIN_TASK_STACK_SIZE + - (uxTaskGetStackHighWaterMark(NULL)) + ); + ESP_LOGI(TAG, "Starting wolfSSH server_test..."); + + /* 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 */ + echoserver_test(&args); + + ESP_LOGI(TAG, "\n\nDone!" + "If running from idf.py monitor, press twice: Ctrl+]"); + + ESP_LOGV(TAG, "\n\nLoop...\n\n"); + ESP_LOGI(TAG, "Stack used: %d", CONFIG_ESP_MAIN_TASK_STACK_SIZE + - uxTaskGetStackHighWaterMark(NULL)); + + while (1) { +#if defined(SINGLE_THREADED) + while (1); +#else + vTaskDelay(60000); +#endif + } + + ESP_LOGI(TAG, "\n\nDone!\n\n" + "If running from idf.py monitor, press twice: Ctrl+]\n\n" + "WOLFSSL_COMPLETE\n" /* exit keyword for wolfssl_monitor.py */ + ); +} /* app_main */ 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 new file mode 100644 index 000000000..0abf70c5a --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/time_helper.c @@ -0,0 +1,360 @@ +/* time_helper.c + * + * Copyright (C) 2006-2023 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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 + * (at your option) any later version. + * + * wolfSSL 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 + */ + +/* common Espressif time_helper v5.6.3.002 */ +#include "sdkconfig.h" +#include "time_helper.h" + +#include +#include + +#if defined(ESP_IDF_VERSION_MAJOR) && defined(ESP_IDF_VERSION_MINOR) + #if (ESP_IDF_VERSION_MAJOR == 5) && (ESP_IDF_VERSION_MINOR >= 1) + #define HAS_ESP_NETIF_SNTP 1 + #include + #include + // #include + #else + #include + #include + #endif +#else + /* TODO Consider pre IDF v5? */ +#endif + +/* ESP-IDF uses a 64-bit signed integer to represent time_t starting from release v5.0 + * See: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/system_time.html#year-2036-and-2038-overflow-issues + */ +const static char* TAG = "time_helper"; + +/* see https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html */ +#ifndef TIME_ZONE +/* + * PST represents Pacific Standard Time. + * +8 specifies the offset from UTC (Coordinated Universal Time), indicating + * that Pacific Time is UTC-8 during standard time. + * PDT represents Pacific Daylight Time. + * M3.2.0 indicates that Daylight Saving Time (DST) starts on the + * second (2) Sunday (0) of March (3). + * M11.1.0 indicates that DST ends on the first (1) Sunday (0) of November (11) + */ + #define TIME_ZONE "PST+8PDT,M3.2.0,M11.1.0" +#endif /* not defined: TIME_ZONE, so we are setting our own */ + +#define NTP_RETRY_COUNT 10 + +/* NELEMS(x) number of elements + * To determine the number of elements in the array, we can divide the total + * size of the array by the size of the array element. + * See https://stackoverflow.com/questions/37538/how-do-i-determine-the-size-of-my-array-in-c + **/ +#define NELEMS(x) ( (int)(sizeof(x) / sizeof((x)[0])) ) + +/* See also CONFIG_LWIP_SNTP_MAX_SERVERS in sdkconfig */ +#define NTP_SERVER_LIST ( (char*[]) { \ + "pool.ntp.org", \ + "time.nist.gov", \ + "utcnist.colorado.edu" \ + } \ + ) +/* #define NTP_SERVER_COUNT using NELEMS: + * + * (int)(sizeof(NTP_SERVER_LIST) / sizeof(NTP_SERVER_LIST[0])) + */ +#define NTP_SERVER_COUNT NELEMS(NTP_SERVER_LIST) + +#ifndef CONFIG_LWIP_SNTP_MAX_SERVERS + /* We should find max value in sdkconfig, if not set it to our count:*/ + #define CONFIG_LWIP_SNTP_MAX_SERVERS NTP_SERVER_COUNT +#endif + +char* ntpServerList[NTP_SERVER_COUNT] = NTP_SERVER_LIST; + +/* our NTP server list is global info */ +extern char* ntpServerList[NTP_SERVER_COUNT]; + +/* Show the current date and time */ +int esp_show_current_datetime() +{ + time_t now; + char strftime_buf[64]; + struct tm timeinfo; + + time(&now); + setenv("TZ", TIME_ZONE, 1); + tzset(); + + localtime_r(&now, &timeinfo); + strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo); + ESP_LOGI(TAG, "The current date/time is: %s", strftime_buf); + return 0; +} + +/* the worst-case scenario is a hard-coded date/time */ +int set_fixed_default_time(void) +{ + /* ideally, we'd like to set time from network, + * but let's set a default time, just in case */ + struct tm timeinfo = { + .tm_year = 2023 - 1900, + .tm_mon = 10, + .tm_mday = 02, + .tm_hour = 13, + .tm_min = 01, + .tm_sec = 05 + }; + struct timeval now; + time_t interim_time; + int ret = -1; + + /* set interim static time */ + interim_time = mktime(&timeinfo); + + ESP_LOGI(TAG, "Adjusting time from fixed value"); + now = (struct timeval){ .tv_sec = interim_time }; + ret = settimeofday(&now, NULL); + + return ret; +} + +/* set_time_from_string(s) + * + * returns 0 = success if able to set the time from the provided string + * error for any other value, typically -1 */ +int set_time_from_string(char* time_buffer) +{ + /* expecting github default formatting: 'Thu Aug 31 12:41:45 2023 -0700' */ + const char *format = "%3s %3s %d %d:%d:%d %d %s"; + struct tm this_timeinfo; + struct timeval now; + time_t interim_time; + char offset[10]; /* expecting trailing offset and single quote, not used */ + char day_str[4]; + char month_str[4]; + int day, year, hour, minute, second; + int quote_offset = 0; + int ret = 0; + + time(&interim_time); + /* expecting the string to be encapsulated in single quotes */ + if (*time_buffer == 0x27) { + quote_offset = 1; + } + + ret = sscanf(time_buffer + quote_offset, + format, + day_str, month_str, + &day, &hour, &minute, &second, &year, + offset); + + + if (ret == 8) { + /* we found a match for all componets */ + + const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + + + /* Ensure day_str and month_str are not too long */ + ret = ESP_FAIL; /* assume failure until proven otherwise */ + this_timeinfo.tm_mon = 0; + if (strlen(day_str) <= 3 && strlen(month_str) <= 3) { + for (int i = 0; i < 12; i++) { + if (strcmp(month_str, months[i]) == 0) { + this_timeinfo.tm_mon = i; + ret = ESP_OK; + break; + } + } + if (ret == ESP_OK) { + this_timeinfo.tm_mday = day; + this_timeinfo.tm_hour = hour; + this_timeinfo.tm_min = minute; + this_timeinfo.tm_sec = second; + this_timeinfo.tm_year = year - 1900; /* years since 1900 */ + + interim_time = mktime(&this_timeinfo); + now = (struct timeval){ .tv_sec = interim_time }; + ret = settimeofday(&now, NULL); + } + else { + ESP_LOGE(TAG, "Bad month value: %s", month_str); + } + + if (ret == ESP_OK) { + ESP_LOGI(TAG, "Time updated to %s", time_buffer); + } + else { + ESP_LOGE(TAG, "Failed to set system time with strig: %s", + time_buffer); + } + } + else { + ESP_LOGE(TAG, "Invalid day (%s) or month (%s) string length.", + day_str, month_str); + ret = ESP_FAIL; + } + } + else { + ESP_LOGE(TAG, "Failed to convert \"%s\" to a tm date.", time_buffer); + ESP_LOGI(TAG, "Trying fixed date that was hard-coded."); + set_fixed_default_time(); + ret = ESP_FAIL; + } + return ret; +} + +/* set time; returns 0 if succecssfully configured with NTP */ +int set_time(void) +{ +#ifndef NTP_SERVER_COUNT + ESP_LOGW(TAG, "Warning: no sntp server names defined. " + "Setting to empty list"); + #define NTP_SERVER_COUNT 0 + #warning "NTP not properly configured" +#endif /* not defined: NTP_SERVER_COUNT */ + +#ifdef HAS_ESP_NETIF_SNTP + #if CONFIG_LWIP_SNTP_MAX_SERVERS > 1 + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG_MULTIPLE( + NTP_SERVER_COUNT, + ESP_SNTP_SERVER_LIST(ntpServerList[0]) + ); + #else + esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(ntpServerList[0]); + #endif /* CONFIG_LWIP_SNTP_MAX_SERVERS > 1 */ +#endif /* HAS_ESP_NETIF_SNTP */ + + int ret = 0; + int i = 0; /* counter for time servers */ + + ESP_LOGI(TAG, "Setting the time. Startup time:"); + esp_show_current_datetime(); + +#ifdef LIBWOLFSSL_VERSION_GIT_HASH_DATE + /* initialy set a default approximate time from recent git commit */ + ESP_LOGI(TAG, "Found git hash date, attempting to set system date."); + set_time_from_string(LIBWOLFSSL_VERSION_GIT_HASH_DATE); + esp_show_current_datetime(); + + ret = -4; +#else + /* otherwise set a fixed time that was hard coded */ + set_fixed_default_time(); + ret = -3; +#endif + +#ifdef CONFIG_SNTP_TIME_SYNC_METHOD_SMOOTH + config.smooth_sync = true; +#endif + + if (NTP_SERVER_COUNT) { + /* next, let's setup NTP time servers + * + * see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/system_time.html#sntp-time-synchronization + * + * WARNING: do not set operating mode while SNTP client is running! + */ + /* TODO Consider esp_sntp_setoperatingmode(SNTP_OPMODE_POLL); */ + sntp_setoperatingmode(SNTP_OPMODE_POLL); + if (NTP_SERVER_COUNT > CONFIG_LWIP_SNTP_MAX_SERVERS) { + ESP_LOGW(TAG, "WARNING: %d NTP Servers defined, but " + "CONFIG_LWIP_SNTP_MAX_SERVERS = %d", + NTP_SERVER_COUNT,CONFIG_LWIP_SNTP_MAX_SERVERS); + } + ESP_LOGI(TAG, "sntp_setservername:"); + for (i = 0; i < CONFIG_LWIP_SNTP_MAX_SERVERS; i++) { + const char* thisServer = ntpServerList[i]; + if (strncmp(thisServer, "\x00", 1) == 0) { + /* just in case we run out of NTP servers */ + break; + } + ESP_LOGI(TAG, "%s", thisServer); + sntp_setservername(i, thisServer); + } + #ifdef HAS_ESP_NETIF_SNTP + ret = esp_netif_sntp_init(&config); + #else + ESP_LOGW(TAG,"Warning: Consider upgrading ESP-IDF to take advantage " + "of updated SNTP libraries"); + #endif + if (ret == ESP_OK) { + ESP_LOGV(TAG, "Successfully called esp_netif_sntp_init"); + } + else { + ESP_LOGE(TAG, "ERROR: esp_netif_sntp_init return = %d", ret); + } + + sntp_init(); + switch (ret) { + case ESP_ERR_INVALID_STATE: + break; + default: + break; + } + ESP_LOGI(TAG, "sntp_init done."); + } + else { + ESP_LOGW(TAG, "No sntp time servers found."); + ret = -1; + } + return ret; +} + +/* wait for NTP to actually set the time */ +int set_time_wait_for_ntp(void) +{ + int ret = 0; +#ifdef HAS_ESP_NETIF_SNTP + int ntp_retry = 0; + const int ntp_retry_count = NTP_RETRY_COUNT; + + ret = esp_netif_sntp_start(); + + ret = esp_netif_sntp_sync_wait(500 / portTICK_PERIOD_MS); +#endif /* HAS_ESP_NETIF_SNTP */ + esp_show_current_datetime(); + +#ifdef HAS_ESP_NETIF_SNTP + while (ret == ESP_ERR_TIMEOUT && (ntp_retry++ < ntp_retry_count)) { + ret = esp_netif_sntp_sync_wait(1000 / portTICK_PERIOD_MS); + ESP_LOGI(TAG, "Waiting for NTP to sync time... (%d/%d)", + ntp_retry, + ntp_retry_count); + esp_show_current_datetime(); + } +#endif /* HAS_ESP_NETIF_SNTP */ + +#ifdef TIME_ZONE + setenv("TZ", TIME_ZONE, 1); + tzset(); +#endif + + if (ret == ESP_OK) { + ESP_LOGI(TAG, "Successfuly set time via NTP servers."); + } + else { + ESP_LOGW(TAG, "Warning: Failed to set time with NTP: " + "result = 0x%0x: %s", + ret, esp_err_to_name(ret)); + } + return ret; +} 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 new file mode 100644 index 000000000..384a86274 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/main/wifi_connect.c @@ -0,0 +1,274 @@ +/* wifi_connect.c + * + * Copyright (C) 2006-2023 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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 + * (at your option) any later version. + * + * wolfSSL 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 + */ + #include "wifi_connect.h" + +#include +#include +#include +#include +#include + +/* wolfSSL */ +#include +#include +#include +#ifndef WOLFSSL_ESPIDF + #warning "Problem with wolfSSL user_settings." + #warning "Check components/wolfssl/include" +#endif + +#if ESP_IDF_VERSION_MAJOR >= 5 +#elif ESP_IDF_VERSION_MAJOR >= 4 + #include "protocol_examples_common.h" +#else + const static int CONNECTED_BIT = BIT0; + static EventGroupHandle_t wifi_event_group; +#endif + +#if defined(ESP_IDF_VERSION_MAJOR) && defined(ESP_IDF_VERSION_MINOR) + #if ESP_IDF_VERSION_MAJOR >= 4 + /* likely using examples, see wifi_connect.h */ + #else + /* TODO - still supporting pre V4 ? */ + const static int CONNECTED_BIT = BIT0; + static EventGroupHandle_t wifi_event_group; + #endif + #if (ESP_IDF_VERSION_MAJOR == 5) + #define HAS_WPA3_FEATURES + #else + #undef HAS_WPA3_FEATURES + #endif +#else + /* TODO Consider pre IDF v5? */ +#endif + +/* breadcrumb prefix for logging */ +const static char *TAG = "wifi_connect"; + +#if ESP_IDF_VERSION_MAJOR < 4 +/* event handler for wifi events */ +static esp_err_t wifi_event_handler(void *ctx, system_event_t *event) +{ + switch (event->event_id) + { + case SYSTEM_EVENT_STA_START: + esp_wifi_connect(); + break; + case SYSTEM_EVENT_STA_GOT_IP: + #if ESP_IDF_VERSION_MAJOR >= 4 + ESP_LOGI(TAG, "got ip:" IPSTR "\n", + IP2STR(&event->event_info.got_ip.ip_info.ip)); + #else + ESP_LOGI(TAG, "got ip:%s", + ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip)); + #endif + /* see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/freertos_idf.html */ + xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + esp_wifi_connect(); + xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); + break; + default: + break; + } + return ESP_OK; +} +#else + +#ifdef CONFIG_ESP_MAXIMUM_RETRY + #define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY +#else + #define CONFIG_ESP_MAXIMUM_RETRY 5 +#endif + +#if CONFIG_ESP_WIFI_AUTH_OPEN +#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_OPEN +#elif CONFIG_ESP_WIFI_AUTH_WEP +#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WEP +#elif CONFIG_ESP_WIFI_AUTH_WPA_PSK +#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_PSK +#elif CONFIG_ESP_WIFI_AUTH_WPA2_PSK +#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_PSK +#elif CONFIG_ESP_WIFI_AUTH_WPA_WPA2_PSK +#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA_WPA2_PSK +#elif CONFIG_ESP_WIFI_AUTH_WPA3_PSK +#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA3_PSK +#elif CONFIG_ESP_WIFI_AUTH_WPA2_WPA3_PSK +#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WPA2_WPA3_PSK +#elif CONFIG_ESP_WIFI_AUTH_WAPI_PSK +#define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD WIFI_AUTH_WAPI_PSK +#endif + +#ifndef ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD + #define CONFIG_ESP_WIFI_AUTH_WPA2_PSK 1 + #define ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD CONFIG_ESP_WIFI_AUTH_WPA2_PSK +#endif + +/* FreeRTOS event group to signal when we are connected*/ +static EventGroupHandle_t s_wifi_event_group; + +/* The event group allows multiple bits for each event, but we only care about two events: + * - we are connected to the AP with an IP + * - we failed to connect after the maximum amount of retries */ +#define WIFI_CONNECTED_BIT BIT0 +#define WIFI_FAIL_BIT BIT1 + + +static int s_retry_num = 0; +ip_event_got_ip_t* event; + +static void event_handler(void* arg, + esp_event_base_t event_base, + int32_t event_id, + void* event_data) +{ + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { + esp_wifi_connect(); + } + else if (event_base == WIFI_EVENT && + event_id == WIFI_EVENT_STA_DISCONNECTED) { + if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) { + esp_wifi_connect(); + s_retry_num++; + ESP_LOGI(TAG, "retry to connect to the AP"); + } + else { + xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); + } + ESP_LOGI(TAG, "connect to the AP fail"); + } + else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { + event = (ip_event_got_ip_t*) event_data; + wifi_show_ip(); + s_retry_num = 0; + xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); + } +} + +int wifi_init_sta(void) +{ + int ret = ESP_OK; + + s_wifi_event_group = xEventGroupCreate(); + + ESP_ERROR_CHECK(esp_netif_init()); + + ESP_ERROR_CHECK(esp_event_loop_create_default()); + esp_netif_create_default_wifi_sta(); + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + esp_event_handler_instance_t instance_any_id; + esp_event_handler_instance_t instance_got_ip; + ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, + ESP_EVENT_ANY_ID, + &event_handler, + NULL, + &instance_any_id)); + ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, + IP_EVENT_STA_GOT_IP, + &event_handler, + NULL, + &instance_got_ip)); + + wifi_config_t wifi_config = { + .sta = { + .ssid = EXAMPLE_ESP_WIFI_SSID, + .password = EXAMPLE_ESP_WIFI_PASS, + /* Authmode threshold resets to WPA2 as default if password matches + * WPA2 standards (pasword len => 8). If you want to connect the + * device to deprecated WEP/WPA networks, Please set the threshold + * value WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK and set the password with + * length and format matching to WIFI_AUTH_WEP/WIFI_AUTH_WPA_PSK + * standards. */ + .threshold.authmode = ESP_WIFI_SCAN_AUTH_MODE_THRESHOLD, + #ifdef HAS_WPA3_FEATURES + .sae_pwe_h2e = WPA3_SAE_PWE_BOTH, + #endif + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); + +#ifdef CONFIG_EXAMPLE_WIFI_SSID + if (XSTRCMP(CONFIG_EXAMPLE_WIFI_SSID, "myssid") == 0) { + ESP_LOGW(TAG, "WARNING: CONFIG_EXAMPLE_WIFI_SSID is \"myssid\"."); + ESP_LOGW(TAG, " Do you have a WiFi AP called \"myssid\", "); + ESP_LOGW(TAG, " or did you forget the ESP-IDF configuration?"); + } +#else + ESP_LOGW(TAG, "WARNING: CONFIG_EXAMPLE_WIFI_SSID not defined."); +#endif + + ESP_ERROR_CHECK(esp_wifi_start() ); + + ESP_LOGI(TAG, "wifi_init_sta finished."); + + /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) + * or connection failed for the maximum number of re-tries (WIFI_FAIL_BIT). + * The bits are set by event_handler() (see above) */ + EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, + WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, + pdFALSE, + pdFALSE, + portMAX_DELAY); + + /* xEventGroupWaitBits() returns the bits before the call returned, + * hence we can test which event actually happened. */ +#if defined(SHOW_SSID_AND_PASSWORD) + ESP_LOGW(TAG, "Undefine SHOW_SSID_AND_PASSWORD to not show SSID/password"); + if (bits & WIFI_CONNECTED_BIT) { + ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", + EXAMPLE_ESP_WIFI_SSID, + EXAMPLE_ESP_WIFI_PASS); + } + else if (bits & WIFI_FAIL_BIT) { + ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", + EXAMPLE_ESP_WIFI_SSID, + EXAMPLE_ESP_WIFI_PASS); + } + else { + ESP_LOGE(TAG, "UNEXPECTED EVENT"); + } +#else + if (bits & WIFI_CONNECTED_BIT) { + ESP_LOGI(TAG, "Connected to AP"); + } + else if (bits & WIFI_FAIL_BIT) { + ESP_LOGI(TAG, "Failed to connect to AP"); + ret = -1; + } + else { + ESP_LOGE(TAG, "AP UNEXPECTED EVENT"); + ret = -2; + } +#endif + return ret; +} + +int wifi_show_ip(void) +{ + // TODO Causes panic: ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); + return ESP_OK; +} +#endif diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/partitions_singleapp_large.csv b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/partitions_singleapp_large.csv new file mode 100644 index 000000000..a9c373bec --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/partitions_singleapp_large.csv @@ -0,0 +1,31 @@ +# to view: idf.py partition-table +# +# ESP-IDF Partition Table +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 24K, +phy_init,data, phy, 0xf000, 4K, +factory, app, factory, 0x10000, 1500K, + + +# For other settings, see: +# https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/partition-tables.html#creating-custom-tables +# +# Here is the summary printed for the "Single factory app, no OTA" configuration: +# +# # ESP-IDF Partition Table +# # Name, Type, SubType, Offset, Size, Flags +# nvs, data, nvs, 0x9000, 0x6000, +# phy_init, data, phy, 0xf000, 0x1000, +# factory, app, factory, 0x10000, 1M, +# +# +# Here is the summary printed for the "Factory app, two OTA definitions" configuration: +# +# # ESP-IDF Partition Table +# # Name, Type, SubType, Offset, Size, Flags +# nvs, data, nvs, 0x9000, 0x4000, +# otadata, data, ota, 0xd000, 0x2000, +# phy_init, data, phy, 0xf000, 0x1000, +# factory, app, factory, 0x10000, 1M, +# ota_0, app, ota_0, 0x110000, 1M, +# ota_1, app, ota_1, 0x210000, 1M, diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/sdkconfig.defaults b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/sdkconfig.defaults new file mode 100644 index 000000000..5cda514a9 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_echoserver/sdkconfig.defaults @@ -0,0 +1,38 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration + +CONFIG_FREERTOS_HZ=1000 +CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y + +# +# Default main stack size +# +# This is typically way bigger than needed for stack size. See user_settings.h +# +CONFIG_ESP_MAIN_TASK_STACK_SIZE=55500 + +# Legacy stack size for older ESP-IDF versions +CONFIG_MAIN_TASK_STACK_SIZE=55500 + +# +# Compiler options +# +CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2 +CONFIG_COMPILER_HIDE_PATHS_MACROS=y +CONFIG_COMPILER_STACK_CHECK_MODE_NORM=y +CONFIG_COMPILER_STACK_CHECK=y + +# +# Partition Table +# +# CONFIG_PARTITION_TABLE_SINGLE_APP is not set +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y +# CONFIG_PARTITION_TABLE_TWO_OTA is not set +# CONFIG_PARTITION_TABLE_CUSTOM is not set +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp_large.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +CONFIG_PARTITION_TABLE_MD5=y +# end of Partition Table diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_template/CMakeLists.txt b/ide/Espressif/ESP-IDF/examples/wolfssh_template/CMakeLists.txt new file mode 100644 index 000000000..58fa04c86 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/CMakeLists.txt @@ -0,0 +1,83 @@ +# wolfSSL Espressif Example Project CMakeLists.txt +# v1.0 +# +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +# enable wolfssl user_settings.h project-wide +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_USER_SETTINGS") +set(WOLFSSL_USER_SETTINGS ON) + + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSH_TERM") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEBUG_WOLFSSH") + +# The wolfSSL CMake file should be able to find the source code. +# Otherwise, assign an environment variable or set it here: +# +# set(WOLFSSL_ROOT "~/workspace/wolfssl-other-source") +# set(WOLFSSH_ROOT "~/workspace/wolfssh-other-source") +# set(WOLFSSL_ROOT "C:/workspace/wolfssl-master") + +# Optional WOLFSSL_CMAKE_SYSTEM_NAME detection to find +# USE_MY_PRIVATE_CONFIG path for my_private_config.h +# +# Expected path varies: +# +# WSL: /mnt/c/workspace +# Linux: ~/workspace +# Windows: C:\workspace +# +if(WIN32) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_WINDOWS") + message("Detected Windows") +endif() +if(CMAKE_HOST_UNIX) + message("Detected UNIX") +endif() +if(APPLE) + message("Detected APPLE") +endif() +if(CMAKE_HOST_UNIX AND (NOT APPLE) AND EXISTS "/proc/sys/fs/binfmt_misc/WSLInterop") + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_WSL") + message("Detected WSL") +endif() +if(CMAKE_HOST_UNIX AND (NOT APPLE) AND (NOT WIN32)) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_LINUX") + message("Detected Linux") +endif() +if(APPLE) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_APPLE") + message("Detected Apple") +endif() +# End optional WOLFSSL_CMAKE_SYSTEM_NAME + +# Check that there are not conflicting wolfSSL components +# The ESP Registry Component will be in ./managed_components/wolfssl__wolfssl +# The local component wolfSSL directory will be in ./components/wolfssl +if( EXISTS "${CMAKE_HOME_DIRECTORY}/managed_components/wolfssl__wolfssl" AND EXISTS "${CMAKE_HOME_DIRECTORY}/components/wolfssl" ) + # These exclude statements don't seem to be honored by the $ENV{IDF_PATH}/tools/cmake/project.cmake' + # add_subdirectory("${CMAKE_HOME_DIRECTORY}/managed_components/wolfssl__wolfssl" EXCLUDE_FROM_ALL) + # add_subdirectory("${CMAKE_HOME_DIRECTORY}/managed_components/wolfssl__wolfssl/include" EXCLUDE_FROM_ALL) + # So we'll error out and let the user decide how to proceed: + message(WARNING "\nFound wolfSSL components in\n" + "./managed_components/wolfssl__wolfssl\n" + "and\n" + "./components/wolfssl\n" + "in project directory: \n" + "${CMAKE_HOME_DIRECTORY}") + message(FATAL_ERROR "\nPlease use either the ESP Registry Managed Component or the wolfSSL component directory but not both.\n" + "If removing the ./managed_components/wolfssl__wolfssl directory, remember to also remove " + "or rename the idf_component.yml file typically found in ./main/") +else() + message(STATUS "No conflicting wolfSSL components found.") +endif() + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +project(wolfssh_template) diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_template/README.md b/ide/Espressif/ESP-IDF/examples/wolfssh_template/README.md new file mode 100644 index 000000000..d6dd17ff7 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/README.md @@ -0,0 +1,64 @@ +# wolfSSL Template Project + +This is an example minimally viable wolfSSL template to get started with your own project. + +### Prerequisites + +It is assumed the [ESP-IDF environment](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/) has been installed. + +### Files Included + +- [main.c](./main/main.c) with a simple call to an Espressif library (`ESP_LOGI`) and a call to a wolfSSL library (`esp_ShowExtendedSystemInfo`) . + +- See [components/wolfssl/include](./components/wolfssl/include/user_settings.h) directory to edit the wolfSSL `user_settings.h`. + +- Edit [main/CMakeLists.txt](./main/CMakeLists.txt) to add/remove source files. + +- The [components/wolfssl/CMakeLists.txt](./components/wolfssl/CMakeLists.txt) typically does not need to be changed. + +- Optional [VisualGDB Project](./VisualGDB/wolfssl_template_IDF_v5.1_ESP32.vgdbproj) for Visual Studio using ESP32 and ESP-IDF v5.1. + +- Edit the project [CMakeLists.txt](./CMakeLists.txt) to optionally point this project's wolfSSL component source code at a different directory: + +``` +set(WOLFSSL_ROOT "~/workspace/wolfssl-other-source") +``` + + +## Getting Started: + +Here's an example using the command-line [idf.py](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-py.html). + +Edit your `WRK_IDF_PATH`to point to your ESP-IDF install directory. + +``` +WRK_IDF_PATH=/mnt/c/SysGCC/esp32/esp-idf/v5.1 + +echo "Run export.sh from ${WRK_IDF_PATH}" +. ${WRK_IDF_PATH}/export.sh + +# build the example: +idf.py build + +# flash the code onto the serial device at /dev/ttyS19 +idf.py flash -p /dev/ttyS19 -b 115200 + +# build, flash, and view UART output with one command: +idf.py flash -p /dev/ttyS19 -b 115200 monitor +``` + +Press `Ctrl+]` to exit `idf.py monitor`. See [additional monitor keyboard commands](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/tools/idf-monitor.html). + +## Other Examples: + +For examples, see: + +- [TLS Client](../wolfssl_client/README.md) +- [TLS Server](../wolfssl_server/README.md) +- [Benchmark](../wolfssl_benchmark/README.md) +- [Test](../wolfssl_test/README.md) +- [wolfssl-examples](https://github.com/wolfSSL/wolfssl-examples/tree/master/ESP32) +- [wolfssh-examples](https://github.com/wolfSSL/wolfssh-examples/tree/main/Espressif) + + + diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_template/VisualGDB/wolfssh_template_IDF_v5.1_ESP32.sln b/ide/Espressif/ESP-IDF/examples/wolfssh_template/VisualGDB/wolfssh_template_IDF_v5.1_ESP32.sln new file mode 100644 index 000000000..1396c1884 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/VisualGDB/wolfssh_template_IDF_v5.1_ESP32.sln @@ -0,0 +1,54 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33829.357 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{803FD0C6-D64E-4E16-9DC3-1DAEC859A3D2}") = "wolfssh_template_IDF_v5.1_ESP32", "wolfssh_template_IDF_v5.1_ESP32.vgdbproj", "{EADCC9AB-72B3-4B51-A838-593E5D80DDF7}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F0564364-33CD-468B-8514-D6A907B2449C}" + ProjectSection(SolutionItems) = preProject + ..\README.md = ..\README.md + ..\..\..\setup.sh = ..\..\..\setup.sh + ..\..\..\setup_win.bat = ..\..\..\setup_win.bat + ..\..\wolfssl_monitor.py = ..\..\wolfssl_monitor.py + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "wolfssh", "wolfssh", "{A9456F78-BEB7-4057-8015-E5A63CB41D44}" + ProjectSection(SolutionItems) = preProject + ..\components\wolfssh\CMakeLists.txt = ..\components\wolfssh\CMakeLists.txt + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "wolfssl", "wolfssl", "{530EF870-BCA9-4320-AD27-1D8FC6B3770C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "include", "include", "{C3B90A14-D318-4828-BDD3-A5D018C032F5}" + ProjectSection(SolutionItems) = preProject + ..\components\wolfssl\include\user_settings.h = ..\components\wolfssl\include\user_settings.h + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|VisualGDB = Debug|VisualGDB + Release|VisualGDB = Release|VisualGDB + Tests (Debug)|VisualGDB = Tests (Debug)|VisualGDB + Tests (Release)|VisualGDB = Tests (Release)|VisualGDB + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {EADCC9AB-72B3-4B51-A838-593E5D80DDF7}.Debug|VisualGDB.ActiveCfg = Debug|VisualGDB + {EADCC9AB-72B3-4B51-A838-593E5D80DDF7}.Debug|VisualGDB.Build.0 = Debug|VisualGDB + {EADCC9AB-72B3-4B51-A838-593E5D80DDF7}.Release|VisualGDB.ActiveCfg = Release|VisualGDB + {EADCC9AB-72B3-4B51-A838-593E5D80DDF7}.Release|VisualGDB.Build.0 = Release|VisualGDB + {EADCC9AB-72B3-4B51-A838-593E5D80DDF7}.Tests (Debug)|VisualGDB.ActiveCfg = Tests (Debug)|VisualGDB + {EADCC9AB-72B3-4B51-A838-593E5D80DDF7}.Tests (Debug)|VisualGDB.Build.0 = Tests (Debug)|VisualGDB + {EADCC9AB-72B3-4B51-A838-593E5D80DDF7}.Tests (Release)|VisualGDB.ActiveCfg = Tests (Release)|VisualGDB + {EADCC9AB-72B3-4B51-A838-593E5D80DDF7}.Tests (Release)|VisualGDB.Build.0 = Tests (Release)|VisualGDB + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {C3B90A14-D318-4828-BDD3-A5D018C032F5} = {530EF870-BCA9-4320-AD27-1D8FC6B3770C} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {68907C18-A199-469F-8856-F03632FDA03E} + EndGlobalSection +EndGlobal diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_template/VisualGDB/wolfssh_template_IDF_v5.1_ESP32.vgdbproj b/ide/Espressif/ESP-IDF/examples/wolfssh_template/VisualGDB/wolfssh_template_IDF_v5.1_ESP32.vgdbproj new file mode 100644 index 000000000..9edbb41e2 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/VisualGDB/wolfssh_template_IDF_v5.1_ESP32.vgdbproj @@ -0,0 +1,269 @@ + + + + + + Unknown + + true + + 7bbd1486-d457-4e49-92ba-0cfc9d80849e + true + true + SourceDirs + + + + + + com.visualgdb.xtensa-esp32-elf + + 12.2.0 + 12.1 + 1 + + + .. + DEBUG + build/$(PlatformName)/$(ConfigurationName) + + false + $(ToolchainNinja) + $(BuildDir) + + + + false + $(SYSPROGS_CMAKE_PATH) + + + true + false + false + Ninja + false + RemoveBuildDirectory + false + + + true + true + true + false + true + false + true + HideOuterProjectTargets + true + false + true + + + true + eadcc9ab-72b3-4b51-a838-593e5d80ddf7 + + Upper + HeaderDirectoryAndSubdirectories + true + + + release/v5.1 + esp-idf/v5.1 + ESPIDF + + COM9 + false + false + ESP32 + + + + + + + + + + + + + + + Default + + + + COM9 + + 115200 + 8 + None + One + None + + + 0 + false + false + false + ASCII + + + 255 + 0 + 0 + 0 + + + 255 + 169 + 169 + 169 + + + 255 + 211 + 211 + 211 + + + 255 + 144 + 238 + 144 + + + 255 + 169 + 169 + 169 + + + + 16 + true + true + true + true + 0 + + LF + false + false + false + + + + true + + + + + Unknown + + true + true + true + + + + false + + + + + Debug + + + + Release + + + + + + + + + false + false + false + false + false + false + false + false + false + + false + false + false + false + false + false + true + false + None + false + false + app_main + true + false + false + true + 0 + false + 0 + true + false + + + openocd + + -f interface/ftdi/tigard.cfg -c "adapter_khz 15000" -f target/esp32.cfg + + + + false + + 131072 + Enabled + + set remotetimeout 60 + target remote :$$SYS:GDB_PORT$$ + mon gdb_breakpoint_override hard + mon reset halt + load + + false + 0 + 0 + false + + 5000 + 1 + true + + size2MB + freq40M + DIO + + true + + + true + Disabled + 0 + false + false + true + false + false + + _estack + 0 + false + + true + + \ No newline at end of file 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 new file mode 100644 index 000000000..6d54b9e74 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssh/CMakeLists.txt @@ -0,0 +1,508 @@ +# Espressif component/wolfssh/CMakeLists.txt +# +# Copyright (C) 2006-2023 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 2 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA +# +# cmake for WOLFSSH Espressif projects +# +# See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html +# + +cmake_minimum_required(VERSION 3.16) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSH_USER_SETTINGS") +set(CMAKE_CURRENT_SOURCE_DIR ".") + +# Attention! +# +# When editing component CMake files, consider the following : +# +# NO Managed Componenets: Normal stand-alone app, "as cloned" from github. +# There's no notion of staging names (e.g. mywolfmqtt) regardless of environment settings. +# All of the component source is locall. See settings such s WOLFSSL_ROOT=[your path] +# +# Partially Managed Components. This one is tricky. When publishing a component with examples, +# those examples will have a chicken-and-egg problem: the required component is not yet published. +# Adding to the complexity is the notion of staging components, that are purposely prefixed with +# "my" (e.g. mywolfmqtt) to distinguish from production, live components (e.g. wolfmqtt) +# +# Partially Managed Component Examples are typically only encountered by the component publisher +# and only at publish time, such as when performing the pre-publish build check. +# +# A partially managed component may also be manually created, when adding a managed component to +# and existing project. For example: +# +# idf.py add-dependency "wolfssl/wolfssh^1.4.15-stable" +# +# Fully Managaged Componenets. This is the typical example as created from the Component Registry: +# For example: +# +# idf.py create-project-from-example "wolfssl/wolfssh^1.4.15-stable:wolfssh_server" +# +# In all cases, keep in mind that components other than wolfssl will depend on the wolfssl component. +# + +# Component naming is only adjusted when using Managed Components, and only when using staging site. +if( "$ENV{IDF_COMPONENT_REGISTRY_URL}" STREQUAL "https://components-staging.espressif.com" ) + # TODO: Is checking these two variables really the best way to detect an active Component Manager? + message(STATUS "component_manager_interface_version = ${component_manager_interface_version}") + message(STATUS "managed_components = ${managed_components}") + if( ("${managed_components}" STREQUAL "") AND ("${component_manager_interface_version}" STREQUAL "") ) + # We've found a staging component, but did not detect the component manager + set(WOLFSSL_COMPONENT_NAME "wolfssl") + else() + set(WOLFSSL_COMPONENT_NAME "mywolfssl") + endif() +else() + set(WOLFSSL_COMPONENT_NAME "wolfssl") +endif() + +set(COMPONENT_REQUIRES lwip "${WOLFSSL_COMPONENT_NAME}") + +# COMPONENT_NAME = wolfssh +# The component name is the directory name. "No feature to change this". +# See https://github.com/espressif/esp-idf/issues/8978#issuecomment-1129892685 + +# set the root of WOLFSSH in top-level project CMakelists.txt: +# set(WOLFSSH_ROOT "C:/some path/with/spaces") +# set(WOLFSSH_ROOT "c:/workspace/WOLFSSH-[username]") +# set(WOLFSSH_ROOT "/mnt/c/some path/with/spaces") +# or use this logic to assign value from Environment Variable WOLFSSH_ROOT, +# or assume this is an example 7 subdirectories below: + +# We are typically in [root]/IDE/Espressif/ESP-IDF/examples/WOLFSSH_test/components/WOLFSSH +# The root of WOLFSSH is 7 directories up from here: + +if(CMAKE_BUILD_EARLY_EXPANSION) + message(STATUS "WOLFSSH component CMAKE_BUILD_EARLY_EXPANSION:") + idf_component_register( + REQUIRES "${COMPONENT_REQUIRES}" + PRIV_REQUIRES + esp_timer + driver + "${WOLFSSL_COMPONENT_NAME}" # either wolfssl or mywolfssl as a staging component + ) + +else() + # not CMAKE_BUILD_EARLY_EXPANSION + message(STATUS "************************************************************************************************") + message(STATUS "wolfssh component config:") + message(STATUS "************************************************************************************************") + + # Check to see if we're already in WOLFSSH, and only if WOLFSSH_ROOT not specified + if ("${WOLFSSH_ROOT}" STREQUAL "") + # WOLFSSH examples are 7 directories deep from WOLFSSH repo root + # 1 2 3 4 5 6 7 + set(THIS_RELATIVE_PATH "../../../../../../..") + get_filename_component(THIS_SEARCH_PATH "${THIS_RELATIVE_PATH}" ABSOLUTE) + message(STATUS "Searching in path = ${THIS_SEARCH_PATH}") + + if (EXISTS "${THIS_SEARCH_PATH}/wolfcrypt/src") + # we're already in WOLFSSH examples! + get_filename_component(WOLFSSH_ROOT "${THIS_SEARCH_PATH}" ABSOLUTE) + message(STATUS "Using WOLFSSH example with root ${WOLFSSH_ROOT}") + else() + # We're in some other repo such as wolfssh, so we'll search for an + # adjacent-level directory for WOLFSSH. (8 directories up, then down one) + # + # For example WOLFSSH examples: + # C:\workspace\WOLFSSH-gojimmypi\IDE\Espressif\ESP-IDF\examples\WOLFSSH_benchmark\components\WOLFSSH + # + # For example wolfSSH examples: + # C:\workspace\wolfssh-gojimmypi\ide\Espressif\ESP-IDF\examples\wolfssh_benchmark\components\WOLFSSH + # + # 1 2 3 4 5 6 7 8 + set(THIS_RELATIVE_PATH "../../../../../../../..") + get_filename_component(THIS_SEARCH_PATH "${THIS_RELATIVE_PATH}" ABSOLUTE) + message(STATUS "Searching next in path = ${THIS_SEARCH_PATH}") + endif() + endif() + + # search other possible locations + if ("${WOLFSSH_ROOT}" STREQUAL "") + # there's not a hard-coded WOLFSSH_ROOT value above, so let's see if we can find it. + if( "$ENV{WOLFSSH_ROOT}" STREQUAL "" ) + message(STATUS "Environment Variable WOLFSSH_ROOT not set. Will search common locations.") + + message(STATUS "CMAKE_CURRENT_SOURCE_DIR = ${CMAKE_CURRENT_SOURCE_DIR}") + get_filename_component(THIS_DIR "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE) + message(STATUS "THIS_DIR = ${THIS_DIR}") + + # find the user name to search for possible "WOLFSSH-username" + message(STATUS "USERNAME = $ENV{USERNAME}") + if( "$ENV{USER}" STREQUAL "" ) # the bash user + if( "$ENV{USERNAME}" STREQUAL "" ) # the Windows user + message(STATUS "could not find USER or USERNAME") + else() + # the bash user is not blank, so we'll use it. + set(THIS_USER "$ENV{USERNAME}") + endif() + else() + # the bash user is not blank, so we'll use it. + set(THIS_USER "$ENV{USER}") + endif() + message(STATUS "THIS_USER = ${THIS_USER}") + + # This same makefile is used for both the WOLFSSH component, and other + # components that may depend on WOLFSSH, such as wolfssh. Therefore + # we need to determine if this makefile is in the WOLFSSH repo, or + # some other repo. + + if( "{THIS_USER}" STREQUAL "" ) + # This is highly unusual to not find a user name. + # In this case, we'll just search for a "WOLFSSH" directory: + message(STATUS "No username found!") + get_filename_component(WOLFSSH_ROOT "${THIS_RELATIVE_PATH}/WOLFSSH" ABSOLUTE) + else() + # We found an environment USER name! + # The first place to look for WOLFSSH will be in a user-clone called "WOLFSSH-[username]" + message(STATUS "Using [THIS_USER = ${THIS_USER}] to see if there's a [relative path]/WOLFSSH-${THIS_USER} directory.") + get_filename_component(WOLFSSH_ROOT "${THIS_RELATIVE_PATH}/WOLFSSH-${THIS_USER}" ABSOLUTE) + + if( EXISTS "${WOLFSSH_ROOT}" ) + message(STATUS "Found WOLFSSH in user-suffix ${WOLFSSH_ROOT}") + else() + # If there's not a user-clone called "WOLFSSH-[username]", + # perhaps there's simply a git clone called "WOLFSSH"? + message(STATUS "Did not find WOLFSSH-${THIS_USER}; continuing search...") + get_filename_component(WOLFSSH_ROOT "${THIS_RELATIVE_PATH}/WOLFSSH" ABSOLUTE) + + if( EXISTS "${WOLFSSH_ROOT}" ) + message(STATUS "Found WOLFSSH in standard ${WOLFSSH_ROOT}") + else() + # Things are looking pretty bleak. We'll likely not be able to compile. + message(STATUS "Did not find WOLFSSH in ${WOLFSSH_ROOT}") + endif() + endif() + endif() + + else() + # there's an environment variable, so use it. + set(WOLFSSH_ROOT "$ENV{WOLFSSH_ROOT}") + + if( EXISTS "${WOLFSSH_ROOT}" ) + get_filename_component(WOLFSSH_ROOT "$ENV{WOLFSSH_ROOT}" ABSOLUTE) + message(STATUS "Found WOLFSSH_ROOT via Environment Variable:") + else() + message(FATAL_ERROR "WOLFSSH_ROOT Environment Variable defined, but path not found:") + message(STATUS "$ENV{WOLFSSH_ROOT}") + endif() + endif() + # end of search for WOLFSSH component root + else() + # There's already a value assigned; we won't search for anything else. + message(STATUS "Found user-specified WOLFSSH_ROOT value.") + endif() # WOLFSSH_ROOT user defined + + # After all the logic above, does our WOLFSSH_ROOT actually exist? + if( EXISTS "${WOLFSSH_ROOT}" ) + message(STATUS "WOLFSSH_ROOT = ${WOLFSSH_ROOT}") + else() + # Abort. We need WOLFSSH _somewhere_. + message(FATAL_ERROR "Could not find WOLFSSH in ${WOLFSSH_ROOT}. Try setting environment variable or git clone.") + endif() + + + set(INCLUDE_PATH ${WOLFSSH_ROOT}) + + set(COMPONENT_SRCDIRS + "\"${WOLFSSH_ROOT}/src/\"" + ) # COMPONENT_SRCDIRS + message(STATUS "This COMPONENT_SRCDIRS = ${COMPONENT_SRCDIRS}") + + set(WOLFSSH_PROJECT_DIR "${CMAKE_HOME_DIRECTORY}/components/wolfssh") + + # Espressif may take several passes through this makefile. Check to see if we found IDF + string(COMPARE EQUAL "${PROJECT_SOURCE_DIR}" "" WOLFSSH_FOUND_IDF) + + message(STATUS "IDF_PATH = $ENV{IDF_PATH}") + message(STATUS "PROJECT_SOURCE_DIR = ${PROJECT_SOURCE_DIR}") + message(STATUS "EXCLUDE_ASM = ${EXCLUDE_ASM}") + + # + # Check to see if there's both a local copy and EDP-IDF copy of the WOLFSSH and/or wolfssh components. + # + if( EXISTS "${WOLFSSH_PROJECT_DIR}" AND EXISTS "$ENV{IDF_PATH}/components/WOLFSSH/" ) + # + # WOLFSSH found in both ESP-IDF and local project - needs to be resolved by user + # + message(STATUS "") + message(STATUS "**************************************************************************************") + message(STATUS "") + message(STATUS "Error: Found components/WOLFSSH in both local project and IDF_PATH") + message(STATUS "") + message(STATUS "To proceed: ") + message(STATUS "") + message(STATUS "Remove either the local project component: ${WOLFSSH_PROJECT_DIR} ") + message(STATUS "or the Espressif shared component installed at: $ENV{IDF_PATH}/components/WOLFSSH/ ") + message(STATUS "") + message(FATAL_ERROR "Please use WOLFSSH in either local project or Espressif components, but not both.") + message(STATUS "") + message(STATUS "**************************************************************************************") + message(STATUS "") + + # Optional: if you change the above FATAL_ERROR to STATUS you can warn at runtime with this macro definition: + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSH_MULTI_INSTALL_WARNING") + + else() + if( EXISTS "$ENV{IDF_PATH}/components/WOLFSSH/" ) + # + # WOLFSSH found in ESP-IDF components and is assumed to be already configured in user_settings.h via setup. + # + message(STATUS "") + message(STATUS "Using components/WOLFSSH in IDF_PATH = $ENV{IDF_PATH}") + message(STATUS "") + else() + # + # WOLFSSH is not an ESP-IDF component. + # We need to now determine if it is local and if so if it is part of the WOLFSSH repo, + # or if WOLFSSH is simply installed as a local component. + # + + if( EXISTS "${WOLFSSH_PROJECT_DIR}" ) + # + # WOLFSSH found in local project. + # + if( EXISTS "${WOLFSSH_PROJECT_DIR}/wolfcrypt/" ) + message(STATUS "") + message(STATUS "Using installed project ./components/WOLFSSH in CMAKE_HOME_DIRECTORY = ${CMAKE_HOME_DIRECTORY}") + message(STATUS "") + # + # Note we already checked above and confirmed there's not another WOLFSSH installed in the ESP-IDF components. + # + # We won't do anything else here, as it will be assumed the original install completed successfully. + # + else() # full WOLFSSH not installed in local project + # + # This is the developer repo mode. WOLFSSH will be assumed to be not installed to ESP-IDF nor local project + # In this configuration, we are likely running a WOLFSSH example found directly in the repo. + # + message(STATUS "") + message(STATUS "Using developer repo ./components/WOLFSSH in CMAKE_HOME_DIRECTORY = ${CMAKE_HOME_DIRECTORY}") + message(STATUS "") + + message(STATUS "************************************************************************************************") + # When in developer mode, we are typically running WOLFSSH examples such as benchmark or test directories. + # However, the as-cloned or distributed WOLFSSH does not have the ./include/ directory, so we'll add it as needed. + # + # first check if there's a [root]/include/user_settings.h + if( EXISTS "${WOLFSSH_ROOT}/include/user_settings.h" ) + message(FATAL_ERROR "Found stray WOLFSSH user_settings.h in " + "${WOLFSSH_ROOT}/include/user_settings.h " + " (please move it to ${WOLFSSH_PROJECT_DIR}/include/user_settings.h )") + else() + # we won't overwrite an existing user settings file, just note that we already have one: + if( EXISTS "${WOLFSSH_PROJECT_DIR}/include/user_settings.h" ) + message(STATUS "Using existing WOLFSSH user_settings.h in " + "${WOLFSSH_PROJECT_DIR}/include/user_settings.h") + else() + message(STATUS "Installing WOLFSSH user_settings.h to " + "${WOLFSSH_PROJECT_DIR}/include/user_settings.h") + # file(COPY "${WOLFSSH_ROOT}/IDE/Espressif/ESP-IDF/user_settings.h" + # DESTINATION "${CMAKE_HOME_DIRECTORY}/WOLFSSH/include/") + endif() + endif() # user_settings.h + + message(STATUS "************************************************************************************************") + message(STATUS "") + endif() + + else() + # we did not find a ./components/WOLFSSH/include/ directory from this pass of cmake. + if($WOLFSSH_FOUND_IDF) + message(STATUS "") + message(STATUS "WARNING: WOLFSSH not found.") + message(STATUS "") + else() + # probably needs to be re-parsed by Espressif + message(STATUS "WOLFSSH found IDF. Project Source:${PROJECT_SOURCE_DIR}") + endif() # else we have not found ESP-IDF yet + endif() # else not a local WOLFSSH component + + endif() #else not an ESP-IDF component + endif() # else not local copy and EDP-IDF WOLFSSH + + + # RTOS_IDF_PATH is typically: + # "/Users/{username}/Desktop/esp-idf/components/freertos/include/freertos" + # depending on the environment, we may need to swap backslashes with forward slashes + string(REPLACE "\\" "/" RTOS_IDF_PATH "$ENV{IDF_PATH}/components/freertos/FreeRTOS-Kernel/include/freertos") + + string(REPLACE "\\" "/" WOLFSSH_ROOT ${WOLFSSH_ROOT}) + + if(IS_DIRECTORY "${RTOS_IDF_PATH}") + message(STATUS "Found current RTOS path: ${RTOS_IDF_PATH}") + else() + # ESP-IDF prior version 4.4x has a different RTOS directory structure + string(REPLACE "\\" "/" RTOS_IDF_PATH "$ENV{IDF_PATH}/components/freertos/include/freertos") + if(IS_DIRECTORY "${RTOS_IDF_PATH}") + message(STATUS "Found legacy RTOS path: ${RTOS_IDF_PATH}") + else() + message(STATUS "Could not find RTOS path") + endif() + endif() + + + set(COMPONENT_ADD_INCLUDEDIRS + # "./include" # not used! See wolfSSL include/user_settings.h + "\"${WOLFSSH_ROOT}/\"" + "\"${WOLFSSH_ROOT}/wolfssh/\"" + "\"${RTOS_IDF_PATH}/\"" + ) + + + if(IS_DIRECTORY ${IDF_PATH}/components/cryptoauthlib) + list(APPEND COMPONENT_ADD_INCLUDEDIRS "../cryptoauthlib/lib") + endif() + + list(APPEND COMPONENT_ADD_INCLUDEDIRS "\"${WOLFSSH_ROOT}/wolfssh/\"") + + + + set(COMPONENT_SRCEXCLUDE + # wolfSSH + # TODO: we likely need to check #if !defined(WOLFSSH_MISC_INCLUDED) && !defined(NO_INLINE) && !defined(WOLFSSH_IGNORE_FILE_WARN) + # here in cmake if we actually want to always exclude wolfssh misc.c file. (see source; ok for demo) + "\"${WOLFSSH_ROOT}/src/misc.c\"" # misc.c does not need to be compiled when using inline (NO_INLINE not defined)) + ) + + spaces2list(COMPONENT_REQUIRES) + + separate_arguments(COMPONENT_SRCDIRS NATIVE_COMMAND "${COMPONENT_SRCDIRS}") + separate_arguments(COMPONENT_SRCEXCLUDE NATIVE_COMMAND "${COMPONENT_SRCEXCLUDE}") + separate_arguments(COMPONENT_ADD_INCLUDEDIRS NATIVE_COMMAND "${COMPONENT_ADD_INCLUDEDIRS}") + + # + # See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html#example-component-requirements + # + message(STATUS "COMPONENT_SRCDIRS = ${COMPONENT_SRCDIRS}") + message(STATUS "COMPONENT_ADD_INCLUDEDIRS = ${COMPONENT_ADD_INCLUDEDIRS}") + message(STATUS "COMPONENT_REQUIRES = ${COMPONENT_REQUIRES}") + message(STATUS "COMPONENT_SRCEXCLUDE = ${COMPONENT_SRCEXCLUDE}") + + # + # see https://docs.espressif.com/projects/esp-idf/en/stable/esp32/migration-guides/release-5.x/build-system.html?highlight=space%20path + # + set(EXTRA_COMPONENT_DIRS "${COMPONENT_SRCDIRS}") + idf_component_register( + SRC_DIRS "${COMPONENT_SRCDIRS}" + INCLUDE_DIRS "${COMPONENT_ADD_INCLUDEDIRS}" + REQUIRES "${COMPONENT_REQUIRES}" + EXCLUDE_SRCS "${COMPONENT_SRCEXCLUDE}" + PRIV_REQUIRES + esp_timer + driver + "${WOLFSSL_COMPONENT_NAME}" # either wolfssl or mywolfssl as a staging component + ) + # some optional diagnostics + if (1) + 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() + + # target_sources(WOLFSSH PRIVATE "\"${WOLFSSH_ROOT}/WOLFSSH/\"" "\"${WOLFSSH_ROOT}/WOLFSSH/wolfcrypt\"") +endif() # CMAKE_BUILD_EARLY_EXPANSION + + + +# check to see if there's both a local copy and EDP-IDF copy of the WOLFSSH components +if( EXISTS "${WOLFSSH_PROJECT_DIR}" AND EXISTS "$ENV{IDF_PATH}/components/WOLFSSH/" ) + message(STATUS "") + message(STATUS "") + message(STATUS "********************************************************************") + message(STATUS "WARNING: Found components/WOLFSSH in both local project and IDF_PATH") + message(STATUS "********************************************************************") + message(STATUS "") +endif() +# end multiple component check + + +# +# LIBWOLFSSH_SAVE_INFO(VAR_OUPUT THIS_VAR VAR_RESULT) +# +# Save the THIS_VAR as a string in a macro called VAR_OUPUT +# +# VAR_OUPUT: the name of the macro to define +# THIS_VAR: the OUTPUT_VARIABLE result from a execute_process() +# VAR_RESULT: the RESULT_VARIABLE from a execute_process(); "0" if successful. +# +function ( LIBWOLFSSH_SAVE_INFO VAR_OUPUT THIS_VAR VAR_RESULT ) + # is the RESULT_VARIABLE output value 0? If so, IS_VALID_VALUE is true. + string(COMPARE EQUAL "${VAR_RESULT}" "0" IS_VALID_VALUE) + + # if we had a successful operation, save the THIS_VAR in VAR_OUPUT + if(${IS_VALID_VALUE}) + # strip newline chars in THIS_VAR parameter and save in VAR_VALUE + string(REPLACE "\n" "" VAR_VALUE ${THIS_VAR}) + + # we'll could percolate the value to the parent for possible later use + # set(${VAR_OUPUT} ${VAR_VALUE} PARENT_SCOPE) + + # but we're only using it here in this function + set(${VAR_OUPUT} ${VAR_VALUE}) + + # we'll print what we found to the console + message(STATUS "Found ${VAR_OUPUT}=${VAR_VALUE}") + + # the interesting part is defining the VAR_OUPUT name a value to use in the app + add_definitions(-D${VAR_OUPUT}=\"${VAR_VALUE}\") + else() + # if we get here, check the execute_process command and parameters. + message(STATUS "LIBWOLFSSH_SAVE_INFO encountered a non-zero VAR_RESULT") + set(${VAR_OUPUT} "Unknown") + endif() +endfunction() # LIBWOLFSSH_SAVE_INFO + +# create some programmatic #define values that will be used by ShowExtendedSystemInfo(). +# see wolfcrypt\src\port\Espressif\esp32_utl.c +if(NOT CMAKE_BUILD_EARLY_EXPANSION) + set (git_cmd "git") + message(STATUS "Adding macro definitions:") + + # LIBWOLFSSH_VERSION_GIT_ORIGIN: git config --get remote.origin.url + execute_process(WORKING_DIRECTORY ${WOLFSSH_ROOT} COMMAND ${git_cmd} "config" "--get" "remote.origin.url" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSH_SAVE_INFO(LIBWOLFSSH_VERSION_GIT_ORIGIN "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSH_VERSION_GIT_BRANCH: git rev-parse --abbrev-ref HEAD + execute_process(WORKING_DIRECTORY ${WOLFSSH_ROOT} COMMAND ${git_cmd} "rev-parse" "--abbrev-ref" "HEAD" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSH_SAVE_INFO(LIBWOLFSSH_VERSION_GIT_BRANCH "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSH_VERSION_GIT_HASH: git rev-parse HEAD + execute_process(WORKING_DIRECTORY ${WOLFSSH_ROOT} COMMAND ${git_cmd} "rev-parse" "HEAD" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSH_SAVE_INFO(LIBWOLFSSH_VERSION_GIT_HASH "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSH_VERSION_GIT_SHORT_HASH: git rev-parse --short HEAD + execute_process(WORKING_DIRECTORY ${WOLFSSH_ROOT} COMMAND ${git_cmd} "rev-parse" "--short" "HEAD" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSH_SAVE_INFO(LIBWOLFSSH_VERSION_GIT_SHORT_HASH "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSH_VERSION_GIT_HASH_DATE git show --no-patch --no-notes --pretty=\'\%cd\' + execute_process(WORKING_DIRECTORY ${WOLFSSH_ROOT} COMMAND ${git_cmd} "show" "--no-patch" "--no-notes" "--pretty=\'\%cd\'" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ) + LIBWOLFSSH_SAVE_INFO(LIBWOLFSSH_VERSION_GIT_HASH_DATE "${TMP_OUT}" "${TMP_RES}") + + message(STATUS "************************************************************************************************") + message(STATUS "WOLFSSH component config complete!") + message(STATUS "************************************************************************************************") +endif() 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 new file mode 100644 index 000000000..d58704b84 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssl/CMakeLists.txt @@ -0,0 +1,676 @@ +# +# Copyright (C) 2006-2023 wolfSSL Inc. +# +# This file is part of wolfSSL. +# +# wolfSSL 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 +# (at your option) any later version. +# +# wolfSSL 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 +# +# cmake for wolfssl Espressif projects +# +# Version 5.6.4.016 for improved manual setting of WOLFSSL_ROOT + ESP8266 support; optional esp-timer / driver components +# +# See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html +# + +cmake_minimum_required(VERSION 3.16) + +set(VERBOSE_COMPONENT_MESSAGES 1) + +# The scope of this CMAKE_C_FLAGS is just this component: +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_USER_SETTINGS") + +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" ) + +if ( "${WOLFSSL_ROOT}" STREQUAL "") + set(WOLFSSL_ROOT "$ENV{WOLFSSL_ROOT}" ) +endif() +# Optional compiler definitions to help with system name detection (typically printed by app diagnostics) +if(VERBOSE_COMPONENT_MESSAGES) + if(WIN32) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_WINDOWS") + message("Detected Windows") + endif() + if(CMAKE_HOST_UNIX) + message("Detected UNIX") + endif() + if(APPLE) + message("Detected APPLE") + endif() + if(CMAKE_HOST_UNIX AND (NOT APPLE) AND EXISTS "/proc/sys/fs/binfmt_misc/WSLInterop") + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_WSL") + message("Detected WSL") + endif() + if(CMAKE_HOST_UNIX AND (NOT APPLE) AND (NOT WIN32)) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_LINUX") + message("Detected Linux") + endif() + if(APPLE) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_APPLE") + message("Detected Apple") + endif() +endif() # End optional WOLFSSL_CMAKE_SYSTEM_NAME + +message(STATUS "CONFIG_TARGET_PLATFORM = ${CONFIG_TARGET_PLATFORM}") + +# Check that there are not conflicting wolfSSL components +# The ESP Registry Component will be in ./managed_components/wolfssl__wolfssl +# The local component wolfSSL directory will be in ./components/wolfssl +if( EXISTS "${CMAKE_HOME_DIRECTORY}/managed_components/wolfssl__wolfssl" AND EXISTS "${CMAKE_HOME_DIRECTORY}/components/wolfssl" ) + # These exclude statements don't seem to be honored by the $ENV{IDF_PATH}/tools/cmake/project.cmake' + # add_subdirectory("${CMAKE_HOME_DIRECTORY}/managed_components/wolfssl__wolfssl" EXCLUDE_FROM_ALL) + # add_subdirectory("${CMAKE_HOME_DIRECTORY}/managed_components/wolfssl__wolfssl/include" EXCLUDE_FROM_ALL) + # So we'll error out and let the user decide how to proceed: + message(WARNING "\nFound wolfSSL components in\n" + "./managed_components/wolfssl__wolfssl\n" + "and\n" + "./components/wolfssl\n" + "in project directory: \n" + "${CMAKE_HOME_DIRECTORY}") + message(FATAL_ERROR "\nPlease use either the ESP Registry Managed Component or the wolfSSL component directory but not both.\n" + "If removing the ./managed_components/wolfssl__wolfssl directory, remember to also remove " + "or rename the idf_component.yml file typically found in ./main/") +else() + message(STATUS "No conflicting wolfSSL components found.") +endif() + + +# Don't include lwip requirement for benchmark and test apps. +if( ("${CMAKE_PROJECT_NAME}" STREQUAL "wolfssl_benchmark") OR ("${CMAKE_PROJECT_NAME}" STREQUAL "wolfssl_test") ) + message(STATUS "Not including lwip for ${CMAKE_PROJECT_NAME}") +else() + # benchmark and test do not need wifi, everything else probably does: + set(COMPONENT_REQUIRES lwip) # we typically don't need lwip directly in wolfssl component +endif() + +# find the user name to search for possible "wolfssl-username" +message(STATUS "USERNAME = $ENV{USERNAME}") +if( "$ENV{USER}" STREQUAL "" ) # the bash user + if( "$ENV{USERNAME}" STREQUAL "" ) # the Windows user + message(STATUS "could not find USER or USERNAME") + else() + # the bash user is not blank, so we'll use it. + set(THIS_USER "$ENV{USERNAME}") + endif() +else() + # the bash user is not blank, so we'll use it. + set(THIS_USER "$ENV{USER}") +endif() +message(STATUS "THIS_USER = ${THIS_USER}") + + +# COMPONENT_NAME = wolfssl +# The component name is the directory name. "No feature to change this". +# See https://github.com/espressif/esp-idf/issues/8978#issuecomment-1129892685 + +# set the root of wolfSSL in top-level project CMakelists.txt: +# set(WOLFSSL_ROOT "C:/some path/with/spaces") +# set(WOLFSSL_ROOT "c:/workspace/wolfssl-[username]") +# set(WOLFSSL_ROOT "/mnt/c/some path/with/spaces") +# or use this logic to assign value from Environment Variable WOLFSSL_ROOT, +# or assume this is an example 7 subdirectories below: + +# We are typically in [root]/IDE/Espressif/ESP-IDF/examples/wolfssl_test/components/wolfssl +# The root of wolfSSL is 7 directories up from here: + +# function: IS_WOLFSSL_SOURCE +# parameter: DIRECTORY_PARAMETER - the directory to test +# output: RESULT = contains contents of DIRECTORY_PARAMETER for wolfssl directory, otherwise blank. +function(IS_WOLFSSL_SOURCE DIRECTORY_PARAMETER RESULT) + if (EXISTS "${DIRECTORY_PARAMETER}/wolfcrypt/src") + set(${RESULT} "${DIRECTORY_PARAMETER}" PARENT_SCOPE) + else() + set(${RESULT} "" PARENT_SCOPE) + endif() +endfunction() + +# ********************************************************************************************* +# function: FIND_WOLFSSL_DIRECTORY +# parameter: OUTPUT_FOUND_WOLFSSL_DIRECTORY contains root of source code, otherwise blank +# +# Example usage: +# FIND_WOLFSSL_DIRECTORY(WOLFSSL_ROOT) +# ********************************************************************************************* +function(FIND_WOLFSSL_DIRECTORY OUTPUT_FOUND_WOLFSSL_DIRECTORY) + message(STATUS "Starting FIND_WOLFSSL_DIRECTORY: ${${OUTPUT_FOUND_WOLFSSL_DIRECTORY}}") + + if ( "${${OUTPUT_FOUND_WOLFSSL_DIRECTORY}}" STREQUAL "" ) + set(CURRENT_SEARCH_DIR "$ENV{WOLFSSL_ROOT}") + if( "${CURRENT_SEARCH_DIR}" STREQUAL "" ) + message(STATUS "The WOLFSSL_ROOT environment variable is not set. Searching...") + else() + get_filename_component(CURRENT_SEARCH_DIR "$ENV{WOLFSSL_ROOT}" ABSOLUTE) + IS_WOLFSSL_SOURCE("${CURRENT_SEARCH_DIR}" FOUND_WOLFSSL) + if( FOUND_WOLFSSL ) + message(STATUS "Found WOLFSSL_ROOT via Environment Variable:") + else() + message(FATAL_ERROR "WOLFSSL_ROOT Environment Variable defined, but path not found:") + message(STATUS "$ENV{WOLFSSL_ROOT}") + endif() + endif() + else() + get_filename_component(CURRENT_SEARCH_DIR "${${OUTPUT_FOUND_WOLFSSL_DIRECTORY}}" ABSOLUTE) + IS_WOLFSSL_SOURCE("${CURRENT_SEARCH_DIR}" FOUND_WOLFSSL) + if( FOUND_WOLFSSL ) + message(STATUS "Found WOLFSSL_ROOT via prior specification.") + else() + message(FATAL_ERROR "WOLFSSL_ROOT Variable defined, but path not found: ${${OUTPUT_FOUND_WOLFSSL_DIRECTORY}}") + endif() + endif() + + + # we'll start in the CMAKE_CURRENT_SOURCE_DIR, typically [something]/projectname/components/wolfssl + message(STATUS "CMAKE_CURRENT_SOURCE_DIR = ${CMAKE_CURRENT_SOURCE_DIR}") + get_filename_component(CURRENT_SEARCH_DIR "${CMAKE_CURRENT_SOURCE_DIR}" ABSOLUTE) + message(STATUS "CURRENT_SEARCH_DIR = ${CURRENT_SEARCH_DIR}") + string(LENGTH ${CURRENT_SEARCH_DIR} CURRENT_SEARCH_DIR_LENGTH) + + # loop through all the parents, looking for wolfssl + while(NOT CURRENT_SEARCH_DIR STREQUAL "/" AND NOT CURRENT_SEARCH_DIR STREQUAL "" ) + string(LENGTH ${CURRENT_SEARCH_DIR} CURRENT_SEARCH_DIR_LENGTH) + # wolfSSL may simply be in a parent directory, such as for local examples in wolfssl repo + IS_WOLFSSL_SOURCE("${CURRENT_SEARCH_DIR}" FOUND_WOLFSSL) + if( FOUND_WOLFSSL ) + message(STATUS "Found wolfssl in CURRENT_SEARCH_DIR = ${CURRENT_SEARCH_DIR}") + set(${OUTPUT_FOUND_WOLFSSL_DIRECTORY} ${CURRENT_SEARCH_DIR} PARENT_SCOPE) + return() + endif() + + 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}") + + #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) + return() + endif() + endif() + + # Next check for no user suffix "wolfssl" subdirectory as we recurse up the directory tree + set(CURRENT_SEARCH_DIR_ALT ${CURRENT_SEARCH_DIR}/wolfssl) + # if(EXISTS ${CURRENT_SEARCH_DIR} AND IS_DIRECTORY ${CURRENT_SEARCH_DIR} AND EXISTS "${CURRENT_SEARCH_DIR}/wolfcrypt/src") + IS_WOLFSSL_SOURCE("${CURRENT_SEARCH_DIR_ALT}" FOUND_WOLFSSL ) + if ( FOUND_WOLFSSL ) + message(STATUS "Found wolfssl in CURRENT_SEARCH_DIR = ${CURRENT_SEARCH_DIR}") + set(${OUTPUT_FOUND_WOLFSSL_DIRECTORY} ${CURRENT_SEARCH_DIR} PARENT_SCOPE) + return() + endif() + + # Move up one directory level + set(PRIOR_SEARCH_DIR "${CURRENT_SEARCH_DIR}") + 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 + set(CURRENT_SEARCH_DIR "") + endif() + endwhile() + + # If not found, set the output variable to empty before exiting + set(${OUTPUT_FOUND_WOLFSSL_DIRECTORY} "" PARENT_SCOPE) +endfunction() + + +# Example usage: +# +# Simply find the WOLFSSL_DIRECTORY by searching parent directories: +# FIND_WOLFSSL_DIRECTORY(WOLFSSL_ROOT) +# + +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 + ) + +else() + # not CMAKE_BUILD_EARLY_EXPANSION + message(STATUS "************************************************************************************************") + 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 + + if(WOLFSSL_ROOT) + IS_WOLFSSL_SOURCE("${WOLFSSL_ROOT}" FOUND_WOLFSSL) + if(FOUND_WOLFSSL) + message(STATUS "Found WOLFSSL_ROOT via CMake specification.") + else() + # WOLFSSL_ROOT Path specified in CMakeLists.txt is not a valid path + message(FATAL_ERROR "WOLFSSL_ROOT CMake Variable defined, but path not found: ${WOLFSSL_ROOT}\n" + "Try correcting WOLFSSL_ROOT in your project CMakeFile.txt or setting environment variable.") + # Abort CMake after fatal error. + endif() + else() + message(STATUS "Searching for wolfSL source code...") + FIND_WOLFSSL_DIRECTORY(WOLFSSL_ROOT) + endif() + + + if(WOLFSSL_ROOT) + message(STATUS "Confirmed wolfssl directory at: ${WOLFSSL_ROOT}") + 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.") + # Abort CMake after fatal error. + endif() + + set(INCLUDE_PATH ${WOLFSSL_ROOT}) + + set(WOLFSSL_EXTRA_PROJECT_DIR "${WOLFSSL_ROOT}/src/") + + # During regression tests, optionally copy source locally and use: set(USE_LOCAL_TEST_BENCH 1) + set(USE_LOCAL_TEST_BENCH 0) + if(NOT USE_LOCAL_TEST_BENCH) + if( "${CMAKE_PROJECT_NAME}" STREQUAL "hello-world" ) + message(STATUS "Include ${WOLFSSL_ROOT}/wolfcrypt/benchmark") + set(WOLFSSL_EXTRA_PROJECT_DIR "${WOLFSSL_ROOT}/wolfcrypt/benchmark") + endif() + + if( "${CMAKE_PROJECT_NAME}" STREQUAL "wolfssl_benchmark" ) + message(STATUS "Include ${WOLFSSL_ROOT}/wolfcrypt/benchmark") + set(WOLFSSL_EXTRA_PROJECT_DIR "${WOLFSSL_ROOT}/wolfcrypt/benchmark") + endif() + + if( "${CMAKE_PROJECT_NAME}" STREQUAL "wolfssl_test" ) + message(STATUS "Include ${WOLFSSL_ROOT}/wolfcrypt/test") + set(WOLFSSL_EXTRA_PROJECT_DIR "${WOLFSSL_ROOT}/wolfcrypt/test") + endif() + endif() + + set(COMPONENT_SRCDIRS "\"${WOLFSSL_ROOT}/src/\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/port/Espressif\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/port/atmel\"" + "\"${WOLFSSL_EXTRA_PROJECT_DIR}\"" + ) # COMPONENT_SRCDIRS + + message(STATUS "This COMPONENT_SRCDIRS = ${COMPONENT_SRCDIRS}") + + # wolfSSL user_settings.h is in the local project. + set(WOLFSSL_PROJECT_DIR "${CMAKE_HOME_DIRECTORY}/components/wolfssl") + + string(REPLACE "/" "//" STR_WOLFSSL_PROJECT_DIR "${WOLFSSL_PROJECT_DIR}") + add_definitions(-DWOLFSSL_USER_SETTINGS_DIR="${STR_WOLFSSL_PROJECT_DIR}//include//user_settings.h") + + # Espressif may take several passes through this makefile. Check to see if we found IDF + string(COMPARE EQUAL "${PROJECT_SOURCE_DIR}" "" WOLFSSL_FOUND_IDF) + + # get a list of all wolfcrypt assembly files; we'll exclude them as they don't target Xtensa + file(GLOB EXCLUDE_ASM *.S) + file(GLOB EXCLUDE_ASM ${CMAKE_SOURCE_DIR} "${WOLFSSL_ROOT}/wolfcrypt/src/*.S") + + message(STATUS "IDF_PATH = $ENV{IDF_PATH}") + message(STATUS "PROJECT_SOURCE_DIR = ${PROJECT_SOURCE_DIR}") + message(STATUS "EXCLUDE_ASM = ${EXCLUDE_ASM}") + + # + # Check to see if there's both a local copy and EDP-IDF copy of the wolfssl and/or wolfssh components. + # + if( EXISTS "${WOLFSSL_PROJECT_DIR}" AND EXISTS "$ENV{IDF_PATH}/components/wolfssl/" ) + # + # wolfSSL found in both ESP-IDF and local project - needs to be resolved by user + # + message(STATUS "") + message(STATUS "**************************************************************************************") + message(STATUS "") + message(STATUS "Error: Found components/wolfssl in both local project and IDF_PATH") + message(STATUS "") + message(STATUS "To proceed: ") + message(STATUS "") + message(STATUS "Remove either the local project component: ${WOLFSSL_PROJECT_DIR} ") + message(STATUS "or the Espressif shared component installed at: $ENV{IDF_PATH}/components/wolfssl/ ") + message(STATUS "") + message(STATUS "") + message(STATUS "**************************************************************************************") + message(STATUS "") + + message(FATAL_ERROR "Please use wolfSSL in either local project or Espressif components, but not both.") + # Abort CMake after fatal error. + + # Optional: if you change the above FATAL_ERROR to STATUS you can warn at runtime with this macro definition: + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_MULTI_INSTALL_WARNING") + + else() + if( EXISTS "$ENV{IDF_PATH}/components/wolfssl/" ) + # + # wolfSSL found in ESP-IDF components and is assumed to be already configured in user_settings.h via setup. + # + message(STATUS "") + message(STATUS "Using components/wolfssl in IDF_PATH = $ENV{IDF_PATH}") + message(STATUS "") + else() + # + # wolfSSL is not an ESP-IDF component. + # We need to now determine if it is local and if so if it is part of the wolfSSL repo, + # or if wolfSSL is simply installed as a local component. + # + + if( EXISTS "${WOLFSSL_PROJECT_DIR}" ) + # + # wolfSSL found in local project. + # + if( EXISTS "${WOLFSSL_PROJECT_DIR}/wolfcrypt/" ) + message(STATUS "") + message(STATUS "Using installed project ./components/wolfssl in CMAKE_HOME_DIRECTORY = ${CMAKE_HOME_DIRECTORY}") + message(STATUS "") + # + # Note we already checked above and confirmed there's not another wolfSSL installed in the ESP-IDF components. + # + # We won't do anything else here, as it will be assumed the original install completed successfully. + # + else() # full wolfSSL not installed in local project + # + # This is the developer repo mode. wolfSSL will be assumed to be not installed to ESP-IDF nor local project + # In this configuration, we are likely running a wolfSSL example found directly in the repo. + # + message(STATUS "") + message(STATUS "Using developer repo ./components/wolfssl in CMAKE_HOME_DIRECTORY = ${CMAKE_HOME_DIRECTORY}") + message(STATUS "") + + message(STATUS "************************************************************************************************") + # When in developer mode, we are typically running wolfSSL examples such as benchmark or test directories. + # However, the as-cloned or distributed wolfSSL does not have the ./include/ directory, so we'll add it as needed. + # + # first check if there's a [root]/include/user_settings.h + if( EXISTS "${WOLFSSL_ROOT}/include/user_settings.h" ) + message(FATAL_ERROR "Found stray wolfSSL user_settings.h in " + "${WOLFSSL_ROOT}/include/user_settings.h " + " (please move it to ${WOLFSSL_PROJECT_DIR}/include/user_settings.h )") + # Abort CMake after fatal error. + else() + # we won't overwrite an existing user settings file, just note that we already have one: + if( EXISTS "${WOLFSSL_PROJECT_DIR}/include/user_settings.h" ) + message(STATUS "Using existing wolfSSL user_settings.h in " + "${WOLFSSL_PROJECT_DIR}/include/user_settings.h") + else() + message(STATUS "Installing wolfSSL user_settings.h to " + "${WOLFSSL_PROJECT_DIR}/include/user_settings.h") + file(COPY "${WOLFSSL_ROOT}/IDE/Espressif/ESP-IDF/user_settings.h" + DESTINATION "${CMAKE_HOME_DIRECTORY}/wolfssl/include/") + endif() + endif() # user_settings.h + + # next check if there's a [root]/include/config.h + if( EXISTS "${WOLFSSL_ROOT}/include/config.h" ) + message(STATUS "******************************************************************************") + message(STATUS "******************************************************************************") + message(STATUS "Found stray wolfSSL config.h in ${WOLFSSL_ROOT}/include/config.h" ) + message(STATUS " Please move it to ${WOLFSSL_PROJECT_DIR}/include/config.h" ) + message(STATUS "******************************************************************************") + message(STATUS "******************************************************************************") + else() + # we won't overwrite an existing user settings file, just note that we already have one: + if( EXISTS "${WOLFSSL_PROJECT_DIR}/include/config.h" ) + message(STATUS "Using existing wolfSSL config.h ${WOLFSSL_PROJECT_DIR}/include/config.h") + else() + message(STATUS "Installing wolfSSL config.h to ${WOLFSSL_PROJECT_DIR}/include/config.h") + file(COPY "${WOLFSSL_ROOT}/IDE/Espressif/ESP-IDF/dummy_config_h" DESTINATION "${WOLFSSL_PROJECT_DIR}/include/") + file(RENAME "${WOLFSSL_PROJECT_DIR}/include/dummy_config_h" "${WOLFSSL_PROJECT_DIR}/include/config.h") + endif() # Project config.h + endif() # WOLFSSL_ROOT config.h + message(STATUS "************************************************************************************************") + message(STATUS "") + endif() + + else() + # we did not find a ./components/wolfssl/include/ directory from this pass of cmake. + if($WOLFSSL_FOUND_IDF) + message(STATUS "") + message(STATUS "WARNING: wolfSSL not found.") + message(STATUS "") + else() + # probably needs to be re-parsed by Espressif + message(STATUS "wolfSSL found IDF. Project Source:${PROJECT_SOURCE_DIR}") + endif() # else we have not found ESP-IDF yet + endif() # else not a local wolfSSL component + + endif() #else not an ESP-IDF component + endif() # else not local copy and EDP-IDF wolfSSL + + + # RTOS_IDF_PATH is typically: + # "/Users/{username}/Desktop/esp-idf/components/freertos/include/freertos" + # depending on the environment, we may need to swap backslashes with forward slashes + string(REPLACE "\\" "/" RTOS_IDF_PATH "$ENV{IDF_PATH}/components/freertos/FreeRTOS-Kernel/include/freertos") + + string(REPLACE "\\" "/" WOLFSSL_ROOT ${WOLFSSL_ROOT}) + + if(IS_DIRECTORY "${RTOS_IDF_PATH}") + message(STATUS "Found current RTOS path: ${RTOS_IDF_PATH}") + else() + # ESP-IDF prior version 4.4x has a different RTOS directory structure + string(REPLACE "\\" "/" RTOS_IDF_PATH "$ENV{IDF_PATH}/components/freertos/include/freertos") + if(IS_DIRECTORY "${RTOS_IDF_PATH}") + message(STATUS "Found legacy RTOS path: ${RTOS_IDF_PATH}") + else() + message(STATUS "Could not find RTOS path") + endif() + endif() + + # wolfSSL-specific include directories + set(COMPONENT_ADD_INCLUDEDIRS + "./include" # this is the location of local project wolfssl user_settings.h + "\"${WOLFSSL_ROOT}/\"" + "\"${WOLFSSL_ROOT}/wolfssl/\"" + "\"${WOLFSSL_ROOT}/wolfssl/wolfcrypt/\"" + "\"${WOLFSSL_ROOT}/wolfssl/wolfcrypt/port/Espressif\"" + "\"${RTOS_IDF_PATH}/\"" + ) + + # Optionally include cryptoauthlib if present + if(IS_DIRECTORY ${IDF_PATH}/components/cryptoauthlib) + list(APPEND COMPONENT_ADD_INCLUDEDIRS "../cryptoauthlib/lib") + endif() + + list(APPEND COMPONENT_ADD_INCLUDEDIRS "\"${WOLFSSL_ROOT}/wolfssl/\"") + list(APPEND COMPONENT_ADD_INCLUDEDIRS "\"${WOLFSSL_ROOT}/wolfssl/wolfcrypt/\"") + + + # Some files are known to be included elsewhere, or not used for Espressif + set(COMPONENT_SRCEXCLUDE + "\"${WOLFSSL_ROOT}/src/bio.c\"" + "\"${WOLFSSL_ROOT}/src/conf.c\"" + "\"${WOLFSSL_ROOT}/src/misc.c\"" + "\"${WOLFSSL_ROOT}/src/pk.c\"" + "\"${WOLFSSL_ROOT}/src/ssl_asn1.c\"" # included by ssl.c + "\"${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_misc.c\"" # included by ssl.c + "\"${WOLFSSL_ROOT}/src/x509.c\"" + "\"${WOLFSSL_ROOT}/src/x509_str.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/evp.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/misc.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_arm32.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_arm64.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_armthumb.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_c32.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_c64.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_cortexm.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_x86_64.c\"" + "\"${WOLFSSL_ROOT}/wolfcrypt/src/sp_sm2_x86_64_asm.S\"" + "\"${EXCLUDE_ASM}\"" + ) + + spaces2list(COMPONENT_REQUIRES) + + separate_arguments(COMPONENT_SRCDIRS NATIVE_COMMAND "${COMPONENT_SRCDIRS}") + separate_arguments(COMPONENT_SRCEXCLUDE NATIVE_COMMAND "${COMPONENT_SRCEXCLUDE}") + separate_arguments(COMPONENT_ADD_INCLUDEDIRS NATIVE_COMMAND "${COMPONENT_ADD_INCLUDEDIRS}") + + # + # See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html#example-component-requirements + # + message(STATUS "COMPONENT_SRCDIRS = ${COMPONENT_SRCDIRS}") + message(STATUS "COMPONENT_ADD_INCLUDEDIRS = ${COMPONENT_ADD_INCLUDEDIRS}") + message(STATUS "COMPONENT_REQUIRES = ${COMPONENT_REQUIRES}") + message(STATUS "COMPONENT_SRCEXCLUDE = ${COMPONENT_SRCEXCLUDE}") + + # + # see https://docs.espressif.com/projects/esp-idf/en/stable/esp32/migration-guides/release-5.x/build-system.html?highlight=space%20path + # + set(EXTRA_COMPONENT_DIRS "${COMPONENT_SRCDIRS}") + idf_component_register( + SRC_DIRS "${COMPONENT_SRCDIRS}" + INCLUDE_DIRS "${COMPONENT_ADD_INCLUDEDIRS}" + REQUIRES "${COMPONENT_REQUIRES}" + EXCLUDE_SRCS "${COMPONENT_SRCEXCLUDE}" + PRIV_REQUIRES + "${THIS_INCLUDE_TIMER}" + "${THIS_INCLUDE_DRIVER}" # this will typically only be needed for wolfSSL benchmark + ) + + # Some optional diagnostics. Verbose ones are truncated. + if (VERBOSE_COMPONENT_MESSAGES) + get_cmake_property(_variableNames VARIABLES) + list (SORT _variableNames) + message(STATUS "") + message(STATUS "ALL VARIABLES BEGIN") + message(STATUS "") + foreach (_variableName ${_variableNames}) + if ( ("${_variableName}" STREQUAL "bootloader_binary_files") + OR ("${_variableName}" STREQUAL "Component paths") + OR ("${_variableName}" STREQUAL "component_targets") + OR ("${_variableName}" STREQUAL "__COMPONENT_TARGETS") + OR ("${_variableName}" STREQUAL "CONFIGS_LIST") + OR ("${_variableName}" STREQUAL "__CONFIG_VARIABLES") + OR ("${_variableName}" STREQUAL "val") + OR ("${_variableName}" MATCHES "^__idf_") + ) + # Truncate the displayed value: + string(SUBSTRING "${${_variableName}}" 0 70 truncatedValue) + message(STATUS "${_variableName} = ${truncatedValue} ... (truncated)") + else() + message(STATUS "${_variableName}=${${_variableName}}") + endif() + endforeach() + message(STATUS "") + message(STATUS "ALL VARIABLES END") + message(STATUS "") + endif() + + # target_sources(wolfssl PRIVATE "\"${WOLFSSL_ROOT}/wolfssl/\"" "\"${WOLFSSL_ROOT}/wolfssl/wolfcrypt\"") + +endif() # CMAKE_BUILD_EARLY_EXPANSION + + + +# check to see if there's both a local copy and EDP-IDF copy of the wolfssl components +if( EXISTS "${WOLFSSL_PROJECT_DIR}" AND EXISTS "$ENV{IDF_PATH}/components/wolfssl/" ) + message(STATUS "") + message(STATUS "") + message(STATUS "********************************************************************") + message(STATUS "WARNING: Found components/wolfssl in both local project and IDF_PATH") + message(STATUS "********************************************************************") + message(STATUS "") +endif() +# end multiple component check + + +# +# LIBWOLFSSL_SAVE_INFO(VAR_OUPUT THIS_VAR VAR_RESULT) +# +# Save the THIS_VAR as a string in a macro called VAR_OUPUT +# +# VAR_OUPUT: the name of the macro to define +# THIS_VAR: the OUTPUT_VARIABLE result from a execute_process() +# VAR_RESULT: the RESULT_VARIABLE from a execute_process(); "0" if successful. +# +function ( LIBWOLFSSL_SAVE_INFO VAR_OUPUT THIS_VAR VAR_RESULT ) + # is the RESULT_VARIABLE output value 0? If so, IS_VALID_VALUE is true. + string(COMPARE EQUAL "${VAR_RESULT}" "0" IS_VALID_VALUE) + + # if we had a successful operation, save the THIS_VAR in VAR_OUPUT + if(${IS_VALID_VALUE}) + # strip newline chars in THIS_VAR parameter and save in VAR_VALUE + string(REPLACE "\n" "" VAR_VALUE ${THIS_VAR}) + + # we'll could percolate the value to the parent for possible later use + # set(${VAR_OUPUT} ${VAR_VALUE} PARENT_SCOPE) + + # but we're only using it here in this function + set(${VAR_OUPUT} ${VAR_VALUE}) + + # we'll print what we found to the console + message(STATUS "Found ${VAR_OUPUT}=${VAR_VALUE}") + + # the interesting part is defining the VAR_OUPUT name a value to use in the app + add_definitions(-D${VAR_OUPUT}=\"${VAR_VALUE}\") + else() + # if we get here, check the execute_process command and parameters. + message(STATUS "LIBWOLFSSL_SAVE_INFO encountered a non-zero VAR_RESULT") + set(${VAR_OUPUT} "Unknown") + endif() +endfunction() # LIBWOLFSSL_SAVE_INFO + +# create some programmatic #define values that will be used by ShowExtendedSystemInfo(). +# see wolfcrypt\src\port\Espressif\esp32_utl.c +if(NOT CMAKE_BUILD_EARLY_EXPANSION) + set (git_cmd "git") + message(STATUS "Adding macro definitions:") + + # LIBWOLFSSL_VERSION_GIT_ORIGIN: git config --get remote.origin.url + execute_process(WORKING_DIRECTORY ${WOLFSSL_ROOT} COMMAND ${git_cmd} "config" "--get" "remote.origin.url" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_GIT_ORIGIN "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSL_VERSION_GIT_BRANCH: git rev-parse --abbrev-ref HEAD + execute_process(WORKING_DIRECTORY ${WOLFSSL_ROOT} COMMAND ${git_cmd} "rev-parse" "--abbrev-ref" "HEAD" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_GIT_BRANCH "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSL_VERSION_GIT_HASH: git rev-parse HEAD + execute_process(WORKING_DIRECTORY ${WOLFSSL_ROOT} COMMAND ${git_cmd} "rev-parse" "HEAD" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_GIT_HASH "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSL_VERSION_GIT_SHORT_HASH: git rev-parse --short HEAD + execute_process(WORKING_DIRECTORY ${WOLFSSL_ROOT} COMMAND ${git_cmd} "rev-parse" "--short" "HEAD" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_GIT_SHORT_HASH "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSL_VERSION_GIT_HASH_DATE git show --no-patch --no-notes --pretty=\'\%cd\' + execute_process(WORKING_DIRECTORY ${WOLFSSL_ROOT} COMMAND ${git_cmd} "show" "--no-patch" "--no-notes" "--pretty=\'\%cd\'" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ) + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_GIT_HASH_DATE "${TMP_OUT}" "${TMP_RES}") + + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_WOLFSSL_ROOT "${WOLFSSL_ROOT}" "${TMP_RES}") + + message(STATUS "************************************************************************************************") + message(STATUS "wolfssl component config complete!") + message(STATUS "************************************************************************************************") +endif() diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssl/README.md b/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssl/README.md new file mode 100644 index 000000000..040c8c0ba --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssl/README.md @@ -0,0 +1,9 @@ +# Component wolfSSL + +This `wolfssl` directory exists only for the stand-alone examples. + +The only files of interest are the [CMakeLists.txt](./CMakeLists.txt) that should point +to the wolfSSL source code and the respective [include/user_settings.h](./include/user_settings.h). + +This directory is _not_ included in the publish to the Espressif Registry, as that +mechanism copies the published source code to the local component directory as needed. 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 new file mode 100644 index 000000000..41f588a01 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/components/wolfssl/include/user_settings.h @@ -0,0 +1,508 @@ +/* user_settings.h + * + * Copyright (C) 2006-2023 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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 + * (at your option) any later version. + * + * wolfSSL 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 + */ + +#include /* essential to chip set detection */ + +#undef WOLFSSL_ESPIDF +#undef WOLFSSL_ESP32 +#undef WOLFSSL_ESPWROOM32SE +#undef WOLFSSL_ESP32 +#undef WOLFSSL_ESP8266 + +#define WOLFSSL_ESPIDF + +/* The Espressif sdkconfig will have chipset info. +** +** Possible values: +** +** CONFIG_IDF_TARGET_ESP32 +** CONFIG_IDF_TARGET_ESP32S2 +** CONFIG_IDF_TARGET_ESP32S3 +** CONFIG_IDF_TARGET_ESP32C3 +** CONFIG_IDF_TARGET_ESP32C6 +*/ + +/* Optionally enable some wolfSSH settings */ +#ifdef ESP_ENABLE_WOLFSSH + /* The default SSH Windows size is massive for an embedded target. Limit it: */ + #define DEFAULT_WINDOW_SZ 2000 + + /* These may be defined in cmake for other examples: */ + #undef WOLFSSH_TERM + #define WOLFSSH_TERM + + #undef DEBUG_WOLFSSH + #define DEBUG_WOLFSSH + + #undef WOLFSSL_KEY_GEN + #define WOLFSSL_KEY_GEN + + #undef WOLFSSL_PTHREADS + #define WOLFSSL_PTHREADS + + #define WOLFSSH_TEST_SERVER + #define WOLFSSH_TEST_THREADING + +#endif /* ESP_ENABLE_WOLFSSH */ + +/* when you want to use SINGLE THREAD */ +/* #define SINGLE_THREADED */ + +/* + * choose ONE of these Espressif chips to define: + * + * WOLFSSL_ESP32 + * WOLFSSL_ESPWROOM32SE + * WOLFSSL_ESP8266 + */ + +#define WOLFSSL_ESP32 + +/* optionally turn off SHA512/224 SHA512/256 */ +/* #define WOLFSSL_NOSHA512_224 */ +/* #define WOLFSSL_NOSHA512_256 */ + +/* when you want to use SINGLE THREAD. Note Default ESP-IDF is FreeRTOS */ +/* #define SINGLE_THREADED */ + +/* When you don't want to use the old SHA */ +/* #define NO_SHA */ +/* #define NO_OLD_TLS */ + +#define BENCH_EMBEDDED +#define USE_CERT_BUFFERS_2048 + +#define NO_OLD_TLS +/* TLS 1.3 + #define WOLFSSL_TLS13 + #define HAVE_TLS_EXTENSIONS + #define WC_RSA_PSS + #define HAVE_SUPPORTED_CURVES +*/ + +#define HAVE_HKDF +#define HAVE_AEAD + +#define NO_FILESYSTEM + +#define HAVE_AESGCM + +#define WOLFSSL_RIPEMD +/* when you want to use SHA224 */ +/* #define WOLFSSL_SHA224 */ + + +/* when you want to use SHA384 */ +/* #define WOLFSSL_SHA384 */ + +/* #define WOLFSSL_SHA3 */ + +#define WOLFSSL_SHA512 + +#define MY_USE_ECC 1 +#define MY_USE_RSA 0 + +/* We can use either or both ECC and RSA, but must use at least one. */ +#if MY_USE_ECC || MY_USE_RSA + #if MY_USE_ECC + /* ---- ECDSA / ECC ---- */ + #define HAVE_ECC + #define HAVE_CURVE25519 + #define HAVE_ED25519 + + /* + #define HAVE_ECC384 + #define CURVE25519_SMALL + */ + #else + #define WOLFSSH_NO_ECC + /* WOLFSSH_NO_ECDSA is typically defined automatically, + * here for clarity: */ + #define WOLFSSH_NO_ECDSA + #endif + + #if MY_USE_RSA + /* ---- RSA ----- */ + /* #define RSA_LOW_MEM */ + + /* DH disabled by default, needed if ECDSA/ECC also turned off */ + #define HAVE_DH + #else + #define WOLFSSH_NO_RSA + #endif +#else + #error "Either RSA or ECC must be enabled" +#endif + + +/* when you want to use pkcs7 */ +/* #define HAVE_PKCS7 */ + +#if defined(HAVE_PKCS7) + #define HAVE_AES_KEYWRAP + #define HAVE_X963_KDF + #define WOLFSSL_AES_DIRECT +#endif + +/* when you want to use aes counter mode */ +/* #define WOLFSSL_AES_DIRECT */ +/* #define WOLFSSL_AES_COUNTER */ + +/* debug options */ +/* #define DEBUG_WOLFSSL */ +/* #define WOLFSSL_ESP32_CRYPT_DEBUG */ +/* #define WOLFSSL_ATECC508A_DEBUG */ + +/* date/time */ +/* if it cannot adjust time in the device, */ +/* enable macro below */ +/* #define NO_ASN_TIME */ +/* #define XTIME time */ + +/* adjust wait-timeout count if you see timeout in RSA HW acceleration */ +#define ESP_RSA_TIMEOUT_CNT 0x249F00 + + +/* USE_FAST_MATH is default */ +#define USE_FAST_MATH + +/***** Use SP_MATH *****/ +/* #undef USE_FAST_MATH */ +/* #define SP_MATH */ +/* #define WOLFSSL_SP_MATH_ALL */ +/* #define WOLFSSL_SP_RISCV32 */ + +/***** Use Integer Heap Math *****/ +/* #undef USE_FAST_MATH */ +/* #define USE_INTEGER_HEAP_MATH */ + + +#define WOLFSSL_SMALL_STACK + +/* The ESP32 has some detailed statup information available:*/ +#define HAVE_VERSION_EXTENDED_INFO + +/* optional SM4 Ciphers. See https://github.com/wolfSSL/wolfsm */ +/* +#define WOLFSSL_SM2 +#define WOLFSSL_SM3 +#define WOLFSSL_SM4 +*/ + +#if defined(WOLFSSL_SM2) || defined(WOLFSSL_SM3) || defined(WOLFSSL_SM4) + /* SM settings, possible cipher suites: + + TLS13-AES128-GCM-SHA256 + TLS13-CHACHA20-POLY1305-SHA256 + TLS13-SM4-GCM-SM3 + TLS13-SM4-CCM-SM3 + + #define WOLFSSL_ESP32_CIPHER_SUITE "TLS13-SM4-GCM-SM3" + #define WOLFSSL_ESP32_CIPHER_SUITE "TLS13-SM4-CCM-SM3" + #define WOLFSSL_ESP32_CIPHER_SUITE "ECDHE-ECDSA-SM4-CBC-SM3" + #define WOLFSSL_ESP32_CIPHER_SUITE "ECDHE-ECDSA-SM4-GCM-SM3" + #define WOLFSSL_ESP32_CIPHER_SUITE "ECDHE-ECDSA-SM4-CCM-SM3" + #define WOLFSSL_ESP32_CIPHER_SUITE "TLS13-SM4-GCM-SM3:" \ + "TLS13-SM4-CCM-SM3:" + */ + + #undef WOLFSSL_BASE16 + #define WOLFSSL_BASE16 /* required for WOLFSSL_SM2 */ + + #undef WOLFSSL_SM4_ECB + #define WOLFSSL_SM4_ECB + + #undef WOLFSSL_SM4_CBC + #define WOLFSSL_SM4_CBC + + #undef WOLFSSL_SM4_CTR + #define WOLFSSL_SM4_CTR + + #undef WOLFSSL_SM4_GCM + #define WOLFSSL_SM4_GCM + + #undef WOLFSSL_SM4_CCM + #define WOLFSSL_SM4_CCM + + #define HAVE_POLY1305 + #define HAVE_CHACHA + + #undef HAVE_AESGCM + #define HAVE_AESGCM +#else + /* default settings */ + #define USE_CERT_BUFFERS_2048 +#endif + +/* esp32-wroom-32se specific definition */ +#if defined(WOLFSSL_ESPWROOM32SE) + #define WOLFSSL_ATECC508A + #define HAVE_PK_CALLBACKS + /* when you want to use a custom slot allocation for ATECC608A */ + /* unless your configuration is unusual, you can use default */ + /* implementation. */ + /* #define CUSTOM_SLOT_ALLOCATION */ +#endif + +/* Default is HW enabled unless turned off. +** Uncomment these lines to force SW instead of HW acceleration */ + +#if defined(CONFIG_IDF_TARGET_ESP32) || defined(WOLFSSL_ESPWROOM32SE) + /* wolfSSL HW Acceleration supported on ESP32. Uncomment to disable: */ + /* #define NO_ESP32_CRYPT */ + /* #define NO_WOLFSSL_ESP32_CRYPT_HASH */ + /* #define NO_WOLFSSL_ESP32_CRYPT_AES */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD */ + + /* These are defined automatically in esp32-crypt.h, here for clarity: */ + /* no SHA224 HW on ESP32 */ + #define NO_WOLFSSL_ESP32_CRYPT_HASH_SHA224 + + /* Define USE_FAST_MATH and SMALL_STACK */ + #define ESP32_USE_RSA_PRIMITIVE + + /* threshold for performance adjustment for HW primitive use */ + /* X bits of G^X mod P greater than */ + #define EPS_RSA_EXPT_XBTIS 32 + + /* X and Y of X * Y mod P greater than */ + #undef ESP_RSA_MULM_BITS + #define ESP_RSA_MULM_BITS 16 + + /***** END CONFIG_IDF_TARGET_ESP32 *****/ + +#elif defined(CONFIG_IDF_TARGET_ESP32S2) + /* wolfSSL HW Acceleration supported on ESP32-S2. Uncomment to disable: */ + /* #define NO_ESP32_CRYPT */ + /* #define NO_WOLFSSL_ESP32_CRYPT_HASH */ + /* Note: There's no AES192 HW on the ESP32-S2; falls back to SW */ + /* #define NO_WOLFSSL_ESP32_CRYPT_AES */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD */ + /***** END CONFIG_IDF_TARGET_ESP32S2 *****/ + +#elif defined(CONFIG_IDF_TARGET_ESP32S3) + /* wolfSSL HW Acceleration supported on ESP32-S3. Uncomment to disable: */ + /* #define NO_ESP32_CRYPT */ + /* #define NO_WOLFSSL_ESP32_CRYPT_HASH */ + /* Note: There's no AES192 HW on the ESP32-S3; falls back to SW */ + /* #define NO_WOLFSSL_ESP32_CRYPT_AES */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD */ + /***** END CONFIG_IDF_TARGET_ESP32S3 *****/ + +#elif defined(CONFIG_IDF_TARGET_ESP32C2) || \ + defined(CONFIG_IDF_TARGET_ESP8684) + /* ESP8684 is essentially ESP32-C2 chip + flash embedded together in a + * single QFN 4x4 mm package. Out of released documentation, Technical + * Reference Manual as well as ESP-IDF Programming Guide is applicable + * to both ESP32-C2 and ESP8684. + * + * See: https://www.esp32.com/viewtopic.php?f=5&t=27926#:~:text=ESP8684%20is%20essentially%20ESP32%2DC2,both%20ESP32%2DC2%20and%20ESP8684. */ + + /* wolfSSL HW Acceleration supported on ESP32-C2. Uncomment to disable: */ + /* #define NO_ESP32_CRYPT */ + /* #define NO_WOLFSSL_ESP32_CRYPT_HASH */ /* to disable all SHA HW */ + + /* These are defined automatically in esp32-crypt.h, here for clarity */ + #define NO_WOLFSSL_ESP32_CRYPT_HASH_SHA384 /* no SHA384 HW on C2 */ + #define NO_WOLFSSL_ESP32_CRYPT_HASH_SHA512 /* no SHA512 HW on C2 */ + + /* There's no AES or RSA/Math accelerator on the ESP32-C2 + * Auto defined with NO_WOLFSSL_ESP32_CRYPT_RSA_PRI, for clarity: */ + #define NO_WOLFSSL_ESP32_CRYPT_AES + #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI + #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL + #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD + #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD + /***** END CONFIG_IDF_TARGET_ESP32C2 *****/ + +#elif defined(CONFIG_IDF_TARGET_ESP32C3) + /* wolfSSL HW Acceleration supported on ESP32-C3. Uncomment to disable: */ + + /* #define NO_ESP32_CRYPT */ + /* #define NO_WOLFSSL_ESP32_CRYPT_HASH */ /* to disable all SHA HW */ + + /* These are defined automatically in esp32-crypt.h, here for clarity: */ + #define NO_WOLFSSL_ESP32_CRYPT_HASH_SHA384 /* no SHA384 HW on C6 */ + #define NO_WOLFSSL_ESP32_CRYPT_HASH_SHA512 /* no SHA512 HW on C6 */ + + /* #define NO_WOLFSSL_ESP32_CRYPT_AES */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD */ + /***** END CONFIG_IDF_TARGET_ESP32C3 *****/ + +#elif defined(CONFIG_IDF_TARGET_ESP32C6) + /* wolfSSL HW Acceleration supported on ESP32-C6. Uncomment to disable: */ + + /* #define NO_ESP32_CRYPT */ + /* #define NO_WOLFSSL_ESP32_CRYPT_HASH */ + /* These are defined automatically in esp32-crypt.h, here for clarity: */ + #define NO_WOLFSSL_ESP32_CRYPT_HASH_SHA384 /* no SHA384 HW on C6 */ + #define NO_WOLFSSL_ESP32_CRYPT_HASH_SHA512 /* no SHA512 HW on C6 */ + + /* #define NO_WOLFSSL_ESP32_CRYPT_AES */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD */ + /* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD */ + /***** END CONFIG_IDF_TARGET_ESP32C6 *****/ + +#elif defined(CONFIG_IDF_TARGET_ESP32H2) + /* wolfSSL Hardware Acceleration not yet implemented */ + #define NO_ESP32_CRYPT + #define NO_WOLFSSL_ESP32_CRYPT_HASH + #define NO_WOLFSSL_ESP32_CRYPT_AES + #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI + /***** END CONFIG_IDF_TARGET_ESP32H2 *****/ + +#elif defined(CONFIG_IDF_TARGET_ESP8266) + /* TODO: Revisit ESP8266 */ + #define NO_ESP32_CRYPT + #define NO_WOLFSSL_ESP32_CRYPT_HASH + #define NO_WOLFSSL_ESP32_CRYPT_AES + #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI + /***** END CONFIG_IDF_TARGET_ESP266 *****/ + +#elif defined(CONFIG_IDF_TARGET_ESP8684) + /* There's no Hardware Acceleration available on ESP8684 */ + #define NO_ESP32_CRYPT + #define NO_WOLFSSL_ESP32_CRYPT_HASH + #define NO_WOLFSSL_ESP32_CRYPT_AES + #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI + /***** END CONFIG_IDF_TARGET_ESP8684 *****/ + +#else + /* Anything else encountered, disable HW accleration */ + #define NO_ESP32_CRYPT + #define NO_WOLFSSL_ESP32_CRYPT_HASH + #define NO_WOLFSSL_ESP32_CRYPT_AES + #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI +#endif /* CONFIG_IDF_TARGET Check */ + +/* Debug options: + +#define ESP_VERIFY_MEMBLOCK +#define DEBUG_WOLFSSL +#define DEBUG_WOLFSSL_VERBOSE +#define DEBUG_WOLFSSL_SHA_MUTEX +#define WOLFSSL_ESP32_CRYPT_DEBUG +#define WOLFSSL_ESP32_CRYPT_HASH_SHA224_DEBUG +#define NO_RECOVER_SOFTWARE_CALC +#define WOLFSSL_TEST_STRAY 1 +#define USE_ESP_DPORT_ACCESS_READ_BUFFER +#define WOLFSSL_ESP32_HW_LOCK_DEBUG +#define WOLFSSL_DEBUG_ESP_RSA_MULM_BITS +#define ESP_DISABLE_HW_TASK_LOCK +*/ + +/* Pause in a loop rather than exit. */ +#define WOLFSSL_ESPIDF_ERROR_PAUSE + +/* #define WOLFSSL_HW_METRICS */ + +/* for test.c */ +/* #define HASH_SIZE_LIMIT */ + +/* Optionally turn off HW math checks */ +/* #define NO_HW_MATH_TEST */ + +/* Optionally include alternate HW test library: alt_hw_test.h */ +/* When enabling, the ./components/wolfssl/CMakeLists.txt file + * will need the name of the library in the idf_component_register + * for the PRIV_REQUIRES list. */ +/* #define INCLUDE_ALT_HW_TEST */ + +/* optionally turn off individual math HW acceleration features */ + +/* Turn off Large Number ESP32 HW Multiplication: +** [Z = X * Y] in esp_mp_mul() */ +/* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MP_MUL */ + +/* Turn off Large Number ESP32 HW Modular Exponentiation: +** [Z = X^Y mod M] in esp_mp_exptmod() */ +/* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_EXPTMOD */ + +/* Turn off Large Number ESP32 HW Modular Multiplication +** [Z = X * Y mod M] in esp_mp_mulmod() */ +/* #define NO_WOLFSSL_ESP32_CRYPT_RSA_PRI_MULMOD */ + +#define WOLFSSL_PUBLIC_MP /* used by benchmark */ +#define USE_CERT_BUFFERS_2048 + +/* when turning on ECC508 / ECC608 support +#define WOLFSSL_ESPWROOM32SE +#define HAVE_PK_CALLBACKS +#define WOLFSSL_ATECC508A +#define ATCA_WOLFSSL +*/ + +/* optional SM4 Ciphers. See https://github.com/wolfSSL/wolfsm +#define WOLFSSL_SM2 +#define WOLFSSL_SM3 +#define WOLFSSL_SM4 +*/ + +#if defined(WOLFSSL_SM2) || defined(WOLFSSL_SM3) || defined(WOLFSSL_SM4) + #include + #define CTX_CA_CERT root_sm2 + #define CTX_CA_CERT_SIZE sizeof_root_sm2 + #define CTX_CA_CERT_TYPE WOLFSSL_FILETYPE_PEM + #define CTX_SERVER_CERT server_sm2 + #define CTX_SERVER_CERT_SIZE sizeof_server_sm2 + #define CTX_SERVER_CERT_TYPE WOLFSSL_FILETYPE_PEM + #define CTX_SERVER_KEY server_sm2_priv + #define CTX_SERVER_KEY_SIZE sizeof_server_sm2_priv + #define CTX_SERVER_KEY_TYPE WOLFSSL_FILETYPE_PEM + + #undef WOLFSSL_BASE16 + #define WOLFSSL_BASE16 +#else + #define USE_CERT_BUFFERS_2048 + #define USE_CERT_BUFFERS_256 + #define CTX_CA_CERT ca_cert_der_2048 + #define CTX_CA_CERT_SIZE sizeof_ca_cert_der_2048 + #define CTX_CA_CERT_TYPE WOLFSSL_FILETYPE_ASN1 + #define CTX_SERVER_CERT server_cert_der_2048 + #define CTX_SERVER_CERT_SIZE sizeof_server_cert_der_2048 + #define CTX_SERVER_CERT_TYPE WOLFSSL_FILETYPE_ASN1 + #define CTX_SERVER_KEY server_key_der_2048 + #define CTX_SERVER_KEY_SIZE sizeof_server_key_der_2048 + #define CTX_SERVER_KEY_TYPE WOLFSSL_FILETYPE_ASN1 +#endif + +/* See settings.h for some of the possible hardening options: + * + * #define NO_ESPIDF_DEFAULT + * #define WC_NO_CACHE_RESISTANT + * #define WC_AES_BITSLICED + * #define HAVE_AES_ECB + * #define HAVE_AES_DIRECT + */ diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/CMakeLists.txt b/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/CMakeLists.txt new file mode 100644 index 000000000..9ae9d6bf7 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/CMakeLists.txt @@ -0,0 +1,154 @@ +# [wolfSSL Project]/main/CMakeLists.txt +# +# Copyright (C) 2006-2023 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 2 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 this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA +# +# cmake for WOLFSSH Espressif projects +# +# See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html +# wolfSSL wolfSSH Espressif Example Project/main/CMakeLists.txt +# v1.0 +# +message(STATUS "main cmake found WOLFSSL_COMPONENT_NAME = ${WOLFSSL_COMPONENT_NAME}") + +if(WIN32) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_WINDOWS") + message("Detected Windows") +endif() +if(CMAKE_HOST_UNIX) + message("Detected UNIX") +endif() +if(APPLE) + message("Detected APPLE") +endif() +if(CMAKE_HOST_UNIX AND (NOT APPLE) AND EXISTS "/proc/sys/fs/binfmt_misc/WSLInterop") + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_WSL") + message("Detected WSL") +endif() +if(CMAKE_HOST_UNIX AND (NOT APPLE) AND (NOT WIN32)) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_LINUX") + message("Detected Linux") +endif() +if(APPLE) + # Windows-specific configuration here + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_CMAKE_SYSTEM_NAME_APPLE") + message("Detected Apple") +endif() +set (git_cmd "git") + +if( EXISTS "${CMAKE_HOME_DIRECTORY}/components/wolfssl/" AND EXISTS "$ENV{IDF_PATH}/components/wolfssl/" ) + # + # wolfSSL found in both ESP-IDF and local project - needs to be resolved by user + # + message(STATUS "") + message(STATUS "WARNING: Found components/wolfssl in both local project and IDF_PATH") + message(STATUS "") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWOLFSSL_MULTI_INSTALL_WARNING") +endif() + +if( "$ENV{IDF_COMPONENT_REGISTRY_URL}" STREQUAL "https://components-staging.espressif.com" ) + if( ("${managed_components}" STREQUAL "") AND ("${component_manager_interface_version}" STREQUAL "") ) + # We've found a staging component, but did not detect the component manager + if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/../components/mywolfssh/CMakeLists.txt) + # This is typically during publish-time build test + message(STATUS "Set name mywolfssh (1)") + set(WOLFSSL_COMPONENT_NAME "mywolfssl") + set(WOLFSSH_COMPONENT_NAME "mywolfssh") + else() + if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/../managed_components/gojimmypi__mywolfmqtt/CMakeLists.txt) + # This is typically upon creating a project from managed component examples + message(STATUS "Set name mywolfssh (2)") + set(WOLFSSL_COMPONENT_NAME "mywolfssl") + set(WOLFSSH_COMPONENT_NAME "mywolfssh") + else() + message(STATUS "Set name wolfmqtt (1) CMAKE_CURRENT_LIST_DIR = ${CMAKE_CURRENT_LIST_DIR}") + set(WOLFSSL_COMPONENT_NAME "wolfssl") + set(WOLFSSH_COMPONENT_NAME "wolfssh") + endif() + endif() + else() + message(STATUS "Set name mywolfssh (3)") + set(WOLFSSL_COMPONENT_NAME "mywolfssl") + set(WOLFSSH_COMPONENT_NAME "mywolfssh") + endif() +else() + message(STATUS "Set name wolfssh (2)") + set(WOLFSSL_COMPONENT_NAME "wolfssl") + set(WOLFSSH_COMPONENT_NAME "wolfssh") +endif() + +## register_component() +idf_component_register(SRCS main.c + INCLUDE_DIRS "." "./include") +# + +# +# LIBWOLFSSL_SAVE_INFO(VAR_OUPUT THIS_VAR VAR_RESULT) +# +# Save the THIS_VAR as a string in a macro called VAR_OUPUT +# +# VAR_OUPUT: the name of the macro to define +# THIS_VAR: the OUTPUT_VARIABLE result from a execute_process() +# VAR_RESULT: the RESULT_VARIABLE from a execute_process(); "0" if successful. +# +function ( LIBWOLFSSL_SAVE_INFO VAR_OUPUT THIS_VAR VAR_RESULT ) + # is the RESULT_VARIABLE output value 0? If so, IS_VALID_VALUE is true. + string(COMPARE EQUAL "${VAR_RESULT}" "0" IS_VALID_VALUE) + + # if we had a successful operation, save the THIS_VAR in VAR_OUPUT + if(${IS_VALID_VALUE}) + # strip newline chars in THIS_VAR parameter and save in VAR_VALUE + string(REPLACE "\n" "" VAR_VALUE ${THIS_VAR}) + + # we'll could percolate the value to the parent for possible later use + # set(${VAR_OUPUT} ${VAR_VALUE} PARENT_SCOPE) + + # but we're only using it here in this function + set(${VAR_OUPUT} ${VAR_VALUE}) + + # we'll print what we found to the console + message(STATUS "Found ${VAR_OUPUT}=${VAR_VALUE}") + + # the interesting part is defining the VAR_OUPUT name a value to use in the app + add_definitions(-D${VAR_OUPUT}=\"${VAR_VALUE}\") + else() + # if we get here, check the execute_process command and parameters. + message(STATUS "LIBWOLFSSL_SAVE_INFO encountered a non-zero VAR_RESULT") + set(${VAR_OUPUT} "Unknown") + endif() +endfunction() # LIBWOLFSSL_SAVE_INFO + +if(NOT CMAKE_BUILD_EARLY_EXPANSION) + # LIBWOLFSSL_VERSION_GIT_HASH + execute_process(COMMAND ${git_cmd} "rev-parse" "HEAD" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_GIT_HASH "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSL_VERSION_GIT_SHORT_HASH + execute_process(COMMAND ${git_cmd} "rev-parse" "--short" "HEAD" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ERROR_QUIET ) + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_GIT_SHORT_HASH "${TMP_OUT}" "${TMP_RES}") + + # LIBWOLFSSL_VERSION_GIT_HASH_DATE + execute_process(COMMAND ${git_cmd} "show" "--no-patch" "--no-notes" "--pretty=\'\%cd\'" OUTPUT_VARIABLE TMP_OUT RESULT_VARIABLE TMP_RES ) + LIBWOLFSSL_SAVE_INFO(LIBWOLFSSL_VERSION_GIT_HASH_DATE "${TMP_OUT}" "${TMP_RES}") +endif() + +message(STATUS "") + 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 new file mode 100644 index 000000000..7e07ec1df --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/include/main.h @@ -0,0 +1,38 @@ +/* template main.h + * + * Copyright (C) 2006-2023 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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 + * (at your option) any later version. + * + * wolfSSL 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 + */ +#ifndef _MAIN_H_ +#define _MAIN_H_ + +/* Espressif libraries */ +#include "sdkconfig.h" +#include +#include + +/* wolfSSL */ +#include "user_settings.h" /* always include wolfSSL user_settings.h first */ +#include +#include + +/* wolfSSH */ +#include +#include + +#endif diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/main.c b/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/main.c new file mode 100644 index 000000000..6204cc398 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/main/main.c @@ -0,0 +1,79 @@ +/* main.c + * + * Copyright (C) 2006-2023 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL 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 + * (at your option) any later version. + * + * wolfSSL 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 + */ +#include "main.h" + +/* actual working example would include WiFi & time libraries here */ + +static const char* const TAG = "My Project"; + +void app_main(void) +{ + ESP_LOGI(TAG, "------------ wolfSSL wolfSSH template Example ----------"); + ESP_LOGI(TAG, "--------------------------------------------------------"); + ESP_LOGI(TAG, "--------------------------------------------------------"); + ESP_LOGI(TAG, "---------------------- BEGIN MAIN ----------------------"); + ESP_LOGI(TAG, "--------------------------------------------------------"); + ESP_LOGI(TAG, "--------------------------------------------------------"); + + ESP_LOGI(TAG, "Hello wolfSSL!"); + +#ifdef DEBUG_WOLFSSH + wolfSSH_Debugging_ON(); +#else + ESP_LOGI(TAG, "DEBUG_WOLFSSH is not defined, " + "so nothing will happen for teh next statement"); +#endif + +#ifdef HAVE_VERSION_EXTENDED_INFO + esp_ShowExtendedSystemInfo(); +#endif + +#ifdef INCLUDE_uxTaskGetStackHighWaterMark + ESP_LOGI(TAG, "Stack HWM: %d", uxTaskGetStackHighWaterMark(NULL)); + + ESP_LOGI(TAG, "Stack used: %d", CONFIG_ESP_MAIN_TASK_STACK_SIZE + - (uxTaskGetStackHighWaterMark(NULL))); +#endif + +/* the simplest check of the wolfSSL library presence: */ +#ifdef LIBWOLFSSL_VERSION_STRING + ESP_LOGI(TAG, ""); + ESP_LOGI(TAG, "Found wolfSSL Version %s\n", LIBWOLFSSL_VERSION_STRING); +#else + ESP_LOGW(TAG, "Warning: Could not find wolfSSL Version"); +#endif + +/* the simplest check of the wolfSSH library presence: */ +#ifdef LIBWOLFSSH_VERSION_STRING + ESP_LOGI(TAG, ""); + ESP_LOGI(TAG, "Found wolfSSH Version %s\n", LIBWOLFSSH_VERSION_STRING); + wolfSSH_Log(WS_LOG_INFO, "[wolfssh] Hello World!"); +#else + ESP_LOGW(TAG, "Warning: Could not find wolfSSH Version"); +#endif + +/* actual working example would initialize WiFi & time libraries here */ + + ESP_LOGI(TAG, "\n\nDone!\n\n" + "If running from idf.py monitor, press twice: Ctrl+]\n\n" + "WOLFSSL_COMPLETE\n" /* exit keyword for wolfssl_monitor.py */ + ); +} /* app_main */ diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_template/partitions_singleapp_large.csv b/ide/Espressif/ESP-IDF/examples/wolfssh_template/partitions_singleapp_large.csv new file mode 100644 index 000000000..a9c373bec --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/partitions_singleapp_large.csv @@ -0,0 +1,31 @@ +# to view: idf.py partition-table +# +# ESP-IDF Partition Table +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 24K, +phy_init,data, phy, 0xf000, 4K, +factory, app, factory, 0x10000, 1500K, + + +# For other settings, see: +# https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/partition-tables.html#creating-custom-tables +# +# Here is the summary printed for the "Single factory app, no OTA" configuration: +# +# # ESP-IDF Partition Table +# # Name, Type, SubType, Offset, Size, Flags +# nvs, data, nvs, 0x9000, 0x6000, +# phy_init, data, phy, 0xf000, 0x1000, +# factory, app, factory, 0x10000, 1M, +# +# +# Here is the summary printed for the "Factory app, two OTA definitions" configuration: +# +# # ESP-IDF Partition Table +# # Name, Type, SubType, Offset, Size, Flags +# nvs, data, nvs, 0x9000, 0x4000, +# otadata, data, ota, 0xd000, 0x2000, +# phy_init, data, phy, 0xf000, 0x1000, +# factory, app, factory, 0x10000, 1M, +# ota_0, app, ota_0, 0x110000, 1M, +# ota_1, app, ota_1, 0x210000, 1M, diff --git a/ide/Espressif/ESP-IDF/examples/wolfssh_template/sdkconfig.defaults b/ide/Espressif/ESP-IDF/examples/wolfssh_template/sdkconfig.defaults new file mode 100644 index 000000000..109246181 --- /dev/null +++ b/ide/Espressif/ESP-IDF/examples/wolfssh_template/sdkconfig.defaults @@ -0,0 +1,38 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration + +CONFIG_FREERTOS_HZ=1000 +CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y + +# +# Default main stack size +# +# This is typically way bigger than needed for stack size. See user_settings.h +# +CONFIG_ESP_MAIN_TASK_STACK_SIZE=10500 + +# Legacy stack size for older ESP-IDF versions +CONFIG_MAIN_TASK_STACK_SIZE=10500 + +# +# Compiler options +# +CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y +CONFIG_COMPILER_OPTIMIZATION_ASSERTION_LEVEL=2 +CONFIG_COMPILER_HIDE_PATHS_MACROS=y +CONFIG_COMPILER_STACK_CHECK_MODE_NORM=y +CONFIG_COMPILER_STACK_CHECK=y + +# +# Partition Table +# +# CONFIG_PARTITION_TABLE_SINGLE_APP is not set +CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y +# CONFIG_PARTITION_TABLE_TWO_OTA is not set +# CONFIG_PARTITION_TABLE_CUSTOM is not set +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" +CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp_large.csv" +CONFIG_PARTITION_TABLE_OFFSET=0x8000 +CONFIG_PARTITION_TABLE_MD5=y +# end of Partition Table From 65a31b5faaf9701ecc4232760898736b36aeffb3 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 28 Dec 2023 12:28:16 -0800 Subject: [PATCH 02/11] Remove Example Server The example server was never used. All new behaviors were added to the echoserver only. Now with wolfSSHd, the server example can finally be removed. 1. Remove the example server from the build. 2. Remove the file notes.md. 3. Update the readme. --- README.md | 12 +- examples/include.am | 1 - examples/server/include.am | 10 - examples/server/server.c | 827 ------------------------------------- examples/server/server.h | 29 -- notes.md | 35 -- 6 files changed, 3 insertions(+), 911 deletions(-) delete mode 100644 examples/server/include.am delete mode 100644 examples/server/server.c delete mode 100644 examples/server/server.h delete mode 100644 notes.md diff --git a/README.md b/README.md index 828ac0ba5..95ff39222 100644 --- a/README.md +++ b/README.md @@ -238,12 +238,6 @@ The sftpclient tool accepts the following command line options: -G get remote filename as local filename -server ------- - -This tool is a place holder. - - SCP === @@ -357,12 +351,12 @@ define `WOLFSSH_SFTP`: For full API usage and implementation details, please see the wolfSSH User Manual. -The SFTP client created is located in the directory examples/sftpclient/ and the -server is ran using the same echoserver as with wolfSSH. +The SFTP client created is located in the directory examples/sftpclient/ and +the example echoserver acts as a SFTP server. src/wolfssh$ ./examples/sftpclient/wolfsftp -A full list of supported commands can be seen with typeing "help" after a +A full list of supported commands can be seen with typing "help" after a connection. diff --git a/examples/include.am b/examples/include.am index 6d11933f6..fb3d8a844 100644 --- a/examples/include.am +++ b/examples/include.am @@ -3,7 +3,6 @@ # All paths should be given relative to the root include examples/client/include.am -include examples/server/include.am include examples/echoserver/include.am include examples/portfwd/include.am include examples/sftpclient/include.am diff --git a/examples/server/include.am b/examples/server/include.am deleted file mode 100644 index 9a4f0cf7f..000000000 --- a/examples/server/include.am +++ /dev/null @@ -1,10 +0,0 @@ -# vim:ft=automake -# All paths should be given relative to the root - -if BUILD_EXAMPLE_SERVERS -noinst_PROGRAMS += examples/server/server -examples_server_server_SOURCES = examples/server/server.c \ - examples/server/server.h -examples_server_server_LDADD = src/libwolfssh.la -examples_server_server_DEPENDENCIES = src/libwolfssh.la -endif diff --git a/examples/server/server.c b/examples/server/server.c deleted file mode 100644 index c74f78922..000000000 --- a/examples/server/server.c +++ /dev/null @@ -1,827 +0,0 @@ -/* server.c - * - * Copyright (C) 2014-2023 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 . - */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#define WOLFSSH_TEST_SERVER -#define WOLFSSH_TEST_THREADING - - -#ifdef WOLFSSL_USER_SETTINGS - #include -#else - #include -#endif - -#include -#include -#include -#include -#include -#include -#include "server.h" - -#ifdef NO_FILESYSTEM - #include - #ifdef WOLFSSH_SCP - #include - #endif -#endif - - -#ifndef NO_WOLFSSH_SERVER - -static const char serverBanner[] = "wolfSSH Example Server\n"; - - -typedef struct { - WOLFSSH* ssh; - SOCKET_T fd; - word32 id; - char nonBlock; -} thread_ctx_t; - - -#ifndef EXAMPLE_HIGHWATER_MARK - #define EXAMPLE_HIGHWATER_MARK 0x3FFF8000 /* 1GB - 32kB */ -#endif -#ifndef EXAMPLE_BUFFER_SZ - #define EXAMPLE_BUFFER_SZ 4096 -#endif -#define SCRATCH_BUFFER_SZ 1200 - - -static byte find_char(const byte* str, const byte* buf, word32 bufSz) -{ - const byte* cur; - - while (bufSz) { - cur = str; - while (*cur != '\0') { - if (*cur == *buf) - return *cur; - cur++; - } - buf++; - bufSz--; - } - - return 0; -} - - -static int dump_stats(thread_ctx_t* ctx) -{ - char stats[1024]; - word32 statsSz; - word32 txCount, rxCount, seq, peerSeq; - - wolfSSH_GetStats(ctx->ssh, &txCount, &rxCount, &seq, &peerSeq); - - WSNPRINTF(stats, sizeof(stats), - "Statistics for Thread #%u:\r\n" - " txCount = %u\r\n rxCount = %u\r\n" - " seq = %u\r\n peerSeq = %u\r\n", - ctx->id, txCount, rxCount, seq, peerSeq); - statsSz = (word32)strlen(stats); - - fprintf(stderr, "%s", stats); - return wolfSSH_stream_send(ctx->ssh, (byte*)stats, statsSz); -} - - -static int NonBlockSSH_accept(WOLFSSH* ssh) -{ - int ret; - int error; - SOCKET_T sockfd; - int select_ret = 0; - - ret = wolfSSH_accept(ssh); - error = wolfSSH_get_error(ssh); - sockfd = (SOCKET_T)wolfSSH_get_fd(ssh); - - while (ret != WS_SUCCESS && - (error == WS_WANT_READ || error == WS_WANT_WRITE)) - { - if (error == WS_WANT_READ) - printf("... client would read block\n"); - else if (error == WS_WANT_WRITE) - printf("... client would write block\n"); - - select_ret = tcp_select(sockfd, 1); - if (select_ret == WS_SELECT_RECV_READY || - select_ret == WS_SELECT_ERROR_READY || - error == WS_WANT_WRITE) - { - ret = wolfSSH_accept(ssh); - error = wolfSSH_get_error(ssh); - } - else if (select_ret == WS_SELECT_TIMEOUT) - error = WS_WANT_READ; - else - error = WS_FATAL_ERROR; - } - - return ret; -} - - -static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs) -{ - int ret; - thread_ctx_t* threadCtx = (thread_ctx_t*)vArgs; - -#if defined(WOLFSSH_SCP) && defined(NO_FILESYSTEM) - ScpBuffer scpBufferRecv, scpBufferSend; - byte fileBuffer[49000]; - byte fileTmp[] = "wolfSSH SCP buffer file"; - - WMEMSET(&scpBufferRecv, 0, sizeof(ScpBuffer)); - scpBufferRecv.buffer = fileBuffer; - scpBufferRecv.bufferSz = sizeof(fileBuffer); - wolfSSH_SetScpRecvCtx(threadCtx->ssh, (void*)&scpBufferRecv); - - /* make buffer file to send if asked */ - WMEMSET(&scpBufferSend, 0, sizeof(ScpBuffer)); - WMEMCPY(scpBufferSend.name, "test.txt", sizeof("test.txt")); - scpBufferSend.nameSz = WSTRLEN("test.txt"); - scpBufferSend.buffer = fileTmp; - scpBufferSend.bufferSz = sizeof(fileBuffer); - scpBufferSend.fileSz = sizeof(fileTmp); - scpBufferSend.mode = 0x1A4; - wolfSSH_SetScpSendCtx(threadCtx->ssh, (void*)&scpBufferSend); -#endif - - if (!threadCtx->nonBlock) - ret = wolfSSH_accept(threadCtx->ssh); - else - ret = NonBlockSSH_accept(threadCtx->ssh); - - if (ret == WS_SUCCESS) { - byte* buf = NULL; - byte* tmpBuf; - int bufSz, backlogSz = 0, rxSz, txSz, stop = 0, txSum; - - do { - bufSz = EXAMPLE_BUFFER_SZ + backlogSz; - - tmpBuf = (byte*)realloc(buf, bufSz); - if (tmpBuf == NULL) - stop = 1; - else - buf = tmpBuf; - - if (!stop) { - do { - rxSz = wolfSSH_stream_read(threadCtx->ssh, - buf + backlogSz, - EXAMPLE_BUFFER_SZ); - if (rxSz <= 0) - rxSz = wolfSSH_get_error(threadCtx->ssh); - } while (rxSz == WS_WANT_READ || rxSz == WS_WANT_WRITE); - - if (rxSz > 0) { - backlogSz += rxSz; - txSum = 0; - txSz = 0; - - while (backlogSz != txSum && txSz >= 0 && !stop) { - txSz = wolfSSH_stream_send(threadCtx->ssh, - buf + txSum, - backlogSz - txSum); - - if (txSz > 0) { - byte c; - const byte matches[] = { 0x03, 0x05, 0x06, 0x00 }; - - c = find_char(matches, buf + txSum, txSz); - switch (c) { - case 0x03: - stop = 1; - break; - case 0x06: - if (wolfSSH_TriggerKeyExchange(threadCtx->ssh) - != WS_SUCCESS) - stop = 1; - break; - case 0x05: - if (dump_stats(threadCtx) <= 0) - stop = 1; - break; - } - txSum += txSz; - } - else if (txSz != WS_REKEYING) - stop = 1; - } - - if (txSum < backlogSz) - memmove(buf, buf + txSum, backlogSz - txSum); - backlogSz -= txSum; - } - else - stop = 1; - } - } while (!stop); - - free(buf); - } else if (ret == WS_SCP_COMPLETE) { - printf("scp file transfer completed\n"); - #if defined(WOLFSSH_SCP) && defined(NO_FILESYSTEM) - if (scpBufferRecv.fileSz > 0) { - word32 z; - - printf("file name : %s\n", scpBufferRecv.name); - printf(" size : %d\n", scpBufferRecv.fileSz); - printf(" mode : %o\n", scpBufferRecv.mode); - printf(" mTime : %lu\n", scpBufferRecv.mTime); - printf("\n"); - - for (z = 0; z < scpBufferRecv.fileSz; z++) - printf("%c", scpBufferRecv.buffer[z]); - printf("\n"); - } - #endif - } else if (ret == WS_SFTP_COMPLETE) { - printf("Use example/echoserver/echoserver for SFTP\n"); - } - wolfSSH_stream_exit(threadCtx->ssh, 0); - WCLOSESOCKET(threadCtx->fd); - wolfSSH_free(threadCtx->ssh); - free(threadCtx); - - return 0; -} - -#ifndef NO_FILESYSTEM -static int load_file(const char* fileName, byte* buf, word32 bufSz) -{ - FILE* file; - word32 fileSz; - word32 readSz; - - if (fileName == NULL) return 0; - - if (WFOPEN(NULL, &file, fileName, "rb") != 0) - return 0; - fseek(file, 0, SEEK_END); - fileSz = (word32)ftell(file); - rewind(file); - - if (fileSz > bufSz) { - fclose(file); - return 0; - } - - readSz = (word32)fread(buf, 1, fileSz, file); - if (readSz < fileSz) { - fclose(file); - return 0; - } - - fclose(file); - - return fileSz; -} -#endif /* !NO_FILESYSTEM */ - -/* returns buffer size on success */ -static int load_key(byte isEcc, byte* buf, word32 bufSz) -{ - word32 sz = 0; - -#ifndef NO_FILESYSTEM - const char* bufName; - bufName = isEcc ? "./keys/server-key-ecc.der" : - "./keys/server-key-rsa.der" ; - sz = load_file(bufName, buf, bufSz); -#else - /* using buffers instead */ - if (isEcc) { - if ((word32)sizeof_ecc_key_der_256 > bufSz) { - return 0; - } - WMEMCPY(buf, ecc_key_der_256, sizeof_ecc_key_der_256); - sz = sizeof_ecc_key_der_256; - } - else { - if ((word32)sizeof_rsa_key_der_2048 > bufSz) { - return 0; - } - WMEMCPY(buf, rsa_key_der_2048, sizeof_rsa_key_der_2048); - sz = sizeof_rsa_key_der_2048; - } -#endif - - return sz; -} - - -static INLINE void c32toa(word32 u32, byte* c) -{ - c[0] = (u32 >> 24) & 0xff; - c[1] = (u32 >> 16) & 0xff; - c[2] = (u32 >> 8) & 0xff; - c[3] = u32 & 0xff; -} - - -/* Map user names to passwords */ -/* Use arrays for username and p. The password or public key can - * be hashed and the hash stored here. Then I won't need the type. */ -typedef struct PwMap { - byte type; - byte username[32]; - word32 usernameSz; - byte p[WC_SHA256_DIGEST_SIZE]; - struct PwMap* next; -} PwMap; - - -typedef struct PwMapList { - PwMap* head; -} PwMapList; - - -static PwMap* PwMapNew(PwMapList* list, byte type, const byte* username, - word32 usernameSz, const byte* p, word32 pSz) -{ - PwMap* map; - - map = (PwMap*)malloc(sizeof(PwMap)); - if (map != NULL) { - wc_Sha256 sha; - byte flatSz[4]; - - map->type = type; - if (usernameSz >= sizeof(map->username)) - usernameSz = sizeof(map->username) - 1; - memcpy(map->username, username, usernameSz + 1); - map->username[usernameSz] = 0; - map->usernameSz = usernameSz; - - wc_InitSha256(&sha); - c32toa(pSz, flatSz); - wc_Sha256Update(&sha, flatSz, sizeof(flatSz)); - wc_Sha256Update(&sha, p, pSz); - wc_Sha256Final(&sha, map->p); - - map->next = list->head; - list->head = map; - } - - return map; -} - - -static void PwMapListDelete(PwMapList* list) -{ - if (list != NULL) { - PwMap* head = list->head; - - while (head != NULL) { - PwMap* cur = head; - head = head->next; - memset(cur, 0, sizeof(PwMap)); - free(cur); - } - } -} - - -static const char samplePasswordBuffer[] = - "jill:upthehill\n" - "jack:fetchapail\n"; - - -static const char samplePublicKeyEccBuffer[] = - "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAA" - "BBBNkI5JTP6D0lF42tbxX19cE87hztUS6FSDoGvPfiU0CgeNSbI+aFdKIzTP5CQEJSvm25" - "qUzgDtH7oyaQROUnNvk= hansel\n" - "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAA" - "BBBKAtH8cqaDbtJFjtviLobHBmjCtG56DMkP6A4M2H9zX2/YCg1h9bYS7WHd9UQDwXO1Hh" - "IZzRYecXh7SG9P4GhRY= gretel\n"; - - -static const char samplePublicKeyRsaBuffer[] = - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9P3ZFowOsONXHD5MwWiCciXytBRZGho" - "MNiisWSgUs5HdHcACuHYPi2W6Z1PBFmBWT9odOrGRjoZXJfDDoPi+j8SSfDGsc/hsCmc3G" - "p2yEhUZUEkDhtOXyqjns1ickC9Gh4u80aSVtwHRnJZh9xPhSq5tLOhId4eP61s+a5pwjTj" - "nEhBaIPUJO2C/M0pFnnbZxKgJlX7t1Doy7h5eXxviymOIvaCZKU+x5OopfzM/wFkey0EPW" - "NmzI5y/+pzU5afsdeEWdiQDIQc80H6Pz8fsoFPvYSG+s4/wz0duu7yeeV1Ypoho65Zr+pE" - "nIf7dO0B8EblgWt+ud+JI8wrAhfE4x hansel\n" - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqDwRVTRVk/wjPhoo66+Mztrc31KsxDZ" - "+kAV0139PHQ+wsueNpba6jNn5o6mUTEOrxrz0LMsDJOBM7CmG0983kF4gRIihECpQ0rcjO" - "P6BSfbVTE9mfIK5IsUiZGd8SoE9kSV2pJ2FvZeBQENoAxEFk0zZL9tchPS+OCUGbK4SDjz" - "uNZl/30Mczs73N3MBzi6J1oPo7sFlqzB6ecBjK2Kpjus4Y1rYFphJnUxtKvB0s+hoaadru" - "biE57dK6BrH5iZwVLTQKux31uCJLPhiktI3iLbdlGZEctJkTasfVSsUizwVIyRjhVKmbdI" - "RGwkU38D043AR1h0mUoGCPIKuqcFMf gretel\n"; - - -static int LoadPasswordBuffer(byte* buf, word32 bufSz, PwMapList* list) -{ - char* str = (char*)buf; - char* delimiter; - char* username; - char* password; - - /* Each line of passwd.txt is in the format - * username:password\n - * This function modifies the passed-in buffer. */ - - if (list == NULL) - return -1; - - if (buf == NULL || bufSz == 0) - return 0; - - while (*str != 0) { - delimiter = strchr(str, ':'); - if (delimiter == NULL) { - return -1; - } - username = str; - *delimiter = 0; - password = delimiter + 1; - str = strchr(password, '\n'); - if (str == NULL) { - return -1; - } - *str = 0; - str++; - if (PwMapNew(list, WOLFSSH_USERAUTH_PASSWORD, - (byte*)username, (word32)strlen(username), - (byte*)password, (word32)strlen(password)) == NULL ) { - - return -1; - } - } - - return 0; -} - - -static int LoadPublicKeyBuffer(byte* buf, word32 bufSz, PwMapList* list) -{ - char* str = (char*)buf; - char* delimiter; - byte* publicKey64; - word32 publicKey64Sz; - byte* username; - word32 usernameSz; - byte publicKey[300]; - word32 publicKeySz; - - /* Each line of passwd.txt is in the format - * ssh-rsa AAAB3BASE64ENCODEDPUBLICKEYBLOB username\n - * This function modifies the passed-in buffer. */ - if (list == NULL) - return -1; - - if (buf == NULL || bufSz == 0) - return 0; - - while (*str != 0) { - /* Skip the public key type. This example will always be ssh-rsa. */ - delimiter = strchr(str, ' '); - if (delimiter == NULL) { - return -1; - } - str = delimiter + 1; - delimiter = strchr(str, ' '); - if (delimiter == NULL) { - return -1; - } - publicKey64 = (byte*)str; - *delimiter = 0; - publicKey64Sz = (word32)(delimiter - str); - str = delimiter + 1; - delimiter = strchr(str, '\n'); - if (delimiter == NULL) { - return -1; - } - username = (byte*)str; - *delimiter = 0; - usernameSz = (word32)(delimiter - str); - str = delimiter + 1; - publicKeySz = sizeof(publicKey); - - if (Base64_Decode(publicKey64, publicKey64Sz, - publicKey, &publicKeySz) != 0) { - - return -1; - } - - if (PwMapNew(list, WOLFSSH_USERAUTH_PUBLICKEY, - username, usernameSz, - publicKey, publicKeySz) == NULL ) { - - return -1; - } - } - - return 0; -} - - -static int wsUserAuth(byte authType, - WS_UserAuthData* authData, - void* ctx) -{ - PwMapList* list; - PwMap* map; - byte authHash[WC_SHA256_DIGEST_SIZE]; - - if (ctx == NULL) { - fprintf(stderr, "wsUserAuth: ctx not set"); - return WOLFSSH_USERAUTH_FAILURE; - } - - if (authType != WOLFSSH_USERAUTH_PASSWORD && - authType != WOLFSSH_USERAUTH_PUBLICKEY) { - - return WOLFSSH_USERAUTH_FAILURE; - } - - /* Hash the password or public key with its length. */ - { - wc_Sha256 sha; - byte flatSz[4]; - wc_InitSha256(&sha); - if (authType == WOLFSSH_USERAUTH_PASSWORD) { - c32toa(authData->sf.password.passwordSz, flatSz); - wc_Sha256Update(&sha, flatSz, sizeof(flatSz)); - wc_Sha256Update(&sha, - authData->sf.password.password, - authData->sf.password.passwordSz); - } - else if (authType == WOLFSSH_USERAUTH_PUBLICKEY) { - c32toa(authData->sf.publicKey.publicKeySz, flatSz); - wc_Sha256Update(&sha, flatSz, sizeof(flatSz)); - wc_Sha256Update(&sha, - authData->sf.publicKey.publicKey, - authData->sf.publicKey.publicKeySz); - } - wc_Sha256Final(&sha, authHash); - } - - list = (PwMapList*)ctx; - map = list->head; - - while (map != NULL) { - if (authData->usernameSz == map->usernameSz && - memcmp(authData->username, map->username, map->usernameSz) == 0) { - - if (authData->type == map->type) { - if (memcmp(map->p, authHash, WC_SHA256_DIGEST_SIZE) == 0) { - return WOLFSSH_USERAUTH_SUCCESS; - } - else { - return (authType == WOLFSSH_USERAUTH_PASSWORD ? - WOLFSSH_USERAUTH_INVALID_PASSWORD : - WOLFSSH_USERAUTH_INVALID_PUBLICKEY); - } - } - else { - return WOLFSSH_USERAUTH_INVALID_AUTHTYPE; - } - } - map = map->next; - } - - return WOLFSSH_USERAUTH_INVALID_USER; -} - - -static void ShowUsage(void) -{ - printf("server %s\n", LIBWOLFSSH_VERSION_STRING); - printf(" -h display this help and exit\n"); - printf(" -m allow multiple connections\n"); - printf(" -e use ECC private key\n"); - printf(" -N use non-blocking sockets\n"); -} - - -THREAD_RETURN WOLFSSH_THREAD server_test(void* args) -{ - WOLFSSH_CTX* ctx = NULL; - PwMapList pwMapList; - SOCKET_T listenFd = 0; - word32 defaultHighwater = EXAMPLE_HIGHWATER_MARK; - word32 threadCount = 0; - word16 port = wolfSshPort; - char multipleConnections = 0; - char useEcc = 0; - int ch; - char nonBlock = 0; - - int argc = ((func_args*)args)->argc; - char** argv = ((func_args*)args)->argv; - ((func_args*)args)->return_code = 0; - - while ((ch = mygetopt(argc, argv, "hmeN")) != -1) { - switch (ch) { - case 'h' : - ShowUsage(); - exit(EXIT_SUCCESS); - - case 'm' : - multipleConnections = 1; - break; - - case 'e' : - useEcc = 1; - break; - - case 'N' : - nonBlock = 1; - break; - - default: - ShowUsage(); - exit(MY_EX_USAGE); - } - } - myoptind = 0; /* reset for test cases */ - -#ifdef WOLFSSH_NO_RSA - /* If wolfCrypt isn't built with RSA, force ECC on. */ - useEcc = 1; -#endif - - if (wolfSSH_Init() != WS_SUCCESS) { - fprintf(stderr, "Couldn't initialize wolfSSH.\n"); - exit(EXIT_FAILURE); - } - - ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL); - if (ctx == NULL) { - fprintf(stderr, "Couldn't allocate SSH CTX data.\n"); - exit(EXIT_FAILURE); - } - - memset(&pwMapList, 0, sizeof(pwMapList)); - wolfSSH_SetUserAuth(ctx, wsUserAuth); - wolfSSH_CTX_SetBanner(ctx, serverBanner); - - { - const char* bufName; - byte buf[SCRATCH_BUFFER_SZ]; - word32 bufSz; - - bufSz = load_key(useEcc, buf, SCRATCH_BUFFER_SZ); - if (bufSz == 0) { - fprintf(stderr, "Couldn't load key.\n"); - exit(EXIT_FAILURE); - } - if (wolfSSH_CTX_UsePrivateKey_buffer(ctx, buf, bufSz, - WOLFSSH_FORMAT_ASN1) < 0) { - fprintf(stderr, "Couldn't use key buffer.\n"); - exit(EXIT_FAILURE); - } - - bufSz = (word32)strlen(samplePasswordBuffer); - memcpy(buf, samplePasswordBuffer, bufSz); - buf[bufSz] = 0; - LoadPasswordBuffer(buf, bufSz, &pwMapList); - - bufName = useEcc ? samplePublicKeyEccBuffer : - samplePublicKeyRsaBuffer; - bufSz = (word32)strlen(bufName); - memcpy(buf, bufName, bufSz); - buf[bufSz] = 0; - LoadPublicKeyBuffer(buf, bufSz, &pwMapList); - } - - tcp_listen(&listenFd, &port, 1); - - do { - SOCKET_T clientFd = 0; - SOCKADDR_IN_T clientAddr; - socklen_t clientAddrSz = sizeof(clientAddr); -#ifndef SINGLE_THREADED - THREAD_TYPE thread; -#endif - WOLFSSH* ssh; - thread_ctx_t* threadCtx; - - threadCtx = (thread_ctx_t*)malloc(sizeof(thread_ctx_t)); - if (threadCtx == NULL) { - fprintf(stderr, "Couldn't allocate thread context data.\n"); - exit(EXIT_FAILURE); - } - - ssh = wolfSSH_new(ctx); - if (ssh == NULL) { - fprintf(stderr, "Couldn't allocate SSH data.\n"); - exit(EXIT_FAILURE); - } - wolfSSH_SetUserAuthCtx(ssh, &pwMapList); - /* Use the session object for its own highwater callback ctx */ - if (defaultHighwater > 0) { - wolfSSH_SetHighwaterCtx(ssh, (void*)ssh); - wolfSSH_SetHighwater(ssh, defaultHighwater); - } - - clientFd = accept(listenFd, (struct sockaddr*)&clientAddr, - &clientAddrSz); - if (clientFd == -1) - err_sys("tcp accept failed"); - - if (nonBlock) - tcp_set_nonblocking(&clientFd); - - wolfSSH_set_fd(ssh, (int)clientFd); - - threadCtx->ssh = ssh; - threadCtx->fd = clientFd; - threadCtx->id = threadCount++; - threadCtx->nonBlock = nonBlock; - -#ifndef SINGLE_THREADED -#if defined(WOLFSSH_OLD_THREADING) || defined(WOLFSSL_THREAD_NO_JOIN) - if (multipleConnections) - ThreadStartNoJoin(server_worker, threadCtx); - else -#endif - { - ThreadStart(server_worker, threadCtx, &thread); - ThreadJoin(thread); - } -#else - server_worker(threadCtx); -#endif /* SINGLE_THREADED */ - } while (multipleConnections); - - PwMapListDelete(&pwMapList); - wolfSSH_CTX_free(ctx); - if (wolfSSH_Cleanup() != WS_SUCCESS) { - fprintf(stderr, "Couldn't clean up wolfSSH.\n"); - exit(EXIT_FAILURE); - } -#if !defined(WOLFSSH_NO_ECC) && defined(FP_ECC) && defined(HAVE_THREAD_LS) - wc_ecc_fp_free(); /* free per thread cache */ -#endif - - WOLFSSL_RETURN_FROM_THREAD(0); -} - -#endif /* NO_WOLFSSH_SERVER */ - - -#ifndef NO_MAIN_DRIVER - - int main(int argc, char** argv) - { - func_args args; - - args.argc = argc; - args.argv = argv; - args.return_code = 0; - - WSTARTTCP(); - - ChangeToWolfSshRoot(); - #ifdef DEBUG_WOLFSSH - wolfSSH_Debugging_ON(); - #endif - - wolfSSH_Init(); - -#ifndef NO_WOLFSSH_SERVER - server_test(&args); -#else - printf("wolfSSH compiled without server support\n"); -#endif - - wolfSSH_Cleanup(); - - return args.return_code; - } - - - int myoptind = 0; - char* myoptarg = NULL; - -#endif /* NO_MAIN_DRIVER */ diff --git a/examples/server/server.h b/examples/server/server.h deleted file mode 100644 index 6619892a3..000000000 --- a/examples/server/server.h +++ /dev/null @@ -1,29 +0,0 @@ -/* server.h - * - * Copyright (C) 2014-2023 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 . - */ - - -#ifndef _WOLFSSH_EXAMPLES_SERVER_H_ -#define _WOLFSSH_EXAMPLES_SERVER_H_ - - -THREAD_RETURN WOLFSSH_THREAD server_test(void* args); - - -#endif /* _WOLFSSH_EXAMPLES_SERVER_H_ */ diff --git a/notes.md b/notes.md deleted file mode 100644 index 61b98d76a..000000000 --- a/notes.md +++ /dev/null @@ -1,35 +0,0 @@ -wolfssh notes -============= - -coding standard ---------------- - -1. Exceptions are allowed with good reason. - -2. Follow the existing style. - -3. Try not to shorthand variables, except for ijk as indicies. - -4. Lengths of arrays should have the array name followed by Sz. - -5. Single return per function. - -6. Check all incoming parameters. - -7. No gotos. - -8. Check all return codes. It feels a little tedious, but the preferred method -is running checks against success. This way if a function returns an error, the -code will drop to the end. - -``` - ret = functionCall(parameter); - if (ret == SUCCESS) - ret = secondFunctionCall(otherParameter); - if (ret == SUCCESS) - ret = thirdFunctionCall(aParameter, anotherParameter); - cleanUp(); - return ret; -``` - - From 9048eba53a8bb42128c092c2ba256f90b60218a9 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 2 Jan 2024 14:01:59 -0800 Subject: [PATCH 03/11] SFTP Test Maintenance 1. In wolfSSH_SftpTest(), move the -p parameter inside the guard with the port number it belongs to. 2. In wolfSSH_SftpTest(), free the conditional variable and mutex. --- tests/sftp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/sftp.c b/tests/sftp.c index ef19ca0b7..ca7dd2b72 100644 --- a/tests/sftp.c +++ b/tests/sftp.c @@ -216,10 +216,10 @@ int wolfSSH_SftpTest(int flag) args[argsCount++] = "jill"; args[argsCount++] = "-P"; args[argsCount++] = "upthehill"; - args[argsCount++] = "-p"; #ifndef USE_WINDOWS_API /* use port that server has found */ + args[argsCount++] = "-p"; snprintf(portNumber, sizeof(portNumber), "%d", ready.port); args[argsCount++] = portNumber; #endif @@ -240,6 +240,7 @@ int wolfSSH_SftpTest(int flag) ThreadJoin(serThread); wolfSSH_Cleanup(); + FreeTcpReady(&ready); return ret; } From 4f638852772d063e4e9fb41ff520938fa884f754 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Wed, 3 Jan 2024 13:24:10 -0800 Subject: [PATCH 04/11] SFTP Test Maintenance 1. Modified SignalTcpReady() to test.h. Matched its prototype to the other functions for TcpReady. 2. Add a timeout in WaitTcpReady() specifically for Zephyr builds. 3. Misc few cleanups. --- examples/echoserver/echoserver.c | 23 ++++++++++------------- tests/api.c | 2 +- tests/sftp.c | 2 +- tests/testsuite.c | 2 +- wolfssh/test.h | 26 ++++++++++++++++---------- 5 files changed, 29 insertions(+), 26 deletions(-) diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index 63409c2f6..3d9b542e0 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -2159,21 +2159,18 @@ static void ShowUsage(void) } -static INLINE void SignalTcpReady(func_args* serverArgs, word16 port) +static INLINE void SignalTcpReady(tcp_ready* ready, word16 port) { #if defined(_POSIX_THREADS) && defined(NO_MAIN_DRIVER) && \ !defined(__MINGW32__) && !defined(SINGLE_THREADED) - tcp_ready* ready = serverArgs->signal; - if (ready != NULL) { - pthread_mutex_lock(&ready->mutex); - ready->ready = 1; - ready->port = port; - pthread_cond_signal(&ready->cond); - pthread_mutex_unlock(&ready->mutex); - } + pthread_mutex_lock(&ready->mutex); + ready->ready = 1; + ready->port = port; + pthread_cond_signal(&ready->cond); + pthread_mutex_unlock(&ready->mutex); #else - (void)serverArgs; - (void)port; + WOLFSSH_UNUSED(ready); + WOLFSSH_UNUSED(port); #endif } @@ -2543,6 +2540,8 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) #endif } + SignalTcpReady(serverArgs->signal, port); + do { WS_SOCKET_T clientFd = WOLFSSH_SOCKET_INVALID; #ifdef WOLFSSL_NUCLEUS @@ -2600,8 +2599,6 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) } #endif - SignalTcpReady(serverArgs, port); - #ifdef WOLFSSL_NUCLEUS clientFd = NU_Accept(listenFd, &clientAddr, 0); #else diff --git a/tests/api.c b/tests/api.c index 9353c4d2b..c417a1c56 100644 --- a/tests/api.c +++ b/tests/api.c @@ -974,7 +974,7 @@ static void test_wolfSSH_SFTP_SendReadPacket(void) ser.signal = &ready; InitTcpReady(ser.signal); ThreadStart(echoserver_test, (void*)&ser, &serThread); - WaitTcpReady(&ser); + WaitTcpReady(&ready); sftp_client_connect(&ctx, &ssh, ready.port); AssertNotNull(ctx); diff --git a/tests/sftp.c b/tests/sftp.c index ca7dd2b72..36b2cb081 100644 --- a/tests/sftp.c +++ b/tests/sftp.c @@ -208,7 +208,7 @@ int wolfSSH_SftpTest(int flag) ser.signal = &ready; InitTcpReady(ser.signal); ThreadStart(echoserver_test, (void*)&ser, &serThread); - WaitTcpReady(&ser); + WaitTcpReady(&ready); argsCount = 0; args[argsCount++] = "."; diff --git a/tests/testsuite.c b/tests/testsuite.c index 8ee4a7c38..c9441b24d 100644 --- a/tests/testsuite.c +++ b/tests/testsuite.c @@ -145,7 +145,7 @@ int wolfSSH_TestsuiteTest(int argc, char** argv) serverArgs.signal = &ready; serverArgs.user_auth = NULL; ThreadStart(echoserver_test, &serverArgs, &serverThread); - WaitTcpReady(&serverArgs); + WaitTcpReady(&ready); WSTRNCPY(cA[clientArgc++], "client", ARGLEN); WSTRNCPY(cA[clientArgc++], "-u", ARGLEN); diff --git a/wolfssh/test.h b/wolfssh/test.h index 9b767f08c..cf276b102 100644 --- a/wolfssh/test.h +++ b/wolfssh/test.h @@ -850,8 +850,8 @@ static INLINE void InitTcpReady(tcp_ready* ready) ready->srfName = NULL; #if defined(_POSIX_THREADS) && defined(NO_MAIN_DRIVER) && \ !defined(__MINGW32__) && !defined(SINGLE_THREADED) - pthread_mutex_init(&ready->mutex, 0); - pthread_cond_init(&ready->cond, 0); + pthread_mutex_init(&ready->mutex, NULL); + pthread_cond_init(&ready->cond, NULL); #endif } @@ -863,24 +863,30 @@ static INLINE void FreeTcpReady(tcp_ready* ready) pthread_mutex_destroy(&ready->mutex); pthread_cond_destroy(&ready->cond); #else - (void)ready; + WOLFSSH_UNUSED(ready); #endif } -static INLINE void WaitTcpReady(func_args* args) +static INLINE void WaitTcpReady(tcp_ready* ready) { #if defined(_POSIX_THREADS) && defined(NO_MAIN_DRIVER) && \ !defined(__MINGW32__) && !defined(SINGLE_THREADED) - pthread_mutex_lock(&args->signal->mutex); + pthread_mutex_lock(&ready->mutex); - if (!args->signal->ready) - pthread_cond_wait(&args->signal->cond, &args->signal->mutex); - args->signal->ready = 0; /* reset */ + while (!ready->ready) { + pthread_cond_wait(&ready->cond, &ready->mutex); + } - pthread_mutex_unlock(&args->signal->mutex); + pthread_mutex_unlock(&ready->mutex); +#ifdef WOLFSSH_ZEPHYR + /* It's like the server isn't ready to accept connections it is + * listening for despite this conditional variable. A 300ms wait + * seems to help. This is not ideal. (XXX) */ + k_sleep(Z_TIMEOUT_TICKS(300)); +#endif /* WOLFSSH_ZEPHYR */ #else - (void)args; + WOLFSSH_UNUSED(ready); #endif } From b6756eb98ee9ec881d94defb8958e41ce23dde53 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 28 Dec 2023 14:29:02 -0800 Subject: [PATCH 05/11] wolfSSHd Terminal 1. Rename the stashed window size values. 2. Set the terminal modes after the child process is running. 3. Decode the modes list from the pty-request message. 4. Store the modes list for later use. --- apps/wolfsshd/wolfsshd.c | 14 +- src/internal.c | 271 +++++++++++++++++++++++++++++++++++++-- sshd_config | 0 wolfssh/internal.h | 14 +- wolfssh/ssh.h | 1 + 5 files changed, 275 insertions(+), 25 deletions(-) create mode 100644 sshd_config diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index 5a98e5cf4..bee94cda8 100644 --- a/apps/wolfsshd/wolfsshd.c +++ b/apps/wolfsshd/wolfsshd.c @@ -1323,19 +1323,21 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, /* 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; + struct winsize s = {0}; + + s.ws_col = ssh->widthChar; + s.ws_row = ssh->heightRows; + s.ws_xpixel = ssh->widthPixels; + s.ws_ypixel = ssh->heightPixels; - WMEMSET(&s, 0, sizeof s); - s.ws_col = ssh->curX; - s.ws_row = ssh->curY; - s.ws_xpixel = ssh->curXP; - s.ws_ypixel = ssh->curYP; ioctl(childFd, TIOCSWINSZ, &s); } #endif wolfSSH_SetTerminalResizeCtx(ssh, (void*)&childFd); + while (ChildRunning) { byte tmp[2]; fd_set readFds; diff --git a/src/internal.c b/src/internal.c index 7e9727cf6..7f7b54884 100644 --- a/src/internal.c +++ b/src/internal.c @@ -7132,6 +7132,243 @@ static int DoChannelClose(WOLFSSH* ssh, } +#define TTY_SET_CHAR(x,y,z) (x)[(y)] = (byte)(z) +#define TTY_SET_FLAG(x,y,z) (x) = (z) ? ((x) | (y)) : ((x) & ~(y)) + +int wolfSSH_DoModes(const byte* modes, word32 modesSz, int fd) +{ + WOLFSSH_TERMIOS term; + word32 idx = 0, arg; + + if (!modes || !modesSz || (modesSz % TERMINAL_MODE_SZ > 1)) + return -1; + /* + * Modes is a list of opcode-argument pairs. The opcodes are + * bytes and the arguments are uint32s. TTY_OP_END is an opcode + * that terminates the list. Of course, it isn't clear if + * TTY_OP_END has an arguement or note. The RFC doesn't say, + * but in operation it usually doesn't. Allow for an odd single + * byte left over. + */ + + tcgetattr(fd, &term); + + while (idx < modesSz && modes[idx] != WOLFSSH_TTY_OP_END + && modes[idx] < WOLFSSH_TTY_INVALID) { + + ato32(modes + idx + 1, &arg); + + switch (modes[idx]) { + /* Special Control Characters (c_cc) */ + case WOLFSSH_VINTR: + TTY_SET_CHAR(term.c_cc, VINTR, arg); + break; + case WOLFSSH_VQUIT: + TTY_SET_CHAR(term.c_cc, VQUIT, arg); + break; + case WOLFSSH_VERASE: + TTY_SET_CHAR(term.c_cc, VERASE, arg); + break; + case WOLFSSH_VKILL: + TTY_SET_CHAR(term.c_cc, VKILL, arg); + break; + case WOLFSSH_VEOF: + TTY_SET_CHAR(term.c_cc, VEOF, arg); + break; + case WOLFSSH_VEOL: + TTY_SET_CHAR(term.c_cc, VEOL, arg); + break; + case WOLFSSH_VEOL2: + TTY_SET_CHAR(term.c_cc, VEOL2, arg); + break; + case WOLFSSH_VSTART: + TTY_SET_CHAR(term.c_cc, VSTART, arg); + break; + case WOLFSSH_VSTOP: + TTY_SET_CHAR(term.c_cc, VSTOP, arg); + break; + case WOLFSSH_VSUSP: + TTY_SET_CHAR(term.c_cc, VSUSP, arg); + break; + case WOLFSSH_VDSUSP: + #ifdef VDSUSP + TTY_SET_CHAR(term.c_cc, VDSUSP, arg); + #endif + break; + case WOLFSSH_VREPRINT: + TTY_SET_CHAR(term.c_cc, VREPRINT, arg); + break; + case WOLFSSH_VWERASE: + TTY_SET_CHAR(term.c_cc, VWERASE, arg); + break; + case WOLFSSH_VLNEXT: + TTY_SET_CHAR(term.c_cc, VLNEXT, arg); + break; + case WOLFSSH_VFLUSH: + #ifdef VFLUSH + TTY_SET_CHAR(term.c_cc, VFLUSH, arg); + #endif + break; + case WOLFSSH_VSWTCH: + #ifdef VSWTCH + TTY_SET_CHAR(term.c_cc, VSWTCH, arg); + #endif + break; + case WOLFSSH_VSTATUS: + #ifdef VSTATUS + TTY_SET_CHAR(term.c_cc, VSTATUS, arg); + #endif + break; + case WOLFSSH_VDISCARD: + TTY_SET_CHAR(term.c_cc, VDISCARD, arg); + break; + + /* Input Modes (c_iflag) */ + case WOLFSSH_IGNPAR: + TTY_SET_FLAG(term.c_iflag, IGNPAR, arg); + break; + case WOLFSSH_PARMRK: + TTY_SET_FLAG(term.c_iflag, PARMRK, arg); + break; + case WOLFSSH_INPCK: + TTY_SET_FLAG(term.c_iflag, INPCK, arg); + break; + case WOLFSSH_ISTRIP: + TTY_SET_FLAG(term.c_iflag, ISTRIP, arg); + break; + case WOLFSSH_INLCR: + TTY_SET_FLAG(term.c_iflag, INLCR, arg); + break; + case WOLFSSH_IGNCR: + TTY_SET_FLAG(term.c_iflag, IGNCR, arg); + break; + case WOLFSSH_ICRNL: + TTY_SET_FLAG(term.c_iflag, ICRNL, arg); + break; + case WOLFSSH_IUCLC: + #ifdef IUCLC + TTY_SET_FLAG(term.c_iflag, IUCLC, arg); + #endif + break; + case WOLFSSH_IXON: + TTY_SET_FLAG(term.c_iflag, IXON, arg); + break; + case WOLFSSH_IXANY: + TTY_SET_FLAG(term.c_iflag, IXANY, arg); + break; + case WOLFSSH_IXOFF: + TTY_SET_FLAG(term.c_iflag, IXOFF, arg); + break; + case WOLFSSH_IMAXBEL: + TTY_SET_FLAG(term.c_iflag, IMAXBEL, arg); + break; + case WOLFSSH_IUTF8: + #ifdef IUTF8 + TTY_SET_FLAG(term.c_iflag, IUTF8, arg); + #endif + break; + + /* Local Modes (c_lflag) */ + case WOLFSSH_ISIG: + TTY_SET_FLAG(term.c_lflag, ISIG, arg); + break; + case WOLFSSH_ICANON: + TTY_SET_FLAG(term.c_lflag, ICANON, arg); + break; + case WOLFSSH_XCASE: + #ifdef XCASE + TTY_SET_FLAG(term.c_lflag, XCASE, arg); + #endif + break; + case WOLFSSH_ECHO: + TTY_SET_FLAG(term.c_lflag, ECHO, arg); + break; + case WOLFSSH_ECHOE: + TTY_SET_FLAG(term.c_lflag, ECHOE, arg); + break; + case WOLFSSH_ECHOK: + TTY_SET_FLAG(term.c_lflag, ECHOK, arg); + break; + case WOLFSSH_ECHONL: + TTY_SET_FLAG(term.c_lflag, ECHONL, arg); + break; + case WOLFSSH_NOFLSH: + TTY_SET_FLAG(term.c_lflag, NOFLSH, arg); + break; + case WOLFSSH_TOSTOP: + TTY_SET_FLAG(term.c_lflag, TOSTOP, arg); + break; + case WOLFSSH_IEXTEN: + TTY_SET_FLAG(term.c_lflag, IEXTEN, arg); + break; + case WOLFSSH_ECHOCTL: + TTY_SET_FLAG(term.c_lflag, ECHOCTL, arg); + break; + case WOLFSSH_ECHOKE: + TTY_SET_FLAG(term.c_lflag, ECHOKE, arg); + break; + case WOLFSSH_PENDIN: + #ifdef PENDIN + TTY_SET_FLAG(term.c_lflag, PENDIN, arg); + #endif + break; + + /* Output Modes (c_oflag) */ + case WOLFSSH_OPOST: + TTY_SET_FLAG(term.c_lflag, OPOST, arg); + break; + case WOLFSSH_OLCUC: + #ifdef OLCUC + TTY_SET_FLAG(term.c_lflag, OLCUC, arg); + #endif + break; + case WOLFSSH_ONLCR: + TTY_SET_FLAG(term.c_lflag, ONLCR, arg); + break; + case WOLFSSH_OCRNL: + TTY_SET_FLAG(term.c_lflag, OCRNL, arg); + break; + case WOLFSSH_ONOCR: + TTY_SET_FLAG(term.c_lflag, ONOCR, arg); + break; + case WOLFSSH_ONLRET: + TTY_SET_FLAG(term.c_lflag, ONLRET, arg); + break; + + /* Control Modes (c_cflag) */ + case WOLFSSH_CS7: + TTY_SET_FLAG(term.c_cflag, CS7, arg); + break; + case WOLFSSH_CS8: + TTY_SET_FLAG(term.c_cflag, CS8, arg); + break; + case WOLFSSH_PARENB: + TTY_SET_FLAG(term.c_cflag, PARENB, arg); + break; + case WOLFSSH_PARODD: + TTY_SET_FLAG(term.c_cflag, PARODD, arg); + break; + + /* Baud Rates */ + case WOLFSSH_TTY_OP_ISPEED: + cfsetispeed(&term, (speed_t)arg); + break; + case WOLFSSH_TTY_OP_OSPEED: + cfsetospeed(&term, (speed_t)arg); + break; + + default: + break; + } + idx += TERMINAL_MODE_SZ; + } + + tcsetattr(fd, TCSANOW, &term); + + return 0; +} + + static int DoChannelRequest(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) { @@ -7189,24 +7426,27 @@ static int DoChannelRequest(WOLFSSH* ssh, ret = GetUint32(&heightPixels, buf, len, &begin); if (ret == WS_SUCCESS) ret = GetStringRef(&modesSz, &modes, buf, len, &begin); - - WOLFSSH_UNUSED(modes); - WOLFSSH_UNUSED(modesSz); - if (ret == WS_SUCCESS) { + ssh->modes = (byte*)WMALLOC(modesSz, ssh->ctx->heap, 0); + if (ssh->modes == NULL) + ret = WS_MEMORY_E; + } + if (ret == WS_SUCCESS) { + ssh->modesSz = modesSz; + WMEMCPY(ssh->modes, modes, modesSz); WLOG(WS_LOG_DEBUG, " term = %s", term); WLOG(WS_LOG_DEBUG, " widthChar = %u", widthChar); WLOG(WS_LOG_DEBUG, " heightRows = %u", heightRows); WLOG(WS_LOG_DEBUG, " widthPixels = %u", widthPixels); WLOG(WS_LOG_DEBUG, " heightPixels = %u", heightPixels); - ssh->curX = widthChar; - ssh->curY = heightRows; - ssh->curXP = widthPixels; - ssh->curYP = heightPixels; + ssh->widthChar = widthChar; + ssh->heightRows = heightRows; + ssh->widthPixels = widthPixels; + ssh->heightPixels = heightPixels; if (ssh->termResizeCb) { if (ssh->termResizeCb(ssh, widthChar, heightRows, - widthPixels, heightPixels, ssh->termCtx) - != WS_SUCCESS) { + widthPixels, heightPixels, + ssh->termCtx) != WS_SUCCESS) { ret = WS_FATAL_ERROR; } } @@ -7276,11 +7516,14 @@ static int DoChannelRequest(WOLFSSH* ssh, WLOG(WS_LOG_DEBUG, " heightRows = %u", heightRows); WLOG(WS_LOG_DEBUG, " widthPixels = %u", widthPixels); WLOG(WS_LOG_DEBUG, " heightPixels = %u", heightPixels); - ssh->curX = widthChar; - ssh->curY = heightRows; + ssh->widthChar = widthChar; + ssh->heightRows = heightRows; + ssh->widthPixels = widthPixels; + ssh->heightPixels = heightPixels; if (ssh->termResizeCb) { - if (ssh->termResizeCb(ssh, widthChar, heightRows, widthPixels, - heightPixels, ssh->termCtx) != WS_SUCCESS) { + if (ssh->termResizeCb(ssh, widthChar, heightRows, + widthPixels, heightPixels, + ssh->termCtx) != WS_SUCCESS) { ret = WS_FATAL_ERROR; } } diff --git a/sshd_config b/sshd_config new file mode 100644 index 000000000..e69de29bb diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 3cd5b3776..c31b229e7 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -378,6 +378,7 @@ enum { #define UINT32_SZ 4 #define LENGTH_SZ UINT32_SZ #define SSH_PROTO_SZ 7 /* "SSH-2.0" */ +#define TERMINAL_MODE_SZ 5 /* opcode byte + argument uint32 */ #define AEAD_IMP_IV_SZ 4 #define AEAD_EXP_IV_SZ 8 #define AEAD_NONCE_SZ (AEAD_IMP_IV_SZ+AEAD_EXP_IV_SZ) @@ -814,10 +815,12 @@ struct WOLFSSH { #ifdef WOLFSSH_TERM WS_CallbackTerminalSize termResizeCb; void* termCtx; - word32 curX; /* current terminal width */ - word32 curY; /* current terminal height */ - word32 curXP; /* pixel width */ - word32 curYP; /* pixel height */ + word32 widthChar; /* current terminal width */ + word32 heightRows; /* current terminal height */ + word32 widthPixels; /* pixel width */ + word32 heightPixels; /* pixel height */ + byte* modes; + word32 modesSz; #endif }; @@ -1262,7 +1265,8 @@ enum TerminalModes { WOLFSSH_PARENB, WOLFSSH_PARODD, WOLFSSH_TTY_OP_ISPEED = 128, - WOLFSSH_TTY_OP_OSPEED + WOLFSSH_TTY_OP_OSPEED, + WOLFSSH_TTY_INVALID = 160 }; #endif /* WOLFSSH_TERM */ diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index ab315daad..10da1f1c7 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -282,6 +282,7 @@ typedef enum { 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*); WOLFSSH_API const char* wolfSSH_GetSessionCommand(const WOLFSSH*); WOLFSSH_API int wolfSSH_SetChannelType(WOLFSSH*, byte, byte*, word32); From 7c83d835c4cfe028e7e70ce0baaa511547c51a76 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 28 Dec 2023 15:20:11 -0800 Subject: [PATCH 06/11] wolfSSHd Terminal 1. Prep the SHELL variable inherited by the new shell to be equal to the user's shell. 2. Prep the new shell's $0 variable to be equal to the shell name prefixed with a '-', ie "/bin/bash" becomes "-bash". --- apps/wolfsshd/wolfsshd.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index bee94cda8..b8b3673f7 100644 --- a/apps/wolfsshd/wolfsshd.c +++ b/apps/wolfsshd/wolfsshd.c @@ -1204,6 +1204,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, /* Child process */ const char *args[] = {"-sh", NULL, NULL, NULL}; char cmd[MAX_COMMAND_SZ]; + char shell[MAX_COMMAND_SZ]; int ret; signal(SIGINT, SIG_DFL); @@ -1258,6 +1259,25 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, setenv("HOME", pPasswd->pw_dir, 1); setenv("LOGNAME", pPasswd->pw_name, 1); + setenv("SHELL", pPasswd->pw_shell, 1); + + if (pPasswd->pw_shell) { + word32 shellSz = (word32)WSTRLEN(pPasswd->pw_shell); + + if (shellSz < sizeof(shell)) { + char* cursor; + char* start; + + WSTRNCPY(shell, pPasswd->pw_shell, sizeof(shell)); + cursor = shell; + do { + start = cursor; + *cursor = '-'; + cursor = WSTRCHR(start, '/'); + } while (cursor && *cursor != '\0'); + args[0] = start; + } + } rc = chdir(pPasswd->pw_dir); if (rc != 0) { From 5c9beb6c50873fea737f7dfcf3708077ddd138b3 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Fri, 29 Dec 2023 16:38:34 -0800 Subject: [PATCH 07/11] wolfSSHd Terminal 1. Modified the ssh terminal size test to be agnostic to the version of sed used. 2. Add some guards around the mode setting code for ioctl() availability so it would build for Windows. --- apps/wolfsshd/test/sshd_term_size_test.sh | 18 ++++++++---------- src/internal.c | 6 ++++++ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/apps/wolfsshd/test/sshd_term_size_test.sh b/apps/wolfsshd/test/sshd_term_size_test.sh index 22d2f3a33..0a25fad54 100755 --- a/apps/wolfsshd/test/sshd_term_size_test.sh +++ b/apps/wolfsshd/test/sshd_term_size_test.sh @@ -26,16 +26,16 @@ COL=`tmux display -p -t test '#{pane_width}'` ROW=`tmux display -p -t test '#{pane_height}'` # get the terminals columns and lines -tmux send-keys -t test 'echo col=$COLUMNS row=$LINES' +tmux send-keys -t test 'echo;echo $COLUMNS $LINES;echo' tmux send-keys -t test 'ENTER' tmux capture-pane -t test -RESULT=`tmux show-buffer | grep -v echo | grep -v rejecting | grep "col="` +RESULT=$(tmux show-buffer | grep '^[0-9]* [0-9]*$') echo "$RESULT" echo "" echo "" -ROW_FOUND=`echo "$RESULT" | sed -e 's/.*[^0-9]\([0-9]\+\)[^0-9]*$/\1/'` -COL_FOUND=`echo "$RESULT" | sed -r 's/^[^0-9]*([0-9]+).*$/\1/'` +ROW_FOUND=$(echo "$RESULT" | sed -e 's/[0-9]* \([0-9]*\)/\1/') +COL_FOUND=$(echo "$RESULT" | sed -e 's/\([0-9]*\) [0-9]*/\1/') if [ "$COL" != "$COL_FOUND" ]; then echo "Col found was $COL_FOUND which does not match expected $COL" @@ -67,15 +67,13 @@ tmux new-session -d -x 50 -y 10 -s test "$TEST_CLIENT -t -u $USER -i $PRIVATE_KE # give the command a second to establish SSH connection sleep 0.5 -echo "New COL=$COL ROW=$ROW" - -tmux send-keys -t test 'echo col=$COLUMNS row=$LINES' +tmux send-keys -t test 'echo;echo $COLUMNS $LINES;echo' tmux send-keys -t test 'ENTER' tmux capture-pane -t test -RESULT=`tmux show-buffer | grep -v echo | grep -v rejecting | grep "col="` +RESULT=$(tmux show-buffer | grep '^[0-9]* [0-9]*$') -ROW_FOUND=`echo "$RESULT" | sed -e 's/.*[^0-9]\([0-9]\+\)[^0-9]*$/\1/'` -COL_FOUND=`echo "$RESULT" | sed -r 's/^[^0-9]*([0-9]+).*$/\1/'` +ROW_FOUND=$(echo "$RESULT" | sed -e 's/[0-9]* \([0-9]*\)/\1/') +COL_FOUND=$(echo "$RESULT" | sed -e 's/\([0-9]*\) [0-9]*/\1/') if [ "50" != "$COL_FOUND" ]; then echo "Col found was $COL_FOUND which does not match expected 50" diff --git a/src/internal.c b/src/internal.c index 7f7b54884..904f47efe 100644 --- a/src/internal.c +++ b/src/internal.c @@ -7132,6 +7132,9 @@ static int DoChannelClose(WOLFSSH* ssh, } +#if !defined(NO_TERMIOS) && defined(WOLFSSH_TERM) +#if defined(HAVE_SYS_IOCTL_H) + #define TTY_SET_CHAR(x,y,z) (x)[(y)] = (byte)(z) #define TTY_SET_FLAG(x,y,z) (x) = (z) ? ((x) | (y)) : ((x) & ~(y)) @@ -7368,6 +7371,9 @@ int wolfSSH_DoModes(const byte* modes, word32 modesSz, int fd) return 0; } +#endif /* HAVE_SYS_IOCTL_H */ +#endif /* !NO_TERMIOS && WOLFSSH_TERM */ + static int DoChannelRequest(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) From 12ad5f116e195f08eb7db7cf96c0cdda588dcbc1 Mon Sep 17 00:00:00 2001 From: gojimmypi Date: Thu, 28 Dec 2023 15:14:10 -0800 Subject: [PATCH 08/11] wolfssh .gitignore update; VS / VS Code / CMake / Build --- .gitignore | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/.gitignore b/.gitignore index c37eb63f4..978150b08 100644 --- a/.gitignore +++ b/.gitignore @@ -31,13 +31,21 @@ libtool libtool.m4 *.log *.gz +*.zip +*.bak +*.dummy +*.xcworkspace Makefile Makefile.in *.deps .dirstamp *.libs stamp-h* +src/stamp-h1 build-aux/ +wolfmqtt-config +build-test/ +build/ wolfssh-config aminclude.am @@ -71,6 +79,18 @@ client.plist # misc .DS_Store +# Visual Studio Code Workspace Files +*.vscode +*.userprefs +*.exe +*.dll +.vs +Backup +UpgradeLog.htm +*.aps +*.VC.db +*.filters + # VS debris *.sdf *.v11.suo @@ -88,3 +108,30 @@ DLL Release .cproject .project .settings + + +# auto-created CMake backups +**/CMakeLists.txt.old + +# VisualGDB +**/.visualgdb +**/*.vgdbproj.*.user + + +# Espressif sdk config default should be saved in sdkconfig.defaults +# we won't track the actual working sdkconfig files +/ide/Espressif/**/out/ +/ide/Espressif/**/sdkconfig +/ide/Espressif/**/sdkconfig.old + +# Espressif managed components to exclude: +/ide/Espressif/**/managed_components/** + +# Espressif managed component lock files to exclude. +# "In general, it's ok to have it under version control, however, it ties +# the solution to the exact version of ESP-IDF and will be ignored if an +# example is built against another IDF version or for a different target. +# So it's better to git ignore it for the examples." +/ide/Espressif/**/dependencies.lock + + From 600656bc8069201c248c3a3c5d28c6194334bb6f Mon Sep 17 00:00:00 2001 From: gojimmypi Date: Thu, 28 Dec 2023 15:21:37 -0800 Subject: [PATCH 09/11] gate PrivBeginPrefix/PrivSuffix; init typeSz in ssh.c --- src/ssh.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/ssh.c b/src/ssh.c index 4e3758d72..fcee2726b 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -1488,10 +1488,13 @@ union wolfSSH_key { static const char* PrivBeginOpenSSH = "-----BEGIN OPENSSH PRIVATE KEY-----"; static const char* PrivEndOpenSSH = "-----END OPENSSH PRIVATE KEY-----"; -static const char* PrivBeginPrefix = "-----BEGIN "; -/* static const char* PrivEndPrefix = "-----END "; */ -static const char* PrivSuffix = " PRIVATE KEY-----"; +#if !defined(NO_FILESYSTEM) && !defined(WOLFSSH_USER_FILESYSTEM) + /* currently only used in wolfSSH_ReadKey_file() */ + static const char* PrivBeginPrefix = "-----BEGIN "; + /* static const char* PrivEndPrefix = "-----END "; */ + static const char* PrivSuffix = " PRIVATE KEY-----"; +#endif static int DoSshPubKey(const byte* in, word32 inSz, byte** out, word32* outSz, const byte** outType, word32* outTypeSz, @@ -1503,7 +1506,7 @@ static int DoSshPubKey(const byte* in, word32 inSz, byte** out, char* type = NULL; char* key = NULL; int ret = WS_SUCCESS; - word32 newKeySz, typeSz; + word32 newKeySz, typeSz = 0; WOLFSSH_UNUSED(inSz); WOLFSSH_UNUSED(heap); From 321023e9090115dda225f60b73533bd2d268ea90 Mon Sep 17 00:00:00 2001 From: gojimmypi Date: Thu, 28 Dec 2023 15:31:13 -0800 Subject: [PATCH 10/11] Gate GetOpenSshKeyRsa with WOLFSSH_NO_RSA --- src/internal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/internal.c b/src/internal.c index 904f47efe..fdd4ca82e 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1073,7 +1073,7 @@ static INLINE int CalcRsaInverses(RsaKey* key) return ret; } - +#ifndef WOLFSSH_NO_RSA /* * Utility for GetOpenSshKey() to read in RSA keys. */ @@ -1105,7 +1105,7 @@ static int GetOpenSshKeyRsa(RsaKey* key, return ret; } - +#endif /* * Utility for GetOpenSshKey() to read in ECDSA keys. From d32051e2530870ff61ed5315803161b050c161d1 Mon Sep 17 00:00:00 2001 From: gojimmypi Date: Fri, 29 Dec 2023 09:44:00 -0800 Subject: [PATCH 11/11] Gate CalcRsaInverses on WOLFSSH_NO_RSA; Gate GetOpenSshKeyEcc on WOLFSSH_NO_ECDSA and WOLFSSH_NO_ECC --- src/internal.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/internal.c b/src/internal.c index fdd4ca82e..7c1791155 100644 --- a/src/internal.c +++ b/src/internal.c @@ -1048,6 +1048,7 @@ static INLINE int GetMpintToMp(mp_int* mp, } +#ifndef WOLFSSH_NO_RSA /* * 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. @@ -1073,7 +1074,6 @@ static INLINE int CalcRsaInverses(RsaKey* key) return ret; } -#ifndef WOLFSSH_NO_RSA /* * Utility for GetOpenSshKey() to read in RSA keys. */ @@ -1107,6 +1107,8 @@ static int GetOpenSshKeyRsa(RsaKey* key, } #endif + +#if !defined(WOLFSSH_NO_ECDSA) && !defined(WOLFSSH_NO_ECC) /* * Utility for GetOpenSshKey() to read in ECDSA keys. */ @@ -1134,7 +1136,7 @@ static int GetOpenSshKeyEcc(ecc_key* key, return ret; } - +#endif /* * Decodes an OpenSSH format key. @@ -1218,7 +1220,7 @@ static int GetOpenSshKey(WS_KeySignature *key, str, strSz, &subIdx); break; #endif - #ifndef WOLFSSH_NO_ECDSA + #if !defined(WOLFSSH_NO_ECDSA) && !defined(WOLFSSH_NO_ECC) case ID_ECDSA_SHA2_NISTP256: ret = GetOpenSshKeyEcc(&key->ks.ecc.key, str, strSz, &subIdx);