Skip to content

Commit 10bcc65

Browse files
Remove dependency on SD/SPIFFS from CertStore
Due to popular demand, remove the hardcoded dependency on SPIFFS or SD from the CertStore by factoring out the file interface into a new class (CertStoreFile) that the user will need to implement as a thin wrapper around either a SPIFFS.file or a SD.file Combine the downloaded certificates into a UNIX "ar" archive and parse that on-the-fly to allow easy inspection and creation of the Cert Store database. Examples updated with a new certificate downloader that creates the certs.ar archive and with a single sample that can be built for either SPIFFS or SD with a #define. Users can copy the implementation of the CertStoreFile they need to their own code as it is self-contained. Also move the CertStore to the BearSSL namespace and remove the suffix and separate SPIFFS/SD sources. Fixes #4740
1 parent 529baab commit 10bcc65

9 files changed

+276
-457
lines changed

Diff for: libraries/ESP8266WiFi/examples/BearSSL_CertStore/BearSSL_CertStore.ino

+87-5
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@
77
//
88
// Why would you need a CertStore?
99
//
10-
// If you know the exact serve being connected to, or you
10+
// If you know the exact server being connected to, or you
1111
// are generating your own self-signed certificates and aren't
1212
// allowing connections to HTTPS/TLS servers out of your
1313
// control, then you do NOT want a CertStore. Hardcode the
1414
// self-signing CA or the site's x.509 certificate directly.
1515
//
1616
// However, if you don't know what specific sites the system
1717
// will be required to connect to and verify, a
18-
// CertStore{SPIFFS,SD}BearSSL can allow you to select from
18+
// CertStore can allow you to select from among
1919
// 10s or 100s of CAs against which you can check the
2020
// target's X.509, without taking any more RAM than a single
2121
// certificate. This is the same way that standard browsers
@@ -31,7 +31,7 @@
3131
// Released to the public domain
3232

3333
#include <ESP8266WiFi.h>
34-
#include <CertStoreSPIFFSBearSSL.h>
34+
#include <CertStoreBearSSL.h>
3535
#include <time.h>
3636

3737
const char *ssid = "....";
@@ -40,7 +40,83 @@ const char *pass = "....";
4040
// A single, global CertStore which can be used by all
4141
// connections. Needs to stay live the entire time any of
4242
// the WiFiClientBearSSLs are present.
43-
CertStoreSPIFFSBearSSL certStore;
43+
BearSSL::CertStore certStore;
44+
45+
// Uncomment below to use the SD card to store the certs
46+
// #define USE_SDCARD 1
47+
48+
#ifdef USE_SDCARD
49+
50+
#include <SD.h>
51+
class SDCertStoreFile : public BearSSL::CertStoreFile {
52+
public:
53+
SDCertStoreFile(const char *name) {
54+
_name = name;
55+
};
56+
virtual ~SDCertStoreFile() override {};
57+
58+
// The main API
59+
virtual bool open(bool write = false) override {
60+
_file = SD.open(_name, write ? FILE_WRITE : FILE_READ);
61+
return _file;
62+
}
63+
virtual bool seek(size_t absolute_pos) override {
64+
return _file.seek(absolute_pos);
65+
}
66+
virtual ssize_t read(void *dest, size_t bytes) override {
67+
return _file.read(dest, bytes);
68+
}
69+
virtual ssize_t write(void *dest, size_t bytes) override {
70+
return _file.write((const uint8_t*)dest, bytes);
71+
}
72+
virtual void close() override {
73+
_file.close();
74+
}
75+
76+
private:
77+
File _file;
78+
const char *_name;
79+
};
80+
81+
SDCertStoreFile certs_idx("/certs.idx");
82+
SDCertStoreFile certs_ar("/certs.ar");
83+
84+
#else
85+
86+
#include <FS.h>
87+
class SPIFFSCertStoreFile : public BearSSL::CertStoreFile {
88+
public:
89+
SPIFFSCertStoreFile(const char *name) {
90+
_name = name;
91+
};
92+
virtual ~SPIFFSCertStoreFile() override {};
93+
94+
// The main API
95+
virtual bool open(bool write = false) override {
96+
_file = SPIFFS.open(_name, write ? "w" : "r");
97+
return _file;
98+
}
99+
virtual bool seek(size_t absolute_pos) override {
100+
return _file.seek(absolute_pos, SeekSet);
101+
}
102+
virtual ssize_t read(void *dest, size_t bytes) override {
103+
return _file.readBytes((char*)dest, bytes);
104+
}
105+
virtual ssize_t write(void *dest, size_t bytes) override {
106+
return _file.write((uint8_t*)dest, bytes);
107+
}
108+
virtual void close() override {
109+
_file.close();
110+
}
111+
112+
private:
113+
File _file;
114+
const char *_name;
115+
};
116+
117+
SPIFFSCertStoreFile certs_idx("/certs.idx");
118+
SPIFFSCertStoreFile certs_ar("/certs.ar");
119+
#endif
44120

45121
// Set time via NTP, as required for x.509 validation
46122
void setClock() {
@@ -108,6 +184,12 @@ void setup() {
108184
Serial.println();
109185
Serial.println();
110186

187+
#ifdef USE_SDCARD
188+
SD.begin();
189+
#else
190+
SPIFFS.begin();
191+
#endif
192+
111193
// We start by connecting to a WiFi network
112194
Serial.print("Connecting to ");
113195
Serial.println(ssid);
@@ -126,7 +208,7 @@ void setup() {
126208

127209
setClock(); // Required for X.509 validation
128210

129-
int numCerts = certStore.initCertStore();
211+
int numCerts = certStore.initCertStore(&certs_idx, &certs_ar);
130212
Serial.printf("Number of CA certs read: %d\n", numCerts);
131213
if (numCerts == 0) {
132214
Serial.printf("No certs found. Did you run certs-from-mozill.py and upload the SPIFFS directory before running?\n");

Diff for: libraries/ESP8266WiFi/examples/BearSSL_CertStore/certs-from-mozilla.py

+20-5
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
# Script by Earle F. Philhower, III. Released to the public domain.
1010

1111
import csv
12-
from os import mkdir
13-
from subprocess import Popen, PIPE
12+
import os
13+
from subprocess import Popen, PIPE, call
1414
import urllib2
1515
try:
1616
# for Python 2.x
@@ -40,12 +40,27 @@
4040
except:
4141
pass
4242

43+
derFiles = []
44+
idx = 0
4345
# Process the text PEM using openssl into DER files
4446
for i in range(0, len(pems)):
45-
certName = "data/ca_%03d.der" % (i);
47+
certName = "data/ca_%03d.der" % (idx);
4648
thisPem = pems[i].replace("'", "")
4749
print names[i] + " -> " + certName
48-
pipe = Popen(['openssl','x509','-inform','PEM','-outform','DER','-out', certName], shell = False, stdin = PIPE).stdin
50+
ssl = Popen(['openssl','x509','-inform','PEM','-outform','DER','-out', certName], shell = False, stdin = PIPE)
51+
pipe = ssl.stdin
4952
pipe.write(thisPem)
50-
pipe.close
53+
pipe.close()
54+
ssl.wait()
55+
if os.path.exists(certName):
56+
derFiles.append(certName)
57+
idx = idx + 1
5158

59+
if os.path.exists("data/certs.ar"):
60+
os.unlink("data/certs.ar");
61+
62+
arCmd = ['ar', 'mcs', 'data/certs.ar'] + derFiles;
63+
call( arCmd )
64+
65+
for der in derFiles:
66+
os.unlink(der)

0 commit comments

Comments
 (0)