Skip to content

Commit

Permalink
Fix MFLN probe and allow returning whether MFLN succeeded or not afte…
Browse files Browse the repository at this point in the history
…r 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.
  • Loading branch information
earlephilhower committed Apr 25, 2019
1 parent d9b0480 commit f6dd826
Show file tree
Hide file tree
Showing 10 changed files with 73 additions and 10 deletions.
5 changes: 5 additions & 0 deletions doc/esp8266wifi/bearssl-client-secure-class.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions libraries/ESP8266WiFi/keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ setBufferSizes KEYWORD2
getLastSSLError KEYWORD2
setCertStore KEYWORD2
probeMaxFragmentLength KEYWORD2
getMFLNStatus KEYWORD2

#WiFiServerBearSSL
setRSACert KEYWORD2
Expand Down
49 changes: 44 additions & 5 deletions libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
};
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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);
}
Expand Down
7 changes: 6 additions & 1 deletion libraries/ESP8266WiFi/src/WiFiClientSecureBearSSL.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -117,7 +122,7 @@ class WiFiClientSecure : public WiFiClient {
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
// 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);
Expand Down
2 changes: 1 addition & 1 deletion tools/sdk/include/bearssl/bearssl_git.h
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// Do not edit -- Automatically generated by tools/sdk/ssl/bearssl/Makefile
#define BEARSSL_GIT 6778687
#define BEARSSL_GIT a143020
4 changes: 2 additions & 2 deletions tools/sdk/include/bearssl/bearssl_hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand All @@ -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.
*
Expand Down
12 changes: 12 additions & 0 deletions tools/sdk/include/bearssl/bearssl_ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/*
Expand Down Expand Up @@ -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.
*
Expand Down
Binary file modified tools/sdk/lib/libbearssl.a
Binary file not shown.

0 comments on commit f6dd826

Please sign in to comment.