8000 Introducing self-signed certificates generated on the ESP32 · giofranco/esp32_https_server@b37ec0c · GitHub
[go: up one dir, main page]

Skip to content

Commit b37ec0c

Browse files
committed
Introducing self-signed certificates generated on the ESP32
1 parent 5933514 commit b37ec0c

File tree

4 files changed

+536
-3
lines changed

4 files changed

+536
-3
lines changed

README.md

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ The library is self-contained and just needs the Arduino and ESP32 system librar
2020

2121
Clone or download the content of this git repository into your Arduino/libraries folder and restart you IDE.
2222

23-
To run the examples, you need to execute the script extras/create_cert.sh first. This script will create a simple CA to sign certificates that are used with the examples. Some notes on the usage can be found in the extras/README.md file.
23+
To run the examples (except for the _Self-Signed-Certificates_ example), you need to execute the script extras/create_cert.sh first. This script will create a simple CA to sign certificates that are used with the examples. Some notes on the usage can be found in the extras/README.md file.
2424

2525
You then should be able to add the library to your project if you selected the ESP32 as architecture.
2626

@@ -37,6 +37,7 @@ You will find several examples showing how you can use the library:
3737
- [Async-Server](examples/Async-Server/Async-Server.ino): Like the Static-Page example, but the server runs in a separate task on the ESP32, so you do not need to call the loop() function in your main sketch.
3838
- [Websocket-Chat](examples/Websocket-Chat/Websocket-Chat.ino): Provides a browser-based chat built on top of websockets. **Note:** Websockets are still under development!
3939
- [Parameter-Validation](examples/Parameter-Validation/Parameter-Validation.ino): Shows how you can integrate validator functions to do formal checks on parameters in your URL.
40+
- [Self-Signed-Certificate](examples/Self-Signed/Self-Signed.ino): Shows how to generate a self-signed certificate on the fly on the ESP when the sketch starts. You do not need to run `create_cert.sh` to use this example.
4041

4142
If you encounter error messages that cert.h or private\_key.h are missing when running an example, make sure to run create\_cert.sh first (see Setup Instructions).
4243

@@ -144,4 +145,35 @@ By default, you need to pass control to the server explicitly. This is done by c
144145

145146
If you want to have the server running in the background (and not calling `loop()` by yourself every few milliseconds), you can make use of the ESP32's task feature and put the whole server in a separate task.
146147

147-
See the Async-Server example to see how this can be done.
148+
See the Async-Server example to see how this can be done.
149+
150+
## Advanced Configuration
151+
152+
This section covers some advanced configuration options that allow you e.g. to customize the build process, but which might require more advanced programming skills and a more sophisticated IDE that just the default Arduino IDE.
153+
154+
### Saving Space by Reducing Functionality
155+
156+
To save program space on the microcontroller, there are some parts of the library that can be disabled during compilation and will then not be a part of your program.
157+
158+
The following flags are currently available:
159+
160+
| Flag | Effect
161+
| ------------------------- | ---------------------------
162+
| HTTPS_DISABLE_SELFSIGNING | Removes the code for generating a self-signed certificate at runtime. You will need to provide certificate and private key data from another data source to use the `HTTPSServer`.
163+
164+
Setting these flags requires a build environment that gives you some control of the compiler, as libraries are usually compiled separately, so just doing a `#define HTTPS_SOMETHING` in your sketch will not work.
165+
166+
**Example: Configuration with Platform IO**
167+
168+
To set these flags in Platform IO, you can modify your `platformio.ini`. To disable for example the self-signed-certificates part of the library, the file could look like this:
169+
170+
```ini
171+
[env:esp32dev]
172+
platform = espressif32
173+
board = esp32dev
174+
framework = arduino
175+
build_flags =
176+
-DHTTPS_DISABLE_SELFSIGNING
177+
```
178+
179+
Note the `-D` in front of the actual flag name, that passes this flag as a definition to the preprocessor. Multiple flags can be added one per line.
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
/**
2+
* Example for the ESP32 HTTP(S) Webserver
3+
*
4+
* IMPORTANT NOTE:
5+
* To run this script, you need to
6+
* 1) Enter your WiFi SSID and PSK below this comment
7+
*
8+
* This script will install an HTTPS Server on your ESP32 with the following
9+
* functionalities:
10+
* - Show simple page on web server root
11+
* - 404 for everything else
12+
*
13+
* In contrast to the other examples, the certificate and the private key will be
14+
* generated on the ESP32, so you do not need to provide them here.
15+
* (this means no need to run create_cert.sh)
16+
*/
17+
18+
// TODO: Configure your WiFi here
19+
#define WIFI_SSID "<your ssid goes here>"
20+
#define WIFI_PSK "<your pre-shared key goes here>"
21+
22+
// We will use wifi
23+
#include <WiFi.h>
24+
25+
// Includes for the server
26+
#include <HTTPSServer.hpp>
27+
#include <SSLCert.hpp>
28+
#include <HTTPRequest.hpp>
29+
#include <HTTPResponse.hpp>
30+
31+
// The HTTPS Server comes in a separate namespace. For easier use, include it here.
32+
using namespace httpsserver;
33+
34+
SSLCert * cert;
35+
HTTPSServer * secureServer;
36+
37+
// Declare some handler functions for the various URLs on the server
38+
void handleRoot(HTTPRequest * req, HTTPResponse * res);
39+
void handle404(HTTPRequest * req, HTTPResponse * res);
40+
41+
void setup() {
42+
// For logging
43+
Serial.begin(115200);
44+
delay(3000); // wait for the monitor to reconnect after uploading.
45+
46+
Serial.println("Creating a new self-signed certificate.");
47+
Serial.println("This may take up to a minute, so be patient ;-)");
48+
49+
// First, we create an empty certificate:
50+
cert = new SSLCert();
51+
52+
// Now, we use the function createSelfSignedCert to create private key and certificate.
53+
// The function takes the following paramters:
54+
// - Key size: 1024 or 2048 bit should be fine here, 4096 on the ESP might be "paranoid mode"
55+
// (in generel: shorter key = faster but less secure)
56+
// - Distinguished name: The name of the host as used in certificates.
57+
// If you want to run your own DNS, the part after CN (Common Name) should match the DNS
58+
// entry pointing to your ESP32. You can try to insert an IP there, but that's not really good style.
59+
int createCertResult = createSelfSignedCert(*cert, KEYSIZE_2048, "CN=myesp32.local,O=FancyCompany,C=DE");
60+
61+
// Now check if creating that worked
62+
if (createCertResult != 0) {
63+
Serial.printf("Cerating certificate failed. Error Code = 0x%02X, check SSLCert.hpp for details", createCertResult);
64+
while(true) delay(500);
65+
}
66+
Serial.println("Creating the certificate was successful");
67+
68+
// If you're working on a serious project, this would be a good place to initialize some form of non-volatile storage
69+
// and to put the certificate and the key there. This has the advantage that the certificate stays the same after a reboot
70+
// so your client still trusts your server, additionally you increase the speed-up of your application.
71+
// Some browsers like Firefox might even reject the second run for the same issuer name (the distinguished name defined above).
72+
//
73+
// Storing:
74+
F438 // For the key:
75+
// cert->getPKLength() will return the length of the private key in byte
76+
// cert->getPKData() will return the actual private key (in DER-format, if that matters to you)
77+
// For the certificate:
78+
// cert->getCertLength() and ->getCertData() do the same for the actual certificate data.
79+
// Restoring:
80+
// When your applications boots, check your non-volatile storage for an existing certificate, and if you find one
81+
// use the parameterized SSLCert constructor to re-create the certificate and pass it to the HTTPSServer.
82+
//
83+
// A short reminder on key security: If you're working on something professional, be aware that the storage of the ESP32 is
84+
// not encrypted in any way. This means that if you just write it to the flash storage, it is easy to extract it if someone
85+
// gets a hand on your hardware. You should decide if that's a relevant risk for you and apply countermeasures like flash
86+
// encryption if neccessary
87+
88+
// We can now use the new certificate to setup our server as usual.
89+
secureServer = new HTTPSServer(cert);
90+
91+
// Connect to WiFi
92+
Serial.println("Setting up WiFi");
93+
WiFi.begin(WIFI_SSID, WIFI_PSK);
94+
while (WiFi.status() != WL_CONNECTED) {
95+
Serial.print(".");
96+
delay(500);
97+
}
98+
Serial.print("Connected. IP=");
99+
Serial.println(WiFi.localIP());
100+
101+
// For every resource available on the server, we need to create a ResourceNode
102+
// The ResourceNode links URL and HTTP method to a handler function
103+
ResourceNode * nodeRoot = new ResourceNode("/", "GET", &handleRoot);
104+
ResourceNode * node404 = new ResourceNode("", "GET", &handle404);
105+
106+
// Add the root node to the server
107+
secureServer->registerNode(nodeRoot);
108+
// Add the 404 not found node to the server.
109+
secureServer->setDefaultNode(node404);
110+
111+
Serial.println("Starting server...");
112+
secureServer->start();
113+
if (secureServer->isRunning()) {
114+
Serial.println("Server ready.");
115+
}
116+
}
117+
118+
void loop() {
119+
// This call will let the server do its work
120+
secureServer->loop();
121+
122+
// Other code would go here...
123+
delay(1);
124+
}
125+
126+
void handleRoot(HTTPRequest * req, HTTPResponse * res) {
127+
// Status code is 200 OK by default.
128+
// We want to deliver a simple HTML page, so we send a corresponding content type:
129+
res->setHeader("Content-Type", "text/html");
130+
131+
// The response implements the Print interface, so you can use it just like
132+
// you would write to Serial etc.
133+
res->println("<!DOCTYPE html>");
134+
res->println("<html>");
135+
res->println("<head><title>Hello World!</title></head>");
136+
res->println("<body>");
137+
res->println("<h1>Hello World!</h1>");
138+
res->print("<p>Your server is running for ");
139+
// A bit of dynamic data: Show the uptime
140+
res->print((int)(millis()/1000), DEC);
141+
res->println(" seconds.</p>");
142+
res->println("</body>");
143+
res->println("</html>");
144+
}
145+
146+
void handle404(HTTPRequest * req, HTTPResponse * res) {
147+
// Discard request body, if we received any
148+
// We do this, as this is the default node and may also server POST/PUT requests
149+
req->discardRequestBody();
150+
151+
// Set the response status
152+
res->setStatusCode(404);
153+
res->setStatusText("Not Found");
154+
155+
// Set content type of the response
156+
res->setHeader("Content-Type", "text/html");
157+
158+
// Write a tiny HTTP page
159+
res->println("<!DOCTYPE html>");
160+
res->println("<html>");
161+
res->println("<head><title>Not Found</title></head>");
162+
res->println("<body><h1>404 Not Found</h1><p>The requested resource was not found on this server.</p></body>");
163+
res->println("</html>");
164+
}

0 commit comments

Comments
 (0)
0