lock in apk cert
This commit is contained in:
parent
59feb4b5e8
commit
95b2db5e02
3 changed files with 62 additions and 13 deletions
|
|
@ -181,13 +181,15 @@ jobs:
|
|||
# included, each logged to sigstore. One power cycle of the HSM for all of it.
|
||||
# The APK's signature is the app's identity on every device that installs it, for
|
||||
# good: the key is the HSM's, and its certificate is the one `make-cert` wrote to
|
||||
# the token (README, "Signing").
|
||||
# the token (android/signing-cert.pem; README, "Signing"). apk_cert_sha256 pins
|
||||
# it: an APK signed with any other certificate fails here instead of shipping.
|
||||
id: sign
|
||||
uses: https://git.lerch.org/lobo/action-hsm-sign@v3
|
||||
uses: https://git.lerch.org/lobo/action-hsm-sign@v3.1
|
||||
with:
|
||||
pin: ${{ secrets.HSM_USER_PIN }}
|
||||
apk: unsigned/app-release-unsigned.apk
|
||||
apk_output: dist/tally.apk
|
||||
apk_cert_sha256: '4b41d0b1b3a184342fdc348e67563c8ca6cbc3765fa7341dee8a4a8fbb5d4aad'
|
||||
files: dist/*
|
||||
public_key: 'https://emil.lerch.org/serverpublic.pem'
|
||||
uhub_control: 'true'
|
||||
|
|
|
|||
41
README.md
41
README.md
|
|
@ -225,28 +225,47 @@ included. The action power cycles the HSM on its smart USB hub for the duration,
|
|||
the private key never leaves the HSM.
|
||||
|
||||
An APK signature carries a certificate, and Java only offers a PKCS#11 key that has one
|
||||
on the token. **Once, before the first signed build**, make a self-signed certificate for
|
||||
the key and store it beside the key. On the HSM host, with the HSM powered, from a clone
|
||||
of action-hsm-sign:
|
||||
on the token; whatever certificate the token holds for the key is used. It is not
|
||||
Tally's own: the token holds one certificate per key, so every app signed with the key
|
||||
carries it, and its subject is generic. It is the identity of all of them on every
|
||||
device: an APK signed with a different one is refused as an update, and users uninstall
|
||||
and reinstall. So it is chosen once, kept in this repository as
|
||||
[android/signing-cert.pem](android/signing-cert.pem) (it is public), and pinned in the
|
||||
workflow by its SHA-256 (`apk_cert_sha256`), so a certificate replaced on the token fails
|
||||
the build instead of silently changing the app's identity.
|
||||
|
||||
It was made on the HSM host, with the HSM powered, from a clone of action-hsm-sign. The
|
||||
certificate is assembled in the container and signed on the token with the user PIN, so
|
||||
the key never leaves it, and written to the card with the Admin PIN (the card's own
|
||||
rule for certificates). `REPLACE_CERT=1` because the key already had a certificate (the
|
||||
card's 2023 "AUT certificate", which signed the very first build, 255f239):
|
||||
|
||||
```
|
||||
docker build -t hsm-signer signer
|
||||
read -rs PKCS11_PIN && export PKCS11_PIN
|
||||
read -rs ADMIN_PIN && export ADMIN_PIN
|
||||
docker run --rm -v /run/pcscd/pcscd.comm:/run/pcscd/pcscd.comm:ro \
|
||||
-e PKCS11_PIN hsm-signer make-cert '/CN=Tally/O=lerch.org'
|
||||
-e PKCS11_PIN -e ADMIN_PIN hsm-signer check-pin
|
||||
docker run --rm -v /run/pcscd/pcscd.comm:/run/pcscd/pcscd.comm:ro \
|
||||
-e PKCS11_PIN -e ADMIN_PIN -e REPLACE_CERT=1 hsm-signer make-cert '/CN=Emil Lerch/O=lerch.org'
|
||||
```
|
||||
|
||||
It prints the certificate; keep a copy. The key is `03` by default, the one the detached
|
||||
signatures use (`KEY_ID` changes it). The certificate is the app's identity on every
|
||||
device from then on: replacing it means users uninstall and reinstall. Its 30-year
|
||||
validity does not matter for APKs, whose certificate dates Android does not check.
|
||||
`check-pin` tries each PIN once first; a wrong PIN costs a try, and the card locks a PIN
|
||||
after three. `make-cert` prints the certificate and its `sha256 (apk_cert_sha256)`:
|
||||
`4b41d0b1b3a184342fdc348e67563c8ca6cbc3765fa7341dee8a4a8fbb5d4aad` (`CN=Emil Lerch,
|
||||
O=lerch.org`, valid to 2056). The key is `03` by default, the one the detached
|
||||
signatures use (`KEY_ID` changes it); a new certificate does not change the key, so the
|
||||
detached signatures and `serverpublic.pem` are unaffected. Its 30-year validity does not
|
||||
matter for APKs, whose certificate dates Android does not check, but is long enough for
|
||||
Google Play (validity past 2033-10-22).
|
||||
|
||||
`mise run apk-signer-test` builds the release APK and runs action-hsm-sign's
|
||||
`signer/test.sh` on it, at the version the workflow uses (or a local checkout named by
|
||||
`ACTION_HSM_SIGN`). That is the same signer image against SoftHSM: a token with a bare
|
||||
key, a detached signature, `make-cert`, APK signing, `apksigner verify`, and a check that
|
||||
the APK's signing key is the token's. What it cannot cover is the HSM itself and the
|
||||
host's pcscd, so the first run on the HSM runner is the real test of those.
|
||||
key, a detached signature, `make-cert` (and its refusal to replace a certificate), APK
|
||||
signing with the certificate pinned, `apksigner verify`, and a check that the APK's
|
||||
signing key is the token's. What it cannot cover is the HSM itself and the host's pcscd,
|
||||
so the first run on the HSM runner is the real test of those.
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
|||
28
android/signing-cert.pem
Normal file
28
android/signing-cert.pem
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIE2zCCAsMCFHrZq0V4qQfkUv0emf3CkUnuZztZMA0GCSqGSIb3DQEBCwUAMCkx
|
||||
EzARBgNVBAMMCkVtaWwgTGVyY2gxEjAQBgNVBAoMCWxlcmNoLm9yZzAgFw0yNjEw
|
||||
MDQxOTE1MjhaGA8yMDU2MDkyNjE5MTUyOFowKTETMBEGA1UEAwwKRW1pbCBMZXJj
|
||||
aDESMBAGA1UECgwJbGVyY2gub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
|
||||
CgKCAgEA0rlFG2I641ARuKWcyFVrL81pwP8O0KGSd7uYkLpf4F3ut6VUZOsaGzCz
|
||||
fACXu6x57DFH1DMZkaf71vg+btRUw/b4eGmTXiAfq5D4CM5Bk1kgxOqat5JL+YF1
|
||||
EunxYV3EqAhtaL9FLrafNL+guX/slQ7ol8RjlWddJqkS+tpoHu6XrmMgChosDfHY
|
||||
cZeGI/B8wkiD4sLVy/VwnlyGPK1Ww4o/EnIwiRH6m3bP/bxfKslXg+Z6mUch530F
|
||||
4O75fhUzBzzrvbluKEH+9uWviVHHdNM3NSmNX5xYqaVr9OdiMHO18lynNZK8DBW4
|
||||
vsrpGO5GX0F5spafa5bBzTPdtJw52v5Mw5pTtKtocwn9ML26lq4KEIBW5aANKvVc
|
||||
hcyFOELJFMzvuE4pxvVzM0SlpG7p7hU7cz7kE83QnZzGup1d9vxpCbBtDIsaB+B5
|
||||
/43YHLc+mTCzTdHNRy91RwYiZKOL3zEsMyWHJXwoO0ELaET0gmrRymbEETdCoWNP
|
||||
qVKxea+zuPpeGGamIPoATgxnVAgfYlnFhSiMDuwERiJ1HIUqlcVaFAETLw/jdvih
|
||||
TgS7FJ7xfZy8+nT+sQt7P2s77A8ogX+NsRyMNic8/pCVOkfWYGCf5n5aOu9EGXiR
|
||||
LHn1X28ZJIfuxJ16JlclkIxnBHp4okJ1mYWHuN2SRFvXu6tCOrkCAwEAATANBgkq
|
||||
hkiG9w0BAQsFAAOCAgEAOwGr7hXIv9+2bx4ngGYAq9FRJeAesaG4inn8L9eSQq7S
|
||||
peJbtyL4BO5/wAZt6gD/qTVWRVFiaLDvs2oyoh+mv74TsAyYHUFKHVptMOaG6OBu
|
||||
3rGdDbQFKpi62/v+aC9zakgNx4oH+0Ev/WbWf3u+VXlZGnF51eBZh3E7B4DW5TkG
|
||||
sMEaXP1wOMdx2cZWg0e84qaHNi4eSUIgB0QSwbXlw2AZEcTVcqAws7sLvhUgphxG
|
||||
aH9n2+a0CCfPZRlyJFJlQ+DXohOOjVENG++PbxPeMmRi0EvmVAhbnrMGhVi6ayxH
|
||||
KmoRwOfoe+Ti6kStPGaYXLIVVA2BKnBCYL3pi/ZWCKSsueJuKLUYzddsZe9exirr
|
||||
y8/Jpct3KvlYaA4dMIaUlYRAGn609hWt7sAqNEnkSHsjqtycPbAi74+AulUpdcWO
|
||||
GL+77YiCx1I4+rXBFLV43kz+Fw0A9btdrv4/gC+siAzDYv7Y21+rM1IxAU+xnHnm
|
||||
btvc04C6CDG2UpPSSdJRm9yugtXk7AH4AtboKUvpCWbwHK0Kd9kAUbJ0Mbbuxf13
|
||||
7YppxMGGSSJjG+XV917tSWG+gNNz2V9KLxsGnCJIRRHaGsBfn8p+TY05PvRFcj7Z
|
||||
vxxEGvrZMBaQz2noQjKsoAsWjr199mfFKm4/rxHpHe3vI3kzfCHaU0MVVCUGrtk=
|
||||
-----END CERTIFICATE-----
|
||||
Loading…
Add table
Reference in a new issue