How to store secrets in your application? Things like API tokens, crendentials to other services, etc. In this post I'll go through my thought process on designing an operating system API for this. Hopefully I'm going to follow up with an implementation post when/if my hobby os project gets that far.
Plaintext files are easy and simple. If you limit access right to current user, they provide some level of security. For instance, private keys under
~/.ssh/ are only secured by file permissions. These secrets are not secure against other applications. And if the disk is not encrypted, they are not secure against physical attackers either.
Encrypted files provide a secure cross-platform solution. The encryption algorithm can be part of the program itself, so that no special OS APIs are required. However, storing the encryption key, for the file is now an issue. In some cases, it might be feasible to ask user for a password, and prompt for that every time the secret is required. Unfortunately, this is often highly impractical or impossible. If there are other ways to store the encryption key, simply storing the data there might be the best option.
System keychain provides a standard way to store such secrets. It usually encrypts the secrets with credentials of the current user, and automatically handles situations like user changing their password. In most systems the keychain also has a management UI, which an be useful in some cases, and harmful in others. One of the most elegant keychain implementations is Apples Keychain Services API. It has access control list so that application can limit which other applications have access to secrets. The application can even indicate should user see some secret in the management UI or not. GNOME keyring has similar functionality. On Windows, however, there is only the Windows Credential Manager which does not have any protection against elevated processes (and even if it did, keylogging and clipboard logging are trivially easy on Windows as well).
What if we could build a new system?
Application can ask the kernel (or the desktop environment, or the login manager) to generate an encryption key. Then application uses a file encrypted with the priovided key to store the secrets. Kernel stores the key in some secure way, probably encrypted with the user password or a TPM, preferably both. Now the problem is just that the application needs to authenticate to the kernel to get the same key again.
My first idea was to simply associate the secrets with the path of the calling binary and the current user name. However, a malicous attacker might be able to replace the application binary, especially when the binary is installed locally for the current user only. The simplest solution to this is to store a cryptographic hash of the application binary as well. Unfortunately this approcach has a severe flaw: updating an application changes its hash.
So, to update applications the old version needs to approve the update. How does it know that the new application is actually an update from the last one? Asking the user should not be an option here, as trusting the user is usually a mistake. So, the developer signs it with their private key, and the application can then verify that it matches the public key embedded in the application itself...
At this point I realize that maybe the kernel should know about authors and public keys? Applications wishing to use the application secret storage must be signed by a developer. If proper code-signing is implemented, it's not that complex to tie secrets to particular applications.