Metadata, Versioning & Compatibility in OTA Firmware Updates
As your OTA system matures, one aspect becomes critical for reliability and long-term support: metadata.
A firmware update isn’t just binary data — it carries a version, a target device, a stack dependency, maybe even a hardware revision. Without this metadata, your device risks:
- Running incompatible firmware
- Downgrading to older (potentially vulnerable) builds
- Misinterpreting what’s installed vs. what’s in flash
This episode will dive into:
- Metadata structure
- Firmware versioning strategies
- Downgrade protection
- BLE stack compatibility (e.g. SoftDevice in Nordic, FUS in STM32WB)
- Real-world examples (Fitbit, Apple Watch, STM32, Nordic)
What is OTA Metadata?
Firmware metadata is a header or external descriptor that carries update context.
Common fields in firmware metadata:
| Field | Purpose |
|---|---|
| Firmware version | For comparison and upgrade logic |
| Target hardware ID | Avoids loading wrong firmware |
| Build date / time | Useful for rollback/telemetry |
| Flash address | Where to write firmware |
| Image size | For memory allocation and boundary checks |
| CRC / SHA256 hash | For data integrity |
| Digital signature | For authenticity and tamper detection |
| BLE stack version | For protocol compatibility |
Example OTA Metadata Structure (C-style)
typedef struct {
uint32_t magic; // e.g., 0xA5A5A5A5
uint32_t version; // e.g., 0x00010002 → v1.2
uint32_t hw_id; // Target hardware model
uint32_t size; // Image size in bytes
uint32_t crc32; // Optional lightweight check
uint8_t sha256[32]; // Strong integrity check
uint32_t ble_stack_ver; // Required BLE stack version
uint32_t flags; // e.g., test build, encrypted, etc.
uint8_t signature[64]; // ECC signature of hash
} ota_metadata_t;
Versioning Strategies
Use structured versioning to track firmware progression.
Semantic Versioning (recommended):
Major.Minor.Patch
→ Example: 2.4.1 = major upgrade v2, feature set 4, bugfix 1
- Increment
Patchfor bugfixes - Increment
Minorfor feature additions - Increment
Majorfor breaking changes (e.g., BLE protocol change)
Preventing Downgrade Attacks
Devices should reject older firmware versions, unless in debug/test mode.
if (incoming_version <= current_version) {
reject_ota("Downgrade not allowed");
}
Used In:
- Apple Watch: Version rollback is prevented by iOS OTA manager
- STM32WB + SBSFU: Metadata contains
version_minflag to block lower versions - Nordic Secure DFU: Version stored in bootloader-protected flash region
BLE Stack Compatibility Checks
BLE stacks (SoftDevice, FUS, etc.) can break compatibility between app and OTA logic.
Your OTA metadata should:
- Contain required stack version (e.g.,
0x010003for SoftDevice S132 v1.3) - Reject update if device has incompatible stack
- Optionally trigger BLE stack update before firmware OTA
STM32WB Example:
- BLE stack (
FUS) is separate from the application - Application metadata must declare compatible FUS version
- FUS updates must be OTA’d in two stages
if (metadata.fus_version_required > current_fus_version) {
trigger_fus_update();
}
External OTA Manifest (App or Server Side)
Some systems don’t embed all metadata in the firmware binary — instead, they use a sidecar JSON file or OTA manifest.
{
"version": "1.4.2",
"device_model": "WB-M1",
"image_size": 98304,
"sha256": "5f2c...78d",
"ble_stack_version": "0.7.5",
"min_supported_version": "1.2.0"
}
Used by:
- Fitbit and Garmin apps (manifest controls compatibility)
- Oura Ring OTA
- Custom mobile BLE updaters using React Native or Flutter
Best Practices
| Practice | Why It Matters |
|---|---|
| Use structured metadata in every image | Enables safe decision-making by bootloader |
| Version comparison on-device | Blocks downgrade, prevents mis-match |
| Validate BLE stack version | Avoids protocol crashes due to mismatch |
| Sign metadata + firmware | Tamper-resistant metadata |
| Store current version in protected area | Allows bootloader checks even after reboots |
Real-World Metadata Behavior
| Product | Versioning | Metadata Stored Where? | Compatibility Check |
|---|---|---|---|
| Fitbit Charge | Semantic | Embedded + cloud manifest | Yes (app enforced) |
| STM32WB + SBSFU | Numeric | Start of flash (secure) | Yes (stack + app) |
| Nordic nRF52840 | Semantic | Init packet during DFU | Yes (SoftDevice) |
| Apple Watch | Hidden | OTA image + iOS-managed | Yes (OS-managed) |
| Echo Buds | Numeric | BLE header + metadata blob | Yes (via BLE stack) |

Leave a comment