DNS-based expiration and revocation of SSH client keys

Presentation slides from the SSHARK talk at 29c3 are available here: sshark-29c3.pdf

The goal of SSHARK is to allow the expiration and revocation of SSH client keys by putting information in DNS TXT records...

How is this possible? With SSHARK, information about SSH key validity is stored in DNS. The information is signed by the SSH key itself rather than with a separate certifying key. The validity check is performed on the server side by using the command="..." facility available in the authorized_keys file as supported by OpenSSH and DropBear SSH servers.

Quick start

SSHARK is meant to be simple to use. Here's a brief how-to. Be careful not to lock yourself out of your house. :-)

(1) Put somewhere on the sshd side and make it executable. Assure that you have the Perl modules Net::DNS and Authen::PAM in your library path.

(2) Put in the ~/.ssh/ directory where you keep your SSH public and private keys, and make it executable. Assure that you have a base64 binary in your command path.

(3) Assure that the 'comment' in your SSH public key is in valid RFC822 email address form, with the domain part being a DNS zone where you have the ability to add records. (If this makes you scream "do not want!" then leave it alone, and specify the lookup domain explicitly with -d in your server-side invocation later.)

(4) Generate some expiration data. In the directory where your SSH public/private keys are stored, execute: ./ id_rsa 86400. You will be prompted for the passphrase to decrypt your SSH private key. If successful, the program will generate a batch of DNS RR's indicating that your key is valid for 1 day (86400 seconds) from the current system time. For TXT "sshark1 serial 1356743196 expiry 1365383196" TXT "sshark1 data L7MfKYu2Ok3zk95N/xuXkIiKfkk8xlR+Xcj7gK/wseXWx8EhtuKL36tzJfyVmVW2LQuvTVvH0oK2" TXT "sshark1 data VDx+rPDyQ47GnoJoXR589LOaMYTUzZF3Aq3EZ3dpB7z69mYWsL3utI9AX81rmUiDEWE0PqbGlZFQ" TXT "sshark1 data n7s7D2RaxLL7fIYnMOQ="

(5) Insert the DNS RR's into the appropriate DNS zone and ensure they are being served correctly.

(6) On the machine running sshd, add your SSH public key to your ~/.ssh/authorized_keys file if it's not already there. Preface the key with a "forced command" that invokes specifying the key type and fingerprint. For example:command="/home/nobody/bin/ -t ssh-rsa -l be:6d:70:bf:04:e2:f8:65:2b:81:4a:72:9b:73:3c:ea" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDIISOnw1Ennf84oHyHNdNdmfHlAknHOecAHjRiIo4/3oi3vMV9O201257A8b34ntZOE6uquMiorogmkyWdYfsv0aX1vO3yDGRPd8/+bOb509vhZAcRvFaEYiN5dxgFeXGFsGH/1Zu1cee3MTcnRjk8HJMXpetvUpFoc/CZnrQw/w==

(7) Test by trying to SSH into the system running sshd using the SSH key. A message from SSHARK will appear upon successful authentication, for example:[sshark] Your key is valid until Sat Dec 8 03:28:30 2012

(8) Test by generating revocation data with ./ id_rsa revoke and publishing it. Now try to SSH in, and your access should be denied with a message from SSHARK, for example:==========================[sshark]========================== Sorry, your SSH key has been revoked. Key: ssh-rsa be:6d:70:bf:04:e2:f8:65:2b:81:4a:72:9b:73:3c:ea Zone: ============================================================

Server-side operational details

In this section, "SSHARK" refers to the server-side component,

USAGE: [ -f <queryFile> ] [ -d <queryDomain> ] -t <keyType> -l <keyHash>

The SSHARK server-side component expects to be run from within the authorized_keys file using the command="..." syntax available in the OpenSSH and DropBear versions of sshd. It requires a specification of the key it is validating, in the form of a key type and hash. Currently, the only supported key type is ssh-rsa. The format of the key hash is sixteen colon-delimited zero-padded lower-case hexadecimal bytes, identical to the output of OpenSSH's ssh-keygen(1) command.

SSHARK normally looks for expiration/revocation records pertaining to a given key (called claims) under a zone derived from that key's comment field. The zone is essentially the comment with the @ substituted with the domain component _sshark. For example, a key with comment will cause SSHARK to look for records under Alternatively SSHARK can be told to look in a different zone using the -d flag. SSHARK always looks for these records by issuing DNS TXT queries. SSHARK can be told to look in a local file (in addition to DNS) by specifying the -f flag, which has a default value of /var/lib/sshark/sshark.dat. That file contains one record per line in whitespace-delimited key-value form, and must be readable by the authenticating user.

The records containing the claims themselves are named after the key type and fingerprint, appended with the zone name. For example: This name is called the querybase. Each claim is a string in the format sshark1 serial S expiry E where S is a serial number (conventionally the UNIX epoch time of the creation of the record, but can be any monotonically incrementing value) and E is the UNIX epoch time of the key's expiration. If E is equal to 0, the claim is one of total revocation.

Each claim is cryptographically signed by the SSH key to which it refers. The records containing the signature are named for the serial number of the claim, prepended with the letter s, and appended with the querybase. For example: The signature records, when concatenated, contain a base64-encoded signed message containing the lower case hexadecimal representation of the SHA-256 hash of the claim.

SSHARK evaluates all claims available for a given key, starting with any revocation claims, and then proceeding through each claim in descending serial number order, until a valid claim is found. Invalid claims, such as those which are malformed or contain an invalid signature, do not affect SSHARK's final decision about key validity. If no valid claims are found, access is denied. If a valid revocation claim is found, access is denied. If a valid expiration claim is found, and the expiration date is not in the future according to the system clock, access is denied. When access is denied, SSHARK informs the authenticating user of the reason, the key fingerprint, and the relevant lookup zone, and terminates.

If access is not denied, SSHARK informs the authenticating user of the the expiration date of the key currently in use, and attempts to make things proceed as normal. If a command was requested, SSHARK executes it. If the internal SFTP facility was requested, SSHARK executes /usr/lib/sftp-server. If a shell was requested, SSHARK calls pam_start(3) with the service name sshark and then calls pam_open_session(3). If /etc/pam.d/sshark is present, something like a normal login will take place. Otherwise, the user's login shell will simply be spawned in whatever environment was already prepared by sshd, which tends to be fairly complete already.

The code

SSHARK is currently available in a reference implementation that only supports ssh-rsa type keys. The server-side component is about 375 lines of Perl, and the component which generates the expiration/revocation data (claims) is a small Bash script. It is up to you to host the claims somewhere in DNS. There is also a pam.d(5) file recommended but not required for the server side. We consider the server-side component to be nearing production quality. However we call it a reference implementation because its dependence on various Perl modules and a recent version of ssh-keygen(1) makes it less than totally portable. Part of SSHARK's goal is to be deployable on SSH servers without the fuss of dependencies. A binary, even statically-linked if necessary, will eventually accomplish this in a way that the Perl script cannot.

You can download the 0.1.1 release tarball here: sshark-0.1.1.tar.gz

The files contained in the tarball are:

This version is being released under GPLv3. We are not married to the GPL, so this might change in the future.


Future directions

Here are some things on our to-do list:

Who's responsible for this?

SSHARK is the work of Greenhost, a growing technology company in Amsterdam. We are develping projects that promote digital security and freedom, and building hosting platforms that respect free speech and the environment. SSHARK was developed by by Anatole Shaw with crucial input from Sacha van Geffen and Mart van Santen. Thanks to Carl van der Tas for important early feedback on the 29c3 presentation, and to Douwe Schmidt for drawing the hilarious logo.

Please send feedback to Anatole Shaw, ash AT greenhost DOT nl.