-
Notifications
You must be signed in to change notification settings - Fork 13.3k
/
WiFiClientSecureBearSSL.h
282 lines (233 loc) · 10.6 KB
/
WiFiClientSecureBearSSL.h
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
/*
WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries
- Mostly compatible with Arduino WiFi shield library and standard
WiFiClient/ServerSecure (except for certificate handling).
Copyright (c) 2018 Earle F. Philhower, III
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef wificlientbearssl_h
#define wificlientbearssl_h
#include <vector>
#include "WiFiClient.h"
#include <bearssl/bearssl.h>
#include "BearSSLHelpers.h"
#include "CertStoreBearSSL.h"
namespace BearSSL {
class WiFiClientSecure : public WiFiClient {
public:
WiFiClientSecure();
WiFiClientSecure(const WiFiClientSecure &rhs);
~WiFiClientSecure() override;
WiFiClientSecure& operator=(const WiFiClientSecure&) = default; // The shared-ptrs handle themselves automatically
int connect(IPAddress ip, uint16_t port) override;
int connect(const String& host, uint16_t port) override;
int connect(const char* name, uint16_t port) override;
uint8_t connected() override;
size_t write(const uint8_t *buf, size_t size) override;
size_t write_P(PGM_P buf, size_t size) override;
size_t write(const char *buf) {
return write((const uint8_t*)buf, strlen(buf));
}
size_t write_P(const char *buf) {
return write_P((PGM_P)buf, strlen_P(buf));
}
size_t write(Stream& stream); // Note this is not virtual
int read(uint8_t *buf, size_t size) override;
int available() override;
int read() override;
int peek() override;
size_t peekBytes(uint8_t *buffer, size_t length) override;
bool flush(unsigned int maxWaitMs);
bool stop(unsigned int maxWaitMs);
void flush() override { (void)flush(0); }
void stop() override { (void)stop(0); }
// Allow sessions to be saved/restored automatically to a memory area
void setSession(Session *session) { _session = session; }
// Don't validate the chain, just accept whatever is given. VERY INSECURE!
void setInsecure() {
_clearAuthenticationSettings();
_use_insecure = true;
}
// Assume a given public key, don't validate or use cert info at all
void setKnownKey(const PublicKey *pk, unsigned usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN) {
_clearAuthenticationSettings();
_knownkey = pk;
_knownkey_usages = usages;
}
// Only check SHA1 fingerprint of certificate
bool setFingerprint(const uint8_t fingerprint[20]) {
_clearAuthenticationSettings();
_use_fingerprint = true;
memcpy_P(_fingerprint, fingerprint, 20);
return true;
}
bool setFingerprint(const char *fpStr);
// Accept any certificate that's self-signed
void allowSelfSignedCerts() {
_clearAuthenticationSettings();
_use_self_signed = true;
}
// Install certificates of trusted CAs or specific site
void setTrustAnchors(const X509List *ta) {
_clearAuthenticationSettings();
_ta = ta;
}
// In cases when NTP is not used, app must set a time manually to check cert validity
void setX509Time(time_t now) {
_now = now;
}
// Install a client certificate for this connection, in case the server requires it (i.e. MQTT)
void setClientRSACert(const X509List *cert, const PrivateKey *sk);
void setClientECCert(const X509List *cert, const PrivateKey *sk,
unsigned allowed_usages, unsigned cert_issuer_key_type);
// Sets the requested buffer size for transmit and receive
void setBufferSizes(int recv, int xmit);
// Returns whether MFLN negotiation for the above buffer sizes succeeded (after connection)
int getMFLNStatus() {
return connected() && br_ssl_engine_get_mfln_negotiated(_eng);
}
// Return an error code and possibly a text string in a passed-in buffer with last SSL failure
int getLastSSLError(char *dest = NULL, size_t len = 0);
// Attach a preconfigured certificate store
void setCertStore(CertStore *certStore) {
_certStore = certStore;
}
// Select specific ciphers (i.e. optimize for speed over security)
// These may be in PROGMEM or RAM, either will run properly
bool setCiphers(const uint16_t *cipherAry, int cipherCount);
bool setCiphers(std::vector<uint16_t> list);
bool setCiphersLessSecure(); // Only use the limited set of RSA ciphers without EC
// Check for Maximum Fragment Length support for given len before connection (possibly insecure)
static bool probeMaxFragmentLength(IPAddress ip, uint16_t port, uint16_t len);
static bool probeMaxFragmentLength(const char *hostname, uint16_t port, uint16_t len);
static bool probeMaxFragmentLength(const String& host, uint16_t port, uint16_t len);
////////////////////////////////////////////////////
// AxTLS API deprecated warnings to help upgrading
#define AXTLS_DEPRECATED \
__attribute__((deprecated( \
"This is deprecated AxTLS API, " \
"check https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/src/WiFiClientSecure.h#L25-L99")))
bool setCACert(const uint8_t* pk, size_t size) AXTLS_DEPRECATED;
bool setCertificate(const uint8_t* pk, size_t size) AXTLS_DEPRECATED;
bool setPrivateKey(const uint8_t* pk, size_t size) AXTLS_DEPRECATED;
bool loadCACert(Stream& stream, size_t size) AXTLS_DEPRECATED;
bool loadCertificate(Stream& stream, size_t size) AXTLS_DEPRECATED;
bool loadPrivateKey(Stream& stream, size_t size) AXTLS_DEPRECATED;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
bool setCACert_P(PGM_VOID_P pk, size_t size) AXTLS_DEPRECATED {
return setCACert((const uint8_t *)pk, size);
}
bool setCertificate_P(PGM_VOID_P pk, size_t size) AXTLS_DEPRECATED {
return setCertificate((const uint8_t *)pk, size);
}
bool setPrivateKey_P(PGM_VOID_P pk, size_t size) AXTLS_DEPRECATED {
return setPrivateKey((const uint8_t *)pk, size);
}
#pragma GCC diagnostic pop
template<typename TFile>
bool loadCertificate(TFile& file) {
return loadCertificate(file, file.size());
}
template<typename TFile>
bool loadPrivateKey(TFile& file) {
return loadPrivateKey(file, file.size());
}
template<typename TFile>
bool loadCACert(TFile& file) {
return loadCACert(file, file.size());
}
bool verify(const char* fingerprint, const char* domain_name) AXTLS_DEPRECATED {
(void)fingerprint;
(void)domain_name;
return connected();
}
bool verifyCertChain(const char* domain_name) AXTLS_DEPRECATED {
(void)domain_name;
return connected();
}
// AxTLS API deprecated section end
/////////////////////////////////////
protected:
bool _connectSSL(const char *hostName); // Do initial SSL handshake
private:
void _clear();
void _clearAuthenticationSettings();
// Only one of the following two should ever be != nullptr!
std::shared_ptr<br_ssl_client_context> _sc;
std::shared_ptr<br_ssl_server_context> _sc_svr;
inline bool ctx_present() {
return (_sc != nullptr) || (_sc_svr != nullptr);
}
br_ssl_engine_context *_eng; // &_sc->eng, to allow for client or server contexts
std::shared_ptr<br_x509_minimal_context> _x509_minimal;
std::shared_ptr<struct br_x509_insecure_context> _x509_insecure;
std::shared_ptr<br_x509_knownkey_context> _x509_knownkey;
std::shared_ptr<unsigned char> _iobuf_in;
std::shared_ptr<unsigned char> _iobuf_out;
time_t _now;
const X509List *_ta;
CertStore *_certStore;
int _iobuf_in_size;
int _iobuf_out_size;
bool _handshake_done;
bool _oom_err;
// AXTLS compatibility shim elements:
// AXTLS managed memory for certs and keys, while BearSSL assumes
// the app manages these. Use this local storage for holding the
// BearSSL created objects in a shared form.
std::shared_ptr<X509List> _axtls_ta;
std::shared_ptr<X509List> _axtls_chain;
std::shared_ptr<PrivateKey> _axtls_sk;
// Optional storage space pointer for session parameters
// Will be used on connect and updated on close
Session *_session;
bool _use_insecure;
bool _use_fingerprint;
uint8_t _fingerprint[20];
bool _use_self_signed;
const PublicKey *_knownkey;
unsigned _knownkey_usages;
// Custom cipher list pointer or NULL if default
std::shared_ptr<uint16_t> _cipher_list;
uint8_t _cipher_cnt;
unsigned char *_recvapp_buf;
size_t _recvapp_len;
bool _clientConnected(); // Is the underlying socket alive?
void _freeSSL();
int _run_until(unsigned target, bool blocking = true);
size_t _write(const uint8_t *buf, size_t size, bool pmem);
bool _wait_for_handshake(); // Sets and return the _handshake_done after connecting
// Optional client certificate
const X509List *_chain;
const PrivateKey *_sk;
unsigned _allowed_usages;
unsigned _cert_issuer_key_type;
// Methods for handling server.available() call which returns a client connection.
friend class WiFiServerSecure; // Server needs to access these constructors
WiFiClientSecure(ClientContext *client, const X509List *chain, unsigned cert_issuer_key_type,
const PrivateKey *sk, int iobuf_in_size, int iobuf_out_size, const X509List *client_CA_ta);
WiFiClientSecure(ClientContext* client, const X509List *chain, const PrivateKey *sk,
int iobuf_in_size, int iobuf_out_size, const X509List *client_CA_ta);
// RSA keyed server
bool _connectSSLServerRSA(const X509List *chain, const PrivateKey *sk, const X509List *client_CA_ta);
// EC keyed server
bool _connectSSLServerEC(const X509List *chain, unsigned cert_issuer_key_type, const PrivateKey *sk,
const X509List *client_CA_ta);
// X.509 validators differ from server to client
bool _installClientX509Validator(); // Set up X509 validator for a client conn.
bool _installServerX509Validator(const X509List *client_CA_ta); // Setup X509 client cert validation, if supplied
uint8_t *_streamLoad(Stream& stream, size_t size);
};
};
#endif