protoncore_android/key-transparency
Neil Marietta c517bba3ee chore: Upgraded Kotlin to 1.9.22 (and needed dependencies). 2024-02-28 18:09:18 +00:00
..
dagger chore!: Upgraded AGP to 8.0.2 (+Java 17). 2023-07-04 16:22:38 +02:00
data chore: Upgraded Kotlin to 1.9.22 (and needed dependencies). 2024-02-28 18:09:18 +00:00
domain chore: Upgraded Kotlin to 1.9.22 (and needed dependencies). 2024-02-28 18:09:18 +00:00
presentation feat(coverage): Update coverage rules and introduce new ExcludeFromCoverage annotation. 2023-08-30 15:47:23 +00:00
README.md feat(key-transparency): Implement PublicAddressVerifier. 2023-04-13 10:41:31 +00:00
build.gradle.kts chore!: Upgraded AGP to 8.0.2 (+Java 17). 2023-07-04 16:22:38 +02:00

README.md

Key transparency

This is the implementation of key transparency for all android clients using proton address keys.

What is key transparency

Key transparency (KT) is a project to solve a security issue of the key management set up at proton. Without KT, clients will fetch public keys for other users from the server, and have no other choices than to trust those keys if the user has not done an out of band verification. This means that the server can do a man-in-the-middle attack on an exchange between proton users, by serving a fake public key for which it has a private key, and reencrypting the message to the real public key of the recipient.

How does it work (briefly)

Each proton address is associated with a signed key list (SKL) generated by the client, a list of all the address keys that the client can decrypt, signed with the primary address key. The server periodically computes a merkle tree (an efficient structure to check a set membership) over all the SKLs of all addresses of proton users. It publishes the root of the merkle tree, by generating a TLS certificate that includes that root, using a 3rd party certificate authority. This periodical publication is called an Epoch, and each epoch is identified by an increasing Epoch ID. This certificate is logged by a "Certificate transparency" authority, to ensure proton doesn't generate multiple versions of an epoch. Now, to ensure that the server does not cheat when serving keys, the server is held accountable by two kind of external parties:

  • External auditors
  • Each proton user, using a client that runs the KT client checks.

External auditors will go through each epoch, recompute the merkle tree from scratch to check the computation was done correctly. And will go through the logs of certificate transparency, to ensure only a single version of an epoch was published with a certificate.

Proton clients will make KT checks in three occasions:

  • Periodically, the client runs a self audit: it verifies that the user's own address keys are correctly included in the current epoch.
  • When fetching the keys from an other user, the client verifies that the keys returned by the server are correctly included in the current epoch.
  • When modifying, removing or generating new keys, the client records the modification, and later verifies that the modification was reflected in the new epoch.

How it is implemented:

Dependencies:

The implementation depends on a custom golang library, which is built and bundled with the golang build for crypto library, see the "gopenpgp" module.

Self audit

Modifying keys

  • When modifying keys, or adding new keys, the SignedKeyListChangeListenerImpl implements the necessary KT checks. It is called by the user manager during signup via an optional binding of SignedKeyListChangeListener.
  • The SignedKeyListChangeListener provides two methods:
    1. listener.onSKLChangeRequested(userId, userAddress) is called before generating the new SKL, to check that the current state of KT is correct.
    2. listener.onSKLChangeAccepted(userId, userAddress, newSKL) is called after the new SKL has been uploaded.

Verifying public keys

  • The VerifyPublicAddress usecase implements the logic to verify public address keys served by the user. It does the necessary checks and returns an instance of a VerifiedState.
  • The verification is called by the key module via an optional binding of PublicAddressVerifier
  • The optional binding is provided by the key transparency module with the PublicAddressVerifierImpl implementation.
  • This logic is integrated into the key module, in the PublicAddressRepositoryImpl which handles fetching public keys. Temporarily, KT errors are caught and logged, to avoid interrupting the operation.

Using the module:

  • Self audit should be run through RunSelfAudit or through the worker, the module provides a periodic worker SelfAuditWorker and a SelfAuditStarter to schedule a worker for each active user logged in the app. The worker can be scheduled via the KeyTransparencyInitializer.
  • The product needs to provide a db that satisfies the KeyTransparencyDatabase interface.
  • The product needs to provide an instance of KeyTransparencyConfig. The config contains a local feature flag to enable/disable the checks globally. If the product wants to enable KT, it needs to provide an instance of KeyTransparencyParameters, the module provides several instances, for each environment that supports KT on the backend.

UI-less integration:

As a first iteration, KT will be integrated without any UI. To avoid weird interactions for the user, all the logic of KT is wrapped in error catching. Errors are logged and not propagated.