Skip to content

Commit b96e73f

Browse files
Merge pull request #7936 from gojimmypi/pr-add-espressif-esp-tls-cert-bundle
Add wolfSSL esp-tls and Certificate Bundle Support
2 parents 3178ce6 + 2a35490 commit b96e73f

14 files changed

Lines changed: 6667 additions & 85 deletions

File tree

wolfcrypt/src/include.am

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,12 @@ EXTRA_DIST += wolfcrypt/src/port/ti/ti-aes.c \
123123
wolfcrypt/src/port/Espressif/esp_sdk_mem_lib.c \
124124
wolfcrypt/src/port/Espressif/esp_sdk_time_lib.c \
125125
wolfcrypt/src/port/Espressif/esp_sdk_wifi_lib.c \
126+
wolfcrypt/src/port/Espressif/esp_crt_bundle/README.md \
127+
wolfcrypt/src/port/Espressif/esp_crt_bundle/cacrt_all.pem \
128+
wolfcrypt/src/port/Espressif/esp_crt_bundle/cacrt_deprecated.pem \
129+
wolfcrypt/src/port/Espressif/esp_crt_bundle/esp_crt_bundle.c \
130+
wolfcrypt/src/port/Espressif/esp_crt_bundle/gen_crt_bundle.py \
131+
wolfcrypt/src/port/Espressif/esp_crt_bundle/cacrt_local.pem \
126132
wolfcrypt/src/port/Espressif/README.md \
127133
wolfcrypt/src/port/arm/cryptoCell.c \
128134
wolfcrypt/src/port/arm/cryptoCellHash.c \

wolfcrypt/src/port/Espressif/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Support for the ESP32 on-board cryptographic hardware acceleration for symmetric
1212

1313
## ESP32 Acceleration
1414

15-
More details about ESP32 HW Accelerationcan be found in:
15+
More details about ESP32 HW Acceleration can be found in:
1616

1717
* [ESP32 Technical Reference Manual](https://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf)
1818
* [ESP32-S2 Technical Reference Manual](https://www.espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf)

wolfcrypt/src/port/Espressif/esp32_mp.c

Lines changed: 264 additions & 72 deletions
Large diffs are not rendered by default.
Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
# wolfSSL Support for ESP-IDF Certificate Bundles
2+
3+
These files are typically only used when integrating wolfSSL with the ESP-IDF
4+
and with the intention of using Certificate Bundles in the esp-tls component.
5+
6+
See the ESP-IDF `idf.py menuconfig`. A recent version of the [wolfSSL Kconfig](https://github.com/wolfSSL/wolfssl/blob/master/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl/Kconfig)
7+
file is needed. The [template example](https://github.com/wolfSSL/wolfssl/tree/master/IDE/Espressif/ESP-IDF/examples/template)
8+
can be use for creating a project-specific [wolfSSL component](https://github.com/wolfSSL/wolfssl/tree/master/IDE/Espressif/ESP-IDF/examples/template/components/wolfssl)
9+
when not using a [Managed Component](https://components.espressif.com/components/wolfssl/wolfssl).
10+
11+
## Getting Started
12+
13+
Use the `idf.py menuconfig`,
14+
15+
When in doubt, delete the `./build` directory. This is particularly important when changing Certificate Bundle PEM files.
16+
17+
## Certificate Inspection
18+
19+
The certificates in the bundle are in PEM format. The [gen_crt_bundle.py script](./gen_crt_bundle.py)
20+
converts them to DER format to load into the `x509_crt_imported_bundle_wolfssl_bin_start` binary
21+
array.
22+
23+
To convert a PEM to DER from command-line:
24+
25+
```
26+
MY_CERT_NAME=ISRG_ROOT_X1
27+
openssl x509 -outform der -in "$MY_CERT_NAME".pem -out "$MY_CERT_NAME".der
28+
```
29+
30+
To inspect a DER file:
31+
32+
```
33+
openssl x509 -inform der -in "$MY_CERT_NAME".der -text -noout
34+
```
35+
36+
37+
## Known Problems and Issues
38+
39+
Here are the areas that may need attention. Most are related to older published versions of the ESP-IDF
40+
that may not yet have wolfSSL integration. An updated ESP-IDF is required to use wolfSSL component _in_ the ESP-IDF.
41+
There's a [gojimmypi V5.2.2 WIP Branch](https://github.com/gojimmypi/esp-idf/tree/my_522/components/lwip) for reference
42+
until a PR is created for upstream support.
43+
44+
### Time
45+
46+
The wolfSSL libraries are by default considerably more robust and strict. As such, it is important to have an accurate
47+
time and date setting for the certficate date ranges.. The wolfssL libraries include some
48+
[time helper functions](https://github.com/wolfSSL/wolfssl/blob/master/wolfssl/wolfcrypt/port/Espressif/esp-sdk-lib.h).
49+
These can be enabled with `#define USE_WOLFSSL_ESP_SDK_TIME` in the `user_settings.h`.
50+
51+
Alternatively, the `WOLFSSL_DEBUG_IGNORE_ASN_TIME` can be used to ignore the time. This is strongly discouraged in anything
52+
other than a development / test environment where the time is known to be incorrect.
53+
54+
### Examples may need to have wolfSSL Certificate Bundles enabled.
55+
56+
In cases where [some examples are gated out](https://github.com/espressif/esp-idf/blob/c9df77efbf871d4c3ae9fb828778ff8c4ab36804/examples/protocols/esp_http_client/main/esp_http_client_example.c#L419),
57+
the "or" needs to be added for `CONFIG_WOLFSSL_CERTIFICATE_BUNDLE` option like this:
58+
59+
```
60+
#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE || CONFIG_WOLFSSL_CERTIFICATE_BUNDLE
61+
```
62+
63+
### Adding Embedded Certificates
64+
65+
The `main` app directory has a [CMakeLists.txt](https://github.com/espressif/esp-idf/blob/6e5414b6c4f265a0adfb56a15fbfbe6beb1f8373/examples/protocols/esp_http_client/main/CMakeLists.txt#L10)
66+
with the `idf_component_register` function:
67+
68+
```
69+
idf_component_register(SRCS "esp_http_client_example.c"
70+
INCLUDE_DIRS "."
71+
REQUIRES ${requires}
72+
EMBED_TXTFILES howsmyssl_com_root_cert.pem
73+
postman_root_cert.pem)
74+
```
75+
76+
This data ends up in the [extern const char](https://github.com/espressif/esp-idf/blob/6e5414b6c4f265a0adfb56a15fbfbe6beb1f8373/examples/protocols/esp_http_client/main/esp_http_client_example.c#L45)
77+
arrays:
78+
79+
```
80+
extern const char howsmyssl_com_root_cert_pem_start[] asm("_binary_howsmyssl_com_root_cert_pem_start");
81+
extern const char howsmyssl_com_root_cert_pem_end[] asm("_binary_howsmyssl_com_root_cert_pem_end");
82+
83+
extern const char postman_root_cert_pem_start[] asm("_binary_postman_root_cert_pem_start");
84+
extern const char postman_root_cert_pem_end[] asm("_binary_postman_root_cert_pem_end");
85+
```
86+
87+
When changing the source files (also located in the `main` directory) - it is usually best to
88+
delete the `./build` directory to ensure fresh contents get parsed in as desired.
89+
90+
VS Code / PlatformIO users can consider deleting the `./pio` and `./vscode` directories.
91+
92+
Visual Studio/VisualGDB users can remove the `./vs` and `.visualgdb`.
93+
94+
### TLS 1.3 issues with howsmyssl.com
95+
96+
Espressif is using the well known https://www.howsmyssl.com/ in the
97+
[examples](https://github.com/espressif/esp-idf/tree/master/examples/protocols/), for instance in
98+
the [esp_http_client](https://github.com/espressif/esp-idf/tree/master/examples/protocols/esp_http_client).
99+
100+
It was recently observed that TLS 1.3 is _not_ currently configured properly on that web site.
101+
See [howsmyssl #716](https://github.com/jmhodges/howsmyssl/issues/716).
102+
103+
As such, when configuring wolfSSL for _only_ TLS 1.3, a `fatal error -313` may occur.
104+
105+
Additionally, not that there's a [cert in the app](https://github.com/espressif/esp-idf/blob/c9df77efbf871d4c3ae9fb828778ff8c4ab36804/examples/protocols/esp_http_client/main/esp_http_client_example.c#L45)
106+
in `howsmyssl_com_root_cert_pem_start`, separate from the bundle certificate data. Take note of this when
107+
attempting to simply change `www.howsmyssl.com` to `www.google.com`.
108+
109+
110+
### postman
111+
112+
Beware there's a hard-coded PEM certificate for the [postman root cert](https://github.com/espressif/esp-idf/blob/c9df77efbf871d4c3ae9fb828778ff8c4ab36804/examples/protocols/esp_http_client/main/esp_http_client_example.c#L48)
113+
(not in the bundle). If you see a failure, the data may need to be updated.
114+
115+
See the comments for adding certificate data, copied here for reference:
116+
117+
>Root cert for howsmyssl.com, taken from howsmyssl_com_root_cert.pem
118+
119+
>The PEM file was extracted from the output of this command:
120+
openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null
121+
122+
>The CA root cert is the last cert given in the chain of certs.
123+
124+
>To embed it in the app binary, the PEM file is named
125+
in the component.mk COMPONENT_EMBED_TXTFILES variable.
126+
127+
## Timeout
128+
129+
Occasionally there may be connection timeouts. This is not specific to wolfSSL. The root cause is likely CDN related.
130+
131+
See the `.timeout_ms` and make adjustments as necessary in the `esp_http_client_config_t`:.
132+
133+
```
134+
esp_http_client_config_t config = {
135+
.url = "https://postman-echo.com/post",
136+
.event_handler = _http_event_handler,
137+
.cert_pem = postman_root_cert_pem_start,
138+
.is_async = true,
139+
.timeout_ms = 5000,
140+
};
141+
```
142+
143+
## Failed to load CA
144+
145+
This is expected to be a common error to encounter:
146+
147+
```
148+
E (28454) esp_crt_bundle-wolfssl: Failed to load CA
149+
W (28454) esp_crt_bundle-wolfssl: Warning: found a matching cert, but not added to the Certificate Manager. error: 0
150+
E (28454) esp_crt_bundle-wolfssl: Did not find a matching crt
151+
E (28464) internal.c: ssl != NULL; no callback, verifyFail = 1
152+
W (28474) internal.c: CleanupStoreCtxCallback
153+
E (28474) internal.c: DoCertFatalAlert = -188
154+
E (28484) esp-tls-wolfssl: wolfSSL_connect returned -1, error code: -188
155+
E (28484) esp-tls-wolfssl: Failed to verify peer certificate , returned 24
156+
E (28494) esp-tls: Failed to open new connection
157+
E (28504) transport_base: Failed to open a new connection
158+
E (28514) HTTP_CLIENT: Connection failed, sock < 0
159+
E (28514) HTTP_CLIENT: HTTP request failed: ESP_ERR_HTTP_CONNECT
160+
```
161+
162+
The problem here is that the example [esp_http_client](https://github.com/espressif/esp-idf/tree/master/examples/protocols/esp_http_client)
163+
app _does not work_ immediately out of the box unless changes are made to the source:
164+
165+
```
166+
#ifdef CONFIG_ESP_TLS_USING_WOLFSSL
167+
#include <wolfssl/wolfcrypt/settings.h>
168+
#include <wolfssl/wolfcrypt/port/Espressif/esp-sdk-lib.h>
169+
170+
/* TODO: conditional bundle */
171+
#include <wolfssl/wolfcrypt/port/Espressif/esp_crt_bundle.h>
172+
#endif
173+
```
174+
175+
` openssl s_client -connect postman-echo.com:443 -CAfile ./postman.pem`
176+
177+
### Component esp-wolfssl needs to be installed
178+
179+
The wrong ESP-IDF toolchain is being used. Use the [gojimmypi my_522 branch](https://github.com/gojimmypi/esp-idf/tree/my_522).
180+
181+
```
182+
-- Component esp-wolfssl needs to be installed. See api-reference/protocols/esp_tls docs.
183+
CMake Error at /mnt/c/SysGCC/esp32/esp-idf/v5.2/tools/cmake/component.cmake:382 (message):
184+
Component esp-wolfssl not found
185+
Call Stack (most recent call first):
186+
/mnt/c/SysGCC/esp32/esp-idf/v5.2/components/esp-tls/CMakeLists.txt:26 (idf_component_get_property)
187+
188+
189+
-- Configuring incomplete, errors occurred!
190+
```
191+
192+
## x509_crt_bundle_wolfssl.S not found
193+
194+
It is important to note that PlatformIO components can NOT be used for esp-tls.
195+
196+
The wolfSSL library MUST be used from either the local project `components` or from the ESP-IDF.
197+
198+
```
199+
*** [.pio\bld_8mb_dbg_wolfssl\.pio\bld_8mb_dbg_wolfssl\x509_crt_bundle_wolfssl.S.o]
200+
Source `.pio\bld_8mb_dbg_wolfssl\x509_crt_bundle_wolfssl.S' not found,
201+
needed by target `.pio\bld_8mb_dbg_wolfssl\.pio\bld_8mb_dbg_wolfssl\x509_crt_bundle_wolfssl.S.o'.
202+
```
203+
204+
205+
## Error couldn't get hostname for not.existent.url
206+
207+
This error is as desired, showing that a bad URL will fail.
208+
209+
```
210+
E (50613) esp-tls: couldn't get hostname for :not.existent.url: getaddrinfo() returns 202, addrinfo=0x0
211+
E (50613) esp-tls: Failed to open new connection
212+
E (50613) transport_base: Failed to open a new connection
213+
E (50623) HTTP_CLIENT: Connection failed, sock < 0
214+
E (50623) HTTP_CLIENT: Error perform http request ESP_ERR_HTTP_CONNECT
215+
```
216+
217+
## Tool doesn't match supported version from list
218+
219+
Edit the `C:\Users\%USER%\.platformio\packages\framework-espidf\tools\tools.json` and replace
220+
`13.2.0_20230928` with the desired version, such as `esp-13.2.0_20240530`.
221+
222+
```
223+
Tool doesn't match supported version from list ['esp-13.2.0_20230928']:
224+
C:/Users/gojimmypi/.platformio/packages/toolchain-xtensa-esp-elf/bin/xtensa-esp32-elf-gcc.exe
225+
```
226+
227+
## ESP_ERROR_CHECK failed: esp_err_t 0xffffffff (ESP_FAIL) at 0x400d3b60
228+
229+
This is a generic `ESP_ERROR_CHECK` result, in this case the default WiFi SSID and password could not connect:
230+
231+
232+
```
233+
I (25970) example_connect: Wi-Fi disconnected, trying to reconnect...
234+
I (28380) example_connect: WiFi Connect failed 7 times, stop reconnect.
235+
ESP_ERROR_CHECK failed: esp_err_t 0xffffffff (ESP_FAIL) at 0x400d3b60
236+
file: "main/esp_http_client_example.c" line 936
237+
func: app_main
238+
expression: example_connect()
239+
240+
abort() was called at PC 0x400890e3 on core 0
241+
```
242+
243+
## Manual Testing
244+
245+
To test if the `howsmyssl` web site has TLS 1.3 working, use the [wolfSSL client example](https://github.com/wolfSSL/wolfssl/tree/master/examples/client):
246+
247+
```bash
248+
./examples/client/client -v 4 -h www.howsmyssl.com -p 443 -g -j
249+
```
250+
251+
Or OpenSSL:
252+
253+
```bash
254+
openssl s_client -connect www.howsmyssl.com:443 -tls1_3 -ciphersuites 'TLS_AES_256_GCM_SHA384'
255+
```
256+
257+
Returns this unintuitive error:
258+
259+
```text
260+
$ openssl s_client -connect www.howsmyssl.com:443 -tls1_3 -ciphersuites 'TLS_AES_256_GCM_SHA384'
261+
CONNECTED(00000003)
262+
4007DA6C617F0000:error:0A000410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:../ssl/record/rec_layer_s3.c:1584:SSL alert number 40
263+
---
264+
no peer certificate available
265+
---
266+
No client certificate CA names sent
267+
---
268+
SSL handshake has read 7 bytes and written 247 bytes
269+
Verification: OK
270+
---
271+
New, (NONE), Cipher is (NONE)
272+
Secure Renegotiation IS NOT supported
273+
Compression: NONE
274+
Expansion: NONE
275+
No ALPN negotiated
276+
Early data was not sent
277+
Verify return code: 0 (ok)
278+
---
279+
```
280+
281+
282+
283+
Or OpenSSL,
284+
285+
```bash
286+
openssl s_client -tls1_3 -host www.howsmyssl.com -port 443
287+
```

0 commit comments

Comments
 (0)