1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-04-19 23:22:16 +03:00
david gauchard 97018a5bbf
various minor web fixes (#8885)
* httpclient: use refs - httpserver: add chunks in examples

* basic https client: update cert

* debug log: read() returning -1 is usual and means "nothing to read"

* emulation on host: SSL server has never been and is now working

* style

* move SSL server certs from examples into a single place with appropriate warnings

* web-hello-servers: make chunks bigger

* factorize template declaration

* http-client: add getString(pre-reservation)

* mock: add umm_info()

* style

* comment API in example

* style

* fix per review
2023-03-30 19:39:35 +02:00

193 lines
6.8 KiB
C++

/*
Demonstrate the usage of client certificate validation
for WiFiServerBearSSL.
By Earle F. Philhower, III
TLS servers can require that a client present it with an X.509
certificate signed by a trusted authority. Clients which try
and connect without a x.509 key, or with an x.509 key not signed
by the trusted authority (which could be a self-signing CA)
can not connect.
This example uses a predefined CA and any number of client
certificates. Clients will need both their X.509 cert and their
private key, both of which are generated in the signing process.
To run this example:
1. Generate a private certificate-authority certificate and key:
openssl genrsa -out ca_key.pem 2048
openssl req -x509 -new -nodes -key ca_key.pem -days 4096 -config ca.conf -out ca_cer.pem
KEEP ca_key.pem ABSOLUTELY SECURE, WITH IT ANYONE CAN MAKE CERTS
SIGNED BY YOU!
DO NOT UPLOAD ca_key.pem TO THE ESP8266, IT'S NOT NEEDED (SEE BELOW)!
ca_cer.pem is the Public X.509 certificate for your signing authority
and can(must) be shared and included in the server as the trust root.
2. Generate a private server certificate and key pair (using the
self-signed CA or any other CA you'd like)
openssl genrsa -out server_key.pem 2048
openssl req -out server_req.csr -key server_key.pem -new -config server.conf
openssl x509 -req -in server_req.csr -out server_cer.pem -sha256 -CAcreateserial -days 4000 -CA ca_cer.pem -CAkey ca_key.pem
KEEP server_key.pem SECURE, IT IS YOUR SERVER'S PRIVATE KEY.
THIS WILL BE STORED IN THE SERVER ALONE. CLIENTS DO NOT NEED IT!
server_cer.pem *CAN* BE SHARED WITH CLIENTS, OR THE CLIENTS CAN SIMPLY
USE YOUR SELF-SIGNED CA_CER.PEM
3. Generate any number of private client certificate/key pairs (using the
private CA above)
openssl genrsa -out client1_key.pem 2048
openssl req -out client1_req.csr -key client1_key.pem -new -config client.conf
openssl x509 -req -in client1_req.csr -out client1_cer.pem -sha256 -CAcreateserial -days 4000 -CA ca_cer.pem -CAkey ca_key.pem
Every client should have its own unique certificate generated and
a copy of that specific client's private key.
DO NOT SHARE THE PRIVATE KEY GENERATED ABOVE!
Included with this example are *SAMPLE* certs and keys. They are NOT
SECURE, since they're shared with all copies of the repo, so
DO NOT USE THE SAMPLE CERTS, KEYS, OR CAS IN YOUR OWN PROJECT!!!
Run this example and then try connecting to the server IP:4433.
If you don't specify the client cert and key on the WGET command
line, you will not get connected.
ex: wget --quiet --O - --no-check-certificate --certificate=client1_cer.pem --private-key=client1_key.pem https://esp.ip.add.ress/
ex: curl --insecure --cert client1_cer.pem --key client1_key.pem https://esp.ip.add.ress/
This example is released into the public domain.
*/
#include <ESP8266WiFi.h>
#include <time.h>
#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif
const char *ssid = STASSID;
const char *pass = STAPSK;
constexpr int port = 443;
// The server which will require a client cert signed by the trusted CA
BearSSL::WiFiServerSecure server(port);
// The hardcoded certificate authority for this example.
// The server's private key which must be kept secret
// The server's public certificate which must be shared
// Don't use them on your own apps!!!!!
#define USING_INSECURE_CERTS_AND_KEYS_AND_CAS 1
#include <ssl-tls-ca-key-cert-example.h>
// Note there are no client certificates required here in the server.
// That is because all clients will send a certificate that can be
// proven to be signed by the public CA certificate included at the
// head of the app.
// Set time via NTP, as required for x.509 validation
void setClock() {
configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov");
Serial.print("Waiting for NTP time sync: ");
time_t now = time(nullptr);
while (now < 8 * 3600 * 2) {
delay(500);
Serial.print(".");
now = time(nullptr);
}
Serial.println("");
struct tm timeinfo;
gmtime_r(&now, &timeinfo);
Serial.print("Current time: ");
Serial.print(asctime(&timeinfo));
}
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println();
// We start by connecting to a WiFi network
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
setClock(); // Required for X.509 validation
// Attach the server private cert/key combo
BearSSL::X509List *serverCertList = new BearSSL::X509List(server_cert);
BearSSL::PrivateKey *serverPrivKey = new BearSSL::PrivateKey(server_private_key);
server.setRSACert(serverCertList, serverPrivKey);
// Require a certificate validated by the trusted CA
BearSSL::X509List *serverTrustedCA = new BearSSL::X509List(ca_cert);
server.setClientTrustAnchor(serverTrustedCA);
// Actually start accepting connections
server.begin();
Serial.println("This example requires a client certificate.");
Serial.printf("ex: wget --quiet --O - --no-check-certificate --certificate=client1_cer.pem --private-key=client1_key.pem https://%s:%d/\n", WiFi.localIP().toString().c_str(), port);
Serial.printf("ex: curl --insecure --cert client1_cer.pem --key client1_key.pem https://%s:%d/\n", WiFi.localIP().toString().c_str(), port);
}
static const char *HTTP_RES = "HTTP/1.0 200 OK\r\n"
"Connection: close\r\n"
"Content-Length: 59\r\n"
"Content-Type: text/html; charset=iso-8859-1\r\n"
"\r\n"
"<html>\r\n"
"<body>\r\n"
"<p>Hello my friend!</p>\r\n"
"</body>\r\n"
"</html>\r\n";
void loop() {
BearSSL::WiFiClientSecure incoming = server.accept();
if (!incoming) { return; }
Serial.println("Incoming connection...\n");
// Ugly way to wait for \r\n (i.e. end of HTTP request which we don't actually parse here)
uint32_t timeout = millis() + 1000;
int lcwn = 0;
for (;;) {
unsigned char x = 0;
if ((millis() > timeout) || (incoming.available() && incoming.read(&x, 1) < 0)) {
incoming.stop();
Serial.printf("Connection error, closed\n");
return;
} else if (!x) {
yield();
continue;
} else if (x == 0x0D) {
continue;
} else if (x == 0x0A) {
if (lcwn) { break; }
lcwn = 1;
} else
lcwn = 0;
}
incoming.write((uint8_t *)HTTP_RES, strlen(HTTP_RES));
incoming.flush();
incoming.stop();
Serial.printf("Connection closed.\n");
}