Using SmartCardHsm with GnuPG

4 minute read

GnuPG

When you want to store your GnuPG private key(s) on a smartcard, you have a few options like the Yubikey, NitroKey GPG compatible cards, or the OpenPGP. The advantage of these cards is that they support GnuPG directly. The disadvantage is that they can only store 1 or a few keys.

Another option is SmartCardHSM, NitroKey HSM is based on SmartCardHsm and should be compatible. The newer versions support 4k RSA encryption keys and can store up 19 RSA 4k keys. The older version is limited to 2k RSA keys. I still have the older version. The advantage is that you can store multiple keys on the card. To use it for GPG encryption you’ll need to set up a gpg-agent with gnupg-pkcs11-scd.

Prepare

Smardcards

I use 3 smartcards to store my keys, these SmartCardHSM’s were created with Device Key Encryption Key (DKEK) keys. See my previous blog posts on how to setup SmartCardHSM with Device Key Encryption Keys:

I create the public / private key pair on an air gaped system running Kal Linux live and copy the key to the other smartcards. See my previous blog posts on how to do this. I’ll only show how to create the keypair in this blog post.

Setup gpg

Create the keypair.

kali@kali:~$ pkcs11-tool --module opensc-pkcs11.so --keypairgen --key-type rsa:2048 --label gpg.intern.stafnet.local --login
Using slot 0 with a present token (0x0)
Key pair generated:
Private Key Object; RSA 
  label:      gpg.intern.stafnet.local
  ID:         47490caa5589d5b95e2067c5bc49b03711b854da
  Usage:      decrypt, sign, unwrap
  Access:     none
Public Key Object; RSA 2048 bits
  label:      gpg.intern.stafnet.local
  ID:         47490caa5589d5b95e2067c5bc49b03711b854da
  Usage:      encrypt, verify, wrap
  Access:     none
kali@kali:~$ 

Create and upload the certificate

Create a self signed certificate

Create a self-signed certificate based on the key pair.

$ openssl req -x509 -engine pkcs11 -keyform engine -new -key 47490caa5589d5b95e2067c5bc49b03711b854da -sha256 -out cert.pem -subj "/CN=gpg.intern.stafnet.local"

Convert to DER

The certificate is created in the PEM format, to be able to upload it to the smartcard we need it in the DER format (we’d have created the certificate directly in the DER format with -outform der).

$ openssl x509 -outform der -in cert.pem -out cert.der

Upload the certificate to the smartcard(s)

$ pkcs11-tool --module /usr/lib64/opensc-pkcs11.so -l --write-object cert.der --type cert --id 47490caa5589d5b95e2067c5bc49b03711b854da --label "gpg.intern.stafnet.local"
Using slot 0 with a present token (0x0)
Logging in to "UserPIN (SmartCard-HSM)".
Please enter User PIN: 
Created certificate:
Certificate Object; type = X.509 cert
  label:      gpg.intern.stafnet.local
  subject:    DN: CN=gpg.intern.stafnet.local
  ID:         47490caa5589d5b95e2067c5bc49b03711b854da
$ 

Setup the gpg-agent

Install the gnupg-pkcs11-scd from GNU/Linux distribution package manager.

Configure gnupg-agent

$ cat ~/.gnupg/gpg-agent.conf
scdaemon-program /usr/bin/gnupg-pkcs11-scd
pinentry-program /usr/bin/pinentry
$ 
$ cat ~/.gnupg/gnupg-pkcs11-scd.conf
providers smartcardhsm
provider-smartcardhsm-library /usr/lib64/opensc-pkcs11.so
$ 

Reload the agent

gpg-agent --server gpg-connect-agent << EOF
RELOADAGENT
EOF

Verify

$ gpg --card-status
Application ID ...: D2760001240111503131171B486F1111
Version ..........: 11.50
Manufacturer .....: unknown
Serial number ....: 171B486F
Name of cardholder: [not set]
Language prefs ...: [not set]
Sex ..............: unspecified
URL of public key : [not set]
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: 1R 1R 1R
Max. PIN lengths .: 0 0 0
PIN retry counter : 0 0 0
Signature counter : 0
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
$ 

Get the GPG KEY-FRIEDNLY string

gpg-agent --server gpg-connect-agent << EOF
SCD LEARN
EOF
$ gpg-agent --server gpg-connect-agent << EOF
> SCD LEARN
> EOF
OK Pleased to meet you
gnupg-pkcs11-scd[26682.2406156096]: Listening to socket '/tmp/gnupg-pkcs11-scd.NeQexh/agent.S'
gnupg-pkcs11-scd[26682.2406156096]: accepting connection
gnupg-pkcs11-scd[26682]: chan_0 -> OK PKCS#11 smart-card server for GnuPG ready
gnupg-pkcs11-scd[26682.2406156096]: processing connection
gnupg-pkcs11-scd[26682]: chan_0 <- GETINFO socket_name
gnupg-pkcs11-scd[26682]: chan_0 -> D /tmp/gnupg-pkcs11-scd.NeQexh/agent.S
gnupg-pkcs11-scd[26682]: chan_0 -> OK
gnupg-pkcs11-scd[26682]: chan_0 <- LEARN
gnupg-pkcs11-scd[26682]: chan_0 -> S SERIALNO D2760001240111503131171B486F1111
gnupg-pkcs11-scd[26682]: chan_0 -> S APPTYPE PKCS11
S SERIALNO D2760001240111503131171B486F1111
S APPTYPE PKCS11
gnupg-pkcs11-scd[26682]: chan_0 -> S KEY-FRIEDNLY 5780C7B3D0186C21C8C4503DDA7641FC71FD9B54 /CN=gpg.intern.stafnet.local on UserPIN (SmartCard-HSM)
gnupg-pkcs11-scd[26682]: chan_0 -> S CERTINFO 101 www\x2ECardContact\x2Ede/PKCS\x2315\x20emulated/DECM0102330/UserPIN\x20\x28SmartCard\x2DHSM\x29/47490CAA5589D5B95E2067C5BC49B03711B854DA
gnupg-pkcs11-scd[26682]: chan_0 -> S KEYPAIRINFO 5780C7B3D0186C21C8C4503DDA7641FC71FD9B54 www\x2ECardContact\x2Ede/PKCS\x2315\x20emulated/DECM0102330/UserPIN\x20\x28SmartCard\x2DHSM\x29/47490CAA5589D5B95E2067C5BC49B03711B854DA
gnupg-pkcs11-scd[26682]: chan_0 -> OK
S KEY-FRIEDNLY 5780C7B3D0186C21C8C4503DDA7641FC71FD9B54 /CN=gpg.intern.stafnet.local on UserPIN (SmartCard-HSM)
S CERTINFO 101 www\x2ECardContact\x2Ede/PKCS\x2315\x20emulated/DECM0102330/UserPIN\x20\x28SmartCard\x2DHSM\x29/47490CAA5589D5B95E2067C5BC49B03711B854DA
S KEYPAIRINFO 5780C7B3D0186C21C8C4503DDA7641FC71FD9B54 www\x2ECardContact\x2Ede/PKCS\x2315\x20emulated/DECM0102330/UserPIN\x20\x28SmartCard\x2DHSM\x29/47490CAA5589D5B95E2067C5BC49B03711B854DA
OK
gnupg-pkcs11-scd[26682]: chan_0 <- RESTART
gnupg-pkcs11-scd[26682]: chan_0 -> OK
$ gnupg-pkcs11-scd[26682]: chan_0 <- [eof]
gnupg-pkcs11-scd[26682.2406156096]: post-processing connection
gnupg-pkcs11-scd[26682.2406156096]: accepting connection
gnupg-pkcs11-scd[26682.2406156096]: cleanup connection
gnupg-pkcs11-scd[26682.2406156096]: Terminating
gnupg-pkcs11-scd[26682.2369189632]: Thread command terminate
gnupg-pkcs11-scd[26682.2369189632]: Cleaning up threads
^C
$ 

Import the key into GPG

$ gpg --expert --full-generate-key
gpg (GnuPG) 2.2.19; Copyright (C) 2019 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
   (1) RSA and RSA (default)
   (2) DSA and Elgamal
   (3) DSA (sign only)
   (4) RSA (sign only)
   (7) DSA (set your own capabilities)
   (8) RSA (set your own capabilities)
   (9) ECC and ECC
  (10) ECC (sign only)
  (11) ECC (set your own capabilities)
  (13) Existing key
  (14) Existing key from card
Your selection? 13

Use the KEY-FRIEDNLY string as the grip.

Test

List your key

$ gpg --list-keys
/home/staf/.gnupg/pubring.kbx
-----------------------------
pub   rsa2048 2020-05-02 [SCE]
      XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
uid           [ultimate] gpg.intern.stafnet.local (signing key) <staf@wagemakers.be>

Sign

Create a test file.

$ echo "I'm boe." > /tmp/boe

Sign

$gpg --sign --default-key  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX /tmp/boe

Enter your pin code.

┌──────────────────────────────────────────────────────────────────────────────────┐
│ Please enter the PIN (PIN required for token 'SmartCard-HSM (UserPIN)' (try 0))  │
│ to unlock the card                                                               │
│                                                                                  │
│ PIN ____________________________________________________________________________ │
│                                                                                  │
│            <OK>                                                <Cancel>          │   
└──────────────────────────────────────────────────────────────────────────────────┘

Verify

$ gpg --verify /tmp/boe.gpg
gpg: Signature made Sat 02 May 2020 12:16:48 PM CEST
gpg:                using RSA key XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 
gpg: Good signature from "gpg.intern.stafnet.local (signing key) <staf@wagemakers.be>" [ultimate]

Have fun…

Links

Leave a comment