Skip to content

Latest commit

 

History

History
148 lines (113 loc) · 5.38 KB

File metadata and controls

148 lines (113 loc) · 5.38 KB

Security & OTA Firmware Updates

HydroponicOne is built for production environments where security and reliability are paramount. This guide explains how to enable firmware signing and manage secure Over-The-Air (OTA) updates.

🛠️ Security Configuration

To lock down your system, enable strict security in firmware/include/config.h.

Enforce Strict Security

Uncomment the following line in config.h:

#define ENFORCE_STRICT_SECURITY

What this enables:

  1. Blocks Plain HTTP OTA: Only HTTPS firmware downloads are allowed.
  2. Requires Signed Firmware: The ESP32 will reject any update that is not cryptographically signed with your RSA-2048 private key.
  3. SHA256 Integrity Check: After download, the device computes the SHA256 of the new partition and compares it to the signed hash. A mismatch aborts the update.

🔐 Security Model

Security Model

graph TD
    subgraph "Developer / Build Server"
        Bin["firmware.bin"]
        Key[("Private Key (.pem)")]
        Sign["Signing Script"]
        Bin -- "Compute" --> Hash["SHA256 Hash"]
        Hash & Key -- "RSA Sign" --> Signature["Signature (Base64)"]
    end

    subgraph "Cloud / Deployment"
        IoT["HydroponicOne Dashboard"]
        IoT -- "Send via MQTT" --> Payload["{ url, hash, signature }"]
    end

    subgraph "Edge Device (ESP32)"
        Pub[("Public Key (LittleFS)")]
        ESP["OTA Manager"]
        
        Payload -- "1. Verify Sig" --> ESP
        Pub -- "RSA Verify" --> ESP
        
        ESP -- "2. Download" --> HTTPS["HTTPS Firmware"]
        HTTPS -- "3. Validate" --> ESP
        ESP -- "Compute local SHA256" --> Match{"Match?"}
        Match -- "YES" --> Flash["Update Partition & Reboot"]
        Match -- "NO" --> Abort["Abort & Rollback"]
    end
Loading

Why this works: An attacker cannot forge a valid signature without your private key. Even if they intercept the MQTT payload, they cannot substitute a malicious binary because the SHA256 won't match.


🔑 Managing RSA Keys

HydroponicOne uses RSA-2048 signing. You must generate a public/private key pair.

Automated Key Generation

Run the following script from the project root:

python firmware/scripts/generate_keys.py

Results:

  • firmware/data/ota_priv.pem: PRIVATE KEY. Keep this secret. Never commit it to git.
  • firmware/data/ota_pub.pem: PUBLIC KEY. This is flashed to the ESP32 via LittleFS to verify updates.
  • firmware/data/ota_ca.pem: CA CERTIFICATE. This self-signed X.509 certificate is used to secure your local HTTPS OTA server.
  • firmware/scripts/ota_ca_key.pem: CA PRIVATE KEY. Used by host_ota.py to encrypt traffic. Keep this secret.

Caution

If you lose your ota_priv.pem, you will no longer be able to OTA update your devices. You must re-flash them via USB with a new public key.


🔄 The Secure Update Workflow

1. Build your Firmware

Compile your project using PlatformIO:

cd firmware
pio run -e dht_bmp

The binary will be at .pio/build/dht_bmp/firmware.bin.

2. Sign the Binary

Use the signing script to generate SHA256 + signature:

python scripts/sign_firmware.py --bin .pio/build/dht_bmp/firmware.bin

Output:

[*] Firmware: .pio/build/dht_bmp/firmware.bin
[*] Size:     1234567 bytes
[*] SHA256:   a1b2c3d4e5f6...

============================================================
 SIGNED OTA CREDENTIALS — Paste into HydroponicOne Dashboard
============================================================

  SHA256:    a1b2c3d4e5f6...
  Signature: SGVsbG8gV29ybGQ=...

============================================================

3. Host the Binary

Upload firmware.bin to any HTTPS-accessible URL (GitHub Releases, S3 bucket, your own server, etc.).

Alternatively, host locally via host_ota.py: If you want to deploy from your local computer inside your local network, you can start a simple HTTPS server that uses the CA cert configured above:

python scripts/host_ota.py

This serves files from .pio/build/dht_bmp/ over HTTPS on port 8443. The URL you will use in the dashboard is: https://<YOUR_LOCAL_IP>:8443/firmware.bin

4. Deploy via Dashboard

  1. Navigate to the OTA Firmware Update page in the HydroponicOne dashboard.
  2. Enter the firmware URL and a version string (for your own reference).
  3. Click the 🛡 Shield toggle to enable Secure Mode.
  4. Paste the SHA256 hash and Base64 signature from the script output.
  5. Click Deploy Signed Firmware.

The backend dispatches the payload via MQTT. The ESP32 will:

  1. Verify the RSA signature of the SHA256 hash.
  2. Download the binary over HTTPS.
  3. Compute the SHA256 of the downloaded partition.
  4. Compare it against the signed hash.
  5. If everything matches, reboot into the new firmware.

💡 Troubleshooting OTA

  • "Signature Verification Failed": Ensure the ota_pub.pem on your ESP32 matches the ota_priv.pem used to sign the binary. You must re-flash via USB after changing keys.
  • "SHA256 Mismatch": The file may have been corrupted during download, or you signed a different binary than the one hosted at the URL.
  • "HTTPS Required": You have ENFORCE_STRICT_SECURITY enabled but provided an http:// URL. Use https://.
  • Python Dependencies: Ensure you have installed the requirements:
    pip install -r firmware/scripts/requirements.txt