diff --git a/.github/workflows/arduino-release.yml b/.github/workflows/arduino-release.yml new file mode 100644 index 00000000..9041750b --- /dev/null +++ b/.github/workflows/arduino-release.yml @@ -0,0 +1,242 @@ +name: Arduino CI Build (2 of 4) Release Arduino wolfSSL for Local Examples + +# TODO - implement this once future wolfSSL is released +# +# Known to fail on current 5.8.2 wolfSSL Arduino Release +# +# See ardduino.yml - Arduino CI Build (3 of 4) Latest wolfSSL for Local Examples + +# +# Test local Arduino examples with published Arduino wolfssl +# +# These 4 workflows across 3 repos are interdependent for the current $REPO_OWNER: +# +# Arduino CI Build 1: https://github.com/$REPO_OWNER/wolfssl # /.github/workflows/arduino.yml +# - Builds Arduino library from local clone of wolfssl master branch +# - Fetches examples from https://github.com/$REPO_OWNER/wolfssl-examples +# +# THIS Arduino CI Build 2: https://github.com/$REPO_OWNER/wolfssl-examples # /.github/workflows/arduino-release.yml +# - Tests examples based on latest published release of Arduino library, NOT latest on wolfssl github. +# - Should be identical to Arduino CI Build 3 in every way but wolfssl install. +# - Copies only compile script from wolfssl-examples +# - Builds local examples +# - No other repos used +# +# Arduino CI Build 3: https://github.com/$REPO_OWNER/wolfssl-examples # /.github/workflows/arduino.yml +# - Fetches current wolfSSL from https://github.com/$REPO_OWNER/wolfssl +# - Creates an updated Arduino library +# - Compiles local examples +# - Contains the source of `compile-all-examples.sh` and respective board-list.txt +# +# Arduino CI Build 4: https://github.com/$REPO_OWNER/Arduino-wolfssl # /.github/workflows/arduino.yml +# - Assembles and installs an updated Arduino wolfssl library from LOCAL wolfssl master source +# - Copies only compile script copied from wolfssl-examples +# - Builds local examples +# - No other repos used +# +# +# ** NOTE TO MAINTAINERS ** +# +# Consider using winmerge or similar tool to keep the 4 arduino[-release].yml files in relative sync. +# Although there are some specific differences, most of the contents are otherwise identical. +# +# See https://github.com/wolfSSL/Arduino-wolfSSL +# +# To test locally: +# cd [your WOLFSSL_ROOT], e.g. cd /mnt/c/workspace/wolfssl-$USER +# [optional checkout] e.g. git checkout tags/v5.8.2-stable +# pushd ./IDE/ARDUINO +# export ARDUINO_ROOT="$HOME/Arduino/libraries" +# ./wolfssl-arduino.sh INSTALL +# cd [your WOLFSSL_EXAMPLES_ROOT] e.g. /mnt/c/workspace/wolfssl-examples-$USER +# + +# START OF COMMON SECTION +on: + push: + branches: [ '**', 'master', 'main', 'release/**' ] + paths: + - 'Arduino/**' + - '!Arduino/sketches/board_list.txt' # Not triggered on arduino.yml file. TODO remove this line after next Arduino wolfssl release + - '.github/workflows/arduino-release.yml' + pull_request: + branches: [ '**' ] + paths: + - 'Arduino/**' + - '!Arduino/sketches/board_list.txt' # Not triggered on arduino.yml file. TODO remove this line after next Arduino wolfssl release + - '.github/workflows/arduino-release.yml' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +# END OF COMMON SECTION + +jobs: + build: + # if: github.repository_owner == 'wolfssl' + runs-on: ubuntu-latest + env: + REPO_OWNER: ${{ github.repository_owner }} + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Install Arduino CLI + run: | + # Script to fetch and run install.sh from arduino/arduino-cli + + # The install script will test to see if the recently installed apps in in the path + # So set it up in advance: + mkdir -p "${PWD}/bin" + echo "${PWD}/bin" >> $GITHUB_PATH + + # Sets the install directory to a consistent path at the repo root. + ROOT_BIN="$GITHUB_WORKSPACE/bin" + + # Ensures that BINDIR exists before the installer runs + mkdir -p "$ROOT_BIN" + + # Save as a lobal environment variable + echo "$ROOT_BIN" >> "$GITHUB_PATH" + + # Download and run install script from Arduino: + # -S show errors; -L follow redirects; -v Verbose + set +e # don't abort on error + set -o pipefail + + curl -vSL --retry 5 --retry-delay 10 \ + https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh \ + | sh -x + rc=$? + c_rc=${PIPESTATUS[0]} # curl's exit code + s_rc=${PIPESTATUS[1]} # sh's exit code + + set -e # restore default abort-on-error + + # If there was a curl error, we have our own local copy that is more reliable and can add our own debugging + if [ "$rc" -ne 0 ]; then + echo "Primary install failed: curl=$c_rc, sh=$s_rc. Falling back..." >&2 + echo "Using local copy of arduino_install.sh" + pushd ./Arduino/sketches + chmod +x ./arduino_install.sh + + # Mimic curl install, does not use current directory: + BINDIR="$ROOT_BIN" sh -x ./arduino_install.sh + popd + else + echo "Alternative install script not needed." + fi + + - name: Confirm Arduino CLI install + run: arduino-cli version + + - name: Setup Arduino CLI + run: | + arduino-cli config init + arduino-cli core update-index + arduino-cli config add board_manager.additional_urls https://www.pjrc.com/teensy/package_teensy_index.json + arduino-cli core update-index + arduino-cli config add board_manager.additional_urls https://arduino.esp8266.com/stable/package_esp8266com_index.json + arduino-cli core update-index + arduino-cli core install esp32:esp32 # ESP32 + arduino-cli core install arduino:avr # Arduino Uno, Mega, Nano + arduino-cli core install arduino:sam # Arduino Due + arduino-cli core install arduino:samd # Arduino Zero + arduino-cli core install teensy:avr # PJRC Teensy + arduino-cli core install esp8266:esp8266 # ESP8266 + arduino-cli core install arduino:mbed_nano # nanorp2040connect + arduino-cli core install arduino:mbed_portenta # portenta_h7_m7 + arduino-cli core install arduino:mbed_edge + # sudo "/home/$USER/.arduino15/packages/arduino/hardware/mbed_nano/4.2.4/post_install.sh" + arduino-cli core install arduino:renesas_uno + arduino-cli lib install "ArduinoJson" # Example dependency + arduino-cli lib install "WiFiNINA" # ARDUINO_SAMD_NANO_33_IOT + arduino-cli lib install "Ethernet" # Install Ethernet library + arduino-cli lib install "Bridge" # Pseudo-network for things like arduino:samd:tian + + - name: Set job environment variables + run: | + # Script to assign some common environment variables after everything is installed + + ICON_OK=$(printf "\xE2\x9C\x85") + ICON_FAIL=$(printf "\xE2\x9D\x8C") + + echo "GITHUB_WORK=$(realpath "$GITHUB_WORKSPACE/../..")" >> "$GITHUB_ENV" + echo "ARDUINO_ROOT=$(realpath "$HOME/Arduino/libraries")" >> "$GITHUB_ENV" + + # Show repo-specific location of examples: + echo "WOLFSSL_EXAMPLES_ROOT=$(realpath "./Arduino/sketches")" >> "$GITHUB_ENV" + + # Show predefined summary: + echo "GITHUB_WORKSPACE = $GITHUB_WORKSPACE" + + # Show assigned build:env values (e.g. "wolfssl", "gojimmpi" or other owners): + echo "REPO_OWNER = $REPO_OWNER" + + # Show our custom values: + echo "GITHUB_WORK = $GITHUB_WORK" + echo "ARDUINO_ROOT = $ARDUINO_ROOT" + + # WOLFSSL_EXAMPLES_ROOT is the report root, not example location + echo "WOLFSSL_EXAMPLES_ROOT = $WOLFSSL_EXAMPLES_ROOT" + + - name: Show wolfssl-examples + run: | + # The examples are local in this wolfssl-example repo, but should have been copied to library, above + ls ./Arduino/sketches + + # end Show wolfssl-examples + + # - name: Shallow clone wolfssl + # + # not used here, we'll install with arduino-cli in next step + + # + # These comments are mainly here to help align with arduino.yml source side-by-side sync + # + # end wolfssl source + + - name: Install wolfSSL Published Arduino library + + run: | + # Install wolfssl via latest published version with arduino-cli lib install + + + arduino-cli lib install "wolfSSL" + + # End Install wolfSSL Arduino library + + - name: List installed Arduino libraries + run: arduino-cli lib list + + # This will fail with Arduino published wolfSSL v5.7.6 and older + # as the examples moved. See https://github.com/wolfSSL/wolfssl/pull/8514 + # + - name: Compile Arduino Sketches for Various Boards + run: | + # Call the compile-all-examples.sh script to compile all the examples for each of the fqbn names in the local copy of board_list.txt + + echo "Current directory = $PWD" + echo "ARDUINO_ROOT = $ARDUINO_ROOT" + echo "WOLFSSL_EXAMPLES_ROOT = $WOLFSSL_EXAMPLES_ROOT" + + pushd ./Arduino/sketches + chmod +x ./compile-all-examples.sh + + # The script expects all the examples to be in the current directory. + # So copy from local directory to newly instlled wolfssl arduino library to compile there. + cp ./compile-all-examples.sh "$ARDUINO_ROOT/wolfssl/examples/compile-all-examples.sh" + cp ./board_list.txt "$ARDUINO_ROOT/wolfssl/examples/board_list.txt" + + # TODO Use standard board_list.txt after next release of wolfSSL + cp ./board_list_v5.8.2.txt "$ARDUINO_ROOT/wolfssl/examples/board_list_v5.8.2.txt" + + # Compile the Arduino library examples in-place + pushd "$ARDUINO_ROOT/wolfssl/examples/" + echo "PWD=$PWD" + ./compile-all-examples.sh board_list_v5.8.2.txt + popd + popd + + # End Compile Arduino Sketches for Various Boards diff --git a/.github/workflows/arduino.yml b/.github/workflows/arduino.yml index 72356099..3b9933a5 100644 --- a/.github/workflows/arduino.yml +++ b/.github/workflows/arduino.yml @@ -1,13 +1,64 @@ -name: Arduino CI Build +name: Arduino CI Build (3 of 4) Latest wolfSSL for Local Examples +# +# Test local Arduino examples with clone of LATEST github master branch wolfssl +# +# These 4 workflows across 3 repos are interdependent for the current $REPO_OWNER: +# +# Arduino CI Build 1: https://github.com/$REPO_OWNER/wolfssl # /.github/workflows/arduino.yml +# - Builds Arduino library from local clone of wolfssl master branch +# - Fetches examples from https://github.com/$REPO_OWNER/wolfssl-examples +# +# Arduino CI Build 2: https://github.com/$REPO_OWNER/wolfssl-examples # /.github/workflows/arduino-release.yml +# - Tests examples based on latest published release of Arduino library, NOT latest on wolfssl github. +# - Should be identical to Arduino CI Build 3 in every way but wolfssl install. +# - Copies only compile script from wolfssl-examples +# - Builds local examples +# - No other repos used +# +# THIS Arduino CI Build 3: https://github.com/$REPO_OWNER/wolfssl-examples # /.github/workflows/arduino.yml +# - Fetches current wolfSSL from https://github.com/$REPO_OWNER/wolfssl +# - Creates an updated Arduino library +# - Compiles local examples +# - Contains the source of `compile-all-examples.sh` and respective board-list.txt +# +# Arduino CI Build 4: https://github.com/$REPO_OWNER/Arduino-wolfssl # /.github/workflows/arduino.yml +# - Assembles and installs an updated Arduino wolfssl library from LOCAL wolfssl master source +# - Copies only compile script copied from wolfssl-examples +# - Builds local examples +# - No other repos used +# +# +# ** NOTE TO MAINTAINERS ** +# +# Consider using winmerge or similar tool to keep the 4 arduino[-release].yml files in relative sync. +# Although there are some specific differences, most of the contents are otherwise identical. +# # See https://github.com/wolfSSL/Arduino-wolfSSL +# +# To test locally: +# cd [your WOLFSSL_ROOT], e.g. cd /mnt/c/workspace/wolfssl-$USER +# [optional checkout] e.g. git checkout tags/v5.8.2-stable +# pushd ./IDE/ARDUINO +# export ARDUINO_ROOT="$HOME/Arduino/libraries" +# ./wolfssl-arduino.sh INSTALL +# cd [your WOLFSSL_EXAMPLES_ROOT] e.g. /mnt/c/workspace/wolfssl-examples-$USER +# # START OF COMMON SECTION on: push: - branches: [ 'master', 'main', 'release/**' ] + branches: [ '**', 'master', 'main', 'release/**' ] + paths: + - 'Arduino/**' + - '!Arduino/sketches/board_list_v5.8.2.txt' # Not triggered on arduino-release.yml file. TODO remove this line after next Arduino wolfssl release + - '.github/workflows/arduino.yml' pull_request: - branches: [ '*' ] + branches: [ '**' ] + paths: + - 'Arduino/**' + - '!Arduino/sketches/board_list_v5.8.2.txt' # Not triggered on arduino-release.yml file. TODO remove this line after next Arduino wolfssl release + - '.github/workflows/arduino.yml' workflow_dispatch: concurrency: @@ -17,16 +68,62 @@ concurrency: jobs: build: - if: github.repository_owner == 'wolfssl' + # if: github.repository_owner == 'wolfssl' runs-on: ubuntu-latest + env: + REPO_OWNER: ${{ github.repository_owner }} steps: - name: Checkout Repository uses: actions/checkout@v4 - name: Install Arduino CLI run: | - curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh - echo "$(pwd)/bin" >> $GITHUB_PATH + # Script to fetch and run install.sh from arduino/arduino-cli + + # The install script will test to see if the recently installed apps in in the path + # So set it up in advance: + mkdir -p "${PWD}/bin" + echo "${PWD}/bin" >> $GITHUB_PATH + + # Sets the install directory to a consistent path at the repo root. + ROOT_BIN="$GITHUB_WORKSPACE/bin" + + # Ensures that BINDIR exists before the installer runs + mkdir -p "$ROOT_BIN" + + # Save as a lobal environment variable + echo "$ROOT_BIN" >> "$GITHUB_PATH" + + # Download and run install script from Arduino: + # -S show errors; -L follow redirects; -v Verbose + set +e # don't abort on error + set -o pipefail + + curl -vSL --retry 5 --retry-delay 10 \ + https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh \ + | sh -x + rc=$? + c_rc=${PIPESTATUS[0]} # curl's exit code + s_rc=${PIPESTATUS[1]} # sh's exit code + + set -e # restore default abort-on-error + + # If there was a curl error, we have our own local copy that is more reliable and can add our own debugging + if [ "$rc" -ne 0 ]; then + echo "Primary install failed: curl=$c_rc, sh=$s_rc. Falling back..." >&2 + echo "Using local copy of arduino_install.sh" + pushd ./Arduino/sketches + chmod +x ./arduino_install.sh + + # Mimic curl install, does not use current directory: + BINDIR="$ROOT_BIN" sh -x ./arduino_install.sh + popd + else + echo "Alternative install script not needed." + fi + + - name: Confirm Arduino CLI install + run: arduino-cli version - name: Setup Arduino CLI run: | @@ -36,133 +133,151 @@ jobs: arduino-cli core update-index arduino-cli config add board_manager.additional_urls https://arduino.esp8266.com/stable/package_esp8266com_index.json arduino-cli core update-index - arduino-cli core install esp32:esp32 # ESP32 - arduino-cli core install arduino:avr # Arduino Uno, Mega, Nano - arduino-cli core install arduino:sam # Arduino Due - arduino-cli core install arduino:samd # Arduino Zero - arduino-cli core install teensy:avr # PJRC Teensy - arduino-cli core install esp8266:esp8266 # ESP8266 - arduino-cli lib install "ArduinoJson" # Example dependency - arduino-cli lib install "WiFiNINA" # ARDUINO_SAMD_NANO_33_IOT - arduino-cli lib install "Ethernet" # Install Ethernet library - - # arduino-cli lib install "wolfSSL" # Install wolfSSL library from Arduino - - # Install current wolfSSL as an Arduino library: + arduino-cli core install esp32:esp32 # ESP32 + arduino-cli core install arduino:avr # Arduino Uno, Mega, Nano + arduino-cli core install arduino:sam # Arduino Due + arduino-cli core install arduino:samd # Arduino Zero + arduino-cli core install teensy:avr # PJRC Teensy + arduino-cli core install esp8266:esp8266 # ESP8266 + arduino-cli core install arduino:mbed_nano # nanorp2040connect + arduino-cli core install arduino:mbed_portenta # portenta_h7_m7 + arduino-cli core install arduino:mbed_edge + # sudo "/home/$USER/.arduino15/packages/arduino/hardware/mbed_nano/4.2.4/post_install.sh" + arduino-cli core install arduino:renesas_uno + arduino-cli lib install "ArduinoJson" # Example dependency + arduino-cli lib install "WiFiNINA" # ARDUINO_SAMD_NANO_33_IOT + arduino-cli lib install "Ethernet" # Install Ethernet library + arduino-cli lib install "Bridge" # Pseudo-network for things like arduino:samd:tian + + - name: Set job environment variables + run: | + # Script to assign some common environment variables after everything is installed + + ICON_OK=$(printf "\xE2\x9C\x85") + ICON_FAIL=$(printf "\xE2\x9D\x8C") + + echo "GITHUB_WORK=$(realpath "$GITHUB_WORKSPACE/../..")" >> "$GITHUB_ENV" + echo "ARDUINO_ROOT=$(realpath "$HOME/Arduino/libraries")" >> "$GITHUB_ENV" + + # Show repo-specific location of examples: + echo "WOLFSSL_EXAMPLES_ROOT=$(realpath "./Arduino/sketches")" >> "$GITHUB_ENV" + + # Show predefined summary: + echo "GITHUB_WORKSPACE = $GITHUB_WORKSPACE" + + # Show assigned build:env values (e.g. "wolfssl", "gojimmpi" or other owners): + echo "REPO_OWNER = $REPO_OWNER" + + # Show our custom values: + echo "GITHUB_WORK = $GITHUB_WORK" + echo "ARDUINO_ROOT = $ARDUINO_ROOT" + + # WOLFSSL_EXAMPLES_ROOT is the report root, not example location + echo "WOLFSSL_EXAMPLES_ROOT = $WOLFSSL_EXAMPLES_ROOT" + + - name: Show wolfssl-examples + run: | + # The examples are local in this wolfssl-example repo, but should have been copied to library, above + ls ./Arduino/sketches + + # end Show wolfssl-examples + - name: Shallow clone wolfssl run: | - git clone --depth 1 https://github.com/wolfSSL/wolfssl.git - echo "Checking Arduino library directories..." + # Clone the wolfssl to use for example build + + # TODO remove after merge + REPO_OWNER=gojimmypi + # End TODO + + git clone --depth 1 https://github.com/$REPO_OWNER/wolfssl.git + + # Assign your PR branch for testing here: + THIS_PR_BRANCH="" + + echo "REPO_OWNER=$REPO_OWNER" + + # TODO remove after merge + # A user-specific branch assignment + if [[ "$REPO_OWNER" == "gojimmypi" ]]; then + THIS_PR_BRANCH="pr-arduino-testing" + else + echo "unexpected repo owner!" + fi + # END TODO + + # If a branch is assigned for current repo user, checkout + if [ -z "$THIS_PR_BRANCH" ]; then + echo "Assign your PR branch name for testing" + else + # fetch open PR changes + pushd wolfssl + git remote add $REPO_OWNER https://github.com/$REPO_OWNER/wolfssl.git + git fetch --depth 1 "$REPO_OWNER" "$THIS_PR_BRANCH" + git checkout "$THIS_PR_BRANCH" + popd + fi + # end wolfssl source - name: Install wolfSSL Arduino library run: | - pushd wolfssl/IDE/ARDUINO + # Install wolfssl via wolfssl-arduino.sh install script + + # Even though the examples are in this library, we'll test as installed for library publishing. + # When WOLFSSL_EXAMPLES_ROOT is set, the examples will be copied from that path to the published library. + # WOLFSSL_EXAMPLES_ROOT is the repo root, not example directory location (./Arduino/sketches) within. + export WOLFSSL_EXAMPLES_ROOT=$(realpath "./") - # Set default ARDUINO_ROOT. TODO: once script is updated, this should be removed. - export ARDUINO_ROOT="$HOME/Arduino/libraries" + # Confirm ARDUINO_ROOT to install the wolfSSL library, see above "Set job environment variables" + echo "PWD = $PWD" + echo "ARDUINO_ROOT = $ARDUINO_ROOT" + echo "WOLFSSL_EXAMPLES_ROOT = $WOLFSSL_EXAMPLES_ROOT" + ls ./Arduino/sketches - bash wolfssl-arduino.sh INSTALL # Install wolfSSL library + if [ -z "$WOLFSSL_EXAMPLES_ROOT" ]; then + echo "$ICON_FAIL ERROR: Tests should be performed on in-place examples. WOLFSSL_EXAMPLES_ROOT is blank" + fi + + # The install script is in the wolfssl repo, in /IDE/ARDUINO directory. + # Only explicit source code is copied to the Arduino library. + # Edit wolfssl-arduino.sh as needed for new examples. + pushd ./wolfssl/IDE/ARDUINO + chmod +x ./wolfssl-arduino.sh + bash ./wolfssl-arduino.sh INSTALL # Install wolfSSL as Arduino library in ARDUINO_ROOT popd + echo "Examples installed in $ARDUINO_ROOT/wolfssl/examples" + ls "$ARDUINO_ROOT/wolfssl/examples" -al + + # End Install wolfSSL Arduino library + + - name: List installed Arduino libraries + run: arduino-cli lib list + # This will fail with Arduino published wolfSSL v5.7.6 and older - # See https://github.com/wolfSSL/wolfssl/pull/8514 - # Pending: "arduino:sam:arduino_due_x" - - name: Compile Arduino Sketches for various boards + # as the examples moved. See https://github.com/wolfSSL/wolfssl/pull/8514 + # + - name: Compile Arduino Sketches for Various Boards run: | - set +e - SUCCESS=true - for BOARD in "arduino:avr:uno" "esp32:esp32:esp32" "arduino:avr:mega" "arduino:avr:nano" "arduino:samd:arduino_zero_native" "esp8266:esp8266:generic" "teensy:avr:teensy40"; do - echo "Compiling for $BOARD" - for EXAMPLE in $(find Arduino/sketches -mindepth 1 -maxdepth 1 -type d); do - - # skip known no-wifi SAMD boards - if [[ "$BOARD" =~ "arduino:samd:arduino_zero_native" && ( "$EXAMPLE" =~ "wolfssl_server" || "$EXAMPLE" =~ "wolfssl_client" || "$EXAMPLE" =~ "test" ) ]]; then - echo "Skipping $EXAMPLE for $BOARD (No WiFi support)" - continue - fi - - # skip known no-wifi AVR boards - if [[ "$BOARD" =~ ^arduino:avr:(uno|mega|nano)$ ]] && \ - ( [[ "$EXAMPLE" =~ "wolfssl_server" ]] || \ - [[ "$EXAMPLE" =~ "wolfssl_client" ]] || \ - [[ "$EXAMPLE" =~ "test" ]] ); then - echo "Skipping $EXAMPLE for $BOARD (No WiFi support)" - continue - fi - - # skip known no-wifi teensy AVR boards - if [[ "$BOARD" =~ ^teensy:avr:(teensy40)$ ]] && \ - ( [[ "$EXAMPLE" =~ "wolfssl_server" ]] || \ - [[ "$EXAMPLE" =~ "wolfssl_client" ]] || \ - [[ "$EXAMPLE" =~ "test" ]] ); then - echo "Skipping $EXAMPLE for $BOARD (needs ethernet update)" - continue - fi - - # skip examples other than template and version for known tiny memory boards - if [[ "$BOARD" =~ ( "arduino:avr:uno"|"arduino:avr:nano" ) && ( "$EXAMPLE" != "template" ) && ( "$EXAMPLE" != "wolfssl_version" ) ]]; then - echo "Skipping $EXAMPLE for $BOARD (memory limited)" - continue - fi - - # TODO: new template known to fail. Fixed in https://github.com/wolfSSL/wolfssl/pull/8514 - if [[ "$EXAMPLE" =~ "Arduino/sketches/template" ]]; then - echo "Skipping $EXAMPLE for $BOARD (needs code update. see wolfssl/pull/8514)" - continue - fi - - # TODO: new wolfssl_AES_CTR known to fail. Fixed in https://github.com/wolfSSL/wolfssl/pull/8514 - if [[ "$EXAMPLE" =~ "Arduino/sketches/wolfssl_AES_CTR" ]]; then - echo "Skipping $EXAMPLE for $BOARD (needs updated user_settings.h - see wolfssl/pull/8514)" - continue - fi - - # TODO skip Compiling Arduino/sketches/wolfssl_version for arduino:avr:mega - if [[ "$BOARD" =~ "arduino:avr:mega" && "$EXAMPLE" =~ "Arduino/sketches/wolfssl_version" ]]; then - echo "Skipping $EXAMPLE for $BOARD (needs updated code - see wolfssl/pull/8514)" - continue - fi - - # TODO skip Compiling Arduino/sketches/wolfssl_version for arduino:avr:uno - if [[ "$BOARD" =~ ^arduino:avr:(uno|mega|nano)$ ]] && \ - ( [[ "$EXAMPLE" =~ "wolfssl_version" ]] ); then - echo "Skipping $EXAMPLE for $BOARD (fixed in see wolfssl/pull/8514)" - continue - fi - - if [[ "$BOARD" =~ "arduino:avr:uno" && "$EXAMPLE" =~ "Arduino/sketches/wolfssl_version" ]]; then - echo "Skipping $EXAMPLE for $BOARD (needs updated code - see wolfssl/pull/8514)" - continue - fi - - # TODO skip ESP8266 - if [[ "$BOARD" =~ "esp8266:esp8266:generic" ]]; then - echo "Skipping $EXAMPLE for $BOARD (needs testing)" - continue - fi - - # If otherwise not excluded, compile this $EXAMPLE for this $BOARD - echo "Compiling $EXAMPLE for $BOARD" - arduino-cli compile --fqbn $BOARD "$EXAMPLE" - EXIT_CODE=$? - if [ "$EXIT_CODE" -ne 0 ]; then - echo "❌ Compilation failed for $EXAMPLE on $BOARD (Exit code: $EXIT_CODE)" - SUCCESS=false - else - echo "✅ Compilation succeeded for $EXAMPLE on $BOARD" - fi - done - done - - if [ "$SUCCESS" = true ]; then - echo "✅ All sketches compiled successfully!" - else - echo "❌ One or more sketches failed to compile." - exit 1 - fi + # Call the compile-all-examples.sh script to compile all the examples for each of the fqbn names in the local copy of board_list.txt + + echo "Current directory = $PWD" + echo "ARDUINO_ROOT = $ARDUINO_ROOT" + echo "WOLFSSL_EXAMPLES_ROOT = $WOLFSSL_EXAMPLES_ROOT" + + pushd ./Arduino/sketches + chmod +x ./compile-all-examples.sh + + # The script expects all the examples to be in the current directory. + # So copy from local directory to newly instlled wolfssl arduino library to compile there. + cp ./compile-all-examples.sh "$ARDUINO_ROOT/wolfssl/examples/compile-all-examples.sh" + cp ./board_list.txt "$ARDUINO_ROOT/wolfssl/examples/board_list.txt" + + # Compile the Arduino library examples in-place + pushd "$ARDUINO_ROOT/wolfssl/examples/" + echo "PWD=$PWD" + ./compile-all-examples.sh ./board_list.txt + popd + popd - - name: Upload Compilation Artifacts - uses: actions/upload-artifact@v4 - with: - name: compiled-sketch - path: Arduino/sketches/template/build/* + # End Compile Arduino Sketches for Various Boards diff --git a/.gitignore b/.gitignore index 863d4bde..1ff16e0a 100644 --- a/.gitignore +++ b/.gitignore @@ -375,3 +375,6 @@ tpm/evp_tpm /Arduino/**/Output/* /Arduino/**/TraceReports/* /Arduino/**/.visualgdb/* +/Arduino/sketches/output.log +/**/*.bak + diff --git a/Arduino/README.md b/Arduino/README.md index efcfca77..6b5be0d5 100644 --- a/Arduino/README.md +++ b/Arduino/README.md @@ -14,6 +14,8 @@ Functional examples: - [sketches/wolfssl_AES_CTR](./sketches/wolfssl_AES_CTR/README.md) AES CTR Encrypt / decrypt. - [sketches/wolfssl_client](./sketches/wolfssl_client/README.md) TLS Client. - [sketches/wolfssl_server](./sketches/wolfssl_server/README.md) TLS Server. +- [sketches/wolfssl_client_dtls](./sketches/wolfssl_client_dtls/README.md) DTLS Client. +- [sketches/wolfssl_server_dtls](./sketches/wolfssl_server_dtls/README.md) DTLS Server. Both the `template` and `wolfssl_AES_CTR` examples include VisualGDB project files. @@ -51,6 +53,34 @@ from [stm32duino/Arduino_Core_STM32](https://github.com/stm32duino/Arduino_Core_ https://github.com/stm32duino/BoardManagerFiles/raw/main/package_stmicroelectronics_index.json ``` +or + +``` +https://raw.githubusercontent.com/stm32duino/BoardManagerFiles/main/package_stmicroelectronics_index.json +``` + +ESP8266 Support uses this: + +``` +http://arduino.esp8266.com/stable/package_esp8266com_index.json +``` + +STM32Duino: + +``` +http://dan.drown.org/stm32duino/package_STM32duino_index.json, +``` + +Teensy: +``` +https://www.pjrc.com/teensy/package_teensy_index.json +``` + +There are Arduino-specific, compile-time (macros & includes) of interest for these files: + +- [settings.h]() +- [settings.h]() + ## Using wolfSSL from the Arduino IDE The Official wolfSSL: https://github.com/wolfSSL/arduino-wolfSSL See [PR #1](https://github.com/wolfSSL/Arduino-wolfSSL/pull/1). @@ -226,3 +256,9 @@ Build and run `testwolfcrypt`. ./configure --enable-all make clean && make && ./wolfcrypt/test/testwolfcrypt ``` + +### Testing + +See the enclose [board_list.txt](./board_list.txt) file: a list of fully qualified board names +that is used by the [github/workflows/arduino.yml](/github/workflows/arduino.yml) action. + diff --git a/Arduino/sketches/README.md b/Arduino/sketches/README.md index 5fc0004e..7278ec72 100644 --- a/Arduino/sketches/README.md +++ b/Arduino/sketches/README.md @@ -6,14 +6,32 @@ There are currently five example Arduino sketches: * [wolfssl_AES_CTR](./wolfssl_AES_CTR/README.md): Basic AES CTR Encryption / Decryption example. * [wolfssl_client](./wolfssl_client/README.md): Basic TLS listening client. * [wolfssl_server](./wolfssl_server/README.md): Basic TLS server. +* [wolfssl_client_dtls](./wolfssl_client_dtls/README.md): Basic DTLS listening client. +* [wolfssl_server_dtls](./wolfssl_server_dtls/README.md): Basic DTLS server. * [wolfssl_version](./wolfssl_version/README.md): Bare-bones wolfSSL example. Examples have been most recently confirmed operational on the -[Arduino IDE](https://www.arduino.cc/en/software) 2.2.1. +[Arduino IDE](https://www.arduino.cc/en/software) 2.3.6. For examples on other platforms, see the [IDE directory](https://github.com/wolfssl/wolfssl/tree/master/IDE). Additional wolfssl examples can be found at [wolfSSL/wolfssl-examples](https://github.com/wolfSSL/wolfssl-examples/). +## Testing + +See GitHub workflow files: + +- [wolfssl/arduino.yml](https://github.com/wolfssl/wolfssl/blob/master/.github/workflows/arduino.yml) Arduino CI Build (1 of 4) wolfssl +- [wolfssl-examples/arduino-release.yml](https://github.com/wolfssl/wolfssl-examples/blob/master/.github/workflows/arduino-release.yml) Arduino CI Build (2 of 4) Release Arduino wolfSSL for Local Examples +- [wolfssl-examples/arduino.yml](https://github.com/wolfssl/wolfssl-examples/blob/master/.github/workflows/arduino.yml) Arduino CI Build (3 of 4) Latest wolfSSL for Local Examples +- [Arduino-wolfSSL](https://github.com/wolfssl/Arduino-wolfSSL/blob/master/.github/workflows/arduino.yml) Arduino CI Build (4 of 4) Arduino-wolfSSL + +Note that the local files here are copied to other repositories as needed from the workflow jobs: + +- `arduino_install.sh` Local copy of https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh +- `board_list.txt` Comprehensive known tested boards, used by GitHub actions in wolfssl, Arduino-wolfssl, and this repo. +- `board_list_v5.8.2_.txt` Release v5.8.2 known tested boards, used by GitHub actions in wolfssl, Arduino-wolfssl, and this repo. +- `compile-all-examples.sh` Compile all examples for all sketches in current directory. + ## Using wolfSSL The typical include will look something like this: diff --git a/Arduino/sketches/arduino_install.sh b/Arduino/sketches/arduino_install.sh new file mode 100644 index 00000000..bd1ff02c --- /dev/null +++ b/Arduino/sketches/arduino_install.sh @@ -0,0 +1,243 @@ +#!/bin/sh +# Source: https://github.com/arduino/tooling-project-assets/blob/main/other/installation-script/install.sh + +# The original version of this script (https://github.com/Masterminds/glide.sh/blob/master/get) is licensed under the +# MIT license. See https://github.com/Masterminds/glide/blob/master/LICENSE for more details and copyright notice. + +# This local copy at wolfSSL was created for GitHub workflow files that occasionally would fail to fetch at run. + +PROJECT_OWNER="arduino" +PROJECT_NAME="arduino-cli" + +# BINDIR represents the local bin location, defaults to ./bin. +EFFECTIVE_BINDIR="" +DEFAULT_BINDIR="$PWD/bin" +TEMPDIR="${TMPDIR:-${TEMP:-${TMP:-/tmp}}}" + +fail() { + echo "$1" + exit 1 +} + +initDestination() { + if [ -n "$BINDIR" ]; then + if [ ! -d "$BINDIR" ]; then + # The second instance of $BINDIR is intentionally a literal in this message. + # shellcheck disable=SC2016 + fail "$BINDIR "'($BINDIR)'" folder not found. Please create it before continuing." + fi + EFFECTIVE_BINDIR="$BINDIR" + else + if [ ! -d "$DEFAULT_BINDIR" ]; then + mkdir "$DEFAULT_BINDIR" + fi + EFFECTIVE_BINDIR="$DEFAULT_BINDIR" + fi + echo "Installing in $EFFECTIVE_BINDIR" +} + +initArch() { + ARCH=$(uname -m) + case $ARCH in + armv5*) ARCH="armv5" ;; + armv6*) ARCH="ARMv6" ;; + armv7*) ARCH="ARMv7" ;; + aarch64) ARCH="ARM64" ;; + arm64) ARCH="ARM64" ;; + x86) ARCH="32bit" ;; + x86_64) ARCH="64bit" ;; + i686) ARCH="32bit" ;; + i386) ARCH="32bit" ;; + esac + echo "ARCH=$ARCH" +} + +initFallbackArch() { + case "${OS}_${ARCH}" in + macOS_ARM64) + # Rosetta 2 allows applications built for x86-64 hosts to run on the ARM 64-bit M1 processor + FALLBACK_ARCH='64bit' + ;; + esac +} + +initOS() { + OS=$(uname -s) + case "$OS" in + Linux*) OS='Linux' ;; + Darwin*) OS='macOS' ;; + MINGW*) OS='Windows' ;; + MSYS*) OS='Windows' ;; + esac + echo "OS=$OS" +} + +initDownloadTool() { + if command -v "curl" >/dev/null 2>&1; then + DOWNLOAD_TOOL="curl" + elif command -v "wget" >/dev/null 2>&1; then + DOWNLOAD_TOOL="wget" + else + fail "You need curl or wget as download tool. Please install it first before continuing" + fi + echo "Using $DOWNLOAD_TOOL as download tool" +} + +# checkLatestVersion() sets the CHECKLATESTVERSION_TAG variable to the latest version +checkLatestVersion() { + # Use the GitHub releases webpage to find the latest version for this project + # so we don't get rate-limited. + CHECKLATESTVERSION_REGEX="v\?[0-9][A-Za-z0-9\.-]*" + CHECKLATESTVERSION_LATEST_URL="https://github.com/${PROJECT_OWNER}/${PROJECT_NAME}/releases/latest" + if [ "$DOWNLOAD_TOOL" = "curl" ]; then + CHECKLATESTVERSION_TAG=$(curl -SsL $CHECKLATESTVERSION_LATEST_URL | grep -o "Release $CHECKLATESTVERSION_REGEX · ${PROJECT_OWNER}/${PROJECT_NAME}" | grep -o "$CHECKLATESTVERSION_REGEX") + elif [ "$DOWNLOAD_TOOL" = "wget" ]; then + CHECKLATESTVERSION_TAG=$(wget -q -O - $CHECKLATESTVERSION_LATEST_URL | grep -o "<title>Release $CHECKLATESTVERSION_REGEX · ${PROJECT_OWNER}/${PROJECT_NAME}" | grep -o "$CHECKLATESTVERSION_REGEX") + fi + if [ "$CHECKLATESTVERSION_TAG" = "" ]; then + echo "Cannot determine latest tag." + exit 1 + fi +} + +getFile() { + GETFILE_URL="$1" + GETFILE_FILE_PATH="$2" + if [ "$DOWNLOAD_TOOL" = "curl" ]; then + GETFILE_HTTP_STATUS_CODE=$(curl --silent --show-error --write-out '%{http_code}' --location "$GETFILE_URL" -o "$GETFILE_FILE_PATH") + elif [ "$DOWNLOAD_TOOL" = "wget" ]; then + TMP_FILE=$(mktemp) + wget --server-response --content-on-error -q -O "$GETFILE_FILE_PATH" "$GETFILE_URL" 2>"$TMP_FILE" + GETFILE_HTTP_STATUS_CODE=$(awk '/^ HTTP/{print $2}' "$TMP_FILE") + rm -f "$TMP_FILE" + fi + echo "$GETFILE_HTTP_STATUS_CODE" +} + +downloadFile() { + if [ -z "$1" ]; then + checkLatestVersion + TAG="$CHECKLATESTVERSION_TAG" + else + TAG=$1 + fi + # arduino-lint_0.4.0-rc1_Linux_64bit.[tar.gz, zip] + APPLICATION_DIST_PREFIX="${PROJECT_NAME}_${TAG#"v"}_" + if [ "$OS" = "Windows" ]; then + APPLICATION_DIST_EXTENSION=".zip" + else + APPLICATION_DIST_EXTENSION=".tar.gz" + fi + APPLICATION_DIST="${APPLICATION_DIST_PREFIX}${OS}_${ARCH}${APPLICATION_DIST_EXTENSION}" + + # Support specifying nightly build versions (e.g., "nightly-latest") via the script argument. + case "$TAG" in + nightly*) + DOWNLOAD_URL_PREFIX="https://downloads.arduino.cc/${PROJECT_NAME}/nightly/" + ;; + *) + DOWNLOAD_URL_PREFIX="https://downloads.arduino.cc/${PROJECT_NAME}/" + ;; + esac + DOWNLOAD_URL="${DOWNLOAD_URL_PREFIX}${APPLICATION_DIST}" + + INSTALLATION_TMP_FILE="${TEMPDIR}/$APPLICATION_DIST" + echo "Downloading $DOWNLOAD_URL" + httpStatusCode=$(getFile "$DOWNLOAD_URL" "$INSTALLATION_TMP_FILE") + if [ "$httpStatusCode" -ne 200 ]; then + if [ -n "$FALLBACK_ARCH" ]; then + echo "$OS $ARCH release not currently available. Checking for alternative $OS $FALLBACK_ARCH release for your system." + FALLBACK_APPLICATION_DIST="${APPLICATION_DIST_PREFIX}${OS}_${FALLBACK_ARCH}${APPLICATION_DIST_EXTENSION}" + DOWNLOAD_URL="${DOWNLOAD_URL_PREFIX}${FALLBACK_APPLICATION_DIST}" + echo "Downloading $DOWNLOAD_URL" + httpStatusCode=$(getFile "$DOWNLOAD_URL" "$INSTALLATION_TMP_FILE") + fi + + if [ "$httpStatusCode" -ne 200 ]; then + echo "Did not find a release for your system: $OS $ARCH" + echo "Trying to find a release using the GitHub API." + + LATEST_RELEASE_URL="https://api.github.com/repos/${PROJECT_OWNER}/$PROJECT_NAME/releases/tags/$TAG" + TMP_BODY_FILE=$(mktemp) + HTTP_STATUS_CODE=$(getFile "$LATEST_RELEASE_URL" "$TMP_BODY_FILE") + BODY=$(cat "$TMP_BODY_FILE") + rm -f "$TMP_BODY_FILE" + if [ "$HTTP_STATUS_CODE" != 200 ]; then + echo "Request failed with HTTP status code $HTTP_STATUS_CODE" + fail "Body: $BODY" + fi + + # || true forces this command to not catch error if grep does not find anything + DOWNLOAD_URL=$(echo "$BODY" | grep 'browser_' | cut -d\" -f4 | grep "$APPLICATION_DIST") || true + if [ -z "$DOWNLOAD_URL" ]; then + DOWNLOAD_URL=$(echo "$BODY" | grep 'browser_' | cut -d\" -f4 | grep "$FALLBACK_APPLICATION_DIST") || true + fi + + if [ -z "$DOWNLOAD_URL" ]; then + echo "Sorry, we dont have a dist for your system: $OS $ARCH" + fail "You can request one here: https://github.com/${PROJECT_OWNER}/$PROJECT_NAME/issues" + else + echo "Downloading $DOWNLOAD_URL" + getFile "$DOWNLOAD_URL" "$INSTALLATION_TMP_FILE" + fi + fi + fi +} + +installFile() { + INSTALLATION_TMP_DIR="${TEMPDIR}/$PROJECT_NAME" + mkdir -p "$INSTALLATION_TMP_DIR" + if [ "$OS" = "Windows" ]; then + unzip -d "$INSTALLATION_TMP_DIR" "$INSTALLATION_TMP_FILE" + else + tar xf "$INSTALLATION_TMP_FILE" -C "$INSTALLATION_TMP_DIR" + fi + INSTALLATION_TMP_BIN="$INSTALLATION_TMP_DIR/$PROJECT_NAME" + cp "$INSTALLATION_TMP_BIN" "$EFFECTIVE_BINDIR" + rm -rf "$INSTALLATION_TMP_DIR" + rm -f "$INSTALLATION_TMP_FILE" +} + +bye() { + BYE_RESULT=$? + if [ "$BYE_RESULT" != "0" ]; then + echo "Failed to install $PROJECT_NAME" + fi + exit $BYE_RESULT +} + +testVersion() { + set +e + if EXECUTABLE_PATH="$(command -v $PROJECT_NAME)"; then + # Convert to resolved, absolute paths before comparison + EXECUTABLE_REALPATH="$(cd -- "$(dirname -- "$EXECUTABLE_PATH")" && pwd -P)" + EFFECTIVE_BINDIR_REALPATH="$(cd -- "$EFFECTIVE_BINDIR" && pwd -P)" + if [ "$EXECUTABLE_REALPATH" != "$EFFECTIVE_BINDIR_REALPATH" ]; then + # $PATH is intentionally a literal in this message. + # shellcheck disable=SC2016 + echo "An existing $PROJECT_NAME was found at $EXECUTABLE_PATH. Please prepend \"$EFFECTIVE_BINDIR\" to your "'$PATH'" or remove the existing one." + fi + else + # $PATH is intentionally a literal in this message. + # shellcheck disable=SC2016 + echo "install.sh: $PROJECT_NAME not found. You might want to add \"$EFFECTIVE_BINDIR\" to your "'$PATH' + fi + + set -e + APPLICATION_VERSION="$("$EFFECTIVE_BINDIR/$PROJECT_NAME" version)" + echo "$APPLICATION_VERSION installed successfully in $EFFECTIVE_BINDIR" +} + +# Execution + +#Stop execution on any error +trap "bye" EXIT +initDestination +set -e +initArch +initOS +initFallbackArch +initDownloadTool +downloadFile "$1" +installFile +testVersion diff --git a/Arduino/sketches/board_list.txt b/Arduino/sketches/board_list.txt new file mode 100644 index 00000000..52c78b41 --- /dev/null +++ b/Arduino/sketches/board_list.txt @@ -0,0 +1,173 @@ +# Edit with caution. +# +# This is a list of Arduino fqbn (fully qualified board names). +# +# Syntax: +# +# fqbn # fully qualified Arduino board name in format x:y:z, with optional comment after "#" +# --no-[example] # to optionally exclude an example. This comment displayed as for reason +# +# Each line is the exact text used in the ./compile-all-examples.sh +# +# See also: +# [this repo wolfssl-examples]/.github/workflows/arduino.yml +# [this repo wolfssl-examples]/.github/workflows/arduino-release.yml +# [other repo wolfssl]/.github/workflows/arduino.yml +# [other repo Arduino-wolfssl]/.github/workflows/arduino.yml +# +# This exact boardlist.txt is also used by: +# [repo owner]/Arduino-wolfSSL/.github/workflows/arduino.yml +# [repo owner]/wolfssl/.github/workflows/arduino.yml +# +# There's only one reference `board_list.txt` (this file) +# - copied to other workflows as needed with curl. +# +# There's only one compiling script `compile-all-examples.sh` (in this directory) +# - copied to other workflows as needed with curl. +# +# To view available boards: +# arduino-cli board listall | grep '^esp32:esp32:' +# + +arduino:avr:leonardoeth + # Ethernet Leonardo ETH (ATmega32u4 + W5500 Ethernet), only 2K RAM + --no-wolfssl_AES_CTR # Global variables use 4973 bytes (194%) of dynamic memory, leaving -2413 bytes for local variables. Maximum is 2560 bytes. + --no-wolfssl_client # Global variables use 4973 bytes (194%) of dynamic memory, leaving -2413 bytes for local variables. Maximum is 2560 bytes. + --no-wolfssl_server # Global variables use 4973 bytes (194%) of dynamic memory, leaving -2413 bytes for local variables. Maximum is 2560 bytes. + --no-wolfssl_client_dtls # Global variables use 4973 bytes (194%) of dynamic memory, leaving -2413 bytes for local variables. Maximum is 2560 bytes. + --no-wolfssl_server_dtls # Global variables use 4973 bytes (194%) of dynamic memory, leaving -2413 bytes for local variables. Maximum is 2560 bytes. + + +arduino:avr:yun + # Ethernet & WiFi has AR9331 Linux module for networking, but only 2K RAM + --no-wolfssl_AES_CTR # Global variables use 4973 bytes (194%) of dynamic memory, leaving -2413 bytes for local variables. Maximum is 2560 bytes. + --no-wolfssl_client # Global variables use 4973 bytes (194%) of dynamic memory, leaving -2413 bytes for local variables. Maximum is 2560 bytes. + --no-wolfssl_server # Global variables use 4973 bytes (194%) of dynamic memory, leaving -2413 bytes for local variables. Maximum is 2560 bytes. + --no-wolfssl_client_dtls # Global variables use 4973 bytes (194%) of dynamic memory, leaving -2413 bytes for local variables. Maximum is 2560 bytes. + --no-wolfssl_server_dtls # Global variables use 4973 bytes (194%) of dynamic memory, leaving -2413 bytes for local variables. Maximum is 2560 bytes. + +arduino:samd:mkrwifi1010 + # WiFi NINA-W102 module + --no-wolfssl_client_dtls # TODO This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library + --no-wolfssl_server_dtls # TODO This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library + +arduino:samd:mkr1000 + # WiFi uses WINC1500 module + --no-template # TODO wolfio.h:290:32: error: 'EWOULDBLOCK' undeclared (first use in this function); did you mean 'MP_WOULDBLOCK'? + --no-wolfssl_AES_CTR # TODO wolfio.h:290:32: error: 'EWOULDBLOCK' undeclared (first use in this function); did you mean 'MP_WOULDBLOCK'? + --no-wolfssl_client # TODO wolfio.h:290:32: error: 'EWOULDBLOCK' undeclared (first use in this function); did you mean 'MP_WOULDBLOCK'? + --no-wolfssl_server # TODO wolfio.h:290:32: error: 'EWOULDBLOCK' undeclared (first use in this function); did you mean 'MP_WOULDBLOCK'? + --no-wolfssl_client_dtls # TODO wolfio.h:290:32: error: 'EWOULDBLOCK' undeclared (first use in this function); did you mean 'MP_WOULDBLOCK'? + --no-wolfssl_server_dtls # TODO wolfio.h:290:32: error: 'EWOULDBLOCK' undeclared (first use in this function); did you mean 'MP_WOULDBLOCK'? + --no-wolfssl_version # TODO wolfio.h:290:32: error: 'EWOULDBLOCK' undeclared (first use in this function); did you mean 'MP_WOULDBLOCK'? + +arduino:samd:mkrfox1200 + # Sigfox Low-power IoT radio + --no-wolfssl_client # TODO WiFiNINA/src/utility/spi_drv.cpp:103:15: error: 'NINA_GPIO0' was not declared in this scope + --no-wolfssl_server # TODO WiFiNINA/src/utility/spi_drv.cpp:103:15: error: 'NINA_GPIO0' was not declared in this scope + --no-wolfssl_client_dtls # TODO WiFiNINA/src/utility/spi_drv.cpp:103:15: error: 'NINA_GPIO0' was not declared in this scope + --no-wolfssl_server_dtls # TODO WiFiNINA/src/utility/spi_drv.cpp:103:15: error: 'NINA_GPIO0' was not declared in this scope + +arduino:mbed_nano:nanorp2040connect + # WiFi NINA-W102 module + --no-wolfssl_client_dtls # TODO This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library + --no-wolfssl_server_dtls # TODO This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library + +# The like (ABX00045) and regular (ABX00042) are considered equivalent +# The Portenta devices are Linux-like and not typical Arduino boards +arduino:mbed_portenta:envie_m7 + # WiFi & Ethernet via onboard module + --no-wolfssl_client_dtls # TODO This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library + --no-wolfssl_server_dtls # TODO This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library + +# The Portenta devices are Linux-like and not typical Arduino boards +arduino:mbed_portenta:portenta_x8 + # WiFi & Ethernet via onboard module + --no-wolfssl_client # TODO mbed_portenta/4.4.1/libraries/WiFi/src/WiFi.h:188:3: error: 'WiFiAccessPoint' does not name a type + --no-wolfssl_server # TODO mbed_portenta/4.4.1/libraries/WiFi/src/WiFi.h:188:3: error: 'WiFiAccessPoint' does not name a type + --no-wolfssl_client_dtls # TODO This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library + --no-wolfssl_server_dtls # TODO This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library + +arduino:mbed_edge:edge_control + # Cellular LTE Cat-M/NB-IoT + --no-wolfssl_client # TODO Wrong network? WiFiNINA/src/utility/spi_drv.cpp:103:15: error: 'NINA_GPIO0' was not declared in this scope + --no-wolfssl_server # TODO Wrong network? WiFiNINA/src/utility/spi_drv.cpp:103:15: error: 'NINA_GPIO0' was not declared in this scope + --no-wolfssl_client # TODO Wrong network? WiFiNINA/src/utility/spi_drv.cpp:103:15: error: 'NINA_GPIO0' was not declared in this scope + --no-wolfssl_server # TODO Wrong network? WiFiNINA/src/utility/spi_drv.cpp:103:15: error: 'NINA_GPIO0' was not declared in this scope + --no-wolfssl_client_dtls # TODO This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library + --no-wolfssl_server_dtls # TODO This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library + +arduino:renesas_uno:unor4wifi + # WiFi & BT UNO R4 WiFi (ESP32-S3 coprocessor) + --no-wolfssl_client_dtls # TODO This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library + --no-wolfssl_server_dtls # TODO This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library + +arduino:avr:mega + --no-wolfssl_client # There's no wifi on mega for client example + --no-wolfssl_server # There's no wifi on mega for server example + --no-wolfssl_client_dtls # There's no wifi on mega for client DTLS example + --no-wolfssl_server_dtls # There's no wifi on mega for server DTLS example +arduino:avr:nano + --no-wolfssl_AES_CTR # Global variables use 5010 bytes (244%) of dynamic memory, leaving -2962 bytes for local variables. Maximum is 2048 bytes. + --no-wolfssl_client # There's no wifi on nano for client example + --no-wolfssl_server # There's no wifi on nano for server example + --no-wolfssl_client_dtls # There's no wifi on nano for client DTLS example + --no-wolfssl_server_dtls # There's no wifi on nano for server DTLS example +arduino:avr:uno + --no-wolfssl_AES_CTR # Global variables use 5010 bytes (244%) of dynamic memory, leaving -2962 bytes for local variables. Maximum is 2048 bytes. + --no-wolfssl_client # There's no wifi on uno for client example + --no-wolfssl_server # There's no wifi on uno for server example + --no-wolfssl_client_dtls # There's no wifi on uno for client DTLS example + --no-wolfssl_server_dtls # There's no wifi on uno for server DTLS example + +# Although it may have network capability, flash is pretty small: +arduino:avr:ethernet + --no-wolfssl_AES_CTR # Global variables use 5010 bytes (244%) of dynamic memory, leaving -2962 bytes for local variables. Maximum is 2048 bytes. + --no-wolfssl_client # Global variables use 5010 bytes (244%) of dynamic memory, leaving -2962 bytes for local variables. Maximum is 2048 bytes. + --no-wolfssl_server # Global variables use 5010 bytes (244%) of dynamic memory, leaving -2962 bytes for local variables. Maximum is 2048 bytes. + --no-wolfssl_client_dtls # Global variables use 5010 bytes (244%) of dynamic memory, leaving -2962 bytes for local variables. Maximum is 2048 bytes. + --no-wolfssl_server_dtls # Global variables use 5010 bytes (244%) of dynamic memory, leaving -2962 bytes for local variables. Maximum is 2048 bytes. + +arduino:sam:arduino_due_x + --no-wolfssl_client_dtls # TODO This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library + --no-wolfssl_server_dtls # TODO This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library + +arduino:samd:arduino_zero_native + --no-wolfssl_client # TODO error: 'NINA_GPIO0' was not declared in this scope + --no-wolfssl_server # TODO error: 'NINA_GPIO0' was not declared in this scope + --no-wolfssl_client_dtls # TODO error: 'NINA_GPIO0' was not declared in this scope + --no-wolfssl_server_dtls # TODO error: 'NINA_GPIO0' was not declared in this scope + + +# Pseudo network via bridge.h only. No connect / write / etc. +arduino:samd:tian + --no-wolfssl_client # HttpClient cannot be used for this example + --no-wolfssl_server # HttpClient cannot be used for this example + --no-wolfssl_client_dtls # HttpClient cannot be used for this example + --no-wolfssl_server_dtls # HttpClient cannot be used for this example + +# All examples should work on (nearly all) ESP32 devices +esp32:esp32:esp32 +esp32:esp32:esp32s2 +esp32:esp32:esp32s3 +esp32:esp32:esp32c3 +esp32:esp32:esp32c6 + +# Except for the ESP32-H2 what does not have WiFi +esp32:esp32:esp32h2 + --no-wolfssl_client # There's no WiFi on esp32h2 for client example + --no-wolfssl_server # There's no WiFi on esp32h2 for server example + --no-wolfssl_client_dtls # There's no WiFi on esp32h2 for client DTLS example + --no-wolfssl_server_dtls # There's no WiFi on esp32h2 for server DTLS example + +esp8266:esp8266:generic + --no-wolfssl_client # There's not enough memory on ESP8266 at this time (TODO) + --no-wolfssl_server # There's not enough memory on ESP8266 at this time (TODO) + --no-wolfssl_client_dtls # There's not enough memory on ESP8266 at this time (TODO) + --no-wolfssl_server_dtls # There's not enough memory on ESP8266 at this time (TODO) + +teensy:avr:teensy40 + --no-wolfssl_client # TODO: Wrong network? WiFiNINA/src/utility/wifi_drv.h:300:12: error: 'PinStatus' does not name a type + --no-wolfssl_server # TODO: Wrong network? WiFiNINA/src/utility/wifi_drv.h:300:12: error: 'PinStatus' does not name a type + --no-wolfssl_client_dtls # TODO: This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library + --no-wolfssl_server_dtls # TODO: This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library diff --git a/Arduino/sketches/board_list_v5.8.2.txt b/Arduino/sketches/board_list_v5.8.2.txt new file mode 100644 index 00000000..f811e3ce --- /dev/null +++ b/Arduino/sketches/board_list_v5.8.2.txt @@ -0,0 +1,123 @@ +# Edit with caution. +# +# TODO this is an interim board list file for current release of Arduino wolfSSL +# +# See ./board_list for more comprehensive list of boards. +# +# This is a list of Arduino fqbn (fully qualified board names). +# +# Syntax: +# +# fqbn # fully qualified Arduino board name in format x:y:z, with optional comment after "#" +# --no-[example] # to optionally exclude an example. This comment displayed as for reason +# +# Each line is the exact text used in the ./compile-all-examples.sh +# +# See also: +# [this repo wolfssl-examples]/.github/workflows/arduino.yml +# [this repo wolfssl-examples]/.github/workflows/arduino-release.yml +# [other repo wolfssl]/.github/workflows/arduino.yml +# [other repo Arduino-wolfssl]/.github/workflows/arduino.yml +# +# This exact boardlist.txt is also used by: +# [repo owner]/Arduino-wolfSSL/.github/workflows/arduino.yml +# [repo owner]/wolfssl/.github/workflows/arduino.yml +# +# There's only one reference `board_list.txt` (this file) +# - copied to other workflows as needed with curl. +# +# There's only one compiling script `compile-all-examples.sh` (in this directory) +# - copied to other workflows as needed with curl. +# +# To view available boards: +# arduino-cli board listall | grep '^esp32:esp32:' +# + +arduino:avr:mega + --no-wolfssl_version # Fixed in https://github.com/wolfSSL/wolfssl/pull/9075 Force old OID values: WOLFSSL_OLD_OID_SUM for WC_16BIT_CPU + --no-template # Fixed in https://github.com/wolfSSL/wolfssl/pull/9075 Force old OID values: WOLFSSL_OLD_OID_SUM for WC_16BIT_CPU + --no-wolfssl_AES_CTR # Fixed in https://github.com/wolfSSL/wolfssl/pull/9075 Force old OID values: WOLFSSL_OLD_OID_SUM for WC_16BIT_CPU + --no-wolfssl_client # there's no wifi on mega for client examplex + --no-wolfssl_server # there's no wifi on mega for server example + --no-wolfssl_client_dtls # there's no wolfssl_client_dtls example for the v5.8.2 release + --no-wolfssl_server_dtls # there's no wolfssl_server_dtls example for the v5.8.2 release + +arduino:avr:nano + --no-wolfssl_version # Fixed in https://github.com/wolfSSL/wolfssl/pull/9075 Force old OID values: WOLFSSL_OLD_OID_SUM for WC_16BIT_CPU + --no-template # Fixed in https://github.com/wolfSSL/wolfssl/pull/9075 Force old OID values: WOLFSSL_OLD_OID_SUM for WC_16BIT_CPU + --no-wolfssl_AES_CTR # Fixed in https://github.com/wolfSSL/wolfssl/pull/9075 Force old OID values: WOLFSSL_OLD_OID_SUM for WC_16BIT_CPU + --no-wolfssl_AES_CTR # Global variables use 5010 bytes (244%) of dynamic memory, leaving -2962 bytes for local variables. Maximum is 2048 bytes. + --no-wolfssl_client # there's no wifi on nano for client example + --no-wolfssl_server # there's no wifi on nano for server example + --no-wolfssl_client_dtls # there's no wolfssl_client_dtls example for the v5.8.2 release + --no-wolfssl_server_dtls # there's no wolfssl_server_dtls example for the v5.8.2 release + +arduino:avr:uno + --no-wolfssl_version # Fixed in https://github.com/wolfSSL/wolfssl/pull/9075 Force old OID values: WOLFSSL_OLD_OID_SUM for WC_16BIT_CPU + --no-template # Fixed in https://github.com/wolfSSL/wolfssl/pull/9075 Force old OID values: WOLFSSL_OLD_OID_SUM for WC_16BIT_CPU + --no-wolfssl_AES_CTR # Fixed in https://github.com/wolfSSL/wolfssl/pull/9075 Force old OID values: WOLFSSL_OLD_OID_SUM for WC_16BIT_CPU + --no-wolfssl_AES_CTR # Global variables use 5010 bytes (244%) of dynamic memory, leaving -2962 bytes for local variables. Maximum is 2048 bytes. + --no-wolfssl_client # there's no wifi on uno for client example + --no-wolfssl_server # there's no wifi on uno for server example + --no-wolfssl_client_dtls # there's no wolfssl_client_dtls example for the v5.8.2 release + --no-wolfssl_server_dtls # there's no wolfssl_server_dtls example for the v5.8.2 release + +# Although it may have network capability, flash is pretty small: +arduino:avr:ethernet + --no-wolfssl_version # Fixed in https://github.com/wolfSSL/wolfssl/pull/9075 Force old OID values: WOLFSSL_OLD_OID_SUM for WC_16BIT_CPU + --no-template # Fixed in https://github.com/wolfSSL/wolfssl/pull/9075 Force old OID values: WOLFSSL_OLD_OID_SUM for WC_16BIT_CPU + --no-wolfssl_AES_CTR # Global variables use 5010 bytes (244%) of dynamic memory, leaving -2962 bytes for local variables. Maximum is 2048 bytes. + --no-wolfssl_client # Global variables use 5010 bytes (244%) of dynamic memory, leaving -2962 bytes for local variables. Maximum is 2048 bytes. + --no-wolfssl_server # Global variables use 5010 bytes (244%) of dynamic memory, leaving -2962 bytes for local variables. Maximum is 2048 bytes. + --no-wolfssl_client_dtls # there's no wolfssl_client_dtls example for the v5.8.2 release + --no-wolfssl_server_dtls # there's no wolfssl_server_dtls example for the v5.8.2 release + +arduino:sam:arduino_due_x + --no-wolfssl_AES_CTR # Fixed in https://github.com/wolfSSL/wolfssl/pull/9076 Disallow atomics during fence & WOLFSSL_NO_ATOMIC + --no-wolfssl_version # Fixed in https://github.com/wolfSSL/wolfssl/pull/9076 Disallow atomics during fence & WOLFSSL_NO_ATOMIC + --no-template # Fixed in https://github.com/wolfSSL/wolfssl/pull/9076 Disallow atomics during fence & WOLFSSL_NO_ATOMIC + --no-wolfssl_client # Fixed in https://github.com/wolfSSL/wolfssl/pull/9076 Disallow atomics during fence & WOLFSSL_NO_ATOMIC + --no-wolfssl_server # Fixed in https://github.com/wolfSSL/wolfssl/pull/9076 Disallow atomics during fence & WOLFSSL_NO_ATOMIC + --no-wolfssl_client_dtls # there's no wolfssl_client_dtls example for the v5.8.2 release + --no-wolfssl_server_dtls # there's no wolfssl_server_dtls example for the v5.8.2 release + +arduino:samd:arduino_zero_native + --no-wolfssl_client # TODO error: 'NINA_GPIO0' was not declared in this scope + --no-wolfssl_server # TODO error: 'NINA_GPIO0' was not declared in this scope + --no-wolfssl_client_dtls # there's no wolfssl_client_dtls example for the v5.8.2 release + --no-wolfssl_server_dtls # there's no wolfssl_server_dtls example for the v5.8.2 release + + +# Pseudo network via bridge.h only. No connect / write / etc. +arduino:samd:tian + --no-wolfssl_client # HttpClient cannot be used for this example + --no-wolfssl_server # HttpClient cannot be used for this example + --no-wolfssl_client_dtls # there's no wolfssl_client_dtls example for the v5.8.2 release + --no-wolfssl_server_dtls # there's no wolfssl_server_dtls example for the v5.8.2 release + +# All examples should work on (nearly all) ESP32 devices +esp32:esp32:esp32 +esp32:esp32:esp32s2 +esp32:esp32:esp32s3 +esp32:esp32:esp32c3 +esp32:esp32:esp32c6 +esp32:esp32:esp32h2 + --no-wolfssl_client # there's no WiFi on esp32h2 for client example + --no-wolfssl_server # there's no WiFi on esp32h2 for server example + --no-wolfssl_client_dtls # there's no wolfssl_client_dtls example for the v5.8.2 release + --no-wolfssl_server_dtls # there's no wolfssl_client_dtls example for the v5.8.2 release + +esp8266:esp8266:generic + --no-wolfssl_AES_CTR # Fixed in upcoming PR + --no-wolfssl_version # Fixed in upcoming PR + --no-template # Fixed in upcoming PR + --no-wolfssl_client # TODO there's not enough memory on ESP8266 at this time + --no-wolfssl_server # TODO there's not enough memory on ESP8266 at this time + --no-wolfssl_client_dtls # there's no wolfssl_client_dtls example for the v5.8.2 release + --no-wolfssl_server_dtls # there's no wolfssl_server_dtls example for the v5.8.2 release + +teensy:avr:teensy40 + --no-wolfssl_client # Wrong network? WiFiNINA/src/utility/wifi_drv.h:300:12: error: 'PinStatus' does not name a type + --no-wolfssl_server # Wrong network? WiFiNINA/src/utility/wifi_drv.h:300:12: error: 'PinStatus' does not name a type + --no-wolfssl_client_dtls # there's no wolfssl_client_dtls example for the v5.8.2 release + --no-wolfssl_server_dtls # there's no wolfssl_server_dtls example for the v5.8.2 release diff --git a/Arduino/sketches/compile-all-examples.sh b/Arduino/sketches/compile-all-examples.sh new file mode 100644 index 00000000..72536021 --- /dev/null +++ b/Arduino/sketches/compile-all-examples.sh @@ -0,0 +1,472 @@ +#!/bin/bash +# +# ./wolfssl-arduino.sh INSTALL +# export ARDUINO_ROOT=/home/$USER/Arduino/libraries +# +# ./wolfssl-arduino.sh INSTALL /mnt/c/Users/gojimmypi/Documents/Arduino/libraries + +# Run shell check to ensure this a good script. +# Specify the executable shell checker you want to use: +MY_SHELLCHECK="shellcheck" + +# Check if the executable is available in the PATH +if command -v "$MY_SHELLCHECK" >/dev/null 2>&1; then + # Run your command here + $MY_SHELLCHECK "$0" || exit 1 +else + echo "$MY_SHELLCHECK is not installed. Please install it if changes to this script have been made." + exit 1 +fi + +set +e + +# Configuration parameters +SHOW_DIR_CONTENTS=0 +SHOW_USER_SETTINGS=0 +SHOW_BOARD_LIST=0 +SHOW_EXAMPLE_LIST=0 + +# need to reassign ARDUINO_ROOT in this run +ARDUINO_ROOT="$HOME/Arduino/libraries" + +# Used for column alignment; e.g. len(wolfssl_client_dtls) + 2 +MAX_FQBN_LEN=21 + +# default board list is board_list.txt, may be overridden +BOARD_LIST="./board_list.txt" + +# Unicode in a UTF8 file +ICON_OK=$(printf "\xE2\x9C\x85") +ICON_WARN=$(printf "\xE2\x9A\xA0") +ICON_FAIL=$(printf "\xE2\x9D\x8C") + +# Check if board list specified. +if [ $# -gt 0 ]; then + # First parameter may be alternate fqbn list + if [[ -f "$1" ]]; then + BOARD_LIST="$1" + echo "Using specified fqbn list file: $BOARD_LIST" + else + echo "Error: Parameter specified for board list file does not exist: $1" + exit 1 + fi +fi + +# Internal variabled +BOARD_CT=0 +BOARD_COMPILE_CT=0 +BOARD_SKIP_CT=0 +BOARD_FAIL_CT=0 +EXAMPLE_CT=0 +THIS_FOUND_FLAG=0 + +# Assume success unless proven otherwise +SUCCESS="true" + +# Same example names, initialized later +EXAMPLES=(wolfssl_client wolfssl_client_dtls server) + +# associative array, where the keys are arbitrary strings +declare -A DISABLED # per FQBN: DISABLED["example-name"]=1 +declare -A COMMENT # per FQBN: COMMENT["example-name"]="some comment" +declare -A VALID_EXAMPLES # set of valid example names + +# Indexed arrays to hold results +declare -a SUMMARY_STATUS +declare -a SUMMARY_BOARD +declare -a SUMMARY_EXAMPLE + +echo "Icon check:" +printf '--OK: %s; Warn: %s; Not OK: %s\n' "$ICON_OK" "$ICON_WARN" "$ICON_FAIL" + +if [[ $SHOW_DIR_CONTENTS -ne 0 ]]; then + echo "********************************************************************************" + echo "Installed libraries:" + echo "********************************************************************************" + ls "$ARDUINO_ROOT" -al + + echo "********************************************************************************" + echo "wolfssl:" + echo "********************************************************************************" + ls "$ARDUINO_ROOT/wolfssl" -al + + echo "********************************************************************************" + echo "wolfssl/src:" + echo "********************************************************************************" + ls "$ARDUINO_ROOT/wolfssl/src/" -al + + echo "********************************************************************************" + echo "********************************************************************************" + ls "$ARDUINO_ROOT/wolfssl/src/user_settings.h" -al + echo "********************************************************************************" + echo "********************************************************************************" +fi +if [[ $SHOW_USER_SETTINGS -ne 0 ]]; then + cat "$ARDUINO_ROOT/wolfssl/src/user_settings.h" + echo "********************************************************************************" + echo "********************************************************************************" +fi +if [[ $SHOW_BOARD_LIST -ne 0 ]]; then + echo "Begin compile for $BOARD_LIST" + cat "$BOARD_LIST" + echo "--------------------------------------------------------------------------------" +fi +if [[ $SHOW_EXAMPLE_LIST -ne 0 ]]; then + echo "Examples found:" + find ./ -mindepth 1 -maxdepth 1 -type d + echo "********************************************************************************" + echo "********************************************************************************" +fi + + +#FAIL_LIST=() # items like "fqbn example exitcode" +#OVERALL_OK=1 # flip to 0 on first failure + +# -------- helper functions -------- + +strip_cr() { + if [[ $1 == *$'\r' ]]; then + printf '%s' "${1%$'\r'}" + else + printf '%s' "$1" + fi +} + +is_skip() { + # skip blank lines or lines that start with # (leading spaces allowed) + # [[ -z $1 || $1 =~ ^[[:space:]]*# ]] + local line="$1" + LINE_VALUE="" + LINE_COMMENT="" + + # Trim leading/trailing spaces from the whole line + line="${line#"${line%%[![:space:]]*}"}" # trim leading + line="${line%"${line##*[![:space:]]}"}" # trim trailing + + # Blank line? + if [[ -z $line ]]; then + # echo "is_skip early return 0" + return 0 + fi + + # Split at first '#' + LINE_VALUE="${line%%#*}" + LINE_COMMENT="" + if [[ $line == *"#"* ]]; then + LINE_COMMENT="${line#*#}" + fi + + # Trim each part + LINE_VALUE="${LINE_VALUE%"${LINE_VALUE##*[![:space:]]}"}" + LINE_VALUE="${LINE_VALUE#"${LINE_VALUE%%[![:space:]]*}"}" + # echo "LINE_VALUE=$LINE_VALUE" + + LINE_COMMENT="${LINE_COMMENT%"${LINE_COMMENT##*[![:space:]]}"}" + LINE_COMMENT="${LINE_COMMENT#"${LINE_COMMENT%%[![:space:]]*}"}" + # echo "LINE_COMMENT=$LINE_COMMENT" + + # Pure comment line (no value) + if [[ -z $LINE_VALUE ]]; then + # echo "is_skip return 0" + return 0 + fi + + # Not a skip line + # echo "is_skip return 1" + return 1 +} #is_skip + +norm_key() { + # lowercase only, preserve underscores and dashes + printf '%s' "${1,,}" +} # norm_key + +discover_examples() { + EXAMPLES=() + EXAMPLE_CT=0 + + echo "Discovering examples in current directory $(pwd)" + # Read NUL-separated paths to handle spaces safely + while IFS= read -r -d '' d; do + # strip leading "./" so we keep just the dir name + local name="${d#./}" + EXAMPLES+=("$name") + echo "Found example directory: $name" + ((EXAMPLE_CT++)) + done < <(find ./ -mindepth 1 -maxdepth 1 -type d -print0 | sort -z) + + # Optional: filter out hidden dirs or known exclusions + # local keep=() + # for e in "${EXAMPLES[@]}"; do + # [[ $e == .* ]] && continue # skip hidden like .git + # [[ $e == build || $e == out ]] && continue + # keep+=("$e") + # done + # EXAMPLES=("${keep[@]}") +} # discover_examples + +build_valid_examples() { + local e key + for e in "${EXAMPLES[@]}"; do + key=$(norm_key "$e") + VALID_EXAMPLES["$key"]=1 + done +} # build_valid_examples + +warn_unknown_flag() { + # $1 is raw flag text after --no- + # $2 is current FQBN for context + printf '%s WARN: Unknown example in flag "--no-%s" under FQBN "%s" (ignored)\n' "$ICON_WARN" "$1" "$2" >&2 +} # warn_unknown_flag + +set_flag() { + # flag looks like --no-name + local raw=${1#--no-} + local key + key=$(norm_key "$raw") + # echo "this key = $key" + if [[ -n ${VALID_EXAMPLES[$key]+x} ]]; then + DISABLED["$key"]=1 + COMMENT["$key"]="$2" + else + warn_unknown_flag "$raw" "$BOARD" + fi +} # set_flag + +clear_flags() { + local k + for k in "${!DISABLED[@]}"; do + unset -v "DISABLED[$k]" + unset -v "COMMENT[$k]" + done + THIS_FOUND_FLAG=0 +} # clear_flags + +is_disabled() { + # return 0 if disabled for this FQBN, else 1 + local key + key=$(norm_key "$1") + # echo "checking $key" + if [[ -n ${DISABLED[$key]+x} ]]; then + return 0 + else + return 1 + fi +} # is_disabled + +comment_for() { + local key + key=$(norm_key "$1") + printf '%s' "${COMMENT[$key]}" +} # comment_for + +has_comment() { + local key value + key=$(norm_key "$1") + + # Key must exist + if [[ ! -v COMMENT[$key] ]]; then + return 1 + fi + + value=${COMMENT[$key]} + + # Remove all whitespace for the check + local trimmed="${value//[[:space:]]/}" + + if [[ -n $trimmed ]]; then + return 0 # true: (not and error) has a non-blank comment + else + return 1 # false: (error) empty or whitespace only + fi +} # has_comment + +# Optional for each EXAMPLE / BOARD +# +#while IFS= read -r EXAMPLE; do +# echo "Checking example: for $EXAMPLE" +# while IFS= read -r BOARD; do +# # Clean board names, +# BOARD="${BOARD//$'\r'/}" # Remove carriage returns from the line +# +# # Skip any non-board fqbn lines +# if [[ "$BOARD" =~ ^[[:space:]]*$ ]]; then +# continue #skip blank lines +# fi# +# +# if [[ "$BOARD" == \#* || "$BOARD" == " "*#* ]]; then +# continue # Skip comments and lines starting with space + # +# fi +# +# echo "Checking $EXAMPLE for $BOARD" + + +# ************************************************************************************* +# +discover_examples +build_valid_examples +# ************************************************************************************* + +peek= +echo "Here we go!" + +#************************************************************************************* +# Read fqbn BOARD from $BOARD_LIST (typically ./board_list.txt) +#************************************************************************************* +while :; do + # read next FQBN line, some next lines might be hints to disable compile: --no-[n] + if [[ -n $peek ]]; then + line=$peek + peek= + else + IFS= read -r line || break + fi + + line=$(strip_cr "$line") + if [[ "$line" == "exit" ]]; then + echo "Encountered exit in $BOARD_LIST; aborting" + break + fi + + + if is_skip "$line"; then + # echo "This line skipped: $line" + continue + fi + + BOARD="${line//$'\r'/}" # Remove carriage returns from the line + + echo "" + echo "*************************************************************************************" + echo "Testing board: $BOARD" + echo "*************************************************************************************" + + echo "Checking flags..." + clear_flags + + # collect any --no- lines under this FQBN + while IFS= read -r next; do + next=$(strip_cr "$next") + + # echo "--calling is_skip with next=$next" + if is_skip "$next"; then + # echo "--skip! $next" + continue + fi + + # echo " checking [$next] is like --no" + if [[ $LINE_VALUE == --no-* ]]; then + if [[ -n "$LINE_COMMENT" ]]; then + echo "$LINE_VALUE: $LINE_COMMENT" + else + echo "$LINE_VALUE: (No comment provided; Consider adding reason in $BOARD_LIST)" + fi + set_flag "$LINE_VALUE" "$LINE_COMMENT" + THIS_FOUND_FLAG=1 + continue + # else + # not a line stat starts with --no + fi + + peek=$next + break + done + if [[ $THIS_FOUND_FLAG -ne 0 ]]; then + echo "-------------------------------------------------------------------------------------" + fi + + # echo "Flags done..." + + # Typically at the end, or when multiple blank lines encountered + # if [[ -z $next && -z $peek ]]; then + # echo "Continue, skipping blank line..." + # continue + # fi + echo "Begin Board: $BOARD" + + echo "-------------------------------------------------------------------------------------" + ((BOARD_CT++)) + THIS_EXAMPLE_CT=0 + for EXAMPLE in "${EXAMPLES[@]}"; do + start_time=$(date +%s) # record start time (epoch seconds) + echo "Checking $EXAMPLE for $BOARD" + if is_disabled "$EXAMPLE"; then + echo "Skipped" + ((BOARD_SKIP_CT++)) + + if has_comment "$EXAMPLE"; then + this_comment=$(comment_for "$EXAMPLE") + echo "Comment: $this_comment" + else + echo "No comment in $BOARD_LIST for disable reason on $EXAMPLE example." + fi + else + # If otherwise not excluded, compile this $EXAMPLE for this $BOARD + ((BOARD_COMPILE_CT++)) + echo "arduino-cli compile --fqbn \"$BOARD\" \"$EXAMPLE\"" + arduino-cli compile --fqbn "$BOARD" "$EXAMPLE" + EXIT_CODE=$? + if [ $EXIT_CODE -ne 0 ]; then + echo "$ICON_FAIL Compilation failed for $EXAMPLE on $BOARD (Exit code: $EXIT_CODE)" + ((BOARD_FAIL_CT++)) + SUCCESS=false + SUMMARY_STATUS+=("$ICON_FAIL") + else + echo "$ICON_OK Compilation succeeded for $EXAMPLE on $BOARD" + SUMMARY_STATUS+=("$ICON_OK") + fi # exit code + + SUMMARY_BOARD+=("$BOARD") + SUMMARY_EXAMPLE+=("$EXAMPLE") + fi # is_disabled check + + end_time=$(date +%s) # record end time + elapsed=$(( end_time - start_time )) + echo "Block took ${elapsed} seconds" + + if [[ $THIS_EXAMPLE_CT -lt $EXAMPLE_CT ]]; then + echo "-------------------------------------------------------------------------------------" + fi + ((THIS_EXAMPLE_CT++)) + done # for each example +done < "$BOARD_LIST" # for each BOARD + + +# Optional for each EXAMPLE / BOARD +# +# done < board_list.txt # for each BOARD +#done < <(find ./sketches -mindepth 1 -maxdepth 1 -type d) # for each EXAMPLE directory name + +echo "Done!" +echo "-------------------------------------------------------------------------------------" +echo "Boards found: $BOARD_CT" +echo "Examples found: $EXAMPLE_CT" +echo "Board Examples: $(( ${BOARD_CT:-0} * ${EXAMPLE_CT:-0} ))" +echo "Compilation Summary:" +printf "%-4s %-*s %-*s\n" "STAT" "$MAX_FQBN_LEN" "EXAMPLE" "$MAX_FQBN_LEN" "BOARD" +printf "%-4s %-*s %-*s\n" "----" "$MAX_FQBN_LEN" "-------" "$MAX_FQBN_LEN" "-----" + +for i in "${!SUMMARY_STATUS[@]}"; do + printf "%-4s %-*s %-*s\n" \ + "${SUMMARY_STATUS[$i]}" \ + "$MAX_FQBN_LEN" "${SUMMARY_EXAMPLE[$i]}" \ + "$MAX_FQBN_LEN" "${SUMMARY_BOARD[$i]}" +done + +if [ "$SUCCESS" = true ]; then + echo "$ICON_OK All $BOARD_COMPILE_CT sketches compiled successfully! $BOARD_SKIP_CT board examples skipped (see $BOARD_LIST)." +else + case "$BOARD_FAIL_CT" in + 0) + echo "$ICON_FAIL no sketches failed to compile. Other error?" + ;; + 1) + echo "$ICON_FAIL 1 sketch failed to compile." + ;; + *) + echo "$ICON_FAIL $BOARD_FAIL_CT sketches failed to compile." + ;; + esac + + exit 1 +fi diff --git a/Arduino/sketches/template/template.ino b/Arduino/sketches/template/template.ino index 89989769..0d0f8d81 100644 --- a/Arduino/sketches/template/template.ino +++ b/Arduino/sketches/template/template.ino @@ -6,7 +6,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, @@ -21,6 +21,13 @@ #include <Arduino.h> +#if defined(ARDUINO_PORTENTA_X8) + /* The Portenta is a Linux device. See wolfSSL examples: + * https://github.com/wolfSSL/wolfssl/tree/master/examples + * By default Serial is disabled and mapped to ErrorSerial */ + #include <SerialRPC.h> +#endif + /* wolfSSL user_settings.h must be included from settings.h * Make all configurations changes in user_settings.h * Do not edit wolfSSL `settings.h` or `config.h` files. diff --git a/Arduino/sketches/template/wolfssl_helper.c b/Arduino/sketches/template/wolfssl_helper.c index f4eeb573..c6dcd39e 100644 --- a/Arduino/sketches/template/wolfssl_helper.c +++ b/Arduino/sketches/template/wolfssl_helper.c @@ -6,7 +6,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, @@ -26,10 +26,36 @@ * Be sure to include these files in all libraries that reference * wolfssl in this order: */ -#include <Arduino.h> -/* settings.h is typically included in wolfssl.h, but here as a reminder: */ -#include <wolfssl/wolfcrypt/settings.h> -#include <wolfssl.h> +#if defined(ARDUINO_PORTENTA_X8) + /* This file is purposely a c and not .cpp file for testing. + * On Portenta X8 the core headers assume C++, and things like A6, + * PIN_SPI_MOSI, etc. - rely on C++-only constructs. + * So don't include Arduino.h here for Portenta. */ + + #include <wolfssl/wolfcrypt/settings.h> + #include <wolfssl/ssl.h> /* The ssl.h usually included by wolfssl.h */ + + #ifdef __cplusplus + extern "C" { + #endif + + /* Sample source code is C, but Arduino is compiling with C++ + * Declare a helper function to be used in wolfssl/wolfcrypt/logging.c */ + int wolfSSL_Arduino_Serial_Print(const char* const s); + + #ifdef __cplusplus + } + #endif +#else + /* Assume all other target boards would want to include Arduino.h in a + * helper such as this one. Not needed in this wolfssl_helper.c example. */ + #include <Arduino.h> + + /* settings.h is typically included in wolfssl.h, but here as a reminder: */ + #include <wolfssl/wolfcrypt/settings.h> + #include <wolfssl.h> /* The wolfssl core Arduino library file */ +#endif + #include "wolfssl_helper.h" diff --git a/Arduino/sketches/template/wolfssl_helper.h b/Arduino/sketches/template/wolfssl_helper.h index 844f0223..1291dbe0 100644 --- a/Arduino/sketches/template/wolfssl_helper.h +++ b/Arduino/sketches/template/wolfssl_helper.h @@ -6,7 +6,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, diff --git a/Arduino/sketches/wolfssl_AES_CTR/wolfssl_AES_CTR.ino b/Arduino/sketches/wolfssl_AES_CTR/wolfssl_AES_CTR.ino index 31ef7973..a47d096e 100644 --- a/Arduino/sketches/wolfssl_AES_CTR/wolfssl_AES_CTR.ino +++ b/Arduino/sketches/wolfssl_AES_CTR/wolfssl_AES_CTR.ino @@ -6,7 +6,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, @@ -19,6 +19,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +#include <Arduino.h> + +#if defined(ARDUINO_PORTENTA_X8) + /* The Portenta is a Linux device. See wolfSSL examples: + * https://github.com/wolfSSL/wolfssl/tree/master/examples + * By default Serial is disabled and mapped to ErrorSerial */ + #include <SerialRPC.h> +#endif + /* The Advanced Encryption Standard (AES) is a specification for the encryption of electronic data established by the U.S. National Institute of Standards and Technology (NIST) in 2001. @@ -50,7 +59,21 @@ Teensy 4.1 (ARM Cortex M7) */ #define WOLFSSL_AES_CTR_EXAMPLE +/* wolfSSL user_settings.h must be included from settings.h + * Make all configurations changes in user_settings.h + * Do not edit wolfSSL `settings.h` or `config.h` files. + * Do not explicitly include user_settings.h in any source code. + * Each Arduino sketch that uses wolfSSL must have: #include "wolfssl.h" + * C/C++ source files can use: #include <wolfssl/wolfcrypt/settings.h> + * The wolfSSL "settings.h" must be included in each source file using wolfSSL. + * The wolfSSL "settings.h" must appear before any other wolfSSL include. + */ #include <wolfssl.h> + + /* settings.h is included from Arduino `wolfssl.h`, but a good practice to + * include before any other wolfssl headers. As a reminder here: */ +#include <wolfssl/wolfcrypt/settings.h> + #include <wolfssl/wolfcrypt/aes.h> #if defined(NO_AES) or !defined(WOLFSSL_AES_COUNTER) or !defined(WOLFSSL_AES_128) diff --git a/Arduino/sketches/wolfssl_client/wolfssl_client.ino b/Arduino/sketches/wolfssl_client/wolfssl_client.ino index 8af1eafe..c56de7fd 100644 --- a/Arduino/sketches/wolfssl_client/wolfssl_client.ino +++ b/Arduino/sketches/wolfssl_client/wolfssl_client.ino @@ -6,7 +6,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, @@ -39,6 +39,18 @@ Tested with: /* If you have a private include, define it here, otherwise edit WiFi params */ /* #define MY_PRIVATE_CONFIG "/workspace/my_private_config.h" */ +#if defined(ARDUINO) && defined(ESP8266) + #warning "This example is not yet supported on Arduino ESP8266" +#endif + +#if defined(DEBUG_WOLFSSL) + /* Optionally enabled verbose wolfSSL debugging */ + #define DEBUG_WOLFSSL_MESSAGES_ON +#else + /* DEBUG_WOLFSSL needs to be enabled */ + #undef DEBUG_WOLFSSL_MESSAGES_ON +#endif + /* set REPEAT_CONNECTION to a non-zero value to continually run the example. */ #define REPEAT_CONNECTION 0 @@ -68,12 +80,12 @@ Tested with: /* the /workspace directory may contain a private config * excluded from GitHub with items such as WiFi passwords */ #include MY_PRIVATE_CONFIG - static const char ssid[] PROGMEM = MY_ARDUINO_WIFI_SSID; - static const char password[] PROGMEM = MY_ARDUINO_WIFI_PASSWORD; + static const char ssid[] PROGMEM = MY_ARDUINO_WIFI_SSID; + static const char password[] PROGMEM = MY_ARDUINO_WIFI_PASSWORD; #else /* when using WiFi capable boards: */ - static const char ssid[] PROGMEM = "your_SSID"; - static const char password[] PROGMEM = "your_PASSWORD"; + static const char ssid[] PROGMEM = "your_SSID"; + static const char password[] PROGMEM = "your_PASSWORD"; #endif #define BROADCAST_ADDRESS "255.255.255.255" @@ -132,6 +144,10 @@ Tested with: #elif defined(ESP8266) #define USING_WIFI #include <ESP8266WiFi.h> + /* Ensure the F() flash macro is defined */ + #ifndef F + #define F + #endif WiFiClient client; #elif defined(ARDUINO_SAM_DUE) @@ -140,7 +156,10 @@ Tested with: /* Needs "Ethernet by Various" library to be installed. Tested with V2.0.2 */ #include <Ethernet.h> EthernetClient client; - +#elif defined(ARDUINO_AVR_ETHERNET) || defined(ARDUINO_AVR_LEONARDO_ETH) + /* Boards such as arduino:avr:ethernet and arduino:avr:leonardoeth */ + #include <Ethernet.h> + EthernetClient client; #elif defined(ARDUINO_SAMD_NANO_33_IOT) #define USING_WIFI #include <SPI.h> @@ -153,6 +172,36 @@ Tested with: #include <WiFiNINA.h> WiFiClient client; +#elif defined(ARDUINO_SAMD_TIAN) + #include <Bridge.h> + #include <HttpClient.h> + HttpClient client; + /* Arduino Tian does not support network shields like the standard Ethernet or Wi-Fi shields. */ + #error "HttpClient cannot be used for this example" +#elif defined(ARDUINO_PORTENTA_X8) + /* The Portenta is a Linux device. See wolfSSL examples: + * https://github.com/wolfSSL/wolfssl/tree/master/examples + * By default Serial is disabled and mapped to ErrorSerial */ + #include <SerialRPC.h> + + /* ----No - network placeholders(compile - only) ---- */ + #include <IPAddress.h> + struct X8NoNetClient { + int write(const uint8_t*, size_t) { return -1; } + int available() { return 0; } + int read() { return -1; } + void stop() {} + bool connected() { return false; } + IPAddress remoteIP() { return IPAddress(0, 0, 0, 0); } + }; + struct X8NoNetServer { + explicit X8NoNetServer(uint16_t) {} + void begin() {} + X8NoNetClient available() { return X8NoNetClient(); } + }; + + X8NoNetClient client; + X8NoNetServer server(WOLFSSL_PORT); #elif defined(USING_WIFI) #define USING_WIFI #include <WiFi.h> @@ -205,7 +254,10 @@ static char errBuf[80]; static int EthernetSend(WOLFSSL* ssl, char* msg, int sz, void* ctx); static int EthernetReceive(WOLFSSL* ssl, char* reply, int sz, void* ctx); static int reconnect = RECONNECT_ATTEMPTS; +#if 0 +/* optional showPeerEx, currently disabled */ static int lng_index PROGMEM = 0; /* 0 = English */ +#endif #if defined(__arm__) #include <malloc.h> @@ -462,7 +514,8 @@ int setup_network(void) { /*****************************************************************************/ /* Arduino setup_wolfssl() */ /*****************************************************************************/ -int setup_wolfssl(void) { +int setup_wolfssl(void) +{ int ret = 0; WOLFSSL_METHOD* method; @@ -482,8 +535,14 @@ int setup_wolfssl(void) { #endif #if defined(DEBUG_WOLFSSL) - wolfSSL_Debugging_ON(); - Serial.println(F("wolfSSL Debugging is On!")); + Serial.println(F("wolfSSL Debugging is available! (DEBUG_WOLFSSL)")); + #if defined(DEBUG_WOLFSSL_MESSAGES_ON) + Serial.println(F("Enabling verbose messages wolfSSL_Debugging_ON")); + wolfSSL_Debugging_ON(); + #else + Serial.println(F("Enable verbose messages with wolfSSL_Debugging_ON")); + Serial.println(F("or define DEBUG_WOLFSSL_MESSAGES_ON")); + #endif #else Serial.println(F("wolfSSL Debugging is Off! (enable with DEBUG_WOLFSSL)")); #endif @@ -509,6 +568,7 @@ int setup_wolfssl(void) { * It is best on embedded devices to choose a TLS session cache size. */ #endif + /* Initialize wolfSSL before assigning ctx */ ret = wolfSSL_Init(); if (ret == WOLFSSL_SUCCESS) { Serial.println("Successfully called wolfSSL_Init"); @@ -543,7 +603,8 @@ int setup_wolfssl(void) { /*****************************************************************************/ /* Arduino setup_certificates() */ /*****************************************************************************/ -int setup_certificates(void) { +int setup_certificates(void) +{ int ret = 0; Serial.println(F("Initializing certificates...")); @@ -609,7 +670,8 @@ int setup_certificates(void) { /* Arduino setup() */ /*****************************************************************************/ /*****************************************************************************/ -void setup(void) { +void setup(void) +{ int i = 0; Serial.begin(SERIAL_BAUD); while (!Serial && (i < 10)) { @@ -650,13 +712,17 @@ void setup(void) { wolfSSL_SetIOSend(ctx, EthernetSend); wolfSSL_SetIORecv(ctx, EthernetReceive); +#if defined THIS_USER_SETTINGS_VERSION + Serial.print(F("This user_settings.h version:")) + Serial.println(THIS_USER_SETTINGS_VERSION) +#endif + Serial.println(F("Completed Arduino setup!")); /* See companion wolfssl_server.ino code; server begins listening here * https://github.com/wolfSSL/wolfssl/tree/master/IDE/ARDUINO/sketches/wolfssl_server * Any other server will work. See also: * https://github.com/wolfSSL/wolfssl/tree/master/examples/client */ - /* See companion wolfssl_server.ino code */ return; } /* Arduino setup */ @@ -731,7 +797,7 @@ int error_check_ssl(WOLFSSL* ssl, int this_ret, bool halt_on_error, } return err; -} +} /* error_check_ssl */ /*****************************************************************************/ /*****************************************************************************/ diff --git a/Arduino/sketches/wolfssl_client_dtls/README.md b/Arduino/sketches/wolfssl_client_dtls/README.md new file mode 100644 index 00000000..924225b7 --- /dev/null +++ b/Arduino/sketches/wolfssl_client_dtls/README.md @@ -0,0 +1,28 @@ +# Arduino Basic DTLS Listening Client + +Open the [wolfssl_client_dtls.ino](./wolfssl_client_dtls.ino) file in the Arduino IDE. + +If using WiFi, be sure to set `ssid` and `password` values. + +May need "Ethernet by Various" library to be installed. Tested with v2.0.2 and v2.8.1. + +See the `#define WOLFSSL_TLS_SERVER_HOST` to set your own server address. + +Other IDE products are also supported, such as: + +- [PlatformIO in VS Code](https://docs.platformio.org/en/latest/frameworks/arduino.html) +- [VisualGDB](https://visualgdb.com/tutorials/arduino/) +- [VisualMicro](https://www.visualmicro.com/) + +For examples on other platforms, see the [IDE directory](https://github.com/wolfssl/wolfssl/tree/master/IDE). +Additional examples can be found on [wolfSSL/wolfssl-examples](https://github.com/wolfSSL/wolfssl-examples/). + + +### Troubleshooting + +When encountering odd errors such as `undefined reference to ``_impure_ptr'`, try cleaning the Arduino +cache directories. For Windows, that's typically in: + +```text +C:\Users\%USERNAME%\AppData\Local\Temp\arduino\sketches +``` diff --git a/Arduino/sketches/wolfssl_client_dtls/wolfssl_client_dtls.ino b/Arduino/sketches/wolfssl_client_dtls/wolfssl_client_dtls.ino new file mode 100644 index 00000000..e4e8fec6 --- /dev/null +++ b/Arduino/sketches/wolfssl_client_dtls/wolfssl_client_dtls.ino @@ -0,0 +1,950 @@ +/* + * client-dtls13.c + * + * Copyright (C) 2006-2025 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 3 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 + * + *============================================================================= + * + * Bare-bones example of a DTLS 1.3 client for instructional/learning purposes. + * This example uses blocking sockets for simplicity. + * + * Define USE_DTLS12 to use DTLS 1.2 instead of DTLS 1.3 +/* +Tested with: + +1) Intel Galileo acting as the Client, with a laptop acting as a server using + the server example provided in examples/server. + Legacy Arduino v1.86 was used to compile and program the Galileo + +2) Espressif ESP32 WiFi + +3) Arduino Due, Nano33 IoT, Nano RP-2040 +*/ + +/* + * Note to code editors: the Arduino client and server examples are edited in + * parallel for side-by-side comparison between examples. + */ + +/* If you have a private include, define it here, otherwise edit WiFi params */ +/* #define MY_PRIVATE_CONFIG "/workspace/my_private_config.h" */ + +#if defined(ARDUINO) && defined(ESP8266) + #warning "This example is not yet supported on Arduino ESP8266" +#endif + +#if defined(DEBUG_WOLFSSL) + /* Optionally enabled verbose wolfSSL debugging */ + #define DEBUG_WOLFSSL_MESSAGES_ON +#else + /* DEBUG_WOLFSSL needs to be enabled */ + #undef DEBUG_WOLFSSL_MESSAGES_ON +#endif + +/* set REPEAT_CONNECTION to a non-zero value to continually run the example. */ +#define REPEAT_CONNECTION 0 + +/* Edit this with your other DTLS host server address to connect to: */ +#define WOLFSSL_DTLS_SERVER_HOST "192.168.1.107" + +/* wolfssl TLS examples communicate on port 11111 */ +#define WOLFSSL_PORT 11111 + +/* Choose a monitor serial baud rate: 9600, 14400, 19200, 57600, 74880, etc. */ +#define SERIAL_BAUD 115200 + +/* We'll wait up to 2000 milliseconds to properly shut down connection */ +#define SHUTDOWN_DELAY_MS 2000 + +/* Number of times to retry connection. */ +#define RECONNECT_ATTEMPTS 20 + +/* Number of DTLS messages to send. Use -1 for continual messages. */ +#define DTLS_MESSAGE_CT 42 + +/* Assume bad socket until proven otherwise */ +#define INVALID_SOCKET -1 + +/* Maximum size in bytes of buffer to send and receive */ +#define MAXLINE 128 + +/* Optional stress test. Define to consume memory until exhausted: */ +/* #define MEMORY_STRESS_TEST */ + +/* Choose client or server example, not both. */ +#define WOLFSSL_CLIENT_EXAMPLE +/* #define WOLFSSL_SERVER_EXAMPLE */ + +#if defined(MY_PRIVATE_CONFIG) + /* the /workspace directory may contain a private config + * excluded from GitHub with items such as WiFi passwords */ + #include MY_PRIVATE_CONFIG + static const char ssid[] PROGMEM = MY_ARDUINO_WIFI_SSID; + static const char password[] PROGMEM = MY_ARDUINO_WIFI_PASSWORD; +#else + /* when using WiFi capable boards: */ + static const char ssid[] PROGMEM = "your_SSID"; + static const char password[] PROGMEM = "your_PASSWORD"; +#endif + +#define BROADCAST_ADDRESS "255.255.255.255" + +/* There's an optional 3rd party NTPClient library by Fabrice Weinberg. + * If it is installed, uncomment define USE_NTP_LIB here: */ +/* #define USE_NTP_LIB */ +#ifdef USE_NTP_LIB + #include <NTPClient.h> +#endif + +/* wolfSSL user_settings.h must be included from settings.h + * Make all configurations changes in user_settings.h + * Do not edit wolfSSL `settings.h` or `config.h` files. + * Do not explicitly include user_settings.h in any source code. + * Each Arduino sketch that uses wolfSSL must have: #include "wolfssl.h" + * C/C++ source files can use: #include <wolfssl/wolfcrypt/settings.h> + * The wolfSSL "settings.h" must be included in each source file using wolfSSL. + * The wolfSSL "settings.h" must appear before any other wolfSSL include. + */ +#include <wolfssl.h> +/* Important: make sure settings.h appears before any other wolfSSL headers */ +#include <wolfssl/wolfcrypt/settings.h> +/* Reminder: settings.h includes user_settings.h + * For ALL project wolfSSL settings, see: + * [your path]/Arduino\libraries\wolfSSL\src\user_settings.h */ +#include <wolfssl/ssl.h> +#include <wolfssl/certs_test.h> +#include <wolfssl/wolfcrypt/error-crypt.h> + +#ifndef WOLFSSL_DTLS + /* Support for DTLS by default was added after wolfSSL v5.8.2 release */ + #error "This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library" +#endif + +/* Define DEBUG_WOLFSSL in user_settings.h for more verbose logging. */ +#if defined(DEBUG_WOLFSSL) + #define PROGRESS_DOT F("") +#else + #define PROGRESS_DOT F(".") +#endif + +/* Convert a macro to a string */ +#define xstr(x) str(x) +#define str(x) #x + +/* optional board-specific networking includes */ +#if defined(ESP32) + #define USING_WIFI + #include <WiFi.h> + #include <WiFiUdp.h> + #ifdef USE_NTP_LIB + WiFiUDP ntpUDP; + #endif + /* Ensure the F() flash macro is defined */ + #ifndef F + #define F + #endif + WiFiClient client; + +#elif defined(ESP8266) + #define USING_WIFI + #include <ESP8266WiFi.h> + WiFiClient client; + +#elif defined(ARDUINO_SAM_DUE) + #include <SPI.h> + /* There's no WiFi/Ethernet on the Due. Requires Ethernet Shield. + /* Needs "Ethernet by Various" library to be installed. Tested with V2.0.2 */ + #include <Ethernet.h> + EthernetClient client; +#elif defined(ARDUINO_AVR_ETHERNET) || defined(ARDUINO_AVR_LEONARDO_ETH) + /* Boards such as arduino:avr:ethernet and arduino:avr:leonardoeth */ + #include <Ethernet.h> + EthernetClient client; + +#elif defined(ARDUINO_SAMD_NANO_33_IOT) + #define USING_WIFI + #include <SPI.h> + #include <WiFiNINA.h> /* Needs Arduino WiFiNINA library installed manually */ + WiFiClient client; + +#elif defined(ARDUINO_ARCH_RP2040) + #define USING_WIFI + #include <SPI.h> + #include <WiFiNINA.h> + WiFiClient client; + +#elif defined(ARDUINO_SAMD_TIAN) + #include <Bridge.h> + #include <HttpClient.h> + HttpClient client; + /* Arduino Tian does not support network shields like the standard Ethernet or Wi-Fi shields. */ + #error "HttpClient cannot be used for this example" +#elif defined(ARDUINO_PORTENTA_X8) + /* The Portenta is a Linux device. See wolfSSL examples: + * https://github.com/wolfSSL/wolfssl/tree/master/examples + * By default Serial is disabled and mapped to ErrorSerial */ + #include <SerialRPC.h> + + /* ----No - network placeholders(compile - only) ---- */ + #include <IPAddress.h> + struct X8NoNetClient { + int write(const uint8_t*, size_t) { return -1; } + int available() { return 0; } + int read() { return -1; } + void stop() {} + bool connected() { return false; } + IPAddress remoteIP() { return IPAddress(0, 0, 0, 0); } + }; + struct X8NoNetServer { + explicit X8NoNetServer(uint16_t) {} + void begin() {} + X8NoNetClient available() { return X8NoNetClient(); } + }; + + X8NoNetClient client; + X8NoNetServer server(WOLFSSL_PORT); +#elif defined(USING_WIFI) + #define USING_WIFI + #include <WiFi.h> + #include <WiFiUdp.h> + #ifdef USE_NTP_LIB + WiFiUDP ntpUDP; + #endif + WiFiClient client; + +/* TODO +#elif defined(OTHER_BOARD) +*/ +#else + /* assume all other boards using WiFi library. Edit as needed: */ + #include <WiFi.h> + #define USING_WIFI + WiFiClient client; +#endif + +/* Only for syntax highlighters to show interesting options enabled: */ +#if defined(HAVE_SNI) \ + || defined(HAVE_MAX_FRAGMENT) \ + || defined(HAVE_TRUSTED_CA) \ + || defined(HAVE_TRUNCATED_HMAC) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) \ + || defined(HAVE_SUPPORTED_CURVES) \ + || defined(HAVE_ALPN) \ + || defined(HAVE_SESSION_TICKET) \ + || defined(HAVE_SECURE_RENEGOTIATION) \ + || defined(HAVE_SERVER_RENEGOTIATION_INFO) +#endif + +static const char host[] PROGMEM = WOLFSSL_DTLS_SERVER_HOST; /* server to connect to */ +static const int port PROGMEM = WOLFSSL_PORT; /* port on server to connect to */ + +static WOLFSSL_CTX* ctx = NULL; +static WOLFSSL* ssl = NULL; +static char* wc_error_message = (char*)malloc(80 + 1); +static char errBuf[80]; + +#if defined(MEMORY_STRESS_TEST) + #define MEMORY_STRESS_ITERATIONS 100 + #define MEMORY_STRESS_BLOCK_SIZE 1024 + #define MEMORY_STRESS_INITIAL (4*1024) + static char* memory_stress[MEMORY_STRESS_ITERATIONS]; /* typically 1K per item */ + static int mem_ctr = 0; +#endif + +static int EthernetSend(WOLFSSL* ssl, char* msg, int sz, void* ctx); +static int EthernetReceive(WOLFSSL* ssl, char* reply, int sz, void* ctx); +static int reconnect = RECONNECT_ATTEMPTS; +#if 0 +/* optional showPeerEx, currently disabled */ +static int lng_index PROGMEM = 0; /* 0 = English */ +#endif + +#if defined(__arm__) + #include <malloc.h> + extern char _end; + extern "C" char *sbrk(int i); + static char *ramstart=(char *)0x20070000; + static char *ramend=(char *)0x20088000; +#endif + +/*****************************************************************************/ +/* fail_wait - in case of unrecoverable error */ +/*****************************************************************************/ +int fail_wait(void) { + show_memory(); + + Serial.println(F("Failed. Halt.")); + while (1) { + delay(1000); + } + return 0; +} + +/*****************************************************************************/ +/* show_memory() to optionally view during debugging. */ +/*****************************************************************************/ +int show_memory(void) +{ +#if defined(__arm__) + struct mallinfo mi = mallinfo(); + + char *heapend=sbrk(0); + register char * stack_ptr asm("sp"); + #if defined(DEBUG_WOLFSSL_VERBOSE) + Serial.print(" arena="); + Serial.println(mi.arena); + Serial.print(" ordblks="); + Serial.println(mi.ordblks); + Serial.print(" uordblks="); + Serial.println(mi.uordblks); + Serial.print(" fordblks="); + Serial.println(mi.fordblks); + Serial.print(" keepcost="); + Serial.println(mi.keepcost); + #endif + + #if defined(DEBUG_WOLFSSL) || defined(MEMORY_STRESS_TEST) + Serial.print("Estimated free memory: "); + Serial.print(stack_ptr - heapend + mi.fordblks); + Serial.println(F(" bytes")); + #endif + + #if (0) + /* Experimental: not supported on all devices: */ + Serial.print("RAM Start %lx\n", (unsigned long)ramstart); + Serial.print("Data/Bss end %lx\n", (unsigned long)&_end); + Serial.print("Heap End %lx\n", (unsigned long)heapend); + Serial.print("Stack Ptr %lx\n",(unsigned long)stack_ptr); + Serial.print("RAM End %lx\n", (unsigned long)ramend); + + Serial.print("Heap RAM Used: ",mi.uordblks); + Serial.print("Program RAM Used ",&_end - ramstart); + Serial.print("Stack RAM Used ",ramend - stack_ptr); + + Serial.print("Estimated Free RAM: %d\n\n",stack_ptr - heapend + mi.fordblks); + #endif +#else + Serial.println(F("show_memory() not implemented for this platform")); +#endif + return 0; +} + +/*****************************************************************************/ +/* Arduino setup_hardware() */ +/*****************************************************************************/ +int setup_hardware(void) { + int ret = 0; + +#if defined(ARDUINO_SAMD_NANO_33_IOT) + Serial.println(F("Detected known tested and working Arduino Nano 33 IoT")); +#elif defined(ARDUINO_ARCH_RP2040) + Serial.println(F("Detected known tested and working Arduino RP-2040")); +#elif defined(__arm__) && defined(ID_TRNG) && defined(TRNG) + /* need to manually turn on random number generator on Arduino Due, etc. */ + pmc_enable_periph_clk(ID_TRNG); + trng_enable(TRNG); + Serial.println(F("Enabled ARM TRNG")); +#endif + + show_memory(); + randomSeed(analogRead(0)); + return ret; +} + +/*****************************************************************************/ +/* Arduino setup_datetime() */ +/* The device needs to have a valid date within the valid range of certs. */ +/*****************************************************************************/ +int setup_datetime(void) { + int ret = 0; + int ntp_tries = 20; + + /* we need a date in the range of cert expiration */ +#ifdef USE_NTP_LIB + #if defined(ESP32) + NTPClient timeClient(ntpUDP, "pool.ntp.org"); + + timeClient.begin(); + timeClient.update(); + delay(1000); + while (!timeClient.isTimeSet() && (ntp_tries > 0)) { + timeClient.forceUpdate(); + Serial.println(F("Waiting for NTP update")); + delay(2000); + ntp_tries--; + } + if (ntp_tries <= 0) { + Serial.println(F("Warning: gave up waiting on NTP")); + } + Serial.println(timeClient.getFormattedTime()); + Serial.println(timeClient.getEpochTime()); + #endif +#endif + +#if defined(ESP32) + /* see esp32-hal-time.c */ + ntp_tries = 5; + /* Replace "pool.ntp.org" with your preferred NTP server */ + configTime(0, 0, "pool.ntp.org"); + + /* Wait for time to be set */ + while ((time(nullptr) <= 100000) && ntp_tries > 0) { + Serial.println(F("Waiting for time to be set...")); + delay(2000); + ntp_tries--; + } +#endif + + return ret; +} /* setup_datetime */ + +/*****************************************************************************/ +/* Arduino setup_network() */ +/*****************************************************************************/ +int setup_network(void) { + int ret = 0; + +#if defined(USING_WIFI) + int status = WL_IDLE_STATUS; + + /* The ESP8266 & ESP32 support both AP and STA. We'll use STA: */ + #if defined(ESP8266) || defined(ESP32) + WiFi.mode(WIFI_STA); + #else + String fv; + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + /* don't continue if no network */ + while (true) ; + } + + fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + #endif + + Serial.print(F("Connecting to WiFi ")); + Serial.print(ssid); + status = WiFi.begin(ssid, password); + while (status != WL_CONNECTED) { + delay(1000); + Serial.print(F(".")); + Serial.print(status); + status = WiFi.status(); + } + + Serial.println(F(" Connected!")); +#else + /* Newer Ethernet shields have a + * MAC address printed on a sticker on the shield */ + byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; + IPAddress ip(192, 168, 1, 42); + IPAddress myDns(192, 168, 1, 1); + Ethernet.init(10); /* Most Arduino shields */ + /* Ethernet.init(5); * MKR ETH Shield */ + /* Ethernet.init(0); * Teensy 2.0 */ + /* Ethernet.init(20); * Teensy++ 2.0 */ + /* Ethernet.init(15); * ESP8266 with Adafruit FeatherWing Ethernet */ + /* Ethernet.init(33); * ESP32 with Adafruit FeatherWing Ethernet */ + Serial.println(F("Initialize Ethernet with DHCP:")); + if (Ethernet.begin(mac) == 0) { + Serial.println(F("Failed to configure Ethernet using DHCP")); + /* Check for Ethernet hardware present */ + if (Ethernet.hardwareStatus() == EthernetNoHardware) { + Serial.println(F("Ethernet shield was not found.")); + while (true) { + delay(1); /* do nothing */ + } + } + if (Ethernet.linkStatus() == LinkOFF) { + Serial.println(F("Ethernet cable is not connected.")); + } + /* try to configure using IP address instead of DHCP : */ + Ethernet.begin(mac, ip, myDns); + } + else { + Serial.print(F(" DHCP assigned IP ")); + Serial.println(Ethernet.localIP()); + } + /* We'll assume the Ethernet connection is ready to go. */ +#endif + + Serial.println(F("********************************************************")); + Serial.print(F(" wolfSSL Example Client IP = ")); +#if defined(USING_WIFI) + Serial.println(WiFi.localIP()); +#else + Serial.println(Ethernet.localIP()); +#endif + Serial.print(F(" Configured Server Host to connect to: ")); + Serial.println(host); + Serial.println(F("********************************************************")); + Serial.println(F("Setup network complete.")); + + return ret; +} + +/*****************************************************************************/ +/* Arduino setup_wolfssl() */ +/*****************************************************************************/ +int setup_wolfssl(void) +{ + int ret = 0; + WOLFSSL_METHOD* method; + + /* Show a revision of wolfssl user_settings.h file in use when available: */ +#if defined(WOLFSSL_USER_SETTINGS_ID) + Serial.print(F("WOLFSSL_USER_SETTINGS_ID: ")); + Serial.println(F(WOLFSSL_USER_SETTINGS_ID)); +#else + Serial.println(F("No WOLFSSL_USER_SETTINGS_ID found.")); +#endif + +#if defined(NO_WOLFSSL_SERVER) + Serial.println(F("wolfSSL server code disabled to save space.")); +#endif +#if defined(NO_WOLFSSL_CLIENT) + Serial.println(F("wolfSSL client code disabled to save space.")); +#endif + +#if defined(DEBUG_WOLFSSL) + Serial.println(F("wolfSSL Debugging is available! (DEBUG_WOLFSSL)")); + #if defined(DEBUG_WOLFSSL_MESSAGES_ON) + Serial.println(F("Enabling verbose messages wolfSSL_Debugging_ON")); + wolfSSL_Debugging_ON(); + #else + Serial.println(F("Enable verbose messages with wolfSSL_Debugging_ON")); + Serial.println(F("or define DEBUG_WOLFSSL_MESSAGES_ON")); + #endif +#else + Serial.println(F("wolfSSL Debugging is Off! (enable with DEBUG_WOLFSSL)")); +#endif + + /* See ssl.c for TLS cache settings. Larger cache = use more RAM. */ +#if defined(NO_SESSION_CACHE) + Serial.println(F("wolfSSL TLS NO_SESSION_CACHE")); +#elif defined(MICRO_SESSION_CACHEx) + Serial.println(F("wolfSSL TLS MICRO_SESSION_CACHE")); +#elif defined(SMALL_SESSION_CACHE) + Serial.println(F("wolfSSL TLS SMALL_SESSION_CACHE")); +#elif defined(MEDIUM_SESSION_CACHE) + Serial.println(F("wolfSSL TLS MEDIUM_SESSION_CACHE")); +#elif defined(BIG_SESSION_CACHE) + Serial.println(F("wolfSSL TLS BIG_SESSION_CACHE")); +#elif defined(HUGE_SESSION_CACHE) + Serial.println(F("wolfSSL TLS HUGE_SESSION_CACHE")); +#elif defined(HUGE_SESSION_CACHE) + Serial.println(F("wolfSSL TLS HUGE_SESSION_CACHE")); +#else + Serial.println(F("WARNING: Unknown or no TLS session cache setting.")); + /* See wolfssl/src/ssl.c for amount of memory used. + * It is best on embedded devices to choose a TLS session cache size. */ +#endif + + /* Initialize wolfSSL before assigning ctx */ + ret = wolfSSL_Init(); + if (ret == WOLFSSL_SUCCESS) { + Serial.println("Successfully called wolfSSL_Init"); + } + else { + Serial.println("ERROR: wolfSSL_Init failed"); + } + + /* See companion server example with wolfSSLv23_server_method here. + * method = wolfSSLv23_client_method()); SSL 3.0 - TLS 1.3. + * method = wolfTLSv1_2_client_method(); only TLS 1.2 + * method = wolfTLSv1_3_client_method(); only TLS 1.3 + * + * see Arduino\libraries\wolfssl\src\user_settings.h */ + + Serial.println("Here we go!"); + +#ifdef WOLFSSL_DTLS13 + Serial.println(F("Setting wolfDTLSv1_3_client_method")); + method = wolfDTLSv1_3_client_method(); +#else + Serial.println(F("Setting wolfDTLSv1_2_client_method")); + method = wolfDTLSv1_2_client_method(); +#endif + ctx = wolfSSL_CTX_new(method); + if (ctx == NULL) { + fail_wait(); + } + + if (method == NULL) { + Serial.println(F("Unable to get wolfssl client method")); + fail_wait(); + } + + ctx = wolfSSL_CTX_new(method); + if (ctx == NULL) { + Serial.println(F("unable to get ctx")); + fail_wait(); + } + + return ret; +} + +/*****************************************************************************/ +/* Arduino setup_certificates() */ +/*****************************************************************************/ +int setup_certificates(void) +{ + int ret = 0; + + /* See user_settings.h that should have included wolfssl/certs_test.h */ + + Serial.println(F("Initializing certificates...")); + show_memory(); + + /* Use built-in validation, No verification callback function: */ + wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, 0); + + /* Certificate */ + Serial.println("Initializing certificates..."); + ret = wolfSSL_CTX_use_certificate_buffer(ctx, + CTX_CLIENT_CERT, + CTX_CLIENT_CERT_SIZE, + CTX_CLIENT_CERT_TYPE); + if (ret == WOLFSSL_SUCCESS) { + Serial.print("Success: use certificate: "); + Serial.println(xstr(CTX_SERVER_CERT)); + } + else { + Serial.println(F("Error: wolfSSL_CTX_use_certificate_buffer failed: ")); + wc_ErrorString(ret, wc_error_message); + Serial.println(wc_error_message); + fail_wait(); + } + + /* Setup private client key */ + ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, + CTX_CLIENT_KEY, + CTX_CLIENT_KEY_SIZE, + CTX_CLIENT_KEY_TYPE); + if (ret == WOLFSSL_SUCCESS) { + Serial.print("Success: use private key buffer: "); + Serial.println(xstr(CTX_SERVER_KEY)); + } + else { + Serial.println(F("Error: wolfSSL_CTX_use_PrivateKey_buffer failed: ")); + wc_ErrorString(ret, wc_error_message); + Serial.println(wc_error_message); + fail_wait(); + } + + ret = wolfSSL_CTX_load_verify_buffer(ctx, + CTX_CA_CERT, + CTX_CA_CERT_SIZE, + CTX_CA_CERT_TYPE); + if (ret == WOLFSSL_SUCCESS) { + Serial.println(F("Success: load_verify CTX_CA_CERT")); + } + else { + Serial.println(F("Error: wolfSSL_CTX_load_verify_buffer failed: ")); + wc_ErrorString(ret, wc_error_message); + Serial.println(wc_error_message); + fail_wait(); + } + + return ret; +} /* Arduino setup */ + +/*****************************************************************************/ +/*****************************************************************************/ +/* Arduino setup() */ +/*****************************************************************************/ +/*****************************************************************************/ +void setup(void) { + int i = 0; + Serial.begin(SERIAL_BAUD); + while (!Serial && (i < 10)) { + /* wait for serial port to connect. Needed for native USB port only */ + delay(1000); + i++; + } + Serial.println(F("")); + Serial.println(F("")); + Serial.println(F("wolfSSL DTLS Client Example Startup.")); + + /* Optionally pre-allocate a large block of memory for testing */ +#if defined(MEMORY_STRESS_TEST) + Serial.println(F("WARNING: Memory Stress Test Active!")); + Serial.print(F("Allocating extra memory: ")); + Serial.print(MEMORY_STRESS_INITIAL); + Serial.println(F(" bytes...")); + memory_stress[mem_ctr] = (char*)malloc(MEMORY_STRESS_INITIAL); + show_memory(); +#endif + + setup_hardware(); + + setup_network(); + + setup_datetime(); + + setup_wolfssl(); + + setup_certificates(); + +#if defined THIS_USER_SETTINGS_VERSION + Serial.print(F("This user_settings.h version:")) + Serial.println(THIS_USER_SETTINGS_VERSION) +#endif + + Serial.println(F("Completed Arduino setup!")); + /* See companion wolfssl_server_dtls.ino code; server begins listening here + * https://github.com/wolfSSL/wolfssl-examples/tree/master/Arduino/sketches/wolfssl_server_dtls + * Any other DTLS server will work. See also: + * https://github.com/wolfSSL/wolfssl/tree/master/examples/client + */ + return; +} /* Arduino setup */ + +/*****************************************************************************/ +/* wolfSSL error_check() */ +/*****************************************************************************/ +int error_check(int this_ret, bool halt_on_error, + const __FlashStringHelper* message) { + int ret = 0; + if (this_ret == WOLFSSL_SUCCESS) { + Serial.print(F("Success: ")); + Serial.println(message); + } + else { + Serial.print(F("ERROR: return = ")); + Serial.print(this_ret); + Serial.print(F(": ")); + Serial.println(message); + Serial.println(wc_GetErrorString(this_ret)); + if (halt_on_error) { + fail_wait(); + } + } + show_memory(); + + return ret; +} /* error_check */ + +/*****************************************************************************/ +/* wolfSSL error_check_ssl */ +/* Parameters: */ +/* ssl is the current WOLFSSL object pointer */ +/* halt_on_error set to true to suspend operations for critical error */ +/* message is expected to be a memory-efficient F("") macro string */ +/*****************************************************************************/ +int error_check_ssl(WOLFSSL* ssl, int this_ret, bool halt_on_error, + const __FlashStringHelper* message) { + int err = 0; + + if (ssl == NULL) { + Serial.println(F("ssl is Null; Unable to allocate SSL object?")); +#ifndef DEBUG_WOLFSSL + Serial.println(F("Define DEBUG_WOLFSSL in user_settings.h for more.")); +#else + Serial.println(F("See wolfssl/wolfcrypt/error-crypt.h for codes.")); +#endif + Serial.print(F("ERROR: ")); + Serial.println(message); + show_memory(); + if (halt_on_error) { + fail_wait(); + } + } + else { + err = wolfSSL_get_error(ssl, this_ret); + if (err == WOLFSSL_SUCCESS) { + Serial.print(F("Success m: ")); + Serial.println(message); + } + else { + if (err < 0) { + wolfSSL_ERR_error_string(err, errBuf); + Serial.print(F("WOLFSSL Error: ")); + Serial.print(err); + Serial.print(F("; ")); + Serial.println(errBuf); + } + else { + Serial.println(F("Success: ssl object.")); + } + } + } + + return err; +} /* error_check_ssl */ + +/*****************************************************************************/ +/*****************************************************************************/ +/* Arduino loop() */ +/*****************************************************************************/ +/*****************************************************************************/ +void loop() +{ + /* standard variables used in a dtls client */ + char sendLine[MAXLINE] = "Hello DTLS wolfSSL!"; + char recvLine[MAXLINE - 1]; + struct sockaddr_in servAddr; + const char* cipherName; + int msg_ct = 0; + int n = 0; + int sockfd = INVALID_SOCKET; + int err; + int ret; + int exitVal = 1; + + /* Assign ssl variable */ + ssl = wolfSSL_new(ctx); + if (ssl == NULL) { + Serial.println(F("unable to get ssl object\n")); + goto cleanup; + } + + /* servAddr setup */ + memset(&servAddr, 0, sizeof(servAddr)); + servAddr.sin_family = AF_INET; + servAddr.sin_port = htons(WOLFSSL_PORT); + if (inet_pton(AF_INET, WOLFSSL_DTLS_SERVER_HOST, &servAddr.sin_addr) < 1) { + perror("inet_pton()"); + goto cleanup; + } + + if (wolfSSL_dtls_set_peer(ssl, &servAddr, sizeof(servAddr)) + != WOLFSSL_SUCCESS) { + Serial.println(F("wolfSSL_dtls_set_peer failed\n")); + goto cleanup; + } + + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + perror("socket()"); + goto cleanup; + } + + /* Set the file descriptor for ssl */ + if (wolfSSL_set_fd(ssl, sockfd) != WOLFSSL_SUCCESS) { + Serial.println(F("cannot set socket file descriptor\n")); + goto cleanup; + } + + Serial.print(F("Connecting to wolfSSL DTLS Secure Server...")); + do { + reconnect--; + err = 0; /* reset error */ + Serial.println(F("wolfSSL_connect ...")); + ret = wolfSSL_connect(ssl); + if ((ret != WOLFSSL_SUCCESS) && (ret != WC_PENDING_E)) { + Serial.println(F("Failed connection, checking error.")); + err = error_check_ssl(ssl, ret, true, + F("Create WOLFSSL object from ctx")); + Serial.print("err ="); + Serial.println(err); + } + else { + Serial.print(PROGRESS_DOT); + } + } while ((err == WC_PENDING_E) && (reconnect > 0)); + + Serial.println(); + Serial.println(F("Connected!")); + Serial.print(F("SSL version is ")); + Serial.println(wolfSSL_get_version(ssl)); + + cipherName = wolfSSL_get_cipher(ssl); + Serial.print(F("SSL cipher suite is ")); + Serial.println(cipherName); + +/*****************************************************************************/ +/* Code for sending datagram to server */ +/*****************************************************************************/ + Serial.println(F("Begin DTLS Loop...")); + msg_ct = 0; + while (msg_ct < DTLS_MESSAGE_CT || (DTLS_MESSAGE_CT == -1)) { + msg_ct++; + + /* Send sendLine to the server */ + Serial.print(F("Sending Message #")); + Serial.print(msg_ct); + Serial.print(F(": \"")); + Serial.print(F(sendLine)); + Serial.println(F("\" ... ")); + if (wolfSSL_write(ssl, sendLine, strlen(sendLine)) != strlen(sendLine)) { + err = error_check_ssl(ssl, ret, true, + F("Create WOLFSSL object from ctx")); + Serial.print("err ="); + Serial.println(err); + goto cleanup; + } + + /* n is the # of bytes received */ + Serial.println(F("Reading Message...")); + n = wolfSSL_read(ssl, recvLine, sizeof(recvLine)-1); + + if (n > 0) { + /* Add a terminating character to the generic server message */ + recvLine[n] = '\0'; + Serial.println(F("Got Message...")); + printf("%s\n", recvLine); + } + else { + err = error_check_ssl(ssl, ret, true, + F("Create WOLFSSL object from ctx")); + Serial.print("err ="); + Serial.println(err); + goto cleanup; + } + + } /* (msg_ct > DTLS_MESSAGE_CT || (DTLS_MESSAGE_CT == -1)) */ + + exitVal = 0; +cleanup: + if (ssl != NULL) { + /* Attempt a full shutdown */ + ret = wolfSSL_shutdown(ssl); + if (ret == WOLFSSL_SHUTDOWN_NOT_DONE) { + Serial.println("Not done... Try again wolfSSL_shutdown"); + ret = wolfSSL_shutdown(ssl); + } + + if (ret != WOLFSSL_SUCCESS) { + err = error_check_ssl(ssl, ret, true, + F("Create WOLFSSL object from ctx")); + Serial.print("err ="); + Serial.println(err); + Serial.println(F("wolfSSL_shutdown failed\n")); + } + wolfSSL_free(ssl); + } + if (sockfd != INVALID_SOCKET) { + close(sockfd); + } + if (ctx != NULL) { + wolfSSL_CTX_free(ctx); + } + wolfSSL_Cleanup(); + + Serial.print(F("Reset to start over.")); + Serial.print(F("Done!")); + + while (1) { + delay(1000); + } +} /* Arduino loop */ + diff --git a/Arduino/sketches/wolfssl_server/wolfssl_server.ino b/Arduino/sketches/wolfssl_server/wolfssl_server.ino index 1b9d4ede..7f75bcc7 100644 --- a/Arduino/sketches/wolfssl_server/wolfssl_server.ino +++ b/Arduino/sketches/wolfssl_server/wolfssl_server.ino @@ -6,7 +6,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, @@ -39,6 +39,18 @@ Tested with: /* If you have a private include, define it here, otherwise edit WiFi params */ /* #define MY_PRIVATE_CONFIG "/workspace/my_private_config.h" */ +#if defined(ARDUINO) && defined(ESP8266) + #warning "This example is not yet supported on Arduino ESP8266" +#endif + +#if defined(DEBUG_WOLFSSL) + /* Optionally enabled verbose wolfSSL debugging */ + #define DEBUG_WOLFSSL_MESSAGES_ON +#else + /* DEBUG_WOLFSSL needs to be enabled */ + #undef DEBUG_WOLFSSL_MESSAGES_ON +#endif + /* set REPEAT_CONNECTION to a non-zero value to continually run the example. */ #define REPEAT_CONNECTION 1 @@ -68,12 +80,12 @@ Tested with: /* the /workspace directory may contain a private config * excluded from GitHub with items such as WiFi passwords */ #include MY_PRIVATE_CONFIG - static const char ssid[] PROGMEM = MY_ARDUINO_WIFI_SSID; - static const char password[] PROGMEM = MY_ARDUINO_WIFI_PASSWORD; + static const char ssid[] PROGMEM = MY_ARDUINO_WIFI_SSID; + static const char password[] PROGMEM = MY_ARDUINO_WIFI_PASSWORD; #else /* when using WiFi capable boards: */ - static const char ssid[] PROGMEM = "your_SSID"; - static const char password[] PROGMEM = "your_PASSWORD"; + static const char ssid[] PROGMEM = "your_SSID"; + static const char password[] PROGMEM = "your_PASSWORD"; #endif #define BROADCAST_ADDRESS "255.255.255.255" @@ -132,6 +144,10 @@ Tested with: #elif defined(ESP8266) #define USING_WIFI #include <ESP8266WiFi.h> + /* Ensure the F() flash macro is defined */ + #ifndef F + #define F + #endif WiFiClient client; WiFiServer server(WOLFSSL_PORT); #elif defined(ARDUINO_SAM_DUE) @@ -140,7 +156,12 @@ Tested with: /* Needs "Ethernet by Various" library to be installed. Tested with V2.0.2 */ #include <Ethernet.h> EthernetClient client; - EthernetClient server(WOLFSSL_PORT); + EthernetServer server(WOLFSSL_PORT); +#elif defined(ARDUINO_AVR_ETHERNET) || defined(ARDUINO_AVR_LEONARDO_ETH) + /* Boards such as arduino:avr:ethernet and arduino:avr:leonardoeth */ + #include <Ethernet.h> + EthernetClient client; + EthernetServer server(WOLFSSL_PORT); #elif defined(ARDUINO_SAMD_NANO_33_IOT) #define USING_WIFI #include <SPI.h> @@ -153,6 +174,36 @@ Tested with: #include <WiFiNINA.h> WiFiClient client; WiFiServer server(WOLFSSL_PORT); +#elif defined(ARDUINO_SAMD_TIAN) + #include <Bridge.h> + #include <HttpClient.h> + HttpClient client; + /* Arduino Tian does not support network shields like the standard Ethernet or Wi-Fi shields. */ + #error "HttpClient cannot be used for this example" +#elif defined(ARDUINO_PORTENTA_X8) + /* The Portenta is a Linux device. See wolfSSL examples: + * https://github.com/wolfSSL/wolfssl/tree/master/examples + * By default Serial is disabled and mapped to ErrorSerial */ + #include <SerialRPC.h> + + /* ----No - network placeholders(compile - only) ---- */ + #include <IPAddress.h> + struct X8NoNetClient { + int write(const uint8_t*, size_t) { return -1; } + int available() { return 0; } + int read() { return -1; } + void stop() {} + bool connected() { return false; } + IPAddress remoteIP() { return IPAddress(0, 0, 0, 0); } + }; + struct X8NoNetServer { + explicit X8NoNetServer(uint16_t) {} + void begin() {} + X8NoNetClient available() { return X8NoNetClient(); } + }; + + X8NoNetClient client; + X8NoNetServer server(WOLFSSL_PORT); #elif defined(USING_WIFI) #define USING_WIFI #include <WiFi.h> @@ -206,7 +257,10 @@ static char errBuf[80]; static int EthernetSend(WOLFSSL* ssl, char* msg, int sz, void* ctx); static int EthernetReceive(WOLFSSL* ssl, char* reply, int sz, void* ctx); static int reconnect = RECONNECT_ATTEMPTS; +#if 0 +/* optional showPeerEx, currently disabled */ static int lng_index PROGMEM = 0; /* 0 = English */ +#endif #if defined(__arm__) #include <malloc.h> @@ -463,7 +517,8 @@ int setup_network(void) { /*****************************************************************************/ /* Arduino setup_wolfssl() */ /*****************************************************************************/ -int setup_wolfssl(void) { +int setup_wolfssl(void) +{ int ret = 0; WOLFSSL_METHOD* method; @@ -483,8 +538,14 @@ int setup_wolfssl(void) { #endif #if defined(DEBUG_WOLFSSL) - wolfSSL_Debugging_ON(); - Serial.println(F("wolfSSL Debugging is On!")); + Serial.println(F("wolfSSL Debugging is available! (DEBUG_WOLFSSL)")); + #if defined(DEBUG_WOLFSSL_MESSAGES_ON) + Serial.println(F("Enabling verbose messages wolfSSL_Debugging_ON")); + wolfSSL_Debugging_ON(); + #else + Serial.println(F("Enable verbose messages with wolfSSL_Debugging_ON")); + Serial.println(F("or define DEBUG_WOLFSSL_MESSAGES_ON")); + #endif #else Serial.println(F("wolfSSL Debugging is Off! (enable with DEBUG_WOLFSSL)")); #endif @@ -510,6 +571,7 @@ int setup_wolfssl(void) { * It is best on embedded devices to choose a TLS session cache size. */ #endif + /* Initialize wolfSSL before assigning ctx */ ret = wolfSSL_Init(); if (ret == WOLFSSL_SUCCESS) { Serial.println("Successfully called wolfSSL_Init"); @@ -544,7 +606,8 @@ int setup_wolfssl(void) { /*****************************************************************************/ /* Arduino setup_certificates() */ /*****************************************************************************/ -int setup_certificates(void) { +int setup_certificates(void) +{ int ret = 0; Serial.println(F("Initializing certificates...")); @@ -594,7 +657,8 @@ int setup_certificates(void) { /* Arduino setup() */ /*****************************************************************************/ /*****************************************************************************/ -void setup(void) { +void setup(void) +{ int i = 0; Serial.begin(SERIAL_BAUD); while (!Serial && (i < 10)) { @@ -725,7 +789,7 @@ int error_check_ssl(WOLFSSL* ssl, int this_ret, bool halt_on_error, } return err; -} +} /* error_check_ssl */ /*****************************************************************************/ /*****************************************************************************/ diff --git a/Arduino/sketches/wolfssl_server_dtls/README.md b/Arduino/sketches/wolfssl_server_dtls/README.md new file mode 100644 index 00000000..43deb7ec --- /dev/null +++ b/Arduino/sketches/wolfssl_server_dtls/README.md @@ -0,0 +1,140 @@ +# Arduino Basic TLS Server + +Open the [wolfssl_server_dtls.ino](./wolfssl_server_dtls.ino) file in the Arduino IDE. + +If using WiFi, be sure to set `ssid` and `password` values. + +May need "Ethernet by Various" library to be installed. Tested with v2.0.2 and v2.8.1. + +See the `#define WOLFSSL_TLS_SERVER_HOST` to set your own server address. + +Other IDE products are also supported, such as: + +- [PlatformIO in VS Code](https://docs.platformio.org/en/latest/frameworks/arduino.html) +- [VisualGDB](https://visualgdb.com/tutorials/arduino/) +- [VisualMicro](https://www.visualmicro.com/) + +For examples on other platforms, see the [IDE directory](https://github.com/wolfssl/wolfssl/tree/master/IDE). +Additional examples can be found on [wolfSSL/wolfssl-examples](https://github.com/wolfSSL/wolfssl-examples/). + +## Connect with an Arduino Sketch + +See the companion [Arduino Sketch Client](../wolfssl_client/wolfssl_client_dtls.ino). + +## Connect with Linux Client + +See also the [wolfSSL Example TLS Client](https://github.com/wolfSSL/wolfssl/tree/master/examples/client) +and [wolfSSL Example TLS Server](https://github.com/wolfSSL/wolfssl/tree/master/examples/server). + +Assuming a listening [Arduino Sketch Server](./wolfssl_server.ino) at `192.168.1.38` on port `11111`, +connect with the `client` executable: + +``` +./examples/client/client -h 192.168.1.38 -p 11111 -v 3 +``` + +## wolfSSL Error -308 wolfSSL_connect error state on socket + +When using a wired Ethernet connection, and this error is encountered, simply +press the reset button or power cycle the Arduino before making a connection. + +Here's one possible script to test the server from a command-line client: + +```bash +#!/usr/bin/env bash +echo "client log " > client_log.txt +counter=1 +THIS_ERR=0 +while [ $THIS_ERR -eq 0 ]; do + ./examples/client/client -h 192.168.1.38 -p 11111 -v 3 >> client_log.txt + + THIS_ERR=$? + if [ $? -ne 0 ]; then + echo "Failed!" + exit 1 + fi + echo "Iteration $counter" + echo "Iteration $counter" >> client_log.txt + ((counter++)) +done +``` + +Output expected from the `client` command: + +``` +$ ./examples/client/client -h 192.168.1.38 -p 11111 -v 3 +Alternate cert chain used + issuer : /C=US/ST=Montana/L=Bozeman/O=Sawtooth/OU=Consulting/CN=www.wolfssl.com/emailAddress=info@wolfssl.com + subject: /C=US/ST=Montana/L=Bozeman/O=wolfSSL/OU=Support/CN=www.wolfssl.com/emailAddress=info@wolfssl.com + altname = example.com + altname = 127.0.0.1 + serial number:01 +SSL version is TLSv1.2 +SSL cipher suite is ECDHE-RSA-AES128-GCM-SHA256 +SSL curve name is SECP256R1 +--- +Server certificate +-----BEGIN CERTIFICATE----- +MIIE6DCCA9CgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBlDELMAkGA1UEBhMCVVMx +EDAOBgNVBAgMB01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoMCFNh +d3Rvb3RoMRMwEQYDVQQLDApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29sZnNz +bC5jb20xHzAdBgkqhkiG9w0BCQEWEGluZm9Ad29sZnNzbC5jb20wHhcNMjMxMjEz +MjIxOTI4WhcNMjYwOTA4MjIxOTI4WjCBkDELMAkGA1UEBhMCVVMxEDAOBgNVBAgM +B01vbnRhbmExEDAOBgNVBAcMB0JvemVtYW4xEDAOBgNVBAoMB3dvbGZTU0wxEDAO +BgNVBAsMB1N1cHBvcnQxGDAWBgNVBAMMD3d3dy53b2xmc3NsLmNvbTEfMB0GCSqG +SIb3DQEJARYQaW5mb0B3b2xmc3NsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAMCVCOFXQfJxbbfSRUEnAWXGRa7yvCQwuJXOL07W9hyIvHyf+6hn +f/5cnFF194rKB+c1L4/hvXvAL3yrZKgX/Mpde7rgIeVyLm8uhtiVc9qsG1O5Xz/X +GQ0lT+FjY1GLC2Q/rUO4pRxcNLOuAKBjxfZ/C1loeHOmjBipAm2vwxkBLrgQ48bM +QLRpo0YzaYduxLsXpvPo3a1zvHsvIbX9ZlEMvVSz4W1fHLwjc9EJA4kU0hC5ZMMq +0KGWSrzh1Bpbx6DAwWN4D0Q3MDKWgDIjlaF3uhPSl3PiXSXJag3DOWCktLBpQkIJ +6dgIvDMgs1gip6rrxOHmYYPF0pbf2dBPrdcCAwEAAaOCAUUwggFBMB0GA1UdDgQW +BBSzETLJkpiE4sn40DtuA0LKHw6OPDCB1AYDVR0jBIHMMIHJgBQnjmcRdMMmHT/t +M2OzpNgdMOXo1aGBmqSBlzCBlDELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB01vbnRh +bmExEDAOBgNVBAcMB0JvemVtYW4xETAPBgNVBAoMCFNhd3Rvb3RoMRMwEQYDVQQL +DApDb25zdWx0aW5nMRgwFgYDVQQDDA93d3cud29sZnNzbC5jb20xHzAdBgkqhkiG +9w0BCQEWEGluZm9Ad29sZnNzbC5jb22CFDNEGqhsAez2YPJwUQpM0RT6vOlEMAwG +A1UdEwQFMAMBAf8wHAYDVR0RBBUwE4ILZXhhbXBsZS5jb22HBH8AAAEwHQYDVR0l +BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBK/7nl +hZvaU2Z/ByK/thnqQuukEQdi/zlfMzc6hyZxPROyyrhkOHuKmUgOpaRrsZlu4EZR +vRlSrbymfip6fCOnzNteQ31rBMi33ZWt8JGAWcUZkSYnkbhIHOtVtqp9pDjxA7xs +i6qU1jwFepbFBvEmFC51+93lNbMBLLOtYlohmgi+Vvz5okKHhuWpxZnPrhS+4LkI +JA0dXNYU4UyfQLOp6S1Si0y/rEQxZ8GNBoXsD+SZ10t7IQZm1OT1nf+O8IY5WB2k +W+Jj73zJGIeoAiUQPoco+fXvR56lgAgRkGj+0aOoUbk3/9XKfId/a7wsEsjFhYv8 +DMa5hrjJBMNRN9JP +-----END CERTIFICATE----- +Session timeout set to 500 seconds +Client Random : 56A0BB9647B064D3F20947032B74B31FDB4C93DBAC9460BA8AEA213A2B2DD4A8 +SSL-Session: + Protocol : TLSv1.2 + Cipher : TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + Session-ID: 3255404E997FA9C27ECB4F1A20A70E722E4AA504B63A945FC175434D1907EC31 + Session-ID-ctx: + Master-Key: 67F22168BBADD678643BBA76B398277270C29788AC18FD05B57F6B715F49A7BCEEF75BEAF7FE266B0CC058534AF76C1F + TLS session ticket: NONE + Start Time: 1705533296 + Timeout : 500 (sec) + Extended master secret: no +I hear you fa shizzle! +``` + +### Troubleshooting + +When encountering odd errors such as `undefined reference to ``_impure_ptr'`, such as this: + +```text +c:/users/gojimmypi/appdata/local/arduino15/packages/esp32/tools/xtensa-esp32-elf-gcc/esp-2021r2-patch5-8.4.0/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: C:\Users\gojimmypi\AppData\Local\Temp\arduino\sketches\EAB8D79A02D1ECF107884802D893914E\libraries\wolfSSL\wolfcrypt\src\logging.c.o:(.literal.wolfssl_log+0x8): undefined reference to `_impure_ptr' +collect2.exe: error: ld returned 1 exit status + +exit status 1 + +Compilation error: exit status 1 +``` + +Try cleaning the Arduino cache directories. For Windows, that's typically in: + +```text +C:\Users\%USERNAME%\AppData\Local\Temp\arduino\sketches +``` + +Remove all other boards from other serial ports, leaving one the one being programmed. diff --git a/Arduino/sketches/wolfssl_server_dtls/wolfssl_server_dtls.ino b/Arduino/sketches/wolfssl_server_dtls/wolfssl_server_dtls.ino new file mode 100644 index 00000000..38e9148f --- /dev/null +++ b/Arduino/sketches/wolfssl_server_dtls/wolfssl_server_dtls.ino @@ -0,0 +1,984 @@ +/* server-dtls13.c + * + * Copyright (C) 2006-2025 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 3 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 + * + *============================================================================= + * + * Bare-bones example of a DTLS 1.3 server for instructional/learning purposes. + * This example can only accept one connection at a time. + * + * Define USE_DTLS12 to use DTLS 1.2 instead of DTLS 1.3 +/* +Tested with: + +1) Intel Galileo acting as the Client, with a laptop acting as a server using + the server example provided in examples/server. + Legacy Arduino v1.86 was used to compile and program the Galileo + +2) Espressif ESP32 WiFi + +3) Arduino Due, Nano33 IoT, Nano RP-2040 +*/ + +/* + * Note to code editors: the Arduino client and server examples are edited in + * parallel for side-by-side comparison between examples. + */ + +/* If you have a private include, define it here, otherwise edit WiFi params */ +/* #define MY_PRIVATE_CONFIG "/workspace/my_private_config.h" */ + +#if defined(ARDUINO) && defined(ESP8266) + #warning "This example is not yet supported on Arduino ESP8266" +#endif + +#if defined(DEBUG_WOLFSSL) + /* Optionally enabled verbose wolfSSL debugging */ + #define DEBUG_WOLFSSL_MESSAGES_ON +#else + /* DEBUG_WOLFSSL needs to be enabled */ + #undef DEBUG_WOLFSSL_MESSAGES_ON +#endif + +/* set REPEAT_CONNECTION to a non-zero value to continually run the example. */ +#define REPEAT_CONNECTION 0 + +/* Edit this with your other TLS host server address to connect to: */ +/* #define WOLFSSL_TLS_SERVER_HOST "192.168.1.39" */ + +/* wolfssl TLS examples communicate on port 11111 */ +#define WOLFSSL_PORT 11111 + +/* Choose a monitor serial baud rate: 9600, 14400, 19200, 57600, 74880, etc. */ +#define SERIAL_BAUD 115200 + +/* We'll wait up to 2000 milliseconds to properly shut down connection */ +#define SHUTDOWN_DELAY_MS 2000 + +/* Number of times to retry connection. */ +#define RECONNECT_ATTEMPTS 20 + +/* Assume bad socket until proven otherwise */ +#define INVALID_SOCKET -1 + +/* Maximum size in bytes of buffer to send and receive */ +#define MAXLINE 128 + +/* Optional stress test. Define to consume memory until exhausted: */ +/* #define MEMORY_STRESS_TEST */ + +/* Choose client or server example, not both. */ +/* #define WOLFSSL_CLIENT_EXAMPLE */ +#define WOLFSSL_SERVER_EXAMPLE + +#if defined(MY_PRIVATE_CONFIG) + /* the /workspace directory may contain a private config + * excluded from GitHub with items such as WiFi passwords */ + #include MY_PRIVATE_CONFIG + static const char ssid[] PROGMEM = MY_ARDUINO_WIFI_SSID; + static const char password[] PROGMEM = MY_ARDUINO_WIFI_PASSWORD; +#else + /* when using WiFi capable boards: */ + static const char ssid[] PROGMEM = "your_SSID"; + static const char password[] PROGMEM = "your_PASSWORD"; +#endif + +#define BROADCAST_ADDRESS "255.255.255.255" + +/* There's an optional 3rd party NTPClient library by Fabrice Weinberg. + * If it is installed, uncomment define USE_NTP_LIB here: */ +/* #define USE_NTP_LIB */ +#ifdef USE_NTP_LIB + #include <NTPClient.h> +#endif + +/* wolfSSL user_settings.h must be included from settings.h + * Make all configurations changes in user_settings.h + * Do not edit wolfSSL `settings.h` or `config.h` files. + * Do not explicitly include user_settings.h in any source code. + * Each Arduino sketch that uses wolfSSL must have: #include "wolfssl.h" + * C/C++ source files can use: #include <wolfssl/wolfcrypt/settings.h> + * The wolfSSL "settings.h" must be included in each source file using wolfSSL. + * The wolfSSL "settings.h" must appear before any other wolfSSL include. + */ +#include <wolfssl.h> +/* Important: make sure settings.h appears before any other wolfSSL headers */ +#include <wolfssl/wolfcrypt/settings.h> +/* Reminder: settings.h includes user_settings.h + * For ALL project wolfSSL settings, see: + * [your path]/Arduino\libraries\wolfSSL\src\user_settings.h */ +#include <wolfssl/ssl.h> +#include <wolfssl/certs_test.h> +#include <wolfssl/wolfcrypt/error-crypt.h> + +#ifndef WOLFSSL_DTLS + /* Support for DTLS by default was added after wolfSSL v5.8.2 release */ + #error "This example requires WOLFSSL_DTLS. See user_settings.h in the Arduino wolfssl library" +#endif + +/* Define DEBUG_WOLFSSL in user_settings.h for more verbose logging. */ +#if defined(DEBUG_WOLFSSL) + #define PROGRESS_DOT F("") +#else + #define PROGRESS_DOT F(".") +#endif + +/* Convert a macro to a string */ +#define xstr(x) str(x) +#define str(x) #x + +/* optional board-specific networking includes */ +#if defined(ESP32) + #define USING_WIFI + #include <WiFi.h> + #include <WiFiUdp.h> + #ifdef USE_NTP_LIB + WiFiUDP ntpUDP; + #endif + /* Ensure the F() flash macro is defined */ + #ifndef F + #define F + #endif + WiFiClient client; + WiFiServer server(WOLFSSL_PORT); +#elif defined(ESP8266) + #define USING_WIFI + #include <ESP8266WiFi.h> + /* Ensure the F() flash macro is defined */ + #ifndef F + #define F + #endif + WiFiClient client; + WiFiServer server(WOLFSSL_PORT); +#elif defined(ARDUINO_SAM_DUE) + #include <SPI.h> + /* There's no WiFi/Ethernet on the Due. Requires Ethernet Shield. + /* Needs "Ethernet by Various" library to be installed. Tested with V2.0.2 */ + #include <Ethernet.h> + EthernetClient client; + EthernetClient server(WOLFSSL_PORT); +#elif defined(ARDUINO_AVR_ETHERNET) || defined(ARDUINO_AVR_LEONARDO_ETH) + /* Boards such as arduino:avr:ethernet and arduino:avr:leonardoeth */ + #include <Ethernet.h> + EthernetClient client; + + EthernetClient server(WOLFSSL_PORT); +#elif defined(ARDUINO_SAMD_NANO_33_IOT) + #define USING_WIFI + #include <SPI.h> + #include <WiFiNINA.h> /* Needs Arduino WiFiNINA library installed manually */ + WiFiClient client; + WiFiServer server(WOLFSSL_PORT); +#elif defined(ARDUINO_ARCH_RP2040) + #define USING_WIFI + #include <SPI.h> + #include <WiFiNINA.h> + WiFiClient client; + WiFiServer server(WOLFSSL_PORT); +#elif defined(ARDUINO_SAMD_TIAN) + #include <Bridge.h> + #include <HttpClient.h> + HttpClient client; + /* Arduino Tian does not support network shields like the standard Ethernet or Wi-Fi shields. */ + #error "HttpClient cannot be used for this example" +#elif defined(ARDUINO_PORTENTA_X8) + /* The Portenta is a Linux device. See wolfSSL examples: + * https://github.com/wolfSSL/wolfssl/tree/master/examples + * By default Serial is disabled and mapped to ErrorSerial */ + #include <SerialRPC.h> + + /* ----No - network placeholders(compile - only) ---- */ + #include <IPAddress.h> + struct X8NoNetClient { + int write(const uint8_t*, size_t) { return -1; } + int available() { return 0; } + int read() { return -1; } + void stop() {} + bool connected() { return false; } + IPAddress remoteIP() { return IPAddress(0, 0, 0, 0); } + }; + struct X8NoNetServer { + explicit X8NoNetServer(uint16_t) {} + void begin() {} + X8NoNetClient available() { return X8NoNetClient(); } + }; + + X8NoNetClient client; + X8NoNetServer server(WOLFSSL_PORT); +#elif defined(USING_WIFI) + #define USING_WIFI + #include <WiFi.h> + #include <WiFiUdp.h> + #ifdef USE_NTP_LIB + WiFiUDP ntpUDP; + #endif + WiFiClient client; + WiFiServer server(WOLFSSL_PORT); +/* TODO +#elif defined(OTHER_BOARD) +*/ +#else + /* assume all other boards using WiFi library. Edit as needed: */ + #include <WiFi.h> + #define USING_WIFI + WiFiClient client; + WiFiServer server(WOLFSSL_PORT); +#endif + +/* Only for syntax highlighters to show interesting options enabled: */ +#if defined(HAVE_SNI) \ + || defined(HAVE_MAX_FRAGMENT) \ + || defined(HAVE_TRUSTED_CA) \ + || defined(HAVE_TRUNCATED_HMAC) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST) \ + || defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) \ + || defined(HAVE_SUPPORTED_CURVES) \ + || defined(HAVE_ALPN) \ + || defined(HAVE_SESSION_TICKET) \ + || defined(HAVE_SECURE_RENEGOTIATION) \ + || defined(HAVE_SERVER_RENEGOTIATION_INFO) +#endif + +static const int port PROGMEM = WOLFSSL_PORT; /* port on server to connect to */ + +static WOLFSSL_CTX* ctx = NULL; +static WOLFSSL* ssl = NULL; +static char* wc_error_message = (char*)malloc(80 + 1); +static char errBuf[80]; + +#if defined(MEMORY_STRESS_TEST) + #define MEMORY_STRESS_ITERATIONS 100 + #define MEMORY_STRESS_BLOCK_SIZE 1024 + #define MEMORY_STRESS_INITIAL (4*1024) + static char* memory_stress[MEMORY_STRESS_ITERATIONS]; /* typically 1K per item */ + static int mem_ctr = 0; +#endif + +static int EthernetSend(WOLFSSL* ssl, char* msg, int sz, void* ctx); +static int EthernetReceive(WOLFSSL* ssl, char* reply, int sz, void* ctx); +static int reconnect = RECONNECT_ATTEMPTS; +#if 0 +/* optional showPeerEx, currently disabled */ +static int lng_index PROGMEM = 0; /* 0 = English */ +#endif +static int listenfd = INVALID_SOCKET; /* Initialize our socket */ + +#if defined(__arm__) + #include <malloc.h> + extern char _end; + extern "C" char *sbrk(int i); + static char *ramstart=(char *)0x20070000; + static char *ramend=(char *)0x20088000; +#endif + +/*****************************************************************************/ +/* fail_wait - in case of unrecoverable error */ +/*****************************************************************************/ +int fail_wait(void) { + show_memory(); + + Serial.println(F("Failed. Halt.")); + while (1) { + delay(1000); + } + return 0; +} + +/*****************************************************************************/ +/* show_memory() to optionally view during debugging. */ +/*****************************************************************************/ +int show_memory(void) +{ +#if defined(__arm__) + struct mallinfo mi = mallinfo(); + + char *heapend=sbrk(0); + register char * stack_ptr asm("sp"); + #if defined(DEBUG_WOLFSSL_VERBOSE) + Serial.print(" arena="); + Serial.println(mi.arena); + Serial.print(" ordblks="); + Serial.println(mi.ordblks); + Serial.print(" uordblks="); + Serial.println(mi.uordblks); + Serial.print(" fordblks="); + Serial.println(mi.fordblks); + Serial.print(" keepcost="); + Serial.println(mi.keepcost); + #endif + + #if defined(DEBUG_WOLFSSL) || defined(MEMORY_STRESS_TEST) + Serial.print("Estimated free memory: "); + Serial.print(stack_ptr - heapend + mi.fordblks); + Serial.println(F(" bytes")); + #endif + + #if (0) + /* Experimental: not supported on all devices: */ + Serial.print("RAM Start %lx\n", (unsigned long)ramstart); + Serial.print("Data/Bss end %lx\n", (unsigned long)&_end); + Serial.print("Heap End %lx\n", (unsigned long)heapend); + Serial.print("Stack Ptr %lx\n",(unsigned long)stack_ptr); + Serial.print("RAM End %lx\n", (unsigned long)ramend); + + Serial.print("Heap RAM Used: ",mi.uordblks); + Serial.print("Program RAM Used ",&_end - ramstart); + Serial.print("Stack RAM Used ",ramend - stack_ptr); + + Serial.print("Estimated Free RAM: %d\n\n",stack_ptr - heapend + mi.fordblks); + #endif +#else + Serial.println(F("show_memory() not implemented for this platform")); +#endif + return 0; +} + +/*****************************************************************************/ +/* Arduino setup_hardware() */ +/*****************************************************************************/ +int setup_hardware(void) { + int ret = 0; + +#if defined(ARDUINO_SAMD_NANO_33_IOT) + Serial.println(F("Detected known tested and working Arduino Nano 33 IoT")); +#elif defined(ARDUINO_ARCH_RP2040) + Serial.println(F("Detected known tested and working Arduino RP-2040")); +#elif defined(__arm__) && defined(ID_TRNG) && defined(TRNG) + /* need to manually turn on random number generator on Arduino Due, etc. */ + pmc_enable_periph_clk(ID_TRNG); + trng_enable(TRNG); + Serial.println(F("Enabled ARM TRNG")); +#endif + + show_memory(); + randomSeed(analogRead(0)); + return ret; +} + +/*****************************************************************************/ +/* Arduino setup_datetime() */ +/* The device needs to have a valid date within the valid range of certs. */ +/*****************************************************************************/ +int setup_datetime(void) { + int ret = 0; + int ntp_tries = 20; + + /* we need a date in the range of cert expiration */ +#ifdef USE_NTP_LIB + #if defined(ESP32) + NTPClient timeClient(ntpUDP, "pool.ntp.org"); + + timeClient.begin(); + timeClient.update(); + delay(1000); + while (!timeClient.isTimeSet() && (ntp_tries > 0)) { + timeClient.forceUpdate(); + Serial.println(F("Waiting for NTP update")); + delay(2000); + ntp_tries--; + } + if (ntp_tries <= 0) { + Serial.println(F("Warning: gave up waiting on NTP")); + } + Serial.println(timeClient.getFormattedTime()); + Serial.println(timeClient.getEpochTime()); + #endif +#endif + +#if defined(ESP32) + /* see esp32-hal-time.c */ + ntp_tries = 5; + /* Replace "pool.ntp.org" with your preferred NTP server */ + configTime(0, 0, "pool.ntp.org"); + + /* Wait for time to be set */ + while ((time(nullptr) <= 100000) && ntp_tries > 0) { + Serial.println(F("Waiting for time to be set...")); + delay(2000); + ntp_tries--; + } +#endif + + return ret; +} /* setup_datetime */ + +/*****************************************************************************/ +/* Arduino setup_network() */ +/*****************************************************************************/ +int setup_network(void) { + int ret = 0; + +#if defined(USING_WIFI) + int status = WL_IDLE_STATUS; + + /* The ESP8266 & ESP32 support both AP and STA. We'll use STA: */ + #if defined(ESP8266) || defined(ESP32) + WiFi.mode(WIFI_STA); + #else + String fv; + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + /* don't continue if no network */ + while (true) ; + } + + fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + #endif + + Serial.print(F("Connecting to WiFi ")); + Serial.print(ssid); + status = WiFi.begin(ssid, password); + while (status != WL_CONNECTED) { + delay(1000); + Serial.print(F(".")); + Serial.print(status); + status = WiFi.status(); + } + + Serial.println(F(" Connected!")); +#else + /* Newer Ethernet shields have a + * MAC address printed on a sticker on the shield */ + byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; + IPAddress ip(192, 168, 1, 42); + IPAddress myDns(192, 168, 1, 1); + Ethernet.init(10); /* Most Arduino shields */ + /* Ethernet.init(5); * MKR ETH Shield */ + /* Ethernet.init(0); * Teensy 2.0 */ + /* Ethernet.init(20); * Teensy++ 2.0 */ + /* Ethernet.init(15); * ESP8266 with Adafruit FeatherWing Ethernet */ + /* Ethernet.init(33); * ESP32 with Adafruit FeatherWing Ethernet */ + Serial.println(F("Initialize Ethernet with DHCP:")); + if (Ethernet.begin(mac) == 0) { + Serial.println(F("Failed to configure Ethernet using DHCP")); + /* Check for Ethernet hardware present */ + if (Ethernet.hardwareStatus() == EthernetNoHardware) { + Serial.println(F("Ethernet shield was not found.")); + while (true) { + delay(1); /* do nothing */ + } + } + if (Ethernet.linkStatus() == LinkOFF) { + Serial.println(F("Ethernet cable is not connected.")); + } + /* try to configure using IP address instead of DHCP : */ + Ethernet.begin(mac, ip, myDns); + } + else { + Serial.print(F(" DHCP assigned IP ")); + Serial.println(Ethernet.localIP()); + } + /* We'll assume the Ethernet connection is ready to go. */ +#endif + + Serial.println(F("********************************************************")); + Serial.print(F(" wolfSSL Example Server IP = ")); +#if defined(USING_WIFI) + Serial.println(WiFi.localIP()); +#else + Serial.println(Ethernet.localIP()); +#endif + /* In server mode, there's no host definition. */ + /* See companion example: wolfssl_client.ino */ + Serial.println(F("********************************************************")); + Serial.println(F("Setup network complete.")); + + return ret; +} + +/*****************************************************************************/ +/* Arduino setup_wolfssl() */ +/*****************************************************************************/ +int setup_wolfssl(void) +{ + int ret = 0; + WOLFSSL_METHOD* method; + + /* Show a revision of wolfssl user_settings.h file in use when available: */ +#if defined(WOLFSSL_USER_SETTINGS_ID) + Serial.print(F("WOLFSSL_USER_SETTINGS_ID: ")); + Serial.println(F(WOLFSSL_USER_SETTINGS_ID)); +#else + Serial.println(F("No WOLFSSL_USER_SETTINGS_ID found.")); +#endif + +#if defined(NO_WOLFSSL_SERVER) + Serial.println(F("wolfSSL server code disabled to save space.")); +#endif +#if defined(NO_WOLFSSL_CLIENT) + Serial.println(F("wolfSSL client code disabled to save space.")); +#endif + +#if defined(DEBUG_WOLFSSL) + Serial.println(F("wolfSSL Debugging is available! (DEBUG_WOLFSSL)")); + #if defined(DEBUG_WOLFSSL_MESSAGES_ON) + Serial.println(F("Enabling verbose messages wolfSSL_Debugging_ON")); + wolfSSL_Debugging_ON(); + #else + Serial.println(F("Enable verbose messages with wolfSSL_Debugging_ON")); + Serial.println(F("or define DEBUG_WOLFSSL_MESSAGES_ON")); + #endif +#else + Serial.println(F("wolfSSL Debugging is Off! (enable with DEBUG_WOLFSSL)")); +#endif + + /* See ssl.c for TLS cache settings. Larger cache = use more RAM. */ +#if defined(NO_SESSION_CACHE) + Serial.println(F("wolfSSL TLS NO_SESSION_CACHE")); +#elif defined(MICRO_SESSION_CACHEx) + Serial.println(F("wolfSSL TLS MICRO_SESSION_CACHE")); +#elif defined(SMALL_SESSION_CACHE) + Serial.println(F("wolfSSL TLS SMALL_SESSION_CACHE")); +#elif defined(MEDIUM_SESSION_CACHE) + Serial.println(F("wolfSSL TLS MEDIUM_SESSION_CACHE")); +#elif defined(BIG_SESSION_CACHE) + Serial.println(F("wolfSSL TLS BIG_SESSION_CACHE")); +#elif defined(HUGE_SESSION_CACHE) + Serial.println(F("wolfSSL TLS HUGE_SESSION_CACHE")); +#elif defined(HUGE_SESSION_CACHE) + Serial.println(F("wolfSSL TLS HUGE_SESSION_CACHE")); +#else + Serial.println(F("WARNING: Unknown or no TLS session cache setting.")); + /* See wolfssl/src/ssl.c for amount of memory used. + * It is best on embedded devices to choose a TLS session cache size. */ +#endif + + /* Initialize wolfSSL before assigning ctx */ + ret = wolfSSL_Init(); + if (ret == WOLFSSL_SUCCESS) { + Serial.println("Successfully called wolfSSL_Init"); + } + else { + Serial.println("ERROR: wolfSSL_Init failed"); + } + + /* See companion server example with wolfSSLv23_server_method here. + * method = wolfSSLv23_client_method()); SSL 3.0 - TLS 1.3. + * method = wolfTLSv1_2_client_method(); only TLS 1.2 + * method = wolfTLSv1_3_client_method(); only TLS 1.3 + * + * see Arduino\libraries\wolfssl\src\user_settings.h */ + + Serial.println("Here we go!"); + +#ifdef WOLFSSL_DTLS13 + Serial.println(F("Setting wolfDTLSv1_3_client_method")); + method = wolfDTLSv1_3_server_method(); +#else + Serial.println(F("Setting wolfDTLSv1_2_client_method")); + method = wolfDTLSv1_2_servert_method(); +#endif + ctx = wolfSSL_CTX_new(method); + if (ctx == NULL) { + fail_wait(); + } + + if (method == NULL) { + Serial.println(F("Unable to get wolfssl client method")); + fail_wait(); + } + + ctx = wolfSSL_CTX_new(method); + if (ctx == NULL) { + Serial.println(F("unable to get ctx")); + fail_wait(); + } + + return ret; +} + +/*****************************************************************************/ +/* Arduino setup_certificates() */ +/*****************************************************************************/ +int setup_certificates(void) +{ + int ret = 0; + +/* See user_settings.h that should have included wolfssl/certs_test.h */ + +Serial.println(F("Initializing certificates...")); +show_memory(); + + /* Load CA certificates */ + if (ret == WOLFSSL_SUCCESS) { + /* caCertLoc[] = "../certs/ca-cert.pem"; */ + ret = wolfSSL_CTX_load_verify_buffer(ctx, + CTX_CA_CERT, + CTX_CA_CERT_SIZE, + CTX_SERVER_CERT_TYPE); + } + + /* If successful, Load server certificates */ + Serial.println("Initializing certificates..."); + ret = wolfSSL_CTX_use_certificate_buffer(ctx, + CTX_SERVER_CERT, + CTX_SERVER_CERT_SIZE, + CTX_CA_CERT_TYPE); + + if (ret == WOLFSSL_SUCCESS) { + Serial.print("Success: use certificate: "); + Serial.println(xstr(CTX_SERVER_CERT)); + } + else { + Serial.print("Error: wolfSSL_CTX_use_certificate_buffer failed: "); + wc_ErrorString(ret, wc_error_message); + Serial.println(wc_error_message); + fail_wait(); + } + + /* Setup private server key */ + ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, + CTX_SERVER_KEY, + CTX_SERVER_KEY_SIZE, + CTX_SERVER_KEY_TYPE); + if (ret == WOLFSSL_SUCCESS) { + Serial.print("Success: use private key buffer: "); + Serial.println(xstr(CTX_SERVER_KEY)); + } + else { + Serial.print("Error: wolfSSL_CTX_use_PrivateKey_buffer failed: "); + wc_ErrorString(ret, wc_error_message); + Serial.println(wc_error_message); + fail_wait(); + } + + /* Setup private server key */ + ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, + CTX_SERVER_KEY, + CTX_SERVER_KEY_SIZE, + CTX_SERVER_KEY_TYPE); + + if (ret == WOLFSSL_SUCCESS) { + Serial.print("Success: use private key buffer: "); + Serial.println(xstr(CTX_SERVER_KEY)); + } + else { + Serial.print("Error: wolfSSL_CTX_use_PrivateKey_buffer failed: "); + wc_ErrorString(ret, wc_error_message); + Serial.println(wc_error_message); + fail_wait(); + } + + return ret; +} /* Arduino setup */ + +/*****************************************************************************/ +/*****************************************************************************/ +/* Arduino setup() */ +/*****************************************************************************/ +/*****************************************************************************/ +void setup(void) +{ + int i = 0; + Serial.begin(SERIAL_BAUD); + while (!Serial && (i < 10)) { + /* wait for serial port to connect. Needed for native USB port only */ + delay(1000); + i++; + } + + Serial.println(F("")); + Serial.println(F("")); + Serial.println(F("wolfSSL DTLS Server Example Startup.")); + + /* Optionally pre-allocate a large block of memory for testing */ +#if defined(MEMORY_STRESS_TEST) + Serial.println(F("WARNING: Memory Stress Test Active!")); + Serial.print(F("Allocating extra memory: ")); + Serial.print(MEMORY_STRESS_INITIAL); + Serial.println(F(" bytes...")); + memory_stress[mem_ctr] = (char*)malloc(MEMORY_STRESS_INITIAL); + show_memory(); +#endif + + setup_hardware(); + + setup_network(); + + setup_datetime(); + + setup_wolfssl(); + + setup_certificates(); + +#if defined THIS_USER_SETTINGS_VERSION + Serial.print(F("This user_settings.h version:")) + Serial.println(THIS_USER_SETTINGS_VERSION) +#endif + + /* Start the server + * See https://www.arduino.cc/reference/en/libraries/ethernet/server.begin/ + */ + + Serial.println(F("Completed Arduino setup()")); + + server.begin(); + Serial.println("Begin Server... (waiting for remote client to connect)"); + + /* See companion wolfssl_client.ino code */ + return; +} /* Arduino setup */ + +/*****************************************************************************/ +/* wolfSSL error_check() */ +/*****************************************************************************/ +int error_check(int this_ret, bool halt_on_error, + const __FlashStringHelper* message) { + int ret = 0; + if (this_ret == WOLFSSL_SUCCESS) { + Serial.print(F("Success: ")); + Serial.println(message); + } + else { + Serial.print(F("ERROR: return = ")); + Serial.print(this_ret); + Serial.print(F(": ")); + Serial.println(message); + Serial.println(wc_GetErrorString(this_ret)); + if (halt_on_error) { + fail_wait(); + } + } + show_memory(); + + return ret; +} /* error_check */ + +/*****************************************************************************/ +/* wolfSSL error_check_ssl */ +/* Parameters: */ +/* ssl is the current WOLFSSL object pointer */ +/* halt_on_error set to true to suspend operations for critical error */ +/* message is expected to be a memory-efficient F("") macro string */ +/*****************************************************************************/ +int error_check_ssl(WOLFSSL* ssl, int this_ret, bool halt_on_error, + const __FlashStringHelper* message) { + int err = 0; + + if (ssl == NULL) { + Serial.println(F("ssl is Null; Unable to allocate SSL object?")); +#ifndef DEBUG_WOLFSSL + Serial.println(F("Define DEBUG_WOLFSSL in user_settings.h for more.")); +#else + Serial.println(F("See wolfssl/wolfcrypt/error-crypt.h for codes.")); +#endif + Serial.print(F("ERROR: ")); + Serial.println(message); + show_memory(); + if (halt_on_error) { + fail_wait(); + } + } + else { + err = wolfSSL_get_error(ssl, this_ret); + if (err == WOLFSSL_SUCCESS) { + Serial.print(F("Success m: ")); + Serial.println(message); + } + else { + if (err < 0) { + wolfSSL_ERR_error_string(err, errBuf); + Serial.print(F("WOLFSSL Error: ")); + Serial.print(err); + Serial.print(F("; ")); + Serial.println(errBuf); + } + else { + Serial.println(F("Success: ssl object.")); + } + } + } + + return err; +} /* error_check_ssl */ + +static void sig_handler(const int sig); +static void free_resources(void); + +/*****************************************************************************/ +/*****************************************************************************/ +/* Arduino loop() */ +/*****************************************************************************/ +/*****************************************************************************/ +void loop() +{ + int exitVal = 1; + struct sockaddr_in servAddr; /* our server's address */ + struct sockaddr_in cliaddr; /* the client's address */ + int ret; + int err; + int recvLen = 0; /* length of message */ + socklen_t cliLen; + char buff[MAXLINE]; /* the incoming message */ + char ack[] = "I hear you fashizzle!\n"; + + /* Initialize wolfSSL before assigning ctx */ + if (wolfSSL_Init() != WOLFSSL_SUCCESS) { + fprintf(stderr, "wolfSSL_Init error.\n"); + fail_wait(); + } + + /* No-op when debugging is not compiled in */ + wolfSSL_Debugging_ON(); + + + /* Create a UDP/IP socket */ + if ((listenfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ) { + perror("socket()"); + goto cleanup; + } + printf("Socket allocated\n"); + memset((char *)&servAddr, 0, sizeof(servAddr)); + /* host-to-network-long conversion (htonl) */ + /* host-to-network-short conversion (htons) */ + servAddr.sin_family = AF_INET; + servAddr.sin_addr.s_addr = htonl(INADDR_ANY); + servAddr.sin_port = htons(WOLFSSL_PORT); + + /* Bind Socket */ + if (bind(listenfd, (struct sockaddr*)&servAddr, sizeof(servAddr)) < 0) { + perror("bind()"); + goto cleanup; + } + + // signal(SIGINT, sig_handler); + + while (1) { + printf("Awaiting client connection on port %d\n", WOLFSSL_PORT); + + cliLen = sizeof(cliaddr); + ret = (int)recvfrom(listenfd, (char *)&buff, sizeof(buff), MSG_PEEK, + (struct sockaddr*)&cliaddr, &cliLen); + + if (ret < 0) { + perror("recvfrom()"); + goto cleanup; + } + else if (ret == 0) { + fprintf(stderr, "recvfrom zero return\n"); + goto cleanup; + } + + /* Create the WOLFSSL Object */ + if ((ssl = wolfSSL_new(ctx)) == NULL) { + fprintf(stderr, "wolfSSL_new error.\n"); + goto cleanup; + } + + if (wolfSSL_dtls_set_peer(ssl, &cliaddr, cliLen) != WOLFSSL_SUCCESS) { + fprintf(stderr, "wolfSSL_dtls_set_peer error.\n"); + goto cleanup; + } + + if (wolfSSL_set_fd(ssl, listenfd) != WOLFSSL_SUCCESS) { + fprintf(stderr, "wolfSSL_set_fd error.\n"); + break; + } + + if (wolfSSL_accept(ssl) != WOLFSSL_SUCCESS) { + err = wolfSSL_get_error(ssl, 0); + fprintf(stderr, "error = %d, %s\n", err, + wolfSSL_ERR_reason_error_string(err)); + fprintf(stderr, "SSL_accept failed.\n"); + goto cleanup; + } + + while (1) { + if ((recvLen = wolfSSL_read(ssl, buff, sizeof(buff)-1)) > 0) { + printf("heard %d bytes\n", recvLen); + + buff[recvLen] = '\0'; + printf("I heard this: \"%s\"\n", buff); + } + else if (recvLen <= 0) { + err = wolfSSL_get_error(ssl, 0); + if (err == WOLFSSL_ERROR_ZERO_RETURN) /* Received shutdown */ + break; + fprintf(stderr, "error = %d, %s\n", err, + wolfSSL_ERR_reason_error_string(err)); + fprintf(stderr, "SSL_read failed.\n"); + goto cleanup; + } + printf("Sending reply.\n"); + if (wolfSSL_write(ssl, ack, sizeof(ack)) < 0) { + err = wolfSSL_get_error(ssl, 0); + fprintf(stderr, "error = %d, %s\n", err, + wolfSSL_ERR_reason_error_string(err)); + fprintf(stderr, "wolfSSL_write failed.\n"); + goto cleanup; + } + } + + printf("reply sent \"%s\"\n", ack); + + /* Attempt a full shutdown */ + ret = wolfSSL_shutdown(ssl); + if (ret == WOLFSSL_SHUTDOWN_NOT_DONE) + ret = wolfSSL_shutdown(ssl); + if (ret != WOLFSSL_SUCCESS) { + err = wolfSSL_get_error(ssl, 0); + fprintf(stderr, "err = %d, %s\n", err, + wolfSSL_ERR_reason_error_string(err)); + fprintf(stderr, "wolfSSL_shutdown failed\n"); + } + wolfSSL_free(ssl); + ssl = NULL; + + printf("Awaiting new connection\n"); + } + + exitVal = 0; +cleanup: + free_resources(); + wolfSSL_Cleanup(); + + Serial.println(F("Done!")); + while (1) { + delay(1000); + } +} + + +static void sig_handler(const int sig) +{ + (void)sig; + free_resources(); + wolfSSL_Cleanup(); +} + +static void free_resources(void) +{ + if (ssl != NULL) { + wolfSSL_shutdown(ssl); + wolfSSL_free(ssl); + ssl = NULL; + } + if (ctx != NULL) { + wolfSSL_CTX_free(ctx); + ctx = NULL; + } + if (listenfd != INVALID_SOCKET) { + close(listenfd); + listenfd = INVALID_SOCKET; + } +} + diff --git a/Arduino/sketches/wolfssl_version/wolfssl_version.ino b/Arduino/sketches/wolfssl_version/wolfssl_version.ino index 12be948f..ac34124b 100644 --- a/Arduino/sketches/wolfssl_version/wolfssl_version.ino +++ b/Arduino/sketches/wolfssl_version/wolfssl_version.ino @@ -6,7 +6,7 @@ * * 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 + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, @@ -21,6 +21,13 @@ #include <Arduino.h> +#if defined(ARDUINO_PORTENTA_X8) + /* The Portenta is a Linux device. See wolfSSL examples: + * https://github.com/wolfSSL/wolfssl/tree/master/examples + * By default Serial is disabled and mapped to ErrorSerial */ + #include <SerialRPC.h> +#endif + /* wolfSSL user_settings.h must be included from settings.h * Make all configurations changes in user_settings.h * Do not edit wolfSSL `settings.h` or `config.h` files.