Deep Dive: Using Okular to Digitally Sign PDFs

Bottom Line; Up Front

Digitally signing a PDF is a simple task; however, properly configuring Okular to sign documents can be challenging for new users.

Background

The inspiration for this post comes from a Linus Tech Tips video[1]. The video is part three of a four part series where Linus and Luke use desktop Linux as their daily driver. In this video they were trying to accomplish a variety of day-to-day tasks using a Linux desktop. I think, for the most part, the list of tasks were good tests of the difficulty in using desktop Linux in a home or office environment. Installing a new font was one challenge that seemed out of place. I wouldn’t call that a common task unless one was working with design or desktop publishing on a daily basis; otherwise, I think the challenge was fair. Adding a font didn’t matter in the end because Linus breezed through that challenge. He ran into the most trouble trying to digitally sign a PDF.

After settling into my new daily driver I decided to revisit the Linux Daily Driver Challenge series. I wanted to compare my experience to that of Linus and Luke and see if there were common threads. There was. I ran into the same problem as Linus when trying to digitally sign a PDF. I tried Evince first since it is the default document viewer for Gnome[2], my desktop environment of choice. It is light and fast and it can annotate, but not digitally sign, documents. Linus used Manjaro during the challenge, which installs KDE Plasma[3] as the default desktop environment, so I installed Okular[4], the default KDE document viewer. Okular is full-featured and comes with, in true KDE form, a lot of options, including an option to digitally sign PDFs. I hit the jackpot, or so I thought. I loaded up a PDF, clicked tools, then digitally sign. I drew a rectangle to insert a signature field, then I was greeted with a message from Okular:

There are no available signing certificates

Linus ran into the same thing. Clicking the “Adding Digital Signatures”[5] link brings up the corresponding documentation. The second paragraph under “Adding Digital Signatures” is where the rabbit hole begins:

“To be able to sign a document you need to have a proper PKCS signing certificate available on your system. Okular does not have the ability to create such certificates since they need to be issued by certificate authorities to be useful for validation, etc.”

Linux doesn’t come with a default PKCS[6] signing certificate, nor do macOS or Windows; and with good reason.

A digital signature isn’t simply a digital representation of a hand-written signature. It is cryptographically signed and verified by a third party to provide assurance the entity signing the document is who they say they are.

Deep Dive Into Digital Signatures

Rather than provide yet another copy and paste tutorial I want to first dive deeper into digital signatures. Click here to jump to the tutorial section of the post. Otherwise, continue reading to learn more about what goes into creating a digital signature, and how they work.

Not All Signatures Are Created Equally

A quick web search for “sign pdf linux”[7] or “digitally sign pdf linux”[8] returns a mix of results that usually fall into two categories: signing with an electronic signature or with a digital signature. There is a distinct difference between the two and the terms should not be interchanged, but often are. So, what is the difference between the two types of signatures?

Electronic, or E-Signatures (Logical)

An electronic, or e-signature is a logical representation of a hand-written, or “wet” signature. It can be a scanned copy of a hand-written signature, a typed name, a freehand drawing of a signature, or clicking a check in a box marked “I Agree.” Most electronic signatures do not require any form of identity verification, but advanced (AES) and qualified (QES) signatures include extra steps to verify the identity of the signatory. Anyone who uses a service like DocuSign is using an electronic signature. In the video Luke used Sejda PDF Desktop[9] to electronically sign a PDF. He generated an electronic (logical) representation of his handwritten signature and pasted it into a document. Technically he didn’t digitally sign the PDF, but that’s being pedantic. I think it’s safe to assume that either an electronic or digitally signature met the requirements of the challenge.

Down a Cryptographic Rabbit Hole

Compared to electronic signatures, digital signatures are more complex. They go beyond logical representations of hand-written signatures and provide a mechanism for validating the authenticity of the signatory and the integrity of the signed data. Digital signatures provide these validation mechanisms using public key cryptography.[10] and public key infrastructure[11] and it helps to understand both when working with digital signatures.

Public Key Cryptography

Public key, or asymmetric, cryptography is a cryptographic system that uses pairs of keys. Each keypair includes a public key (which may be known to others) and a private key (which must be known only by the owner). In this system anyone can encrypt data using the recipient’s public key, but only the recipient may decrypt the data with their private key. A sender can also encrypt a hash of the data with a private key to produce a digital signature. Anyone with the sender’s corresponding public key can verify the authenticity and integrity of the message using the digital signature. In order for the system to work public keys must be exchanged between individuals. In-person or other out-of-band methods[12] may work on a small scale, but for larger, web-scale environments public key infrastructure is necessary.

Public Key Infrastructure, Certificate Authorities, and Trusted Roots

Covering the full breadth and depth of public key infrastructure (PKI) is well beyond the scope of this post, and not necessary to understand the part it plays in digital signatures. I will cover what I believe to be the parts most pertinant to digital signatures.

A PKI is composed of the roles, policies, hardware, software, and processes necessary to issue, manage, use, store, and revoke digital certificates and manage public-key encryption. PKI provides trust services. These services assure the actions or outputs of entities; whether people or computers, respect one or more of the following capabilities: confidentiality, integrity, or authenticity.

In a PKI the certificate authority (CA) is the entity responsible for issuing digital certificates. A CA can be private to an organization, or public such as Let’s Encrypt[13]. Adobe maintains a list[[14]]](#14) of public CAs and trust service providers (TSP) who issue digital signing certificates. Certificates may also be issued and self-signed by an individual. Signing can be an automated or human-supervised process. The act of signing by the CA affirms the certificate belongs to the entity in the subject field of the certificate. It also creates what is known as a trust chain.

A trust chain has a head and a tail. At the head is the CA, or root, certificate self-signed by the CA. It is also known as a trusted root. The tail is the leaf, or client certificate. The leaf could be a server certificate used to secure browser sessions, or a document signing certificate. Often found between the head and tail are one or more intermediate certificates. Intermediate certificates are issued by trusted CAs to subordinate certificate providers giving them authority to issue client, or end-entity, certificates. The purpose of intermediate certificates is to reduce exposure of the trusted root CA private keys. If the private key corresponding to an intermediate certificate is exposed it only affects certificates issued by the intermediate rather than the trusted root and its entire trust chain. It is also less costly in terms of time and money to become a subordinate CA and issue intermediate certificates signed by a trusted root[15].

Most operating systems and web browsers come pre-installed with the trusted root public certificates for the established public CAs. When a client connects to a secure website, or tries to validate the signature on a document, it checks the entire certificate chain starting with the leaf certificate, followed by any intermediate certificates, and ending with the trusted root certificate. If any link in the chain fails to validate, the client presents the user with a warning. Warnings appear for expired certificates, certificates not matching the requested hostname or signature, and certificates signed by an unknown CA among other reasons[16]. Many people ignore these warnings, but they shouldn’t. Their intent is to protect users from malicious sites, or from accepting documents that were altered in transit. The trust chain helps prevent forgeries. That is why CAs and TSPs undergo extensive audits, and also why we don’t all use self-signed certificates to sign and encrypt data.

Digital Signatures (Cryptographic)

I mentioned earlier that digital signatures are created using private keys to encrypt a hash value of some data. What is a hash and how does it relate to digital signatures?

A hash is a fixed-length digest of arbitrary length data. Two common hash functions are SHA256 and SHA512. They produce hashes that are 256 and 512 bits in length respectively, even for files multiple gigabytes in size. The hash function output is collision resistant, meaning it is very difficult to produce the same hash from different inputs. Distribution of the digest can be a weakness in this model. If the digest is sent with the data, and it is intercepted and modified by a third party in transit, there would be no way to detect the tampering. To prevent man-in-the middle attacks the sender encrypts the digest with their private key producing a digital signature. The recipient decrypts the digest using the sender’s public key. If the digest calculated from the received data matches the decrypted digest, the signature is valid.

In summary, a digital signature is the hash value from the original data encrypted with a private key and digital signatures provide a way to validate both authenticity and integrity of a message, file, or other data. It took time to get to this point, but I feel explaining the technology underlying digital signatures is necessary to understand some of the challenges presented when using them with Okular. Thus ends the rabbit hole.

Configuring Okular

It’s time to configure Okular to sign PDFs. I use default installations of Manjaro Linux[17] and Slackware 15[18], both running as virtual machines with the KDE Plasma desktop, to demonstrate configuring Okular and signing and validating documents. Manjaro is used to sign and Slackware to validate unless noted otherwise.

Setting Up Local PKI

The infrastructure necessary for signing PDFs does not exist by default, so next sections explain how using an existing certificate, with self-signed certificates, or with a certificate signed by a CA.

Self-Signed Certificate

There is no shortage of tutorials for creating self-signed certificates on the web[19], and most focus on OpenSSL[20]. Okular looks for signing certificates in the current user’s Firefox certificate store if it exists, falling back to the system-wide store in /etc/pki/nssdb, and finally the user certificate store at ~/.pki/nssdb if the first two cannot be found. These certificate stores are managed using certutil, part of Network Security Services (NSS)[21] from Mozilla. I use the ~/.pki/nssdb in these examples, but you can use any NSS-compatible certificate database.

Create The Directory

The first step is to create the directory if it does not exist.

mkdir -p ~/.pki/nssdb

Initialize a New Certificate Database

The database must be initialized before adding certificates:

certutil -N -d ~/.pki/nssdb

-N tells certutil to create a new database and the location specified by -d.

This command will prompt to set a password and the complexity requirements are rather weak, but the usual password recommendations apply. Use something complex with letters, numbers, and special characters or a passphrase, and use a unique password. I recommend storing the password in a password manager like BitWarden[22] or KeePassXC[23].

Issue a Self-Signed Certificate

Next up is creating a self-signed certificate. This command line will introduce a few new arguments for which brief descriptions follow. Completing this step also establishes a new, private CA.

certutil -S -d ~/.pki/nssdb -s "CN=Example Signing Certificate;OU=Example Certificate Authority;O=Example Organization;L=City;ST=State;C=US" -t ",,C,C" -n "Example Signing Certificate" -x

  • -S - Create a new certificate and add it to the database
  • -s - The subject of the certificate formatted according to RFC 1485[24]
  • -t - Trust arguments. Comma separated attributes that determine for which uses the certificate is trusted in order of SSL, e-mail, or object signing. In this example we only care about e-mail and object-signing so the first field is left blank. A self-signed certificate is also a CA certificate, so we assign trust arguments commensurate with a trusted authority.
  • -n - A friendly name for the certificate.
  • -x - Create a self-signed certificate. Without this option certutil expects the -c argument and the issuer certificate identifier.

I recommend reading RFC 1485 to understand subject syntax. Attribute order matters and there are character restrictions on the attributes.

Confirm Creation Of The Certificate and Private Key

The -L argument lists all certificates in the database. -K does the same for keys are requires a password.

certutil -L -d ~/.pki/nssdb

certutil -L -d ~/.pki/nssdb

certutil -K -d ~/.pki/nssdb

certutil -K -d ~/.pki/nssdb

Importing an Existing Certificate and Private Key

Importing an existing key pair is slightly more involved. certutil can easily import a certificate, but it does not have a similar function to import a certificate. To do so one must use a separate tool: pk12util. As its name suggests, pk12util expects to receive a PKCS#12[25] bundle as input. I use openssl to create PKCS#12 bundles with an easy one-liner:

openssl pkcs12 -export -in foo.crt -inkey foo.key -out foo.p12

I use .p12 as the file extension for PKCS#12 bundles. Some people use .pfx. On Linux, the extension is arbitrary. Use whatever you like.

Importing the bundle is also simple and quick:

pk12util -d ~/.pki/nssdb -i foo.p12

Creating a Certificate Signing Request (CSR) for Signing By a Third Party CA

Self-signed certificates, or certificates issued by private CAs are fine if used within an organization or a small group of people who trust one another, but if signed documents will be exchanged between entities and third party verification is required, a certificate should be signed by a public CA. The web[26] has countless tutorials covering the process. Briefly, a certificate signing request is generated from a private key and sent to the CA for signing. The CA then verifies the identity of the entity requesting a certificate. Verification requirements vary from confirming ownership of a domain to providing legal documents demonstrating legal ownership or residence. Generally the more thorough the verification, the higher the cost of the signed certificate. Upon completion of verification, the CA issues a certificate to the requestor valid for a duration of 90 days or as long as two years. The process must be repeated upon expiration or software will consider the certificate no longer valid. That said, creating a certificate signing request with certutil is similar to creating a self-signed certificate:

certutil -R -d ~/.pki/nssdb -s "CN=Example Signing Certificate;OU=Example Certificate Authority;O=Example Organization;L=City;ST=State;C=US" -n "Example Signing Certificate" -a -o example-signing-cert.csr

A couple new command line arguments are introduced here:

  • -R - Create a certificate signing request (CSR)
  • -a - Output the CSR in ASCII format
  • -o - Direct the output to a file, otherwise the default is stdout

After the certificate is issued, it must be imported into the database:

certutil -A -d ~/.pki/nssdb -n "Example Signed Certificate" -t ",,P,P" -a -i example-signing-cert.crt

The above command assumes the certificate file example-signing-cert.crt is in PEM[27] format, which is an ASCII format (hence the -a). Some CAs use a binary format known as DER[28]. In the case of the latter, the -a argument may be omitted.

A couple new arguments are introduced here as well:

  • -A - Add a certificate to the database.
  • -i - Name of the file containing the certificate to import.
  • `-t “,,P,P” - The certificate will be used for signing so we mark it as a trusted peer for e-mail and object signing.

The CA root certificate, and all intermediate certificates, must be imported as well. Use something like the following to import a CA certificate:

certutil -A -d ~/.pki/nssdb -n "CA Root Certificate" -t "C,C,C" -a -i ca-root-certificate.crt

We "C,C,C" trustargs because the certificate belongs to a trusted certificate authority.

Intermediate certificates may be imported using a lower level of trust:

certutil -A -d ~/.pki/nssdb -n "Intermediate CA Certificate" -t ",," -a -i intermediate-ca-certificate.crt

I recommend spending time with the certutil man page (man certutil), along with all of the NSS tools man pages, to learn the full scope of their capabilities.

Configure Okular

Most of the terminal work is complete and now it is time to configure Okular to sign PDFs. It is a quick, four step process:

  1. Click on the “Settings” menu in Okular, then click on “Configure Backends…”
  2. Click “PDF” on the backends menu.
  3. If the default certificate database is ~/.pki/nssdb click on “OK”, otherwise enter ~/.pki/nssdb in the “Custom” field, then click “OK”.
  4. Restart Okular to apply the change.

That’s it! Okular is ready to sign PDFs.

Sign a PDF

Signing a PDF is a five step process, but is also very easy:

  1. Load a PDF into Okular. Any PDF will do.
  2. Click the “Tools” menu and select “Digitally Sign…”
  3. Draw a rectangle on the PDF where you want the signature placed.
  4. Enter the certificate store password if prompted, then select your signing certificate to sign the document.
  5. Save the signed document to a new file.

Validating the Digital Signature

Validating the digital signature is important. A valid signature assures the recipient no modifications were made to the document in transit and the sender is who they claim. I used three tools to validate the signature on my example PDF:

  1. LibreOffice Writer[29]
  2. pdfsig, part of Poppler[30], in a terminal (Konsole[31])
  3. Okular

LibreOffice displayed a warning at the top of the window when I loaded the document. Clicking through “Show Signatures” brought me to a dialog to view the certificate. The certificate could not be validated, a result I expected.

LibreOffice Writer cannot validate the signing certificate

pdfsig gave similar output in the terminal.

pdfsig: Certificate issuer is unknown

Finally, Okular validated the cryptography, but apparently not the certificate.

The signature is cryptographically valid.

This led me down a rabbit hole. I checked the signature on two other systems, a Mandriva Linux[32] VM and a laptop running Pop!_OS[33], and saw the same results. Further digging brought me to a KDE bug report[34] posted in late November 2021. I think this is a regression, or an unimplemented feature, in Okular because pdfsig, which shares the same PDF rendering library, validates the signature properly. I was surprised by this because the screenshots in the Okular documentation suggest otherwise. I plan to look at the source code and follow the bug report. I doubt I’ll be able to offer a fix, but I want to make sure I have a clear understanding of the problem. That’s a nice benefit of open source software. Anyone can review it and offer contributions and, in some cases, it is a source of documentation.

Wrapping Up

Digitally signing PDFs with Okular isn’t hard, especially once the certificates and keys are in the right place. Creating or installing the certificate takes the user away from Okular, but that’s unavoidable unless the developers want to implement those features; a balancing act shared by both commerical and open source software developers. I think the user experience would improve if Okular validated both the cryptopgrahic integrity and the certificate authenticity without needing other tools. I’m sure it will change eventually, but today an extra step is necessary.

I think Linus made the right decision giving up on signing the PDF. He was clearly frustrated by searches not returning the results he wanted. Had he continued he might have found the commands he needed, but I think it would have taken far longer than 15 minutes to complete, and led him down a rabbit hole to more frustration. I likely would have shared his frustration trying to accomplish the same task if I was a new Linux user, too.

When I started researching this post I knew I wanted to do more than write another tutorial. I was already familiar with creating self-signed certificates, converting them to various formats, and importing them into other tools, but I think I took the details for granted. I didn’t really understand what happened when data is digitally signed, and I wanted to clarify that process for myself and others. I also wanted to make it clear why a self-signed certificate may check a box, and help someone complete a task, but in the broader scope of PKI that isn’t a good solution. I wanted to explain that protecting data from prying eyes is only one part of encryption. Verifying data integrity and the authenticity of who encrypted the data is equally, if not more, important. I think I succeeded in that goal.

External Links

  1. Trying to do Simple Tasks on Linux lol - Daily Driver Challenge Pt.3
  2. GNOME - Simple, beautiful, elegant
  3. KDE Plasma
  4. Okular: The Universal Document Viewer
  5. Signatures
  6. Definition: PKCS
  7. DuckDuckGo Search: sign pdf linux
  8. DuckDuckGo Search: digitally sign pdf linux
  9. Sejda PDF Desktop
  10. Public Key Cryptography
  11. Public Key Infrastructure
  12. Definition: Out-of-band
  13. Let’s Encrypt
  14. Adobe Approved Trust List Members
  15. How to Become a Certificate Authority (Public vs Private)
  16. What do the security warning codes mean?
  17. Manjaro Linux
  18. Slackware 15
  19. DuckDuckGo Search: how to create self signed certificates linux
  20. OpenSSL
  21. Network Security Services (NSS)
  22. BitWarden
  23. KeePassXC
  24. A String Representation of Distinguished Names
  25. PKCS #12: Personal Information Exchange Syntax v1.1
  26. DuckDuckGo Search: how to request an ssl certificate
  27. Textual Encodings of PKIX, PKCS, and CMS Structures
  28. Use of the RSASSA-PSS Signature Algorithm in Cryptographic Message Syntax (CMS)
  29. LibreOffice Writer
  30. Poppler
  31. Konsole
  32. Linux Development - Mandriva Linux
  33. Pop!_OS by System76
  34. PDF signature certificate chain validation