Skip to content

RFC: run hook script before/after decryption#188

Open
peff wants to merge 1 commit intostr4d:mainfrom
peff:hooks
Open

RFC: run hook script before/after decryption#188
peff wants to merge 1 commit intostr4d:mainfrom
peff:hooks

Conversation

@peff
Copy link
Copy Markdown

@peff peff commented Oct 28, 2024

This runs a program of the user's choice before and after we attempt an actual decryption. This can be used for (among other things), a visual indicator that the key is being used, as well as that it may be waiting for a touch input.

I think an indicator like that is something people want (e.g., #154) but the solutions I've seen are overly complicated:

  • there is https://github.com/maximbaz/yubikey-touch-detector, but it is full of hacks and heuristics. I don't think it handles PIV at all, and for gpg it waits for an inotify event on the keyring file, then waits to see if gpg --card-status blocks. Yuck!

  • I've looked into whether a separate daemon could connect to pcscd and observe the connection from age-plugin-yubikey, but I don't think its API is nearly rich enough.

  • I did get something working by running pcscd with --debug, and then processing the log with journalctl --follow --unit=pcscd to find clients connecting and disconnecting. It works, but...gross.

Whereas if we can just trigger some user-defined script during decryption, then all of those problems go away. We don't need a separate long-running daemon, and most of what would go in the hook script is user-specific details of how to trigger the indicator.

The rest of this description assumes somebody doesn't have another great solution. Of course I'm happy to hear about it if they do. :)

I've marked this as "RFC" because there are a lot of design options, and I mostly wanted to give something concrete when starting the conversation. Various thoughts:

  • should there be a hook like this at all? It's perhaps a little weird to run an arbitary program from a security-focused tool. But if an attacker controls your environment or $PATH I think you're in trouble anyway (after all, we found age-plugin-yubikey on the $PATH already). And if you don't use the feature, I think it's easy to make it low cost when not enabled (in this PR it's just an environment variable check).

  • if we want hooks, should they go into the age/rage client tool? That would work, but it's a bit coarser. We don't know when (or even if) a yubikey decryption will happen.

  • how should the hook be configured? There's no config file, which I think is an intentional choice. We could just speculatively try to spawn some well-known name (age-yubikey-hook-decrypt or something) but that seemed a bit heavyweight for people not using the feature.

    In this PR we get the program name from the environment. It uses the same hook script for the before/after events, with a command-line option to differentiate. But it could also easily be two separate programs.

  • how should the hook be spawned? For short hooks, it would actually be simpler if the command were spawned using a shell (and then you could get away without writing a hook script at all, and just putting a few commands into the environment). Some other systems use this approach (e.g., most configured commands in Git) and I've found it convenient. But I wonder if it's a portability headache for systems without /bin/sh.

  • what information should the hook get? I'm passing it start/stop here. It could perhaps receive information about the key, including the needs_touch flag. For my purposes, those weren't useful (I just want to show a key icon while we wait; even if a touch isn't required, the flashing key is a good reminder that a decryption happened).

  • we'd need documentation and perhaps tests. It didn't make sense to me to write documentation until some of the above questions are answered.

Just to flesh out the rest of the example use case for my system, my $AGE_YUBIKEY_HOOK_DECRYPT environment variable contains age-yubikey-hook, which is a script that looks like this:

#!/bin/sh
case "$1" in
start) t=🔑 ;;
    *) t=   ;;
esac

exec awesome-client "key_status:set_text('$t')"

which is obviously quite specific to my setup (key_status is an awesomeWM wibox.widget.textbox() widget configured within the window manager). But hopefully it gives a sense of what I'm trying to do with it.

Thoughts?

This runs a program of the user's choice before and after we attempt an
actual decryption. This can be used for (among other things), a visual
indicator that the key is being used, as well as that it may be waiting
for a touch input.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant