Mobile certificate pinning and pin rotation
Applies to the mobile client only. The web tier does not pin and must not try: HPKP is dead in every browser, and its replacement is HSTS plus Certificate Transparency, which the infrastructure security requirements already cover.
Status: the runbook is here, the pins are not
There is no mobile client in the repository yet. M31-001 builds the app shell and its API client, and M33-014 says to pin from that client's first version rather than retrofit it, so the pinning configuration lands with M31-001.
⚠ This document exists ahead of the code on purpose. Rotation is the part with a long lead time: it needs a backup key generated and published before the first pinned release ships, and that is not a decision anyone can make retroactively once an app is in the stores.
Why pinning is warranted here and nowhere else
A mobile app on a patient's phone, on hospital or public Wi-Fi, talking to a cloud cell that holds their full record, is the one client where the threat is real and the control is possible. A browser cannot pin, and a server-to-server call already runs over a channel we control at both ends.
⚠⚠ Never pin a leaf certificate
Pinning a leaf is the standard way to brick an app. Certificates rotate on a schedule the app-store release cycle cannot match: a leaf may be reissued in 90 days, while an app update takes days to review and months to reach the long tail of the installed base. When the leaf rotates, every device still running the old build stops being able to reach the platform, and the fix is a release those devices cannot receive because the release channel is not the thing that broke — their ability to talk to us is.
Pin the intermediate CA, and always pin a backup key set alongside the active one.
| Pin target | Verdict |
|---|---|
| Leaf certificate | ⛔ never |
| Intermediate CA | ✅ pin this |
| Backup key, not yet in use | ✅ pin this too, from day one |
The backup pin is what makes rotation survivable: it is already trusted by every installed build, so the certificate can move to it without shipping anything.
Rotation procedure
- Before the first pinned release, generate the backup key pair and record its SPKI hash beside the active one. Both go into the client's pin set.
- To rotate, obtain the new certificate from the backup key that is already pinned. Installed builds keep working, because that key is in their pin set.
- Ship a client release that adds a new backup pin and drops the retired one. Do not remove the pin the previous release is relying on.
- Only once the new release has reached the installed base does the retired pin leave the set.
⚠ Step 3 before step 2 is the mistake to watch for: dropping the old pin while devices still depend on it produces the same brick as pinning a leaf, one release later.
The kill switch
Pinning must be disableable without an app release, because the failure mode it creates is total: a pin that no longer matches means the app cannot reach the platform at all, including to be told that anything is wrong.
- The client reads a remotely-configured flag at startup and falls back to standard system trust when pinning is switched off.
- ⚠ The flag must be fetched over a path that is not itself pinned, or it cannot be read in exactly the situation it exists for. This is the one deliberate exception to pinning, and it is the reason the flag carries no authority beyond turning pinning off: it cannot select a different host, a different certificate, or a different API base URL.
- Switching pinning off is an incident action with an audit trail, not a configuration preference. It restores the security posture of an unpinned app, which is the platform's normal web posture, and it is strictly better than an installed base that cannot connect.
What pinning does not do
Pinning proves the connection reaches a certificate chain the client already knew about. It says nothing about whether the endpoint is in the right country, which is a residency question the cell model answers, and nothing about what the app does with the data once it arrives.