Skip to content

Commit 9cb9fcc

Browse files
Merge pull request #12 from appdevforall/fix/phase1-security-d6-download-integrity
fix(controller): verify download integrity + fail closed on TLS (D6)
2 parents 54c9788 + 9d04c02 commit 9cb9fcc

2 files changed

Lines changed: 22 additions & 10 deletions

File tree

‎controller/app/src/main/java/org/iiab/controller/Aria2Manager.java‎

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ public void startDownload(Context context, String url, DownloadListener listener
6464
if (!caCertFile.exists()) {
6565
extractAsset(context, "cacert.pem", caCertFile);
6666
}
67+
// D6: fail closed. The downloaded rootfs is extracted and executed as
68+
// root, so we must never fall back to an unverified TLS connection
69+
// where a MITM could swap it. If the CA bundle is unavailable, abort.
70+
if (!caCertFile.exists()) {
71+
throw new Exception("Secure download aborted: CA certificate bundle (cacert.pem) is unavailable.");
72+
}
6773

6874
Log.d(TAG, "Executing Native Aria2c...");
6975
Log.d(TAG, "Target URL: " + url);
@@ -83,20 +89,20 @@ public void startDownload(Context context, String url, DownloadListener listener
8389
command.add("--max-connection-per-server=4");
8490
command.add("--split=4");
8591
command.add("--follow-metalink=mem");
92+
// D6: verify the SHA-256 checksums embedded in the .meta4 (Metalink)
93+
// while downloading. On mismatch aria2 exits non-zero, so onError fires
94+
// and the archive is never extracted/executed.
95+
command.add("--check-integrity=true");
8696
command.add("--enable-dht=true");
8797
command.add("--dht-file-path=" + dhtFile.getAbsolutePath());
8898
command.add("--bt-enable-lpd=true");
8999
command.add("--seed-time=0");
90100

91-
// --- Apply SSL Certificate Validation ---
92-
if (caCertFile.exists()) {
93-
Log.d(TAG, "SSL certificates found. Enforcing strict validation.");
94-
command.add("--check-certificate=true");
95-
command.add("--ca-certificate=" + caCertFile.getAbsolutePath());
96-
} else {
97-
Log.w(TAG, "cacert.pem not found! Falling back to insecure connection.");
98-
command.add("--check-certificate=false");
99-
}
101+
// --- Apply SSL Certificate Validation (D6: always strict; cacert
102+
// presence was already enforced above, so there is no insecure path) ---
103+
Log.d(TAG, "Enforcing strict TLS certificate validation.");
104+
command.add("--check-certificate=true");
105+
command.add("--ca-certificate=" + caCertFile.getAbsolutePath());
100106

101107
command.add("--console-log-level=warn");
102108
command.add("--summary-interval=1");

‎controller/docs/TECH_DEBT_PLAN.md‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,13 @@ _Last updated: 2026-06-17. Tracks remediation work against the findings below. I
4141
- **S3** (`IIABAdbManager` key spec): the ADB identity key was created with `ENCRYPT | DECRYPT` + non-randomized encryption padding on top of sign/verify. Verified no `Cipher` uses this alias, so the spec is now `SIGN | VERIFY` only (encryption paddings / `setRandomizedEncryptionRequired(false)` removed). Alias kept at `v3` (non-disruptive: hardens new key generation without forcing existing devices to re-pair ADB).
4242
- No new unit tests: both are framework-bound legacy line-fixes with no extractable pure logic; verified by inspection + compile + CI lint.
4343

44-
**Phase 1 — Security hardening: IN PROGRESS.** Done so far: **S1** (PR #9), **M4**, **S3**. Remaining: **D2**, **D6**, **D12**, **S4**, **D11**.
44+
**D6 — Download integrity + TLS fail-closed (Phase 1 security): DONE** (PR `fix/phase1-security-d6-download-integrity`)
45+
- Closes **D6**: the rootfs (`latest_*.meta4` -> `.tar.gz`) is extracted and executed as root, but downloads had no integrity check and `Aria2Manager` silently fell back to `--check-certificate=false` when `cacert.pem` was missing.
46+
- **TLS fail-closed**: `cacert.pem` is now required (fail with a clear error if it cannot be provisioned) and `--check-certificate=true` is always passed — the insecure fallback is removed. Applies to all aria2 downloads (rootfs + ZIM).
47+
- **Integrity**: `--check-integrity=true` makes aria2 verify the SHA-256 checksums published in the `.meta4` (confirmed present: file-level + per-piece) during download; on mismatch aria2 exits non-zero, `onError` fires and the archive is never extracted. Uses the server's published hash + verified TLS, so no redundant on-device re-hash of the ~1.2 GB file.
48+
- Follow-up (separate items): ZIM content integrity (Kiwix publishes no embedded hash today; needs `.sha256` sidecars) and the cleartext OTA APK path in `MainActivity` (**F15**).
49+
50+
**Phase 1 — Security hardening: IN PROGRESS.** Done so far: **S1** (PR #9), **M4**, **S3** (PR #10), **D6**. Remaining: **D2**, **D12**, **S4**, **D11**.
4551

4652
## 1. Executive summary
4753

0 commit comments

Comments
 (0)