Scute is a component of the GnuPG cryptographic software suite. It provides a PKCS#11 interface to other GnuPG’s components, especially Scdaemon, the component that manages cryptographic tokens.
Scute allows PKCS#11-compatible applications, such as Mozilla Firefox (and more generally any application using Mozilla’s NSS library), to use a X.509 certificate backed up by a private key stored on a OpenPGP smartcard or a similar token.
The primary use case of Scute is TLS client authentication: that is, to allow a user to authenticate to a website using a token-based certificate. However, it can also be used to digitally sign PDF or OpenDocument documents, which is what I’ll describe here.
If you’re using GNU/Linux, Scute may be available in your distribution’s
package repository, typically under the (predictable) name
As of this writing, it is available at least in Debian and several
Debian-based distributions, in ArchLinux, and Gentoo.
If you’re using Mac OS, Scute is also available in the MacPorts tree.
On other systems, you may need to compile Scute from source. Make sure you
have build tools for your system, as well as the
libassuan libraries. On most Unix-like systems, building Scute
should then be straightforward with the usual process for autoconf-iscated
$ wget https://gnupg.org/ftp/gcrypt/scute/scute-1.7.0.tar.bz2 $ tar xf scute-1.7.0.tar.bz2 $ cd scute-1.7.0 $ ./configure $ make # make install-strip
No matter how you installed Scute, take note of where the actual library
scute.so on Unix-like systems,
Mac OS) ends up being located, you will need that later. In the rest of this
note, I will assume the library is at
Beyond Scute itself, you will need a functional GnuPG system, including the GpgSM component (needed to manipulate X.509 certificates), the GnuPG Agent (needed to access private keys), and Scdaemon (needed to access cryptographic tokens). If you have installed Scute using a package manager, those components will likely have been pulled automatically as run-time dependencies of Scute.
Once you have the required software on your machine, then you need the cryptographic token that Scute will use.
You may use any token that is supported by GnuPG’s Scdaemon. It can be an actual OpenPGP smartcard, or any token that can behave as an OpenPGP smartcard, such as a FST-01/GnuK, a Yubikey, a Nitrokey, etc.
If you have any interest in Scute at all, it is quite likely that you are already familiar with cryptographic tokens and even that your OpenPGP private keys are already stored on such a token. :) You may skip that entire section if that’s the case.
Check whether GnuPG can access your token. Make sure your token is plugged
in, then call
gpg --card-status (if you’re using GnuPG ≥ 2.3, you
may also use the new
$ gpg --card-status Reader ...........: 234B:0000:FSIJ-1.2.19-6879436D:0 Application ID ...: D276000124010200FFFE6879436D0000 Application type .: OpenPGP [...]
Then you need to generate a signing key (if you don’t already have one) and to load it on token.1 For now at least, it is recommended to stick to a RSA key, as other key types are less well supported by applications across the board.
In the rest of this note, we’ll use the following key:
$ gpg --edit-key alice Secret key is available. sec rsa2048/54B4CC7749CAE7C3 created: 2020-05-13 expires: never usage: SC trust: ultimate validity: ultimate ssb rsa2048/45EDD81BCE62E9BD created: 2020-05-13 expires: never usage: E ssb rsa2048/6D733C967F54A189 created: 2022-09-22 expires: never usage: S [ultimate] (1). Alice <firstname.lastname@example.org>
The signing subkey (
6D733C967F54A189) is the one we’ll
transfer to the token for use with Scute. Select it…
gpg> key 2 sec rsa2048/54B4CC7749CAE7C3 created: 2020-05-13 expires: never usage: SC trust: ultimate validity: ultimate ssb rsa2048/45EDD81BCE62E9BD created: 2020-05-13 expires: never usage: E ssb* rsa2048/6D733C967F54A189 created: 2022-09-22 expires: never usage: S [ultimate] (1). Alice <email@example.com>
… and send it to the token:
gpg> keytocard Signature key ....: [none] Encryption key ...: [none] Authentication key: [none] Please select where to store the key: (1) Signature key (3) Authentication key Your selection?
Store the key in the first slot (the signature slot).
sec rsa2048/54B4CC7749CAE7C3 created: 2020-05-13 expires: never usage: SC trust: ultimate validity: ultimate ssb rsa2048/45EDD81BCE62E9BD created: 2020-05-13 expires: never usage: E ssb* rsa2048/6D733C967F54A189 created: 2022-09-22 expires: never usage: S card-no: FFFE 6879436D [ultimate] (1). Alice <firstname.lastname@example.org>
card-no, which confirms that the private key is now
stored on the token with serial number
Save the modifications to the keyring (otherwise, the signing private
subkey, even after having been sent to the token, would still reside in the
GnuPG Agent’s store, in
$GNUPGHOME/private-keys-v1.d) and quit
the key editor:
The token is now ready (at least for signing; of course, while you’re at it, you may want to also move your encryption subkey to it, but this note is only about signatures). You may want to check that it is working as expected, by unplugging it and then trying to sign anything with GnuPG: you should be prompted to insert the token back and to unlock it with your PIN.
Now that we have a signing key on a cryptographic token, we need to obtain a X.509 certificate out of it. With the token plugged in, use GpgSM to generate a certificate signing request (CSR):
$ gpgsm --armor --output request.pem --gen-key Please select what kind of key you want: (1) RSA (2) Existing key (3) Existing key from card Your selection?
(3) Existing key from card, then select the signing key
you have just transferred to the token:
Serial number of the card: D276000124010200FFFE6879436D0000 Available keys: (1) 352393AF8BE1BE756418703681D0DC0D94DA6B1D OPENPGP.1 Your selection? 1
Then you need to fill in the details that will go into the certificate signing request, starting by what the certificate will be used for (this will be the value of the X509v3 Key Usage extension):
Possible actions for a RSA key: (1) sign, encrypt (2) sign (3) encrypt Your selection? 2
We want a certificate that can be used to emit digital signatures, so
Fill in the other details as you see fit:
Enter the X.509 subject name: CN=Alice,O=Example Corp,DC=example,DC=net Enter email addresses (end with an empty line): > email@example.com > Enter DNS names (optional; end with an empty line): > Enter URIs (optional; end with an empty line): > Create self-signed certificate? (y/N) N Parameters to be used for the certificate request: Key-Type: card:OPENPGP.1 Key-Length: 1024 Key-Usage: sign Name-DN: CN=Alice,O=Example Corp,DC=example,DC=net Name-Email: firstname.lastname@example.org Really create request? (y/N) y Now creating certificate request. This may take a while ... gpgsm: about to sign CSR for key: &352393AF8BE1BE756418703681D0DC0D94DA6B1D gpgsm: certificate request created Ready. You should now send this request to your CA.
The certificate signing request is now in
request.pem. Now, as
suggested by GpgSM, you need to get it signed by a certification authority
(CA) to obtain the desired certificate.
It’s up to you to choose which certification authority to send your request to (unless maybe this decision is forced upon you, for example by your employer), and every CA may have its own procedure to deliver the certificate, so I won’t cover that step here.2 What matters is that at the end, you should have your signed certificate as well as the certificate(s) of the CA that signed it.
Import your new certificate and the CA’s certificate into the GpgSM keyring:
$ gpgsm --import ca-certificate.pem $ gpgsm --import certificate.pem
Unplug your token and try using GpgSM to sign any file:
$ gpgsm --output test.signed --sign test.txt
You should be prompted to insert your token back in and to unlock it.
You are now ready to emit CMS signatures with your token-based X.509 certificate. Now let’s see how to do that with some common applications.
Many applications that can sign documents rely on Mozilla’s NSS library for the cryptographic operations. This makes things quite easy for us, because once you have configured one such application to use Scute, it’s basically done for all the other applications as well, as long as they use the same certificate database.
Here, before using any application, let’s first create a brand new NSS certificate database, that will be specifically intended for use with Scute:
$ mkdir ~/.local/share/scute-nss $ certutil -N -d ~/.local/share/scute-nss Enter a password which will be used to encrypt your keys. The password should be at least 8 characters long, and should contain at least one non-alphabetic character. Enter new password: Re-enter password:
Since the database will only be used with Scute, it will never actually contain any private key (our private signing key will remain on the cryptographic token), so it’s OK not to protect it with a password (by entering an empty one). You can choose to have a password, but then signing applications will have to ask for the password to open the database before they can even send any signing request to the token.
Import the certificate of your CA into the database. This is not strictly required for signing, but applications will also use that database to verify signatures, so having the CA certificate in there will ensure that your signatures can be verified and treated as valid.
$ certutil -A -i ca.pem -n TheCA -t ,T, -d ~/.local/share/scute-nss
Then add the Scute dynamic module to the database:3
$ modutile -add Scute -libfile /usr/local/lib/scute.so -db ~/.local/share/scute-nss WARNING: Performing this operation while the browser is running could cause corruption of your security databases. If the browser is currently running, you should exit browser before continuing this operation. Type ‘q <enter>’ to abort, or <enter> to continue: Module "Scute" added to database.
Insert your token if it was not already plugged in and list the available certificates in the database:
$ certutil -d ~/.local/share/scute-nss -L -h Scute Certificate Nickname Trust Attributes SSL,S/MIME,JAR/XPI TheCA ,c, FFFE 6879436D:DummyLabel u,u,u
Observe that your token-based certificate is there (under a nickname made
up from the serial number of your token). The
u trust attribute
indicates that the private key is available, as expected.
pdfsig console program is provided with the Poppler PDF library. Use it to
sign a PDF file as follows:
$ pdfsig -nssdir ~/.local/share/scute-nss -add-signature \ -nick "FFFE 6879436D:DummyLabel" file.pdf file-signed.pdf
Okular is the document viewer of the
KDE/Plasma desktop environment. To make it use the dedicated NSS database we
have just created, go to Settings > Configure Backends, and in
the PDF tab, set the “Custom Certificate Database” to the
~/.local/share/scute-nss directory, then restart the
Open a PDF file, and make sure your token is inserted.4 Then select Tools > Digitally Sign…. Okular creates visible signatures, so you need to manually draw a rectangle over your document where you want the signature to appear. You will be prompted to select the certificate to use (in our example there would be only one), then to enter your token’s PIN, and finally to choose where to save the signed document.
LibreOffice can use Scute to sign OpenDocument files or PDF files. The procedure is the same in both cases.
As for Okular, you need to instruct LibreOffice to use the dedicated NSS certificate database we have created. In LibreOffice’s Options window, go to the LibreOffice > Security and click on the Certificate… button to bring the Certificate Path dialog, where you can select a custom NSS path. Set the path to our database, then restart the application.
Open a document to sign, make sure your token is plugged in, then go to File > Digital Signature > Digital Signatures…. The Digital Signatures dialog list the current signatures (none if the document has never been signed). Click on the Sign Document… button, select your signing certificate, then enter your token’s PIN when prompted.
When signing OpenDocument files (instead of PDF files), you can choose between an OpenPGP signature and a X.509 signature – the OpenDocument format supports both, where the PDF format only supports X.509. The choice between the two is made when you select your signing certificate. If you select the OpenPGP certificate, then you don’t need Scute at all, LibreOffice will know how to use GnuPG directly.
JSignPdf is a Java application for signing PDF files. It doesn’t use NSS, but does support PKCS#11 modules all the same and therefore can use Scute – but it requires its own configuration.
After unpacking the JSignPdf archive, go to the
and edit the
conf.properties file. Feel free to explore that file
and tweak the parameters at your convenance, but the important thing to do if
you want to use Scute is to make sure the following line is uncommented:
Then edit the
pkcs11.cfg file so that it contains the
Then insert your token, and start the JSignPdf application using the
launcher script in the top-level directory (
PKCS11 as the Keystore type, then click on the Load
Keys button. JSignPdf will fetch the available signing certificates
from the token and list them in the Key alias menu. Then select the
PDF file to sign, and click on Sign it to proceed with the actual
JSignPdf has a lot of options that you can explore (especially if you enable the Advanced view). It allows to create both unvisible and visible signatures, and for the latter, it allows to customize almost every aspect of the generated signature.
If you’re using Mac OS on a M1-powered Apple machine, you must make sure
to use a Java virtual machine that is really targeting your architecture
(arm64), instead of a x86_64 JVM that is running under emulation. That is
libscute.dylib library, assuming you have
installed it through MacPorts, will be a arm64 library — a x86_64 virtual
machine would not be able to dynamically load such a library.
ywhen GpgSM asks you whether you want such a certificate. Then the file produced by GpgSM will be the certificate itself, ready to use.
You can add a comment by replying to this message on the Fediverse.