12

I would like to give a daemon-style process (i.e. no user interaction) access to a shared secret key so that it can access a shared, encrypted data file. User applications accessing the same encrypted data store the shared secret key in the user's OS keychain (e.g. OS X Keychain or Gnome Keyring, etc.). The OS keychain, in turn protects the secret key with the user's login (or other user-specific) password.

Encryption here is used to protect data as it transits public networks between server and client. The data in question is raw data from scientific experiments. Mostly non-valuable (i.e. unlikely to draw an attacker to speculatively break the encryption and browse the data), but some of it is potentially very valuable and the users wish to keep its details private until they choose to share it publicly (i.e. protect it from casual observers on the network). The value of the data is hard to determine without scientific analysis, so watching users' activity (including queries) as they transit the wire unencrypted would provide some clues to observers about a datum's value.

The daemon-process is a query server for the system. It reads from the shared data, processes a query, and returns identifiers for a result set to the client who then pulls the identified data from the shared store.

We allow synchronization of the encrypted data to users' local workstations/laptops, so encryption of the data on disk is at most a nuisance to a determined attacker. We also allow users to run the query server locally (still started by init.d/launchd), so I want to do whatever I can to protect the secret key stored with the daemon. The major risk is that a determined malicious user is able to discover the secret key from the daemon on their system. Exposure of that key would require us to change the key, update all users' and then re-encrypt the database.

What is the best way to store the shared secret key for the daemon process? I can put the key on disk and encrypt the file on disk, but the daemon process must then have the key to decrypt that file. This seems equivalent to just having the shared secret key for the original encrypted data. My naive approach would be to store the key in the application's binary, but I can't imagine that's the best option. Any advice?

Barry Wark
  • 241
  • 2
  • 8
  • Which accounts must read/write the data? Does the daemon just read what a user has written, vice versa, or is it two way? –  Jan 18 '11 at 18:22
  • Do you want the daemon to survive an unexpected reboot? If so, this is a pretty tough problem. If not, could an admin provide it with the key on startup? – nealmcb Jan 18 '11 at 18:46
  • @Graham The daemon only needs to read the data, but the encryption is symmetric AES (out of our control). – Barry Wark Jan 18 '11 at 18:59
  • @nealmcb The daemon is started by an init.d script on Linux or a launchd job on OS X. We're operating in a very low IT-budget environment (academia), so I'd like to avoid admin involvement. Obviously, putting the key in an init.d or launchd script/file is probably worse than in the binary, but only marginally so. – Barry Wark Jan 18 '11 at 19:00
  • What are you trying to achieve? What are you trying to protect? From who? What's your threat model? The question is not well defined. – D.W. Jan 19 '11 at 07:16

5 Answers5

12

This quickly turns into a 'turtles all the way down' problem. You just have to decide at which point you stop encrypting things and rely on another method. I think the goal should be to stop casual users, but not determined hackers, to easily get at the protected data.

I wrestled with a similar method in a web application which needed to store the DB password and the SSL cert password. What I ended up doing was encrypting those passwords in a config file for the app using a different master password. The master password was stored as an environment variable set by the application startup script. Since the master password was set only in the startup script, it was easy enough to give a single user access to the script along with the ability to run it using standard UNIX file permissions.

My thinking was that to get access to this script otherwise, you needed to already be root, at which point, it doesn't really matter. If you can't trust root (or the server has been hacked) you probably have other issues.

Also, there's a little security through obscurity here in that all the details of how this works is not documented very well on purpose. You would have to backtrace how the startup script works, then figure out which algorithm is used, how the salt + plantext is formatted, etc. If you want to get the DB password and got this far, I figure you could probably already have just broken into the DB server directly.

AngerClown
  • 235
  • 2
  • 5
7

As usual, the best place to start is by asking yourself some questions: What's your threat model? What are you trying to protect? Who are you trying to protect it against? Why are you using crypto in the first place? None of these is clear from the question. (Crypto is not magic pixie dust.) And without answers to those questions, we cannot give you a solution: the right solution is going to depend upon what you are trying to achieve.

Generally speaking there is going to be no great solution to this problem. The private key is going to have live in cleartext somewhere on disk (or in cleartext equivalent), if you want to be able to launch the system without user involvement. You'll quickly hit "turtles all the way down", as others have suggested.

One step you can take is to ensure the private key is protected by filesystem access controls: e.g., is readable by root but not by ordinary users.

Footnote: There are sophisticated approaches, but they are probably not suitable for your low-cost environment. (1) One more secure approach is to store the private key in a hardware security module connected to the server. If the server gets compromised, software cannot steal the private key (but it can still instruct the hardware security module to sign/decrypt arbitrary messages). (2) A more sophisticated approach is to use a TPM, and to lock the private key to a particular piece of software. Unfortunately current OS's don't provide good support for this, so it would be very challenging to do yourself as a sysadmin: it would require significant developer support.

D.W.
  • 98,420
  • 30
  • 267
  • 572
  • I'm not an appsec expert (obviously), but I've taken a stab at specifying the answers to your questions in my edited question. – Barry Wark Jan 19 '11 at 19:16
  • @Barry, Got it, thanks. Yup, I think the best you're going to be able to do (given the cost constraints) is store the key in the filesystem and make sure it is readable only by root (or by the userid that the daemon runs under). – D.W. Jan 27 '11 at 06:33
1

Isn't there a keychain available to the account for the daemon?

Steve
  • 15,155
  • 3
  • 37
  • 66
  • 2
    Probably not - the root account doesn't have a keychain by default, neither do bin, daemon etc. The system keychains are tamper-proof. The daemon could _create_ a keychain for its account, but now where do you store the passphrase? –  Jan 18 '11 at 18:34
  • Ahh, good point. – Steve Jan 18 '11 at 18:56
  • yfuhs As Graham says, we could create a keychain, but then the daemon needs to know that keychain's password. – Barry Wark Jan 18 '11 at 19:01
1

For completeness, the solution we chose was a combination of @SteveSyfuhs' and @AngerClown's answers. On OS X, we're making use of the System keychain (/Library/Keychains/System.keychain). On Linux, we're storing the encryption key in a file with permissions bits 400 (i.e. read-only by owner only), owned by root.

Barry Wark
  • 241
  • 2
  • 8
  • Sounds sensible to me, and as good as anyone can reasonably do (given your constraints). – D.W. Jan 27 '11 at 06:34
1

Barry, I like your solution and have an idea to take it one step further. How about keeping the machine image you use to create new machines automatically set to using 400 on the key file, then on boot start your server software as root, read the key into memory, delete the key, then switch the user running the server software to a non root account.

devadvocate
  • 111
  • 2