1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-06-13 13:01:55 +03:00

Remove axTLS from code and documentation (#7437)

This commit is contained in:
Earle F. Philhower, III
2020-07-09 09:21:38 -07:00
committed by GitHub
parent 1ead157558
commit 70e4457041
29 changed files with 10 additions and 3533 deletions

View File

@ -107,7 +107,4 @@ Other Function Calls
IPAddress localIP ()
uint16_t localPort ()
Documentation for the above functions is not yet prepared.
For code samples please refer to separate section with `examples
:arrow\_right: <client-examples.rst>`__ dedicated specifically to the Client Class.
Documentation for the above functions is not yet available.

View File

@ -1,322 +0,0 @@
:orphan:
Client
------
Let's write a simple client program to access a single web page and display its contents on a serial monitor. This is typical operation performed by a client to access server's API to retrieve specific information. For instance we may want to contact GitHub's API to periodically check the number of open issues reported on `esp8266/Arduino <https://github.com/esp8266/Arduino/issues>`__ repository.
Table of Contents
-----------------
- `Introduction <#introduction>`__
- `Get Connected to Wi-Fi <#get-connected-to-wi-fi>`__
- `Select a Server <#select-a-server>`__
- `Instantiate the Client <#instantiate-the-client>`__
- `Get Connected to the Server <#get-connected-to-the-server>`__
- `Request the Data <#request-the-data>`__
- `Read Reply from the Server <#read-reply-from-the-server>`__
- `Now to the Sketch <#now-to-the-sketch>`__
- `Test it Live <#test-it-live>`__
- `Test it More <#test-it-more>`__
- `Conclusion <#conclusion>`__
Introduction
~~~~~~~~~~~~
This time we are going to concentrate just on retrieving a web page contents sent by a server, to demonstrate basic client's functionality. Once you are able to retrieve information from a server, you should be able to phrase it and extract specific data you need.
Get Connected to Wi-Fi
~~~~~~~~~~~~~~~~~~~~~~
We should start with connecting the module to an access point to obtain an access to internet. The code to provide this functionality has been already discussed in chapter `Quick Start <readme.rst#quick-start>`__. Please refer to it for details.
Select a Server
~~~~~~~~~~~~~~~
Once connected to the network we should connect to the specific server. Web address of this server is declared in ``host`` character string as below.
.. code:: cpp
const char* host = "www.example.com";
I have selected ``www.example.com`` domain name and you can select any other. Just check if you can access it using a web browser.
.. figure:: pictures/client-example-domain.png
:alt: A web page to be retreived by the clinet program
alt text
Instantiate the Client
~~~~~~~~~~~~~~~~~~~~~~
Now we should declare a client that will be contacting the host (server):
.. code:: cpp
WiFiClient client;
Get Connected to the Server
~~~~~~~~~~~~~~~~~~~~~~~~~~~
In next line we will connect to the host and check the connection result. Note ``80``, that is the standard port number used for web access.
.. code:: cpp
if (client.connect(host, 80))
{
// we are connected to the host!
}
else
{
// connection failure
}
Request the Data
~~~~~~~~~~~~~~~~
If connection is successful, we should send request the host to provide specific information we need. This is done using the `HTTP GET <https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods>`__ request as in the following lines:
.. code:: cpp
client.print(String("GET /") + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n" +
"\r\n"
);
Read Reply from the Server
~~~~~~~~~~~~~~~~~~~~~~~~~~
Then, while connection by our client is still alive or while data are available to read (``while (client.connected() || client.available())``, see below) we can read line by line and print out server's response:
.. code:: cpp
while (client.connected() || client.available())
{
if (client.available())
{
String line = client.readStringUntil('\n');
Serial.println(line);
}
}
The inner ``if (client.available())`` is checking if there are any data available from the server. If so, then they are printed out.
Data can be unavailable while the TCP connection is still alive. That means data could be later received.
Once server sends all requested data it will disconnect, then once all received data are read, program will exit the ``while`` loop.
Now to the Sketch
~~~~~~~~~~~~~~~~~
Complete sketch, including a case when contention to the server fails, is presented below.
.. code:: cpp
#include <ESP8266WiFi.h>
const char* ssid = "********";
const char* password = "********";
const char* host = "www.example.com";
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println(" connected");
}
void loop()
{
WiFiClient client;
Serial.printf("\n[Connecting to %s ... ", host);
if (client.connect(host, 80))
{
Serial.println("connected]");
Serial.println("[Sending a request]");
client.print(String("GET /") + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n" +
"\r\n"
);
Serial.println("[Response:]");
while (client.connected() || client.available())
{
if (client.available())
{
String line = client.readStringUntil('\n');
Serial.println(line);
}
}
client.stop();
Serial.println("\n[Disconnected]");
}
else
{
Serial.println("connection failed!]");
client.stop();
}
delay(5000);
}
Test it Live
~~~~~~~~~~~~
Upload sketch the module and open serial monitor. You should see a log similar to presented below.
First, after establishing Wi-Fi connection, you should see confirmation, that client connected to the server and send the request:
::
Connecting to sensor-net ........ connected
[Connecting to www.example.com ... connected]
[Sending a request]
Then, after getting the request, server will first respond with a header that specifies what type of information will follow (e.g. ``Content-Type: text/html``), how long it is (like ``Content-Length: 1270``), etc.:
::
[Response:]
HTTP/1.1 200 OK
Cache-Control: max-age=604800
Content-Type: text/html
Date: Sat, 30 Jul 2016 12:30:45 GMT
Etag: "359670651+ident"
Expires: Sat, 06 Aug 2016 12:30:45 GMT
Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
Server: ECS (ewr/15BD)
Vary: Accept-Encoding
X-Cache: HIT
x-ec-custom-error: 1
Content-Length: 1270
Connection: close
End of header is marked with an empty line and then you should see the HTML code of requested web page.
::
<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
(...)
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is established to be used for illustrative examples in documents. You may use this
domain in examples without prior coordination or asking for permission.</p>
<p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
[Disconnected]
Test it More
~~~~~~~~~~~~
In case server's web address is incorrect, or server is not accessible, you should see the following short and simple message on the serial monitor:
::
Connecting to sensor-net ........ connected
[Connecting to www.wrong-example.com ... connection failed!]
General client loop
~~~~~~~~~~~~~~~~~~~
Here is a general TCP sending / receiving loop:
.. code:: cpp
while (client.available() || client.connected())
{
if (client.available())
{
// client.available() bytes are immediately available for reading
// warning: reading them *allows* peer to send more, so they should
// be read *only* when they can immediately be processed, see below
// for flow control
}
if (client.connected())
{
if (client.availableForWrite() >= N)
{
// TCP layer will be able to *bufferize* our N bytes,
// and send them *asynchronously*, with by default
// a small delay if those data are small
// because Nagle is around (~200ms)
// unless client.setNoDelay(true) was called.
//
// In any case client.write() will *never* block here
}
else
{
// or we can send but it will take time because data are too
// big to be asynchronously bufferized: TCP needs to receive
// some ACKs to release its buffers.
// That means that write() will block until it receives
// authorization to send because we are not in a
// multitasking environment
// It is always OK to do this, client.availableForWrite() is
// only needed when efficiency is a priority and when data
// to send can wait where they currently are, especially
// when they are in another tcp client.
// Flow control:
// It is also important to know that the ACKs we are sending
// to remote are directly generated from client.read().
// It means that:
// Not immediately reading available data can be good for
// flow control and avoid useless memory filling/overflow by
// preventing peer from sending more data, and slow down
// incoming bandwidth
// (tcp is really a nice and efficient beast)
}
}
// this is necessary for long duration loops (harmless otherwise)
yield();
}
Conclusion
~~~~~~~~~~
With this simple example we have demonstrated how to set up a client program, connect it to a server, request a web page and retrieve it. Now you should be able to write your own client program for ESP8266 and move to more advanced dialogue with a server, like e.g. using `HTTPS <https://en.wikipedia.org/wiki/HTTPS>`__ protocol with the `Client Secure <client-secure-examples.rst>`__ .
For more client examples please check
- `WiFiClientBasic.ino <https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/WiFiClientBasic/WiFiClientBasic.ino>`__ - a simple sketch that sends a message to a TCP server
- `WiFiClient.ino <https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino>`__ - this sketch sends data via HTTP GET requests to data.sparkfun.com service.
For the list of functions provided to manage clients, please refer to the `Client Class :arrow\_right: <client-class.rst>`__ documentation.

View File

@ -1,102 +0,0 @@
:orphan:
Client Secure Class
-------------------
Methods and properties described in this section are specific to ESP8266. They are not covered in `Arduino WiFi library <https://www.arduino.cc/en/Reference/WiFi>`__ documentation. Before they are fully documented please refer to information below.
Supported crypto
~~~~~~~~~~~~~~~~
In the background the library `axtls <http://axtls.sourceforge.net>`_ is used. The library supports only rsa certificates and no new eliptic curve certificates. TLSv1.2 is supported since SDK 2.4.0-rc1.
The following ciphers and digests are supported by `specification <http://axtls.sourceforge.net/specifications.htm>`_:
* Symmetric Ciphers
* AES128-SHA
* AES256-SHA
* AES128-SHA256
* AES256-SHA256
* Asymmetric Ciphers
* RSA 512/1024/2048/4096 bit encryption/decryption.
* RSA signing/verification
* Digests
* SHA1
* MD5
* SHA256/384/512
* HMAC-SHA1
* HMAC-MD5
* HMAC-SHA256
loadCertificate
~~~~~~~~~~~~~~~
Load client certificate from file system.
.. code:: cpp
loadCertificate(file)
*Declarations*
.. code:: cpp
#include <FS.h>
#include <LittleFS.h>
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
const char* certificateFile = "/client.cer";
*setup() or loop()*
.. code:: cpp
if (!LittleFS.begin())
{
Serial.println("Failed to mount the file system");
return;
}
Serial.printf("Opening %s", certificateFile);
File crtFile = LittleFS.open(certificateFile, "r");
if (!crtFile)
{
Serial.println(" Failed!");
}
WiFiClientSecure client;
Serial.print("Loading %s", certificateFile);
if (!client.loadCertificate(crtFile))
{
Serial.println(" Failed!");
}
// proceed with connecting of client to the host
setCertificate
~~~~~~~~~~~~~~
Load client certificate from C array.
.. code:: cpp
setCertificate (array, size)
For a practical example please check `this interesting blog <https://nofurtherquestions.wordpress.com/2016/03/14/making-an-esp8266-web-accessible/>`__.
Other Function Calls
~~~~~~~~~~~~~~~~~~~~
.. code:: cpp
bool verify (const char *fingerprint, const char *domain_name)
void setPrivateKey (const uint8_t *pk, size_t size)
bool loadCertificate (Stream &stream, size_t size)
bool loadPrivateKey (Stream &stream, size_t size)
template<typename TFile > bool loadPrivateKey (TFile &file)
Documentation for the above functions is not yet prepared.
For code samples please refer to separate section with `examples <client-secure-examples.rst>`__ dedicated specifically to the Client Secure Class.

View File

@ -1,181 +0,0 @@
:orphan:
Client Secure
-------------
The client secure is a `client <#client>`__ but secure. Application example below will be easier to follow if you check similar and simpler `example <client-examples.rst>`__ for the "ordinary" client. That being said we will concentrate on discussing the code that is specific to the client secure.
Table of Contents
-----------------
- `Introduction <#introduction>`__
- `The Sketch <#the-sketch>`__
- `How to Verify Server's
Identity? <#how-to-verify-server-s-identity>`__
- `Get the Fingerprint <#get-the-fingerprint>`__
- `Connect to the Server <#connect-to-the-server>`__
- `Is it THAT Server? <#is-it-that-server>`__
- `GET Response from the Server <#get-response-from-the-server>`__
- `Read and Check the Response <#read-and-check-the-response>`__
- `Does it Work? <#does-it-work>`__
- `Conclusion <#conclusion>`__
Introduction
~~~~~~~~~~~~
In this example we will be retrieving information from a secure server https://api.github.com. This server is set up in place to provide specific and structured information on `GitHub <https://github.com>`__ repositories. For instance, we may ask it to provide us the build status or the latest version of `esp8266 /
Adruino <https://github.com/esp8266/Arduino/>`__ core.
The build status of esp8266 / Adruino may be checked on the repository's `home page <https://github.com/esp8266/Arduino#using-git-version>`__ or on `Travis CI <https://travis-ci.org/esp8266/Arduino>`__ site as below:
.. figure:: pictures/esp8266-arduino-build-status-travisci.png
:alt: Build status of esp8266 / Arduino repository on Travis CI site
alt text
GitHub provides a separate server with `API <https://developer.github.com/v3/>`__ to access such information is structured form as `JSON <https://en.wikipedia.org/wiki/JSON>`__.
As you may guess we will use the client secure to contact https://api.github.com server and request the `build status <https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref>`__. If we open specific resource provided in the API with a web browser, the following should show up:
.. figure:: pictures/esp8266-arduino-build-status-json.png
:alt: Build status of esp8266 / Arduino repository in JSON fromat
alt text
What we need to do, is to use client secure to connect to ``https://api.github.com``, to GET ``/repos/esp8266/Arduino/commits/master/status``, search for the line ``"state": "success"`` and display "Build Successful" if we find it, or "Build Failed" if otherwise.
The Sketch
~~~~~~~~~~
A classic `sketch <https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/HTTPSRequest/HTTPSRequest.ino>`__ that is doing what we need is already available among `examples <https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WiFi/examples>`__ of ESP8266WiFi library. Please open it to go through it step by step.
How to Verify Server's Identity?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To establish a secure connection with a server we need to verify server's identity. Clients that run on "regular" computers do it by comparing server's certificate with locally stored list of trusted root certificates. Such certificates take several hundreds of KB, so it is not a good option for an ESP module. As an alternative we can use much smaller SHA1 fingerprint of specific certificate.
In declaration section of code we provide the name of ``host`` and the corresponding ``fingerprint``.
.. code:: cpp
const char* host = "api.github.com";
const char* fingerprint = "CF 05 98 89 CA FF 8E D8 5E 5C E0 C2 E4 F7 E6 C3 C7 50 DD 5C";
Get the Fingerprint
~~~~~~~~~~~~~~~~~~~
We can obtain the ``fingerprint`` for specific ``host`` using a web browser. For instance on Chrome press *Ctrl+Shift+I* and go to *Security > View Certificate > Details > Thumbprint*. This will show a window like below where you can copy the fingerprint and paste it into sketch.
.. figure:: pictures/client-secure-check-fingerprint.png
:alt: Locating the fingerprint of GitHub api
alt text
Remaining steps look almost identical as for the `non-secure client example <client-examples.rst>`__.
Connect to the Server
~~~~~~~~~~~~~~~~~~~~~
Instantiate the ``WiFiClientSecure`` object and establish a connection (please note we need to use specific ``httpsPort`` for secure connections):
.. code:: cpp
WiFiClientSecure client;
Serial.print("connecting to ");
Serial.println(host);
if (!client.connect(host, httpsPort)) {
Serial.println("connection failed");
return;
}
Is it THAT Server?
~~~~~~~~~~~~~~~~~~
Now verify if the fingerprint we have matches this one provided by the server:
.. code:: cpp
if (client.verify(fingerprint, host)) {
Serial.println("certificate matches");
} else {
Serial.println("certificate doesn't match");
}
If this check fails, it is up to you to decide if to proceed further or abort connection. Also note that certificates have specific validity period. Therefore the fingerprint of certificate we have checked today, will certainly be invalid some time later.
GET Response from the Server
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In the next steps we should execute GET command. This is done is similar way as discussed in `non-secure client example <client-examples.rst>`__.
.. code:: cpp
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"User-Agent: BuildFailureDetectorESP8266\r\n" +
"Connection: close\r\n\r\n");
After sending the request we should wait for a reply and then process received information.
Out of received reply we can skip response header. This can be done by reading until an empty line ``"\r"`` that marks the end of the header:
.. code:: cpp
while (client.connected()) {
String line = client.readStringUntil('\n');
if (line == "\r") {
Serial.println("headers received");
break;
}
}
Read and Check the Response
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Finally we should read JSON provided by server and check if it contains ``{"state": "success"``:
.. code:: cpp
String line = client.readStringUntil('\n');
if (line.startsWith("{\"state\":\"success\"")) {
Serial.println("esp8266/Arduino CI successfull!");
} else {
Serial.println("esp8266/Arduino CI has failed");
}
Does it Work?
~~~~~~~~~~~~~
Now once you know how it should work, get the `sketch <https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/HTTPSRequest/HTTPSRequest.ino>`__. Update credentials to your Wi-Fi network. Check the current fingerprint of ``api.github.com`` and update it if required. Then upload sketch and open a serial monitor.
If everything is fine (including build status of esp8266 / Arduino) you should see message as below:
::
connecting to sensor-net
........
WiFi connected
IP address:
192.168.1.104
connecting to api.github.com
certificate matches
requesting URL: /repos/esp8266/Arduino/commits/master/status
request sent
headers received
esp8266/Arduino CI successfull!
reply was:
==========
{"state":"success","statuses":[{"url":"https://api.github.com/repos/esp8266/Arduino/statuses/8cd331a8bae04a6f1443ff0c93539af4720d8ddf","id":677326372,"state":"success","description":"The Travis CI build passed","target_url":"https://travis-ci.org/esp8266/Arduino/builds/148827821","context":"continuous-integration/travis-ci/push","created_at":"2016-08-01T09:54:38Z","updated_at":"2016-08-01T09:54:38Z"},{"url":"https://api.github.com/repos/esp8266/Arduino/statuses/8cd331a8bae04a6f1443ff0c93539af4720d8ddf","id":677333081,"state":"success","description":"27.62% (+0.00%) compared to 0718188","target_url":"https://codecov.io/gh/esp8266/Arduino/commit/8cd331a8bae04a6f1443ff0c93539af4720d8ddf","context":"codecov/project","created_at":"2016-08-01T09:59:05Z","updated_at":"2016-08-01T09:59:05Z"},
(...)
==========
closing connection
Conclusion
~~~~~~~~~~
Programming a secure client is almost identical as programming a non-secure client. The difference gets down to one extra step to verify server's identity. Keep in mind limitations due to heavy memory usage that depends on the strength of the key used by the server and whether server is willing to negotiate the `TLS buffer size <https://www.igvita.com/2013/10/24/optimizing-tls-record-size-and-buffering-latency/>`__.
For the list of functions provided to manage secure clients, please refer to the `Client Secure Class
:arrow\_right: <client-secure-class.rst>`__ documentation.

View File

@ -154,18 +154,7 @@ The Client class creates `clients <https://en.wikipedia.org/wiki/Client_(computi
.. figure:: pictures/esp8266-client.png
:alt: ESP8266 operating as the Client
Check out the separate section with `examples <client-examples.rst>`__ / `list of functions <client-class.rst>`__
axTLS Client Secure - DEPRECATED
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
The axTLS Client Secure is an extension of `Client Class <#client>`__ where connection and data exchange with servers is done using a `secure protocol <https://en.wikipedia.org/wiki/Transport_Layer_Security>`__. It supports `TLS 1.1 <https://en.wikipedia.org/wiki/Transport_Layer_Security#TLS_1.1>`__. The `TLS 1.2 <https://en.wikipedia.org/wiki/Transport_Layer_Security#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 would like to learn how `client secure library <https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/src/WiFiClientSecure.h>`__ has been developed, what server access has been tested, and how memory limitations have been overcome, read this fascinating issue report `#43 <https://github.com/esp8266/Arduino/issues/43>`__.
Check out the separate section with `examples <client-secure-examples.rst>`__ / `list of functions <client-secure-class.rst>`__
Check out the separate section with `list of functions <client-class.rst>`__
BearSSL Client Secure and Server Secure
@ -182,6 +171,9 @@ Secure clients and servers require siginificant amounts of additional memory and
`BearSSL::WiFiServerSecure <bearssl-server-secure-class.rst>`__ discusses the TLS server mode available. Please read and understand the `BearSSL::WiFiClientSecure <bearssl-client-secure-class.rst>`__ first as the server uses most of the same concepts.
Check out the separate section with `examples <client-secure-examples.rst>`__ .
Server
~~~~~~

View File

@ -238,11 +238,6 @@ The page would be refreshed every 5 seconds. Each time this happens, you should
Connection: Keep-Alive
[client disonnected]
What Else?
~~~~~~~~~~
Looking on `client examples <client-examples.rst>`__ you will quickly find out the similarities in protocol to the server. The protocol starts with a header that contains information what communication will be about. It contains what content type is communicated or accepted like ``text/html``. It states whether connection will be kept alive or closed after submission of the header. It contains identification of the sender like ``User-Agent: Mozilla/5.0 (Windows NT 6.1)``, etc.
Conclusion
~~~~~~~~~~