eMAPT study materials
eMAPT study resources

Mutual TLS With a Client Certificate in Every APK

eMAPT · Put your knowledge to work in context.

All case studies

Mutual TLS With a Client Certificate in Every APK

An Android banking app uses mutual TLS for its API. Every APK contains assets/client.p12, a PKCS#12 file with a client certificate and private key, protected by the password changeit stored in BuildConfig. The internal CA issues one client certificate for the app, valid for two years, and the server accepts any certificate signed by that CA without mapping it to a user or device. After mTLS, the app still sends a bearer token for the user. A tester extracts the P12, imports it into a desktop HTTP client, and successfully completes the TLS handshake to the production API; without a valid bearer token the API returns 401, but with a token stolen from a device the tester retrieves account data. The team says mTLS is working because the handshake fails without the P12. There are 50,000 installs and no revocation process for the shared certificate.

1. Does the shared client certificate provide meaningful client authentication? Explain what the tester's result proves.

Read the worked answer

The shared P12 authenticates the APK, not the user or device. Because every install has the same private key and password, extraction from one device compromises all 50,000. The tester's success proves the certificate is not a secret and that the server has no per-client identity to bind. mTLS still requires a bearer token, so the certificate only filters clients that do not have the APK. An attacker with a stolen token can pair it with the extracted P12 and reach the API. The handshake failing without the P12 only shows that the server requires some certificate signed by the CA; it does not show that the client is legitimate.

2. Design a per-device mTLS provisioning flow using Android Keystore and server-side binding.

Read the worked answer

Generate an EC or RSA key pair in Android Keystore with hardware-backed storage and setUserAuthenticationRequired where appropriate. Create a CSR with a device-generated ID, authenticate the user, and have the server sign a short-lived client certificate with sub or SAN mapping to the user and device. Install the certificate chain; the private key never leaves the Keystore. The server should authorize based on the certificate identity plus the bearer token, not just CA signature. Use short validity, OCSP or CRL, and rotation on re-enrollment. Add Play Integrity or App Attest to raise the bar against emulators and repackaged apps.

3. What should be done about the existing shared certificate and the 50,000 installed clients?

Read the worked answer

Treat the shared certificate as compromised. Revoke it at the CA or remove it from the server trust list, issue a new per-device provisioning flow, and force an app update. Because revocation affects all installs, plan a migration window with telemetry and a hard cutoff. Invalidate outstanding bearer tokens, monitor for use of the old certificate, and add server-side alerts for many accounts using one certificate. Do not just issue a new shared P12; that repeats the same design flaw.