├── .cargo └── config.toml ├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .gitmodules ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── build.rs ├── esp-mbedtls-sys ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── build.rs ├── gen │ ├── builder.rs │ ├── include │ │ ├── include.h │ │ └── soc │ │ │ ├── esp32 │ │ │ └── config.h │ │ │ ├── esp32c3 │ │ │ ├── config.h │ │ │ └── sha1_alt.h │ │ │ ├── esp32c6 │ │ │ ├── config.h │ │ │ └── sha1_alt.h │ │ │ ├── esp32s2 │ │ │ ├── config.h │ │ │ ├── sha1_alt.h │ │ │ ├── sha256_alt.h │ │ │ └── sha512_alt.h │ │ │ ├── esp32s3 │ │ │ ├── config.h │ │ │ ├── sha1_alt.h │ │ │ ├── sha256_alt.h │ │ │ └── sha512_alt.h │ │ │ └── generic │ │ │ └── config.h │ └── toolchains │ │ ├── toolchain-clang-esp32.cmake │ │ ├── toolchain-clang-esp32c3.cmake │ │ ├── toolchain-clang-esp32c6.cmake │ │ ├── toolchain-clang-esp32s2.cmake │ │ ├── toolchain-clang-esp32s3.cmake │ │ └── toolchain-clang-generic.cmake ├── libs │ ├── riscv32imac-unknown-none-elf │ │ ├── libmbedcrypto.a │ │ ├── libmbedtls.a │ │ └── libmbedx509.a │ ├── riscv32imc-unknown-none-elf │ │ ├── libmbedcrypto.a │ │ ├── libmbedtls.a │ │ └── libmbedx509.a │ ├── xtensa-esp32-none-elf │ │ ├── libmbedcrypto.a │ │ ├── libmbedtls.a │ │ └── libmbedx509.a │ ├── xtensa-esp32s2-none-elf │ │ ├── libmbedcrypto.a │ │ ├── libmbedtls.a │ │ └── libmbedx509.a │ └── xtensa-esp32s3-none-elf │ │ ├── libmbedcrypto.a │ │ ├── libmbedtls.a │ │ └── libmbedx509.a └── src │ ├── c_types.rs │ ├── include │ ├── esp32.rs │ ├── esp32c3.rs │ ├── esp32c6.rs │ ├── esp32s2.rs │ └── esp32s3.rs │ └── lib.rs ├── esp-mbedtls ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT └── src │ ├── edge_nal.rs │ ├── esp_hal.rs │ ├── esp_hal │ ├── bignum.rs │ └── sha │ │ ├── mod.rs │ │ ├── sha1.rs │ │ ├── sha256.rs │ │ └── sha512.rs │ └── lib.rs ├── examples ├── async_client.rs ├── async_server.rs ├── certs │ ├── .gitkeep │ ├── ca_cert.pem │ ├── ca_key.pem │ ├── certauth.cryptomix.com.pem │ ├── certificate.pem │ ├── private_key.pem │ └── www.google.com.pem ├── crypto_self_test.rs ├── crypto_self_test_std.rs ├── edge_server.rs ├── sync_client.rs └── sync_server.rs ├── genssl.sh ├── justfile ├── src └── lib.rs └── xtask ├── Cargo.toml └── src └── main.rs /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | # Build on host 3 | #target = "x86_64-unknown-linux-gnu" 4 | # Build on target firmware with baremetal 5 | #target = "xtensa-esp32-none-elf" 6 | #target = "xtensa-esp32s2-none-elf" 7 | #target = "xtensa-esp32s3-none-elf" 8 | #target = "riscv32imc-unknown-none-elf" 9 | # Build on target firmware with ESP IDF 10 | #target = "xtensa-esp32-espidf" 11 | #target = "xtensa-esp32s2-espidf" 12 | #target = "xtensa-esp32s3-espidf" 13 | #target = "riscv32imc-esp-espidf" 14 | 15 | [target.xtensa-esp32-none-elf] 16 | runner = "espflash flash --monitor --baud 921600" 17 | 18 | rustflags = [ 19 | "-C", "link-arg=-Tlinkall.x", 20 | "-C", "link-arg=-nostartfiles", 21 | ] 22 | 23 | [target.riscv32imc-unknown-none-elf] 24 | runner = "espflash flash --monitor --baud 921600" 25 | 26 | rustflags = [ 27 | "-C", "link-arg=-Tlinkall.x", 28 | 29 | # Required to obtain backtraces (e.g. when using the "esp-backtrace" crate.) 30 | # NOTE: May negatively impact performance of produced code 31 | "-C", "force-frame-pointers", 32 | ] 33 | 34 | [target.riscv32imac-unknown-none-elf] 35 | runner = "espflash flash --monitor --baud 921600" 36 | 37 | rustflags = [ 38 | "-C", "link-arg=-Tlinkall.x", 39 | 40 | # Required to obtain backtraces (e.g. when using the "esp-backtrace" crate.) 41 | # NOTE: May negatively impact performance of produced code 42 | "-C", "force-frame-pointers", 43 | ] 44 | 45 | [target.xtensa-esp32s2-none-elf] 46 | runner = "espflash flash --monitor --baud 921600" 47 | 48 | rustflags = [ 49 | #"-C", "linker=rust-lld", 50 | "-C", "link-arg=-Tlinkall.x", 51 | ] 52 | 53 | [target.xtensa-esp32s3-none-elf] 54 | runner = "espflash flash --monitor --baud 921600" 55 | 56 | rustflags = [ 57 | "-C", "link-arg=-Tlinkall.x", 58 | "-C", "link-arg=-nostartfiles", 59 | ] 60 | 61 | [target.'cfg(target_os = "espidf")'] 62 | linker = "ldproxy" 63 | runner = "espflash flash --monitor" 64 | rustflags = [ "--cfg", "espidf_time64"] 65 | 66 | [unstable] 67 | # Enable this when building for baremetal 68 | build-std = ["core", "alloc"] 69 | # Enable this when building on the host machine or for ESP-IDF 70 | #build-std = ["std", "panic_abort"] 71 | 72 | [alias] 73 | xtask = "run --manifest-path ./xtask/Cargo.toml --" 74 | 75 | 76 | # Alias' for quickly building for different chips or running examples 77 | # By default we enable 78 | # - `default` HAL features to set up basic chip specific settings 79 | esp32 = "run --release --features esp32 --target xtensa-esp32-none-elf --features esp-hal/default" 80 | esp32s2 = "run --release --features esp32s2 --target xtensa-esp32s2-none-elf --features esp-hal/default" 81 | esp32s3 = "run --release --features esp32s3 --target xtensa-esp32s3-none-elf --features esp-hal/default" 82 | esp32c3 = "run --release --features esp32c3 --target riscv32imc-unknown-none-elf --features esp-hal/default" 83 | esp32c6 = "run --release --features esp32c6 --target riscv32imac-unknown-none-elf --features esp-hal/default" 84 | 85 | besp32 = "build --release --features esp32 --target xtensa-esp32-none-elf --features esp-hal/default" 86 | besp32s2 = "build --release --features esp32s2 --target xtensa-esp32s2-none-elf --features esp-hal/default" 87 | besp32s3 = "build --release --features esp32s3 --target xtensa-esp32s3-none-elf --features esp-hal/default" 88 | besp32c3 = "build --release --features esp32c3 --target riscv32imc-unknown-none-elf --features esp-hal/default" 89 | besp32c6 = "build --release --features esp32c6 --target riscv32imac-unknown-none-elf --features esp-hal/default" 90 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sh text eol=lf 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # This CI optionally builds libraries and then builds examples against them. 2 | # 3 | # If a change is detected within `esp-mbedtls-sys/`, a rebuild is triggered and this CI will automatically 4 | # rebuild the libraries using the xtask. Then the tests are executed against the rebuilt libraries. 5 | # 6 | # If no rebuild occurs, the tests are executed against the current libraries. 7 | # 8 | # The libraries are pushed on either of these conditions: 9 | # 1. The PR is labelled with `rebuild-libs`. 10 | # Then libraries will be forcefully rebuilt and then pushed onto the PR branch. 11 | # 2. The libraries are rebuilt on the main branch. 12 | # When pushing a PR that would trigger a rebuild, the libraries get automatically 13 | # pushed to the main branch after successful testing. 14 | 15 | name: Build (optional) and test examples 16 | 17 | on: 18 | pull_request: 19 | branches: 20 | - main 21 | types: 22 | - opened 23 | - synchronize 24 | - reopened 25 | - labeled 26 | push: 27 | branches: 28 | - main 29 | workflow_dispatch: 30 | 31 | env: 32 | CARGO_TERM_COLOR: always 33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 34 | 35 | # Cancel any currently running workflows from the same PR, branch, or 36 | # tag when a new workflow is triggered. 37 | # 38 | # https://stackoverflow.com/a/66336834 39 | concurrency: 40 | cancel-in-progress: true 41 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} 42 | 43 | jobs: 44 | build-test: 45 | runs-on: ubuntu-latest 46 | permissions: read-all 47 | outputs: 48 | upload-libs: ${{ steps.detect-changes.outputs.libs == 'true' }} 49 | 50 | steps: 51 | # ==== Setup ==== 52 | - uses: actions/checkout@v4 53 | 54 | - name: mbedtls init 55 | run: git submodule update --init --recursive 56 | 57 | - uses: dtolnay/rust-toolchain@v1 58 | with: 59 | target: x86_64-unknown-linux-gnu 60 | toolchain: stable 61 | components: rust-src,rustfmt 62 | 63 | - uses: Swatinem/rust-cache@v2 64 | with: 65 | workspaces: | 66 | ./ 67 | xtask 68 | 69 | - name: Detect esp-mbedtls-sys/ changes 70 | uses: dorny/paths-filter@v3 71 | id: detect-changes 72 | with: 73 | filters: | 74 | libs: 75 | - 'esp-mbedtls-sys/**' 76 | 77 | - name: Install Rust for Xtensa and Espressif LLVM installation (optional) 78 | uses: esp-rs/xtensa-toolchain@v1.6 79 | with: 80 | ldproxy: true 81 | override: false 82 | extended-llvm: ${{ 83 | steps.detect-changes.outputs.libs == 'true' || 84 | contains(github.event.pull_request.labels.*.name, 'rebuild-libs') 85 | }} 86 | 87 | # ==== Build libs ==== 88 | - name: Build libraries and bindings 89 | if: | 90 | steps.detect-changes.outputs.libs == 'true' || 91 | contains(github.event.pull_request.labels.*.name, 'rebuild-libs') 92 | run: | 93 | rm -rf esp-mbedtls-sys/libs/* 94 | cargo +stable xtask gen 95 | 96 | # ==== Test ==== 97 | # If the libs are rebuilt, the tests are executed against the new libraries, 98 | # else they get executed against the latest version in HEAD 99 | 100 | # Tests requires nightly riscv32imc-unknown-none-elf to be installed 101 | - uses: dtolnay/rust-toolchain@v1 102 | with: 103 | target: riscv32imc-unknown-none-elf 104 | toolchain: nightly 105 | components: rust-src,rustfmt 106 | - uses: extractions/setup-just@v1 107 | with: 108 | just-version: 1.13.0 109 | 110 | - name: check 111 | run: just 112 | 113 | - name: Upload libraries artifacts for commit 114 | if: | 115 | (steps.detect-changes.outputs.libs == 'true' && 116 | github.ref == 'refs/heads/main') || 117 | contains(github.event.pull_request.labels.*.name, 'rebuild-libs') 118 | uses: actions/upload-artifact@v4 119 | with: 120 | name: esp-mbedtls-sys 121 | retention-days: 1 122 | path: | 123 | esp-mbedtls-sys/libs 124 | esp-mbedtls-sys/src 125 | 126 | # If libraries are rebuilt and tests are successful, we upload them in a specific job 127 | # that has write access to prevent security breaches, and unwanted use of the token 128 | commit-libs: 129 | runs-on: ubuntu-latest 130 | permissions: 131 | contents: write 132 | needs: build-test 133 | # TODO: Currently GitHub doesn't allow pushing to a forked repo's branch when running an action on a PR to upstream. 134 | if: | 135 | github.event.pull_request.head.repo.full_name == github.repository && 136 | ((needs.build-test.outputs.upload-libs && 137 | github.ref == 'refs/heads/main') || 138 | contains(github.event.pull_request.labels.*.name, 'rebuild-libs')) 139 | steps: 140 | - uses: actions/checkout@v4 141 | with: 142 | # In a pull request trigger, ref is required as GitHub Actions checks out in detached HEAD mode, 143 | # meaning it doesn’t check out your branch by default. 144 | ref: ${{ github.head_ref || github.ref_name }} 145 | # When doing a pull request, we need to fetch the forked repository. 146 | repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }} 147 | 148 | - name: Download artifacts 149 | uses: actions/download-artifact@v4 150 | with: 151 | name: esp-mbedtls-sys 152 | # Required because else artifacts will be put into the base directory 153 | path: esp-mbedtls-sys/ 154 | 155 | - name: Commit and push libraries to ${{ github.head_ref || github.ref_name }} 156 | run: | 157 | git config user.name "github-actions[bot]" 158 | git config user.email "github-actions[bot]@users.noreply.github.com" 159 | git add esp-mbedtls-sys/libs 160 | git add esp-mbedtls-sys/src 161 | # Only commit and push when there are changes 162 | git diff --cached --quiet || ( 163 | git commit -m "chore: auto-push built libraries" 164 | git push 165 | ) 166 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | 3 | # Libraries shouldn't contain Cargo.lock 4 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 5 | Cargo.lock 6 | 7 | # You should copy the template and not modify `settings.json` 8 | .vscode/settings.json 9 | 10 | .embuild 11 | 12 | tmpsrc 13 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "mbedtls"] 2 | path = esp-mbedtls-sys/mbedtls 3 | url = https://github.com/espressif/mbedtls 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "examples" 3 | version = "0.1.0" 4 | authors = ["bjoernQ "] 5 | edition = "2021" 6 | license = "MIT OR Apache-2.0" 7 | rust-version = "1.84" 8 | 9 | [profile.release] 10 | debug = true 11 | lto = "fat" 12 | opt-level = "s" 13 | 14 | 15 | [profile.release.package.esp-wifi] 16 | opt-level = 3 17 | 18 | [profile.dev] 19 | debug = true 20 | lto = "fat" 21 | opt-level = "z" 22 | 23 | [profile.dev.package.esp-wifi] 24 | opt-level = 3 25 | 26 | [dependencies] 27 | esp-hal = { version = "=1.0.0-rc.0", optional = true } 28 | esp-backtrace = { version = "0.16", optional = true, features = [ 29 | "panic-handler", 30 | "println", 31 | "exception-handler", 32 | ] } 33 | esp-println = { version = "0.14", optional = true, features = ["log-04"] } 34 | esp-hal-embassy = { version = "0.8", optional = true } 35 | 36 | embassy-time = { version = "0.4.0", optional = true } 37 | embassy-executor = { version = "0.7", package = "embassy-executor", features = [ 38 | "nightly", 39 | ], optional = true } 40 | embassy-net = { version = "0.6.0", features = [ 41 | "tcp", 42 | "udp", 43 | "dhcpv4", 44 | "medium-ethernet", 45 | ], optional = true } 46 | 47 | esp-wifi = { version = "0.15.0", optional = true, features = [ 48 | "sys-logs", 49 | "wifi", 50 | ] } 51 | blocking-network-stack = { git = "https://github.com/bjoernQ/blocking-network-stack", rev = "b3ecefc222d8806edd221f266999ca339c52d34e" } 52 | smoltcp = { version = "0.12.0", optional = true, default-features = false, features = [ 53 | "proto-ipv4", 54 | "socket-tcp", 55 | "socket-icmp", 56 | "socket-udp", 57 | "medium-ethernet", 58 | "proto-dhcpv4", 59 | "socket-raw", 60 | "socket-dhcpv4", 61 | ] } 62 | log = "0.4.16" 63 | embedded-io = "0.6.1" 64 | embedded-io-async = "0.6.0" 65 | heapless = "0.8.0" 66 | critical-section = "1.0.1" 67 | static_cell = { version = "2.1", features = ["nightly"] } 68 | 69 | esp-mbedtls = { path = "./esp-mbedtls" } 70 | 71 | edge-http = { version = "0.5.0", optional = true } 72 | edge-nal = { version = "0.5.0", optional = true } 73 | edge-nal-embassy = { version = "0.5.0", optional = true } 74 | cfg-if = "1.0.0" 75 | esp-alloc = { version = "0.8.0", optional = true } 76 | esp-bootloader-esp-idf = { version = "0.1.0", optional = true } 77 | enumset = { version = "1", default-features = false } 78 | 79 | [target.'cfg(target_os = "espidf")'.dependencies] 80 | esp-idf-svc = { version = "0.51", features = ["binstart"] } 81 | 82 | [[example]] 83 | name = "crypto_self_test" 84 | required-features = ["examples"] 85 | 86 | [[example]] 87 | name = "crypto_self_test_std" 88 | 89 | [[example]] 90 | name = "async_client" 91 | required-features = ["examples-async"] 92 | 93 | [[example]] 94 | name = "async_server" 95 | required-features = ["examples-async"] 96 | 97 | [[example]] 98 | name = "edge_server" 99 | required-features = ["examples-async", "edge-http"] 100 | 101 | [features] 102 | examples = [ 103 | "esp-hal", 104 | "esp-backtrace", 105 | "esp-println", 106 | "esp-wifi", 107 | "esp-wifi/smoltcp", 108 | "smoltcp", 109 | "esp-alloc", 110 | "esp-bootloader-esp-idf", 111 | ] 112 | examples-async = [ 113 | "examples", 114 | "esp-hal-embassy", 115 | "embassy-time", 116 | "embassy-executor", 117 | "embassy-net", 118 | "edge-http", 119 | "edge-nal", 120 | "edge-nal-embassy", 121 | "esp-mbedtls/async", 122 | "esp-mbedtls/edge-nal", 123 | ] 124 | examples-std = ["critical-section/std"] 125 | 126 | esp32 = [ 127 | "esp-hal?/esp32", 128 | "esp-hal-embassy?/esp32", 129 | "esp-backtrace?/esp32", 130 | "esp-println?/esp32", 131 | "esp-wifi?/esp32", 132 | "esp-mbedtls/esp32", 133 | ] 134 | esp32c3 = [ 135 | "esp-hal?/esp32c3", 136 | "esp-hal-embassy?/esp32c3", 137 | "esp-backtrace?/esp32c3", 138 | "esp-println?/esp32c3", 139 | "esp-wifi?/esp32c3", 140 | "esp-mbedtls/esp32c3", 141 | ] 142 | esp32c6 = [ 143 | "esp-hal?/esp32c6", 144 | "esp-hal-embassy?/esp32c6", 145 | "esp-backtrace?/esp32c6", 146 | "esp-println?/esp32c6", 147 | "esp-wifi?/esp32c6", 148 | "esp-mbedtls/esp32c6", 149 | ] 150 | esp32s2 = [ 151 | "esp-hal?/esp32s2", 152 | "esp-hal-embassy?/esp32s2", 153 | "esp-backtrace?/esp32s2", 154 | "esp-println?/esp32s2", 155 | "esp-wifi?/esp32s2", 156 | "esp-mbedtls/esp32s2", 157 | ] 158 | esp32s3 = [ 159 | "esp-hal?/esp32s3", 160 | "esp-hal-embassy?/esp32s3", 161 | "esp-backtrace?/esp32s3", 162 | "esp-println?/esp32s3", 163 | "esp-wifi?/esp32s3", 164 | "esp-mbedtls/esp32s3", 165 | ] 166 | 167 | # Enable mTLS for the running example. See example documentation for further details. 168 | # Applies to: 169 | # - async_client 170 | # - async_server 171 | # - sync_client 172 | # - sync_server 173 | mtls = [] 174 | 175 | [build-dependencies] 176 | embuild = { version = "0.33", features = ["espidf"] } 177 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2022 esp-rs 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 esp-rs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # esp-mbedtls 2 | 3 | This is mbedtls for ESP32 / bare-metal Rust. 4 | 5 | It comes with mbedtls precompiled to avoid the need for a complete C toolchain. See `build_mbedtls` for how it was built. 6 | 7 | ## Status 8 | 9 | This should work together with `esp-wifi`. It currently won't work without. However it's not well tested yet besides the included examples. 10 | 11 | In general this is heavy in terms of heap memory used and code size. If you can, you should prefer using something like `embedded-tls`. 12 | 13 | For now it's missing advanced configuration options which will be added step-by-step. 14 | 15 | The examples use one hard-coded address of `www.google.com` which might not always work. 16 | 17 | ### Certificates 18 | 19 | These examples use certificates that expire after a given time. 20 | 21 | The script `genssl.sh` is there to renew expired certificates, without having to manually update them within the code. 22 | 23 | ## Running Examples 24 | 25 | Examples are available for: 26 | 27 | - esp32 28 | - esp32c3 29 | - esp32c6 30 | - esp32s2 31 | - esp32s3 32 | 33 | To run examples, you need to specify the architecture as a feature, the example name, the target and the toolchain. 34 | 35 | You also need to set `SSID` and `PASSWORD` as your environment variables 36 | 37 | ### Examples 38 | 39 | Xtensa: 40 | 41 | ```shell 42 | SSID= PASSWORD= cargo +esp run --release --example sync_client -F esp32s3 --target xtensa-esp32s3-none-elf 43 | ``` 44 | 45 | RISC-V: 46 | 47 | ```shell 48 | SSID= PASSWORD= cargo +nightly run --release --example async_client -F esp32c3,async --target riscv32imc-unknown-none-elf 49 | ``` 50 | 51 | Here's a table of the architectures with their corresponding target for quick reference: 52 | 53 | | Architecture | Target | Toolchain | 54 | | ------------ | --------------------------- | ------------------ | 55 | | esp32 | xtensa-esp32-none-elf | esp | 56 | | esp32c3 | riscv32imc-unknown-none-elf | nightly | 57 | | esp32c6 | riscv32imac-unknown-none-elf| nightly | 58 | | esp32s2 | xtensa-esp32s2-none-elf | esp | 59 | | esp32s3 | xtensa-esp32s3-none-elf | esp | 60 | 61 | Heres's a list of all the examples with their description, and the required features to enable them: 62 | 63 | | Example | Features | Description | 64 | | :----------------------- | -------- | ------------------------------------------------------------ | 65 | | async_client | - | Example of a HTTPS connection using the async client. | 66 | | async_client (with mTLS) | mtls | Example of a HTTPS connection using the async client, with certificate authentication. This sends client certificates to a server, and the response indicates informations about the certificates. | 67 | | sync_client | - | Example of a HTTPS connection using the sync client. | 68 | | sync_client (with mTLS) | mtls | Example of a HTTPS connection using the sync client, with certificate authentication. This sends client certificates to a server, and the response indicates informations about the certificates. | 69 | | async_server | - | Example of a simple async server with HTTPS support. This uses self-signed certificates, so you will need to enable an exception in your browser. | 70 | | async_server (with mTLS) | mtls | Example of a simple async server with HTTPS support, with client authentication. You will need to pass client certificates in your request in order to have a successful connection. Refer to the documentation inside the example. | 71 | | sync_server | - | Example of a simple sync server with HTTPS support. This uses self-signed certificates, so you will need to enable an exception in your browser. | 72 | | sync_server (with mTLS) | mtls | Example of a simple sync server with HTTPS support, with client authentication. You will need to pass client certificates in your request in order to have a successful connection. Refer to the documentation inside the example. | 73 | 74 | This needs `espflash` version 2.x. If you are using version 1.x you need to remove the `flash` command from the runner in `.cargo/config.toml` 75 | 76 | ## License 77 | 78 | Licensed under either of: 79 | 80 | - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 81 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 82 | 83 | at your option. 84 | 85 | ### Contribution 86 | 87 | Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in 88 | the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without 89 | any additional terms or conditions. 90 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | if std::env::var("CARGO_CFG_TARGET_OS").unwrap().as_str() == "espidf" { 3 | embuild::espidf::sysenv::output(); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "esp-mbedtls-sys" 3 | version = "0.1.0" 4 | edition = "2021" 5 | links = "mbedtls" 6 | license = "MIT OR Apache-2.0" 7 | rust-version = "1.84" 8 | 9 | [build-dependencies] 10 | anyhow = "1.0.68" 11 | bindgen = "0.71.1" 12 | env_logger = "0.10.0" 13 | log = "0.4.17" 14 | cmake = "0.1.52" 15 | fs_extra = "1.3.0" 16 | embuild = "0.33" 17 | 18 | [dependencies] 19 | # For malloc/free 20 | # TODO: Replace with `esp-alloc` once `esp-alloc` starts to provide `malloc` and `free` in future 21 | # ... or switch to our own `mbedtls_malloc/free` 22 | esp-wifi = { version = "0.15.0", default-features = false, optional = true } 23 | 24 | # ESP-IDF: The mbedtls lib distributed with ESP-IDF is used 25 | [target.'cfg(target_os = "espidf")'.dependencies] 26 | esp-idf-sys = { version = "0.36", default-features = false } 27 | 28 | # All other platforms: mbedtls libs and bindings are created on the fly 29 | 30 | [features] 31 | default = [] 32 | 33 | # ESP-HAL: Exactly *one* chip MUST be selected via its feature: 34 | esp32 = ["esp-wifi/esp32"] 35 | esp32c3 = ["esp-wifi/esp32c3"] 36 | esp32c6 = ["esp-wifi/esp32c6"] 37 | esp32s2 = ["esp-wifi/esp32s2"] 38 | esp32s3 = ["esp-wifi/esp32s3"] 39 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2022 esp-rs 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 esp-rs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/build.rs: -------------------------------------------------------------------------------- 1 | use std::{env, path::PathBuf}; 2 | 3 | use anyhow::Result; 4 | 5 | #[path = "gen/builder.rs"] 6 | mod builder; 7 | 8 | fn main() -> Result<()> { 9 | let crate_root_path = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); 10 | 11 | builder::MbedtlsBuilder::track(&crate_root_path.join("gen")); 12 | builder::MbedtlsBuilder::track(&crate_root_path.join("mbedtls")); 13 | 14 | // If any one of these features is selected, we don't build anything 15 | // and just use the pre-generated baremetal ESP bindings and libraries 16 | let esp32 = env::var("CARGO_FEATURE_ESP32").is_ok(); 17 | let esp32c3 = env::var("CARGO_FEATURE_ESP32C3").is_ok(); 18 | let esp32c6 = env::var("CARGO_FEATURE_ESP32C6").is_ok(); 19 | let esp32s2 = env::var("CARGO_FEATURE_ESP32S2").is_ok(); 20 | let esp32s3 = env::var("CARGO_FEATURE_ESP32S3").is_ok(); 21 | 22 | let host = env::var("HOST").unwrap(); 23 | let target = env::var("TARGET").unwrap(); 24 | 25 | // If we're building for ESP32, ESP32C3, ESP32C6, ESP32S2, or ESP32S3, we don't need to do anything 26 | // Just link against the pre-built libraries and use the pre-generated bindings 27 | let bindings_dir = crate_root_path.join("src").join("include"); 28 | let libs_dir = crate_root_path.join("libs"); 29 | 30 | let dirs = if esp32 { 31 | Some(( 32 | bindings_dir.join("esp32.rs"), 33 | libs_dir.join("xtensa-esp32-none-elf"), 34 | )) 35 | } else if esp32c3 { 36 | Some(( 37 | bindings_dir.join("esp32c3.rs"), 38 | libs_dir.join("riscv32imc-unknown-none-elf"), 39 | )) 40 | } else if esp32c6 { 41 | Some(( 42 | bindings_dir.join("esp32c6.rs"), 43 | libs_dir.join("riscv32imac-unknown-none-elf"), 44 | )) 45 | } else if esp32s2 { 46 | Some(( 47 | bindings_dir.join("esp32s2.rs"), 48 | libs_dir.join("xtensa-esp32s2-none-elf"), 49 | )) 50 | } else if esp32s3 { 51 | Some(( 52 | bindings_dir.join("esp32s3.rs"), 53 | libs_dir.join("xtensa-esp32s3-none-elf"), 54 | )) 55 | } else if target.ends_with("-espidf") { 56 | // Nothing to do for ESP-IDF, `esp-idf-sys` will do everything for us 57 | None 58 | } else { 59 | // Need to do on-the-fly build and bindings' generation 60 | let out = PathBuf::from(env::var_os("OUT_DIR").unwrap()); 61 | 62 | let builder = builder::MbedtlsBuilder::new( 63 | crate_root_path.clone(), 64 | "generic".to_string(), 65 | None, 66 | None, 67 | None, 68 | Some(target), 69 | Some(host), 70 | ); 71 | 72 | let libs_dir = builder.compile(&out, None)?; 73 | let bindings = builder.generate_bindings(&out, None)?; 74 | 75 | Some((bindings, libs_dir)) 76 | }; 77 | 78 | if let Some((bindings, libs_dir)) = dirs { 79 | println!( 80 | "cargo::rustc-env=ESP_MBEDTLS_SYS_GENERATED_BINDINGS_FILE={}", 81 | bindings.display() 82 | ); 83 | 84 | println!("cargo:rustc-link-lib=static={}", "mbedtls"); 85 | println!("cargo:rustc-link-lib=static={}", "mbedx509"); 86 | println!("cargo:rustc-link-lib=static={}", "mbedcrypto"); 87 | println!("cargo:rustc-link-search={}", libs_dir.display()); 88 | } 89 | 90 | Ok(()) 91 | } 92 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/gen/builder.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | path::{Path, PathBuf}, 3 | process::Command, 4 | }; 5 | 6 | use anyhow::{anyhow, Result}; 7 | use bindgen::Builder; 8 | use cmake::Config; 9 | 10 | pub struct MbedtlsBuilder { 11 | crate_root_path: PathBuf, 12 | soc_config: String, 13 | clang_path: Option, 14 | sysroot_path: Option, 15 | cmake_target: Option, 16 | clang_target: Option, 17 | host: Option, 18 | } 19 | 20 | impl MbedtlsBuilder { 21 | /// Create a new MbedtlsBuilder 22 | /// 23 | /// Arguments: 24 | /// - `crate_root_path`: Path to the root of the crate 25 | /// - `soc_config`: The name of the SoC configuration in the `headers/` directory. Use `generic` for a generic, software-only build 26 | /// - `clang_path`: Optional path to the Clang compiler. If not specified, the system Clang will be used for generating bindings, 27 | /// and the system compiler (likely GCC) would be used for building the MbedTLS C code itself 28 | /// - `sysroot_path`: Optional path to the compiler sysroot directory. If not specified, the host sysroot will be used 29 | /// - `cmake_target`: Optional target for CMake when building MbedTLS, with Rust target-triple syntax. If not specified, the "TARGET" env variable will be used 30 | /// - `clang_target`: Optional target for Clang when generating bindings. If not specified, the host target will be used 31 | /// - `host`: Optional host target for the build 32 | pub const fn new( 33 | crate_root_path: PathBuf, 34 | soc_config: String, 35 | clang_path: Option, 36 | sysroot_path: Option, 37 | cmake_target: Option, 38 | clang_target: Option, 39 | host: Option, 40 | ) -> Self { 41 | Self { 42 | crate_root_path, 43 | soc_config, 44 | clang_path, 45 | sysroot_path, 46 | cmake_target, 47 | clang_target, 48 | host, 49 | } 50 | } 51 | 52 | /// Generate bindings for esp-mbedtls-sys 53 | /// 54 | /// Arguments: 55 | /// - `out_path`: Path to write the bindings to 56 | pub fn generate_bindings( 57 | &self, 58 | out_path: &Path, 59 | copy_file_path: Option<&Path>, 60 | ) -> Result { 61 | if let Some(clang_path) = &self.clang_path { 62 | std::env::set_var("CLANG_PATH", clang_path); 63 | } 64 | 65 | let canon = |path: &Path| { 66 | // TODO: Is this really necessary? 67 | path.display() 68 | .to_string() 69 | .replace('\\', "/") 70 | .replace("//?/C:", "") 71 | }; 72 | 73 | // Generate the bindings using `bindgen`: 74 | log::info!("Generating bindings"); 75 | let mut builder = Builder::default().clang_args([ 76 | &format!( 77 | "-I{}", 78 | canon(&self.crate_root_path.join("mbedtls").join("include")) 79 | ), 80 | &format!( 81 | "-I{}", 82 | canon( 83 | &self 84 | .crate_root_path 85 | .join("gen") 86 | .join("include") 87 | .join("soc") 88 | .join(&self.soc_config) 89 | ) 90 | ), 91 | ]); 92 | 93 | if let Some(sysroot_path) = &self.sysroot_path { 94 | builder = builder.clang_args([ 95 | &format!("-I{}", canon(&sysroot_path.join("include"))), 96 | &format!("--sysroot={}", canon(sysroot_path)), 97 | ]); 98 | } 99 | 100 | if let Some(target) = &self.clang_target { 101 | builder = builder.clang_arg(&format!("--target={target}")); 102 | } 103 | 104 | let bindings = builder 105 | .ctypes_prefix("crate::c_types") 106 | .derive_debug(false) 107 | .header( 108 | self.crate_root_path 109 | .join("gen") 110 | .join("include") 111 | .join("include.h") 112 | .to_string_lossy(), 113 | ) 114 | .layout_tests(false) 115 | .use_core() 116 | .generate() 117 | .map_err(|_| anyhow!("Failed to generate bindings"))?; 118 | 119 | let bindings_file = out_path.join("bindings.rs"); 120 | 121 | // Write out the bindings to the appropriate path: 122 | log::info!("Writing out bindings to: {}", bindings_file.display()); 123 | bindings.write_to_file(&bindings_file)?; 124 | 125 | // Format the bindings: 126 | Command::new("rustfmt") 127 | .arg(bindings_file.to_string_lossy().to_string()) 128 | .arg("--config") 129 | .arg("normalize_doc_attributes=true") 130 | .output()?; 131 | 132 | if let Some(copy_file_path) = copy_file_path { 133 | log::info!("Copying bindings to {}", copy_file_path.display()); 134 | std::fs::copy(&bindings_file, copy_file_path)?; 135 | } 136 | 137 | Ok(bindings_file) 138 | } 139 | 140 | /// Compile mbedtls 141 | /// 142 | /// Arguments: 143 | /// - `out_path`: Path to write the compiled libraries to 144 | pub fn compile(&self, out_path: &Path, copy_path: Option<&Path>) -> Result { 145 | if let Some(clang_path) = &self.clang_path { 146 | std::env::set_var("CLANG_PATH", clang_path); 147 | } 148 | 149 | log::info!("Compiling for {} SOC", self.soc_config); 150 | let mbedtls_path = self.crate_root_path.join("mbedtls"); 151 | 152 | let target_dir = out_path.join("mbedtls").join("build"); 153 | 154 | std::fs::create_dir_all(&target_dir)?; 155 | 156 | // Compile mbedtls and generate libraries to link against 157 | log::info!("Compiling mbedtls"); 158 | let mut config = Config::new(&mbedtls_path); 159 | 160 | config 161 | .define("USE_SHARED_MBEDTLS_LIBRARY", "OFF") 162 | .define("USE_STATIC_MBEDTLS_LIBRARY", "ON") 163 | .define("ENABLE_PROGRAMS", "OFF") 164 | .define("ENABLE_TESTING", "OFF") 165 | .define("CMAKE_EXPORT_COMPILE_COMMANDS", "ON") 166 | // Clang will complain about some documentation formatting in mbedtls 167 | .define("MBEDTLS_FATAL_WARNINGS", "OFF") 168 | .define( 169 | "MBEDTLS_CONFIG_FILE", 170 | &self 171 | .crate_root_path 172 | .join("gen") 173 | .join("include") 174 | .join("soc") 175 | .join(&self.soc_config) 176 | .join("config.h"), 177 | ) 178 | .define( 179 | "CMAKE_TOOLCHAIN_FILE", 180 | &self 181 | .crate_root_path 182 | .join("gen") 183 | .join("toolchains") 184 | .join(format!("toolchain-clang-{}.cmake", self.soc_config)), 185 | ) 186 | .cflag(&format!( 187 | "-I{}", 188 | self.crate_root_path 189 | .join("gen") 190 | .join("include") 191 | .join("soc") 192 | .join(&self.soc_config) 193 | .display() 194 | )) 195 | .cflag(&format!("-DMBEDTLS_CONFIG_FILE=''")) 196 | .cxxflag(&format!("-DMBEDTLS_CONFIG_FILE=''")) 197 | .profile("Release") 198 | .out_dir(&target_dir); 199 | 200 | if let Some(target) = &self.cmake_target { 201 | config.target(target); 202 | } 203 | 204 | if let Some(host) = &self.host { 205 | config.host(host); 206 | } 207 | 208 | config.build(); 209 | 210 | let lib_dir = target_dir.join("lib"); 211 | 212 | if let Some(copy_path) = copy_path { 213 | log::info!("Copying mbedtls libraries to {}", copy_path.display()); 214 | std::fs::create_dir_all(copy_path)?; 215 | 216 | for file in ["libmbedcrypto.a", "libmbedx509.a", "libmbedtls.a"] { 217 | std::fs::copy(lib_dir.join(file), copy_path.join(file))?; 218 | } 219 | } 220 | 221 | Ok(lib_dir) 222 | } 223 | 224 | /// Re-run the build script if the file or directory has changed. 225 | #[allow(unused)] 226 | pub fn track(file_or_dir: &Path) { 227 | println!("cargo:rerun-if-changed={}", file_or_dir.display()) 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/gen/include/include.h: -------------------------------------------------------------------------------- 1 | #define MBEDTLS_CONFIG_FILE "config.h" 2 | 3 | #include MBEDTLS_CONFIG_FILE 4 | 5 | #include "mbedtls/ssl.h" 6 | #include "mbedtls/x509.h" 7 | #include "mbedtls/entropy.h" 8 | #include "mbedtls/debug.h" 9 | #include "mbedtls/ctr_drbg.h" 10 | #include "psa/crypto_values.h" 11 | 12 | // Provides a function prototype to generate bindings for mbedtls_mpi_exp_mod_soft() 13 | #if defined(MBEDTLS_MPI_EXP_MOD_ALT_FALLBACK) 14 | int mbedtls_mpi_exp_mod_soft(mbedtls_mpi *X, const mbedtls_mpi *A, 15 | const mbedtls_mpi *E, const mbedtls_mpi *N, 16 | mbedtls_mpi *prec_RR); 17 | #endif 18 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/gen/include/soc/esp32c3/sha1_alt.h: -------------------------------------------------------------------------------- 1 | typedef struct mbedtls_sha1_context { 2 | void* hasher; 3 | } mbedtls_sha1_context; 4 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/gen/include/soc/esp32c6/sha1_alt.h: -------------------------------------------------------------------------------- 1 | typedef struct mbedtls_sha1_context { 2 | void* hasher; 3 | } mbedtls_sha1_context; 4 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/gen/include/soc/esp32s2/sha1_alt.h: -------------------------------------------------------------------------------- 1 | typedef struct mbedtls_sha1_context { 2 | void* hasher; 3 | } mbedtls_sha1_context; 4 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/gen/include/soc/esp32s2/sha256_alt.h: -------------------------------------------------------------------------------- 1 | typedef struct mbedtls_sha256_context { 2 | void* sha224_hasher; 3 | void* sha256_hasher; 4 | int is224; 5 | } mbedtls_sha256_context; 6 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/gen/include/soc/esp32s2/sha512_alt.h: -------------------------------------------------------------------------------- 1 | typedef struct mbedtls_sha512_context { 2 | void* sha384_hasher; 3 | void* sha512_hasher; 4 | int is384; 5 | } mbedtls_sha512_context; 6 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/gen/include/soc/esp32s3/sha1_alt.h: -------------------------------------------------------------------------------- 1 | typedef struct mbedtls_sha1_context { 2 | void* hasher; 3 | } mbedtls_sha1_context; 4 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/gen/include/soc/esp32s3/sha256_alt.h: -------------------------------------------------------------------------------- 1 | typedef struct mbedtls_sha256_context { 2 | void* sha224_hasher; 3 | void* sha256_hasher; 4 | int is224; 5 | } mbedtls_sha256_context; 6 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/gen/include/soc/esp32s3/sha512_alt.h: -------------------------------------------------------------------------------- 1 | typedef struct mbedtls_sha512_context { 2 | void* sha384_hasher; 3 | void* sha512_hasher; 4 | int is384; 5 | } mbedtls_sha512_context; 6 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/gen/toolchains/toolchain-clang-esp32.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Generic) 2 | 3 | # Install with `espup install --extended-llvm` 4 | set(CMAKE_C_COMPILER "$ENV{CLANG_PATH}") 5 | 6 | set(CLANG_DIR_PATH "${CMAKE_C_COMPILER}") 7 | cmake_path(REMOVE_FILENAME CLANG_DIR_PATH) 8 | 9 | set(CMAKE_AR "${CLANG_DIR_PATH}/llvm-ar") 10 | set(CMAKE_RANLIB "${CLANG_DIR_PATH}/llvm-ranlib") 11 | set(CMAKE_OBJDUMP xtensa-esp32-elf-objdump) 12 | 13 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --target=xtensa-esp-elf -mcpu=esp32" 14 | CACHE STRING "C Compiler Base Flags" 15 | FORCE) 16 | 17 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --target=xtensa-esp-elf -mcpu=esp32" 18 | CACHE STRING "C++ Compiler Base Flags" 19 | FORCE) 20 | 21 | set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} --target=xtensa-esp-elf -mcpu=esp32 -Xassembler --longcalls" 22 | CACHE STRING "Assembler Base Flags" 23 | FORCE) 24 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/gen/toolchains/toolchain-clang-esp32c3.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Generic) 2 | 3 | # Install with `espup install --extended-llvm` 4 | set(CMAKE_C_COMPILER "$ENV{CLANG_PATH}") 5 | 6 | set(CLANG_DIR_PATH "${CMAKE_C_COMPILER}") 7 | cmake_path(REMOVE_FILENAME CLANG_DIR_PATH) 8 | 9 | set(CMAKE_AR "${CLANG_DIR_PATH}/llvm-ar") 10 | set(CMAKE_RANLIB "${CLANG_DIR_PATH}/llvm-ranlib") 11 | set(CMAKE_OBJDUMP riscv32-esp-elf-objdump) 12 | 13 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --target=riscv32-esp-elf -march=rv32imc -mabi=ilp32" 14 | CACHE STRING "C Compiler Base Flags" 15 | FORCE) 16 | 17 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --target=riscv32-esp-elf -march=rv32imc -mabi=ilp32" 18 | CACHE STRING "C++ Compiler Base Flags" 19 | FORCE) 20 | 21 | set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} --target=riscv32-esp-elf -march=rv32imc -mabi=ilp32" 22 | CACHE STRING "Assembler Base Flags" 23 | FORCE) 24 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/gen/toolchains/toolchain-clang-esp32c6.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Generic) 2 | 3 | # Install with `espup install --extended-llvm` 4 | set(CMAKE_C_COMPILER "$ENV{CLANG_PATH}") 5 | 6 | set(CLANG_DIR_PATH "${CMAKE_C_COMPILER}") 7 | cmake_path(REMOVE_FILENAME CLANG_DIR_PATH) 8 | 9 | set(CMAKE_AR "${CLANG_DIR_PATH}/llvm-ar") 10 | set(CMAKE_RANLIB "${CLANG_DIR_PATH}/llvm-ranlib") 11 | set(CMAKE_OBJDUMP riscv32-esp-elf-objdump) 12 | 13 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --target=riscv32-esp-elf -march=rv32imac -mabi=ilp32" 14 | CACHE STRING "C Compiler Base Flags" 15 | FORCE) 16 | 17 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --target=riscv32-esp-elf -march=rv32imac -mabi=ilp32" 18 | CACHE STRING "C++ Compiler Base Flags" 19 | FORCE) 20 | 21 | set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} --target=riscv32-esp-elf -march=rv32imac -mabi=ilp32" 22 | CACHE STRING "Assembler Base Flags" 23 | FORCE) 24 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/gen/toolchains/toolchain-clang-esp32s2.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Generic) 2 | 3 | # Install with `espup install --extended-llvm` 4 | set(CMAKE_C_COMPILER "$ENV{CLANG_PATH}") 5 | 6 | set(CLANG_DIR_PATH "${CMAKE_C_COMPILER}") 7 | cmake_path(REMOVE_FILENAME CLANG_DIR_PATH) 8 | 9 | set(CMAKE_AR "${CLANG_DIR_PATH}/llvm-ar") 10 | set(CMAKE_RANLIB "${CLANG_DIR_PATH}/llvm-ranlib") 11 | set(CMAKE_OBJDUMP xtensa-esp32s2-elf-objdump) 12 | 13 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --target=xtensa-esp-elf -mcpu=esp32s2" 14 | CACHE STRING "C Compiler Base Flags" 15 | FORCE) 16 | 17 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --target=xtensa-esp-elf -mcpu=esp32s2" 18 | CACHE STRING "C++ Compiler Base Flags" 19 | FORCE) 20 | 21 | set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} --target=xtensa-esp-elf -mcpu=esp32s2 -Xassembler --longcalls" 22 | CACHE STRING "Assembler Base Flags" 23 | FORCE) 24 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/gen/toolchains/toolchain-clang-esp32s3.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Generic) 2 | 3 | # Install with `espup install --extended-llvm` 4 | set(CMAKE_C_COMPILER "$ENV{CLANG_PATH}") 5 | 6 | set(CLANG_DIR_PATH "${CMAKE_C_COMPILER}") 7 | cmake_path(REMOVE_FILENAME CLANG_DIR_PATH) 8 | 9 | set(CMAKE_AR "${CLANG_DIR_PATH}/llvm-ar") 10 | set(CMAKE_RANLIB "${CLANG_DIR_PATH}/llvm-ranlib") 11 | set(CMAKE_OBJDUMP xtensa-esp32s3-elf-objdump) 12 | 13 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --target=xtensa-esp-elf -mcpu=esp32s3" 14 | CACHE STRING "C Compiler Base Flags" 15 | FORCE) 16 | 17 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --target=xtensa-esp-elf -mcpu=esp32s3" 18 | CACHE STRING "C++ Compiler Base Flags" 19 | FORCE) 20 | 21 | set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} --target=xtensa-esp-elf -mcpu=esp32s3 -Xassembler --longcalls" 22 | CACHE STRING "Assembler Base Flags" 23 | FORCE) 24 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/gen/toolchains/toolchain-clang-generic.cmake: -------------------------------------------------------------------------------- 1 | set(CMAKE_SYSTEM_NAME Generic) 2 | 3 | # For generic targets, just use the C compiler and utilities user should have in their PATH already 4 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/libs/riscv32imac-unknown-none-elf/libmbedcrypto.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esp-rs/esp-mbedtls/35e8ccd5999cf0c831c9b825491fd68581d108c2/esp-mbedtls-sys/libs/riscv32imac-unknown-none-elf/libmbedcrypto.a -------------------------------------------------------------------------------- /esp-mbedtls-sys/libs/riscv32imac-unknown-none-elf/libmbedtls.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esp-rs/esp-mbedtls/35e8ccd5999cf0c831c9b825491fd68581d108c2/esp-mbedtls-sys/libs/riscv32imac-unknown-none-elf/libmbedtls.a -------------------------------------------------------------------------------- /esp-mbedtls-sys/libs/riscv32imac-unknown-none-elf/libmbedx509.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esp-rs/esp-mbedtls/35e8ccd5999cf0c831c9b825491fd68581d108c2/esp-mbedtls-sys/libs/riscv32imac-unknown-none-elf/libmbedx509.a -------------------------------------------------------------------------------- /esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedcrypto.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esp-rs/esp-mbedtls/35e8ccd5999cf0c831c9b825491fd68581d108c2/esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedcrypto.a -------------------------------------------------------------------------------- /esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedtls.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esp-rs/esp-mbedtls/35e8ccd5999cf0c831c9b825491fd68581d108c2/esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedtls.a -------------------------------------------------------------------------------- /esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedx509.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esp-rs/esp-mbedtls/35e8ccd5999cf0c831c9b825491fd68581d108c2/esp-mbedtls-sys/libs/riscv32imc-unknown-none-elf/libmbedx509.a -------------------------------------------------------------------------------- /esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedcrypto.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esp-rs/esp-mbedtls/35e8ccd5999cf0c831c9b825491fd68581d108c2/esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedcrypto.a -------------------------------------------------------------------------------- /esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedtls.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esp-rs/esp-mbedtls/35e8ccd5999cf0c831c9b825491fd68581d108c2/esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedtls.a -------------------------------------------------------------------------------- /esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedx509.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esp-rs/esp-mbedtls/35e8ccd5999cf0c831c9b825491fd68581d108c2/esp-mbedtls-sys/libs/xtensa-esp32-none-elf/libmbedx509.a -------------------------------------------------------------------------------- /esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedcrypto.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esp-rs/esp-mbedtls/35e8ccd5999cf0c831c9b825491fd68581d108c2/esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedcrypto.a -------------------------------------------------------------------------------- /esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedtls.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esp-rs/esp-mbedtls/35e8ccd5999cf0c831c9b825491fd68581d108c2/esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedtls.a -------------------------------------------------------------------------------- /esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedx509.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esp-rs/esp-mbedtls/35e8ccd5999cf0c831c9b825491fd68581d108c2/esp-mbedtls-sys/libs/xtensa-esp32s2-none-elf/libmbedx509.a -------------------------------------------------------------------------------- /esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedcrypto.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esp-rs/esp-mbedtls/35e8ccd5999cf0c831c9b825491fd68581d108c2/esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedcrypto.a -------------------------------------------------------------------------------- /esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedtls.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esp-rs/esp-mbedtls/35e8ccd5999cf0c831c9b825491fd68581d108c2/esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedtls.a -------------------------------------------------------------------------------- /esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedx509.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esp-rs/esp-mbedtls/35e8ccd5999cf0c831c9b825491fd68581d108c2/esp-mbedtls-sys/libs/xtensa-esp32s3-none-elf/libmbedx509.a -------------------------------------------------------------------------------- /esp-mbedtls-sys/src/c_types.rs: -------------------------------------------------------------------------------- 1 | pub use core::ffi::*; 2 | -------------------------------------------------------------------------------- /esp-mbedtls-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | // For `malloc`, `calloc` and `free` which are provided by `esp-wifi` on baremetal 4 | #[cfg(any( 5 | feature = "esp32", 6 | feature = "esp32c3", 7 | feature = "esp32c6", 8 | feature = "esp32s2", 9 | feature = "esp32s3" 10 | ))] 11 | use esp_wifi as _; 12 | 13 | #[cfg(not(target_os = "espidf"))] 14 | mod c_types; 15 | 16 | #[allow( 17 | non_camel_case_types, 18 | non_snake_case, 19 | non_upper_case_globals, 20 | dead_code 21 | )] 22 | pub mod bindings { 23 | #[cfg(all( 24 | not(target_os = "espidf"), 25 | not(any( 26 | feature = "esp32", 27 | feature = "esp32c3", 28 | feature = "esp32c6", 29 | feature = "esp32s2", 30 | feature = "esp32s3" 31 | )) 32 | ))] 33 | include!(env!("ESP_MBEDTLS_SYS_GENERATED_BINDINGS_FILE")); 34 | 35 | // This and below are necessary because of https://github.com/rust-lang/cargo/issues/10358 36 | #[cfg(feature = "esp32")] 37 | include!("include/esp32.rs"); 38 | 39 | #[cfg(feature = "esp32c3")] 40 | include!("include/esp32c3.rs"); 41 | 42 | #[cfg(feature = "esp32c6")] 43 | include!("include/esp32c6.rs"); 44 | 45 | #[cfg(feature = "esp32s2")] 46 | include!("include/esp32s2.rs"); 47 | 48 | #[cfg(feature = "esp32s3")] 49 | include!("include/esp32s3.rs"); 50 | 51 | #[cfg(target_os = "espidf")] 52 | pub use esp_idf_sys::*; 53 | } 54 | -------------------------------------------------------------------------------- /esp-mbedtls/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "esp-mbedtls" 3 | version = "0.1.0" 4 | edition = "2021" 5 | license = "MIT OR Apache-2.0" 6 | rust-version = "1.84" 7 | 8 | [lib] 9 | harness = false 10 | 11 | [dependencies] 12 | esp-mbedtls-sys = { path = "../esp-mbedtls-sys" } 13 | log = { version = "0.4.17", default-features = false } 14 | enumset = { version = "1", default-features = false } 15 | embedded-io = { version = "0.6.1" } 16 | embedded-io-async = { version = "0.6.0", optional = true } 17 | esp-hal = { version = "=1.0.0-rc.0", features = ["unstable"], optional = true } 18 | # For malloc/free 19 | # TODO: Replace with `esp-alloc` once `esp-alloc` starts to provide `malloc` and `free` in future 20 | # ... or switch to our own `mbedtls_malloc/free` 21 | esp-wifi = { version = "0.15", default-features = false, optional = true } 22 | cfg-if = "1.0.0" 23 | edge-nal = { version = "0.5.0", optional = true } 24 | critical-section = "1.1.3" 25 | crypto-bigint = { version = "0.5.3", optional = true, default-features = false, features = ["extra-sizes"] } 26 | nb = { version = "1.1.0", optional = true } 27 | 28 | [features] 29 | default = ["edge-nal"] 30 | async = ["dep:embedded-io-async"] 31 | esp32 = ["esp-hal/esp32", "esp-wifi/esp32", "esp-mbedtls-sys/esp32"] 32 | esp32c3 = ["esp-hal/esp32c3", "esp-wifi/esp32c3", "esp-mbedtls-sys/esp32c3"] 33 | esp32c6 = ["esp-hal/esp32c6", "esp-wifi/esp32c6", "esp-mbedtls-sys/esp32c6"] 34 | esp32s2 = ["esp-hal/esp32s2", "esp-wifi/esp32s2", "esp-mbedtls-sys/esp32s2"] 35 | esp32s3 = ["esp-hal/esp32s3", "esp-wifi/esp32s3", "esp-mbedtls-sys/esp32s3"] 36 | 37 | # Implement the traits defined in the latest HEAD of `edge-nal` 38 | edge-nal = ["dep:edge-nal", "async"] 39 | 40 | # Enable dependencies related to esp-hal (baremetal) 41 | esp-hal = ["dep:esp-hal", "crypto-bigint", "nb"] 42 | -------------------------------------------------------------------------------- /esp-mbedtls/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2022 esp-rs 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /esp-mbedtls/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 esp-rs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /esp-mbedtls/src/edge_nal.rs: -------------------------------------------------------------------------------- 1 | use core::ffi::CStr; 2 | use core::net::SocketAddr; 3 | 4 | use embedded_io::Error; 5 | 6 | use crate::asynch::Session; 7 | use crate::{Certificates, Mode, TlsError, TlsReference, TlsVersion}; 8 | 9 | /// An implementation of `edge-nal`'s `TcpAccept` trait over TLS. 10 | pub struct TlsAcceptor<'d, T> { 11 | acceptor: T, 12 | min_version: TlsVersion, 13 | certificates: Certificates<'d>, 14 | tls_ref: TlsReference<'d>, 15 | } 16 | 17 | impl<'d, T> TlsAcceptor<'d, T> 18 | where 19 | T: edge_nal::TcpAccept, 20 | { 21 | /// Create a new instance of the `TlsAcceptor` type. 22 | /// 23 | /// Arguments: 24 | /// 25 | /// * `acceptor` - The underlying TCP acceptor 26 | /// * `min_version` - The minimum TLS version to support 27 | /// * `certificates` - The certificates to use for each accepted TLS connection 28 | /// * `tls_ref` - A reference to the active `Tls` instance 29 | pub const fn new( 30 | acceptor: T, 31 | min_version: TlsVersion, 32 | certificates: Certificates<'d>, 33 | tls_ref: TlsReference<'d>, 34 | ) -> Self { 35 | Self { 36 | acceptor, 37 | min_version, 38 | certificates, 39 | tls_ref, 40 | } 41 | } 42 | } 43 | 44 | impl edge_nal::TcpAccept for TlsAcceptor<'_, T> 45 | where 46 | T: edge_nal::TcpAccept, 47 | { 48 | type Error = TlsError; 49 | type Socket<'a> 50 | = Session<'a, T::Socket<'a>> 51 | where 52 | Self: 'a; 53 | 54 | async fn accept( 55 | &self, 56 | ) -> Result<(SocketAddr, Self::Socket<'_>), ::Error> { 57 | let (addr, socket) = self 58 | .acceptor 59 | .accept() 60 | .await 61 | .map_err(|e| TlsError::Io(e.kind()))?; 62 | log::debug!("Accepted new connection on socket"); 63 | 64 | let session = Session::new( 65 | socket, 66 | Mode::Server, 67 | self.min_version, 68 | self.certificates, 69 | self.tls_ref, 70 | )?; 71 | 72 | Ok((addr, session)) 73 | } 74 | } 75 | 76 | /// An implementation of `edge-nal`'s `TcpConnect` trait over TLS. 77 | pub struct TlsConnector<'d, T> { 78 | connector: T, 79 | servername: &'d CStr, 80 | min_version: TlsVersion, 81 | certificates: Certificates<'d>, 82 | tls_ref: TlsReference<'d>, 83 | } 84 | 85 | impl<'d, T> TlsConnector<'d, T> 86 | where 87 | T: edge_nal::TcpConnect, 88 | { 89 | /// Create a new instance of the `TlsConnector` type. 90 | /// 91 | /// Arguments: 92 | /// 93 | /// * `connector` - The underlying TCP connector 94 | /// * `servername` - The server name to check against the certificate presented by the server 95 | /// * `min_version` - The minimum TLS version to support 96 | /// * `certificates` - The certificates to use for each established TLS connection 97 | /// * `tls_ref` - A reference to the active `Tls` instance 98 | pub const fn new( 99 | connector: T, 100 | servername: &'d CStr, 101 | min_version: TlsVersion, 102 | certificates: Certificates<'d>, 103 | tls_ref: TlsReference<'d>, 104 | ) -> Self { 105 | Self { 106 | connector, 107 | servername, 108 | min_version, 109 | certificates, 110 | tls_ref, 111 | } 112 | } 113 | } 114 | 115 | impl edge_nal::TcpConnect for TlsConnector<'_, T> 116 | where 117 | T: edge_nal::TcpConnect, 118 | { 119 | type Error = TlsError; 120 | 121 | type Socket<'a> 122 | = Session<'a, T::Socket<'a>> 123 | where 124 | Self: 'a; 125 | 126 | async fn connect(&self, remote: SocketAddr) -> Result, Self::Error> { 127 | let socket = self 128 | .connector 129 | .connect(remote) 130 | .await 131 | .map_err(|e| TlsError::Io(e.kind()))?; 132 | log::debug!("Connected to {remote}"); 133 | 134 | let session = Session::new( 135 | socket, 136 | Mode::Client { 137 | servername: self.servername, 138 | }, 139 | self.min_version, 140 | self.certificates, 141 | self.tls_ref, 142 | )?; 143 | 144 | Ok(session) 145 | } 146 | } 147 | 148 | impl edge_nal::Readable for Session<'_, T> 149 | where 150 | T: edge_nal::Readable, 151 | { 152 | async fn readable(&mut self) -> Result<(), Self::Error> { 153 | // ... 1- because it is difficult to figure out - with the MbedTLS API - if `Session::read` would return without blocking 154 | // For this, we need support for that in MbedTLS itself, which is not available at the moment. 155 | // 2- because `Readable` currently throws exception with `edge-nal-embassy` 156 | Ok(()) 157 | } 158 | } 159 | 160 | impl edge_nal::TcpSplit for Session<'_, T> 161 | where 162 | T: edge_nal::TcpSplit + embedded_io_async::Read + embedded_io_async::Write + edge_nal::Readable, 163 | { 164 | type Read<'a> 165 | = Self 166 | where 167 | Self: 'a; 168 | 169 | type Write<'a> 170 | = Self 171 | where 172 | Self: 'a; 173 | 174 | fn split(&mut self) -> (Self::Read<'_>, Self::Write<'_>) { 175 | panic!("Splitting a TLS session is not supported yet"); 176 | } 177 | } 178 | 179 | impl edge_nal::TcpShutdown for Session<'_, T> 180 | where 181 | T: embedded_io_async::Read + embedded_io_async::Write + edge_nal::TcpShutdown, 182 | { 183 | async fn close(&mut self, what: edge_nal::Close) -> Result<(), Self::Error> { 184 | Session::close(self).await?; 185 | 186 | self.stream 187 | .close(what) 188 | .await 189 | .map_err(|e| TlsError::Io(e.kind())) 190 | } 191 | 192 | async fn abort(&mut self) -> Result<(), Self::Error> { 193 | self.stream 194 | .abort() 195 | .await 196 | .map_err(|e| TlsError::Io(e.kind())) 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /esp-mbedtls/src/esp_hal.rs: -------------------------------------------------------------------------------- 1 | #[doc(hidden)] 2 | use core::cell::RefCell; 3 | use critical_section::Mutex; 4 | 5 | use esp_hal::peripherals::{RSA, SHA}; 6 | use esp_hal::rsa::Rsa; 7 | use esp_hal::sha::Sha; 8 | 9 | use crate::{Tls, TlsError}; 10 | 11 | #[cfg(any( 12 | feature = "esp32c3", 13 | feature = "esp32c6", 14 | feature = "esp32s2", 15 | feature = "esp32s3" 16 | ))] 17 | mod bignum; 18 | #[cfg(not(feature = "esp32"))] 19 | mod sha; 20 | 21 | /// Hold the RSA peripheral for cryptographic operations. 22 | /// 23 | /// This is initialized when `with_hardware_rsa()` is called on a [Session] and is set back to None 24 | /// when the session that called `with_hardware_rsa()` is dropped. 25 | /// 26 | /// Note: Due to implementation constraints, this session and every other session will use the 27 | /// hardware accelerated RSA driver until the session called with this function is dropped. 28 | static mut RSA_REF: Option> = None; 29 | 30 | /// Hold the SHA peripheral for cryptographic operations. 31 | static SHARED_SHA: Mutex>>> = Mutex::new(RefCell::new(None)); 32 | 33 | impl<'d> Tls<'d> { 34 | /// Create a new instance of the `Tls` type. 35 | /// 36 | /// Note that there could be only one active `Tls` instance at any point in time, 37 | /// and the function will return an error if there is already an active instance. 38 | /// 39 | /// Arguments: 40 | /// 41 | /// * `sha` - The SHA peripheral from the HAL 42 | pub fn new(sha: SHA<'d>) -> Result { 43 | let this = Self::create()?; 44 | 45 | critical_section::with(|cs| { 46 | SHARED_SHA 47 | .borrow_ref_mut(cs) 48 | .replace(unsafe { core::mem::transmute(Sha::new(sha)) }) 49 | }); 50 | 51 | Ok(this) 52 | } 53 | 54 | /// Enable the use of the hardware accelerated RSA peripheral for the `Tls` singleton. 55 | /// 56 | /// # Arguments 57 | /// 58 | /// * `rsa` - The RSA peripheral from the HAL 59 | pub fn with_hardware_rsa(self, rsa: RSA<'d>) -> Self { 60 | unsafe { RSA_REF = core::mem::transmute(Some(Rsa::new(rsa))) } 61 | self 62 | } 63 | } 64 | 65 | impl Drop for Tls<'_> { 66 | fn drop(&mut self) { 67 | unsafe { 68 | RSA_REF = core::mem::transmute(None::); 69 | } 70 | critical_section::with(|cs| SHARED_SHA.borrow_ref_mut(cs).take()); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /esp-mbedtls/src/esp_hal/bignum.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_snake_case)] 2 | 3 | use core::ffi::c_int; 4 | 5 | use esp_hal::rsa::{operand_sizes, RsaModularExponentiation}; 6 | 7 | use crypto_bigint::*; 8 | 9 | use esp_mbedtls_sys::bindings::*; 10 | 11 | use crate::esp_hal::RSA_REF; 12 | 13 | macro_rules! error_checked { 14 | ($block:expr) => {{ 15 | let res = $block; 16 | if res != 0 { 17 | panic!("Non zero error {:?}", res); 18 | } else { 19 | // Do nothing for now 20 | } 21 | }}; 22 | } 23 | 24 | #[cfg(feature = "esp32")] 25 | const SOC_RSA_MAX_BIT_LEN: usize = 4096; 26 | #[cfg(feature = "esp32c3")] 27 | const SOC_RSA_MAX_BIT_LEN: usize = 3072; 28 | #[cfg(feature = "esp32c6")] 29 | const SOC_RSA_MAX_BIT_LEN: usize = 3072; 30 | #[cfg(feature = "esp32s2")] 31 | const SOC_RSA_MAX_BIT_LEN: usize = 4096; 32 | #[cfg(feature = "esp32s3")] 33 | const SOC_RSA_MAX_BIT_LEN: usize = 4096; 34 | 35 | /// Bad input parameters to function. 36 | const MBEDTLS_ERR_MPI_BAD_INPUT_DATA: c_int = -0x0004; 37 | 38 | /// Calculate the number of words used for a hardware operation. 39 | /// 40 | /// For every chip except `esp32`, this will return `words` 41 | /// For `esp32`, this will return the number of words rounded up to the 512 block count. 42 | const fn calculate_hw_words(words: usize) -> usize { 43 | // Round up number of words to nearest 44 | // 512 bit (16 word) block count. 45 | #[cfg(feature = "esp32")] 46 | return (words + 0xF) & !0xF; 47 | #[cfg(not(feature = "esp32"))] 48 | words 49 | } 50 | 51 | /// Return the number of words actually used to represent an mpi number. 52 | fn mpi_words(X: &mbedtls_mpi) -> usize { 53 | for i in (0..=X.private_n).rev() { 54 | let index = i as usize; 55 | 56 | if unsafe { X.private_p.add(index - 1).read() } != 0 { 57 | return index; 58 | } 59 | } 60 | 0 61 | } 62 | 63 | #[inline] 64 | fn copy_bytes(src: *const T, dst: *mut T, count: usize) 65 | where 66 | T: Copy, 67 | { 68 | unsafe { core::ptr::copy_nonoverlapping(src, dst, count) }; 69 | } 70 | 71 | fn compute_mprime(M: &mbedtls_mpi) -> u32 { 72 | let mut t: u64 = 1; 73 | let mut two_2_i_minus_1: u64 = 2; // 2^(i-1) 74 | let mut two_2_i: u64 = 4; // 2^i 75 | let n = unsafe { M.private_p.read() } as u64; 76 | 77 | for _ in 2..=32 { 78 | if n * t % two_2_i >= two_2_i_minus_1 { 79 | t += two_2_i_minus_1; 80 | } 81 | 82 | two_2_i_minus_1 <<= 1; 83 | two_2_i <<= 1; 84 | } 85 | 86 | (u32::MAX as u64 - t + 1) as u32 87 | } 88 | 89 | /// Calculate Rinv = RR^2 mod M, where: 90 | /// 91 | /// R = b^n where b = 2^32, n=num_words, 92 | /// R = 2^N (where N=num_bits) 93 | /// RR = R^2 = 2^(2*N) (where N=num_bits=num_words*32) 94 | /// 95 | /// This calculation is computationally expensive (mbedtls_mpi_mod_mpi) 96 | /// so caller should cache the result where possible. 97 | /// 98 | /// DO NOT call this function while holding esp_mpi_enable_hardware_hw_op(). 99 | fn calculate_rinv(prec_RR: &mut mbedtls_mpi, M: &mbedtls_mpi, num_words: usize) -> c_int { 100 | let ret = 0; 101 | let num_bits = num_words * 32; 102 | let mut RR = mbedtls_mpi { 103 | private_s: 0, 104 | private_n: 0, 105 | private_p: core::ptr::null_mut(), 106 | }; 107 | 108 | unsafe { 109 | mbedtls_mpi_init(&mut RR); 110 | error_checked!(mbedtls_mpi_set_bit(&mut RR, num_bits * 2, 1)); 111 | error_checked!(mbedtls_mpi_mod_mpi(prec_RR, &RR, M)); 112 | mbedtls_mpi_free(&mut RR); 113 | } 114 | 115 | ret 116 | } 117 | 118 | /// Z = X ^ Y mod M 119 | #[no_mangle] 120 | pub unsafe extern "C" fn mbedtls_mpi_exp_mod( 121 | Z: *mut mbedtls_mpi, 122 | X: &mbedtls_mpi, 123 | Y: &mbedtls_mpi, 124 | M: &mbedtls_mpi, 125 | prec_RR: *mut mbedtls_mpi, 126 | ) -> c_int { 127 | match RSA_REF { 128 | None => return unsafe { mbedtls_mpi_exp_mod_soft(Z, X, Y, M, prec_RR) }, 129 | Some(ref mut rsa) => { 130 | let x_words = mpi_words(X); 131 | let y_words = mpi_words(Y); 132 | let m_words = mpi_words(M); 133 | 134 | // All numbers must be the lame length, so choose longest number as 135 | // cardinal length of operation 136 | let num_words = 137 | calculate_hw_words(core::cmp::max(m_words, core::cmp::max(x_words, y_words))); 138 | 139 | if num_words * 32 > SOC_RSA_MAX_BIT_LEN { 140 | return unsafe { mbedtls_mpi_exp_mod_soft(Z, X, Y, M, prec_RR) }; 141 | } 142 | 143 | if M.private_p.is_null() { 144 | todo!("Handle this null"); 145 | } 146 | unsafe { 147 | if mbedtls_mpi_cmp_int(M, 0) <= 0 || M.private_p.read() & 1 == 0 { 148 | return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 149 | } 150 | 151 | if mbedtls_mpi_cmp_int(Y, 0) < 0 { 152 | return MBEDTLS_ERR_MPI_BAD_INPUT_DATA; 153 | } 154 | 155 | if mbedtls_mpi_cmp_int(Y, 0) == 0 { 156 | return mbedtls_mpi_lset(Z, 1); 157 | } 158 | } 159 | 160 | let mut rinv_new = mbedtls_mpi { 161 | private_s: 0, 162 | private_n: 0, 163 | private_p: core::ptr::null_mut(), 164 | }; 165 | 166 | // Determine RR pointer, either _RR for cached value or local RR_new 167 | let rinv: &mut mbedtls_mpi = if prec_RR.is_null() { 168 | unsafe { mbedtls_mpi_init(&mut rinv_new) }; 169 | &mut rinv_new 170 | } else { 171 | // This is safe since we check above if pointer is not null 172 | unsafe { &mut *prec_RR } 173 | }; 174 | 175 | if rinv.private_p.is_null() { 176 | calculate_rinv(rinv, M, num_words); 177 | } 178 | 179 | unsafe { 180 | error_checked!(mbedtls_mpi_grow(Z, m_words)); 181 | } 182 | 183 | nb::block!(rsa.ready()).unwrap(); 184 | rsa.enable_disable_constant_time_acceleration(true); 185 | rsa.enable_disable_search_acceleration(true); 186 | unsafe { 187 | match num_words { 188 | U256::LIMBS => { 189 | const OP_SIZE: usize = U256::LIMBS; 190 | let mut base = [0u32; OP_SIZE]; 191 | let mut exponent = [0u32; OP_SIZE]; 192 | let mut modulus = [0u32; OP_SIZE]; 193 | let mut r = [0u32; OP_SIZE]; 194 | copy_bytes(X.private_p, base.as_mut_ptr(), x_words); 195 | copy_bytes(Y.private_p, exponent.as_mut_ptr(), y_words); 196 | copy_bytes(M.private_p, modulus.as_mut_ptr(), m_words); 197 | copy_bytes(rinv.private_p, r.as_mut_ptr(), mpi_words(rinv)); 198 | let mut mod_exp = RsaModularExponentiation::< 199 | operand_sizes::Op256, 200 | esp_hal::Blocking, 201 | >::new( 202 | rsa, 203 | &exponent, // exponent (Y) Y_MEM 204 | &modulus, // modulus (M) M_MEM 205 | compute_mprime(M), // mprime 206 | ); 207 | let mut out = [0u32; OP_SIZE]; 208 | mod_exp.start_exponentiation( 209 | &base, // X_MEM 210 | &r, // Z_MEM 211 | ); 212 | 213 | mod_exp.read_results(&mut out); 214 | copy_bytes(out.as_ptr(), (*Z).private_p, m_words); 215 | } 216 | U384::LIMBS => { 217 | const OP_SIZE: usize = U384::LIMBS; 218 | let mut base = [0u32; OP_SIZE]; 219 | let mut exponent = [0u32; OP_SIZE]; 220 | let mut modulus = [0u32; OP_SIZE]; 221 | let mut r = [0u32; OP_SIZE]; 222 | copy_bytes(X.private_p, base.as_mut_ptr(), x_words); 223 | copy_bytes(Y.private_p, exponent.as_mut_ptr(), y_words); 224 | copy_bytes(M.private_p, modulus.as_mut_ptr(), m_words); 225 | copy_bytes(rinv.private_p, r.as_mut_ptr(), mpi_words(rinv)); 226 | let mut mod_exp = RsaModularExponentiation::< 227 | operand_sizes::Op384, 228 | esp_hal::Blocking, 229 | >::new( 230 | rsa, 231 | &exponent, // exponent (Y) Y_MEM 232 | &modulus, // modulus (M) M_MEM 233 | compute_mprime(M), // mprime 234 | ); 235 | let mut out = [0u32; OP_SIZE]; 236 | mod_exp.start_exponentiation( 237 | &base, // X_MEM 238 | &r, // Z_MEM 239 | ); 240 | 241 | mod_exp.read_results(&mut out); 242 | copy_bytes(out.as_ptr(), (*Z).private_p, m_words); 243 | } 244 | U512::LIMBS => { 245 | const OP_SIZE: usize = U512::LIMBS; 246 | let mut base = [0u32; OP_SIZE]; 247 | let mut exponent = [0u32; OP_SIZE]; 248 | let mut modulus = [0u32; OP_SIZE]; 249 | let mut r = [0u32; OP_SIZE]; 250 | copy_bytes(X.private_p, base.as_mut_ptr(), x_words); 251 | copy_bytes(Y.private_p, exponent.as_mut_ptr(), y_words); 252 | copy_bytes(M.private_p, modulus.as_mut_ptr(), m_words); 253 | copy_bytes(rinv.private_p, r.as_mut_ptr(), mpi_words(rinv)); 254 | let mut mod_exp = RsaModularExponentiation::< 255 | operand_sizes::Op512, 256 | esp_hal::Blocking, 257 | >::new( 258 | rsa, 259 | &exponent, // exponent (Y) Y_MEM 260 | &modulus, // modulus (M) M_MEM 261 | compute_mprime(M), // mprime 262 | ); 263 | let mut out = [0u32; OP_SIZE]; 264 | mod_exp.start_exponentiation( 265 | &base, // X_MEM 266 | &r, // Z_MEM 267 | ); 268 | 269 | mod_exp.read_results(&mut out); 270 | copy_bytes(out.as_ptr(), (*Z).private_p, m_words); 271 | } 272 | U1024::LIMBS => { 273 | const OP_SIZE: usize = U1024::LIMBS; 274 | let mut base = [0u32; OP_SIZE]; 275 | let mut exponent = [0u32; OP_SIZE]; 276 | let mut modulus = [0u32; OP_SIZE]; 277 | let mut r = [0u32; OP_SIZE]; 278 | copy_bytes(X.private_p, base.as_mut_ptr(), x_words); 279 | copy_bytes(Y.private_p, exponent.as_mut_ptr(), y_words); 280 | copy_bytes(M.private_p, modulus.as_mut_ptr(), m_words); 281 | copy_bytes(rinv.private_p, r.as_mut_ptr(), mpi_words(rinv)); 282 | let mut mod_exp = RsaModularExponentiation::< 283 | operand_sizes::Op1024, 284 | esp_hal::Blocking, 285 | >::new( 286 | rsa, 287 | &exponent, // exponent (Y) Y_MEM 288 | &modulus, // modulus (M) M_MEM 289 | compute_mprime(M), // mprime 290 | ); 291 | let mut out = [0u32; OP_SIZE]; 292 | mod_exp.start_exponentiation( 293 | &base, // X_MEM 294 | &r, // Z_MEM 295 | ); 296 | 297 | mod_exp.read_results(&mut out); 298 | copy_bytes(out.as_ptr(), (*Z).private_p, m_words); 299 | } 300 | U2048::LIMBS => { 301 | const OP_SIZE: usize = U2048::LIMBS; 302 | let mut base = [0u32; OP_SIZE]; 303 | let mut exponent = [0u32; OP_SIZE]; 304 | let mut modulus = [0u32; OP_SIZE]; 305 | let mut r = [0u32; OP_SIZE]; 306 | copy_bytes(X.private_p, base.as_mut_ptr(), x_words); 307 | copy_bytes(Y.private_p, exponent.as_mut_ptr(), y_words); 308 | copy_bytes(M.private_p, modulus.as_mut_ptr(), m_words); 309 | copy_bytes(rinv.private_p, r.as_mut_ptr(), mpi_words(rinv)); 310 | let mut mod_exp = RsaModularExponentiation::< 311 | operand_sizes::Op2048, 312 | esp_hal::Blocking, 313 | >::new( 314 | rsa, 315 | &exponent, // exponent (Y) Y_MEM 316 | &modulus, // modulus (M) M_MEM 317 | compute_mprime(M), // mprime 318 | ); 319 | let mut out = [0u32; OP_SIZE]; 320 | mod_exp.start_exponentiation( 321 | &base, // X_MEM 322 | &r, // Z_MEM 323 | ); 324 | 325 | mod_exp.read_results(&mut out); 326 | copy_bytes(out.as_ptr(), (*Z).private_p, m_words); 327 | } 328 | #[cfg(not(any(feature = "esp32c3", feature = "esp32c6")))] 329 | U4096::LIMBS => { 330 | const OP_SIZE: usize = U4096::LIMBS; 331 | let mut base = [0u32; OP_SIZE]; 332 | let mut exponent = [0u32; OP_SIZE]; 333 | let mut modulus = [0u32; OP_SIZE]; 334 | let mut r = [0u32; OP_SIZE]; 335 | copy_bytes(X.private_p, base.as_mut_ptr(), x_words); 336 | copy_bytes(Y.private_p, exponent.as_mut_ptr(), y_words); 337 | copy_bytes(M.private_p, modulus.as_mut_ptr(), m_words); 338 | copy_bytes(rinv.private_p, r.as_mut_ptr(), mpi_words(rinv)); 339 | let mut mod_exp = RsaModularExponentiation::< 340 | operand_sizes::Op4096, 341 | esp_hal::Blocking, 342 | >::new( 343 | rsa, 344 | &exponent, // exponent (Y) Y_MEM 345 | &modulus, // modulus (M) M_MEM 346 | compute_mprime(M), // mprime 347 | ); 348 | let mut out = [0u32; OP_SIZE]; 349 | mod_exp.start_exponentiation( 350 | &base, // X_MEM 351 | &r, // Z_MEM 352 | ); 353 | 354 | mod_exp.read_results(&mut out); 355 | copy_bytes(out.as_ptr(), (*Z).private_p, m_words); 356 | } 357 | op => { 358 | todo!("Implement operand: {}", op); 359 | } 360 | } 361 | } 362 | 363 | assert_eq!(X.private_s, 1); 364 | // Compensate for negative X 365 | if X.private_s == -1 && unsafe { Y.private_p.read() & 1 } != 0 { 366 | unsafe { (*Z).private_s = -1 }; 367 | unsafe { error_checked!(mbedtls_mpi_add_mpi(Z, M, Z)) }; 368 | } else { 369 | unsafe { (*Z).private_s = 1 }; 370 | } 371 | 372 | if prec_RR.is_null() { 373 | unsafe { mbedtls_mpi_free(&mut rinv_new) }; 374 | } 375 | 0 376 | } 377 | } 378 | } 379 | -------------------------------------------------------------------------------- /esp-mbedtls/src/esp_hal/sha/mod.rs: -------------------------------------------------------------------------------- 1 | use esp_hal::sha::{Context, ShaDigest}; 2 | 3 | mod sha1; 4 | #[cfg(any(feature = "esp32s2", feature = "esp32s3"))] 5 | mod sha256; 6 | #[cfg(any(feature = "esp32s2", feature = "esp32s3"))] 7 | mod sha512; 8 | -------------------------------------------------------------------------------- /esp-mbedtls/src/esp_hal/sha/sha1.rs: -------------------------------------------------------------------------------- 1 | use core::ffi::{c_int, c_uchar, c_void}; 2 | 3 | use esp_hal::sha::Sha1; 4 | 5 | use crate::esp_hal::SHARED_SHA; 6 | 7 | use super::{Context, ShaDigest}; 8 | 9 | #[allow(non_camel_case_types)] 10 | #[repr(C)] 11 | pub struct mbedtls_sha1_context { 12 | hasher: *mut Context, 13 | } 14 | 15 | #[no_mangle] 16 | pub unsafe extern "C" fn mbedtls_sha1_init(ctx: *mut mbedtls_sha1_context) { 17 | let hasher_mem = crate::aligned_calloc( 18 | core::mem::align_of::>(), 19 | core::mem::size_of::>(), 20 | ) as *mut Context; 21 | core::ptr::write(hasher_mem, Context::::new()); 22 | (*ctx).hasher = hasher_mem; 23 | } 24 | 25 | #[no_mangle] 26 | pub unsafe extern "C" fn mbedtls_sha1_free(ctx: *mut mbedtls_sha1_context) { 27 | if !ctx.is_null() && !(*ctx).hasher.is_null() { 28 | crate::free((*ctx).hasher as *const c_void); 29 | (*ctx).hasher = core::ptr::null_mut(); 30 | } 31 | } 32 | 33 | #[no_mangle] 34 | pub unsafe extern "C" fn mbedtls_sha1_clone( 35 | dst: *mut mbedtls_sha1_context, 36 | src: *const mbedtls_sha1_context, 37 | ) { 38 | core::ptr::copy((*src).hasher.clone(), (*dst).hasher, 1); 39 | } 40 | 41 | #[no_mangle] 42 | pub unsafe extern "C" fn mbedtls_sha1_starts(_ctx: *mut mbedtls_sha1_context) -> c_int { 43 | 0 44 | } 45 | 46 | #[no_mangle] 47 | pub unsafe extern "C" fn mbedtls_sha1_update( 48 | ctx: *mut mbedtls_sha1_context, 49 | input: *const c_uchar, 50 | ilen: usize, 51 | ) -> c_int { 52 | let mut data = core::ptr::slice_from_raw_parts(input as *const u8, ilen as usize); 53 | critical_section::with(|cs| { 54 | let mut sha = SHARED_SHA.borrow_ref_mut(cs); 55 | let mut hasher = ShaDigest::restore(sha.as_mut().unwrap(), (*ctx).hasher.as_mut().unwrap()); 56 | while !data.is_empty() { 57 | data = nb::block!(hasher.update(&*data)).unwrap(); 58 | } 59 | nb::block!(hasher.save((*ctx).hasher.as_mut().unwrap())).unwrap(); 60 | }); 61 | 0 62 | } 63 | 64 | #[no_mangle] 65 | pub unsafe extern "C" fn mbedtls_sha1_finish( 66 | ctx: *mut mbedtls_sha1_context, 67 | output: *mut c_uchar, 68 | ) -> c_int { 69 | let mut data: [u8; 20] = [0u8; 20]; 70 | critical_section::with(|cs| { 71 | let mut sha = SHARED_SHA.borrow_ref_mut(cs); 72 | let mut hasher = ShaDigest::restore(sha.as_mut().unwrap(), (*ctx).hasher.as_mut().unwrap()); 73 | nb::block!(hasher.finish(&mut data)).unwrap(); 74 | nb::block!(hasher.save((*ctx).hasher.as_mut().unwrap())).unwrap(); 75 | }); 76 | core::ptr::copy_nonoverlapping(data.as_ptr(), output, data.len()); 77 | 0 78 | } 79 | -------------------------------------------------------------------------------- /esp-mbedtls/src/esp_hal/sha/sha256.rs: -------------------------------------------------------------------------------- 1 | use core::ffi::{c_int, c_uchar, c_void}; 2 | 3 | use esp_hal::sha::{Sha224, Sha256}; 4 | 5 | use crate::esp_hal::SHARED_SHA; 6 | 7 | use super::{Context, ShaDigest}; 8 | 9 | #[allow(non_camel_case_types)] 10 | #[repr(C)] 11 | pub struct mbedtls_sha256_context { 12 | sha224_hasher: *mut Context, 13 | sha256_hasher: *mut Context, 14 | is224: c_int, 15 | } 16 | 17 | #[no_mangle] 18 | pub unsafe extern "C" fn mbedtls_sha256_init(ctx: *mut mbedtls_sha256_context) { 19 | let sha224_mem = crate::aligned_calloc( 20 | core::mem::align_of::>(), 21 | core::mem::size_of::>(), 22 | ) as *mut Context; 23 | let sha256_mem = crate::aligned_calloc( 24 | core::mem::align_of::>(), 25 | core::mem::size_of::>(), 26 | ) as *mut Context; 27 | (*ctx).sha224_hasher = sha224_mem; 28 | (*ctx).sha256_hasher = sha256_mem; 29 | } 30 | 31 | #[no_mangle] 32 | pub unsafe extern "C" fn mbedtls_sha256_free(ctx: *mut mbedtls_sha256_context) { 33 | if !ctx.is_null() { 34 | if !(*ctx).sha224_hasher.is_null() { 35 | crate::free((*ctx).sha224_hasher as *const c_void); 36 | (*ctx).sha224_hasher = core::ptr::null_mut(); 37 | } 38 | if !(*ctx).sha256_hasher.is_null() { 39 | crate::free((*ctx).sha256_hasher as *const c_void); 40 | (*ctx).sha256_hasher = core::ptr::null_mut(); 41 | } 42 | } 43 | } 44 | 45 | #[no_mangle] 46 | pub unsafe extern "C" fn mbedtls_sha256_clone( 47 | dst: *mut mbedtls_sha256_context, 48 | src: *const mbedtls_sha256_context, 49 | ) { 50 | core::ptr::copy((*src).sha224_hasher.clone(), (*dst).sha224_hasher, 1); 51 | core::ptr::copy((*src).sha256_hasher.clone(), (*dst).sha256_hasher, 1); 52 | (*dst).is224 = (*src).is224; 53 | } 54 | 55 | #[no_mangle] 56 | pub unsafe extern "C" fn mbedtls_sha256_starts( 57 | ctx: *mut mbedtls_sha256_context, 58 | is224: c_int, 59 | ) -> c_int { 60 | if is224 == 1 { 61 | (*ctx).is224 = 1; 62 | core::ptr::write((*ctx).sha224_hasher, Context::new()); 63 | } else { 64 | core::ptr::write((*ctx).sha256_hasher, Context::new()); 65 | } 66 | 0 67 | } 68 | 69 | #[no_mangle] 70 | pub unsafe extern "C" fn mbedtls_sha256_update( 71 | ctx: *mut mbedtls_sha256_context, 72 | input: *const c_uchar, 73 | ilen: usize, 74 | ) -> c_int { 75 | let mut data = core::ptr::slice_from_raw_parts(input as *const u8, ilen as usize); 76 | critical_section::with(|cs| { 77 | let mut sha = SHARED_SHA.borrow_ref_mut(cs); 78 | if (*ctx).is224 == 1 { 79 | let mut hasher = ShaDigest::restore( 80 | sha.as_mut().unwrap(), 81 | (*ctx).sha224_hasher.as_mut().unwrap(), 82 | ); 83 | while !data.is_empty() { 84 | data = nb::block!(hasher.update(&*data)).unwrap(); 85 | } 86 | nb::block!(hasher.save((*ctx).sha224_hasher.as_mut().unwrap())).unwrap(); 87 | } else { 88 | let mut hasher = ShaDigest::restore( 89 | sha.as_mut().unwrap(), 90 | (*ctx).sha256_hasher.as_mut().unwrap(), 91 | ); 92 | while !data.is_empty() { 93 | data = nb::block!(hasher.update(&*data)).unwrap(); 94 | } 95 | nb::block!(hasher.save((*ctx).sha256_hasher.as_mut().unwrap())).unwrap(); 96 | } 97 | }); 98 | 0 99 | } 100 | 101 | #[no_mangle] 102 | pub unsafe extern "C" fn mbedtls_sha256_finish( 103 | ctx: *mut mbedtls_sha256_context, 104 | output: *mut c_uchar, 105 | ) -> c_int { 106 | let mut data: [u8; 32] = [0u8; 32]; 107 | critical_section::with(|cs| { 108 | let mut sha = SHARED_SHA.borrow_ref_mut(cs); 109 | 110 | if (*ctx).is224 == 1 { 111 | let mut hasher = ShaDigest::restore( 112 | sha.as_mut().unwrap(), 113 | (*ctx).sha224_hasher.as_mut().unwrap(), 114 | ); 115 | nb::block!(hasher.finish(&mut data)).unwrap(); 116 | nb::block!(hasher.save((*ctx).sha224_hasher.as_mut().unwrap())).unwrap(); 117 | core::ptr::copy_nonoverlapping(data.as_ptr(), output, 28); 118 | } else { 119 | let mut hasher = ShaDigest::restore( 120 | sha.as_mut().unwrap(), 121 | (*ctx).sha256_hasher.as_mut().unwrap(), 122 | ); 123 | nb::block!(hasher.finish(&mut data)).unwrap(); 124 | nb::block!(hasher.save((*ctx).sha256_hasher.as_mut().unwrap())).unwrap(); 125 | core::ptr::copy_nonoverlapping(data.as_ptr(), output, 32); 126 | } 127 | }); 128 | 0 129 | } 130 | -------------------------------------------------------------------------------- /esp-mbedtls/src/esp_hal/sha/sha512.rs: -------------------------------------------------------------------------------- 1 | use core::ffi::{c_int, c_uchar, c_void}; 2 | 3 | use esp_hal::sha::{Sha384, Sha512}; 4 | 5 | use crate::esp_hal::SHARED_SHA; 6 | 7 | use super::{Context, ShaDigest}; 8 | 9 | #[allow(non_camel_case_types)] 10 | #[repr(C)] 11 | pub struct mbedtls_sha512_context { 12 | sha384_hasher: *mut Context, 13 | sha512_hasher: *mut Context, 14 | is384: c_int, 15 | } 16 | 17 | #[no_mangle] 18 | pub unsafe extern "C" fn mbedtls_sha512_init(ctx: *mut mbedtls_sha512_context) { 19 | let sha384_mem = crate::aligned_calloc( 20 | core::mem::align_of::>(), 21 | core::mem::size_of::>(), 22 | ) as *mut Context; 23 | let sha512_mem = crate::aligned_calloc( 24 | core::mem::align_of::>(), 25 | core::mem::size_of::>(), 26 | ) as *mut Context; 27 | (*ctx).sha384_hasher = sha384_mem; 28 | (*ctx).sha512_hasher = sha512_mem; 29 | } 30 | 31 | #[no_mangle] 32 | pub unsafe extern "C" fn mbedtls_sha512_free(ctx: *mut mbedtls_sha512_context) { 33 | if !ctx.is_null() { 34 | if !(*ctx).sha384_hasher.is_null() { 35 | crate::free((*ctx).sha384_hasher as *const c_void); 36 | (*ctx).sha384_hasher = core::ptr::null_mut(); 37 | } 38 | if !(*ctx).sha512_hasher.is_null() { 39 | crate::free((*ctx).sha512_hasher as *const c_void); 40 | (*ctx).sha512_hasher = core::ptr::null_mut(); 41 | } 42 | } 43 | } 44 | 45 | #[no_mangle] 46 | pub unsafe extern "C" fn mbedtls_sha512_clone( 47 | dst: *mut mbedtls_sha512_context, 48 | src: *const mbedtls_sha512_context, 49 | ) { 50 | core::ptr::copy((*src).sha384_hasher.clone(), (*dst).sha384_hasher, 1); 51 | core::ptr::copy((*src).sha512_hasher.clone(), (*dst).sha512_hasher, 1); 52 | (*dst).is384 = (*src).is384; 53 | } 54 | 55 | #[no_mangle] 56 | pub unsafe extern "C" fn mbedtls_sha512_starts( 57 | ctx: *mut mbedtls_sha512_context, 58 | is384: c_int, 59 | ) -> c_int { 60 | if is384 == 1 { 61 | (*ctx).is384 = 1; 62 | core::ptr::write((*ctx).sha384_hasher, Context::new()); 63 | } else { 64 | core::ptr::write((*ctx).sha512_hasher, Context::new()); 65 | } 66 | 0 67 | } 68 | 69 | #[no_mangle] 70 | pub unsafe extern "C" fn mbedtls_sha512_update( 71 | ctx: *mut mbedtls_sha512_context, 72 | input: *const c_uchar, 73 | ilen: usize, 74 | ) -> c_int { 75 | let mut data = core::ptr::slice_from_raw_parts(input as *const u8, ilen as usize); 76 | critical_section::with(|cs| { 77 | let mut sha = SHARED_SHA.borrow_ref_mut(cs); 78 | if (*ctx).is384 == 1 { 79 | let mut hasher = ShaDigest::restore( 80 | sha.as_mut().unwrap(), 81 | (*ctx).sha384_hasher.as_mut().unwrap(), 82 | ); 83 | while !data.is_empty() { 84 | data = nb::block!(hasher.update(&*data)).unwrap(); 85 | } 86 | nb::block!(hasher.save((*ctx).sha384_hasher.as_mut().unwrap())).unwrap(); 87 | } else { 88 | let mut hasher = ShaDigest::restore( 89 | sha.as_mut().unwrap(), 90 | (*ctx).sha512_hasher.as_mut().unwrap(), 91 | ); 92 | while !data.is_empty() { 93 | data = nb::block!(hasher.update(&*data)).unwrap(); 94 | } 95 | nb::block!(hasher.save((*ctx).sha512_hasher.as_mut().unwrap())).unwrap(); 96 | } 97 | }); 98 | 0 99 | } 100 | 101 | #[no_mangle] 102 | pub unsafe extern "C" fn mbedtls_sha512_finish( 103 | ctx: *mut mbedtls_sha512_context, 104 | output: *mut c_uchar, 105 | ) -> c_int { 106 | let mut data: [u8; 64] = [0u8; 64]; 107 | critical_section::with(|cs| { 108 | let mut sha = SHARED_SHA.borrow_ref_mut(cs); 109 | 110 | if (*ctx).is384 == 1 { 111 | let mut hasher = ShaDigest::restore( 112 | sha.as_mut().unwrap(), 113 | (*ctx).sha384_hasher.as_mut().unwrap(), 114 | ); 115 | nb::block!(hasher.finish(&mut data)).unwrap(); 116 | nb::block!(hasher.save((*ctx).sha384_hasher.as_mut().unwrap())).unwrap(); 117 | core::ptr::copy_nonoverlapping(data.as_ptr(), output, 48); 118 | } else { 119 | let mut hasher = ShaDigest::restore( 120 | sha.as_mut().unwrap(), 121 | (*ctx).sha512_hasher.as_mut().unwrap(), 122 | ); 123 | nb::block!(hasher.finish(&mut data)).unwrap(); 124 | nb::block!(hasher.save((*ctx).sha512_hasher.as_mut().unwrap())).unwrap(); 125 | core::ptr::copy_nonoverlapping(data.as_ptr(), output, 64); 126 | } 127 | }); 128 | 0 129 | } 130 | -------------------------------------------------------------------------------- /examples/async_client.rs: -------------------------------------------------------------------------------- 1 | //! Example for a client connection to a server. 2 | //! This example connects to either `Google.com` or `certauth.cryptomix.com` (mTLS) and then prints out the result. 3 | //! 4 | //! # mTLS 5 | //! Use the mTLS feature to enable client authentication and send client certificates when doing a 6 | //! request. Note that this will connect to `certauth.cryptomix.com` instead of `google.com` 7 | #![no_std] 8 | #![no_main] 9 | #![feature(type_alias_impl_trait)] 10 | #![feature(impl_trait_in_assoc_type)] 11 | 12 | use core::ffi::CStr; 13 | 14 | #[doc(hidden)] 15 | pub use esp_hal as hal; 16 | 17 | use embassy_net::tcp::TcpSocket; 18 | use embassy_net::{Config, Ipv4Address, Runner, StackResources}; 19 | 20 | use embassy_executor::Spawner; 21 | use embassy_time::{Duration, Timer}; 22 | use esp_backtrace as _; 23 | use esp_mbedtls::{asynch::Session, Certificates, Mode, TlsVersion}; 24 | use esp_mbedtls::{Tls, X509}; 25 | use esp_println::logger::init_logger; 26 | use esp_println::{print, println}; 27 | use esp_wifi::wifi::{ 28 | ClientConfiguration, Configuration, WifiController, WifiDevice, WifiEvent, WifiState, 29 | }; 30 | use esp_wifi::{init, EspWifiController}; 31 | use hal::{clock::CpuClock, rng::Rng, timer::timg::TimerGroup}; 32 | 33 | // Patch until https://github.com/embassy-rs/static-cell/issues/16 is fixed 34 | macro_rules! mk_static { 35 | ($t:ty,$val:expr) => {{ 36 | static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); 37 | #[deny(unused_attributes)] 38 | let x = STATIC_CELL.uninit().write(($val)); 39 | x 40 | }}; 41 | } 42 | 43 | const SSID: &str = env!("SSID"); 44 | const PASSWORD: &str = env!("PASSWORD"); 45 | 46 | // Setup configuration based on mTLS feature. 47 | cfg_if::cfg_if! { 48 | if #[cfg(feature = "mtls")] { 49 | const REMOTE_IP: Ipv4Address = Ipv4Address::new(62, 210, 201, 125); // certauth.cryptomix.com 50 | const SERVERNAME: &CStr = c"certauth.cryptomix.com"; 51 | const REQUEST: &[u8] = b"GET /json/ HTTP/1.0\r\nHost: certauth.cryptomix.com\r\n\r\n"; 52 | } else { 53 | const REMOTE_IP: Ipv4Address = Ipv4Address::new(142, 250, 185, 68); // google.com 54 | const SERVERNAME: &CStr = c"www.google.com"; 55 | const REQUEST: &[u8] = b"GET /notfound HTTP/1.0\r\nHost: www.google.com\r\n\r\n"; 56 | } 57 | } 58 | 59 | esp_bootloader_esp_idf::esp_app_desc!(); 60 | 61 | #[esp_hal_embassy::main] 62 | async fn main(spawner: Spawner) -> ! { 63 | init_logger(log::LevelFilter::Info); 64 | 65 | let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); 66 | let peripherals = esp_hal::init(config); 67 | 68 | esp_alloc::heap_allocator!(size: 72 * 1024); 69 | esp_alloc::heap_allocator!(#[unsafe(link_section = ".dram2_uninit")] size: 64 * 1024); 70 | 71 | let timg0 = TimerGroup::new(peripherals.TIMG0); 72 | let mut rng = Rng::new(peripherals.RNG); 73 | 74 | let esp_wifi_ctrl = &*mk_static!( 75 | EspWifiController<'_>, 76 | init(timg0.timer0, rng.clone()).unwrap() 77 | ); 78 | 79 | let (controller, interfaces) = esp_wifi::wifi::new(&esp_wifi_ctrl, peripherals.WIFI).unwrap(); 80 | 81 | let wifi_interface = interfaces.sta; 82 | 83 | cfg_if::cfg_if! { 84 | if #[cfg(feature = "esp32")] { 85 | let timg1 = TimerGroup::new(peripherals.TIMG1); 86 | esp_hal_embassy::init(timg1.timer0); 87 | } else { 88 | use esp_hal::timer::systimer::SystemTimer; 89 | let systimer = SystemTimer::new(peripherals.SYSTIMER); 90 | esp_hal_embassy::init(systimer.alarm0); 91 | } 92 | } 93 | 94 | let config = Config::dhcpv4(Default::default()); 95 | 96 | let seed = (rng.random() as u64) << 32 | rng.random() as u64; 97 | 98 | // Init network stack 99 | let (stack, runner) = embassy_net::new( 100 | wifi_interface, 101 | config, 102 | mk_static!(StackResources<3>, StackResources::<3>::new()), 103 | seed, 104 | ); 105 | 106 | spawner.spawn(connection(controller)).ok(); 107 | spawner.spawn(net_task(runner)).ok(); 108 | 109 | let mut rx_buffer = [0; 4096]; 110 | let mut tx_buffer = [0; 4096]; 111 | 112 | loop { 113 | if stack.is_link_up() { 114 | break; 115 | } 116 | Timer::after(Duration::from_millis(500)).await; 117 | } 118 | 119 | println!("Waiting to get IP address..."); 120 | loop { 121 | if let Some(config) = stack.config_v4() { 122 | println!("Got IP: {}", config.address); 123 | break; 124 | } 125 | Timer::after(Duration::from_millis(500)).await; 126 | } 127 | 128 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); 129 | 130 | socket.set_timeout(Some(Duration::from_secs(10))); 131 | 132 | let remote_endpoint = (REMOTE_IP, 443); 133 | println!("connecting..."); 134 | let r = socket.connect(remote_endpoint).await; 135 | if let Err(e) = r { 136 | println!("connect error: {:?}", e); 137 | #[allow(clippy::empty_loop)] 138 | loop {} 139 | } 140 | 141 | cfg_if::cfg_if! { 142 | if #[cfg(feature = "mtls")] { 143 | let certificates = Certificates { 144 | ca_chain: X509::pem( 145 | concat!(include_str!("./certs/certauth.cryptomix.com.pem"), "\0").as_bytes(), 146 | ) 147 | .ok(), 148 | certificate: X509::pem(concat!(include_str!("./certs/certificate.pem"), "\0").as_bytes()) 149 | .ok(), 150 | private_key: X509::pem(concat!(include_str!("./certs/private_key.pem"), "\0").as_bytes()) 151 | .ok(), 152 | password: None, 153 | }; 154 | } else { 155 | let certificates = Certificates { 156 | ca_chain: X509::pem( 157 | concat!(include_str!("./certs/www.google.com.pem"), "\0").as_bytes(), 158 | ) 159 | .ok(), 160 | ..Default::default() 161 | }; 162 | } 163 | } 164 | 165 | let mut tls = Tls::new(peripherals.SHA) 166 | .unwrap() 167 | .with_hardware_rsa(peripherals.RSA); 168 | 169 | tls.set_debug(0); 170 | 171 | let mut session = Session::new( 172 | &mut socket, 173 | Mode::Client { 174 | servername: SERVERNAME, 175 | }, 176 | TlsVersion::Tls1_3, 177 | certificates, 178 | tls.reference(), 179 | ) 180 | .unwrap(); 181 | 182 | println!("Start tls connect"); 183 | session.connect().await.unwrap(); 184 | 185 | println!("connected!"); 186 | let mut buf = [0; 1024]; 187 | 188 | use embedded_io_async::Write; 189 | 190 | let r = session.write_all(REQUEST).await; 191 | if let Err(e) = r { 192 | println!("write error: {:?}", e); 193 | #[allow(clippy::empty_loop)] 194 | loop {} 195 | } 196 | 197 | loop { 198 | let n = match session.read(&mut buf).await { 199 | Ok(n) => n, 200 | Err(esp_mbedtls::TlsError::Eof) => { 201 | break; 202 | } 203 | Err(e) => { 204 | println!("read error: {:?}", e); 205 | break; 206 | } 207 | }; 208 | print!("{}", core::str::from_utf8(&buf[..n]).unwrap()); 209 | } 210 | println!(); 211 | println!("Done"); 212 | 213 | #[allow(clippy::empty_loop)] 214 | loop {} 215 | } 216 | 217 | #[embassy_executor::task] 218 | async fn connection(mut controller: WifiController<'static>) { 219 | println!("start connection task"); 220 | println!("Device capabilities: {:?}", controller.capabilities()); 221 | loop { 222 | if matches!(esp_wifi::wifi::wifi_state(), WifiState::StaConnected) { 223 | // wait until we're no longer connected 224 | controller.wait_for_event(WifiEvent::StaDisconnected).await; 225 | Timer::after(Duration::from_millis(5000)).await 226 | } 227 | if !matches!(controller.is_started(), Ok(true)) { 228 | let client_config = Configuration::Client(ClientConfiguration { 229 | ssid: SSID.try_into().unwrap(), 230 | password: PASSWORD.try_into().unwrap(), 231 | ..Default::default() 232 | }); 233 | controller.set_configuration(&client_config).unwrap(); 234 | println!("Starting wifi"); 235 | controller.start_async().await.unwrap(); 236 | println!("Wifi started!"); 237 | } 238 | println!("About to connect..."); 239 | 240 | match controller.connect_async().await { 241 | Ok(_) => println!("Wifi connected!"), 242 | Err(e) => { 243 | println!("Failed to connect to wifi: {e:?}"); 244 | Timer::after(Duration::from_millis(5000)).await 245 | } 246 | } 247 | } 248 | } 249 | 250 | #[embassy_executor::task] 251 | async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) { 252 | runner.run().await 253 | } 254 | -------------------------------------------------------------------------------- /examples/async_server.rs: -------------------------------------------------------------------------------- 1 | //! Example for an async server. 2 | //! Contains a basic server implementation to test mbedtls in server mode. 3 | //! 4 | //! This example uses self-signed certificate. Your browser may display an error. 5 | //! You have to enable the exception to then proceed, of if using curl, use the flag `-k`. 6 | //! 7 | //! # mTLS 8 | //! Running this example with the feature `mtls` will make the server request a client 9 | //! certificate for the connection. If you send a request, without passing 10 | //! certificates, you will get an error. Theses certificates below are generated 11 | //! to work is the configured CA: 12 | //! 13 | //! certificate.pem 14 | //! ```text 15 | #![doc = include_str!("./certs/certificate.pem")] 16 | //! ``` 17 | //! 18 | //! private_key.pem 19 | //! ```text 20 | #![doc = include_str!("./certs/private_key.pem")] 21 | //! ``` 22 | //! 23 | //! Test with curl: 24 | //! ```bash 25 | //! curl https:/// --cert certificate.pem --key private_key.pem -k 26 | //! ``` 27 | //! 28 | #![no_std] 29 | #![no_main] 30 | #![feature(type_alias_impl_trait)] 31 | #![feature(impl_trait_in_assoc_type)] 32 | 33 | #[doc(hidden)] 34 | pub use esp_hal as hal; 35 | 36 | use embassy_net::tcp::TcpSocket; 37 | use embassy_net::{Config, IpListenEndpoint, Runner, StackResources}; 38 | 39 | use embassy_executor::Spawner; 40 | use embassy_time::{Duration, Timer}; 41 | use esp_alloc as _; 42 | use esp_backtrace as _; 43 | use esp_mbedtls::{asynch::Session, Certificates, Mode, TlsVersion}; 44 | use esp_mbedtls::{Tls, TlsError, X509}; 45 | use esp_println::logger::init_logger; 46 | use esp_println::{print, println}; 47 | use esp_wifi::wifi::{ 48 | ClientConfiguration, Configuration, WifiController, WifiDevice, WifiEvent, WifiState, 49 | }; 50 | use esp_wifi::{init, EspWifiController}; 51 | use hal::{clock::CpuClock, rng::Rng, timer::timg::TimerGroup}; 52 | 53 | // Patch until https://github.com/embassy-rs/static-cell/issues/16 is fixed 54 | macro_rules! mk_static { 55 | ($t:ty,$val:expr) => {{ 56 | static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); 57 | #[deny(unused_attributes)] 58 | let x = STATIC_CELL.uninit().write(($val)); 59 | x 60 | }}; 61 | } 62 | 63 | const SSID: &str = env!("SSID"); 64 | const PASSWORD: &str = env!("PASSWORD"); 65 | 66 | esp_bootloader_esp_idf::esp_app_desc!(); 67 | 68 | #[esp_hal_embassy::main] 69 | async fn main(spawner: Spawner) -> ! { 70 | init_logger(log::LevelFilter::Info); 71 | 72 | let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); 73 | let peripherals = esp_hal::init(config); 74 | 75 | esp_alloc::heap_allocator!(size: 72 * 1024); 76 | esp_alloc::heap_allocator!(#[unsafe(link_section = ".dram2_uninit")] size: 64 * 1024); 77 | 78 | let timg0 = TimerGroup::new(peripherals.TIMG0); 79 | let mut rng = Rng::new(peripherals.RNG); 80 | 81 | let esp_wifi_ctrl = &*mk_static!( 82 | EspWifiController<'_>, 83 | init(timg0.timer0, rng.clone()).unwrap() 84 | ); 85 | 86 | let (controller, interfaces) = esp_wifi::wifi::new(&esp_wifi_ctrl, peripherals.WIFI).unwrap(); 87 | 88 | let wifi_interface = interfaces.sta; 89 | 90 | cfg_if::cfg_if! { 91 | if #[cfg(feature = "esp32")] { 92 | let timg1 = TimerGroup::new(peripherals.TIMG1); 93 | esp_hal_embassy::init(timg1.timer0); 94 | } else { 95 | use esp_hal::timer::systimer::SystemTimer; 96 | let systimer = SystemTimer::new(peripherals.SYSTIMER); 97 | esp_hal_embassy::init(systimer.alarm0); 98 | } 99 | } 100 | 101 | let config = Config::dhcpv4(Default::default()); 102 | 103 | let seed = (rng.random() as u64) << 32 | rng.random() as u64; 104 | 105 | // Init network stack 106 | let (stack, runner) = embassy_net::new( 107 | wifi_interface, 108 | config, 109 | mk_static!(StackResources<3>, StackResources::<3>::new()), 110 | seed, 111 | ); 112 | 113 | spawner.spawn(connection(controller)).ok(); 114 | spawner.spawn(net_task(runner)).ok(); 115 | 116 | let mut tls = Tls::new(peripherals.SHA) 117 | .unwrap() 118 | .with_hardware_rsa(peripherals.RSA); 119 | 120 | tls.set_debug(0); 121 | 122 | let mut rx_buffer = [0; 4096]; 123 | let mut tx_buffer = [0; 4096]; 124 | 125 | loop { 126 | if stack.is_link_up() { 127 | break; 128 | } 129 | Timer::after(Duration::from_millis(500)).await; 130 | } 131 | 132 | println!("Waiting to get IP address..."); 133 | loop { 134 | if let Some(config) = stack.config_v4() { 135 | println!("Got IP: {}", config.address); 136 | println!( 137 | "Point your browser to https://{}/", 138 | config.address.address() 139 | ); 140 | break; 141 | } 142 | Timer::after(Duration::from_millis(500)).await; 143 | } 144 | 145 | let mut socket = TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer); 146 | socket.set_timeout(Some(Duration::from_secs(10))); 147 | loop { 148 | println!("Waiting for connection..."); 149 | let r = socket 150 | .accept(IpListenEndpoint { 151 | addr: None, 152 | port: 443, 153 | }) 154 | .await; 155 | println!("Connected..."); 156 | 157 | if let Err(e) = r { 158 | println!("connect error: {:?}", e); 159 | continue; 160 | } 161 | 162 | use embedded_io_async::Write; 163 | 164 | let mut buffer = [0u8; 1024]; 165 | let mut pos = 0; 166 | let mut session = Session::new( 167 | &mut socket, 168 | Mode::Server, 169 | TlsVersion::Tls1_2, 170 | Certificates { 171 | // Provide a ca_chain if you want to enable mTLS for the server. 172 | #[cfg(feature = "mtls")] 173 | ca_chain: X509::pem(concat!(include_str!("./certs/ca_cert.pem"), "\0").as_bytes()) 174 | .ok(), 175 | // Use self-signed certificates 176 | certificate: X509::pem( 177 | concat!(include_str!("./certs/certificate.pem"), "\0").as_bytes(), 178 | ) 179 | .ok(), 180 | private_key: X509::pem( 181 | concat!(include_str!("./certs/private_key.pem"), "\0").as_bytes(), 182 | ) 183 | .ok(), 184 | ..Default::default() 185 | }, 186 | tls.reference(), 187 | ) 188 | .unwrap(); 189 | 190 | println!("Start tls connect"); 191 | match session.connect().await { 192 | Ok(()) => { 193 | log::info!("Got session"); 194 | loop { 195 | match session.read(&mut buffer).await { 196 | Ok(0) => { 197 | println!("read EOF"); 198 | break; 199 | } 200 | Ok(len) => { 201 | let to_print = 202 | unsafe { core::str::from_utf8_unchecked(&buffer[..(pos + len)]) }; 203 | 204 | if to_print.contains("\r\n\r\n") { 205 | print!("{}", to_print); 206 | println!(); 207 | break; 208 | } 209 | 210 | pos += len; 211 | } 212 | Err(e) => { 213 | println!("read error: {:?}", e); 214 | break; 215 | } 216 | }; 217 | } 218 | 219 | let r = session 220 | .write_all( 221 | b"HTTP/1.0 200 OK\r\n\r\n\ 222 | \ 223 | \ 224 |

Hello Rust! Hello esp-mbedtls!

\ 225 | \ 226 | \r\n\ 227 | ", 228 | ) 229 | .await; 230 | if let Err(e) = r { 231 | println!("write error: {:?}", e); 232 | } 233 | 234 | Timer::after(Duration::from_millis(1000)).await; 235 | } 236 | Err(TlsError::NoClientCertificate) => { 237 | println!("Error: No client certificates given. Please provide client certificates during your request"); 238 | } 239 | Err(TlsError::MbedTlsError(-30592)) => { 240 | println!("Fatal message: Please enable the exception for a self-signed certificate in your browser"); 241 | } 242 | Err(error) => { 243 | panic!("{:?}", error); 244 | } 245 | } 246 | drop(session); 247 | println!("Closing socket"); 248 | socket.close(); 249 | Timer::after(Duration::from_millis(1000)).await; 250 | 251 | socket.abort(); 252 | } 253 | } 254 | 255 | #[embassy_executor::task] 256 | async fn connection(mut controller: WifiController<'static>) { 257 | println!("start connection task"); 258 | println!("Device capabilities: {:?}", controller.capabilities()); 259 | loop { 260 | if matches!(esp_wifi::wifi::wifi_state(), WifiState::StaConnected) { 261 | // wait until we're no longer connected 262 | controller.wait_for_event(WifiEvent::StaDisconnected).await; 263 | Timer::after(Duration::from_millis(5000)).await 264 | } 265 | if !matches!(controller.is_started(), Ok(true)) { 266 | let client_config = Configuration::Client(ClientConfiguration { 267 | ssid: SSID.try_into().unwrap(), 268 | password: PASSWORD.try_into().unwrap(), 269 | ..Default::default() 270 | }); 271 | controller.set_configuration(&client_config).unwrap(); 272 | println!("Starting wifi"); 273 | controller.start_async().await.unwrap(); 274 | println!("Wifi started!"); 275 | } 276 | println!("About to connect..."); 277 | 278 | match controller.connect_async().await { 279 | Ok(_) => println!("Wifi connected!"), 280 | Err(e) => { 281 | println!("Failed to connect to wifi: {e:?}"); 282 | Timer::after(Duration::from_millis(5000)).await 283 | } 284 | } 285 | } 286 | } 287 | 288 | #[embassy_executor::task] 289 | async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) { 290 | runner.run().await 291 | } 292 | -------------------------------------------------------------------------------- /examples/certs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esp-rs/esp-mbedtls/35e8ccd5999cf0c831c9b825491fd68581d108c2/examples/certs/.gitkeep -------------------------------------------------------------------------------- /examples/certs/ca_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDSzCCAjOgAwIBAgIUAtFs1cYQXPzsSiAx9eNPjZ6WwpUwDQYJKoZIhvcNAQEL 3 | BQAwNTEaMBgGA1UEAwwRZXNwLW1iZWR0bHMubG9jYWwxFzAVBgNVBAoMDkNBIENl 4 | cnRpZmljYXRlMB4XDTI1MDIyODE4NTQ1OFoXDTI2MDIyODE4NTQ1OFowNTEaMBgG 5 | A1UEAwwRZXNwLW1iZWR0bHMubG9jYWwxFzAVBgNVBAoMDkNBIENlcnRpZmljYXRl 6 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmZ/fLZ7vJy0MJVNNpAc2 7 | TExin7zmSuVMKJlmqkOXpZs34AycQ3ew2kSBPH53ikna/qAKUnXJz2P/21XzBNb0 8 | aeixTqT0ABG+RG6g7gpD//XiEzjMzrl7dlWKOXCA5/nXQB43s01HPT2838lVsbJu 9 | J/y5bUHyPTuZoJEXRDuetuIr6Pw8fGr6ZraHSdJ2FWjndDcyluFAqONwa+HBJHd8 10 | QuKyb7eK0gi3EhOl356630J0dQKXEAsQdmgYRirRK3YwmqKtHpWqmau2WI6iaM+4 11 | alGIZSnsIqtE1Dp09Q64v6CDvhPF98uCuuBtpDVGIyY9WVUeDqz6WJ5vN9GGVtw7 12 | KQIDAQABo1MwUTAdBgNVHQ4EFgQUJOks4RmsqH87xDke2I2lgONnh44wHwYDVR0j 13 | BBgwFoAUJOks4RmsqH87xDke2I2lgONnh44wDwYDVR0TAQH/BAUwAwEB/zANBgkq 14 | hkiG9w0BAQsFAAOCAQEAAUsAqMDVMR3Vxen8QipBw97B6PnwoDwCOC4qCW2cbQ65 15 | RL+F53CuOPQrKDxztzk6z/DkrxkyaTRnpJkjtnpFL0+Jg5lX5LvMMckaLT4+eTXG 16 | IpN1p9QmH6paivdampMj3ahTyW1RtKQxEj2tArpy7mSGz4eopCALOGZw6xD717vQ 17 | gaOmyky24k+ZTXlGNq1pAppv5WT/CP9kj/QLfXjjSMDePaBnZFPoijuQNWWp0AP7 18 | h2E4jlPd2YLYdmxyuDCf7MYrUtpOmtzRcLa6TdEqtomqIrHkKyNO6fG+F4MWQgQK 19 | oyB3qwwIfRvoZrJ8r9IKFMtGxowVD/PMWM0hlpqWHQ== 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /examples/certs/ca_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCZn98tnu8nLQwl 3 | U02kBzZMTGKfvOZK5UwomWaqQ5elmzfgDJxDd7DaRIE8fneKSdr+oApSdcnPY//b 4 | VfME1vRp6LFOpPQAEb5EbqDuCkP/9eITOMzOuXt2VYo5cIDn+ddAHjezTUc9Pbzf 5 | yVWxsm4n/LltQfI9O5mgkRdEO5624ivo/Dx8avpmtodJ0nYVaOd0NzKW4UCo43Br 6 | 4cEkd3xC4rJvt4rSCLcSE6XfnrrfQnR1ApcQCxB2aBhGKtErdjCaoq0elaqZq7ZY 7 | jqJoz7hqUYhlKewiq0TUOnT1Dri/oIO+E8X3y4K64G2kNUYjJj1ZVR4OrPpYnm83 8 | 0YZW3DspAgMBAAECggEAFO4F0TiX0xHNV5F9oLUV1ffLMQGiq34JbfeWV+idEsQu 9 | rODy8jMunlIafGQrg6Tzx+CEf38KN23jmB2h3h0uD/bSn0kUcCT6s+aRmNS/tnHo 10 | st84cgqtsi3Nxu0XtuMgSx1Cz/Qdmk+cua17thm97cc9+Q90whhqYgiab6KiyT4Z 11 | m9sZgN8emjkYI57NY+b4sSE2owgbn5Ow4dRhAP9NriC/Pb9DtrN+iOWZYFGgSUjv 12 | hobMZBj48ChM7krT3gxJVzGIKU/7cVB20Llq7hBLn+f9dhkTP/FCFfT9svY0OHd/ 13 | jD7DJJzjpyGUfZiTC1itJzt/3ncmU0xpjujx96FC7QKBgQDJU763LI9X2YqyD7b9 14 | 5fEpZ4R9y0/NrOlremYZB7dq+F8EzTju5oExYmHwMMXhbPXEdvPCOpvaOMJURP/K 15 | vP0IVYg2M8D5dIGPCqeUu8+DC6PAu2E2cb2y0ZPV1XJECpyRl4GNIcwIVHpE4EhZ 16 | ecJsGNM74OIC/skv/1s8iVDZTQKBgQDDV9d2MEevGYbMBkONRHO38I9NwA6GGH0Q 17 | MGb0GjCP3PEBk+LlSow13GryrThLJxo1rmKVPlUvMsCxWA58PSPBZ5PHCXKis1sp 18 | 4vG8fGr0NyUSOlgklaPGxiFlM44OvyFRwXeCt/a2HWUaIXT85Fir380qI1PFUEdS 19 | AWQtuz7bTQKBgEhsr/cFOKvJvnM/4/yCc7cJXkhCk3rR8UaQyZnHhNwebVA0435N 20 | vbweQE0/vm/R2rfKcvY0T0y5jm7yQ3KTehM9cbrN82XJ27Gxi4ed6JCj50y2G8qS 21 | MEPb0Orj1i9UAe7+KcSzm8qDWVjdtik5/A8W/yZTR/r73TQ/EHs+iq8hAoGAATK+ 22 | vZjaN7a+Xu4C6BDtbMlq950f+a6YxcqmNwUaGyfNyqavk5x7c7EgbtClMcDRplal 23 | gCjbuOhkyjGyFQ0C9SK/g08Jhvn2qzEbLn7M4SadcZkuBTttv8BjYA2K54hAmhHH 24 | u+OI/eD8R8bAwvRbnuJGjeWdk+5EIbqkdKtbXVkCgYAFnotzrjwD2kTyWZikKIzz 25 | fqHBGfTwIX7PqKK4XXOs/2A6Uhi255mbFcYolQoGnsHqzd1OXAPCnKCfy0HkEuKh 26 | 6xgAL10X6Ew1b4KnNRYnuaRB59cVfg3cyWDaxK9bg36DmlxRijJwe4pbNyJbhqIP 27 | bPu9SGuz598NRff62GGTgg== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /examples/certs/certauth.cryptomix.com.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIE/TCCA+WgAwIBAgISA2jafRaGFthCqW08pWDEXR57MA0GCSqGSIb3DQEBCwUA 3 | MDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQwwCgYDVQQD 4 | EwNSMTEwHhcNMjUwMjI0MTQyMTAxWhcNMjUwNTI1MTQyMTAwWjAhMR8wHQYDVQQD 5 | ExZjZXJ0YXV0aC5jcnlwdG9taXguY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A 6 | MIIBCgKCAQEAwH3Xiay7k16647cEJ9LLHQcNqHw47h7XcKbxtMwfvbVxrtZSafJx 7 | K1ptsZJ7sKJbAB+poSE2vEv96niD4SQ+cpIWOPOUi5J6RJKJoqDkqUmkqCPZ97y/ 8 | APlagcTzzS/4FCqdl1Fnwq022840zDz9ujNSVNAbxMTdgy+ZWXlvU2BjTZImh9bi 9 | QPkCpypiI3xA39uPZxS8O4nPUADH2mT1RCuJfVSyFlwFqmRxRSDap+s/5jQSk9eK 10 | /JPMJ/tyTnvDffjPVMFu1sP6hCUVIM5eck+NI+9CG3UUujamd0+bNuSfKIYG0QAZ 11 | viXm+x/3aWDVIJFpn6YpRgZtw9qrhixlmQIDAQABo4ICGzCCAhcwDgYDVR0PAQH/ 12 | BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8E 13 | AjAAMB0GA1UdDgQWBBRd2goaTTmFEV2jTBBGc00XVrNeRDAfBgNVHSMEGDAWgBTF 14 | z0ak6vTDwHpslcQtsF6SLybjuTBXBggrBgEFBQcBAQRLMEkwIgYIKwYBBQUHMAGG 15 | Fmh0dHA6Ly9yMTEuby5sZW5jci5vcmcwIwYIKwYBBQUHMAKGF2h0dHA6Ly9yMTEu 16 | aS5sZW5jci5vcmcvMCEGA1UdEQQaMBiCFmNlcnRhdXRoLmNyeXB0b21peC5jb20w 17 | EwYDVR0gBAwwCjAIBgZngQwBAgEwggEFBgorBgEEAdZ5AgQCBIH2BIHzAPEAdwCi 18 | 4wrkRe+9rZt+OO1HZ3dT14JbhJTXK14bLMS5UKRH5wAAAZU4ir1eAAAEAwBIMEYC 19 | IQChesHawemZY3ts8JbPphLdcYMat+zg+TyRw7Pd5xu2WgIhAOHDfTjNo6EBAXhQ 20 | OBJQbSLD8tJZmY/sDOVHJCwEbGQlAHYAzPsPaoVxCWX+lZtTzumyfCLphVwNl422 21 | qX5UwP5MDbAAAAGVOIq97QAABAMARzBFAiB13Kes1ACtothXEKs8+cNcNJBuyNgE 22 | DxyEFANk5MfAQgIhAKhkPibYPbpLQ75S1Agz9s3D1t8Jx8Ff/zUbYTJTKOJPMA0G 23 | CSqGSIb3DQEBCwUAA4IBAQCUuQZ3qhOmUkRJs8axLjlxwVCi9ESGIwOh+sXn6sxn 24 | 7F/3oEpOjqhVpzlAGMSYf2J3M1Rk7gkzepAr9CZDKIZPE181A55UiV76/yOfEaif 25 | 1iwUxw+4ScXUTZlD3nab+LekVQoPwHmrQAVzoKyLDiNywx10dlDNSYsaV+6VzWms 26 | Z/Mx6Wlu52jPsyuzBetTrbmH1qeo9ZkXFNciMZxDOsH3DGLHmJwQccSmDPg/qBKX 27 | qjVS1fmtGVcZRtEH5ZDZQAYF5JJ77Q9c9AWxoZ6LMOX8u5+5GypD068z4lXL4D6r 28 | s6SThW4N5jMY4hGVcgj6vBMSNwJ+MT4+CtdgfkA10KKi 29 | -----END CERTIFICATE----- 30 | -----BEGIN CERTIFICATE----- 31 | MIIFBjCCAu6gAwIBAgIRAIp9PhPWLzDvI4a9KQdrNPgwDQYJKoZIhvcNAQELBQAw 32 | TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh 33 | cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw 34 | WhcNMjcwMzEyMjM1OTU5WjAzMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg 35 | RW5jcnlwdDEMMAoGA1UEAxMDUjExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB 36 | CgKCAQEAuoe8XBsAOcvKCs3UZxD5ATylTqVhyybKUvsVAbe5KPUoHu0nsyQYOWcJ 37 | DAjs4DqwO3cOvfPlOVRBDE6uQdaZdN5R2+97/1i9qLcT9t4x1fJyyXJqC4N0lZxG 38 | AGQUmfOx2SLZzaiSqhwmej/+71gFewiVgdtxD4774zEJuwm+UE1fj5F2PVqdnoPy 39 | 6cRms+EGZkNIGIBloDcYmpuEMpexsr3E+BUAnSeI++JjF5ZsmydnS8TbKF5pwnnw 40 | SVzgJFDhxLyhBax7QG0AtMJBP6dYuC/FXJuluwme8f7rsIU5/agK70XEeOtlKsLP 41 | Xzze41xNG/cLJyuqC0J3U095ah2H2QIDAQABo4H4MIH1MA4GA1UdDwEB/wQEAwIB 42 | hjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwEgYDVR0TAQH/BAgwBgEB 43 | /wIBADAdBgNVHQ4EFgQUxc9GpOr0w8B6bJXELbBeki8m47kwHwYDVR0jBBgwFoAU 44 | ebRZ5nu25eQBc4AIiMgaWPbpm24wMgYIKwYBBQUHAQEEJjAkMCIGCCsGAQUFBzAC 45 | hhZodHRwOi8veDEuaS5sZW5jci5vcmcvMBMGA1UdIAQMMAowCAYGZ4EMAQIBMCcG 46 | A1UdHwQgMB4wHKAaoBiGFmh0dHA6Ly94MS5jLmxlbmNyLm9yZy8wDQYJKoZIhvcN 47 | AQELBQADggIBAE7iiV0KAxyQOND1H/lxXPjDj7I3iHpvsCUf7b632IYGjukJhM1y 48 | v4Hz/MrPU0jtvfZpQtSlET41yBOykh0FX+ou1Nj4ScOt9ZmWnO8m2OG0JAtIIE38 49 | 01S0qcYhyOE2G/93ZCkXufBL713qzXnQv5C/viOykNpKqUgxdKlEC+Hi9i2DcaR1 50 | e9KUwQUZRhy5j/PEdEglKg3l9dtD4tuTm7kZtB8v32oOjzHTYw+7KdzdZiw/sBtn 51 | UfhBPORNuay4pJxmY/WrhSMdzFO2q3Gu3MUBcdo27goYKjL9CTF8j/Zz55yctUoV 52 | aneCWs/ajUX+HypkBTA+c8LGDLnWO2NKq0YD/pnARkAnYGPfUDoHR9gVSp/qRx+Z 53 | WghiDLZsMwhN1zjtSC0uBWiugF3vTNzYIEFfaPG7Ws3jDrAMMYebQ95JQ+HIBD/R 54 | PBuHRTBpqKlyDnkSHDHYPiNX3adPoPAcgdF3H2/W0rmoswMWgTlLn1Wu0mrks7/q 55 | pdWfS6PJ1jty80r2VKsM/Dj3YIDfbjXKdaFU5C+8bhfJGqU3taKauuz0wHVGT3eo 56 | 6FlWkWYtbt4pgdamlwVeZEW+LM7qZEJEsMNPrfC03APKmZsJgpWCDWOKZvkZcvjV 57 | uYkQ4omYCTX5ohy+knMjdOmdH9c7SpqEWBDC86fiNex+O0XOMEZSa8DA 58 | -----END CERTIFICATE----- 59 | -------------------------------------------------------------------------------- /examples/certs/certificate.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDITCCAgmgAwIBAgIUXEA0lvHpsXpablgTemrCN1mHXPkwDQYJKoZIhvcNAQEL 3 | BQAwNTEaMBgGA1UEAwwRZXNwLW1iZWR0bHMubG9jYWwxFzAVBgNVBAoMDkNBIENl 4 | cnRpZmljYXRlMB4XDTI1MDIyODE4NTQ1OVoXDTI2MDIyODE4NTQ1OVowHDEaMBgG 5 | A1UEAwwRZXNwLW1iZWR0bHMubG9jYWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw 6 | ggEKAoIBAQDEIXzky77owhFwwTB6cC9U0kJMYOA7che9UXDrCztOhDNpLtPZTN4l 7 | kA/MvcIJOFWYvSSV9fm4SZLswyO4yGwTcClY1xP7R2gP/KVpvTBBJKj0kaVWW6MH 8 | SL/31SFjsEAgP1tTXNabceNYpD7LKHKggl2kFKGzwy34GWy4XBmga0g6WeeB9NvC 9 | pX4Jx1q20yPGF/P5fpZCE6cRZU9tdbOSbxaa4ahfx3I+imXfKzq5n5w4X89HVtJl 10 | 9l9jDVnxyvxTsLZ1Vs+kQ97E8BJ/Mw6o7zg2rS/yd27KxvEzUrDRN0DFFC07+q2W 11 | rau0/lWlCzivb7mqMu/xsnjO3e3/kIWPAgMBAAGjQjBAMB0GA1UdDgQWBBQII11i 12 | KFCw6jjW1XwroPtLS1lDYDAfBgNVHSMEGDAWgBQk6SzhGayofzvEOR7YjaWA42eH 13 | jjANBgkqhkiG9w0BAQsFAAOCAQEAT+VxRdg/SPa9zQntTAkWqRaRV2dM2yriBOYn 14 | TbnKhCCanXbNWYJwp5yBGUcZO68HfXM7hIlrqHUKDwqz9BNAKRH3fTtSABR5cJqv 15 | Ye+8be4uEwssLU8uvUuFI4rzebeRiJuE1XHqpV6ZUY7MY7jthoRF6GCb+flHxm6m 16 | wL2yeOpPUTFcYiNJEnPpNhJ3np02BvQ6tryKrTCrXJMd06FoDxj03PsH0wACWitV 17 | sms0sBq+0rGtF+NS6qHjlUjfmEU8D11NHQ+zoaHjPDwm+WJQwXtQkFhtqVmvsfAY 18 | v9Gi9oKnKmA04DEa7SnGErTjK0wR1I5JrsSWyxJTXTLhf1vOag== 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /examples/certs/private_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDEIXzky77owhFw 3 | wTB6cC9U0kJMYOA7che9UXDrCztOhDNpLtPZTN4lkA/MvcIJOFWYvSSV9fm4SZLs 4 | wyO4yGwTcClY1xP7R2gP/KVpvTBBJKj0kaVWW6MHSL/31SFjsEAgP1tTXNabceNY 5 | pD7LKHKggl2kFKGzwy34GWy4XBmga0g6WeeB9NvCpX4Jx1q20yPGF/P5fpZCE6cR 6 | ZU9tdbOSbxaa4ahfx3I+imXfKzq5n5w4X89HVtJl9l9jDVnxyvxTsLZ1Vs+kQ97E 7 | 8BJ/Mw6o7zg2rS/yd27KxvEzUrDRN0DFFC07+q2Wrau0/lWlCzivb7mqMu/xsnjO 8 | 3e3/kIWPAgMBAAECggEATrpuitzqZj44h/1Ue2F67l50NHqSp+oVc240mHTquorA 9 | pFEiwtBjP8rDPNlTASZ23ZfXDsctFXebHaT7Otpg37CfOEUlhTFVqU0uDPLfYtbX 10 | Z0zrhG3GVE80l8Qa4gxGwWsNOrpCfyVJMDTF7ADxelK6SfnqKuGHG1cBWEPIGaci 11 | IGXKNfRWCBAVDJTdh+VlODqtc8u3Wq7lpjAhjO6hIgX/w2ILoJsK9W8yENTQnHEE 12 | 2xsiz2Z6uGsFJd8Iv084o9KnPJaAJgerQQm3pEtplsigWTlJ1nzEwycahgFCyHwq 13 | Ce5yHaT3WL7VxdjiWRnNomA5/qylTWJX7OBHZTi5WQKBgQD2lSsIFZKWyzVhdc7M 14 | bm0qEpFjjpZeVqdEqaLv1NS+86cHemFTi593f3S+hbN+aDpx5CNSLLGI0dgeHoxU 15 | kUNmUib2V3NqlF2lcRiUgO3fLkQeabqfD9fi4uM3MlNYeLweFW3AK8mHdX3SV2kf 16 | vVyTbbrMhSsbn/1VXfQKmcr6IwKBgQDLnw2f9+e7z3h4PWwJEvR9CbJlk3ce0Z+W 17 | RaTGBFoXihJ04gdNv26LhfhqieQ+lnOkfnNVt2xKUbR2BZH5/3XxlhypnaIIU+6o 18 | fYzYy6DYYfBsx8ikpFFfeUQZKiwmW9G/jY6LimftHfbPJp1Gn5nzIlWk4aAumvzB 19 | 5xGH3snPpQKBgQDrnXF20hY2HIovTECEOuf4kbF27eJk1mwSQf29KSL4Kx1pGdkx 20 | 2XJQ3usQufTfTny6IwJVHPuu/sSBUzNIA13hwZIVRU61gntRAJY6IFArN6xDW0fF 21 | gYAJ/j6amW3mVcd6/4LVY4G3+950RK3gdDKndOxPTNf6F5AcKCBumLHI/QKBgQCJ 22 | OB2RcRoMeetAdHwKvWhfnxpG05LSBQgb18EL5MDl3hlEBVJQtbIEensHKPfUqcUy 23 | 1DhbSmnCx77qTiSqqdpMvRGByIX6QL2zdDBnpQo26AGC/TucoFNqGKmon7/y9auq 24 | //VQ2ivhInFB9k7E2ieALuIyZA5zeeTdsx8gRiYQNQKBgQCodagLsk4Y+bIOUajN 25 | LHt5gdKDn7512u2fe3CXxRnUO8Dpzz7+eCkheads0uzbD7BMUa8vgIbLgTV49uWE 26 | rBvndcfebphTSno+17KDTBcihQOEaXjaUe3yCDc4oRPSWxRcuZGpLHDnJT8ZP/Hi 27 | vjeTo95A5B5sv8yVYLU/VUb8iw== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /examples/certs/www.google.com.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDlTCCAzugAwIBAgIQQ+uMfI3Mj0QQZFYhRtPwJjAKBggqhkjOPQQDAjA7MQsw 3 | CQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZpY2VzMQwwCgYD 4 | VQQDEwNXRTIwHhcNMjUwMTA2MDgzODAzWhcNMjUwMzMxMDgzODAyWjAZMRcwFQYD 5 | VQQDEw53d3cuZ29vZ2xlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGaA 6 | bsttKtyBEpY5OH8mwOEPGfZn9qjPrsF79lXnkn5Xc/0koWbRIuzYutY9Iz5bdwNs 7 | AhhmpAVpmpUfBciMAUajggJBMIICPTAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAww 8 | CgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUhyYGv3XVRCnACG/Z 9 | UR4yKJRGJkAwHwYDVR0jBBgwFoAUdb7Ed66J9kQ3fc+xaB8dGuvcNFkwWAYIKwYB 10 | BQUHAQEETDBKMCEGCCsGAQUFBzABhhVodHRwOi8vby5wa2kuZ29vZy93ZTIwJQYI 11 | KwYBBQUHMAKGGWh0dHA6Ly9pLnBraS5nb29nL3dlMi5jcnQwGQYDVR0RBBIwEIIO 12 | d3d3Lmdvb2dsZS5jb20wEwYDVR0gBAwwCjAIBgZngQwBAgEwNgYDVR0fBC8wLTAr 13 | oCmgJ4YlaHR0cDovL2MucGtpLmdvb2cvd2UyL2RUTTMtMGhwV2ZFLmNybDCCAQQG 14 | CisGAQQB1nkCBAIEgfUEgfIA8AB2AE51oydcmhDDOFts1N8/Uusd8OCOG41pwLH6 15 | ZLFimjnfAAABlDr6h4gAAAQDAEcwRQIgVFIvSZ/WmB5uwiif9RjXPmncrwFccud/ 16 | qvIpA/WKUP0CIQCJxO0atfloQtvR09p+t4XOTn+IgUI0otk53S+3oprTdgB2AN6F 17 | gddQJHxrzcuvVjfF54HGTORu1hdjn480pybJ4r03AAABlDr6h5MAAAQDAEcwRQIh 18 | AJeYHbiFxmordAaffqDqP10NoytFNteByJ8AMnU6/UFVAiBapJZqAScCu+7oJzRA 19 | GNfc5SMo0T/viKyVFXHwlhBM6zAKBggqhkjOPQQDAgNIADBFAiEA6kEUiiMFH3Al 20 | 0DbV9JHwmkDzd+a1y7IhysqL8rBsoWgCIEmmO+m0vx5BqgXdUH5Kk05tYee4BNBV 21 | /ESAo2fEokY7 22 | -----END CERTIFICATE----- 23 | -----BEGIN CERTIFICATE----- 24 | MIICnjCCAiWgAwIBAgIQf/Mta0CdFdWWWwWHOnxy4DAKBggqhkjOPQQDAzBHMQsw 25 | CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU 26 | MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMjMxMjEzMDkwMDAwWhcNMjkwMjIwMTQw 27 | MDAwWjA7MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZp 28 | Y2VzMQwwCgYDVQQDEwNXRTIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ1fh/y 29 | FO2QfeGeKjRDhsHVlugncN+eBMupyoZ5CwhNRorCdKS72b/u/SPXOPNL71QX4b7n 30 | ylUlqAwwrC1dTqFRo4H+MIH7MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggr 31 | BgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU 32 | db7Ed66J9kQ3fc+xaB8dGuvcNFkwHwYDVR0jBBgwFoAUgEzW63T/STaj1dj8tT7F 33 | avCUHYwwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzAChhhodHRwOi8vaS5wa2ku 34 | Z29vZy9yNC5jcnQwKwYDVR0fBCQwIjAgoB6gHIYaaHR0cDovL2MucGtpLmdvb2cv 35 | ci9yNC5jcmwwEwYDVR0gBAwwCjAIBgZngQwBAgEwCgYIKoZIzj0EAwMDZwAwZAIw 36 | C724NlXINaPS2X05c9P394K4CdGBb+VkRdveqsAORRKPrJPoH2DsLn5ELCKUkeys 37 | AjAv3wyQdkwtaWHVT/2YmBiE2zTqmOybzYhi/9Jl5TNqmgztI0k4L1G/kdASosk4 38 | ONo= 39 | -----END CERTIFICATE----- 40 | -----BEGIN CERTIFICATE----- 41 | MIIDejCCAmKgAwIBAgIQf+UwvzMTQ77dghYQST2KGzANBgkqhkiG9w0BAQsFADBX 42 | MQswCQYDVQQGEwJCRTEZMBcGA1UEChMQR2xvYmFsU2lnbiBudi1zYTEQMA4GA1UE 43 | CxMHUm9vdCBDQTEbMBkGA1UEAxMSR2xvYmFsU2lnbiBSb290IENBMB4XDTIzMTEx 44 | NTAzNDMyMVoXDTI4MDEyODAwMDA0MlowRzELMAkGA1UEBhMCVVMxIjAgBgNVBAoT 45 | GUdvb2dsZSBUcnVzdCBTZXJ2aWNlcyBMTEMxFDASBgNVBAMTC0dUUyBSb290IFI0 46 | MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE83Rzp2iLYK5DuDXFgTB7S0md+8Fhzube 47 | Rr1r1WEYNa5A3XP3iZEwWus87oV8okB2O6nGuEfYKueSkWpz6bFyOZ8pn6KY019e 48 | WIZlD6GEZQbR3IvJx3PIjGov5cSr0R2Ko4H/MIH8MA4GA1UdDwEB/wQEAwIBhjAd 49 | BgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAd 50 | BgNVHQ4EFgQUgEzW63T/STaj1dj8tT7FavCUHYwwHwYDVR0jBBgwFoAUYHtmGkUN 51 | l8qJUC99BM00qP/8/UswNgYIKwYBBQUHAQEEKjAoMCYGCCsGAQUFBzAChhpodHRw 52 | Oi8vaS5wa2kuZ29vZy9nc3IxLmNydDAtBgNVHR8EJjAkMCKgIKAehhxodHRwOi8v 53 | Yy5wa2kuZ29vZy9yL2dzcjEuY3JsMBMGA1UdIAQMMAowCAYGZ4EMAQIBMA0GCSqG 54 | SIb3DQEBCwUAA4IBAQAYQrsPBtYDh5bjP2OBDwmkoWhIDDkic574y04tfzHpn+cJ 55 | odI2D4SseesQ6bDrarZ7C30ddLibZatoKiws3UL9xnELz4ct92vID24FfVbiI1hY 56 | +SW6FoVHkNeWIP0GCbaM4C6uVdF5dTUsMVs/ZbzNnIdCp5Gxmx5ejvEau8otR/Cs 57 | kGN+hr/W5GvT1tMBjgWKZ1i4//emhA1JG1BbPzoLJQvyEotc03lXjTaCzv8mEbep 58 | 8RqZ7a2CPsgRbuvTPBwcOMBBmuFeU88+FSBX6+7iP0il8b4Z0QFqIwwMHfs/L6K1 59 | vepuoxtGzi4CZ68zJpiq1UvSqTbFJjtbD4seiMHl 60 | -----END CERTIFICATE----- 61 | -------------------------------------------------------------------------------- /examples/crypto_self_test.rs: -------------------------------------------------------------------------------- 1 | //! Run crypto self tests to ensure their functionnality 2 | #![no_std] 3 | #![no_main] 4 | 5 | #[doc(hidden)] 6 | pub use esp_hal as hal; 7 | 8 | use esp_alloc as _; 9 | use esp_backtrace as _; 10 | use esp_mbedtls::Tls; 11 | use esp_println::{logger::init_logger, println}; 12 | 13 | /// Only used for ROM functions 14 | #[allow(unused_imports)] 15 | use esp_wifi::init; 16 | use hal::{clock::CpuClock, main, rng::Rng, timer::timg::TimerGroup}; 17 | 18 | pub fn cycles() -> u64 { 19 | #[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))] 20 | { 21 | esp_hal::xtensa_lx::timer::get_cycle_count() as u64 22 | } 23 | 24 | #[cfg(not(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3")))] 25 | { 26 | use esp_hal::timer::systimer::{SystemTimer, Unit}; 27 | SystemTimer::unit_value(Unit::Unit0) 28 | } 29 | } 30 | 31 | esp_bootloader_esp_idf::esp_app_desc!(); 32 | 33 | #[main] 34 | fn main() -> ! { 35 | init_logger(log::LevelFilter::Info); 36 | 37 | // Init ESP-WIFI heap for malloc 38 | let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); 39 | let peripherals = esp_hal::init(config); 40 | 41 | esp_alloc::heap_allocator!(size: 115 * 1024); 42 | 43 | let timg0 = TimerGroup::new(peripherals.TIMG0); 44 | 45 | let _init = init(timg0.timer0, Rng::new(peripherals.RNG)).unwrap(); 46 | 47 | let mut tls = Tls::new(peripherals.SHA) 48 | .unwrap() 49 | .with_hardware_rsa(peripherals.RSA); 50 | 51 | tls.set_debug(1); 52 | 53 | // | Hash Algorithm | Software (cycles) | Hardware (cycles) | Hardware Faster (x times) | 54 | // |----------------|-------------------|-------------------|---------------------------| 55 | // | SHA-1 | 3,390,785 | 896,889 | 3.78 | 56 | // | SHA-224 | 8,251,799 | 898,344 | 9.19 | 57 | // | SHA-256 | 8,237,932 | 901,709 | 9.14 | 58 | // | SHA-384 | 13,605,806 | 799,532 | 17.02 | 59 | // | SHA-512 | 13,588,104 | 801,556 | 16.95 | 60 | 61 | for test in enumset::EnumSet::all() { 62 | println!("Testing {:?}", test); 63 | 64 | let before = cycles(); 65 | 66 | tls.self_test(test, true); 67 | 68 | let after = cycles(); 69 | 70 | println!("Took {:?} cycles", after.checked_sub(before)); 71 | } 72 | 73 | // HW Crypto: 74 | // Testing RSA 75 | // INFO - RSA key validation: 76 | // INFO - passed 77 | // PKCS#1 encryption : 78 | // INFO - passed 79 | // PKCS#1 decryption : 80 | // INFO - passed 81 | // INFO - PKCS#1 data sign : 82 | // INFO - passed 83 | // PKCS#1 sig. verify: 84 | // INFO - passed 85 | // INFO - 10 86 | // INFO - pre_cal 16377170 87 | // INFO - MPI test #1 (mul_mpi): 88 | // INFO - passed 89 | // INFO - MPI test #2 (div_mpi): 90 | // INFO - passed 91 | // INFO - MPI test #3 (exp_mod): 92 | // INFO - passed 93 | // INFO - MPI test #4 (inv_mod): 94 | // INFO - passed 95 | // INFO - MPI test #5 (simple gcd): 96 | // INFO - passed 97 | // INFO - 10 98 | // INFO - post_cal 17338357 99 | // Took 961187 cycles 100 | // Done 101 | 102 | // SW Crypto: 103 | // Testing RSA 104 | // INFO - RSA key validation: 105 | // INFO - passed 106 | // PKCS#1 encryption : 107 | // INFO - passed 108 | // PKCS#1 decryption : 109 | // INFO - passed 110 | // INFO - PKCS#1 data sign : 111 | // INFO - passed 112 | // PKCS#1 sig. verify: 113 | // INFO - passed 114 | // INFO - 10 115 | // INFO - pre_cal 19067376 116 | // INFO - MPI test #1 (mul_mpi): 117 | // INFO - passed 118 | // INFO - MPI test #2 (div_mpi): 119 | // INFO - passed 120 | // INFO - MPI test #3 (exp_mod): 121 | // INFO - passed 122 | // INFO - MPI test #4 (inv_mod): 123 | // INFO - passed 124 | // INFO - MPI test #5 (simple gcd): 125 | // INFO - passed 126 | // INFO - 10 127 | // INFO - post_cal 20393146 128 | // Took 1325770 cycles 129 | // Done 130 | 131 | println!("Done"); 132 | 133 | #[allow(clippy::empty_loop)] 134 | loop {} 135 | } 136 | -------------------------------------------------------------------------------- /examples/crypto_self_test_std.rs: -------------------------------------------------------------------------------- 1 | //! Run crypto self tests to ensure their functionnality 2 | 3 | use esp_mbedtls::Tls; 4 | 5 | fn cycles() -> std::time::Instant { 6 | std::time::Instant::now() 7 | } 8 | 9 | fn main() { 10 | let mut tls = Tls::new().unwrap(); 11 | 12 | tls.set_debug(1); 13 | 14 | // | Hash Algorithm | Software (cycles) | Hardware (cycles) | Hardware Faster (x times) | 15 | // |----------------|-------------------|-------------------|---------------------------| 16 | // | SHA-1 | 3,390,785 | 896,889 | 3.78 | 17 | // | SHA-224 | 8,251,799 | 898,344 | 9.19 | 18 | // | SHA-256 | 8,237,932 | 901,709 | 9.14 | 19 | // | SHA-384 | 13,605,806 | 799,532 | 17.02 | 20 | // | SHA-512 | 13,588,104 | 801,556 | 16.95 | 21 | 22 | for test in enumset::EnumSet::all() { 23 | println!("Testing {:?}", test); 24 | 25 | let before = cycles(); 26 | 27 | tls.self_test(test, true); 28 | 29 | println!("Took {:?}", before.elapsed()); 30 | } 31 | 32 | // HW Crypto: 33 | // Testing RSA 34 | // INFO - RSA key validation: 35 | // INFO - passed 36 | // PKCS#1 encryption : 37 | // INFO - passed 38 | // PKCS#1 decryption : 39 | // INFO - passed 40 | // INFO - PKCS#1 data sign : 41 | // INFO - passed 42 | // PKCS#1 sig. verify: 43 | // INFO - passed 44 | // INFO - 10 45 | // INFO - pre_cal 16377170 46 | // INFO - MPI test #1 (mul_mpi): 47 | // INFO - passed 48 | // INFO - MPI test #2 (div_mpi): 49 | // INFO - passed 50 | // INFO - MPI test #3 (exp_mod): 51 | // INFO - passed 52 | // INFO - MPI test #4 (inv_mod): 53 | // INFO - passed 54 | // INFO - MPI test #5 (simple gcd): 55 | // INFO - passed 56 | // INFO - 10 57 | // INFO - post_cal 17338357 58 | // Took 961187 cycles 59 | // Done 60 | 61 | // SW Crypto: 62 | // Testing RSA 63 | // INFO - RSA key validation: 64 | // INFO - passed 65 | // PKCS#1 encryption : 66 | // INFO - passed 67 | // PKCS#1 decryption : 68 | // INFO - passed 69 | // INFO - PKCS#1 data sign : 70 | // INFO - passed 71 | // PKCS#1 sig. verify: 72 | // INFO - passed 73 | // INFO - 10 74 | // INFO - pre_cal 19067376 75 | // INFO - MPI test #1 (mul_mpi): 76 | // INFO - passed 77 | // INFO - MPI test #2 (div_mpi): 78 | // INFO - passed 79 | // INFO - MPI test #3 (exp_mod): 80 | // INFO - passed 81 | // INFO - MPI test #4 (inv_mod): 82 | // INFO - passed 83 | // INFO - MPI test #5 (simple gcd): 84 | // INFO - passed 85 | // INFO - 10 86 | // INFO - post_cal 20393146 87 | // Took 1325770 cycles 88 | // Done 89 | 90 | println!("Done"); 91 | } 92 | -------------------------------------------------------------------------------- /examples/edge_server.rs: -------------------------------------------------------------------------------- 1 | //! Example for an HTTPS server using [edge-http](https://github.com/ivmarkov/edge-net) as the 2 | //! HTTPS server implementation, and `esp-mbedtls` for the TLS layer. 3 | //! 4 | //! Note: If you run out of heap memory, you need to increase `heap_size` in cfg.toml 5 | //! 6 | //! This example uses self-signed certificate. Your browser may display an error. 7 | //! You have to enable the exception to then proceed, of if using curl, use the flag `-k`. 8 | #![no_std] 9 | #![no_main] 10 | #![feature(type_alias_impl_trait)] 11 | #![feature(impl_trait_in_assoc_type)] 12 | 13 | use core::net::{IpAddr, Ipv4Addr, SocketAddr}; 14 | 15 | #[doc(hidden)] 16 | pub use esp_hal as hal; 17 | 18 | use edge_http::io::server::{Connection, Handler, Server}; 19 | use edge_http::io::Error; 20 | use edge_http::Method; 21 | use edge_nal_embassy::{Tcp, TcpBuffers}; 22 | 23 | use embedded_io_async::{Read, Write}; 24 | 25 | use embassy_net::{Config, Runner, StackResources}; 26 | 27 | use embassy_executor::Spawner; 28 | use embassy_time::{Duration, Timer}; 29 | use esp_backtrace as _; 30 | use esp_mbedtls::{Certificates, Tls, TlsVersion}; 31 | use esp_mbedtls::{TlsError, X509}; 32 | use esp_println::logger::init_logger; 33 | use esp_println::println; 34 | use esp_wifi::wifi::{ 35 | ClientConfiguration, Configuration, WifiController, WifiDevice, WifiEvent, WifiState, 36 | }; 37 | use esp_wifi::{init, EspWifiController}; 38 | use hal::{clock::CpuClock, rng::Rng, timer::timg::TimerGroup}; 39 | 40 | // Patch until https://github.com/embassy-rs/static-cell/issues/16 is fixed 41 | macro_rules! mk_static { 42 | ($t:ty,$val:expr) => {{ 43 | static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); 44 | #[deny(unused_attributes)] 45 | let x = STATIC_CELL.uninit().write(($val)); 46 | x 47 | }}; 48 | } 49 | 50 | const SSID: &str = env!("SSID"); 51 | const PASSWORD: &str = env!("PASSWORD"); 52 | 53 | /// Number of sockets used for the HTTPS server 54 | #[cfg(any(feature = "esp32", feature = "esp32s2"))] 55 | const SERVER_SOCKETS: usize = 1; 56 | #[cfg(not(any(feature = "esp32", feature = "esp32s2")))] 57 | const SERVER_SOCKETS: usize = 2; 58 | 59 | /// Total number of sockets used for the application 60 | const SOCKET_COUNT: usize = 1 + 1 + SERVER_SOCKETS; // DHCP + DNS + Server 61 | 62 | const RX_SIZE: usize = 4096; 63 | const TX_SIZE: usize = 2048; 64 | 65 | /// HTTPS server evaluated at compile time with socket count and buffer size. 66 | pub type HttpsServer = Server; 67 | 68 | esp_bootloader_esp_idf::esp_app_desc!(); 69 | 70 | #[esp_hal_embassy::main] 71 | async fn main(spawner: Spawner) -> ! { 72 | init_logger(log::LevelFilter::Info); 73 | 74 | let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); 75 | let peripherals = esp_hal::init(config); 76 | 77 | esp_alloc::heap_allocator!(size: 74 * 1024); 78 | esp_alloc::heap_allocator!(#[unsafe(link_section = ".dram2_uninit")] size: 64 * 1024); 79 | 80 | let timg0 = TimerGroup::new(peripherals.TIMG0); 81 | let mut rng = Rng::new(peripherals.RNG); 82 | 83 | let esp_wifi_ctrl = &*mk_static!( 84 | EspWifiController<'_>, 85 | init(timg0.timer0, rng.clone()).unwrap() 86 | ); 87 | 88 | let (controller, interfaces) = esp_wifi::wifi::new(&esp_wifi_ctrl, peripherals.WIFI).unwrap(); 89 | 90 | let wifi_interface = interfaces.sta; 91 | 92 | cfg_if::cfg_if! { 93 | if #[cfg(feature = "esp32")] { 94 | let timg1 = TimerGroup::new(peripherals.TIMG1); 95 | esp_hal_embassy::init(timg1.timer0); 96 | } else { 97 | use esp_hal::timer::systimer::SystemTimer; 98 | let systimer = SystemTimer::new(peripherals.SYSTIMER); 99 | esp_hal_embassy::init(systimer.alarm0); 100 | } 101 | } 102 | 103 | let config = Config::dhcpv4(Default::default()); 104 | 105 | let seed = (rng.random() as u64) << 32 | rng.random() as u64; 106 | 107 | // Init network stack 108 | let (stack, runner) = embassy_net::new( 109 | wifi_interface, 110 | config, 111 | mk_static!( 112 | StackResources, 113 | StackResources::::new() 114 | ), 115 | seed, 116 | ); 117 | 118 | spawner.spawn(connection(controller)).ok(); 119 | spawner.spawn(net_task(runner)).ok(); 120 | 121 | loop { 122 | if stack.is_link_up() { 123 | break; 124 | } 125 | Timer::after(Duration::from_millis(500)).await; 126 | } 127 | 128 | println!("Waiting to get IP address..."); 129 | loop { 130 | if let Some(config) = stack.config_v4() { 131 | println!("Got IP: {}", config.address); 132 | println!( 133 | "Point your browser to https://{}/", 134 | config.address.address() 135 | ); 136 | break; 137 | } 138 | Timer::after(Duration::from_millis(500)).await; 139 | } 140 | 141 | let mut server = HttpsServer::new(); 142 | let buffers = TcpBuffers::::new(); 143 | let tcp = Tcp::new(stack, &buffers); 144 | 145 | use edge_nal::TcpBind; 146 | 147 | let acceptor = tcp 148 | .bind(SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 443)) 149 | .await 150 | .unwrap(); 151 | 152 | let certificates = Certificates { 153 | // Use self-signed certificates 154 | certificate: X509::pem(concat!(include_str!("./certs/certificate.pem"), "\0").as_bytes()) 155 | .ok(), 156 | private_key: X509::pem(concat!(include_str!("./certs/private_key.pem"), "\0").as_bytes()) 157 | .ok(), 158 | ..Default::default() 159 | }; 160 | 161 | let mut tls = Tls::new(peripherals.SHA) 162 | .unwrap() 163 | .with_hardware_rsa(peripherals.RSA); 164 | 165 | tls.set_debug(0); 166 | 167 | loop { 168 | let tls_acceptor = esp_mbedtls::asynch::TlsAcceptor::new( 169 | &acceptor, 170 | TlsVersion::Tls1_2, 171 | certificates, 172 | tls.reference(), 173 | ); 174 | match server 175 | .run( 176 | Some(15 * 1000), 177 | edge_nal::WithTimeout::new(15_000, tls_acceptor), 178 | HttpHandler, 179 | ) 180 | .await 181 | { 182 | Ok(_) => {} 183 | Err(Error::Io(edge_nal::WithTimeoutError::Error(TlsError::MbedTlsError(-30592)))) => { 184 | println!("Fatal message: Please enable the exception for a self-signed certificate in your browser"); 185 | } 186 | Err(error) => { 187 | // panic!("{:?}", error); 188 | log::error!("{:?}", error); 189 | } 190 | } 191 | } 192 | } 193 | 194 | struct HttpHandler; 195 | 196 | impl Handler for HttpHandler { 197 | type Error 198 | = Error 199 | where 200 | E: core::fmt::Debug; 201 | 202 | async fn handle( 203 | &self, 204 | _task_id: impl core::fmt::Display + Copy, 205 | connection: &mut Connection<'_, T, N>, 206 | ) -> Result<(), Self::Error> 207 | where 208 | T: Read + Write, 209 | { 210 | println!("Got new connection"); 211 | let headers = connection.headers()?; 212 | 213 | if headers.method != Method::Get { 214 | connection 215 | .initiate_response(405, Some("Method Not Allowed"), &[]) 216 | .await?; 217 | } else if headers.path != "/" { 218 | connection 219 | .initiate_response(404, Some("Not Found"), &[]) 220 | .await?; 221 | } else { 222 | connection 223 | .initiate_response(200, Some("OK"), &[("Content-Type", "text/plain")]) 224 | .await?; 225 | 226 | connection.write_all(b"Hello world!").await?; 227 | } 228 | 229 | Ok(()) 230 | } 231 | } 232 | 233 | #[embassy_executor::task] 234 | async fn connection(mut controller: WifiController<'static>) { 235 | println!("start connection task"); 236 | println!("Device capabilities: {:?}", controller.capabilities()); 237 | loop { 238 | if matches!(esp_wifi::wifi::wifi_state(), WifiState::StaConnected) { 239 | // wait until we're no longer connected 240 | controller.wait_for_event(WifiEvent::StaDisconnected).await; 241 | Timer::after(Duration::from_millis(5000)).await 242 | } 243 | if !matches!(controller.is_started(), Ok(true)) { 244 | let client_config = Configuration::Client(ClientConfiguration { 245 | ssid: SSID.try_into().unwrap(), 246 | password: PASSWORD.try_into().unwrap(), 247 | ..Default::default() 248 | }); 249 | controller.set_configuration(&client_config).unwrap(); 250 | println!("Starting wifi"); 251 | controller.start_async().await.unwrap(); 252 | println!("Wifi started!"); 253 | } 254 | println!("About to connect..."); 255 | 256 | match controller.connect_async().await { 257 | Ok(_) => println!("Wifi connected!"), 258 | Err(e) => { 259 | println!("Failed to connect to wifi: {e:?}"); 260 | Timer::after(Duration::from_millis(5000)).await 261 | } 262 | } 263 | } 264 | } 265 | 266 | #[embassy_executor::task] 267 | async fn net_task(mut runner: Runner<'static, WifiDevice<'static>>) { 268 | runner.run().await 269 | } 270 | -------------------------------------------------------------------------------- /examples/sync_client.rs: -------------------------------------------------------------------------------- 1 | //! Example for a client connection to a server. 2 | //! This example connects to either `Google.com` or `certauth.cryptomix.com` (mTLS) and then prints out the result. 3 | //! 4 | //! # mTLS 5 | //! Use the mTLS feature to enable client authentication and send client certificates when doing a 6 | //! request. Note that this will connect to `certauth.cryptomix.com` instead of `google.com` 7 | #![no_std] 8 | #![no_main] 9 | 10 | use core::ffi::CStr; 11 | 12 | #[doc(hidden)] 13 | pub use esp_hal as hal; 14 | 15 | use blocking_network_stack::Stack; 16 | 17 | use esp_alloc as _; 18 | use esp_backtrace as _; 19 | use esp_mbedtls::{Certificates, Session}; 20 | use esp_mbedtls::{Mode, Tls, TlsVersion, X509}; 21 | use esp_println::{logger::init_logger, print, println}; 22 | use esp_wifi::{ 23 | init, 24 | wifi::{ClientConfiguration, Configuration}, 25 | }; 26 | use hal::{clock::CpuClock, main, rng::Rng, time, timer::timg::TimerGroup}; 27 | use smoltcp::{ 28 | iface::{SocketSet, SocketStorage}, 29 | wire::{DhcpOption, IpAddress}, 30 | }; 31 | 32 | const SSID: &str = env!("SSID"); 33 | const PASSWORD: &str = env!("PASSWORD"); 34 | 35 | // Setup configuration based on mTLS feature. 36 | cfg_if::cfg_if! { 37 | if #[cfg(feature = "mtls")] { 38 | const REMOTE_IP: IpAddress = IpAddress::v4(62, 210, 201, 125); // certauth.cryptomix.com 39 | const SERVERNAME: &CStr = c"certauth.cryptomix.com"; 40 | const REQUEST: &[u8] = b"GET /json/ HTTP/1.0\r\nHost: certauth.cryptomix.com\r\n\r\n"; 41 | } else { 42 | const REMOTE_IP: IpAddress = IpAddress::v4(142, 250, 185, 68); // google.com 43 | const SERVERNAME: &CStr = c"www.google.com"; 44 | const REQUEST: &[u8] = b"GET /notfound HTTP/1.0\r\nHost: www.google.com\r\n\r\n"; 45 | } 46 | } 47 | 48 | esp_bootloader_esp_idf::esp_app_desc!(); 49 | 50 | #[main] 51 | fn main() -> ! { 52 | init_logger(log::LevelFilter::Info); 53 | let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); 54 | let peripherals = esp_hal::init(config); 55 | 56 | esp_alloc::heap_allocator!(size: 72 * 1024); 57 | esp_alloc::heap_allocator!(#[unsafe(link_section = ".dram2_uninit")] size: 64 * 1024); 58 | 59 | let timg0 = TimerGroup::new(peripherals.TIMG0); 60 | 61 | let mut rng = Rng::new(peripherals.RNG); 62 | 63 | let esp_wifi_ctrl = init(timg0.timer0, rng.clone()).unwrap(); 64 | 65 | let (mut controller, interfaces) = 66 | esp_wifi::wifi::new(&esp_wifi_ctrl, peripherals.WIFI).unwrap(); 67 | 68 | let mut device = interfaces.sta; 69 | let iface = create_interface(&mut device); 70 | 71 | let mut socket_set_entries: [SocketStorage; 3] = Default::default(); 72 | let mut sockets = SocketSet::new(&mut socket_set_entries[..]); 73 | let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new(); 74 | // we can set a hostname here (or add other DHCP options) 75 | dhcp_socket.set_outgoing_options(&[DhcpOption { 76 | kind: 12, 77 | data: b"esp-mbedtls", 78 | }]); 79 | sockets.add(dhcp_socket); 80 | 81 | let now = || time::Instant::now().duration_since_epoch().as_millis(); 82 | let wifi_stack = Stack::new(iface, device, sockets, now, rng.random()); 83 | 84 | println!("Call wifi_connect"); 85 | let client_config = Configuration::Client(ClientConfiguration { 86 | ssid: SSID.try_into().unwrap(), 87 | password: PASSWORD.try_into().unwrap(), 88 | ..Default::default() 89 | }); 90 | 91 | controller.set_configuration(&client_config).unwrap(); 92 | controller.start().unwrap(); 93 | controller.connect().unwrap(); 94 | 95 | println!("Wait to get connected"); 96 | loop { 97 | let res = controller.is_connected(); 98 | match res { 99 | Ok(connected) => { 100 | if connected { 101 | break; 102 | } 103 | } 104 | Err(err) => { 105 | println!("{:?}", err); 106 | #[allow(clippy::empty_loop)] 107 | loop {} 108 | } 109 | } 110 | } 111 | 112 | // wait for getting an ip address 113 | println!("Wait to get an ip address"); 114 | loop { 115 | wifi_stack.work(); 116 | 117 | if wifi_stack.is_iface_up() { 118 | println!("Got ip {:?}", wifi_stack.get_ip_info()); 119 | break; 120 | } 121 | } 122 | 123 | println!("We are connected!"); 124 | 125 | println!("Making HTTP request"); 126 | let mut rx_buffer = [0u8; 1536]; 127 | let mut tx_buffer = [0u8; 1536]; 128 | let mut socket = wifi_stack.get_socket(&mut rx_buffer, &mut tx_buffer); 129 | 130 | socket.work(); 131 | 132 | socket.open(REMOTE_IP, 443).unwrap(); 133 | 134 | cfg_if::cfg_if! { 135 | if #[cfg(feature = "mtls")] { 136 | let certificates = Certificates { 137 | ca_chain: X509::pem( 138 | concat!(include_str!("./certs/certauth.cryptomix.com.pem"), "\0").as_bytes(), 139 | ) 140 | .ok(), 141 | certificate: X509::pem(concat!(include_str!("./certs/certificate.pem"), "\0").as_bytes()) 142 | .ok(), 143 | private_key: X509::pem(concat!(include_str!("./certs/private_key.pem"), "\0").as_bytes()) 144 | .ok(), 145 | password: None, 146 | }; 147 | } else { 148 | let certificates = Certificates { 149 | ca_chain: X509::pem( 150 | concat!(include_str!("./certs/www.google.com.pem"), "\0").as_bytes(), 151 | ) 152 | .ok(), 153 | ..Default::default() 154 | }; 155 | } 156 | } 157 | 158 | let mut tls = Tls::new(peripherals.SHA) 159 | .unwrap() 160 | .with_hardware_rsa(peripherals.RSA); 161 | 162 | tls.set_debug(0); 163 | 164 | let mut session = Session::new( 165 | &mut socket, 166 | Mode::Client { 167 | servername: SERVERNAME, 168 | }, 169 | TlsVersion::Tls1_3, 170 | certificates, 171 | tls.reference(), 172 | ) 173 | .unwrap(); 174 | 175 | println!("Start tls connect"); 176 | session.connect().unwrap(); 177 | 178 | println!("Write to connection"); 179 | session.write(REQUEST).unwrap(); 180 | 181 | println!("Read from connection"); 182 | let mut buffer = [0u8; 4096]; 183 | loop { 184 | match session.read(&mut buffer) { 185 | Ok(len) => { 186 | print!("{}", unsafe { 187 | core::str::from_utf8_unchecked(&buffer[..len]) 188 | }); 189 | } 190 | Err(_) => { 191 | println!(); 192 | break; 193 | } 194 | } 195 | } 196 | println!("Done"); 197 | 198 | #[allow(clippy::empty_loop)] 199 | loop {} 200 | } 201 | 202 | // some smoltcp boilerplate 203 | fn timestamp() -> smoltcp::time::Instant { 204 | smoltcp::time::Instant::from_micros( 205 | esp_hal::time::Instant::now() 206 | .duration_since_epoch() 207 | .as_micros() as i64, 208 | ) 209 | } 210 | 211 | fn create_interface(device: &mut esp_wifi::wifi::WifiDevice) -> smoltcp::iface::Interface { 212 | // users could create multiple instances but since they only have one WifiDevice 213 | // they probably can't do anything bad with that 214 | smoltcp::iface::Interface::new( 215 | smoltcp::iface::Config::new(smoltcp::wire::HardwareAddress::Ethernet( 216 | smoltcp::wire::EthernetAddress::from_bytes(&device.mac_address()), 217 | )), 218 | device, 219 | timestamp(), 220 | ) 221 | } 222 | -------------------------------------------------------------------------------- /examples/sync_server.rs: -------------------------------------------------------------------------------- 1 | //! Example for a sync server. 2 | //! Contains a basic server implementation to test mbedtls in server mode. 3 | //! 4 | //! This example uses self-signed certificate. Your browser may display an error. 5 | //! You have to enable the exception to then proceed, of if using curl, use the flag `-k`. 6 | //! 7 | //! # mTLS 8 | //! Running this example with the feature `mtls` will make the server request a client 9 | //! certificate for the connection. If you send a request, without passing 10 | //! certificates, you will get an error. Theses certificates below are generated 11 | //! to work is the configured CA: 12 | //! 13 | //! certificate.pem 14 | //! ```text 15 | #![doc = include_str!("./certs/certificate.pem")] 16 | //! ``` 17 | //! 18 | //! private_key.pem 19 | //! ```text 20 | #![doc = include_str!("./certs/private_key.pem")] 21 | //! ``` 22 | //! 23 | //! Test with curl: 24 | //! ```bash 25 | //! curl https:/// --cert certificate.pem --key private_key.pem -k 26 | //! ``` 27 | //! 28 | #![no_std] 29 | #![no_main] 30 | 31 | #[doc(hidden)] 32 | pub use esp_hal as hal; 33 | 34 | use blocking_network_stack::Stack; 35 | 36 | use embedded_io::*; 37 | use esp_backtrace as _; 38 | use esp_mbedtls::{Certificates, Session}; 39 | use esp_mbedtls::{Mode, Tls, TlsError, TlsVersion, X509}; 40 | use esp_println::{logger::init_logger, print, println}; 41 | use esp_wifi::{ 42 | init, 43 | wifi::{ClientConfiguration, Configuration}, 44 | }; 45 | use hal::{clock::CpuClock, main, rng::Rng, time, timer::timg::TimerGroup}; 46 | use smoltcp::{ 47 | iface::{SocketSet, SocketStorage}, 48 | wire::DhcpOption, 49 | }; 50 | 51 | const SSID: &str = env!("SSID"); 52 | const PASSWORD: &str = env!("PASSWORD"); 53 | 54 | esp_bootloader_esp_idf::esp_app_desc!(); 55 | 56 | #[main] 57 | fn main() -> ! { 58 | init_logger(log::LevelFilter::Info); 59 | let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); 60 | let peripherals = esp_hal::init(config); 61 | 62 | esp_alloc::heap_allocator!(size: 72 * 1024); 63 | esp_alloc::heap_allocator!(#[unsafe(link_section = ".dram2_uninit")] size: 64 * 1024); 64 | 65 | let timg0 = TimerGroup::new(peripherals.TIMG0); 66 | 67 | let mut rng = Rng::new(peripherals.RNG); 68 | 69 | let esp_wifi_ctrl = init(timg0.timer0, rng.clone()).unwrap(); 70 | 71 | let (mut controller, interfaces) = 72 | esp_wifi::wifi::new(&esp_wifi_ctrl, peripherals.WIFI).unwrap(); 73 | 74 | let mut device = interfaces.sta; 75 | let iface = create_interface(&mut device); 76 | 77 | let mut socket_set_entries: [SocketStorage; 3] = Default::default(); 78 | let mut sockets = SocketSet::new(&mut socket_set_entries[..]); 79 | let mut dhcp_socket = smoltcp::socket::dhcpv4::Socket::new(); 80 | // we can set a hostname here (or add other DHCP options) 81 | dhcp_socket.set_outgoing_options(&[DhcpOption { 82 | kind: 12, 83 | data: b"esp-mbedtls", 84 | }]); 85 | sockets.add(dhcp_socket); 86 | 87 | let now = || time::Instant::now().duration_since_epoch().as_millis(); 88 | let wifi_stack = Stack::new(iface, device, sockets, now, rng.random()); 89 | 90 | println!("Call wifi_connect"); 91 | let client_config = Configuration::Client(ClientConfiguration { 92 | ssid: SSID.try_into().unwrap(), 93 | password: PASSWORD.try_into().unwrap(), 94 | ..Default::default() 95 | }); 96 | controller.set_configuration(&client_config).unwrap(); 97 | controller.start().unwrap(); 98 | controller.connect().unwrap(); 99 | 100 | println!("Wait to get connected"); 101 | loop { 102 | let res = controller.is_connected(); 103 | match res { 104 | Ok(connected) => { 105 | if connected { 106 | break; 107 | } 108 | } 109 | Err(err) => { 110 | println!("{:?}", err); 111 | #[allow(clippy::empty_loop)] 112 | loop {} 113 | } 114 | } 115 | } 116 | 117 | // wait for getting an ip address 118 | println!("Wait to get an ip address"); 119 | loop { 120 | wifi_stack.work(); 121 | 122 | if wifi_stack.is_iface_up() { 123 | println!("Got ip {:?}", wifi_stack.get_ip_info()); 124 | break; 125 | } 126 | } 127 | 128 | println!("We are connected!"); 129 | 130 | println!( 131 | "Point your browser to https://{:?}/", 132 | wifi_stack.get_ip_info().unwrap().ip 133 | ); 134 | let mut rx_buffer = [0u8; 1536]; 135 | let mut tx_buffer = [0u8; 1536]; 136 | let mut socket = wifi_stack.get_socket(&mut rx_buffer, &mut tx_buffer); 137 | 138 | socket.listen(443).unwrap(); 139 | 140 | let mut tls = Tls::new(peripherals.SHA) 141 | .unwrap() 142 | .with_hardware_rsa(peripherals.RSA); 143 | 144 | tls.set_debug(0); 145 | 146 | loop { 147 | socket.work(); 148 | 149 | if !socket.is_open() { 150 | socket.listen(443).unwrap(); 151 | } 152 | 153 | if socket.is_connected() { 154 | println!("New connection"); 155 | 156 | let mut time_out = false; 157 | let wait_end = now() + 20 * 1000; 158 | let mut buffer = [0u8; 1024]; 159 | let mut pos = 0; 160 | 161 | let mut session = Session::new( 162 | &mut socket, 163 | Mode::Server, 164 | TlsVersion::Tls1_2, 165 | Certificates { 166 | // Provide a ca_chain if you want to enable mTLS for the server. 167 | #[cfg(feature = "mtls")] 168 | ca_chain: X509::pem( 169 | concat!(include_str!("./certs/ca_cert.pem"), "\0").as_bytes(), 170 | ) 171 | .ok(), 172 | // Use self-signed certificates 173 | certificate: X509::pem( 174 | concat!(include_str!("./certs/certificate.pem"), "\0").as_bytes(), 175 | ) 176 | .ok(), 177 | private_key: X509::pem( 178 | concat!(include_str!("./certs/private_key.pem"), "\0").as_bytes(), 179 | ) 180 | .ok(), 181 | ..Default::default() 182 | }, 183 | tls.reference(), 184 | ) 185 | .unwrap(); 186 | 187 | match session.connect() { 188 | Ok(_) => { 189 | while let Ok(len) = session.read(&mut buffer[pos..]) { 190 | let to_print = 191 | unsafe { core::str::from_utf8_unchecked(&buffer[..(pos + len)]) }; 192 | 193 | if to_print.contains("\r\n\r\n") { 194 | print!("{}", to_print); 195 | println!(); 196 | break; 197 | } 198 | 199 | pos += len; 200 | 201 | if now() > wait_end { 202 | println!("Timed out"); 203 | time_out = true; 204 | break; 205 | } 206 | } 207 | 208 | if !time_out { 209 | session 210 | .write_all( 211 | b"HTTP/1.0 200 OK\r\n\r\n\ 212 | \ 213 | \ 214 |

Hello Rust! Hello esp-mbedtls!

\ 215 | \ 216 | \r\n\ 217 | ", 218 | ) 219 | .unwrap(); 220 | } 221 | } 222 | Err(TlsError::NoClientCertificate) => { 223 | println!("Error: No client certificates given. Please provide client certificates during your request"); 224 | } 225 | Err(TlsError::MbedTlsError(-30592)) => { 226 | println!("Fatal message: Please enable the exception for a self-signed certificate in your browser"); 227 | } 228 | Err(error) => { 229 | panic!("{:?}", error); 230 | } 231 | } 232 | 233 | drop(session); 234 | socket.close(); 235 | 236 | println!("Done\n"); 237 | println!(); 238 | } 239 | } 240 | } 241 | 242 | // some smoltcp boilerplate 243 | fn timestamp() -> smoltcp::time::Instant { 244 | smoltcp::time::Instant::from_micros( 245 | esp_hal::time::Instant::now() 246 | .duration_since_epoch() 247 | .as_micros() as i64, 248 | ) 249 | } 250 | 251 | fn create_interface(device: &mut esp_wifi::wifi::WifiDevice) -> smoltcp::iface::Interface { 252 | // users could create multiple instances but since they only have one WifiDevice 253 | // they probably can't do anything bad with that 254 | smoltcp::iface::Interface::new( 255 | smoltcp::iface::Config::new(smoltcp::wire::HardwareAddress::Ethernet( 256 | smoltcp::wire::EthernetAddress::from_bytes(&device.mac_address()), 257 | )), 258 | device, 259 | timestamp(), 260 | ) 261 | } 262 | -------------------------------------------------------------------------------- /genssl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/env bash 2 | # This is a simple script to refresh the certificate chains from the links used in the example, 3 | # and to refresh the self-signed CA and associated certificate + private key pair used for examples. 4 | 5 | CERTS_DIR=./examples/certs 6 | 7 | # Get certificate chain for www.google.com 8 | echo -n | openssl s_client -showcerts -connect www.google.com:443 2>/dev/null | awk '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/' > $CERTS_DIR/www.google.com.pem 9 | 10 | # Get certificate chain for certauth.cryptomix.com 11 | echo -n | openssl s_client -showcerts -connect certauth.cryptomix.com:443 2>/dev/null | awk '/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/' > $CERTS_DIR/certauth.cryptomix.com.pem 12 | 13 | # Generate a CA and a pair of certificate + private key signed with the CA 14 | 15 | # Generate CA certificate 16 | openssl req \ 17 | -x509 \ 18 | -newkey rsa:2048 \ 19 | -keyout $CERTS_DIR/ca_key.pem \ 20 | -out $CERTS_DIR/ca_cert.pem \ 21 | -nodes \ 22 | -days 365 \ 23 | -subj "/CN=esp-mbedtls.local/O=CA\ Certificate" 24 | 25 | 26 | # Generate certificate signing request (CSR) 27 | openssl req \ 28 | -newkey rsa:2048 \ 29 | -keyout $CERTS_DIR/private_key.pem \ 30 | -out $CERTS_DIR/csr.pem \ 31 | -nodes \ 32 | -subj "/CN=esp-mbedtls.local" 33 | 34 | # Sign key with CA certificates from CSR 35 | openssl x509 \ 36 | -req \ 37 | -in $CERTS_DIR/csr.pem \ 38 | -CA $CERTS_DIR/ca_cert.pem \ 39 | -CAkey $CERTS_DIR/ca_key.pem \ 40 | -out $CERTS_DIR/certificate.pem \ 41 | -CAcreateserial \ 42 | -days 365 43 | 44 | # Remove csr 45 | rm $CERTS_DIR/csr.pem 46 | -------------------------------------------------------------------------------- /justfile: -------------------------------------------------------------------------------- 1 | export SSID := "Dummy" 2 | export PASSWORD := "Dummy" 3 | 4 | all: (check "esp32" "esp") (check "esp32s3" "esp") (check "esp32c3" "nightly") (check "esp32c6" "nightly") 5 | cd esp-mbedtls && cargo +nightly fmt --all -- --check 6 | 7 | [private] 8 | check arch toolchain: 9 | cargo +{{ toolchain }} b{{ arch }} --example sync_client --features="examples" 10 | cargo +{{ toolchain }} b{{ arch }} --example sync_client --features="examples, mtls" 11 | cargo +{{ toolchain }} b{{ arch }} --example async_client --features="examples-async" 12 | cargo +{{ toolchain }} b{{ arch }} --example async_client --features="examples-async, mtls" 13 | cargo +{{ toolchain }} b{{ arch }} --example sync_server --features="examples" 14 | cargo +{{ toolchain }} b{{ arch }} --example sync_server --features="examples, mtls" 15 | cargo +{{ toolchain }} b{{ arch }} --example async_server --features="examples-async" 16 | cargo +{{ toolchain }} b{{ arch }} --example async_server --features="examples-async, mtls" 17 | cargo +{{ toolchain }} b{{ arch }} --example edge_server --features="examples-async" 18 | cargo +{{ toolchain }} b{{ arch }} --example crypto_self_test --features="examples" 19 | cargo +{{ toolchain }} b --example crypto_self_test_std --features="examples-std" --target x86_64-unknown-linux-gnu -Z build-std=std,panic_abort 20 | cargo +{{ toolchain }} fmt --all -- --check 21 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | // see examples 4 | -------------------------------------------------------------------------------- /xtask/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "xtask" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | anyhow = "1.0.68" 8 | bindgen = "0.68.1" 9 | directories = "4.0.1" 10 | env_logger = "0.10.0" 11 | log = "0.4.17" 12 | cmake = "0.1.52" 13 | tempdir = "0.3.7" 14 | fs_extra = "1.3.0" 15 | clap = { version = "4.4.2", features = ["derive"] } 16 | -------------------------------------------------------------------------------- /xtask/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | env, 3 | path::{Path, PathBuf}, 4 | }; 5 | 6 | use anyhow::Result; 7 | use clap::{Parser, Subcommand, ValueEnum}; 8 | use directories::UserDirs; 9 | use log::LevelFilter; 10 | use tempdir::TempDir; 11 | 12 | #[path = "../../esp-mbedtls-sys/gen/builder.rs"] 13 | mod builder; 14 | 15 | // Arguments 16 | #[derive(Parser, Debug)] 17 | #[command(author, version, about = "Compile and generate bindings for mbedtls to be used in Rust.", long_about = None, subcommand_required = true)] 18 | struct Args { 19 | #[command(subcommand)] 20 | command: Option, 21 | } 22 | 23 | #[derive(Subcommand, Debug)] 24 | enum Commands { 25 | /// Generate Rust bindings for mbedtls and generate .a libraries 26 | Gen { 27 | #[arg(long, value_name = "TARGET", value_enum)] 28 | chip: Option, 29 | }, 30 | /// Generate Rust bindings for mbedtls 31 | Bindings { 32 | #[arg(long, value_name = "TARGET", value_enum)] 33 | chip: Option, 34 | }, 35 | /// Build mbedtls and generate .a libraries 36 | Compile { 37 | #[arg(long, value_name = "TARGET", value_enum)] 38 | chip: Option, 39 | }, 40 | } 41 | 42 | /// All SOCs available for compiling and binding 43 | #[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq)] 44 | enum Soc { 45 | ESP32, 46 | ESP32C3, 47 | ESP32C6, 48 | ESP32S2, 49 | ESP32S3, 50 | } 51 | 52 | impl core::fmt::Display for Soc { 53 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { 54 | match self { 55 | Soc::ESP32 => write!(f, "esp32"), 56 | Soc::ESP32C3 => write!(f, "esp32c3"), 57 | Soc::ESP32C6 => write!(f, "esp32c6"), 58 | Soc::ESP32S2 => write!(f, "esp32s2"), 59 | Soc::ESP32S3 => write!(f, "esp32s3"), 60 | } 61 | } 62 | } 63 | 64 | #[derive(Debug, PartialEq)] 65 | enum Arch { 66 | RiscV, 67 | Xtensa, 68 | } 69 | 70 | impl Arch { 71 | pub const fn clang(&self) -> Option<&str> { 72 | const ESP_XTENSA_CLANG_PATH: &str = "xtensa-esp32-elf-clang/esp-19.1.2_20250225/esp-clang/bin/clang"; 73 | 74 | match self { 75 | Arch::Xtensa => Some(ESP_XTENSA_CLANG_PATH), 76 | // Clang is a cross-compiler 77 | _ => Some(ESP_XTENSA_CLANG_PATH), 78 | } 79 | } 80 | 81 | pub const fn sysroot(&self) -> &str { 82 | const ESP_XTENSA_SYSROOT_PATH: &str = "xtensa-esp-elf/esp-14.2.0_20240906/xtensa-esp-elf/xtensa-esp-elf"; 83 | const ESP_RISCV_SYSROOT_PATH: &str = "riscv32-esp-elf/esp-14.2.0_20240906/riscv32-esp-elf/riscv32-esp-elf"; 84 | 85 | match self { 86 | Arch::RiscV => ESP_RISCV_SYSROOT_PATH, 87 | Arch::Xtensa => ESP_XTENSA_SYSROOT_PATH, 88 | } 89 | } 90 | } 91 | 92 | /// Data for binding compiling on a target 93 | struct CompilationTarget<'a> { 94 | /// Chip of the target 95 | soc: Soc, 96 | 97 | /// The chip architecture 98 | arch: Arch, 99 | 100 | /// Rust target triple 101 | target: &'a str, 102 | 103 | /// Clang target 104 | clang_target: &'a str, 105 | } 106 | 107 | impl CompilationTarget<'_> { 108 | pub fn gen(&self, sys_crate_root_path: PathBuf, toolchain_dir: &Path) -> Result<()> { 109 | self.build(sys_crate_root_path.clone(), toolchain_dir)?; 110 | self.generate_bindings(sys_crate_root_path, toolchain_dir)?; 111 | 112 | Ok(()) 113 | } 114 | 115 | pub fn build(&self, sys_crate_root_path: PathBuf, toolchain_dir: &Path) -> Result<()> { 116 | let builder = builder::MbedtlsBuilder::new( 117 | sys_crate_root_path.clone(), 118 | format!("{}", self.soc), 119 | self.arch.clang().map(|clang| toolchain_dir.join(clang)), 120 | None, 121 | Some(self.target.into()), 122 | Some(self.clang_target.into()), 123 | // Fake host, but we do need to pass something to CMake 124 | Some("x86_64-unknown-linux-gnu".into()), 125 | ); 126 | 127 | let out = TempDir::new("esp-mbedtls-sys")?; 128 | 129 | builder.compile( 130 | out.path(), 131 | Some(&sys_crate_root_path.join("libs").join(self.target)), 132 | )?; 133 | 134 | Ok(()) 135 | } 136 | 137 | pub fn generate_bindings( 138 | &self, 139 | sys_crate_root_path: PathBuf, 140 | toolchain_dir: &Path, 141 | ) -> Result<()> { 142 | let builder = builder::MbedtlsBuilder::new( 143 | sys_crate_root_path.clone(), 144 | format!("{}", self.soc), 145 | self.arch.clang().map(|clang| toolchain_dir.join(clang)), 146 | Some(toolchain_dir.join(self.arch.sysroot())), 147 | Some(self.target.into()), 148 | Some(self.clang_target.into()), 149 | None, 150 | ); 151 | 152 | let out = TempDir::new("esp-mbedtls-sys")?; 153 | 154 | builder.generate_bindings( 155 | out.path(), 156 | Some( 157 | &sys_crate_root_path 158 | .join("src") 159 | .join("include") 160 | .join(format!("{}.rs", self.soc)), 161 | ), 162 | )?; 163 | 164 | Ok(()) 165 | } 166 | } 167 | 168 | static COMPILATION_TARGETS: &[CompilationTarget] = &[ 169 | CompilationTarget { 170 | soc: Soc::ESP32, 171 | arch: Arch::Xtensa, 172 | clang_target: "xtensa-esp32-none-elf", 173 | target: "xtensa-esp32-none-elf", 174 | }, 175 | CompilationTarget { 176 | soc: Soc::ESP32C3, 177 | arch: Arch::RiscV, 178 | clang_target: "riscv32-esp-elf", 179 | target: "riscv32imc-unknown-none-elf", 180 | }, 181 | CompilationTarget { 182 | soc: Soc::ESP32C6, 183 | arch: Arch::RiscV, 184 | clang_target: "riscv32-esp-elf", 185 | target: "riscv32imac-unknown-none-elf", 186 | }, 187 | CompilationTarget { 188 | soc: Soc::ESP32S2, 189 | arch: Arch::Xtensa, 190 | clang_target: "xtensa-esp32s2-none-elf", 191 | target: "xtensa-esp32s2-none-elf", 192 | }, 193 | CompilationTarget { 194 | soc: Soc::ESP32S3, 195 | arch: Arch::Xtensa, 196 | clang_target: "xtensa-esp32s3-none-elf", 197 | target: "xtensa-esp32s3-none-elf", 198 | }, 199 | ]; 200 | 201 | fn main() -> Result<()> { 202 | env_logger::Builder::new() 203 | .filter_module("xtask", LevelFilter::Info) 204 | .init(); 205 | 206 | // The directory containing the cargo manifest for the 'xtask' package is a 207 | // subdirectory 208 | let workspace = PathBuf::from(env!("CARGO_MANIFEST_DIR")); 209 | let workspace = workspace.parent().unwrap().canonicalize()?; 210 | 211 | let sys_crate_root_path = workspace.join("esp-mbedtls-sys"); 212 | 213 | // Determine the $HOME directory, and subsequently the Espressif tools 214 | // directory: 215 | let home = UserDirs::new().unwrap().home_dir().to_path_buf(); 216 | // We use the tools that come installed with the toolchain 217 | // Note that the RiscV toolchain is not installed by default and needs the `-r` `espup` flag 218 | let toolchain_dir = home.join(".rustup").join("toolchains").join("esp"); 219 | 220 | let args = Args::parse(); 221 | 222 | let target = |chip| COMPILATION_TARGETS 223 | .iter() 224 | .find(|&target| target.soc == chip) 225 | .expect("Compilation target {chip} not found"); 226 | 227 | match args.command { 228 | Some(Commands::Gen { chip }) => match chip { 229 | Some(chip) => { 230 | target(chip).gen(sys_crate_root_path.clone(), &toolchain_dir)?; 231 | } 232 | None => { 233 | for target in COMPILATION_TARGETS { 234 | target.gen(sys_crate_root_path.clone(), &toolchain_dir)?; 235 | } 236 | } 237 | }, 238 | Some(Commands::Compile { chip }) => match chip { 239 | Some(chip) => { 240 | target(chip).build(sys_crate_root_path.clone(), &toolchain_dir)?; 241 | } 242 | None => { 243 | for target in COMPILATION_TARGETS { 244 | target.build(sys_crate_root_path.clone(), &toolchain_dir)?; 245 | } 246 | } 247 | }, 248 | Some(Commands::Bindings { chip }) => match chip { 249 | Some(chip) => { 250 | target(chip).generate_bindings(sys_crate_root_path.clone(), &toolchain_dir)?; 251 | } 252 | None => { 253 | for target in COMPILATION_TARGETS { 254 | target.generate_bindings(sys_crate_root_path.clone(), &toolchain_dir)?; 255 | } 256 | } 257 | }, 258 | _ => { 259 | unreachable!(); 260 | } 261 | } 262 | 263 | Ok(()) 264 | } 265 | --------------------------------------------------------------------------------