1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-07-18 23:03:34 +03:00

WiFiServerSecure: Cache SSL sessions (#7774)

* WiFiServerSecure: Cache the SSL sessions

* Add SSL session caching to HTTPS server examples

* Document server SSL session caching

* Fix an incomplete sentence in the documentation

* Document BearSSL::Session

* Use the number of sessions instead of the buffer size in ServerSessions' constructors
This commit is contained in:
Zakary Kamal Ismail
2020-12-22 00:13:43 -05:00
committed by GitHub
parent 8add1fd2d9
commit 032db6fc81
10 changed files with 146 additions and 19 deletions

View File

@ -872,6 +872,22 @@ bool X509List::append(const uint8_t *derCert, size_t derLen) {
return true;
}
ServerSessions::~ServerSessions() {
if (_isDynamic && _store != nullptr)
delete _store;
}
ServerSessions::ServerSessions(ServerSession *sessions, uint32_t size, bool isDynamic) :
_size(sessions != nullptr ? size : 0),
_store(sessions), _isDynamic(isDynamic) {
if (_size > 0)
br_ssl_session_cache_lru_init(&_cache, (uint8_t*)_store, size * sizeof(ServerSession));
}
const br_ssl_session_cache_class **ServerSessions::getCache() {
return _size > 0 ? &_cache.vtable : nullptr;
}
// SHA256 hash for updater
void HashSHA256::begin() {
br_sha256_init( &_cc );

View File

@ -133,6 +133,9 @@ class X509List {
// significantly faster. Completely optional.
class WiFiClientSecure;
// Cache for a TLS session with a server
// Use with BearSSL::WiFiClientSecure::setSession
// to accelerate the TLS handshake
class Session {
friend class WiFiClientSecureCtx;
@ -140,10 +143,51 @@ class Session {
Session() { memset(&_session, 0, sizeof(_session)); }
private:
br_ssl_session_parameters *getSession() { return &_session; }
// The actual BearSSL ession information
// The actual BearSSL session information
br_ssl_session_parameters _session;
};
// Represents a single server session.
// Use with BearSSL::ServerSessions.
typedef uint8_t ServerSession[100];
// Cache for the TLS sessions of multiple clients.
// Use with BearSSL::WiFiServerSecure::setCache
class ServerSessions {
friend class WiFiClientSecureCtx;
public:
// Uses the given buffer to cache the given number of sessions and initializes it.
ServerSessions(ServerSession *sessions, uint32_t size) : ServerSessions(sessions, size, false) {}
// Dynamically allocates a cache for the given number of sessions and initializes it.
// If the allocation of the buffer wasn't successfull, the value
// returned by size() will be 0.
ServerSessions(uint32_t size) : ServerSessions(size > 0 ? new ServerSession[size] : nullptr, size, true) {}
~ServerSessions();
// Returns the number of sessions the cache can hold.
uint32_t size() { return _size; }
private:
ServerSessions(ServerSession *sessions, uint32_t size, bool isDynamic);
// Returns the cache's vtable or null if the cache has no capacity.
const br_ssl_session_cache_class **getCache();
// Size of the store in sessions.
uint32_t _size;
// Store where the informations for the sessions are stored.
ServerSession *_store;
// Whether the store is dynamically allocated.
// If this is true, the store needs to be freed in the destructor.
bool _isDynamic;
// Cache of the server using the _store.
br_ssl_session_cache_lru _cache;
};
// Updater SHA256 hash and signature verification
class HashSHA256 : public UpdaterHashClass {
public:
@ -170,7 +214,7 @@ class SigningVerifier : public UpdaterVerifyClass {
private:
PublicKey *_pubKey;
};
// Stack thunked versions of calls
extern "C" {
extern unsigned char *thunk_br_ssl_engine_recvapp_buf( const br_ssl_engine_context *cc, size_t *len);

View File

@ -124,7 +124,8 @@ WiFiClientSecureCtx::~WiFiClientSecureCtx() {
WiFiClientSecureCtx::WiFiClientSecureCtx(ClientContext* client,
const X509List *chain, const PrivateKey *sk,
int iobuf_in_size, int iobuf_out_size, const X509List *client_CA_ta) {
int iobuf_in_size, int iobuf_out_size, ServerSessions *cache,
const X509List *client_CA_ta) {
_clear();
_clearAuthenticationSettings();
stack_thunk_add_ref();
@ -132,7 +133,7 @@ WiFiClientSecureCtx::WiFiClientSecureCtx(ClientContext* client,
_iobuf_out_size = iobuf_out_size;
_client = client;
_client->ref();
if (!_connectSSLServerRSA(chain, sk, client_CA_ta)) {
if (!_connectSSLServerRSA(chain, sk, cache, client_CA_ta)) {
_client->unref();
_client = nullptr;
_clear();
@ -142,7 +143,8 @@ WiFiClientSecureCtx::WiFiClientSecureCtx(ClientContext* client,
WiFiClientSecureCtx::WiFiClientSecureCtx(ClientContext *client,
const X509List *chain,
unsigned cert_issuer_key_type, const PrivateKey *sk,
int iobuf_in_size, int iobuf_out_size, const X509List *client_CA_ta) {
int iobuf_in_size, int iobuf_out_size, ServerSessions *cache,
const X509List *client_CA_ta) {
_clear();
_clearAuthenticationSettings();
stack_thunk_add_ref();
@ -150,7 +152,7 @@ WiFiClientSecureCtx::WiFiClientSecureCtx(ClientContext *client,
_iobuf_out_size = iobuf_out_size;
_client = client;
_client->ref();
if (!_connectSSLServerEC(chain, cert_issuer_key_type, sk, client_CA_ta)) {
if (!_connectSSLServerEC(chain, cert_issuer_key_type, sk, cache, client_CA_ta)) {
_client->unref();
_client = nullptr;
_clear();
@ -1178,7 +1180,7 @@ bool WiFiClientSecureCtx::_installServerX509Validator(const X509List *client_CA_
// Called by WiFiServerBearSSL when an RSA cert/key is specified.
bool WiFiClientSecureCtx::_connectSSLServerRSA(const X509List *chain,
const PrivateKey *sk,
const PrivateKey *sk, ServerSessions *cache,
const X509List *client_CA_ta) {
_freeSSL();
_oom_err = false;
@ -1206,6 +1208,8 @@ 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);
if (cache != nullptr)
br_ssl_server_set_cache(_sc_svr.get(), cache->getCache());
if (client_CA_ta && !_installServerX509Validator(client_CA_ta)) {
DEBUG_BSSL("_connectSSLServerRSA: Can't install serverX509check\n");
return false;
@ -1222,7 +1226,7 @@ bool WiFiClientSecureCtx::_connectSSLServerRSA(const X509List *chain,
// Called by WiFiServerBearSSL when an elliptic curve cert/key is specified.
bool WiFiClientSecureCtx::_connectSSLServerEC(const X509List *chain,
unsigned cert_issuer_key_type, const PrivateKey *sk,
const X509List *client_CA_ta) {
ServerSessions *cache, const X509List *client_CA_ta) {
#ifndef BEARSSL_SSL_BASIC
_freeSSL();
_oom_err = false;
@ -1250,6 +1254,8 @@ 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);
if (cache != nullptr)
br_ssl_server_set_cache(_sc_svr.get(), cache->getCache());
if (client_CA_ta && !_installServerX509Validator(client_CA_ta)) {
DEBUG_BSSL("_connectSSLServerEC: Can't install serverX509check\n");
return false;

View File

@ -179,15 +179,18 @@ class WiFiClientSecureCtx : public WiFiClient {
// Methods for handling server.available() call which returns a client connection.
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, const X509List *client_CA_ta);
const PrivateKey *sk, int iobuf_in_size, int iobuf_out_size, ServerSessions *cache,
const X509List *client_CA_ta);
WiFiClientSecureCtx(ClientContext* client, const X509List *chain, const PrivateKey *sk,
int iobuf_in_size, int iobuf_out_size, const X509List *client_CA_ta);
int iobuf_in_size, int iobuf_out_size, ServerSessions *cache,
const X509List *client_CA_ta);
// RSA keyed server
bool _connectSSLServerRSA(const X509List *chain, const PrivateKey *sk, const X509List *client_CA_ta);
bool _connectSSLServerRSA(const X509List *chain, const PrivateKey *sk,
ServerSessions *cache, const X509List *client_CA_ta);
// EC keyed server
bool _connectSSLServerEC(const X509List *chain, unsigned cert_issuer_key_type, const PrivateKey *sk,
const X509List *client_CA_ta);
ServerSessions *cache, const X509List *client_CA_ta);
// X.509 validators differ from server to client
bool _installClientX509Validator(); // Set up X509 validator for a client conn.
@ -290,13 +293,15 @@ class WiFiClientSecure : public WiFiClient {
// Methods for handling server.available() call which returns a client connection.
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, const X509List *client_CA_ta):
_ctx(new WiFiClientSecureCtx(client, chain, cert_issuer_key_type, sk, iobuf_in_size, iobuf_out_size, client_CA_ta)) {
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)) {
}
WiFiClientSecure(ClientContext* client, const X509List *chain, const PrivateKey *sk,
int iobuf_in_size, int iobuf_out_size, const X509List *client_CA_ta):
_ctx(new WiFiClientSecureCtx(client, chain, sk, iobuf_in_size, iobuf_out_size, client_CA_ta)) {
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)) {
}
}; // 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, _client_CA_ta);
WiFiClientSecure result(_unclaimed, _chain, _sk, _iobuf_in_size, _iobuf_out_size, _cache, _client_CA_ta);
_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, _client_CA_ta);
WiFiClientSecure result(_unclaimed, _chain, _cert_issuer_key_type, _sk, _iobuf_in_size, _iobuf_out_size, _cache, _client_CA_ta);
_unclaimed = _unclaimed->next();
result.setNoDelay(_noDelay);
DEBUGV("WS:av\r\n");

View File

@ -42,6 +42,11 @@ class WiFiServerSecure : public WiFiServer {
_iobuf_out_size = xmit;
}
// Sets the server's cache to the given one.
void setCache(ServerSessions *cache) {
_cache = cache;
}
// Set the server's RSA key and x509 certificate (required, pick one).
// Caller needs to preserve the chain and key throughout the life of the server.
void setRSACert(const X509List *chain, const PrivateKey *sk);
@ -69,6 +74,7 @@ class WiFiServerSecure : public WiFiServer {
int _iobuf_in_size = BR_SSL_BUFSIZE_INPUT;
int _iobuf_out_size = 837;
const X509List *_client_CA_ta = nullptr;
ServerSessions *_cache = nullptr;
};