Skip to content

Update: Fix signed OTA signature verification bypass when installSignature() called before begin()#12425

Merged
me-no-dev merged 2 commits into
masterfrom
copilot/fix-signature-verification-issue
Mar 5, 2026
Merged

Update: Fix signed OTA signature verification bypass when installSignature() called before begin()#12425
me-no-dev merged 2 commits into
masterfrom
copilot/fix-signature-verification-issue

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 4, 2026

_reset() (invoked at the start of begin()) was zeroing _signatureSize, silently disabling all hashing and verification even when installSignature() had been called beforehand — the documented usage order. As a result, unsigned or tampered firmware was accepted without error.

Change

  • libraries/Update/src/Updater.cpp: Remove _signatureSize = 0; from _reset(). _signatureSize is user-installed configuration, not runtime state; it must survive the _reset() call inside begin(). Runtime allocations (_signatureBuffer, _hash) are still freed by _reset() as before.

Before: calling installSignature()begin() would zero _signatureSize, causing the guards in _writeBuffer() and end() (if (_hash && _signatureSize > 0)) to short-circuit, skipping hashing and verification entirely.

After: _signatureSize persists across begin(), so verification runs as expected.

Original prompt

Bug

GitHub Issue: #12422

When using the Update library's signed OTA update feature, calling installSignature() before begin() (as documented) results in the signature verification being silently bypassed. Even unsigned firmware is accepted.

Root Cause

The _reset() method (called at the start of begin()) clears _signatureSize to 0 on line 128 of Updater.cpp:

#ifdef UPDATE_SIGN
  _signatureSize = 0;
#endif /* UPDATE_SIGN */

However, _reset() does not clear _sign or _hashType. This causes the following cascade:

  1. User calls Update.installSignature(&sign) → sets _sign, _hashType, _signatureSize = 512
  2. User calls Update.begin(size) → calls _reset()_signatureSize becomes 0
  3. In begin(), the check if (_sign && _hashType >= 0) still passes, so _hash is created and initialized
  4. But since _signatureSize == 0:
    • In _writeBuffer(): if (_hash && _signatureSize > 0) is false → firmware bytes are never hashed
    • In end(): if (_hash && _sign && _signatureSize > 0) is false → signature verification is completely skipped
  5. Result: unsigned/tampered firmware is silently accepted

Fix Required

In _reset() in libraries/Update/src/Updater.cpp, the _signatureSize should NOT be reset to 0. The signature configuration (_sign, _hashType, _signatureSize) represents user-installed configuration set before begin(), not runtime state. Only runtime allocations (_signatureBuffer, _hash) should be cleaned up by _reset().

Specifically, in the _reset() method, remove the line:

  _signatureSize = 0;

from inside the #ifdef UPDATE_SIGN block (currently at line 128).

The _signatureBuffer cleanup (lines 107-110) and _hash cleanup (lines 111-115) in _reset() should remain, as those are runtime allocations that need to be freed. But _signatureSize is configuration that must persist across the _reset() call in begin().

After the fix, the #ifdef UPDATE_SIGN section in _reset() should look like:

#ifdef UPDATE_SIGN
  if (_signatureBuffer) {
    delete[] _signatureBuffer;
    _signatureBuffer = nullptr;
  }
  if (_hash && _hashType >= 0) {
    // Clean up internally-created hash object
    delete _hash;
    _hash = nullptr;
  }
#endif /* UPDATE_SIGN */

(The _signatureSize = 0; line that was previously after the second closing brace is removed.)

File to modify

  • libraries/Update/src/Updater.cpp — remove _signatureSize = 0; from _reset() method (line 128)

This pull request was created from Copilot chat.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

…pass

Co-authored-by: lucasssvaz <32426024+lucasssvaz@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix silent bypass of signature verification in OTA updates Update: Fix signed OTA signature verification bypass when installSignature() called before begin() Mar 4, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 4, 2026

Warnings
⚠️

Some issues found for the commit messages in this PR:

  • the commit message "Initial plan":
    • summary looks empty
    • type/action looks empty

Please fix these commit messages - here are some basic tips:

  • follow Conventional Commits style
  • correct format of commit message should be: <type/action>(<scope/component>): <summary>, for example fix(esp32): Fixed startup timeout issue
  • allowed types are: change,ci,docs,feat,fix,refactor,remove,revert,test
  • sufficiently descriptive message summary should be between 10 to 72 characters and start with upper case letter
  • avoid Jira references in commit messages (unavailable/irrelevant for our customers)

TIP: Install pre-commit hooks and run this check when committing (uses the Conventional Precommit Linter).

👋 Hello Copilot, we appreciate your contribution to this project!


📘 Please review the project's Contributions Guide for key guidelines on code, documentation, testing, and more.

🖊️ Please also make sure you have read and signed the Contributor License Agreement for this project.

Click to see more instructions ...


This automated output is generated by the PR linter DangerJS, which checks if your Pull Request meets the project's requirements and helps you fix potential issues.

DangerJS is triggered with each push event to a Pull Request and modify the contents of this comment.

Please consider the following:
- Danger mainly focuses on the PR structure and formatting and can't understand the meaning behind your code or changes.
- Danger is not a substitute for human code reviews; it's still important to request a code review from your colleagues.
- Resolve all warnings (⚠️ ) before requesting a review from human reviewers - they will appreciate it.
- To manually retry these Danger checks, please navigate to the Actions tab and re-run last Danger workflow.

Review and merge process you can expect ...


We do welcome contributions in the form of bug reports, feature requests and pull requests.

1. An internal issue has been created for the PR, we assign it to the relevant engineer.
2. They review the PR and either approve it or ask you for changes or clarifications.
3. Once the GitHub PR is approved we do the final review, collect approvals from core owners and make sure all the automated tests are passing.
- At this point we may do some adjustments to the proposed change, or extend it by adding tests or documentation.
4. If the change is approved and passes the tests it is merged into the default branch.

Generated by 🚫 dangerJS against a9a3f70

@lucasssvaz lucasssvaz marked this pull request as ready for review March 4, 2026 12:06
@lucasssvaz lucasssvaz requested a review from me-no-dev as a code owner March 4, 2026 12:06
@lucasssvaz lucasssvaz added the Area: Libraries Issue is related to Library support. label Mar 4, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 4, 2026

Test Results

 94 files   94 suites   28m 32s ⏱️
 77 tests  77 ✅ 0 💤 0 ❌
714 runs  714 ✅ 0 💤 0 ❌

Results for commit a9a3f70.

♻️ This comment has been updated with latest results.

@me-no-dev me-no-dev added the Status: Pending Merge Pull Request is ready to be merged label Mar 4, 2026
@me-no-dev me-no-dev merged commit 1a8d72d into master Mar 5, 2026
109 of 110 checks passed
@me-no-dev me-no-dev deleted the copilot/fix-signature-verification-issue branch March 5, 2026 11:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: Libraries Issue is related to Library support. Status: Pending Merge Pull Request is ready to be merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants