Skip to content

Commit

Permalink
Make verifier EC/RSA compatible at any bit length
Browse files Browse the repository at this point in the history
Allow EC or RSA keys to be used to verify, as well as any RSA key length
supported by BearSSL (currently 4096 bits).
  • Loading branch information
earlephilhower committed Oct 6, 2018
1 parent ac25877 commit 882e546
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 55 deletions.
33 changes: 16 additions & 17 deletions cores/esp8266/Updater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,6 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn) {
DEBUG_UPDATER.printf("[begin] _size: 0x%08X (%d)\n", _size, _size);
#endif

_md5.begin();
if (_hash) {
_hash->begin();
}
return true;
}

Expand Down Expand Up @@ -188,13 +184,14 @@ bool UpdaterClass::end(bool evenIfRemaining){
#ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf("[Updater] sigLen: %d\n", sigLen);
#endif
if (!sigLen || sigLen > 256) {
if (sigLen != _verify->length()) {
_setError(UPDATE_ERROR_SIGN);
_reset();
return false;
}
}

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

int read = binSize - i;
if(read > 32) {
read = 32;
size_t read = binSize - i;
if(read > sizeof(buff)) {
read = sizeof(buff);
}
_md5.add(buff, read);
if (_hash) {
Expand All @@ -237,17 +234,23 @@ bool UpdaterClass::end(bool evenIfRemaining){
for (int i=0; i<_hash->len(); i++) DEBUG_UPDATER.printf(" %02x", ret[i]);
DEBUG_UPDATER.printf("\n");
#endif
uint8_t sig[256];
uint8_t *sig = (uint8_t*)malloc(sigLen);
if (!sig) {
_setError(UPDATE_ERROR_SIGN);
_reset();
return false;
}
ESP.flashRead(_startAddress + binSize, (uint32_t *)sig, sigLen);
#ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf("[Updater] sig[]:");
DEBUG_UPDATER.printf("[Updater] Received Signature:");
for (size_t i=0; i<sigLen; i++) {
DEBUG_UPDATER.printf(" %02x", sig[i]);
}
DEBUG_UPDATER.printf("\n");
#endif
if (!_verify->verify(_hash, (void *)sig, sigLen)) {
_setError(UPDATE_ERROR_SIGN);
_reset();
return false;
}
}
Expand Down Expand Up @@ -329,10 +332,6 @@ bool UpdaterClass::_writeBuffer(){
_setError(UPDATE_ERROR_WRITE);
return false;
}
_md5.add(_buffer, _bufferLen);
if (_hash) {
_hash->add(_buffer, _bufferLen);
}
_currentAddress += _bufferLen;
_bufferLen = 0;
return true;
Expand Down
5 changes: 4 additions & 1 deletion cores/esp8266/Updater.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#endif
#endif

// Abstract class to implement whatever signing hash desired
class UpdaterHashClass {
public:
virtual void begin() = 0;
Expand All @@ -38,9 +39,11 @@ class UpdaterHashClass {
virtual void *hash() = 0;
};

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

class UpdaterClass {
Expand Down
38 changes: 31 additions & 7 deletions libraries/ESP8266WiFi/src/BearSSLHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -844,11 +844,35 @@ void *BearSSLHashSHA256::hash() {
}

// SHA256 verifier
bool BearSSLVerifier::verify(UpdaterHashClass *hash, void *signature, uint32_t signatureLen) {
if (!_pubKey || !hash || !signature || signatureLen != 256) return false;
br_rsa_pkcs1_vrfy vrfy = br_rsa_pkcs1_vrfy_get_default();
unsigned char vrf[32];
bool ret = vrfy((const unsigned char *)signature, signatureLen, NULL, sizeof(vrf), _pubKey->getRSA(), vrf);
if (!ret) return false;
return !memcmp(vrf, hash->hash(), sizeof(vrf));
uint32_t BearSSLSigningVerifier::length()
{
if (!_pubKey) {
return 0;
} else if (_pubKey->isRSA()) {
return _pubKey->getRSA()->nlen;
} else if (_pubKey->isEC()) {
return _pubKey->getEC()->qlen;
} else {
return 0;
}
}

bool BearSSLSigningVerifier::verify(UpdaterHashClass *hash, void *signature, uint32_t signatureLen) {
if (!_pubKey || !hash || !signature || signatureLen != length()) return false;

if (_pubKey->isRSA()) {
bool ret;
unsigned char vrf[hash->len()];
br_rsa_pkcs1_vrfy vrfy = br_rsa_pkcs1_vrfy_get_default();
ret = vrfy((const unsigned char *)signature, signatureLen, NULL, sizeof(vrf), _pubKey->getRSA(), vrf);
if (!ret || memcmp(vrf, hash->hash(), sizeof(vrf)) ) {
return false;
} else {
return true;
}
} else {
br_ecdsa_vrfy vrfy = br_ecdsa_vrfy_raw_get_default();
// The EC verifier actually does the compare, unlike the RSA one
return vrfy(br_ec_get_default(), hash->hash(), hash->len(), _pubKey->getEC(), (const unsigned char *)signature, signatureLen);
}
};
5 changes: 3 additions & 2 deletions libraries/ESP8266WiFi/src/BearSSLHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,13 @@ class BearSSLHashSHA256 : public UpdaterHashClass {
unsigned char _sha256[32];
};

class BearSSLVerifier : public UpdaterVerifyClass {
class BearSSLSigningVerifier : public UpdaterVerifyClass {
public:
virtual uint32_t length() override;
virtual bool verify(UpdaterHashClass *hash, void *signature, uint32_t signatureLen) override;

public:
BearSSLVerifier(BearSSLPublicKey *pubKey) { _pubKey = pubKey; }
BearSSLSigningVerifier(BearSSLPublicKey *pubKey) { _pubKey = pubKey; }

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

#include <Arduino.h>
Expand All @@ -13,10 +16,11 @@
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>

#define USE_SERIAL Serial

ESP8266WiFiMulti WiFiMulti;

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

void setup() {

USE_SERIAL.begin(115200);
// USE_SERIAL.setDebugOutput(true);
Serial.begin(115200);
// Serial.setDebugOutput(true);

USE_SERIAL.println();
USE_SERIAL.println();
USE_SERIAL.println();
Serial.println();
Serial.println();
Serial.println();

for (uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] WAIT %d...\n", t);
USE_SERIAL.flush();
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}

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

signPubKey = new BearSSLPublicKey(pubkey);
hash = new BearSSLHashSHA256();
sign = new BearSSLVerifier(signPubKey);
sign = new BearSSLSigningVerifier(signPubKey);
}


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

WiFiClient client;


// Ensure all updates are signed appropriately. W/o this call, all will be accepted.
Update.installSignature(hash, sign);

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

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

switch (ret) {
case HTTP_UPDATE_FAILED:
USE_SERIAL.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
break;

case HTTP_UPDATE_NO_UPDATES:
USE_SERIAL.println("HTTP_UPDATE_NO_UPDATES");
Serial.println("HTTP_UPDATE_NO_UPDATES");
break;

case HTTP_UPDATE_OK:
USE_SERIAL.println("HTTP_UPDATE_OK");
Serial.println("HTTP_UPDATE_OK");
break;
}
}
Expand Down

0 comments on commit 882e546

Please sign in to comment.