Skip to content

pfmooney/pivy

Repository files navigation

piv-agent

About

This is an implementation of a simple PIV client for desktop Linux and OSX with minimal dependencies. It contains a piv-tool binary which can conduct basic operations using PIV cards, and the piv-agent, which implements the SSH agent protocol as a drop-in replacement for the OpenSSH ssh-agent command (except that the keys it contains are always on a PIV card).

"PIV cards" notably includes Yubico Yubikey devices such as the NEO and Yubikey4, which can store up to 24 keys by using the "retired key" slots (which this agent supports).

This project re-uses most of the agent and protocol parsing code from OpenSSH, where it’s been pretty thoroughly battle-hardened.

Using the agent

Using the PIV agent is identical to running the normal ssh-agent command, with the exception that piv-agent requires a -g argument specifying the GUID of the PIV card to attach to. You can also give a -K argument with the public key of the "Card Authentication" slot (9E) for extra security.

For example, the GUID of my PIV card is 995E171383029CDA0D9CDBDBAD580813 (if you don’t know your GUID, the piv-tool command can display it). I can use the following command to start the piv-agent against my card:

$ piv-agent -g 995E171383029CDA0D9CDBDBAD580813 bash
$ ssh-add -l
256 SHA256:PJ6ucGKUqlQhiJdArDaF65+AVImg8SVq77vL6nVE/ME PIV_slot_9C /CN=Digital Signature (ECDSA)
256 SHA256:U86TVxP/gxVk4CQibIWit3Q+/5i4aZuXa2NALIahjww PIV_slot_9E /CN=Card Authentication (ECDSA)

I can now use the 9E Card Authentication key with ssh or any other tools that use speak the OpenSSH agent protocol (e.g. the Joyent manta and triton tools). If I try to use the 9C Digital Signature key right now though, I will get an error like this:

$ ssh user@host
sign_and_send_pubkey: signing failed: agent refused operation
user@host: Permission denied (publickey).

To use the 9C key I will have to give my PIV PIN to the agent using the ssh-add -X command, so that it can unlock the card to use the key.

$ ssh-add -X
Enter lock password:
Agent unlocked.
$ ssh user@host
Last login: Wed Mar 28 21:56:11 2018 from laptop
[user@host ~]$

The PIV PIN is stored in memory only with special guard pages allocated either side of it and marked non-swappable. On Linux the memory area is also marked as non-dumpable so that it does not appear in core files.

You can make the agent forget the PIN by using the ssh-add -x command to "lock" it. You can supply any password you like (including an empty string) for the "lock" command. The command ssh-add -D can also be used, and will not prompt for a password (useful from scripts).

The agent will also forget the PIN automatically if the PIV card is unavailable for more than a few minutes, or if unusual conditions occur (e.g. an attacker tries to plug in a device with the same GUID that fails the 9E signature test).

Note that it’s perfectly fine to leave the piv-agent running and remove your PIV card: the agent will just return errors on any attempt to use it until you insert your card again (you will need to enter your PIN again). You can even start the agent without the PIV card present at all.

One useful way to use the piv-agent is to set up a systemd unit file for it to run whenever you log in, and adjust your shell profile to use it as your normal SSH agent. Then your PIV keys are automatically ready for use in any shell.

Other tools

There are two other tools that can be built as part of this repository as well: piv-tool and piv-zfs. The piv-tool utility is a general-purpose PIV information and management tool that uses the same client code as piv-agent, which can be useful for testing or debugging (you don’t have to use it for setting up keys, you can use yubico-piv-tool or any other PIV client just as well).

The piv-zfs tool is an early draft of a tool for managing ZFS encryption-at-rest keys using PIV EC. You can see a brief demo of it in action at https://asciinema.org/a/dsENdri85rPkOk6jpWsqCkUzn. The Makefile will only try to build piv-zfs on Linux or illumos and only if it detects libzfs is available.

Installing on Linux

On Linux you will need to have a compiler and basic build tools and headers installed, as well as the libraries pcsclite and libbsd (and their -dev packages if your distro does those). Some musl based distros will also require installing libedit.

Then, clone this repository and use make to build the binaries:

$ git clone https://github.com/arekinath/piv-agent
$ cd piv-agent
$ make
$ ./piv-tool list
      card: 995E1713
    device: Yubico Yubikey NEO OTP+U2F+CCID 02 00
     chuid: ok
      guid: 995E171383029CDA0D9CDBDBAD580813
     owner: 00000000000000000000000000000000
    fasc-n: D4E739DA739CED39CE739D836858210842108421384210C3F5
    expiry: 2030-01-01
    yubico: implements YubicoPIV extensions (v1.0.4)
      auth: PIN*
     slots:
           ID   TYPE    BITS  CERTIFICATE
           9c   ECDSA   256   /CN=Digital Signature
           9e   ECDSA   256   /CN=Card Authentication

You can run make install to install the agent into /opt/piv-agent and set up a user systemd service to start it automatically at login. The make install command will also print out lines to add to your .profile or .bashrc to make sure the agent is automatically available in all your shells (while still preferring a forwarded SSH agent if you SSH into your machine later).

$ make install
Enter a GUID to use for piv-agent: 995E171383029CDA0D9CDBDBAD580813

sudo install -o root -g wheel -m 0755 -d /opt/piv-agent/bin
Password:
sudo install -o root -g wheel -m 0755 piv-agent piv-tool  /opt/piv-agent/bin
install -d /home/alex/.config/systemd/user
install .dist/piv-agent.service /home/alex/.config/systemd/user
systemctl --user enable piv-agent.service
systemctl --user start piv-agent.service

Add the following lines to your .profile or .bashrc:
  export PATH=/opt/piv-agent/bin:$PATH
  if [[ ! -e "$SSH_AUTH_SOCK" || "$SSH_AUTH_SOCK" == *"/keyring/"* ]]; then
    export SSH_AUTH_SOCK="$XDG_RUNTIME_DIR/ssh-agent.socket"
  fi

Installing on OSX

Compiling on OSX is even easier. Rather than depend on homebrew or MacPorts or another similar system, we simply build libressl-portable in a subdirectory and statically link the binaries against it. The Makefile in this repository will handle it all for you.

Note there is no need to install PCSClite or OpenSC or any of the related tools or libraries on OSX — the PCSC framework built into the operating system itself works fine for piv-agent.

The commands you will need to run are as follows:

## Clone the piv-agent repository
$ git clone https://github.com/arekinath/piv-agent
$ cd piv-agent

## Build libressl and then piv-agent
$ make -j4
$ ./piv-tool list
      card: 995E1713
    device: Yubico Yubikey NEO OTP+U2F+CCID 02 00
     chuid: ok
      guid: 995E171383029CDA0D9CDBDBAD580813
     owner: 00000000000000000000000000000000
    fasc-n: D4E739DA739CED39CE739D836858210842108421384210C3F5
    expiry: 2030-01-01
    yubico: implements YubicoPIV extensions (v1.0.4)
      auth: PIN*
     slots:
           ID   TYPE    BITS  CERTIFICATE
           9c   ECDSA   256   /CN=Digital Signature
           9e   ECDSA   256   /CN=Card Authentication

## Install in /opt/piv-agent and add a launchd service for the agent
$ make install
Enter a GUID to use for piv-agent: 995E171383029CDA0D9CDBDBAD580813

sudo install -o root -g wheel -m 0755 -d /opt/piv-agent/bin
Password:
sudo install -o root -g wheel -m 0755 piv-agent piv-tool  /opt/piv-agent/bin
install .dist/net.cooperi.piv-agent.plist /Users/alex/Library/LaunchAgents
launchctl load /Users/alex/Library/LaunchAgents/net.cooperi.piv-agent.plist
/Users/alex/Library/LaunchAgents/net.cooperi.piv-agent.plist: service already loaded
launchctl start net.cooperi.piv-agent

Add the following lines to your .profile or .bashrc:
  export PATH=/opt/piv-agent/bin:$PATH
  if [[ ! -e "$SSH_AUTH_SOCK" || "$SSH_AUTH_SOCK" == *"launchd"* ]]; then
    source $HOME/.ssh/agent.env >/dev/null
  fi

There is one known issue on OSX currently: the PCSC framework does not work after calling fork(), which forces the piv-agent code to not be able to run in the background (this means using piv-agent bash to start a shell doesn’t work, for example). The best way to use it on OSX is set up as a launchd service.

Like on Linux, there is a make install target that will set up a launchd service for the piv-agent for you and advise you on what to add to .profile to make it available in all new shells.

About

PIV SSH agent

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C 97.8%
  • Makefile 1.1%
  • C++ 1.1%