Wednesday, December 29, 2010

gpg-agent on OS X

I don't like to have username and passwords lying around unencrypted on my hard drive. But I also don't like to have to keep entering in the same information over and over.

A great example of this problem can be found in the Emacs Gnus Mail Reader. Gnus lets you store your username and password information in a file called .authinfo. This way you don't have to enter a password every time you connect to your news or email servers. Of course the file isn't encrypted. EasyPG to the rescue. EasyPG allows you to have any file named *.gpg and it will then use gpg to decrypt the file. One little problem, every time Gnus needs to read info from the .authinfo file it prompts for the gpg password. So although you don't have to remember the passwords for the accounts you have to keep entering your gpg password. Ugghhh.

One way to fix this is to use gpg-agent. gpg-agent is a daemon to manage gpg private keys independently of any protocol. So with this you can configure how long to cache an entry (like a passphrase) so you don't have to enter it again. By default gpg-agent has a cache-ttl of 600 seconds. With this working Gnus can read the encrypted .authinfo file for 5 minutes and only prompts you for a password on the first read. Pretty sweet.

Of course setting up gpg-agent on OS X so that it interacts nicely with GUI apps like Emacs.app as well as command line utilities isn't perfectly straightforward but hopefully this entry will help.

Getting the software

I'm a big fan of MacPort so I'll use that in the examples. But you could download and compile your self.

sudo port install pinentry +gtk2 gpg-agent gnupg2

You need to add one of the variants to pinentry to get a GUI client that works on OS X. Your choices are: gtk1, gtk2, qt3 or qt4. I used gtk2 because I have other ports that depend on it but you can pick your favorite GUI toolkit. If you don't select a variant you will get a pinentry application that can only be run from a terminal.

Setup Emacs to use EasyPG and gpg-agents

The first step is to get Emacs to use EasyPG on files that end in .gpg. More info can be found on the Emacs Wiki.

Add the following to your Emacs.app start-up file

(require 'epa-file)
(epa-file-enable)

Next you need to teach EasyPG to use gpg2 instead of gpg as the name of the gpg executable. This is because MacPorts installs the gpg executable as gpg2 for the gnupg2 port. There is a gnupg port that installs the gpg executable but that is version 1.4 and doesn't work by default with gpg-agent.

Add the following to your Emacs.app start-up file

(setq epg-gpg-program "gpg2")

Lastly you need to teach Emacs how to talk to gpg-agent.

Add the following to your Emacs.app start-up file

(setenv "GPG_AGENT_INFO" "~/.gnupg/S.gpg-agent")

Getting gpg-agent to start at Login

Now that Emacs.app is configured to use gpg and gpg-agent you have to configure it so gpg-agent is started when you login. There are several ways to do this. I think the easiest and most "Macish" is to add a new Login Item in the Users Preference Pane. But to do that it has to be an Application. Luckily, AppleScript makes it easy to make Applications out of simple scripts.

A script to start gpg-agent

First lets write a simple Bash script to start gpg-agent

#!/bin/bash

GPG_AGENT=/opt/local/bin/gpg-agent
GPG_ARGS="--daemon --use-standard-socket"
GPG_SOCKET="~/.gnupg/S.gpg-agent"

if [[ -e ${GPG_SOCKET} ]]
then
    rm ${GPG_SOCKET}
fi

if [[ -x ${GPG_AGENT} ]]
then
    ${GPG_AGENT} ${GPG_ARGS}
fi

Save this to a file named gpg_agent_start.sh in your bin directory and make it executable.

chmod 755 ~/bin/gpg_agent_start.sh

Applescript to make an Application

Next start "AppleScriptEditor" it can be found in your /Applications/Utilities folder. Make a new script with the following:

do shell script "~/bin/gpg_agent_start.sh"

And then do a "Save As …", be sure to select "Application" as the File Format and name it "gpg_agent_Application".

Set as Login Item

  1. Launch System Preferences
  2. Select Accounts
  3. Select Login Items
  4. Use the "+" to add gpg_agent_Application
  5. Close System Preferences
  6. Logout and back in

You should see gpg-agent as a running process.

At this point you should be able to open any encrypted file named *.gpg and get prompted for the password with the pinentry application. Then any access to that file in the next 5 minutes won't require entering a password.

4 comments:

  1. I've been searching all day for an answer to this... and your page by far provided the best description of the process for getting gpg-agent up and running on Emacs. I just have one question. It's not entirely clear how long gpg-agent will cache the password for? Do I have to enter the password for my encrypted authinfo file just once a session? Less? More than that?

    Hope you still read/edit this blog and can help out... Thanks!

    ReplyDelete
  2. Oh and I meant to say, in recent versions of gpgtools the GPG_SOCKET string is invalid as is. It needs to read GPG_SOCKET="~/.gnupg/S.gpg-agent::1"

    ReplyDelete
  3. And that the elisp above wouldn't work for me until I swapped out the home expansion for the full path (setenv "GPG_AGENT_INFO" "/Users/matt/.gnupg/S.gpg-agent"). But I am using the gpgtools.org version of gig-agent.

    ReplyDelete