8000 Add cryptographically signed update support by earlephilhower · Pull Request #5213 · esp8266/Arduino · GitHub
[go: up one dir, main page]

Skip to content

Add cryptographically signed update support #5213

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Dec 3, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
71bf243
Add cryptographically signed update support
earlephilhower Oct 6, 2018
ac25877
Add a simple example
earlephilhower Oct 6, 2018
882e546
Make verifier EC/RSA compatible at any bit length
earlephilhower Oct 6, 2018
29d8c63
Make certain hash bits constant
earlephilhower Oct 7, 2018
e33eb7d
Merge branch 'master' into signedupdates
d-a-v Oct 8, 2018
d9ce799
Merge branch 'master' into signedupdates
earlephilhower Oct 8, 2018
5fb8cd5 8000
When update signed, don't do MD5 work or checking
earlephilhower Oct 10, 2018
b9344f6
Add python automatic signing if keys present
Oct 15, 2018
0ae91ae
Automatically include validation in updater
Oct 15, 2018
dd5c2b0
Merge branch 'master' into signedupdates
earlephilhower Oct 26, 2018
68f703e
Merge branch 'master' into signedupdates
earlephilhower Nov 5, 2018
9823290
Add documentation on signing process
Nov 5, 2018
3de43d6
Update documentation formatting
earlephilhower Nov 6, 2018
3f1013e
Merge branch 'master' into signedupdates
earlephilhower Nov 9, 2018
b3b7477
Move to new BearSSL:: namespace for classes
Nov 9, 2018
2b4016e
Merge branch 'master' into signedupdates
earlephilhower Nov 19, 2018
31b22fb
Move 2 strings into PROGMEM
earlephilhower Nov 29, 2018
b3ed528
Merge branch 'master' into signedupdates
earlephilhower Nov 29, 2018
4164bce
Add openssl return code error checking
earlephilhower Nov 29, 2018
5b2a882
Merge branch 'signedupdates' of https://github.com/earlephilhower/Ard…
earlephilhower Nov 29, 2018
e530a8a
Completely silence normal unsigned builds
earlephilhower Nov 29, 2018
5b243e2
Move debug strings to PMEM
earlephilhower Nov 29, 2018
f1eca3f
Merge branch 'master' into signedupdates
earlephilhower Nov 30, 2018
30e9d9b
Fix prebuild numbering, typo in docs
Nov 30, 2018
15ca564
Warn about Windows incompatibility in build and docs
earlephilhower Nov 30, 2018
d61a8ff
Merge branch 'master' into signedupdates
earlephilhower Dec 1, 2018
f9d340c
Merge branch 'master' into signedupdates
devyte Dec 3, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add cryptographically signed update support
Using a pluggable architecture, allow updates delivered via the Update
class to be verified as signed by a certificate.  By using plugins, avoid
pulling either axTLS or BearSSL into normal builds.

A signature is appended to a binary image, followed by the size of the
signature as a 32-bit int.  The updater takes a verification function
and checks this signature using whatever method it chooses, and if it
fails the update is not applied.

A SHA256 hash class is presently implemented for the signing hash (since
MD5 is a busted algorithm).

A BearSSLPublicKey based verifier is implemented for RSA keys.  The
application only needs the Public Key, while to sign you can use
OpenSSL and your private key (which should never leave your control
or be deployed on any endpoints).
  • Loading branch information
earlephilhower committed Oct 6, 2018
commit 71bf243f6c99b70ae08c98cd3b562c537e5fe9b0
69 changes: 69 additions & 0 deletions cores/esp8266/Updater.cpp
8000
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ UpdaterClass::UpdaterClass()
, _startAddress(0)
, _currentAddress(0)
, _command(U_FLASH)
, _hash(nullptr)
, _verify(nullptr)
{
}

Expand Down Expand Up @@ -140,6 +142,9 @@ bool UpdaterClass::begin(size_t size, int command, int ledPin, uint8_t ledOn) {
#endif

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

Expand Down Expand Up @@ -176,6 +181,42 @@ bool UpdaterClass::end(bool evenIfRemaining){
_size = progress();
}


uint32_t sigLen = 0;
if (_verify) {
ESP.flashRead(_startAddress + _size - sizeof(uint32_t), &sigLen, sizeof(uint32_t));
#ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf("[Updater] sigLen: %d\n", sigLen);
#endif
if (!sigLen || sigLen > 256) {
_setError(UPDATE_ERROR_SIGN);
_reset();
return false;
}
}

int binSize = _size;
if (_hash) {
_hash->begin();
binSize -= sigLen + sizeof(uint32_t);
}
#ifdef DEBUG_UPDATER
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);

int read = binSize - i;
if(read > 32) {
read = 32;
}
_md5.add(buff, read);
if (_hash) {
_hash->add(buff, read);
}
}
_md5.calculate();
if(_target_md5.length()) {
if(_target_md5 != _md5.toString()){
Expand All @@ -188,6 +229,29 @@ bool UpdaterClass::end(bool evenIfRemaining){
#endif
}

if (_verify && _hash) {
_hash->end();
#ifdef DEBUG_UPDATER
unsigned char *ret = (unsigned char *)_hash->hash();
DEBUG_UPDATER.printf("[Updater] Computed Hash:");
for (int i=0; i<_hash->len(); i++) DEBUG_UPDATER.printf(" %02x", ret[i]);
DEBUG_UPDATER.printf("\n");
#endif
uint8_t sig[256];
ESP.flashRead(_startAddress + binSize, (uint32_t *)sig, sigLen);
#ifdef DEBUG_UPDATER
DEBUG_UPDATER.printf("[Updater] sig[]:");
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);
return false;
}
}

if(!_verifyEnd()) {
_reset();
return false;
Expand Down Expand Up @@ -266,6 +330,9 @@ bool UpdaterClass::_writeBuffer(){
return false;
}
_md5.add(_buffer, _bufferLen);
if (_hash) {
_hash->add(_buffer, _bufferLen);
}
_currentAddress += _bufferLen;
_bufferLen = 0;
return true;
Expand Down Expand Up @@ -431,6 +498,8 @@ void UpdaterClass::printError(Print &out){
} else if(_error == UPDATE_ERROR_MD5){
//out.println(F("MD5 Check Failed"));
out.printf("MD5 Failed: expected:%s, calculated:%s\n", _target_md5.c_str(), _md5.toString().c_str());
} else if(_error == UPDATE_ERROR_SIGN){
out.printf("Signature verification failed\n");
} else if(_error == UPDATE_ERROR_FLASH_CONFIG){
out.printf_P(PSTR("Flash config wrong real: %d IDE: %d\n"), ESP.getFlashChipRealSize(), ESP.getFlashChipSize());
} else if(_error == UPDATE_ERROR_NEW_FLASH_CONFIG){
Expand Down
22 changes: 22 additions & 0 deletions cores/esp8266/Updater.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#define UPDATE_ERROR_NEW_FLASH_CONFIG (9)
#define UPDATE_ERROR_MAGIC_BYTE (10)
#define UPDATE_ERROR_BOOTSTRAP (11)
#define UPDATE_ERROR_SIGN (12)

#define U_FLASH 0
#define U_SPIFFS 100
Expand All @@ -28,9 +29,27 @@
#endif
#endif

class UpdaterHashClass {
public:
virtual void begin() = 0;
virtual void add(const void *data, uint32_t len) = 0;
virtual void end() = 0;
virtual int len() = 0;
virtual void *hash() = 0;
};

class UpdaterVerifyClass {
public:
virtual bool verify(UpdaterHashClass *hash, void *signature, uint32_t signatureLen) = 0;
};

class UpdaterClass {
public:
UpdaterClass();

/* Optionally add a cryptographic signature verification hash and method */
void installSignature(UpdaterHashClass *hash, UpdaterVerifyClass *verify) { _hash = hash; _verify = verify; }

/*
Call this to check the space needed for the update
Will return false if there is not enough space
Expand Down Expand Up @@ -166,6 +185,9 @@ class UpdaterClass {
int _ledPin;
uint8_t _ledOn;
int _ledStateRestore;

UpdaterHashClass *_hash;
UpdaterVerifyClass *_verify;
};

extern UpdaterClass Update;
Expand Down
33 changes: 33 additions & 0 deletions libraries/ESP8266WiFi/src/BearSSLHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -819,3 +819,36 @@ bool BearSSLX509List::append(const uint8_t *derCert, size_t derLen) {

return true;
}


// SHA256 hash for updater
void BearSSLHashSHA256::begin() {
br_sha256_init( &_cc );
memset( _sha256, 0, sizeof(_sha256) );
}

void BearSSLHashSHA256::add(const void *data, uint32_t len) {
br_sha256_update( &_cc, data, len );
}

void BearSSLHashSHA256::end() {
br_sha256_out( &_cc, _sha256 );
}

int BearSSLHashSHA256::len() {
return sizeof(_sha256);
}

void *BearSSLHashSHA256::hash() {
return (void*) _sha256;
}

// 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));
};
27 changes: 27 additions & 0 deletions libraries/ESP8266WiFi/src/BearSSLHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#define _BEARSSLHELPERS_H

#include <bearssl/bearssl.h>
#include <Updater.h>


// Internal opaque structures, not needed by user applications
namespace brssl {
Expand Down Expand Up @@ -136,4 +138,29 @@ class BearSSLSession {
br_ssl_session_parameters _session;
};


// Updater SHA256 hash and signature verification
class BearSSLHashSHA256 : public UpdaterHashClass {
public:
virtual void begin() override;
virtual void add(const void *data, uint32_t len) override;
virtual void end() override;
virtual int len() override;
virtual void *hash() override;
private:
br_sha256_context _cc;
unsigned char _sha256[32];
};

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

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

private:
BearSSLPublicKey *_pubKey;
};

#endif
0