[okular] [Bug 459173] Cannot use USB smartcard to sign document
John Scott
bugzilla_noreply at kde.org
Thu Jul 30 00:11:52 BST 2026
https://bugs.kde.org/show_bug.cgi?id=459173
--- Comment #10 from John Scott <jscott at posteo.net> ---
Signing documents with a smartcard is possible already and I don't think the
title of this bug accurately describes a problem, but I'd like to describe some
background information about how smartcard support actually works, because the
fine details are unfortunately not described well in any single place.
Right now there are two signature backends in Okular and both support
smartcards for X.509 signatures even if in two slightly different ways:
• the gpgsm backend, which uses a "GnuPG agent" (conceptually similar to an SSH
agent) via interprocess communication, usually a Unix domain socket, to issue
requests for things to be signed.
• the Mozilla NSS backend, which is a cryptography library from Mozilla which
supports its own internal key and certificate stores but also commonly uses
PKCS#11 modules to interface with other key stores, software and hardware, and
which may include both public certificates as well as secret keys
Now, a word about smartcards. Smartcards come in a lot of different
physical-layer form factors such as on-board TPMs, USB, Bluetooth, or NFC
devices, over TCP/IP, software emulation, and more. They may also use different
conventions for communicating with the host or offer different capabilities,
with notable "profiles" including PIV cards (now an international standard) and
OpenPGP cards. Some cards may require their own "drivers" of sorts if they
operate in some custom way, and in that case you usually get that from the card
manufacturer. Other times, as with PIV cards that (for the most part) "work
alike", you may use a manufacturer-agnostic shim to communicate with the
hardware. OpenSC is a project that aims to do this for many families of cards.
Most applications, like Okular, or web browsers and such, would rather not care
about this. Fortunately there is a standard that helps called PKCS#11, the
Cryptographic Token Interface ("cryptoki") maintained by OASIS:
https://www.oasis-open.org/committees/pkcs11/ It defines a standard API for
shared objects (".so" in Unix land), referred to as "modules", that can be
loaded (such as with dlopen()/dlsym()) to interface with some driver for some
hardware, learn its capabilities, and get info about the keypairs it may store.
Cards may store mere cryptographic (mathematical) objects ("raw" key pairs,
identified by their subjectPublicKeyInfo in X.509 jargon) and leave
higher-level interpretation to the PKCS#11 module software, or to applications.
Other cards may have enough flash storage to hold a convenience copy of the
*public* certificate, so that a card can be plugged into a host computer and
used easily right away. OpenPGP cards, for example, usually store a URL that an
OpenPGP public key can be obtained from, intended to be on the public internet.
So in this conceptual model, we have this arrangement going on:
user agent/application [Okular, LibreOffice, web browser...] ↔ PKCS#11 shared
object (basically a software library for talking to some vendor's hardware with
a pluggable standard API) ↔ actual smartcard hardware (which may have on-board
storage for arbitrary data as a convenience, or which may retain almost no
metadata itself and expects the vendor's PKCS#11 "driver" to take up that
responsibility)
This is a theoretical model though and more layers of abstraction are actually
spliced in. Okular does not speak PKCS#11 or even care to have knowledge of
cryptographic algorithms. It uses its backend (we'll focus on NSS for right
now) to probe for what X.509 certificate authorities the user trusts, what
private keys (if any) the user possesses, what public keys they may correspond
to, and so on. The NSS library, separately from using PKCS#11, knows how to
handle secret keys and store them on disk in its database, but it also has good
support for using PKCS#11 modules when configured to use them (see the
'modutil' utility).
Unlike other TLS/CMS libraries, NSS is designed mainly to meet Mozilla
Firefox's needs, so it's usually configured at the user level instead of with
system-wide configuration files as with OpenSSL. (OpenSSL seldom needs explicit
configuration anyway.) When used with Firefox, NSS stores all of its per-user
preferences—including which certificate authorities to trust, your public and
private keys, and desired means to perform revocation checking—in tandem with
Firefox profiles in a user's home directory. In Firefox's settings it's
possible to tweak NSS's advanced settings right from the GUI. This includes
such things as "I would like to introduce you to my PKCS#11 module. You should
try talking to /usr/lib/pkcs11/foo.so whenever you're doing 'roll call' to see
what public/private keys I possess, in addition to your internal on-disk
store."
If you don't use Firefox, you may not even have an NSS database set up
anywhere... and that's where things get puzzling, because other NSS-using
applications like Okular and LibreOffice don't expose detailed settings like
Firefox does. That's not their fault—it's just that Firefox does double-duty as
being an ordinary application, but also being the de facto configuration UI for
NSS. That's important not just for telling NSS about your favorite PKCS#11
modules, but even just importing a certificate with a private key file to store
on disk. Okular and LibreOffice are designed with the assumption that things
are already set up to your liking, and if they find a Firefox installation with
an NSS database for your user, they'll sometimes try to use it
automagically—that's better than a clean slate anyway, right?
Otherwise different NSS-using applications may choose to duplicate settings or
store them in totally different places which can get kind of crazy, but Okular
and LibreOffice allow you to set the path manually so you can get them all to
agree. A de facto standard, including with GNOME's Evolution, has emerged to
use the directory ~/.pki/nssdb/ as one possible location for an NSS DB. If you
don't use Firefox, such a database can be manipulated with command-line tools
'certutil' (for handling public and private certificates stored internally or
otherwise known to NSS, their nicknames, trust levels for particular
applications, generating new key pairs, and so on), and also 'modutil' (for
setting up what PKCS#11 modules—if any—you'd like to use).
Such configuration only benefits NSS applications, not programs using OpenSSL,
GnuTLS, or other crypto libraries. What crypto library an application uses
behind the scenes often doesn't really make a difference to a user, and
figuring out what installed PKCS#11 modules should actually be used is also a
common toss-up. That's where p11-glue/p11-kit comes in, which (optionally)
provides a PKCS#11 "reverse proxy" module that rounds up all of the other
PKCS#11 modules on your system and presents them as a virtualized one, so you
can centralize your choice of smartcard configuration and which modules to use
in a way amenable to all of the crypto libraries. That's what p11-kit-client
is. This isn't necessary but often simplifies setup on workstations. It also
makes it easy to use different cards, even from different vendors, and which
may need different "drivers" via different PKCS#11 modules, all at the same
time. And in this case, you only need to use 'modutil' to tell NSS about
p11-kit-client. GnuTLS usually tries p11-kit-client by default in the absence
of other configuration, and I don't have personal experience with the OpenSSL
bits but it's probably a small configuration option with the provider/engine.
If you don't want to use the p11-kit shim, using modutil to tell NSS about your
PKCS#11 module(s) directly is also okay. OpenSC provides drivers for many
common card types, including PIV and OpenPGP cards, and so you may inform NSS
of opensc-pkcs11.so. There's also a PKCS#11 module from the folks behind GnuPG
called Scute that (going through gpg-agent and scdaemon) lets you use your
OpenPGP card, even for X.509 crypto. This can be convenient because usually
only one PKCS#11 module can talk to a piece of hardware at a time, so if you're
a GnuPG user even occasionally, OpenSC and GnuPG will fight for custody of the
smartcard. Also, SoftHSM is a PKCS#11 module that, effectively, just stores
your private keys on disk using software. It would be useful if you wanted a
software keystore but Mozilla NSS didn't make one of their own, or if you
wanted to have a centralized location to keep your private key so many
applications on your system could use it (think a TLS certificate's key for
example, which might be used by both an HTTP daemon and an SMTP daemon).
Now the network diagram looks more like this for possibilities:
Okular ↔ Mozilla NSS ↔ { NSS Internal Crypto Store, PKCS#11 module
(opensc-pkcs11.so) ↔ { Foobar Inc. USB Token ↔ { flash storage, RPC-like
transport of signed or to-be-signed data, vendor extensions, ... } , ... },
another PKCS#11 module (...), p11-kit's PKCS#11 module wrapper
(p11-kit-client.so) ↔ { PKCS#11 module (opensc-pkcs11.so), ... } ... }
Yes, recursion is absolutely possible here. I don't make the rules 🤷.
And aside from all of this, there's one problem worth mentioning and which may
cause the reporter's problems: NSS does not cope with multiple certificates
(from any combination of sources) having the same nickname nicely at all. It's
possible to get into a state where you have multiple certificates that end up
with the same nickname in NSS, and when doing 'pdfsig -nick foo', or signing in
Okular or another application, you'll practically reach uncharted territory
with no practical way out. certutil doesn't help since the use of a nickname is
(apparently) the only way to specify a certificate you'd like to *rename*, so
if you're trying to rename certificates to ensure they have unique names,
you're in a chicken-and-egg problem. After renewing a certificate and importing
the new one in NSS's software store, or if any two key stores (the internal one
or any number of PKCS#11 modules) offer up keypairs under the same nickname,
you're kind of toast. One possible future avenue for exploration would be that,
sometimes, NSS allows using a PKCS#11 URI (RFC 7512) in place of a nickname.
With pdfsig on the command-line this is an effective way to unambiguously say
what certificate you'd like to sign with. In my scripts I usually have
something like
> pdfsig -backend NSS -nick pkcs11:model=SoftHSM%20v2;manufacturer=SoftHSM%20project;serial=XXXXXXXXXXXXXXXX;token=X.509%20certificate;id=%47%E3%4A{...}%A8;object=Certum
where, in some higher-level interfaces like '-list-nicks', 'Certum' would
usually appear to be the nickname, sometimes prefixed with the "token name"
which I've aptly named "X.509 certificate".
The reporter's issues may come from having the certificate imported in both the
software certificate store as well as via a PKCS#11 card, which makes NSS get
into that "undefined" state I alluded to before. I would suggest to the
reporter to share the output of 'certutil -K -h all -d ~/.pki/nssdb/', where
that path at the end may need to be replaced with whatever NSS DB location
Okular is actually trying to use (visible in Okular's PDF backend settings).
This will list all private keys that NSS is discovering from any token
anywhere, including the internal software store. If any two keys have the same
nickname (displayed in the rightmost column), that's going to be a problem.
--
You are receiving this mail because:
You are the assignee for the bug.
More information about the Okular-devel
mailing list