This article was originally published on the Red Hat Customer Portal. The information may no longer be current.

Smart cards and hardware security modules (HSM) are technologies used to keep private keys secure on devices physically isolated from other devices while allowing access only to an authorized user. That way only the intended user can use that device to authenticate, authorize, or perform other functions that involve the private keys while others are prevented from gaining access. These devices usually come in the form of a USB device or token which is plugged into the local computer.

In modern "cloud" computing, it is often desirable to use such a device like a smart card on remote servers. For example, one can sign software or documents on a remote server, use the local smart card to authenticate to Kerberos, or other possible uses.

There are various approaches to tackle the problem of using a local smart card on a remote system, and on different levels of the smart card application stack. It is possible to forward the USB device holding the smart card, or forward the lower-level PC/SC protocol which some smart cards talk, or forward the high-level interface used to communicate with smart cards, the PKCS#11 interface. It is also possible to forward between systems one’s OpenPGP keys via GnuPG by using gpg-agent, or one’s SSH keys via ssh-agent. While these are very useful approaches when we are restricted to one particular set of keys, or a single application, they fail to provide a generic smart card or forwarding mechanism.

Hence, in Fedora, we followed the approach of forwarding the higher level smart card interface, PKCS#11, as it provides the following advantages:

  • Unlike USB forwarding it does not require administrator access on the remote system, nor any special interaction with the remote system’s kernel.
  • It can be used to forward more than just smart cards, that is, a Trusted Platform Module (TPM) chip or any HSM can also be forwarded over the PKCS#11 interface.
  • Unlike any application-specific key forwarding mechanism, it forwards the whole feature set of the card, allowing it to access items like X.509 certificates, secret keys, and others.

In the following sections we describe the approach and tools needed to perform that forwarding over SSH secure communication channels.


We assume having a local workstation, and a remote server. On the local computer we have inserted a smart card (in our examples we will use a Nitrokey card, which works very well with the OpenSC drivers). We will forward the card from the workstation to the remote server and demonstrate various operations with the private key on the card.

Installing required packages

Fedora, by default, includes smart card support; the additional components required to forward the card are available as part of the p11-kit-server package, which should be installed on both client and server. For the following examples we will also use some tools from gnutls-utils; these tools can be installed with DNF as follows:

 $ dnf install p11-kit p11-kit-server gnutls-utils libp11

The following sections assume both local and remote computers are running Fedora and the above packages are installed.

Setting up the PKCS#11 forwarding server on a local client

To forward a smart card to a remote server, you first need to identify which smart cards are available. To list the smart cards currently attached to the local computer, use the p11tool command from the gnutls-utils package. For example:

 $ p11tool --list-tokens
 Token 6:
         URL: pkcs11:model=PKCS%2315%20emulated;;serial=DENK0000000;token=UserPIN%20%28Daiki%27s%20token%29
         Label: UserPIN (Daiki's token)
         Type: Hardware token
         Model: PKCS#15 emulated
         Serial: DENK0000000

This is the entry for the card I’d like to forward to remote system. The important pieces are the ‘pkcs11:’ URL listed above, and the module name. Once we determine which smart card to forward, we expose it to a local Unix domain socket, with the following p11-kit server command:

 $ p11-kit server --provider /usr/lib64/pkcs11/ “pkcs11:model=PKCS%2315%20emulated;;serial=DENK0000000;token=UserPIN%20%28Daiki%27s%20token%29”

Here we provide, to the server, the module location (optional) with the --provider option, as well as the URL of the card. We used the values from the Module and URL lines of the p11tool output above. When the p11-kit server command starts, it will print the address of the PKCS#11 unix domain socket and the process ID of the server:


For later use, set the variables output by the tool on your shell prompt (e.g., copy and paste them or call the above p11-kit server command line with eval $(p11-kit server ...)).

Forwarding and using the PKCS#11 Unix socket on the remote server

On the remote server, we will initially forward the previously generated PKCS#11 unix socket, and then access the smart card through it. To access the forwarded socket as if it were a smart card, a dedicated PKCS#11 module is provided as part of the p11-kit-server package.

Preparing the remote system for PKCS#11 socket forwarding

One important detail you should be aware of, is the file system location of the forwarded socket. By convention, the module utilizes the "user runtime directory", managed by systemd: the directory is created when a user logs in, and removed upon logout, so that the user doesn't need to manually clean up the socket file.

To locate your user runtime directory, do:

 $ systemd-path user-runtime

The module looks for the socket file under a subdirectory (/run/user/1000/p11-kit in this example). To enable auto-creation of the directory, do:

 $ systemctl --user enable p11-kit-client.service

Forwarding the PKCS#11 socket

We will use ssh to forward the local PKCS#11 unix socket to the remote server. Following the p11-kit-client convention, we will forward the socket to the remote user run-time path so that cleaning up on disconnect is not required. The remote location of the run-time path can be obtained as follows:

$ ssh <user>@<remotehost> systemd-path user-runtime

The number at the end of the path above is your user ID in that system (and thus will vary from user to user). You can now forward the Unix domain socket with the -R option of the ssh command (after replacing the example path with the actual run-time path):

 $ ssh -R /run/user/<userID>/p11-kit/pkcs11:${P11_KIT_SERVER_ADDRESS#*=} <user>@<remotehost>

After successfully logging in to the remote host, you can use the forwarded smart card as if it were directly connected to the server. Note that if any error occurs in setting up the forwarding, you will see something like this on your terminal:

Warning: remote port forwarding failed for listen path /run/user/...

Using the forwarded PKCS#11 socket

Let’s first make sure it works by listing the forwarded smart card:

 $ ls -l /run/user/1000/p11-kit/pkcs11
 $ p11tool --provider /usr/lib64/pkcs11/ --list-tokens
 Token 0:
         URL: pkcs11:model=PKCS%2315%20emulated;;serial=DENK0000000;token=UserPIN%20%28Daiki%27s%20token%29
         Label: UserPIN (Daiki's token)
         Type: Hardware token
         Model: PKCS#15 emulated
         Serial: DENK0000000
         Module: (null)

We can similarly generate, copy objects or test certificates to the card using the same command. Any applications which support PKCS#11 can perform cryptographic operations through the client module.

Registering the client module for use with OpenSSL and GnuTLS apps

To utilize the p11-kit-client module with OpenSSL (via engine_pkcs11 provided by the libp11 package) and GnuTLS applications in Fedora, you have to register it with p11-kit. To do it for the current user, use the following commands:

$ mkdir .config/pkcs11/modules/
$ echo “module: /usr/lib64/pkcs11/” >.config/pkcs11/modules/p11-kit-client.module

Once this is done both OpenSSL and GnuTLS applications should work, for example:

$ URL=”pkcs11:model=PKCS%2315%20emulated;;serial=DENK0000000;token=UserPIN%20%28Daiki%27s%20token%29”

# Generate a key using gnutls’ p11tool
$ p11tool --generate-ecc --login --label test-key “$URL”

# generate a certificate request with the previous key using openssl
$ openssl req -engine pkcs11 -new -key "$URL;;object=test-key;type=private;pin-value=XXXX" \
         -keyform engine -out req.pem -text -subj "/CN=Test user"

Note that the token URL remains the same in the forwarded system as in the original one.

Using the client module with OpenSSH

To re-use the already forwarded smart card for authentication with another remote host, you can run ssh and provide the -I option with For example:

 $ ssh -I /usr/lib64/pkcs11/ <user>@<anotherhost>

Using the forwarded socket with NSS applications

To register the forwarded smart card in NSS applications, you can set it up with the modutil command:

 $ sudo modutil -dbdir /etc/pki/nssdb -add p11-kit-client -libfile /usr/lib64/pkcs11/
 $ modutil -dbdir /etc/pki/nssdb -list
   3. p11-kit-client
     library name: /usr/lib64/pkcs11/
        uri: pkcs11:library-manufacturer=OpenSC%20Project;library-description=OpenSC%20smartcard%20framework;library-version=0.17
      slots: 1 slot attached
     status: loaded

      slot: Nitrokey Nitrokey HSM (010000000000000000000000) 00 00
     token: UserPIN (Daiki's token)
       uri: pkcs11:token=UserPIN%20(Daiki's%20token);;serial=DENK0000000;model=PKCS%2315%20emulated


With the smart card forwarding described, we make it easy to forward your smart card, or any device accessible under PKCS#11, to the “cloud”. The forwarded device can then be used by OpenSSL, GnuTLS, and NSS applications as if it was a local card, enabling a variety of applications which were not previously possible.

About the author

Daiki Ueno is a programmer in the crypto team at Red Hat, where he works on TLS libraries including NSS and GnuTLS.

Read full bioIcon-Red_Hat-Directional-A-Black-RGB