From fccb3a5db5f7481aed45875d375f332b9d065818 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 5 Nov 2018 13:14:49 -0800 Subject: [PATCH 1/4] Add BearSSL documentation Document the BearSSL::WiFiClientSecure, ::WiFiServerSecure, and the helper classes required to use them. --- .../bearssl-client-secure-class.rst | 213 ++++++++++++++++++ .../bearssl-server-secure-class.rst | 44 ++++ doc/esp8266wifi/readme.rst | 24 +- 3 files changed, 276 insertions(+), 5 deletions(-) create mode 100644 doc/esp8266wifi/bearssl-client-secure-class.rst create mode 100644 doc/esp8266wifi/bearssl-server-secure-class.rst diff --git a/doc/esp8266wifi/bearssl-client-secure-class.rst b/doc/esp8266wifi/bearssl-client-secure-class.rst new file mode 100644 index 0000000000..610be95b91 --- /dev/null +++ b/doc/esp8266wifi/bearssl-client-secure-class.rst @@ -0,0 +1,213 @@ +:orphan: + +BearSSL WiFi Classes +-------------------- + +Methods and properties described in this section are specific to ESP8266. They are not covered in `Arduino WiFi library `__ documentation. Before they are fully documented please refer to information below. + +The `BearSSL `__ library (with modifications for ESP8266 compatibility and to use ROM tables whenver possible) is used to perform all cryptography and TLS operations. + +CPU Requirements +~~~~~~~~~~~~~~~~ + +SSL operations take significant CPU cycles to run, so it is recommended that all TLS/SSL sketches to run at `160 Mhz` and not the default `80 Mhz`. Even at 160 MHz, certain key exchanges can take multiple *seconds* of runtime to complete. There is no special cryptographic hardware in the ESP8266, nor is there a 32x32=>64 multiplier, nor is the program stored in onboard RAM, so there is little that can be done to speed this up. See the secton on limiting cryptographic negotiation for ways of ensuring faster modes are used. + +Memory Requirements +~~~~~~~~~~~~~~~~~~~ +BearSSL doesn't perform memory allocations at runtime, but it does require allocation of memory at the beginning of a connection. There are two memory chunks required: +. 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-connection buffers are approximately 22KB in size, but in certain circumstances it can be reduced dramatically by using MFLN or limiting message sizes. See below for more information. + +Object Lifetimes +~~~~~~~~~~~~~~~~ + +There are many configuration options that require passing in a pointer to an object (i.e. a pointer to a private key, or a certificate list). In order to preserve memory, BearSSL does NOT copy the objects passed in via these pointers and as such any pointer passed in to BearSSL needs to be preserved for the life of the client object. For example, the following code is **in error**: + +.. code:: cpp + + BearSSL::WiFiClientSecure client; + const char x509CA PROGMEM = "......."; + void setup() { + BearSSLX509List x509(x509CA); + client.setTrustAnchor(&x509); + } + void loop() { + client.connect("192.168.1.1", 443); + } + +Because the pointer to the local object `x509` no longer is valid after setup(), expect to crash in the main `loop()` where it is accessed by the `client` object. + +As a rule, either keep your objects global, use `new` to create them, or ensure that all objects needed live inside the same scope as the client. + +TLS and HTTPS basics +~~~~~~~~~~~~~~~~~~~~ + +The following discussion is only intended to give a rough idea of TLS/HTTPS(which is just HTTP over a TLS connection) and the components an application needs to manage to make a TLS connection. For more detailed information, please check the relevant `RFC 5246 `__ and others. + +TLS can be broken into two stages: verifying the identities of server (and potentially client), and then encrypting clocks of data bidirectionally. + + +Public and Private Keys +~~~~~~~~~~~~~~~~~~~~~~~ + +Cryptographic keys are required for many of the BearSSL functions. Both public and private keys are supported, with either Elliptic Curve or RSA key support. + +To generate a public or private key from an existing PEM (ASCII format) or DER (binary format), the simplest method is to use the constructor: + +.. code:: cpp + + BearSSL::PublicKey(const char *pemString) + ... or ... + BearSSL::PublicKey(const uint8_t *derArray, size_t derLen) + +Note that `PROGMEM` strings and arrays are natively supported by these constructors and no special `*_P` modes are required. There are additional functions to identify the key type and access the underlying BearSSL proprietary types, but they are not needed by user applications. + +TLS Sessions +~~~~~~~~~~~~ + +TLS supports the notion of a session (completely independent and different from HTTP sessions) which allow clients to reconnect to a server without having to renegotiate encryption settings or validate X509 certificates. This can save significant time (3-4 seconds in the case of EC keys) and can help save power by allowing the ESP8266 to sleep for a long time, reconnect and transmit some samples using the SSL session, and then jump back to sleep quicker. + +`BearSSLSession` is an opaque class. Use the `BearSSL::WiFiClientSecure.setSession(&BearSSLSession)` method to apply it before the first `BearSSL::WiFiClientSecure.connect()` and it will be updated with session parameters during the operation of the connection. After the connection had had `.close()` called on it, serialize the `BearSSLSession` object to stable store (EEPROM, RTC RAM, etc) and restore it before trying to resonnect. See the `BearSSL_Sessions` example for a detailed example. + + +X.509 Certificate(s) +~~~~~~~~~~~~~~~~~~~~ + +X509 certificates are used to identify peers in TLS connections. Normally only the server identifies itself, but the client can also supply an X509 certificate if desired (this is often done in MQTT applications). The certificate contains many fields, but the most interesting in our applications are the name, the public key, and potentially a chain of signing that leads back to a trusted authority (like a global internet CA or a company-wide private certificate authority). + +Any call that takes an X509 certificate can also take a list of X509 certificates, so there is no special `X509` class, simply `BearSSLX509List` (which may only contain a sincle certificate). + +Generating a certificate to be used to validate using the constructor + +.. code:: cpp + + BearSSLX509List(const char *pemX509); + ...or... + BearSSLX509List(const uint8_t *derCert, size_t derLen); + +If you need to add additional certificates (unlikely in normal operation, the `::append()` operation can be used. + + +Certificate Stores +~~~~~~~~~~~~~~~~~~ + +The web browser you're using to read this document keeps a list of 100s of certification authorities (CAs) worldwide that it trusts to attest to the identity of websites. + +In many cases your application will know the specific CA it needs to validate web or MQTT servers against (often just a single, self-signing CA private to your institution). Simply load your private CA in a `BearSSLX509List` and use that as your trust anchor. + +However, there are cases where you will not know beforehand which CA you will need (i.e. a user enters a website through a keypad), and you need to keep the list of CAs just like your web browser. In those cases, you need to generate a certificate bundle on the PC while compiling your application, upload the `certs.ar` bundle to SPIFFS or SD when uploading your application binary, and pass it to a `BearSSL::CertStore()` in order to validate TLS peers. + +See the `BearSSL_CertStore` example for full details as the `BearSSL::CertStore` requires the creation of a cookie-cutter object for filesystem access (because the SD and SPIFFS filesystems are presently incompatible with each other). At a high level in your `setup()` you will call `BearSSL::initCertStore()` on a global object, and then pass this global certificate store to `client.setCertStore(&gCA)` before every connection attempt to enable it as a validatiaon option. + +Supported Crypto +~~~~~~~~~~~~~~~~ + +Please see the `BearSSL website `__ for detailed cryptographic information. In general, TLS 1.2, TLS 1.1, and TLS 1.0 are supported with RSA and Elliptic Curve keys and a very rich set of hashing and symmetric encryption codes. Please note that Elliptic Curve (EC) key operations take a significant amount of time. + + +BearSSL::WiFiClientSecure Class +------------------------------- + +`BearSSL::WiFiClientSecure` is the object which actually handles TLS encrypted WiFi connections to a remote server or client. It extends `WiFiClient` and so can be used with minimal changes to code that does unsecured communications. + +Validating X509 Certificates (Am I talking to the server I think I'm talking to?) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Prior to connecting to a server, the `BearSSL::WiFiClientSecure` needs to be told how to verify the identity of the other machine. **By default BearSSL will not validate any connections and will refuse to connect to any server.** This is a significant difference from the earlier `axTLS::WiFiClientSecure` in that the deprecated axTLS client would connect to any server and would only attempt to validate the identidy of the remote server if asked to, after connection. + +There are multiple modes to tell BearSSL how to verify the identity of the remote server. See the `BearSSL_Validation` example for real uses of the following methods: + +setInsecure() +^^^^^^^^^^^^^^^ + +Don't verify any X509 certificates. There is no guarantee that the server connected to is the one you think it is in this case, but this call will mimic the behavior of the deprecated axTLS code. + +setKnownKey(const BearSSLPublicKey *pk) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Assume the server is using the specific public key. This does not verify the identity of the server or the X509 certificate it sends, it simply assumes that its public key is the one given. If the server updates its public key at a later point then connections will fail. + +setFingerprint(const uint8_t fp[20]) / setFingerprint(const char *fpStr) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Verify the SHA1 fingerprint of the certificate returned matches this one. If the server certificate changes, it will fail. If an array of 20 bytes are sent in, it is assumed they are the binary SHA1 values. If a `char*` string is passed in, it is parsed as a series of human-readable hex values separated by spaces or colons (i.e. `setFingerprint("00:01:02:03:...:1f");`) + +setTrustAnchors(BearSSLX509List *ta) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use the passed-in certificate(s) as a trust anchor, accepting remote certificates signed by any of these. If you have many trust anchors it may make sense to use a `BearSSL::CertStore` because it will only require RAM for a single trust anchor (while the `setTrustAnchors` call requires memory for all certificates in the list). + +setX509Time(time_t now) +^^^^^^^^^^^^^^^^^^^^^^^ + +For `setTrustAnchors` and `CertStore` , the current time (set via SNTP) is used to verify the certificate against the list, so SNTP must be enabled and functioning before the connection is attempted. If you cannot use SNTP for some reason, you can manually set the "present time" that BearSSL will use to validate a certificate with this call where `now` is standard UNIX time. + +Client Certificates (Proving I'm who I say I am to the server) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +TLS servers can request that a client identify themselves with an X509 certificate signed by a trust anchor it honors (i.e. a global TA or a private CA). This is commonly done for applicaitons like MQTT. By default the client doesn't sent a certificate, and in cases where a certificate is required the server will disconnect and no connection will be possible. + +setClientRSACert / setClientECCert +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Sets a client certificate to send to a TLS server that requests one. It should be called before `connect()` to add a certificate to the client in case the server requests is. Note that certificates include both a certificate and a private key. Both should be provided to you by your certificate generator. Elliptic Curve (EC) keys require additional information, as shown in the prototype. + +MFLN or Maximum Fragment Length Negotiation (Saving RAM) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Because TLS was developed on systems with many megabytes of memory, they require by default a 16KB buffer for receive and transmit. That's enormous for the ESP8266, which has only around 40KB total heap available. + +We can (and do) minimize the transmission buffer down to slightly more than 512 bytes to save memory, since BearSSL can internally ensure transmissions larger than that are broken up into smaller chunks that do fit. But that still leaves the 16KB receive buffer requirement since we cannot in general guarantee the TLS peer will send in smaller chunks. + +TLS 1.2 added MFLN, which lets a client negotiate smaller buffers with a server and reduce the memory requirements on the ESP8266. Unfortunatly, BearSSL needs to know the buffer sizes before it begins connection, so applications that want to use smaller buffers need to check the remote server's support before `connect()` . + +probeMaxFragmentLength(host, port, len) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use one of these calls **before** connection to determine if a specific fragment length is supported (len must be a power of two from 512 to 4096, per the TLC specification). This does **not** initiate a SSL connection, it simply opens a TCP port and performs a trial handshake to check support. + +setBufferSizes(int recv, int xmit) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Once you have verified (or know beforehand) that MFLN is supported you can use this call to set the size of memory buffers allocated by the connection object. This must be called **before** `connect()` or it will be ignored. + +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. + +Sessions (Resuming connections fast) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +setSession(BearSSLSession &sess) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you are connecting to a server repeatedly in a fixed time period (usually 30 or 60 minuntes, but normally configurable at the server), a TLS session can be used to cache crypto settings and speed up connections significantly. + +Errors +~~~~~~ + +BearSSL can fail in many more unique and interesting ways then the deprecated axTLS. Use these calls to get more information when something fails. + +getLastSSLError(char *dest = NULL, size_t len = 0) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Returns the last BearSSL error code encountered, and if passed in a pointer to a character array and length it will also give a human-readable form of the error for display. + +Limiting Ciphers (New connections faster) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There is very rarely reason to use these calls, but they are available. + +setCiphers() +^^^^^^^^^^^^ + +Takes an array (in PROGMEM is valid) or a std::vector of 16-bit BearSSL cipher identifiers and restricts BearSSL to only use them. If the server requires a different cipher, then connection will fail. Generally this is not useful except in cases where you want to connect to servers using a specific cipher. See the BearSSL headers for more information on the supported ciphers. + +setCiphersLessSecure() +^^^^^^^^^^^^^^^^^^^^^^ + +Helper function which essentially limits BearSSL to ciphers that were supported by the deprecated axTLS. These may be less secure than the ones BearSSL would natively choose, but they may be helpful and faster if your server depended on specific axTLS crypto options. + + diff --git a/doc/esp8266wifi/bearssl-server-secure-class.rst b/doc/esp8266wifi/bearssl-server-secure-class.rst new file mode 100644 index 0000000000..4ab934ee84 --- /dev/null +++ b/doc/esp8266wifi/bearssl-server-secure-class.rst @@ -0,0 +1,44 @@ +:orphan: + +BearSSL Secure Server Class +--------------------------- + +Implements a TLS encrypted server with optional client certificate validation. See `Server Class `__ for general information and `BearSSL Secure Client Class `__ for basic server and BearSSL concepts. + +setBufferSizes(int recv, int xmit) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Similar to the `BearSSL::WiFiClientSecure` methos, sets the receive and transmit buffer sizes. Note that servers cannot request a buffer size from the client, so if these are shrunk and the client tries to send a chunk larger than the receive buffer, it will always fail. This must be called before the server is + +Setting Server Certificates +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +TLS servers require a certificate identifying itself and containing its public key, and a private key they will use to encrypt information with. The application author is responsible for generating this certificate and key, either using a self-signed generator or using a commercial certification authority. **Do not re-use the certificates included in the examples provided.** + +This example command will generate a RSA 2048-bit key and certificate: + +.. code:: + + openssl req -x509 -nodes -newkey rsa:2048 -keyout key.pem -out cert.pem -days 4096 + +Again, it is up to the application author to generate this certificate and key and keep the private key safe and **private.** + +setRSACert(const BearSSLX509List *chain, const BearSSLPrivateKey *sk) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Sets a RSA certificate and key to be used by the server when connections are received. Needs to be called before `begin()` + +setECCert(const BearSSLX509List *chain, unsigned cert_issuer_key_type, const BearSSLPrivateKey *sk) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Sets an elliptic curve certificate and key for the server. Needs to be called before `begin()`. + +Requiring Client Certificates +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +TLS servers can request the client to identify itself by transmitting a certificate during handshake. If the client cannot transmit the certificate, the connection will be dropped by the server. + +setClientTrustAnchor(const BearSSLX509List *client_CA_ta) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Sets the trust anchor (normally a self-signing CA) that all received certificates will be verified against. Needs to be called before `begin()`. diff --git a/doc/esp8266wifi/readme.rst b/doc/esp8266wifi/readme.rst index 9e27ed2b55..8de3aaac43 100644 --- a/doc/esp8266wifi/readme.rst +++ b/doc/esp8266wifi/readme.rst @@ -157,18 +157,32 @@ The Client class creates `clients `__ / `list of functions `__ -Client Secure -~~~~~~~~~~~~~ +axTLS Client Secure - DEPRECATED +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The Client Secure is an extension of `Client Class <#client>`__ where connection and data exchange with servers is done using a `secure protocol `__. It supports `TLS 1.1 `__. The `TLS 1.2 `__ is not supported. +The following section details axTLS, the older TLS library used by the project. It is still supported, but additional fixes and documentation will generally not be undertaken. See the following section for the updated TLS client object. -.. figure:: pictures/esp8266-client-secure.png - :alt: ESP8266 operating as the Client Secure +The axTLS Client Secure is an extension of `Client Class <#client>`__ where connection and data exchange with servers is done using a `secure protocol `__. It supports `TLS 1.1 `__. The `TLS 1.2 `__ is not supported. Secure applications have additional memory (and processing) overhead due to the need to run cryptography algorithms. The stronger the certificate's key, the more overhead is needed. In practice it is not possible to run more than a single secure client at a time. The problem concerns RAM memory we can not add, the flash memory size is usually not the issue. If you like to learn how `client secure library `__ has been developed, access to what servers have been tested, and how memory limitations have been overcame, read fascinating issue report `#43 `__. Check out separate section with `examples `__ / `list of functions `__ + +BearSSL Client Secure and Server Secure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`BearSSL::WiFiClientSecure` and `BearSSL::WiFiServerSecure` are extensions of the standard `Client <#client>`__ and `Server <#server>`__ classes where connection and data exchange with servers and clients using `secure protocol `__. It supports `TLS 1.2 `__ using a wide variety of modern ciphers, hashes, and key types. + +.. figure:: pictures/esp8266-client-secure.png + :alt: ESP8266 operating as the Client Secure + +Secure clients and servers require siginificant amounts of additional memory and processing to enable their cryptographic algorithms. In general only a single secure client or server connection at a time can be processed given the little RAM present on the ESP8266, but there are methods of reducing this RAM requirement detailed in the relevant sections. + +`BearSSL::WiFiClientSecure `__ contains more information on using and configuring TLS connections. + +`BearSSL::WiFiServerSecure `__ discusses the TLS server mode available. Please read and understand the `BearSSL::WiFiClientSecure `__ first as the server uses most of the same concepts. + Server ~~~~~~ From c01016f84a3b04cf216fdf8ee1be851b6d784b0b Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 6 Nov 2018 08:36:59 -0800 Subject: [PATCH 2/4] Fix typos and grammar from @devyte and spellcheck --- .../bearssl-client-secure-class.rst | 34 +++++++++---------- .../bearssl-server-secure-class.rst | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/doc/esp8266wifi/bearssl-client-secure-class.rst b/doc/esp8266wifi/bearssl-client-secure-class.rst index 610be95b91..e9f5e4be4a 100644 --- a/doc/esp8266wifi/bearssl-client-secure-class.rst +++ b/doc/esp8266wifi/bearssl-client-secure-class.rst @@ -5,12 +5,12 @@ BearSSL WiFi Classes Methods and properties described in this section are specific to ESP8266. They are not covered in `Arduino WiFi library `__ documentation. Before they are fully documented please refer to information below. -The `BearSSL `__ library (with modifications for ESP8266 compatibility and to use ROM tables whenver possible) is used to perform all cryptography and TLS operations. +The `BearSSL `__ library (with modifications for ESP8266 compatibility and to use ROM tables whenever possible) is used to perform all cryptography and TLS operations. The main ported repo is available `on GitHub `__. CPU Requirements ~~~~~~~~~~~~~~~~ -SSL operations take significant CPU cycles to run, so it is recommended that all TLS/SSL sketches to run at `160 Mhz` and not the default `80 Mhz`. Even at 160 MHz, certain key exchanges can take multiple *seconds* of runtime to complete. There is no special cryptographic hardware in the ESP8266, nor is there a 32x32=>64 multiplier, nor is the program stored in onboard RAM, so there is little that can be done to speed this up. See the secton on limiting cryptographic negotiation for ways of ensuring faster modes are used. +SSL operations take significant CPU cycles to run, so it is recommended that all TLS/SSL sketches to run at `160 Mhz` and not the default `80 Mhz`. Even at 160 MHz, certain key exchanges can take multiple *seconds* of runtime to complete. There is no special cryptographic hardware in the ESP8266, nor is there a 32x32=>64 multiplier, nor is the program stored in onboard RAM, so there is little that can be done to speed this up. See the section on limiting cryptographic negotiation for ways of ensuring faster modes are used. Memory Requirements ~~~~~~~~~~~~~~~~~~~ @@ -43,12 +43,12 @@ Because the pointer to the local object `x509` no longer is valid after setup(), As a rule, either keep your objects global, use `new` to create them, or ensure that all objects needed live inside the same scope as the client. -TLS and HTTPS basics +TLS and HTTPS Basics ~~~~~~~~~~~~~~~~~~~~ The following discussion is only intended to give a rough idea of TLS/HTTPS(which is just HTTP over a TLS connection) and the components an application needs to manage to make a TLS connection. For more detailed information, please check the relevant `RFC 5246 `__ and others. -TLS can be broken into two stages: verifying the identities of server (and potentially client), and then encrypting clocks of data bidirectionally. +TLS can be broken into two stages: verifying the identities of server (and potentially client), and then encrypting clocks of data bidirectionally. Verifying the identity of the other partner is handled via keys encoded in X509 certificates, optionally signed by a series of other entities. Public and Private Keys @@ -71,7 +71,7 @@ TLS Sessions TLS supports the notion of a session (completely independent and different from HTTP sessions) which allow clients to reconnect to a server without having to renegotiate encryption settings or validate X509 certificates. This can save significant time (3-4 seconds in the case of EC keys) and can help save power by allowing the ESP8266 to sleep for a long time, reconnect and transmit some samples using the SSL session, and then jump back to sleep quicker. -`BearSSLSession` is an opaque class. Use the `BearSSL::WiFiClientSecure.setSession(&BearSSLSession)` method to apply it before the first `BearSSL::WiFiClientSecure.connect()` and it will be updated with session parameters during the operation of the connection. After the connection had had `.close()` called on it, serialize the `BearSSLSession` object to stable store (EEPROM, RTC RAM, etc) and restore it before trying to resonnect. See the `BearSSL_Sessions` example for a detailed example. +`BearSSLSession` is an opaque class. Use the `BearSSL::WiFiClientSecure.setSession(&BearSSLSession)` method to apply it before the first `BearSSL::WiFiClientSecure.connect()` and it will be updated with session parameters during the operation of the connection. After the connection has had `.close()` called on it, serialize the `BearSSLSession` object to stable storage (EEPROM, RTC RAM, etc.) and restore it before trying to reconnect. See the `BearSSL_Sessions` example for a detailed example. X.509 Certificate(s) @@ -79,7 +79,7 @@ X.509 Certificate(s) X509 certificates are used to identify peers in TLS connections. Normally only the server identifies itself, but the client can also supply an X509 certificate if desired (this is often done in MQTT applications). The certificate contains many fields, but the most interesting in our applications are the name, the public key, and potentially a chain of signing that leads back to a trusted authority (like a global internet CA or a company-wide private certificate authority). -Any call that takes an X509 certificate can also take a list of X509 certificates, so there is no special `X509` class, simply `BearSSLX509List` (which may only contain a sincle certificate). +Any call that takes an X509 certificate can also take a list of X509 certificates, so there is no special `X509` class, simply `BearSSLX509List` (which may only contain a single certificate). Generating a certificate to be used to validate using the constructor @@ -89,7 +89,7 @@ Generating a certificate to be used to validate using the constructor ...or... BearSSLX509List(const uint8_t *derCert, size_t derLen); -If you need to add additional certificates (unlikely in normal operation, the `::append()` operation can be used. +If you need to add additional certificates (unlikely in normal operation), the `::append()` operation can be used. Certificate Stores @@ -101,7 +101,7 @@ In many cases your application will know the specific CA it needs to validate we However, there are cases where you will not know beforehand which CA you will need (i.e. a user enters a website through a keypad), and you need to keep the list of CAs just like your web browser. In those cases, you need to generate a certificate bundle on the PC while compiling your application, upload the `certs.ar` bundle to SPIFFS or SD when uploading your application binary, and pass it to a `BearSSL::CertStore()` in order to validate TLS peers. -See the `BearSSL_CertStore` example for full details as the `BearSSL::CertStore` requires the creation of a cookie-cutter object for filesystem access (because the SD and SPIFFS filesystems are presently incompatible with each other). At a high level in your `setup()` you will call `BearSSL::initCertStore()` on a global object, and then pass this global certificate store to `client.setCertStore(&gCA)` before every connection attempt to enable it as a validatiaon option. +See the `BearSSL_CertStore` example for full details as the `BearSSL::CertStore` requires the creation of a cookie-cutter object for filesystem access (because the SD and SPIFFS filesystems are presently incompatible with each other). At a high level in your `setup()` you will call `BearSSL::initCertStore()` on a global object, and then pass this global certificate store to `client.setCertStore(&gCA)` before every connection attempt to enable it as a validation option. Supported Crypto ~~~~~~~~~~~~~~~~ @@ -117,7 +117,7 @@ BearSSL::WiFiClientSecure Class Validating X509 Certificates (Am I talking to the server I think I'm talking to?) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Prior to connecting to a server, the `BearSSL::WiFiClientSecure` needs to be told how to verify the identity of the other machine. **By default BearSSL will not validate any connections and will refuse to connect to any server.** This is a significant difference from the earlier `axTLS::WiFiClientSecure` in that the deprecated axTLS client would connect to any server and would only attempt to validate the identidy of the remote server if asked to, after connection. +Prior to connecting to a server, the `BearSSL::WiFiClientSecure` needs to be told how to verify the identity of the other machine. **By default BearSSL will not validate any connections and will refuse to connect to any server.** This is a significant difference from the earlier `axTLS::WiFiClientSecure` in that the deprecated axTLS client would connect to any server and would only attempt to validate the identity of the remote server if asked to, after connection. There are multiple modes to tell BearSSL how to verify the identity of the remote server. See the `BearSSL_Validation` example for real uses of the following methods: @@ -134,7 +134,7 @@ Assume the server is using the specific public key. This does not verify the id setFingerprint(const uint8_t fp[20]) / setFingerprint(const char *fpStr) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Verify the SHA1 fingerprint of the certificate returned matches this one. If the server certificate changes, it will fail. If an array of 20 bytes are sent in, it is assumed they are the binary SHA1 values. If a `char*` string is passed in, it is parsed as a series of human-readable hex values separated by spaces or colons (i.e. `setFingerprint("00:01:02:03:...:1f");`) +Verify the SHA1 fingerprint of the certificate returned matches this one. If the server certificate changes, it will fail. If an array of 20 bytes are sent in, it is assumed they are the binary SHA1 values. If a `char*` string is passed in, it is parsed as a series of human-readable hex values separated by spaces or colons (e.g. `setFingerprint("00:01:02:03:...:1f");`) setTrustAnchors(BearSSLX509List *ta) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -149,12 +149,12 @@ For `setTrustAnchors` and `CertStore` , the current time (set via SNTP) is used Client Certificates (Proving I'm who I say I am to the server) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -TLS servers can request that a client identify themselves with an X509 certificate signed by a trust anchor it honors (i.e. a global TA or a private CA). This is commonly done for applicaitons like MQTT. By default the client doesn't sent a certificate, and in cases where a certificate is required the server will disconnect and no connection will be possible. +TLS servers can request that a client identify themselves with an X509 certificate signed by a trust anchor it honors (i.e. a global TA or a private CA). This is commonly done for applications like MQTT. By default the client doesn't send a certificate, and in cases where a certificate is required the server will disconnect and no connection will be possible. setClientRSACert / setClientECCert ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Sets a client certificate to send to a TLS server that requests one. It should be called before `connect()` to add a certificate to the client in case the server requests is. Note that certificates include both a certificate and a private key. Both should be provided to you by your certificate generator. Elliptic Curve (EC) keys require additional information, as shown in the prototype. +Sets a client certificate to send to a TLS server that requests one. It should be called before `connect()` to add a certificate to the client in case the server requests it. Note that certificates include both a certificate and a private key. Both should be provided to you by your certificate generator. Elliptic Curve (EC) keys require additional information, as shown in the prototype. MFLN or Maximum Fragment Length Negotiation (Saving RAM) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -163,19 +163,19 @@ Because TLS was developed on systems with many megabytes of memory, they require We can (and do) minimize the transmission buffer down to slightly more than 512 bytes to save memory, since BearSSL can internally ensure transmissions larger than that are broken up into smaller chunks that do fit. But that still leaves the 16KB receive buffer requirement since we cannot in general guarantee the TLS peer will send in smaller chunks. -TLS 1.2 added MFLN, which lets a client negotiate smaller buffers with a server and reduce the memory requirements on the ESP8266. Unfortunatly, BearSSL needs to know the buffer sizes before it begins connection, so applications that want to use smaller buffers need to check the remote server's support before `connect()` . +TLS 1.2 added MFLN, which lets a client negotiate smaller buffers with a server and reduce the memory requirements on the ESP8266. Unfortunately, BearSSL needs to know the buffer sizes before it begins connection, so applications that want to use smaller buffers need to check the remote server's support before `connect()` . probeMaxFragmentLength(host, port, len) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Use one of these calls **before** connection to determine if a specific fragment length is supported (len must be a power of two from 512 to 4096, per the TLC specification). This does **not** initiate a SSL connection, it simply opens a TCP port and performs a trial handshake to check support. +Use one of these calls **before** connection to determine if a specific fragment length is supported (len must be a power of two from 512 to 4096, per the specification). This does **not** initiate a SSL connection, it simply opens a TCP port and performs a trial handshake to check support. setBufferSizes(int recv, int xmit) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Once you have verified (or know beforehand) that MFLN is supported you can use this call to set the size of memory buffers allocated by the connection object. This must be called **before** `connect()` or it will be ignored. -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. +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. Sessions (Resuming connections fast) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -183,7 +183,7 @@ Sessions (Resuming connections fast) setSession(BearSSLSession &sess) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -If you are connecting to a server repeatedly in a fixed time period (usually 30 or 60 minuntes, but normally configurable at the server), a TLS session can be used to cache crypto settings and speed up connections significantly. +If you are connecting to a server repeatedly in a fixed time period (usually 30 or 60 minutes, but normally configurable at the server), a TLS session can be used to cache crypto settings and speed up connections significantly. Errors ~~~~~~ @@ -193,7 +193,7 @@ BearSSL can fail in many more unique and interesting ways then the deprecated ax getLastSSLError(char *dest = NULL, size_t len = 0) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Returns the last BearSSL error code encountered, and if passed in a pointer to a character array and length it will also give a human-readable form of the error for display. +Returns the last BearSSL error code encountered and optionally set a user-allocated buffer to a human-readable form of the error. To only get the last error integer code, just call without any parameters (`int errCode = getLastSSLError();`). Limiting Ciphers (New connections faster) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/esp8266wifi/bearssl-server-secure-class.rst b/doc/esp8266wifi/bearssl-server-secure-class.rst index 4ab934ee84..e1114f254d 100644 --- a/doc/esp8266wifi/bearssl-server-secure-class.rst +++ b/doc/esp8266wifi/bearssl-server-secure-class.rst @@ -8,7 +8,7 @@ Implements a TLS encrypted server with optional client certificate validation. setBufferSizes(int recv, int xmit) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Similar to the `BearSSL::WiFiClientSecure` methos, sets the receive and transmit buffer sizes. Note that servers cannot request a buffer size from the client, so if these are shrunk and the client tries to send a chunk larger than the receive buffer, it will always fail. This must be called before the server is +Similar to the `BearSSL::WiFiClientSecure` method, sets the receive and transmit buffer sizes. Note that servers cannot request a buffer size from the client, so if these are shrunk and the client tries to send a chunk larger than the receive buffer, it will always fail. This must be called before the server is Setting Server Certificates ~~~~~~~~~~~~~~~~~~~~~~~~~~~ From ac2f36d5ffc7db097bc87591ac12c32c4fd8f2c7 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 6 Nov 2018 10:11:34 -0800 Subject: [PATCH 3/4] Add additional links in the document --- doc/esp8266wifi/bearssl-client-secure-class.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/esp8266wifi/bearssl-client-secure-class.rst b/doc/esp8266wifi/bearssl-client-secure-class.rst index e9f5e4be4a..1595185e56 100644 --- a/doc/esp8266wifi/bearssl-client-secure-class.rst +++ b/doc/esp8266wifi/bearssl-client-secure-class.rst @@ -10,7 +10,9 @@ The `BearSSL `__ library (with modifications for ESP8266 co CPU Requirements ~~~~~~~~~~~~~~~~ -SSL operations take significant CPU cycles to run, so it is recommended that all TLS/SSL sketches to run at `160 Mhz` and not the default `80 Mhz`. Even at 160 MHz, certain key exchanges can take multiple *seconds* of runtime to complete. There is no special cryptographic hardware in the ESP8266, nor is there a 32x32=>64 multiplier, nor is the program stored in onboard RAM, so there is little that can be done to speed this up. See the section on limiting cryptographic negotiation for ways of ensuring faster modes are used. +SSL operations take significant CPU cycles to run, so it is recommended that all TLS/SSL sketches to run at `160 Mhz` and not the default `80 Mhz`. Even at 160 MHz, certain key exchanges can take multiple *seconds* of runtime to complete. There is no special cryptographic hardware in the ESP8266, nor is there a 32x32=>64 multiplier, nor is the program stored in onboard RAM, so there is little that can be done to speed this up. + +See the section on `sessions `__ and `limiting cryptographic negotiation `__ for ways of ensuring faster modes are used. Memory Requirements ~~~~~~~~~~~~~~~~~~~ @@ -20,7 +22,7 @@ BearSSL doesn't perform memory allocations at runtime, but it does require alloc 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-connection buffers are approximately 22KB in size, but in certain circumstances it can be reduced dramatically by using MFLN or limiting message sizes. See 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 `__ below for more information. Object Lifetimes ~~~~~~~~~~~~~~~~ @@ -48,7 +50,7 @@ TLS and HTTPS Basics The following discussion is only intended to give a rough idea of TLS/HTTPS(which is just HTTP over a TLS connection) and the components an application needs to manage to make a TLS connection. For more detailed information, please check the relevant `RFC 5246 `__ and others. -TLS can be broken into two stages: verifying the identities of server (and potentially client), and then encrypting clocks of data bidirectionally. Verifying the identity of the other partner is handled via keys encoded in X509 certificates, optionally signed by a series of other entities. +TLS can be broken into two stages: verifying the identities of server (and potentially client), and then encrypting blocks of data bidirectionally. Verifying the identity of the other partner is handled via keys encoded in X509 certificates, optionally signed by a series of other entities. Public and Private Keys @@ -73,6 +75,7 @@ TLS supports the notion of a session (completely independent and different from `BearSSLSession` is an opaque class. Use the `BearSSL::WiFiClientSecure.setSession(&BearSSLSession)` method to apply it before the first `BearSSL::WiFiClientSecure.connect()` and it will be updated with session parameters during the operation of the connection. After the connection has had `.close()` called on it, serialize the `BearSSLSession` object to stable storage (EEPROM, RTC RAM, etc.) and restore it before trying to reconnect. See the `BearSSL_Sessions` example for a detailed example. +`Sessions `__ contains additional information on the sessions API. X.509 Certificate(s) ~~~~~~~~~~~~~~~~~~~~ From 70fd7ea3c1bde6772a9f19b90718e068bfe781f2 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 6 Nov 2018 10:17:11 -0800 Subject: [PATCH 4/4] Fix intra-document link format --- doc/esp8266wifi/bearssl-client-secure-class.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/esp8266wifi/bearssl-client-secure-class.rst b/doc/esp8266wifi/bearssl-client-secure-class.rst index 1595185e56..48a6485391 100644 --- a/doc/esp8266wifi/bearssl-client-secure-class.rst +++ b/doc/esp8266wifi/bearssl-client-secure-class.rst @@ -12,7 +12,7 @@ CPU Requirements SSL operations take significant CPU cycles to run, so it is recommended that all TLS/SSL sketches to run at `160 Mhz` and not the default `80 Mhz`. Even at 160 MHz, certain key exchanges can take multiple *seconds* of runtime to complete. There is no special cryptographic hardware in the ESP8266, nor is there a 32x32=>64 multiplier, nor is the program stored in onboard RAM, so there is little that can be done to speed this up. -See the section on `sessions `__ and `limiting cryptographic negotiation `__ for ways of ensuring faster modes are used. +See the section on `sessions <#sessions-resuming-connections-fast>`__ and `limiting cryptographic negotiation <#limiting-ciphers-new-connections-faster>`__ for ways of ensuring faster modes are used. Memory Requirements ~~~~~~~~~~~~~~~~~~~ @@ -22,7 +22,7 @@ BearSSL doesn't perform memory allocations at runtime, but it does require alloc 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-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 `__ 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. Object Lifetimes ~~~~~~~~~~~~~~~~ @@ -75,7 +75,7 @@ TLS supports the notion of a session (completely independent and different from `BearSSLSession` is an opaque class. Use the `BearSSL::WiFiClientSecure.setSession(&BearSSLSession)` method to apply it before the first `BearSSL::WiFiClientSecure.connect()` and it will be updated with session parameters during the operation of the connection. After the connection has had `.close()` called on it, serialize the `BearSSLSession` object to stable storage (EEPROM, RTC RAM, etc.) and restore it before trying to reconnect. See the `BearSSL_Sessions` example for a detailed example. -`Sessions `__ contains additional information on the sessions API. +`Sessions <#sessions-resuming-connections-fast>`__ contains additional information on the sessions API. X.509 Certificate(s) ~~~~~~~~~~~~~~~~~~~~