Refuse to serve a slim APK signed with the wrong key
strip.rs re-signs with this machine's ~/.android/debug.keystore on the assumption it is the key the build was signed with, and never checked. Where it isn't -- a keystore recreated after the APK was built signs as an entirely unrelated certificate -- the phone gets an APK Android refuses, reporting "App not installed" with no cause, which reads as the download rather than the signing. Both certificates are now read with `apksigner verify --print-certs`, compared as sets of digests so a v2 source and a v3 output still match, and a mismatch is refused with both digests and the keystore path in the message. The slim copy is deleted on refusal: nothing would serve it without its stamp, but serveable_now reports the size of whatever slim file is on disk. Verified both ways against tdep-survey's app-dioxus: with a fresh keystore under a throwaway HOME the download 500s with the message and leaves nothing behind, and with the real one it serves the same 52,685,076 bytes as before, signed by the same certificate as the raw build. Raised by the tdep-survey session, which measured that a fresh debug keystore is unrelated to the existing one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0e9c7842f7
commit
141402bcd2
2 files changed
+105
-4
No files matched your search
@@ -240,6 +240,26 @@ mutable at runtime from the phone.
|
||||
somebody asked. Stop and Uninstall do go
|
||||
through the script, and do strand the phone; the app confirms them
|
||||
rather than hiding them.
|
||||
- **A stripped copy is only serveable if it is signed by the key the
|
||||
build was.** `strip.rs` re-signs with `~/.android/debug.keystore`, and
|
||||
nothing about a debug keystore says which builds it made -- it is per
|
||||
machine, and one recreated after an APK was built signs as an entirely
|
||||
unrelated certificate (measured: a fresh AGP-parameter keystore against
|
||||
the existing one, no relation, as a new RSA keypair should be). Where
|
||||
they differ Android refuses the package and the phone says "App not
|
||||
installed" with no cause, which reads as the download rather than the
|
||||
signing and is among the most expensive sentences here to be handed. So
|
||||
the two are compared -- `apksigner verify --print-certs` on the source
|
||||
and on what was just signed, as sets of digests so a v2 source and a v3
|
||||
output still match -- and a mismatch is refused with both certificates
|
||||
and the keystore path named. Measured on the files rather than inferred
|
||||
from the keystore, so it stays true if the signing step changes. The
|
||||
slim copy is deleted on refusal: with no stamp beside it nothing would
|
||||
serve it, but `serveable_now` reports the size of whatever slim file is
|
||||
on disk, so leaving it would have the card describing a download
|
||||
nothing can install. Empty digests mean "not compared" rather than "no
|
||||
signer", and say so in the log rather than refusing -- an APK apksigner
|
||||
cannot read is one this comparison has no opinion about.
|
||||
- **A 500 answers with its message.** `ApiError::Internal` used to be a
|
||||
bare status with an empty body, on the grounds that an internal cause
|
||||
is not safe to hand back -- but every route here is behind the bearer
|
||||
@@ -839,8 +859,14 @@ session reads. What follows is what that means here.
|
||||
`--avd NAME` or `AVD_NAME=`, and when it cannot find that one it lists
|
||||
what *is* attached instead of guessing which of the three situations it
|
||||
is in.
|
||||
- The server needs `aapt2` (SDK build-tools) to add an app, and
|
||||
`llvm-strip` (NDK) only for apps that need stripping. **It has to find
|
||||
- The server needs `aapt2` (SDK build-tools) to add an app, and, for an
|
||||
app that needs stripping, `llvm-strip` (NDK), `zipalign` and
|
||||
`apksigner` (build-tools) **and `~/.android/debug.keystore`** -- the
|
||||
last is the least guessable of the four, since it belongs to no SDK,
|
||||
is created as a side effect of any Gradle Android build, and is
|
||||
consumed by the pipeline's final step. A machine that builds APKs and
|
||||
has no keystore is odd rather than new: something removed it after the
|
||||
build, and the APK it produced is signed by a key that is now gone. **It has to find
|
||||
both without an environment**, because the way this server usually
|
||||
starts is from a service manager, and one hands its process a scrubbed
|
||||
environment: measured in the Gentoo guest, an OpenRC user service gets
|
||||
|
||||
Reference in new issue
Block a user