APK Signing Block considerations
See https://android.izzysoft.de/articles/named/iod-scan-apkchecks#blobs
Some considerations regarding the APK Signing Block and how F-Droid handles Reproducible Builds.
Block types
APK Signature Scheme Block
The signature part of the APK Signing Block can contain more than one signature.
AFAIK android and apksigner
(unlike apksigtool
) only check the one with the strongest supported signature algorithm ID, not all of them.
So it might be possible to hide some data in a signature that won't be checked normally.
Either way it's possible for the app to behave differently depending on which key it was signed with, though we can't do much about that.
Related: Android App Links.
Frosting and SourceStamp Blocks
These opaque Google-specific extensions have their own block types.
There is some documentation, code, and reverse engineering, but in the end we don't really know what's in there.
Dependency Info Block
Another opaque Google-specific extension.
"[...] data is compressed, encrypted by a Google Play signing key [...]"
Any other block types
AFAIK these are simply ignored by apksigner
etc.
So a developer could just create their own block type (or abuse an existing one) and put anything they want in there, including code.
Security
Android apps have access to their own APK file (e.g. I can run apksigcopier extract
in Termux on Termux' own APK in /data/app/
), so AFAIK an app could easily load some kind of code/instructions from the Signing Block, especially from something other than the APK Signature Scheme Block.
I haven't made a PoC for this yet, but it's on my TODO list somewhere.
What to do?
- Apps signed by F-Droid should be "safe".
- Apps using signatures in metadata could already have put something additional in the
APKSigningBlock
, but there is some accountability via git history. - Apps using
Binaries:
-- or the server we download the APK from -- could put anything additional in there.
I'd recommend at least "cleaning" and/or "linting" the APK Signing Block as part of our build process / CI, allowing only APK Signature Scheme Blocks (and verity zero padding), and ideally making sure all signatures in there are valid.
The downside to "cleaning" (when it actually removes something) is that it results in an APK file that verifies correctly, but will not have the same checksum as the original since the APK Signing Block differs.
Current apps using signatures in metadata seem to be "clean":
Output
$ for file in $( find -name APKSigningBlock ); do apksigtool clean --block "$file"; done | uniq -c
37 nothing to clean
$ for file in $( find -name APKSigningBlock ); do apksigtool parse --block --json "$file" | jq -r '.pairs[].value._type'; done | sort | uniq -c
72 APKSignatureSchemeBlock
35 VerityPaddingBlock
However, two apps using Binaries:
have a DependencyInfoBlock
(encrypted by a Google Play signing key).
Output
$ for file in *.apk; do echo "==> $file"; apksigtool parse --json "$file" | jq -r '.pairs[].value._type'; echo; done
==> androdns.android.leetdreams.ch.androdns_15.apk
Error: No APK Signing Block.
==> androdns.android.leetdreams.ch.androdns_16.apk
Error: No APK Signing Block.
==> ch.admin.bag.covidcertificate.verifier_4040000.apk
APKSignatureSchemeBlock
DependencyInfoBlock
VerityPaddingBlock
==> ch.admin.bag.covidcertificate.verifier_4060000.apk
APKSignatureSchemeBlock
DependencyInfoBlock
VerityPaddingBlock
==> ch.admin.bag.covidcertificate.verifier_4070000.apk
APKSignatureSchemeBlock
DependencyInfoBlock
VerityPaddingBlock
==> ch.admin.bag.covidcertificate.wallet_4040000.apk
APKSignatureSchemeBlock
DependencyInfoBlock
VerityPaddingBlock
==> ch.admin.bag.covidcertificate.wallet_4060000.apk
APKSignatureSchemeBlock
DependencyInfoBlock
VerityPaddingBlock
==> ch.admin.bag.covidcertificate.wallet_4070000.apk
APKSignatureSchemeBlock
DependencyInfoBlock
VerityPaddingBlock
==> com.mishiranu.dashchan_1041.apk
APKSignatureSchemeBlock
VerityPaddingBlock
==> com.mishiranu.dashchan_1042.apk
APKSignatureSchemeBlock
VerityPaddingBlock
==> com.mishiranu.dashchan_1043.apk
APKSignatureSchemeBlock
APKSignatureSchemeBlock
VerityPaddingBlock
==> de.corona.tracing_2240202.apk
APKSignatureSchemeBlock
APKSignatureSchemeBlock
VerityPaddingBlock
==> de.corona.tracing_2250002.apk
APKSignatureSchemeBlock
APKSignatureSchemeBlock
VerityPaddingBlock
==> de.corona.tracing_2260004.apk
APKSignatureSchemeBlock
APKSignatureSchemeBlock
VerityPaddingBlock
==> de.schildbach.oeffi_120025.apk
APKSignatureSchemeBlock
APKSignatureSchemeBlock
VerityPaddingBlock
==> de.schildbach.oeffi_120100.apk
APKSignatureSchemeBlock
APKSignatureSchemeBlock
VerityPaddingBlock
==> de.schildbach.oeffi_120103.apk
APKSignatureSchemeBlock
APKSignatureSchemeBlock
VerityPaddingBlock
==> eu.bubu1.fdroidclassic_1014.apk
Error: No APK Signing Block.
==> eu.bubu1.fdroidclassic_1106.apk
APKSignatureSchemeBlock
APKSignatureSchemeBlock
VerityPaddingBlock
==> eu.bubu1.fdroidclassic_1110.apk
APKSignatureSchemeBlock
APKSignatureSchemeBlock
VerityPaddingBlock
==> info.guardianproject.checkey_101.apk
Error: No APK Signing Block.
==> nya.kitsunyan.foxydroid_2.apk
Error: No APK Signing Block.
==> nya.kitsunyan.foxydroid_3.apk
Error: No APK Signing Block.
==> nya.kitsunyan.foxydroid_4.apk
Error: No APK Signing Block.
==> org.briarproject.briar.android_10410.apk
APKSignatureSchemeBlock
==> org.briarproject.briar.android_10411.apk
APKSignatureSchemeBlock
==> org.briarproject.briar.android_10412.apk
APKSignatureSchemeBlock
==> org.jellyfin.mobile_2040199.apk
APKSignatureSchemeBlock
APKSignatureSchemeBlock
VerityPaddingBlock
==> org.jellyfin.mobile_2040299.apk
APKSignatureSchemeBlock
APKSignatureSchemeBlock
VerityPaddingBlock
==> org.jellyfin.mobile_2040499.apk
APKSignatureSchemeBlock
APKSignatureSchemeBlock
VerityPaddingBlock
==> rs.ltt.android_12.apk
APKSignatureSchemeBlock
APKSignatureSchemeBlock
VerityPaddingBlock
==> rs.ltt.android_13.apk
APKSignatureSchemeBlock
APKSignatureSchemeBlock
VerityPaddingBlock
==> rs.ltt.android_14.apk
APKSignatureSchemeBlock
APKSignatureSchemeBlock
VerityPaddingBlock
==> top.fumiama.copymanga_23.apk
APKSignatureSchemeBlock
APKSignatureSchemeBlock
VerityPaddingBlock
==> uk.co.keepawayfromfire.screens_6.apk
APKSignatureSchemeBlock
==> uk.co.keepawayfromfire.screens_7.apk
APKSignatureSchemeBlock
==> uk.co.keepawayfromfire.screens_8.apk
APKSignatureSchemeBlock
Related: #1055 (closed), #974, #1013, #935.
Edit 1: added apksigtool clean
& apksigtool parse
output for apps using signatures in metadata.
Edit 2: added apksigtool parse
output for apps using Binaries:
and Dependency Info Block section.