1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +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-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.
@ -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.
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
loadCACert KEYWORD2
allowSelfSignedCerts KEYWORD2
setSSLVersion KEYWORD2
#WiFiServer
hasClient KEYWORD2

View File

@ -93,6 +93,8 @@ void WiFiClientSecureCtx::_clear() {
_session = nullptr;
_cipher_list = nullptr;
_cipher_cnt = 0;
_tls_min = BR_TLS10;
_tls_max = BR_TLS12;
}
void WiFiClientSecureCtx::_clearAuthenticationSettings() {
@ -125,7 +127,7 @@ WiFiClientSecureCtx::~WiFiClientSecureCtx() {
WiFiClientSecureCtx::WiFiClientSecureCtx(ClientContext* client,
const X509List *chain, 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) {
_clear();
_clearAuthenticationSettings();
stack_thunk_add_ref();
@ -133,6 +135,8 @@ WiFiClientSecureCtx::WiFiClientSecureCtx(ClientContext* client,
_iobuf_out_size = iobuf_out_size;
_client = client;
_client->ref();
_tls_min = tls_min;
_tls_max = tls_max;
if (!_connectSSLServerRSA(chain, sk, cache, client_CA_ta)) {
_client->unref();
_client = nullptr;
@ -144,7 +148,7 @@ WiFiClientSecureCtx::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 X509List *client_CA_ta) {
const X509List *client_CA_ta, int tls_min, int tls_max) {
_clear();
_clearAuthenticationSettings();
stack_thunk_add_ref();
@ -152,6 +156,8 @@ WiFiClientSecureCtx::WiFiClientSecureCtx(ClientContext *client,
_iobuf_out_size = iobuf_out_size;
_client = client;
_client->ref();
_tls_min = tls_min;
_tls_max = tls_max;
if (!_connectSSLServerEC(chain, cert_issuer_key_type, sk, cache, client_CA_ta)) {
_client->unref();
_client = nullptr;
@ -1005,6 +1011,17 @@ bool WiFiClientSecureCtx::setCiphers(const std::vector<uint16_t>& list) {
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
bool WiFiClientSecureCtx::_installClientX509Validator() {
if (_use_insecure || _use_fingerprint || _use_self_signed) {
@ -1110,6 +1127,7 @@ bool WiFiClientSecureCtx::_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);
br_ssl_engine_set_versions(_eng, _tls_min, _tls_max);
// Apply any client certificates, if supplied.
if (_sk && _sk->isRSA()) {
@ -1224,6 +1242,7 @@ bool WiFiClientSecureCtx::_connectSSLServerRSA(const X509List *chain,
sk ? sk->getRSA() : nullptr, BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
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_versions(_eng, _tls_min, _tls_max);
if (cache != nullptr)
br_ssl_server_set_cache(_sc_svr.get(), cache->getCache());
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,
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_versions(_eng, _tls_min, _tls_max);
if (cache != nullptr)
br_ssl_server_set_cache(_sc_svr.get(), cache->getCache());
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 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
virtual bool hasPeekBufferAPI () const override { return true; }
@ -175,6 +179,10 @@ class WiFiClientSecureCtx : public WiFiClient {
std::shared_ptr<uint16_t> _cipher_list;
uint8_t _cipher_cnt;
// TLS ciphers allowed
uint32_t _tls_min;
uint32_t _tls_max;
unsigned char *_recvapp_buf;
size_t _recvapp_len;
@ -194,10 +202,10 @@ class WiFiClientSecureCtx : public WiFiClient {
friend class WiFiClientSecure; // access to private context constructors
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 X509List *client_CA_ta);
const X509List *client_CA_ta, int tls_min, int tls_max);
WiFiClientSecureCtx(ClientContext* client, const X509List *chain, 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);
// RSA keyed server
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
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 X509List *client_CA_ta):
_ctx(new WiFiClientSecureCtx(client, chain, cert_issuer_key_type, sk, iobuf_in_size, iobuf_out_size, cache, 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, tls_min, tls_max)) {
}
WiFiClientSecure(ClientContext* client, const X509List *chain, const PrivateKey *sk,
int iobuf_in_size, int iobuf_out_size, ServerSessions *cache,
const X509List *client_CA_ta):
_ctx(new WiFiClientSecureCtx(client, chain, sk, iobuf_in_size, iobuf_out_size, cache, 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, tls_min, tls_max)) {
}
}; // class WiFiClientSecure

View File

@ -79,13 +79,13 @@ WiFiClientSecure WiFiServerSecure::available(uint8_t* status) {
(void) status; // Unused
if (_unclaimed) {
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();
result.setNoDelay(_noDelay);
DEBUGV("WS:av\r\n");
return result;
} 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();
result.setNoDelay(_noDelay);
DEBUGV("WS:av\r\n");
@ -101,4 +101,15 @@ WiFiClientSecure WiFiServerSecure::available(uint8_t* status) {
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;
}
// 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.
WiFiClientSecure available(uint8_t* status = NULL);
@ -76,6 +80,9 @@ class WiFiServerSecure : public WiFiServer {
const X509List *_client_CA_ta = nullptr;
ServerSessions *_cache = nullptr;
// TLS ciphers allowed
uint32_t _tls_min = BR_TLS10;
uint32_t _tls_max = BR_TLS12;
};
};