Yubikey: Store a wireguard private key on your yubikey

Introduction

I ran across this archived reddit thread today: https://www.reddit.com/r/WireGuard/comments/gn7qob/wireguard_using_a_pkcs_token_on_hardware/

The problem to solve, is to figure out how to store a public key as a secret on a yubikey.

One part of the problem, is that for this approach to work, you must allow objects to be read from the yubikey without pin code. Mainly since I have not figured out a way to script pin input to ykman.

  • Store a secret as an object on the Yubikey
  • Use the secret stored on the Yubikey in the wireguard configuration file

First, we need to have a look at how to store objects, and what addresses are available: https://developers.yubico.com/yubico-piv-tool/Actions/read_write_objects.html

I selected address 0x5fc106; “Security Object”. In my very limited testing, it looks like the 0x5fc106/“Security Object” is not protected by a pin code, whereas some others (e.g 0x5fc109/“Printed Information”) are protected by a pin code.

#--- Create a private key
$ wg genkey > myPrivKey.out

#--- or use an already existing private key (do not use this one)
$ ykman piv write-object 0x5fc106 ./myPrivKey.out

#--- test that the object could be written, and that you don't have a pin code set
$ ykman piv read-object 0x5fc106
2Hyrkc6MUFI17GXAHVv1K1oImYi1dIzZw8N8+o1XflA=

Now your yubikey is set up properly, and you can replace the [Intervace]/PrivateKey attribute in your /etc/wiregurad/wg0.conf file with a PostUp attribute.

#PrivateKey = 2Hyrkc6MUFI17GXAHVv1K1oImYi1dIzZw8N8+o1XflA=
PostUp = wg set %i private-key <(ykman piv read-object 0x5fc106)

Now, test that the interface comes up again:

$ sudo wg-quick down wg0
[#] ip link delete dev wg0

$ sudo wg-quick up wg0
[#] ip link add wg0 type wireguard
[#] wg setconf wg0 /dev/fd/63
[#] ip -4 address add 10.66.67.1/24 dev wg0
[#] ip link set mtu 1420 up dev wg0
[#] wg set wg0 private-key <(ykman piv read-object 0x5fc106)

$ ip a show wg0
11: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none 
    inet 10.66.67.1/24 scope global wg0
       valid_lft forever preferred_lft forever

$ sudo wg show
interface: wg0
  public key: Wk5ZOgVlGo8nZzoUY+ZmzhsyJSNqsGgZP0ZuIDXmu3A=
  private key: (hidden)
  listening port: 37551

peer: WCuj2WSxP3uf6QvVJLs6DvRiW/9wrGOUCQ+H1eG1/lc=
  allowed ips: 10.66.67.2/32
  persistent keepalive: every 25 seconds

peer: BDaWfOFmkvK5KMHRH+J/VrU2Tn7tvAR2bqX3SB9cqGE=
  allowed ips: 10.66.67.3/32
  persistent keepalive: every 25 seconds

References