PHP extension to read private key from the Linux Key Retention Service

As a follow-up on this Security Stackexchange question, asking if Symfony Secrets are a safe way to secure env-variables or database credentials in your web-app, I learned that a safe alternative to .env-files in Symfony would be to use Symfony Secrets. Symfony Secrets generates a public and private key to securely store configuration data.

It does that by generating a public and private key, the problem is that by default the private key is stored in the web-app together with the public key. While it still is secure and would even allow you to commit your secrets to Git, storing the private and public key together kinda defeats the point of asymmetric encryption in my opinion. A more safe approach would be to save the private key in Linux' Key Retention Service. That way the secrets would still be safe even when the web-app gets compromised.

But Symfony/PHP by default does not have access to the Linux Key Retention Service. So I am planning on making a PHP extension in Rust which would access the private key of Symfony Secrets from the Linux Keychain.

To implement this I basically have to tackle two issues.

1. Making a PHP extension in Rust.
I think this will be pretty straight forward. There are many crates like ext-php-rs or phper. Both crates seems to be well maintained and updated, and there are plenty of articles, examples and documentation to use as guidelines.

I think this part won't be an issue, but I'm open to suggestions.

2. Accessing the Linux keyring from Rust.
This part will be the hardest to tackle. I am planning to only implement it for Debian. There are different syscalls available to interact with the Linux Key Retention Service.

Initially I thought I'd have to embed some C-code in Rust to make it work, but that seems unnecessary because there are multiple crates available already to make it easier.

  • libc - A crate to make system calls.
  • syscalls - Another crate to make system calls, but seems to be less popular then libc.
  • keyutils - A crate which seems to interact directly with Linux' keyring.
  • linux-keyutils - A crate which seems to interact directly with Linux' keyring.
  • keyring-rs - A seemingly more high-level, easier to use and well maintained crate to interact with the Linux Keyring. But the description says - The DBus-based Secret Service, the kernel keyutils, and a combo of the two - so not sure if this is what I'm looking for.

I am not sure what would be best, using libc or syscalls to make the calls to the Linux Kernel API myself to retrieve the private key from the keyring (harder to implement, but oh so interesting and learnful) or just using a keyring-crate.

Some pointers regarding this part of the solution would be appreciated!

Does someone have some good advice or pointers to get me started on this?

A more safe approach would be to save the private key in Linux' Key Retention Service. That way the secrets would still be safe even when the web-app gets compromised.

Except your secrets would have to frequently be decrypted, every time you use them, and could easily get copied around several times during the course of their use, leaving decrypted copies of those keys lying around on the unused parts of the stack and heap which an attacker could then dump when he compromises the process. Or he could call the decryption routine. Or he could perhaps dump the HTTP headers of API calls you're making

If your secrets are keys themselves you could store them directly in the key store and use the crypto APIs to sign/encrypt things with those secrets without them ever leaving the kernel.

If they're merely long-lived bearer tokens then it's rather hard to secure them in a process that's actively using them. You can try anyway, on the premise it makes things more difficult for an attacker, though at that point you'll have to carefully think about how much effort you spend on getting some marginal security.

2 Likes

So you would go one step further then saving only the private key from Symfony Secrets in the keychain, but all the secrets/config data?

As I said, that only works if they're actually keys used for encryption or signing, because they never have to leave the machine to use them.
On the other hand many APIs require that bearer tokens to be sent over the wire as they are, so they get used all the time by the process and even leave the machine, so they can't be locked away in something more secure than the process handling them.

So OS key stores only keep the credentials out of the process when those credentials are used for some cryptographic scheme rather than being sent as-is.