mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-21 10:26:06 +03:00
Fix MFLN probe and allow returning whether MFLN succeeded or not after a connection. (#6000)
Fixes #5996 * Add extensions to probe message for EC, others probeMFLN was failing on some connection attempts to servers which only supported EC based ciphers because it did not include the proper TLS handshake extensions to list what kinds of ECs it supported. Add those to the probeMFLN ClientHello message to make probes pass. * Add client.getMFLNStatus method, returns MFLN state After a connection it is useful to check whether MFLN negotiation succeeded. getMFLNStatus returns a bool (valid only after client.connect() succeeds, of course) indicating whether the requested buffer sizes were negotiated successfully.
This commit is contained in:
parent
d9b0480f09
commit
f6dd826437
@ -180,6 +180,11 @@ Once you have verified (or know beforehand) that MFLN is supported you can use t
|
|||||||
|
|
||||||
In certain applications where the TLS server does not support MFLN (not many do as of this writing as it is relatively new to OpenSSL), but you control both the ESP8266 and the server to which it is communicating, you may still be able to `setBufferSizes()` smaller if you guarantee no chunk of data will overflow those buffers.
|
In certain applications where the TLS server does not support MFLN (not many do as of this writing as it is relatively new to OpenSSL), but you control both the ESP8266 and the server to which it is communicating, you may still be able to `setBufferSizes()` smaller if you guarantee no chunk of data will overflow those buffers.
|
||||||
|
|
||||||
|
bool getMFLNStatus()
|
||||||
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
After a successful connection, this method returns whether or not MFLN negotiation succeeded or not. If it did not succeed, and you reduced the receive buffer with `setBufferSizes` then you may experience reception errors if the server attempts to send messages larger than your receive buffer.
|
||||||
|
|
||||||
Sessions (Resuming connections fast)
|
Sessions (Resuming connections fast)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -87,6 +87,7 @@ int fetchMaxFragmentLength() {
|
|||||||
}
|
}
|
||||||
client.connect("tls.mbed.org", 443);
|
client.connect("tls.mbed.org", 443);
|
||||||
if (client.connected()) {
|
if (client.connected()) {
|
||||||
|
Serial.printf("MFLN status: %s\n", client.getMFLNStatus() ? "true" : "false");
|
||||||
Serial.printf("Memory used: %d\n", ret - ESP.getFreeHeap());
|
Serial.printf("Memory used: %d\n", ret - ESP.getFreeHeap());
|
||||||
ret -= ESP.getFreeHeap();
|
ret -= ESP.getFreeHeap();
|
||||||
fetch(&client);
|
fetch(&client);
|
||||||
|
@ -183,6 +183,7 @@ setBufferSizes KEYWORD2
|
|||||||
getLastSSLError KEYWORD2
|
getLastSSLError KEYWORD2
|
||||||
setCertStore KEYWORD2
|
setCertStore KEYWORD2
|
||||||
probeMaxFragmentLength KEYWORD2
|
probeMaxFragmentLength KEYWORD2
|
||||||
|
getMFLNStatus KEYWORD2
|
||||||
|
|
||||||
#WiFiServerBearSSL
|
#WiFiServerBearSSL
|
||||||
setRSACert KEYWORD2
|
setRSACert KEYWORD2
|
||||||
|
@ -965,6 +965,7 @@ bool WiFiClientSecure::_connectSSL(const char* hostName) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
br_ssl_engine_set_buffers_bidi(_eng, _iobuf_in.get(), _iobuf_in_size, _iobuf_out.get(), _iobuf_out_size);
|
br_ssl_engine_set_buffers_bidi(_eng, _iobuf_in.get(), _iobuf_in_size, _iobuf_out.get(), _iobuf_out_size);
|
||||||
|
|
||||||
// Apply any client certificates, if supplied.
|
// Apply any client certificates, if supplied.
|
||||||
if (_sk && _sk->isRSA()) {
|
if (_sk && _sk->isRSA()) {
|
||||||
br_ssl_client_set_single_rsa(_sc.get(), _chain ? _chain->getX509Certs() : nullptr, _chain ? _chain->getCount() : 0,
|
br_ssl_client_set_single_rsa(_sc.get(), _chain ? _chain->getX509Certs() : nullptr, _chain ? _chain->getCount() : 0,
|
||||||
@ -1257,7 +1258,13 @@ bool WiFiClientSecure::probeMaxFragmentLength(IPAddress ip, uint16_t port, uint1
|
|||||||
// 0xc0, 0x13, // BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
|
// 0xc0, 0x13, // BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
|
||||||
static const uint8_t clientHelloTail_P[] PROGMEM = {
|
static const uint8_t clientHelloTail_P[] PROGMEM = {
|
||||||
0x01, 0x00, // No compression
|
0x01, 0x00, // No compression
|
||||||
0x00, 0x05, // Extension length
|
0x00, 26 + 14 + 6 + 5, // Extension length
|
||||||
|
0x00, 0x0d, 0x00, 0x16, 0x00, 0x14, 0x04, 0x03, 0x03, 0x03, 0x05, 0x03,
|
||||||
|
0x06, 0x03, 0x02, 0x03, 0x04, 0x01, 0x03, 0x01, 0x05, 0x01, 0x06,
|
||||||
|
0x01, 0x02, 0x01, // Supported signature algorithms
|
||||||
|
0x00, 0x0a, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x17, 0x00, 0x18, 0x00, 0x19,
|
||||||
|
0x00, 0x1d, // Supported groups
|
||||||
|
0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, // Supported EC formats
|
||||||
0x00, 0x01, // Max Frag Len
|
0x00, 0x01, // Max Frag Len
|
||||||
0x00, 0x01, // len of MaxFragLen
|
0x00, 0x01, // len of MaxFragLen
|
||||||
};
|
};
|
||||||
@ -1322,6 +1329,8 @@ bool WiFiClientSecure::probeMaxFragmentLength(IPAddress ip, uint16_t port, uint1
|
|||||||
uint8_t sessionLen;
|
uint8_t sessionLen;
|
||||||
uint8_t cipher[2];
|
uint8_t cipher[2];
|
||||||
uint8_t comp;
|
uint8_t comp;
|
||||||
|
uint8_t extBytes[2];
|
||||||
|
uint16_t extLen;
|
||||||
|
|
||||||
ret = probe.readBytes(fragResp, 5);
|
ret = probe.readBytes(fragResp, 5);
|
||||||
if (!probe.connected() || (ret != 5) || (fragResp[0] != 0x16) || (fragResp[1] != 0x03) || (fragResp[2] != 0x03)) {
|
if (!probe.connected() || (ret != 5) || (fragResp[0] != 0x16) || (fragResp[1] != 0x03) || (fragResp[2] != 0x03)) {
|
||||||
@ -1388,10 +1397,40 @@ bool WiFiClientSecure::probeMaxFragmentLength(IPAddress ip, uint16_t port, uint1
|
|||||||
// short read or invalid compression
|
// short read or invalid compression
|
||||||
return _SendAbort(probe, supportsLen);
|
return _SendAbort(probe, supportsLen);
|
||||||
}
|
}
|
||||||
if (handLen > 0) {
|
|
||||||
// At this point, having an extension present means that the extension we
|
ret = probe.readBytes(extBytes, 2);
|
||||||
// sent was accepted.
|
handLen -= ret;
|
||||||
supportsLen = true;
|
extLen = extBytes[1] || (extBytes[0]<<8);
|
||||||
|
if ((extLen == 0) || (ret != 2)) {
|
||||||
|
return _SendAbort(probe, supportsLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (handLen > 0) {
|
||||||
|
// Parse each extension and look for MFLN
|
||||||
|
uint8_t typeBytes[2];
|
||||||
|
ret = probe.readBytes(typeBytes, 2);
|
||||||
|
handLen -= 2;
|
||||||
|
if ((ret != 2) || (handLen <= 0) ) {
|
||||||
|
return _SendAbort(probe, supportsLen);
|
||||||
|
}
|
||||||
|
uint8_t lenBytes[2];
|
||||||
|
ret = probe.readBytes(lenBytes, 2);
|
||||||
|
handLen -= 2;
|
||||||
|
uint16_t extLen = lenBytes[1] | (lenBytes[0]<<8);
|
||||||
|
if ((ret != 2) || (handLen <= 0) || (extLen > 32) || (extLen > handLen) ) {
|
||||||
|
return _SendAbort(probe, supportsLen);
|
||||||
|
}
|
||||||
|
if ((typeBytes[0]==0x00) && (typeBytes[1]==0x01)) { // MFLN extension!
|
||||||
|
// If present and 1-byte in length, it's supported
|
||||||
|
return _SendAbort(probe, extLen==1 ? true : false);
|
||||||
|
}
|
||||||
|
// Skip the extension, move to next one
|
||||||
|
uint8_t junk[32];
|
||||||
|
ret = probe.readBytes(junk, extLen);
|
||||||
|
handLen -= extLen;
|
||||||
|
if (ret != extLen) {
|
||||||
|
return _SendAbort(probe, supportsLen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return _SendAbort(probe, supportsLen);
|
return _SendAbort(probe, supportsLen);
|
||||||
}
|
}
|
||||||
|
@ -103,6 +103,11 @@ class WiFiClientSecure : public WiFiClient {
|
|||||||
// Sets the requested buffer size for transmit and receive
|
// Sets the requested buffer size for transmit and receive
|
||||||
void setBufferSizes(int recv, int xmit);
|
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
|
// 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);
|
int getLastSSLError(char *dest = NULL, size_t len = 0);
|
||||||
|
|
||||||
@ -117,7 +122,7 @@ class WiFiClientSecure : public WiFiClient {
|
|||||||
bool setCiphers(std::vector<uint16_t> list);
|
bool setCiphers(std::vector<uint16_t> list);
|
||||||
bool setCiphersLessSecure(); // Only use the limited set of RSA ciphers without EC
|
bool setCiphersLessSecure(); // Only use the limited set of RSA ciphers without EC
|
||||||
|
|
||||||
// Check for Maximum Fragment Length support for given len
|
// 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(IPAddress ip, uint16_t port, uint16_t len);
|
||||||
static bool probeMaxFragmentLength(const char *hostname, 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);
|
static bool probeMaxFragmentLength(const String& host, uint16_t port, uint16_t len);
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
// Do not edit -- Automatically generated by tools/sdk/ssl/bearssl/Makefile
|
// Do not edit -- Automatically generated by tools/sdk/ssl/bearssl/Makefile
|
||||||
#define BEARSSL_GIT 6778687
|
#define BEARSSL_GIT a143020
|
||||||
|
@ -724,7 +724,7 @@ void br_sha256_update(br_sha256_context *ctx, const void *data, size_t len);
|
|||||||
*/
|
*/
|
||||||
void br_sha256_out(const br_sha256_context *ctx, void *out);
|
void br_sha256_out(const br_sha256_context *ctx, void *out);
|
||||||
|
|
||||||
#if BR_DOXYGEN_IGNORE
|
#ifdef BR_DOXYGEN_IGNORE
|
||||||
/**
|
/**
|
||||||
* \brief Save SHA-256 running state.
|
* \brief Save SHA-256 running state.
|
||||||
*
|
*
|
||||||
@ -742,7 +742,7 @@ uint64_t br_sha256_state(const br_sha256_context *ctx, void *out);
|
|||||||
#define br_sha256_state br_sha224_state
|
#define br_sha256_state br_sha224_state
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if BR_DOXYGEN_IGNORE
|
#ifdef BR_DOXYGEN_IGNORE
|
||||||
/**
|
/**
|
||||||
* \brief Restore SHA-256 running state.
|
* \brief Restore SHA-256 running state.
|
||||||
*
|
*
|
||||||
|
@ -864,6 +864,7 @@ typedef struct {
|
|||||||
*/
|
*/
|
||||||
uint16_t max_frag_len;
|
uint16_t max_frag_len;
|
||||||
unsigned char log_max_frag_len;
|
unsigned char log_max_frag_len;
|
||||||
|
unsigned char max_frag_len_negotiated;
|
||||||
unsigned char peer_log_max_frag_len;
|
unsigned char peer_log_max_frag_len;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1830,6 +1831,17 @@ void br_ssl_engine_set_buffer(br_ssl_engine_context *cc,
|
|||||||
void br_ssl_engine_set_buffers_bidi(br_ssl_engine_context *cc,
|
void br_ssl_engine_set_buffers_bidi(br_ssl_engine_context *cc,
|
||||||
void *ibuf, size_t ibuf_len, void *obuf, size_t obuf_len);
|
void *ibuf, size_t ibuf_len, void *obuf, size_t obuf_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Determine if MFLN negotiation was successful
|
||||||
|
*
|
||||||
|
* \param cc SSL engine context.
|
||||||
|
*/
|
||||||
|
static inline uint8_t
|
||||||
|
br_ssl_engine_get_mfln_negotiated(br_ssl_engine_context *cc)
|
||||||
|
{
|
||||||
|
return cc->max_frag_len_negotiated;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Inject some "initial entropy" in the context.
|
* \brief Inject some "initial entropy" in the context.
|
||||||
*
|
*
|
||||||
|
Binary file not shown.
@ -1 +1 @@
|
|||||||
Subproject commit 67786877341aac98c62e3b765fc64f4c49d81370
|
Subproject commit a143020fe65e2ae11a4f96485c903b6133e1bbc7
|
Loading…
x
Reference in New Issue
Block a user