Skip to content

Commit 882e546

Browse files
Make verifier EC/RSA compatible at any bit length
Allow EC or RSA keys to be used to verify, as well as any RSA key length supported by BearSSL (currently 4096 bits).
1 parent ac25877 commit 882e546

File tree

5 files changed

+78
-55
lines changed

5 files changed

+78
-55
lines changed

cores/esp8266/Updater.cpp

+16-17
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,6 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn) {
141141
DEBUG_UPDATER.printf("[begin] _size: 0x%08X (%d)\n", _size, _size);
142142
#endif
143143

144-
_md5.begin();
145-
if (_hash) {
146-
_hash->begin();
147-
}
148144
return true;
149145
}
150146

@@ -188,13 +184,14 @@ bool UpdaterClass::end(bool evenIfRemaining){
188184
#ifdef DEBUG_UPDATER
189185
DEBUG_UPDATER.printf("[Updater] sigLen: %d\n", sigLen);
190186
#endif
191-
if (!sigLen || sigLen > 256) {
187+
if (sigLen != _verify->length()) {
192188
_setError(UPDATE_ERROR_SIGN);
193189
_reset();
194190
return false;
195191
}
196192
}
197193

194+
_md5.begin();
198195
int binSize = _size;
199196
if (_hash) {
200197
_hash->begin();
@@ -204,13 +201,13 @@ bool UpdaterClass::end(bool evenIfRemaining){
204201
DEBUG_UPDATER.printf("[Updater] Adjusted binsize: %d\n", binSize);
205202
#endif
206203
// Calculate the MD5 and hash using proper size
207-
uint8_t buff[32];
208-
for(int i = 0; i < binSize; i += 32) {
209-
ESP.flashRead(_startAddress + i, (uint32_t *)buff, 32);
204+
uint8_t buff[128];
205+
for(int i = 0; i < binSize; i += sizeof(buff)) {
206+
ESP.flashRead(_startAddress + i, (uint32_t *)buff, sizeof(buff));
210207

211-
int read = binSize - i;
212-
if(read > 32) {
213-
read = 32;
208+
size_t read = binSize - i;
209+
if(read > sizeof(buff)) {
210+
read = sizeof(buff);
214211
}
215212
_md5.add(buff, read);
216213
if (_hash) {
@@ -237,17 +234,23 @@ bool UpdaterClass::end(bool evenIfRemaining){
237234
for (int i=0; i<_hash->len(); i++) DEBUG_UPDATER.printf(" %02x", ret[i]);
238235
DEBUG_UPDATER.printf("\n");
239236
#endif
240-
uint8_t sig[256];
237+
uint8_t *sig = (uint8_t*)malloc(sigLen);
238+
if (!sig) {
239+
_setError(UPDATE_ERROR_SIGN);
240+
_reset();
241+
return false;
242+
}
241243
ESP.flashRead(_startAddress + binSize, (uint32_t *)sig, sigLen);
242244
#ifdef DEBUG_UPDATER
243-
DEBUG_UPDATER.printf("[Updater] sig[]:");
245+
DEBUG_UPDATER.printf("[Updater] Received Signature:");
244246
for (size_t i=0; i<sigLen; i++) {
245247
DEBUG_UPDATER.printf(" %02x", sig[i]);
246248
}
247249
DEBUG_UPDATER.printf("\n");
248250
#endif
249251
if (!_verify->verify(_hash, (void *)sig, sigLen)) {
250252
_setError(UPDATE_ERROR_SIGN);
253+
_reset();
251254
return false;
252255
}
253256
}
@@ -329,10 +332,6 @@ bool UpdaterClass::_writeBuffer(){
329332
_setError(UPDATE_ERROR_WRITE);
330333
return false;
331334
}
332-
_md5.add(_buffer, _bufferLen);
333-
if (_hash) {
334-
_hash->add(_buffer, _bufferLen);
335-
}
336335
_currentAddress += _bufferLen;
337336
_bufferLen = 0;
338337
return true;

cores/esp8266/Updater.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#endif
3030
#endif
3131

32+
// Abstract class to implement whatever signing hash desired
3233
class UpdaterHashClass {
3334
public:
3435
virtual void begin() = 0;
@@ -38,9 +39,11 @@ class UpdaterHashClass {
3839
virtual void *hash() = 0;
3940
};
4041

42+
// Abstract class to implement a signature verifier
4143
class UpdaterVerifyClass {
4244
public:
43-
virtual bool verify(UpdaterHashClass *hash, void *signature, uint32_t signatureLen) = 0;
45+
virtual uint32_t length() = 0; // How many bytes of signature are expected
46+
virtual bool verify(UpdaterHashClass *hash, void *signature, uint32_t signatureLen) = 0; // Verify, return "true" on success
4447
};
4548

4649
class UpdaterClass {

libraries/ESP8266WiFi/src/BearSSLHelpers.cpp

+31-7
Original file line numberDiff line numberDiff line change
@@ -844,11 +844,35 @@ void *BearSSLHashSHA256::hash() {
844844
}
845845

846846
// SHA256 verifier
847-
bool BearSSLVerifier::verify(UpdaterHashClass *hash, void *signature, uint32_t signatureLen) {
848-
if (!_pubKey || !hash || !signature || signatureLen != 256) return false;
849-
br_rsa_pkcs1_vrfy vrfy = br_rsa_pkcs1_vrfy_get_default();
850-
unsigned char vrf[32];
851-
bool ret = vrfy((const unsigned char *)signature, signatureLen, NULL, sizeof(vrf), _pubKey->getRSA(), vrf);
852-
if (!ret) return false;
853-
return !memcmp(vrf, hash->hash(), sizeof(vrf));
847+
uint32_t BearSSLSigningVerifier::length()
848+
{
849+
if (!_pubKey) {
850+
return 0;
851+
} else if (_pubKey->isRSA()) {
852+
return _pubKey->getRSA()->nlen;
853+
} else if (_pubKey->isEC()) {
854+
return _pubKey->getEC()->qlen;
855+
} else {
856+
return 0;
857+
}
858+
}
859+
860+
bool BearSSLSigningVerifier::verify(UpdaterHashClass *hash, void *signature, uint32_t signatureLen) {
861+
if (!_pubKey || !hash || !signature || signatureLen != length()) return false;
862+
863+
if (_pubKey->isRSA()) {
864+
bool ret;
865+
unsigned char vrf[hash->len()];
866+
br_rsa_pkcs1_vrfy vrfy = br_rsa_pkcs1_vrfy_get_default();
867+
ret = vrfy((const unsigned char *)signature, signatureLen, NULL, sizeof(vrf), _pubKey->getRSA(), vrf);
868+
if (!ret || memcmp(vrf, hash->hash(), sizeof(vrf)) ) {
869+
return false;
870+
} else {
871+
return true;
872+
}
873+
} else {
874+
br_ecdsa_vrfy vrfy = br_ecdsa_vrfy_raw_get_default();
875+
// The EC verifier actually does the compare, unlike the RSA one
876+
return vrfy(br_ec_get_default(), hash->hash(), hash->len(), _pubKey->getEC(), (const unsigned char *)signature, signatureLen);
877+
}
854878
};

libraries/ESP8266WiFi/src/BearSSLHelpers.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,13 @@ class BearSSLHashSHA256 : public UpdaterHashClass {
152152
unsigned char _sha256[32];
153153
};
154154

155-
class BearSSLVerifier : public UpdaterVerifyClass {
155+
class BearSSLSigningVerifier : public UpdaterVerifyClass {
156156
public:
157+
virtual uint32_t length() override;
157158
virtual bool verify(UpdaterHashClass *hash, void *signature, uint32_t signatureLen) override;
158159

159160
public:
160-
BearSSLVerifier(BearSSLPublicKey *pubKey) { _pubKey = pubKey; }
161+
BearSSLSigningVerifier(BearSSLPublicKey *pubKey) { _pubKey = pubKey; }
161162

162163
private:
163164
BearSSLPublicKey *_pubKey;

libraries/ESP8266httpUpdate/examples/httpUpdateSigned/httpUpdateSigned.ino

+24-28
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
/**
2-
httpUpdate.ino
3-
4-
Created on: 27.11.2015
5-
1+
/*
2+
httpUpdateSigned.ino - Earle F. Philhower, III
3+
Released into the Public Domain
4+
5+
Shows how to use a public key extracted from your private certificate to
6+
only allow updates that you have signed to be applied over HTTP. Remote
7+
updates will require your private key to sign them, but of course
8+
**ANYONE WITH PHYSICAL ACCESS CAN UPDATE THE 8266 VIA THE SERIAL PORT**.
69
*/
710

811
#include <Arduino.h>
@@ -13,10 +16,11 @@
1316
#include <ESP8266HTTPClient.h>
1417
#include <ESP8266httpUpdate.h>
1518

16-
#define USE_SERIAL Serial
17-
1819
ESP8266WiFiMulti WiFiMulti;
1920

21+
// This key is taken from the server public certificate in BearSSL examples
22+
// You should make your own private/public key pair and guard the private
23+
// key (never upload it to the 8266).
2024
const char pubkey[] PROGMEM = R"EOF(
2125
-----BEGIN PUBLIC KEY-----
2226
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyW5a4OO7xd6pRDTETO7h
@@ -30,20 +34,20 @@ TQIDAQAB
3034
)EOF";
3135
BearSSLPublicKey *signPubKey = nullptr;
3236
BearSSLHashSHA256 *hash;
33-
BearSSLVerifier *sign;
37+
BearSSLSigningVerifier *sign;
3438

3539
void setup() {
3640

37-
USE_SERIAL.begin(115200);
38-
// USE_SERIAL.setDebugOutput(true);
41+
Serial.begin(115200);
42+
// Serial.setDebugOutput(true);
3943

40-
USE_SERIAL.println();
41-
USE_SERIAL.println();
42-
USE_SERIAL.println();
44+
Serial.println();
45+
Serial.println();
46+
Serial.println();
4347

4448
for (uint8_t t = 4; t > 0; t--) {
45-
USE_SERIAL.printf("[SETUP] WAIT %d...\n", t);
46-
USE_SERIAL.flush();
49+
Serial.printf("[SETUP] WAIT %d...\n", t);
50+
Serial.flush();
4751
delay(1000);
4852
}
4953

@@ -52,7 +56,7 @@ void setup() {
5256

5357
signPubKey = new BearSSLPublicKey(pubkey);
5458
hash = new BearSSLHashSHA256();
55-
sign = new BearSSLVerifier(signPubKey);
59+
sign = new BearSSLSigningVerifier(signPubKey);
5660
}
5761

5862

@@ -62,32 +66,24 @@ void loop() {
6266

6367
WiFiClient client;
6468

65-
69+
// Ensure all updates are signed appropriately. W/o this call, all will be accepted.
6670
Update.installSignature(hash, sign);
6771

68-
// The line below is optional. It can be used to blink the LED on the board during flashing
69-
// The LED will be on during download of one buffer of data from the network. The LED will
70-
// be off during writing that buffer to flash
71-
// On a good connection the LED should flash regularly. On a bad connection the LED will be
72-
// on much longer than it will be off. Other pins than LED_BUILTIN may be used. The second
73-
// value is used to put the LED on. If the LED is on with HIGH, that value should be passed
7472
ESPhttpUpdate.setLedPin(LED_BUILTIN, LOW);
7573

7674
t_httpUpdate_return ret = ESPhttpUpdate.update(client, "http://192.168.1.8/esp8266.bin");
77-
// Or:
78-
//t_httpUpdate_return ret = ESPhttpUpdate.update(client, "server", 80, "file.bin");
7975

8076
switch (ret) {
8177
case HTTP_UPDATE_FAILED:
82-
USE_SERIAL.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
78+
Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
8379
break;
8480

8581
case HTTP_UPDATE_NO_UPDATES:
86-
USE_SERIAL.println("HTTP_UPDATE_NO_UPDATES");
82+
Serial.println("HTTP_UPDATE_NO_UPDATES");
8783
break;
8884

8985
case HTTP_UPDATE_OK:
90-
USE_SERIAL.println("HTTP_UPDATE_OK");
86+
Serial.println("HTTP_UPDATE_OK");
9187
break;
9288
}
9389
}

0 commit comments

Comments
 (0)