Skip to content

Commit f73d414

Browse files
committed
WiFiClientSecure: add certificate fingerprint verification (#43)
1 parent c970dec commit f73d414

File tree

5 files changed

+65
-2
lines changed

5 files changed

+65
-2
lines changed

libraries/ESP8266WiFi/examples/HTTPSRequest/HTTPSRequest.ino

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ const char* password = "........";
2020
const char* host = "api.github.com";
2121
const int httpsPort = 443;
2222

23+
// Use web browser to view and copy
24+
// SHA1 fingerprint of the certificate
25+
const char* fingerprint = "CF 05 98 89 CA FF 8E D8 5E 5C E0 C2 E4 F7 E6 C3 C7 50 DD 5C";
26+
2327
void setup() {
2428
Serial.begin(115200);
2529
Serial.println();
@@ -35,9 +39,7 @@ void setup() {
3539
Serial.println("IP address: ");
3640
Serial.println(WiFi.localIP());
3741

38-
3942
// Use WiFiClientSecure class to create TLS connection
40-
4143
WiFiClientSecure client;
4244
Serial.print("connecting to ");
4345
Serial.println(host);
@@ -46,6 +48,12 @@ void setup() {
4648
return;
4749
}
4850

51+
if (client.verify(fingerprint, host)) {
52+
Serial.println("certificate matches");
53+
} else {
54+
Serial.println("certificate doesn't match");
55+
}
56+
4957
String url = "/repos/esp8266/Arduino/commits/esp8266/status";
5058
Serial.print("requesting URL: ");
5159
Serial.println(url);

libraries/ESP8266WiFi/src/WiFiClientSecure.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,50 @@ void WiFiClientSecure::stop() {
242242
return WiFiClient::stop();
243243
}
244244

245+
static bool parseHexNibble(char pb, uint8_t* res) {
246+
if (pb >= '0' && pb <= '9') {
247+
*res = (uint8_t) (pb - '0'); return true;
248+
}
249+
else if (pb >= 'a' && pb <= 'f') {
250+
*res = (uint8_t) (pb - 'a' + 10); return true;
251+
}
252+
else if (pb >= 'A' && pb <= 'F') {
253+
*res = (uint8_t) (pb - 'A' + 10); return true;
254+
}
255+
return false;
256+
}
257+
258+
bool WiFiClientSecure::verify(const char* fp, const char* url) {
259+
uint8_t sha1[20];
260+
int len = strlen(fp);
261+
int pos = 0;
262+
for (int i = 0; i < sizeof(sha1); ++i) {
263+
while (pos < len && fp[pos] == ' ') {
264+
++pos;
265+
}
266+
DEBUGV("pos:%d ", pos);
267+
if (pos > len - 2) {
268+
DEBUGV("fingerprint too short\r\n");
269+
return false;
270+
}
271+
uint8_t high, low;
272+
if (!parseHexNibble(fp[pos], &high) || !parseHexNibble(fp[pos+1], &low)) {
273+
DEBUGV("invalid hex sequence: %c%c\r\n", fp[pos], fp[pos+1]);
274+
return false;
275+
}
276+
pos += 2;
277+
sha1[i] = low | (high << 4);
278+
}
279+
if (ssl_match_fingerprint(*_ssl, sha1) != 0) {
280+
DEBUGV("fingerprint doesn't match\r\n");
281+
return false;
282+
}
283+
284+
//TODO: check URL against certificate
285+
286+
return true;
287+
}
288+
245289
extern "C" int ax_port_read(int fd, uint8_t* buffer, size_t count) {
246290
ClientContext* _client = reinterpret_cast<ClientContext*>(fd);
247291
if (_client->state() != ESTABLISHED && !_client->getSize()) {

libraries/ESP8266WiFi/src/WiFiClientSecure.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ class WiFiClientSecure : public WiFiClient {
3838
int connect(IPAddress ip, uint16_t port) override;
3939
int connect(const char* name, uint16_t port) override;
4040

41+
bool verify(const char* fingerprint, const char* url);
42+
4143
size_t write(const uint8_t *buf, size_t size) override;
4244
int read(uint8_t *buf, size_t size) override;
4345
int available() override;

libraries/ESP8266WiFi/src/include/ssl.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,15 @@ EXP_FUNC void STDCALL ssl_display_error(int error_code);
375375
*/
376376
EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl);
377377

378+
/**
379+
* @brief Check if certificate fingerprint (SHA1) matches the one given.
380+
*
381+
* @param ssl [in] An SSL object reference.
382+
* @param fp [in] SHA1 fingerprint to match against
383+
* @return SSL_OK if the certificate is verified.
384+
*/
385+
EXP_FUNC int STDCALL ssl_match_fingerprint(const SSL *ssl, const uint8_t* fp);
386+
378387
/**
379388
* @brief Retrieve an X.509 distinguished name component.
380389
*

tools/sdk/lib/libaxtls.a

-178 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)