forked from espressif/arduino-esp32
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathWiFIClientSecureProtocolUpgradeSTARTTLS.ino
179 lines (134 loc) · 4.69 KB
/
WiFIClientSecureProtocolUpgradeSTARTTLS.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/* STARTSSL example
Inline upgrading from a clear-text connection to an SSL/TLS connection.
Some protocols such as SMTP, XMPP, Mysql, Postgress and others allow, or require,
that you start the connection without encryption; and then send a command to switch
over to encryption.
E.g. a typical SMTP submission would entail a dialogue such as this:
1. client connects to server in the clear
2. server says hello
3. client sents a EHLO
4. server tells the client that it supports SSL/TLS
5. client sends a 'STARTTLS' to make use of this faciltiy
6. client/server negiotiate a SSL or TLS connection.
7. client sends another EHLO
8. server now tells the client what (else) is supported; such as additional authentication options.
... conversation continues encrypted.
This can be enabled in WiFiClientSecure by telling it to start in plaintext:
client.setPlainStart();
and client is than a plain, TCP, connection (just as WiFiClient would be); until the client calls
the method:
client.startTLS(); // returns zero on error; non zero on success.
After which things switch to TLS/SSL.
*/
#include <WiFiClientSecure.h>
#ifndef WIFI_NETWORK
#define WIFI_NETWORK "YOUR Wifi SSID"
#endif
#ifndef WIFI_PASSWD
#define WIFI_PASSWD "your-secret-password"
#endif
#ifndef SMTP_HOST
#define SMTP_HOST "smtp.gmail.com"
#endif
#ifndef SMTP_PORT
#define SMTP_PORT (587) // Standard (plaintext) submission port
#endif
const char* ssid = WIFI_NETWORK; // your network SSID (name of wifi network)
const char* password = WIFI_PASSWD; // your network password
const char* server = SMTP_HOST; // Server URL
const int submission_port = SMTP_PORT; // submission port.
WiFiClientSecure client;
static bool readAllSMTPLines();
void setup() {
int ret;
//Initialize serial and wait for port to open:
Serial.begin(115200);
delay(100);
Serial.print("Attempting to connect to SSID: ");
Serial.print(ssid);
WiFi.begin(ssid, password);
// attempt to connect to Wifi network:
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
// wait 1 second for re-trying
delay(1000);
}
Serial.print("Connected to ");
Serial.println(ssid);
Serial.printf("\nStarting connection to server: %s:%d\n", server, submission_port);
// skip verification for this demo. In production one should at the very least
// enable TOFU; or ideally hardcode a (CA) certificate that is trusted.
//
client.setInsecure();
// Enable a plain-test start.
client.setPlainStart();
if (!client.connect(server, SMTP_PORT)) {
Serial.println("Connection failed!");
return;
};
Serial.println("Connected to server (in the clear, in plaintest)");
if (!readAllSMTPLines()) goto err;
Serial.println("Sending : EHLO\t\tin the clear");
client.print("EHLO there\r\n");
if (!readAllSMTPLines()) goto err;
Serial.println("Sending : STARTTLS\t\tin the clear");
client.print("STARTTLS\r\n");
if (!readAllSMTPLines()) goto err;
Serial.println("Upgrading connection to TLS");
if ((ret=client.startTLS()) <= 0) {
Serial.printf("Upgrade connection failed: err %d\n", ret);
goto err;
}
Serial.println("Sending : EHLO again\t\tover the now encrypted connection");
client.print("EHLO again\r\n");
if (!readAllSMTPLines()) goto err;
// normally, as this point - we'd be authenticating and then be submitting
// an email. This has been left out of this example.
Serial.println("Sending : QUIT\t\t\tover the now encrypted connection");
client.print("QUIT\r\n");
if (!readAllSMTPLines()) goto err;
Serial.println("Completed OK\n");
err:
Serial.println("Closing connection");
client.stop();
}
// SMTP command repsponse start with three digits and a space;
// or, for continuation, with three digits and a '-'.
//
static bool readAllSMTPLines() {
String s = "";
int i;
// blocking read; we cannot rely on a timeout
// of a WiFiClientSecure read; as it is non
// blocking.
//
const unsigned long timeout = 15 * 1000;
unsigned long start = millis(); // the timeout is for the entire CMD block response; not per character/line.
while (1) {
while ((i = client.available()) == 0 && millis() - start < timeout) {
/* .. wait */
};
if (i == 0) {
Serial.println("Timeout reading SMTP response");
return false;
};
if (i < 0)
break;
i = client.read();
if (i < 0)
break;
if (i > 31 && i < 128) s += (char)i;
if (i == 0x0A) {
Serial.print("Receiving: ");
Serial.println(s);
if (s.charAt(3) == ' ')
return true;
s = "";
}
}
Serial.printf("Error reading SMTP command response line: %d\n", i);
return false;
}
void loop() {
// do nothing
}