diff --git a/doc/esp8266wifi/bearssl-client-secure-class.rst b/doc/esp8266wifi/bearssl-client-secure-class.rst index e3ced20ae5..4eee8ef54a 100644 --- a/doc/esp8266wifi/bearssl-client-secure-class.rst +++ b/doc/esp8266wifi/bearssl-client-secure-class.rst @@ -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. +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) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/libraries/ESP8266WiFi/examples/BearSSL_MaxFragmentLength/BearSSL_MaxFragmentLength.ino b/libraries/ESP8266WiFi/examples/BearSSL_MaxFragmentLength/BearSSL_MaxFragmentLength.ino index f05210283b..62b5f03343 100644 --- a/libraries/ESP8266WiFi/examples/BearSSL_MaxFragmentLength/BearSSL_MaxFragmentLength.ino +++ b/libraries/ESP8266WiFi/examples/BearSSL_MaxFragmentLength/BearSSL_MaxFragmentLength.ino @@ -87,6 +87,7 @@ int fetchMaxFragmentLength() { } client.connect("tls.mbed.org", 443); if (client.connected()) { + Serial.printf("MFLN status: %s\n", client.getMFLNStatus() ? "true" : "false"); Serial.printf("Memory used: %d\n", ret - ESP.getFreeHeap()); ret -= ESP.getFreeHeap(); fetch(&client); diff --git a/libraries/ESP8266WiFi/keywords.txt b/libraries/ESP8266WiFi/keywords.txt index 7abf2978ef..b24bfc598e 100644 --- a/libraries/ESP8266WiFi/keywords.txt +++ b/libraries/ESP8266WiFi/keywords.txt @@ -183,6 +183,7 @@ setBufferSizes KEYWORD2 getLastSSLError KEYWORD2 setCertStore KEYWORD2 probeMaxFragmentLength KEYWORD2 +getMFLNStatus KEYWORD2 #WiFiServerBearSSL setRSACert KEYWORD2 diff --git a/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp index e2f35b51ed..67f0df6e65 100644 --- a/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp +++ b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp @@ -965,6 +965,7 @@ bool WiFiClientSecure::_connectSSL(const char* hostName) { return false; } 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. if (_sk && _sk->isRSA()) { 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 static const uint8_t clientHelloTail_P[] PROGMEM = { 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, // len of MaxFragLen }; @@ -1322,6 +1329,8 @@ bool WiFiClientSecure::probeMaxFragmentLength(IPAddress ip, uint16_t port, uint1 uint8_t sessionLen; uint8_t cipher[2]; uint8_t comp; + uint8_t extBytes[2]; + uint16_t extLen; ret = probe.readBytes(fragResp, 5); 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 return _SendAbort(probe, supportsLen); } - if (handLen > 0) { - // At this point, having an extension present means that the extension we - // sent was accepted. - supportsLen = true; + + ret = probe.readBytes(extBytes, 2); + handLen -= ret; + 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); } diff --git a/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h index 0ac9003c78..c9d4f4fb34 100644 --- a/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h +++ b/libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h @@ -103,6 +103,11 @@ class WiFiClientSecure : public WiFiClient { // 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); @@ -117,7 +122,7 @@ class WiFiClientSecure : public WiFiClient { bool setCiphers(std::vector list); 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(const char *hostname, uint16_t port, uint16_t len); static bool probeMaxFragmentLength(const String& host, uint16_t port, uint16_t len); diff --git a/tools/sdk/include/bearssl/bearssl_git.h b/tools/sdk/include/bearssl/bearssl_git.h index 87c14dd9b8..f18263befc 100644 --- a/tools/sdk/include/bearssl/bearssl_git.h +++ b/tools/sdk/include/bearssl/bearssl_git.h @@ -1,2 +1,2 @@ // Do not edit -- Automatically generated by tools/sdk/ssl/bearssl/Makefile -#define BEARSSL_GIT 6778687 +#define BEARSSL_GIT a143020 diff --git a/tools/sdk/include/bearssl/bearssl_hash.h b/tools/sdk/include/bearssl/bearssl_hash.h index 3b15ba7ca4..ca4fa26cc4 100644 --- a/tools/sdk/include/bearssl/bearssl_hash.h +++ b/tools/sdk/include/bearssl/bearssl_hash.h @@ -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); -#if BR_DOXYGEN_IGNORE +#ifdef BR_DOXYGEN_IGNORE /** * \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 #endif -#if BR_DOXYGEN_IGNORE +#ifdef BR_DOXYGEN_IGNORE /** * \brief Restore SHA-256 running state. * diff --git a/tools/sdk/include/bearssl/bearssl_ssl.h b/tools/sdk/include/bearssl/bearssl_ssl.h index 8c8c86bdb5..0393e1f963 100644 --- a/tools/sdk/include/bearssl/bearssl_ssl.h +++ b/tools/sdk/include/bearssl/bearssl_ssl.h @@ -864,6 +864,7 @@ typedef struct { */ uint16_t max_frag_len; unsigned char log_max_frag_len; + unsigned char max_frag_len_negotiated; 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 *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. * diff --git a/tools/sdk/lib/libbearssl.a b/tools/sdk/lib/libbearssl.a index 23ade6f0bf..32ecbf71b9 100644 Binary files a/tools/sdk/lib/libbearssl.a and b/tools/sdk/lib/libbearssl.a differ diff --git a/tools/sdk/ssl/bearssl b/tools/sdk/ssl/bearssl index 6778687734..a143020fe6 160000 --- a/tools/sdk/ssl/bearssl +++ b/tools/sdk/ssl/bearssl @@ -1 +1 @@ -Subproject commit 67786877341aac98c62e3b765fc64f4c49d81370 +Subproject commit a143020fe65e2ae11a4f96485c903b6133e1bbc7