Skip to content

Commit 080b9e1

Browse files
committed
Use per device self signed cert #163
- Make cert unique for firefox - Key length 2048bit - Create key in dedicated task to get a properly sized stack - Use a feature branch of the https lib to get the hostname listed in thr subjectAltName - progress bar during key creation in display
1 parent ff66f3a commit 080b9e1

File tree

5 files changed

+109
-30
lines changed

5 files changed

+109
-30
lines changed

platformio.ini

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ lib_deps =
5454
adafruit/Adafruit BMP280 Library@^2.1.0
5555
pololu/VL53L0X@^1.3.0
5656
; https://github.com/fhessel/esp32_https_server
57-
esp32_https_server
57+
https://github.com/fhessel/esp32_https_server.git#feature/subjectAltName
58+
; esp32_https_server@
5859
build_flags =
5960
-DCORE_DEBUG_LEVEL=3
6061
-DHTTPS_LOGLEVEL=3

src/OpenBikeSensorFirmware.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ void setup() {
254254
}
255255

256256
if (SD.begin()) {
257-
displayTest->showTextOnGrid(2, displayTest->currentLine(), "SD... ok");
257+
displayTest->showTextOnGrid(2, displayTest->currentLine(), "SD... OK");
258258
}
259259
delay(333); // Added for user experience
260260

@@ -302,7 +302,7 @@ void setup() {
302302
writer = new CSVFileWriter;
303303
writer->setFileName();
304304
writer->writeHeader(trackUniqueIdentifier);
305-
displayTest->showTextOnGrid(2, displayTest->currentLine(), "CSV file... ok");
305+
displayTest->showTextOnGrid(2, displayTest->currentLine(), "CSV file... OK");
306306
} else {
307307
displayTest->showTextOnGrid(2, displayTest->currentLine(), "CSV. skipped");
308308
}

src/configServer.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
#include <HTTPURLEncodedBodyParser.hpp>
3333
#include <esp_ota_ops.h>
3434
#include <esp_partition.h>
35-
#include <utils/Https.h>
35+
#include <utils/https.h>
3636
#include "SPIFFS.h"
3737
#include "HTTPMultipartBodyParser.hpp"
3838
#include "Firmware.h"
@@ -368,10 +368,12 @@ static const char* const makeCurrentLocationPrivateIndex =
368368
static const char* const deleteIndex =
369369
"<h3>Flash</h3>"
370370
"<p>Flash stores ssl certificate and configuration.</p>"
371-
"<label for='flash'>format flash</label>"
371+
"<label for='flash'>Format flash</label>"
372372
"<input type='checkbox' id='flash' name='flash' "
373373
"onchange=\"document.getElementById('flashCert').checked = document.getElementById('flashConfig').checked = document.getElementById('flash').checked;\">"
374-
"<label for='flashCert'>delete ssl certificate, a new one will be created at the next start</label>"
374+
"<label for='flashCert'>Delete ssl certificate, a new one will be created at the next start. "
375+
" You need to remove the old certificate from your browsers exception store too.</label>"
376+
// Link https://support.mozilla.org/en-US/kb/Certificate-contains-the-same-serial-number-as-another-certificate ?
375377
"<input type='checkbox' id='flashCert' name='flashCert'>"
376378
"<label for='flashConfig'>delete configuration, default settings will be used at the next start</label>"
377379
"<input type='checkbox' id='flashConfig' name='flashConfig'>"
@@ -495,15 +497,24 @@ void beginPages() {
495497
insecureServer->setDefaultHeader("Server", std::string("OBS/") + OBSVersion);
496498
}
497499

500+
static int ticks;
501+
static void progressTick() {
502+
displayTest->drawWaitBar(4, ticks++);
503+
}
498504

499505
void createHttpServer() {
500-
server = new HTTPSServer(Https::getCertificate(), 443, 2);
506+
if (!Https::existsCertificate()) {
507+
displayTest->showTextOnGrid(0, 3, "Creating ssl cert!");
508+
509+
}
510+
server = new HTTPSServer(Https::getCertificate(progressTick), 443, 2);
511+
displayTest->clearProgressBar(4);
512+
displayTest->showTextOnGrid(0, 3, "");
501513
insecureServer = new HTTPServer(80, 1);
502514

503-
log_i("About to create pages.");
504515
beginPages();
505516

506-
log_i("About to start.");
517+
log_i("Starting http(s) servers.");
507518
server->start();
508519
insecureServer->start();
509520
}

src/utils/Https.cpp renamed to src/utils/https.cpp

Lines changed: 81 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,12 @@
2424
#include "Https.h"
2525
#include <SPIFFS.h>
2626
#include <FS.h>
27+
#include "esp_task_wdt.h"
2728

2829
using namespace httpsserver;
2930

31+
static volatile bool isCertReady = 0;
32+
3033
// "20190101000000"
3134
static std::string toCertDate(time_t theTime) {
3235
char date[32];
@@ -39,12 +42,75 @@ static std::string toCertDate(time_t theTime) {
3942
return std::string(date);
4043
}
4144

45+
static std::string createDn() {
46+
char dn[128];
47+
const uint64_t chipid_num = ESP.getEfuseMac();
48+
// Placed the date in here - firefox does complain about duplicate cert
49+
// otherwise (we can not increase the serial number from here).
50+
snprintf(dn, sizeof(dn),
51+
"CN=obs.local,O=openbikesensor.org,OU=%04x%08x,L=%s,C=DE",
52+
(uint16_t)(chipid_num >> 32),
53+
(uint32_t)(chipid_num),
54+
toCertDate(time(nullptr)).c_str());
55+
return std::string(dn);
56+
}
57+
58+
static void createCert(void *param) {
59+
std::string fromDate;
60+
std::string toDate;
61+
time_t now = time(nullptr);
62+
if (now > (2020 - 1970) * 365 * 24 * 60 * 60) {
63+
fromDate = toCertDate(now);
64+
// Suggestion for hardware devices is to set the validity of the
65+
// cert to a high value. But Apple limits this value to 825
66+
// days in https://support.apple.com/HT210176
67+
toDate = toCertDate(now + 824 * 24 * 60 * 60);
68+
} else {
69+
fromDate = "20210513090700";
70+
toDate = "20301232235959";
71+
}
4272

73+
log_i("DN will be %s", createDn().c_str());
74+
75+
SSLCert newCert;
76+
int res = createSelfSignedCert(newCert,
77+
KEYSIZE_2048,
78+
createDn(),
79+
fromDate,
80+
toDate);
81+
log_i("PK Length %d, Key Length %d", newCert.getPKLength(), newCert.getCertLength());
82+
83+
if (res != 0) {
84+
// Certificate generation failed. Inform the user.
85+
log_e("An error occured during certificate generation.");
86+
log_e("Error code is 0x%04x", res);
87+
log_e("You may have a look at SSLCert.h to find the reason for this error.");
88+
} else {
89+
SSLCert *cert = static_cast<SSLCert *>(param);
90+
cert->setCert(newCert.getCertData(), newCert.getCertLength());
91+
cert->setPK(newCert.getPKData(), newCert.getPKLength());
92+
log_i("Created new cert.");
93+
};
94+
95+
// Can this be done more elegant?
96+
isCertReady = 1;
97+
vTaskDelete(nullptr);
98+
}
99+
100+
/* Just ensure there is a cert! */
101+
void Https::ensureCertificate() {
102+
delete getCertificate();
103+
}
104+
105+
bool Https::existsCertificate() {
106+
return SPIFFS.exists("/key.der") && SPIFFS.exists("/cert.der");
107+
}
43108

44109
/* Load or create cert.
45110
* Based on https://github.com/fhessel/esp32_https_server/blob/de1876cf6fe717cf236ad6603a97e88f22e38d62/examples/REST-API/REST-API.ino#L219
111+
* https://github.com/fhessel/esp32_https_server/issues/48
46112
*/
47-
SSLCert *Https::getCertificate() {
113+
SSLCert *Https::getCertificate(std::function<void()> progress) {
48114
// Try to open key and cert file to see if they exist
49115
File keyFile = SPIFFS.open("/key.der");
50116
File certFile = SPIFFS.open("/cert.der");
@@ -56,27 +122,22 @@ SSLCert *Https::getCertificate() {
56122
log_i("This may take up to a minute, so please stand by :)");
57123

58124
SSLCert * newCert = new SSLCert();
59-
// The part after the CN= is the domain that this certificate will match, in this
60-
// case, it's esp32.local.
61-
// However, as the certificate is self-signed, your browser won't trust the server
62-
// anyway.
63-
64-
std::string fromDate;
65-
std::string toDate;
66-
time_t now = time(nullptr);
67-
if (now > (2020 - 1970) * 365 * 24 * 60 * 60) {
68-
fromDate = toCertDate(now);
69-
toDate = toCertDate(now + 365 * 24 * 60 * 60);
70-
} else {
71-
fromDate = "20210513090700";
72-
toDate = "20301232235959";
125+
126+
TaskHandle_t xHandle;
127+
xTaskCreate(reinterpret_cast<TaskFunction_t>(createCert), "createCert",
128+
16 * 1024, newCert, 1, &xHandle);
129+
130+
while (!isCertReady) {
131+
if (progress) {
132+
progress();
133+
}
134+
delay(100);
135+
yield();
136+
esp_task_wdt_reset();
73137
}
74138

75-
int res = createSelfSignedCert(*newCert,
76-
KEYSIZE_1024,
77-
"CN=obs.local,O=openbikesensor.org,C=DE",
78-
fromDate,
79-
toDate);
139+
log_i("PK Length %d, Key Length %d", newCert->getPKLength(), newCert->getCertLength());
140+
int res = 0;
80141
if (res == 0) {
81142
// We now have a certificate. We store it on the SPIFFS to restore it on next boot.
82143

src/utils/Https.h renamed to src/utils/https.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,19 @@
2525
#define OPENBIKESENSORFIRMWARE_HTTPS_H
2626

2727
#include <SSLCert.hpp>
28+
#include <functional>
2829

2930
using namespace httpsserver;
3031

3132
class Https {
3233
public:
33-
static SSLCert * getCertificate();
34+
static SSLCert * getCertificate(std::function<void()> progress = nullptr);
3435
static bool removeCertificate();
36+
static void ensureCertificate();
37+
static bool existsCertificate();
38+
39+
private:
40+
static SSLCert *getCertificateInternal();
3541
};
3642

3743

0 commit comments

Comments
 (0)