Background
This section is intentionally outside the Fedora guidelines. It is here to give background to the proposed guidelines.
X.509 / SSL certificates
X.509 certificates are used for authentication in TLS and other protocols. It's an X.509 certificate which lets you trust, when you connect to https://fedoraproject.org/, that you really are talking to the Fedora server and not an imposter.
The certificate is signed by a trusted "certificate authority", and contains a public key. It lets you know that whoever has the corresponding private key is truly the entity that the certificate claims they are (the 'subject' of the certificate).
As well as authentication for servers, certificates are often used to authenticate clients. For example for VPN connections, and also your 'Fedora certificate' used for koji access is an X.509 certificate.
At this document, we are only concerned with your certificates, where you have the corresponding private key and they are used to identify yourself.
These certificates are often stored in files, commonly either a PKCS#12 file (e.g. /usr/share/doc/openvpn/sample/sample-keys/client.p12
) or a PKCS#7 or PEM file (e.g. ~/.fedora.cert
).
It's important that a private key remain private; if someone can take a copy of it then they can impersonate you — run a server pretending to be yours, log in to your VPN, abuse Fedora's koji system in your name, etc.
If a key is stored in a file on the file system, it's common to use a passphrase to protect it. So the attacker would have to find the passphrase as well as copying the file. But if they can get access to your system, that's not actually much of an additional barrier.
A much more secure option is to keep the key in a separate hardware 'crypto token'. This will never just give up the key; instead it will perform (sign, encrypt, etc.) operations using the key. So you know the key can never really be stolen.
PKCS#11
PKCS#11 is the API standard for cryptographic tokens. It covers hardware crypto devices such as Hardware Security Modules, and smart cards. There are also implementations of PKCS#11 "providers" in pure software — for example the NSS (Firefox) certificate store, GNOME keyring, and SoftHSM; these are referred to as Software Security Modules.
For our purposes, PKCS#11 mostly just provides an object store for keys and certificates — and for keys it can perform crypto operations for you using the key instead of just handing out the private key data willy-nilly.
For security reasons as described above, it's very useful to be able to import keys into a PKCS#11 token and use them from there — even if it's just a software token like the one provided by gnome-keyring — instead of just having them stored in a file in a user's home directory. That's exactly what you're doing when you import a certificate into something like Firefox, Thunderbird or Evolution. There are plans to make NetworkManager always behave this way too: https://wiki.gnome.org/Projects/NetworkManager/PKCS11
Problem statement
Differences in object reference
Although the use of PKCS#11 is very desirable, it can be very hard to use because each application does things differently. There has historically been no consistent way to specify which certificate to use, from which PKCS#11 provider.
With the pesign tool for signing EFI executables, first you need to create a NSS database and use the modutil
tool to add your desired PKCS#11 provider to that environment. Then you can reference that token by its description and a certificate by its "nickname", which may not even be unique. For example, -t "PIV_II (PIV Card Holder pin)" -c "Certificate for PIV Authentication"
. (You can see this in its full horror in bug 1217727.)
Referencing the same certificate with OpenVPN might look something like: --pkcs11-providers=/usr/lib64/pkcs11/opensc-pkcs11.so --pkcs11-id=piv_II/PKCS\x2315\x20emulated/108421384210c3f5/PIV_II\x20\x28PIV\x20Card\x20Holder\x20pin\x29/01
With wpa_supplicant it's different again, as shown at http://w1.fi/cgit/hostap/plain/wpa_supplicant/examples/openCryptoki.conf
There are two parts to the problem — there's the question of which PKCS#11 provider module(s) should be loaded, and the question of how to identify the certificate you want to use from it. And there are two parts to the solution...
Complexity of specifying a certificate or key
As mentioned above certificates or private keys can be stored in files, or can be stored in a smart card or HSM. Applications do not provide a consistent method to specify these objects. They often require different methods to specify a certificate or key, depending on where it is stored.
No central registry of modules
In addition to the object references, there is no way for a Fedora application to determine the available PKCS#11 modules system-wide. Typically applications request for the user to specify a module in the form of a shared object (.so file), either in configuration file or on every command instance. See for example the pkcs11-tool or browser applications like firefox. Instead of presenting a list of available smart cards or HSMs, they ask instead the user to specify a shared object.
Current status
OpenConnect VPN client
It has exemplary PKCS#11 support following all the above guidelines. Instructions on how to use it, are available on this manual page.
wpa_supplicant
Since wpa_supplicant uses engine_pkcs11, much of the work was already done. All that remained was to make it automatically use the PKCS#11 engine when it detected a "filename" starting with 'pkcs11:
'. (sample commit)
OpenSSL engine_pkcs11
OpenSSL's engine_pkcs11 will load p11-kit-proxy.so
as its default provider if none is specified, and will accept the RFC7512 standard object URIs in place of its own legacy format.
Applications using GnuTLS
Applications linked with GnuTLS that utilize the high level APIs, can load PKCS#11 URLs in place of certificate or key files.
Applications using NSS
Applications linked with NSS, can specify PKCS#11 URLs to identify an object (not yet: https://bugzilla.mozilla.org/show_bug.cgi?id=1162897). They will however not load p11-kit-proxy module by default.