1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-25 20:02:37 +03:00

Add setSSLVersion call to SSL object (#7920)

* Add setSSLVersion call to SSL object

Allow users to only allow specific TLS versions for connections with an
additional call in their app, similar to the setCiphers call.

Fixes #7918

* Add SSL level options to WiFiServerSecure
This commit is contained in:
Earle F. Philhower, III 2021-03-15 12:22:06 -07:00 committed by GitHub
parent dcdd4313cb
commit 7475ba7ff3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 68 additions and 11 deletions

View File

@ -20,7 +20,7 @@ BearSSL doesn't perform memory allocations at runtime, but it does require alloc
. A per-application secondary stack . A per-application secondary stack
. A per-connection TLS receive/transmit buffer plus overhead . A per-connection TLS receive/transmit buffer plus overhead
The per-application secondary stack is approximately 5.6KB in size and is used for temporary variables during BearSSL processing. Only one stack is required, and it will be allocated whenever any `BearSSL::WiFiClientSecure` or `BearSSL::WiFiServerSecure` are instantiated. So, in the case of a global client or server, the memory will be allocated before `setup()` is called. The per-application secondary stack is approximately 6KB in size and is used for temporary variables during BearSSL processing. Only one stack is required, and it will be allocated whenever any `BearSSL::WiFiClientSecure` or `BearSSL::WiFiServerSecure` are instantiated. So, in the case of a global client or server, the memory will be allocated before `setup()` is called.
The per-connection buffers are approximately 22KB in size, but in certain circumstances it can be reduced dramatically by using MFLN or limiting message sizes. See the `MLFN section <#mfln-or-maximum-fragment-length-negotiation-saving-ram>`__ below for more information. The per-connection buffers are approximately 22KB in size, but in certain circumstances it can be reduced dramatically by using MFLN or limiting message sizes. See the `MLFN section <#mfln-or-maximum-fragment-length-negotiation-saving-ram>`__ below for more information.
@ -219,3 +219,13 @@ setCiphersLessSecure()
^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^
Helper function which essentially limits BearSSL to less secure ciphers than it would natively choose, but they may be helpful and faster if your server depended on specific crypto options. Helper function which essentially limits BearSSL to less secure ciphers than it would natively choose, but they may be helpful and faster if your server depended on specific crypto options.
Limiting TLS(SSL) Versions
~~~~~~~~~~~~~~~~~~~~~~~~~~
By default, BearSSL will connect with TLS 1.0, TLS 1.1, or TLS 1.2 protocols (depending on the request of the remote side). If you want to limit to a subset, use the following call:
setSSLVersion(uint32_t min, uint32_t max)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Valid values for min and max are `BR_TLS10`, `BR_TLS11`, `BR_TLS12`. Min and max may be set to the same value if only a single TLS version is desired.

View File

@ -156,6 +156,7 @@ loadCertificate KEYWORD2
loadPrivateKey KEYWORD2 loadPrivateKey KEYWORD2
loadCACert KEYWORD2 loadCACert KEYWORD2
allowSelfSignedCerts KEYWORD2 allowSelfSignedCerts KEYWORD2
setSSLVersion KEYWORD2
#WiFiServer #WiFiServer
hasClient KEYWORD2 hasClient KEYWORD2

View File

@ -93,6 +93,8 @@ void WiFiClientSecureCtx::_clear() {
_session = nullptr; _session = nullptr;
_cipher_list = nullptr; _cipher_list = nullptr;
_cipher_cnt = 0; _cipher_cnt = 0;
_tls_min = BR_TLS10;
_tls_max = BR_TLS12;
} }
void WiFiClientSecureCtx::_clearAuthenticationSettings() { void WiFiClientSecureCtx::_clearAuthenticationSettings() {
@ -125,7 +127,7 @@ WiFiClientSecureCtx::~WiFiClientSecureCtx() {
WiFiClientSecureCtx::WiFiClientSecureCtx(ClientContext* client, WiFiClientSecureCtx::WiFiClientSecureCtx(ClientContext* client,
const X509List *chain, const PrivateKey *sk, const X509List *chain, const PrivateKey *sk,
int iobuf_in_size, int iobuf_out_size, ServerSessions *cache, int iobuf_in_size, int iobuf_out_size, ServerSessions *cache,
const X509List *client_CA_ta) { const X509List *client_CA_ta, int tls_min, int tls_max) {
_clear(); _clear();
_clearAuthenticationSettings(); _clearAuthenticationSettings();
stack_thunk_add_ref(); stack_thunk_add_ref();
@ -133,6 +135,8 @@ WiFiClientSecureCtx::WiFiClientSecureCtx(ClientContext* client,
_iobuf_out_size = iobuf_out_size; _iobuf_out_size = iobuf_out_size;
_client = client; _client = client;
_client->ref(); _client->ref();
_tls_min = tls_min;
_tls_max = tls_max;
if (!_connectSSLServerRSA(chain, sk, cache, client_CA_ta)) { if (!_connectSSLServerRSA(chain, sk, cache, client_CA_ta)) {
_client->unref(); _client->unref();
_client = nullptr; _client = nullptr;
@ -144,7 +148,7 @@ WiFiClientSecureCtx::WiFiClientSecureCtx(ClientContext *client,
const X509List *chain, const X509List *chain,
unsigned cert_issuer_key_type, const PrivateKey *sk, unsigned cert_issuer_key_type, const PrivateKey *sk,
int iobuf_in_size, int iobuf_out_size, ServerSessions *cache, int iobuf_in_size, int iobuf_out_size, ServerSessions *cache,
const X509List *client_CA_ta) { const X509List *client_CA_ta, int tls_min, int tls_max) {
_clear(); _clear();
_clearAuthenticationSettings(); _clearAuthenticationSettings();
stack_thunk_add_ref(); stack_thunk_add_ref();
@ -152,6 +156,8 @@ WiFiClientSecureCtx::WiFiClientSecureCtx(ClientContext *client,
_iobuf_out_size = iobuf_out_size; _iobuf_out_size = iobuf_out_size;
_client = client; _client = client;
_client->ref(); _client->ref();
_tls_min = tls_min;
_tls_max = tls_max;
if (!_connectSSLServerEC(chain, cert_issuer_key_type, sk, cache, client_CA_ta)) { if (!_connectSSLServerEC(chain, cert_issuer_key_type, sk, cache, client_CA_ta)) {
_client->unref(); _client->unref();
_client = nullptr; _client = nullptr;
@ -1005,6 +1011,17 @@ bool WiFiClientSecureCtx::setCiphers(const std::vector<uint16_t>& list) {
return setCiphers(&list[0], list.size()); return setCiphers(&list[0], list.size());
} }
bool WiFiClientSecureCtx::setSSLVersion(uint32_t min, uint32_t max) {
if ( ((min != BR_TLS10) && (min != BR_TLS11) && (min != BR_TLS12)) ||
((max != BR_TLS10) && (max != BR_TLS11) && (max != BR_TLS12)) ||
(max < min) ) {
return false; // Invalid options
}
_tls_min = min;
_tls_max = max;
return true;
}
// Installs the appropriate X509 cert validation method for a client connection // Installs the appropriate X509 cert validation method for a client connection
bool WiFiClientSecureCtx::_installClientX509Validator() { bool WiFiClientSecureCtx::_installClientX509Validator() {
if (_use_insecure || _use_fingerprint || _use_self_signed) { if (_use_insecure || _use_fingerprint || _use_self_signed) {
@ -1110,6 +1127,7 @@ bool WiFiClientSecureCtx::_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);
br_ssl_engine_set_versions(_eng, _tls_min, _tls_max);
// Apply any client certificates, if supplied. // Apply any client certificates, if supplied.
if (_sk && _sk->isRSA()) { if (_sk && _sk->isRSA()) {
@ -1224,6 +1242,7 @@ bool WiFiClientSecureCtx::_connectSSLServerRSA(const X509List *chain,
sk ? sk->getRSA() : nullptr, BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, sk ? sk->getRSA() : nullptr, BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
br_rsa_private_get_default(), br_rsa_pkcs1_sign_get_default()); br_rsa_private_get_default(), br_rsa_pkcs1_sign_get_default());
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);
br_ssl_engine_set_versions(_eng, _tls_min, _tls_max);
if (cache != nullptr) if (cache != nullptr)
br_ssl_server_set_cache(_sc_svr.get(), cache->getCache()); br_ssl_server_set_cache(_sc_svr.get(), cache->getCache());
if (client_CA_ta && !_installServerX509Validator(client_CA_ta)) { if (client_CA_ta && !_installServerX509Validator(client_CA_ta)) {
@ -1270,6 +1289,7 @@ bool WiFiClientSecureCtx::_connectSSLServerEC(const X509List *chain,
sk ? sk->getEC() : nullptr, BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN, sk ? sk->getEC() : nullptr, BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
cert_issuer_key_type, br_ssl_engine_get_ec(_eng), br_ecdsa_i15_sign_asn1); cert_issuer_key_type, br_ssl_engine_get_ec(_eng), br_ecdsa_i15_sign_asn1);
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);
br_ssl_engine_set_versions(_eng, _tls_min, _tls_max);
if (cache != nullptr) if (cache != nullptr)
br_ssl_server_set_cache(_sc_svr.get(), cache->getCache()); br_ssl_server_set_cache(_sc_svr.get(), cache->getCache());
if (client_CA_ta && !_installServerX509Validator(client_CA_ta)) { if (client_CA_ta && !_installServerX509Validator(client_CA_ta)) {

View File

@ -121,6 +121,10 @@ class WiFiClientSecureCtx : public WiFiClient {
bool setCiphers(const std::vector<uint16_t>& list); bool setCiphers(const 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
// Limit the TLS versions BearSSL will connect with. Default is
// BR_TLS10...BR_TLS12
bool setSSLVersion(uint32_t min = BR_TLS10, uint32_t max = BR_TLS12);
// peek buffer API is present // peek buffer API is present
virtual bool hasPeekBufferAPI () const override { return true; } virtual bool hasPeekBufferAPI () const override { return true; }
@ -175,6 +179,10 @@ class WiFiClientSecureCtx : public WiFiClient {
std::shared_ptr<uint16_t> _cipher_list; std::shared_ptr<uint16_t> _cipher_list;
uint8_t _cipher_cnt; uint8_t _cipher_cnt;
// TLS ciphers allowed
uint32_t _tls_min;
uint32_t _tls_max;
unsigned char *_recvapp_buf; unsigned char *_recvapp_buf;
size_t _recvapp_len; size_t _recvapp_len;
@ -194,10 +202,10 @@ class WiFiClientSecureCtx : public WiFiClient {
friend class WiFiClientSecure; // access to private context constructors friend class WiFiClientSecure; // access to private context constructors
WiFiClientSecureCtx(ClientContext *client, const X509List *chain, unsigned cert_issuer_key_type, WiFiClientSecureCtx(ClientContext *client, const X509List *chain, unsigned cert_issuer_key_type,
const PrivateKey *sk, int iobuf_in_size, int iobuf_out_size, ServerSessions *cache, const PrivateKey *sk, int iobuf_in_size, int iobuf_out_size, ServerSessions *cache,
const X509List *client_CA_ta); const X509List *client_CA_ta, int tls_min, int tls_max);
WiFiClientSecureCtx(ClientContext* client, const X509List *chain, const PrivateKey *sk, WiFiClientSecureCtx(ClientContext* client, const X509List *chain, const PrivateKey *sk,
int iobuf_in_size, int iobuf_out_size, ServerSessions *cache, int iobuf_in_size, int iobuf_out_size, ServerSessions *cache,
const X509List *client_CA_ta); const X509List *client_CA_ta, int tls_min, int tls_max);
// RSA keyed server // RSA keyed server
bool _connectSSLServerRSA(const X509List *chain, const PrivateKey *sk, bool _connectSSLServerRSA(const X509List *chain, const PrivateKey *sk,
@ -321,14 +329,14 @@ class WiFiClientSecure : public WiFiClient {
friend class WiFiServerSecure; // Server needs to access these constructors friend class WiFiServerSecure; // Server needs to access these constructors
WiFiClientSecure(ClientContext *client, const X509List *chain, unsigned cert_issuer_key_type, WiFiClientSecure(ClientContext *client, const X509List *chain, unsigned cert_issuer_key_type,
const PrivateKey *sk, int iobuf_in_size, int iobuf_out_size, ServerSessions *cache, const PrivateKey *sk, int iobuf_in_size, int iobuf_out_size, ServerSessions *cache,
const X509List *client_CA_ta): const X509List *client_CA_ta, int tls_min, int tls_max):
_ctx(new WiFiClientSecureCtx(client, chain, cert_issuer_key_type, sk, iobuf_in_size, iobuf_out_size, cache, client_CA_ta)) { _ctx(new WiFiClientSecureCtx(client, chain, cert_issuer_key_type, sk, iobuf_in_size, iobuf_out_size, cache, client_CA_ta, tls_min, tls_max)) {
} }
WiFiClientSecure(ClientContext* client, const X509List *chain, const PrivateKey *sk, WiFiClientSecure(ClientContext* client, const X509List *chain, const PrivateKey *sk,
int iobuf_in_size, int iobuf_out_size, ServerSessions *cache, int iobuf_in_size, int iobuf_out_size, ServerSessions *cache,
const X509List *client_CA_ta): const X509List *client_CA_ta, int tls_min, int tls_max):
_ctx(new WiFiClientSecureCtx(client, chain, sk, iobuf_in_size, iobuf_out_size, cache, client_CA_ta)) { _ctx(new WiFiClientSecureCtx(client, chain, sk, iobuf_in_size, iobuf_out_size, cache, client_CA_ta, tls_min, tls_max)) {
} }
}; // class WiFiClientSecure }; // class WiFiClientSecure

View File

@ -79,13 +79,13 @@ WiFiClientSecure WiFiServerSecure::available(uint8_t* status) {
(void) status; // Unused (void) status; // Unused
if (_unclaimed) { if (_unclaimed) {
if (_sk && _sk->isRSA()) { if (_sk && _sk->isRSA()) {
WiFiClientSecure result(_unclaimed, _chain, _sk, _iobuf_in_size, _iobuf_out_size, _cache, _client_CA_ta); WiFiClientSecure result(_unclaimed, _chain, _sk, _iobuf_in_size, _iobuf_out_size, _cache, _client_CA_ta, _tls_min, _tls_max);
_unclaimed = _unclaimed->next(); _unclaimed = _unclaimed->next();
result.setNoDelay(_noDelay); result.setNoDelay(_noDelay);
DEBUGV("WS:av\r\n"); DEBUGV("WS:av\r\n");
return result; return result;
} else if (_sk && _sk->isEC()) { } else if (_sk && _sk->isEC()) {
WiFiClientSecure result(_unclaimed, _chain, _cert_issuer_key_type, _sk, _iobuf_in_size, _iobuf_out_size, _cache, _client_CA_ta); WiFiClientSecure result(_unclaimed, _chain, _cert_issuer_key_type, _sk, _iobuf_in_size, _iobuf_out_size, _cache, _client_CA_ta, _tls_min, _tls_max);
_unclaimed = _unclaimed->next(); _unclaimed = _unclaimed->next();
result.setNoDelay(_noDelay); result.setNoDelay(_noDelay);
DEBUGV("WS:av\r\n"); DEBUGV("WS:av\r\n");
@ -101,4 +101,15 @@ WiFiClientSecure WiFiServerSecure::available(uint8_t* status) {
return WiFiClientSecure(); return WiFiClientSecure();
} }
bool WiFiServerSecure::setSSLVersion(uint32_t min, uint32_t max) {
if ( ((min != BR_TLS10) && (min != BR_TLS11) && (min != BR_TLS12)) ||
((max != BR_TLS10) && (max != BR_TLS11) && (max != BR_TLS12)) ||
(max < min) ) {
return false; // Invalid options
}
_tls_min = min;
_tls_max = max;
return true;
}
}; };

View File

@ -60,6 +60,10 @@ class WiFiServerSecure : public WiFiServer {
_client_CA_ta = client_CA_ta; _client_CA_ta = client_CA_ta;
} }
// Limit the TLS versions BearSSL will connect with. Default is
// BR_TLS10...BR_TLS12
bool setSSLVersion(uint32_t min = BR_TLS10, uint32_t max = BR_TLS12);
// If awaiting connection available and authenticated (i.e. client cert), return it. // If awaiting connection available and authenticated (i.e. client cert), return it.
WiFiClientSecure available(uint8_t* status = NULL); WiFiClientSecure available(uint8_t* status = NULL);
@ -76,6 +80,9 @@ class WiFiServerSecure : public WiFiServer {
const X509List *_client_CA_ta = nullptr; const X509List *_client_CA_ta = nullptr;
ServerSessions *_cache = nullptr; ServerSessions *_cache = nullptr;
// TLS ciphers allowed
uint32_t _tls_min = BR_TLS10;
uint32_t _tls_max = BR_TLS12;
}; };
}; };