Skip to content

Commit 9a6ab11

Browse files
committed
Example exercising TLS capabilities with root certificate verification
This example opens an encrypted TLS connection to www.eff.org on port 443. Once the secure connection is negotiated and verified with the embedded server certificate, this example is very similar to the earlier raw_async_http_request example for plaintext. The compile-time define ASYNC_TCP_SSL_ENABLED must be defined and enabled project-wide for this example to actually enable and use the TLS support.
1 parent 0a20a69 commit 9a6ab11

File tree

1 file changed

+173
-0
lines changed

1 file changed

+173
-0
lines changed
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#include <Arduino.h>
2+
#include <WiFi.h>
3+
#include <AsyncTCP.h>
4+
5+
const char* ssid = "YOUR-WIFI-SSID-HERE";
6+
const char* password = "YOUR-WIFI-PASSWORD-HERE";
7+
8+
#ifndef ASYNC_TCP_SSL_ENABLED
9+
#error The macro ASYNC_TCP_SSL_ENABLED has not been correctly enabled in your environment!
10+
#endif
11+
12+
// To extract root certificate for test:
13+
// openssl s_client -showcerts -connect SSLDOMAIN.ORG:443 < /dev/null
14+
15+
// Root certificate test site (Let's Encrypt)
16+
17+
const char * hostname = "www.eff.org";
18+
19+
const char * rootCACertificate = \
20+
"-----BEGIN CERTIFICATE-----\n" \
21+
"MIIFYDCCBEigAwIBAgIQQAF3ITfU6UK47naqPGQKtzANBgkqhkiG9w0BAQsFADA/\n" \
22+
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" \
23+
"DkRTVCBSb290IENBIFgzMB4XDTIxMDEyMDE5MTQwM1oXDTI0MDkzMDE4MTQwM1ow\n" \
24+
"TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n" \
25+
"cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwggIiMA0GCSqGSIb3DQEB\n" \
26+
"AQUAA4ICDwAwggIKAoICAQCt6CRz9BQ385ueK1coHIe+3LffOJCMbjzmV6B493XC\n" \
27+
"ov71am72AE8o295ohmxEk7axY/0UEmu/H9LqMZshftEzPLpI9d1537O4/xLxIZpL\n" \
28+
"wYqGcWlKZmZsj348cL+tKSIG8+TA5oCu4kuPt5l+lAOf00eXfJlII1PoOK5PCm+D\n" \
29+
"LtFJV4yAdLbaL9A4jXsDcCEbdfIwPPqPrt3aY6vrFk/CjhFLfs8L6P+1dy70sntK\n" \
30+
"4EwSJQxwjQMpoOFTJOwT2e4ZvxCzSow/iaNhUd6shweU9GNx7C7ib1uYgeGJXDR5\n" \
31+
"bHbvO5BieebbpJovJsXQEOEO3tkQjhb7t/eo98flAgeYjzYIlefiN5YNNnWe+w5y\n" \
32+
"sR2bvAP5SQXYgd0FtCrWQemsAXaVCg/Y39W9Eh81LygXbNKYwagJZHduRze6zqxZ\n" \
33+
"Xmidf3LWicUGQSk+WT7dJvUkyRGnWqNMQB9GoZm1pzpRboY7nn1ypxIFeFntPlF4\n" \
34+
"FQsDj43QLwWyPntKHEtzBRL8xurgUBN8Q5N0s8p0544fAQjQMNRbcTa0B7rBMDBc\n" \
35+
"SLeCO5imfWCKoqMpgsy6vYMEG6KDA0Gh1gXxG8K28Kh8hjtGqEgqiNx2mna/H2ql\n" \
36+
"PRmP6zjzZN7IKw0KKP/32+IVQtQi0Cdd4Xn+GOdwiK1O5tmLOsbdJ1Fu/7xk9TND\n" \
37+
"TwIDAQABo4IBRjCCAUIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw\n" \
38+
"SwYIKwYBBQUHAQEEPzA9MDsGCCsGAQUFBzAChi9odHRwOi8vYXBwcy5pZGVudHJ1\n" \
39+
"c3QuY29tL3Jvb3RzL2RzdHJvb3RjYXgzLnA3YzAfBgNVHSMEGDAWgBTEp7Gkeyxx\n" \
40+
"+tvhS5B1/8QVYIWJEDBUBgNVHSAETTBLMAgGBmeBDAECATA/BgsrBgEEAYLfEwEB\n" \
41+
"ATAwMC4GCCsGAQUFBwIBFiJodHRwOi8vY3BzLnJvb3QteDEubGV0c2VuY3J5cHQu\n" \
42+
"b3JnMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jcmwuaWRlbnRydXN0LmNvbS9E\n" \
43+
"U1RST09UQ0FYM0NSTC5jcmwwHQYDVR0OBBYEFHm0WeZ7tuXkAXOACIjIGlj26Ztu\n" \
44+
"MA0GCSqGSIb3DQEBCwUAA4IBAQAKcwBslm7/DlLQrt2M51oGrS+o44+/yQoDFVDC\n" \
45+
"5WxCu2+b9LRPwkSICHXM6webFGJueN7sJ7o5XPWioW5WlHAQU7G75K/QosMrAdSW\n" \
46+
"9MUgNTP52GE24HGNtLi1qoJFlcDyqSMo59ahy2cI2qBDLKobkx/J3vWraV0T9VuG\n" \
47+
"WCLKTVXkcGdtwlfFRjlBz4pYg1htmf5X6DYO8A4jqv2Il9DjXA6USbW1FzXSLr9O\n" \
48+
"he8Y4IWS6wY7bCkjCWDcRQJMEhg76fsO3txE+FiYruq9RUWhiF1myv4Q6W+CyBFC\n" \
49+
"Dfvp7OOGAN6dEOM4+qR9sdjoSYKEBpsr6GtPAQw4dy753ec5\n" \
50+
"-----END CERTIFICATE-----\n";
51+
52+
AsyncClient sslClient;
53+
54+
void setup() {
55+
// put your setup code here, to run once:
56+
57+
Serial.begin(115200);
58+
while (!Serial);
59+
60+
WiFi.mode(WIFI_STA);
61+
62+
WiFi.begin(ssid, password);
63+
64+
Serial.println("Connecting to WiFi SSID: " + String(ssid));
65+
66+
while (WiFi.status() != WL_CONNECTED)
67+
{
68+
delay(500);
69+
Serial.print(".");
70+
}
71+
72+
Serial.print(F("Connected to WiFi @ IP : "));
73+
Serial.println(WiFi.localIP());
74+
75+
// Callbacks for data handling, run in separate task to achieve concurrency
76+
77+
// Callback on successful connection
78+
sslClient.onConnect([](void * ctx_ptr, AsyncClient * client) {
79+
Serial.println("\n\nonConnect successful! sending data...");
80+
81+
// For the sake of this example, buffer will contain outgoing protocol data
82+
// not necessarily produced from static ASCII strings.
83+
char buffer[128];
84+
85+
// Simulating an HTTP request
86+
87+
// ASYNC_WRITE_FLAG_COPY is the default value of the apiflags parameter in AsyncTCPSock
88+
// and can be omitted. Only if the data to be sent is static or long-lived and guaranteed
89+
// to persist until all data has been written, should you consider passing 0 as apiflags,
90+
// which will instead store the passed pointer without performing a copy.
91+
strcpy(buffer, "GET / HTTP/1.1\r\n");
92+
client->add(buffer, strlen(buffer), ASYNC_WRITE_FLAG_COPY);
93+
94+
snprintf(buffer, sizeof(buffer), "Host: %s\r\n", hostname);
95+
client->add(buffer, strlen(buffer), ASYNC_WRITE_FLAG_COPY);
96+
97+
strcpy(buffer, "Connection: close\r\n\r\n");
98+
client->add(buffer, strlen(buffer), ASYNC_WRITE_FLAG_COPY);
99+
100+
client->send();
101+
},
102+
NULL // <-- Pointer to application data, accessible within callback through ctx_ptr
103+
);
104+
105+
// Callback on data ready to be processed - MUST BE CONSUMED AT ONCE or will be discarded
106+
sslClient.onData([](void * ctx_ptr, AsyncClient * client, void * buf, size_t len) {
107+
108+
Serial.printf("\n\nonData received data (%u bytes), raw buffer follows:\r\n", len);
109+
Serial.write((const uint8_t *)buf, len);
110+
111+
},
112+
NULL // <-- Pointer to application data, accessible within callback through ctx_ptr
113+
);
114+
115+
// Callback on written data being acknowledged as sent. If the data written so far fully covers
116+
// a buffer added WITHOUT the ASYNC_WRITE_FLAG_COPY flag, now is the first safe moment at
117+
// which such a buffer area may be discarded or reused.
118+
sslClient.onAck([](void * ctx_ptr, AsyncClient * client, size_t len, uint32_t ms_delay) {
119+
120+
Serial.printf("\n\nonAck acknowledged sending next %u bytes after %u ms\r\n", len, ms_delay);
121+
122+
},
123+
NULL // <-- Pointer to application data, accessible within callback through ctx_ptr
124+
);
125+
126+
// Callback on socket disconnect, called:
127+
// - on any socket close event (local or remote) after being connected
128+
// - on failure to connect, right after the onError callback
129+
sslClient.onDisconnect([](void * ctx_ptr, AsyncClient * client) {
130+
131+
Serial.println("\n\nonDisconnect socket disconnected!");
132+
133+
},
134+
NULL // <-- Pointer to application data, accessible within callback through ctx_ptr
135+
);
136+
137+
// Callback on error event
138+
sslClient.onError([](void * ctx_ptr, AsyncClient * client, int8_t error) {
139+
140+
Serial.printf("\n\nonError socket reported error %d\r\n", error);
141+
142+
},
143+
NULL // <-- Pointer to application data, accessible within callback through ctx_ptr
144+
);
145+
146+
sslClient.setRootCa(rootCACertificate, strlen(rootCACertificate) + 1);
147+
148+
}
149+
150+
uint32_t t_dot = 0;
151+
uint32_t t_req = 0;
152+
void loop() {
153+
uint32_t t = millis();
154+
155+
// This is to show that the main loop() is running while the AsyncClient
156+
// object processes data in the background.
157+
if (t - t_dot >= 200) {
158+
t_dot = t;
159+
Serial.print("*");
160+
}
161+
162+
// Try connecting to remote host if 10 seconds pass after last try
163+
if (t - t_req >= 20000 && sslClient.state() == 0) {
164+
165+
// NOTE: DNS resolving is also done asynchronously (in the LWIP thread)
166+
t_req = t;
167+
Serial.printf("\n\nStarting connection to %s port 443...\r\n", hostname);
168+
sslClient.connect(hostname, 443, true); // <-- Enable encrypted connection on this instance
169+
170+
}
171+
172+
delay(50);
173+
}

0 commit comments

Comments
 (0)