Really Verifying LineageOS Build Authenticity
Re-establish the chain of trust after the way to verify public builds has changed
The Lineage team has changed the way they sign the public builds. Unfortunately this change is not yet well communicated: The "Verifying Build Authenticity" wiki page as of today only describes the old method. Well, after some "startpaging" (how I call searching the internet) I found a patch and a pull-request describing the new method.
Formerly the Java-based "keytool" was used, which prints out some checksums the user has to compare her/himself. The new tool is Python-based and just says "verified successfully".
While this user-friendly, it leaves open how to verify the provided public key? How to build a chain of trust from the checksums published on the wiki to the public key included in thenew tool'sarchive? Here is how-to.
The basic idea is to extract the public key from an installation archive we could verify using the old method and check if the public key in the new tool's archive matches the one used in the old installation archive.
In detail:
Download and verify aninstallationarchive using the old method, e.g. lineage-14.1-20180803-nightly-i9100-signed.zip
-
Get the checksums from https://wiki.lineageos.org/verifying-builds.html respective commit 8dca5e117efc77be9bfcfeb39c6f69c1dce041ed (which as far as I can tell was the very first commit of this wiki-page and thus shall be our trust anchor). Define shell-variables to have them at hand:
SHA1=9B:6D:F9:06:2A:1A:76:E6:E0:07:B1:1F:C2:EF:CB:EF:4B:32:F2:23 SHA256=51:83:25:EF:7F:96:C0:D1:19:4C:2E:85:6B:04:0D:63:61:66:FF:B8:46:71:7D:72:FA:87:F4:FA:E5:BE:7B:BB
You may want to pick the values from the aforementioned links so you don't need to trust me.
-
Extract the X.509 certificate from the installation archive
unzip -j lineage-14.1-20180803-nightly-i9100-signed.zip META-INF/com/android/otacert
This will extract the certificate otacert into the current directory (unzip -j means: junk paths).
-
Manually verify the fingerprints using different methods
echo $SHA1 | tr -d ':' ; \ openssl x509 -fingerprint -noout -in otacert | sed 's/.*=//' | tr -d ':' ; \ openssl x509 -outform DER -in otacert | sha1sum --binary | tr '[:lower:]' '[:upper:]' echo $SHA256 | tr -d ':' ; \ openssl x509 -outform DER -in otacert | sha256sum --binary | tr '[:lower:]' '[:upper:]'
Line 1 will print the SHA1 check-sum picked from the wiki with colons removed. It's easer to remove the colons then inserting them in line 3. Line 2 will print the SHA1 check-sum using openssl x509 -fingerprint, again colons removed. This line is basically to verify our line 3 is correct. And line 3 calculates the SHA1 check-sum using the tool sha1sum.
Lines 5 and 6 basically do the same, just using SHA256 check-sums. I did not find a way to make openssl x509 -fingerprint use SHA256 check-sums. This is why this step is missing here and why I'm using the external tools at all.
Now we have verified the certificate within the installation archive is the correct one. Fine.
-
Extract the public key from the certificate and convert into format used by the public key provided in the new tool's archive:
openssl x509 -in otacert -noout -pubkey | openssl rsa -pubin -RSAPublicKey_out > otacert.pub
-
Check if the two files are the same
diff otacert.pub lineageos_pubkey && echo okay
q.e.d.
For reference, here is the otacert.pub file:
-----BEGIN RSA PUBLIC KEY----- MIIBCgKCAQEApk3T4fhCA4/wP2e46b8JUw/CkTy1PjZUx47CDbyLHnETYoylq8CG BWDLRCwbUfmLbc5eWcSQN/J/ZPSK7wSQq5kQbwgHohMOGos6rNg05lbwhUtgJne2 bAB7FMLQwo0NxhNB3mSNh521mp554SiIcxo7scYftY9yWsBx3hK2EJPezFaFrCR0 zuLPIvDkS/IIQQ2RxdH2CqeUVUiCK611anDg/hfIPzXl+lm+TdK0RgSPm0IzIYb/ CqR+05whDen9mBxVcZ7I8wyqxEFcIWBfE/V9Ds3waCxITpRWdI3r6A4vLgsc9H+5 XZL/9Gc+FvY3gfOyx81LkEBBq+td+FBZmQIDAQAB -----END RSA PUBLIC KEY-----