Preview: OpenPGP card-backed CAs

| September 24, 2022

Today, we want to share our excitement about the upcoming support for OpenPGP card-backed instances of OpenPGP CA, and take a look at how an OpenPGP card-backed CA instance will be operated.

OpenPGP CA has received support from the NLnet foundation during its initial development. Now we’re receiving a second round of support through the NGI Assure Fund, to add support for hardened modes of operation.

TL;DR

With the upcoming version of OpenPGP CA, initializing a CA that is backed by an OpenPGP card takes just one step. This step automatically generates a new CA key, uploads the key material to your card, and sets up the CA database (in a file named test.oca, here):

$ openpgp-ca -d test.oca ca init example.org card FFFE:01234567 on-host

This card-backed OpenPGP CA instance can be used in exactly the same ways as a soft-key backed CA. For example, you can import and certify a user’s key like this:

$ openpgp-ca -d test.oca user import --key-file alice.pub --email alice@example.org

Tell me more

Ok, that was easy. If you’d like to learn some more details, read on!

Setting up a new CA instance backed by an OpenPGP card

First, we initialize our CA instance. This means generating a new CA private key that we’ll keep on an OpenPGP card. We’ll store the corresponding CA public key as well as the card’s identity in the CA database.

In this article, we’re using a Free Software Gnuk OpenPGP card device. But any OpenPGP card device will work just fine, as long as it supports the cryptographic algorithm of your CA key.

Generating the CA key on the host machine

OpenPGP CA offers different modes of setting up a card-backed CA instance. For most use cases, we suggest ‘on-host’ CA key generation.

When setting up a CA for production use, this one-time ‘on-host’ card initialization step (which handles the CA private key material) is ideally performed on a separate, air-gapped machine, to keep the private key material as safe as possible.

$ openpgp-ca -d test.oca ca init example.org card FFFE:01234567 on-host
Generated new CA key:

-----BEGIN PGP PRIVATE KEY BLOCK-----
Comment: C49F 7907 5059 C1E4 C0E7  9EDE EDA8 8D1B 5CEA 12D5
Comment: OpenPGP CA <openpgp-ca@example.org>

xcZYBGMs5UoBEACkatc48boCCWnSHBlS7yElWYkYbghh1hjVvfjAYF6fOK4uzFSj
DFjHdY5eZV5/ebf4oZG8y7sjOP6X1ivLVAhVwP2fsiF90d0J6snbums8P+TvwBUj
[..]
QoJP/UkbCQ+FW7ClI9AdQ75eaXJsuhZCAq74i/hlWfJ3Yw==
=gPi4
-----END PGP PRIVATE KEY BLOCK-----

Initialized card-backed OpenPGP CA instance

    CA Domain: example.org
  Fingerprint: C49F79075059C1E4C0E79EDEEDA88D1B5CEA12D5
Creation time: 2022-09-23 08:44:26 UTC
   CA Backend: OpenPGP card FFFE:01234567 [User PIN 85643040]

In the ‘on-host’ initialization mode, the CA private key is generated locally on the computer that runs this command, using Sequoia PGP. The generated secret key is printed as part of the command output. You should store a copy of this private key in a secure manner. Note that the private key output is unencrypted.

The init command automatically set the card’s User PIN to a random 8-digit value, as seen in the last line of the output. This PIN is persisted in the OpenPGP CA database, so that the CA can operate without requiring user input. Depending on your threat model, you might consider turning on ’touch confirmation’ on your card, so that each signing operation with the CA key requires physical confirmation by the CA admin.

At this point, our OpenPGP card device contains the certification-capable CA private key. We can now bring the OpenPGP card and a copy of the CA database file test.oca to the internet-connected machine we will use to run our instance of OpenPGP CA.

Note that the CA database only contains the public key material for the CA, when backed by an OpenPGP card. This makes the CA database much less sensitive than a software-key-backed CA’s database (which contains the CA private key material).

Using our card-backed CA instance

Our new, card-backed, CA instance is now ready for use. We can perform all CA operations with it, as described in the OpenPGP CA admin documentation.

Let’s try this by certifying an identity on a newly generated key. We’ll centrally generate a key for a new user, Bobby, and certify its identity bob@example.org with our CA:

$ openpgp-ca -d test.oca user add -e bob@example.org -n "Bobby Tables"

[.. output of Bobby's new private key and password ..]

Let’s inspect the certification on Bobby’s public key, as stored in our CA instance:

$ openpgp-ca -d test.oca user export -e bob@example.org | sq inspect --certifications
[..]
         UserID: Bobby Tables <bob@example.org>
  Certification: Creation time: 2022-09-23 08:52:08 UTC
                 Alleged certifier: C49F79075059C1E4C0E79EDEEDA88D1B5CEA12D5
[..]

We see that Bobby’s User ID Bobby Tables <bob@example.org> has been certified by our OpenPGP CA instance (there is a certification by the CA's fingerprint C49F79075059C1E4C0E79EDEEDA88D1B5CEA12D5`).

Keeping the CA private key material safe

The main goal of running a CA instance backed by an OpenPGP card device is that the computer that runs the CA never has direct access to the CA private key material.

And indeed, this was the case in the workflow outlined above: the computer that runs our OpenPGP CA instance never had direct access to the CA private key material. (Only the computer we used for the card initialization step had access to the CA private key.)

While the certification of Bobby’s identity did use the CA private key material, the actual signing operation was performed on our Gnuk hardware device. The CA private key material is kept on that OpenPGP card device, separate from the host computer.

Variation: Generating the CA key on the card

Alternatively, the ‘on-card’ initialization mode can be used to set up a CA instance. This mode of operation generates a new CA private key directly on your OpenPGP card.

This has the advantage that it’s very easy to do, and no computer ever has access to the CA private key material.

On the other hand, this mode of operation has the disadvantage that you can’t make a second copy of the key material. So, if your OpenPGP card breaks, you lose access to that CA private key (if that happens, you’ll have to roll your CA over to a new CA key. Each user of your CA then needs to obtain a copy of the new CA key, and to make sure that the CA key they obtained is indeed legitimate).

Also, when generating a key on a hardware card, you rely on that card (including its method of obtaining randomness) to generate a strong key.

If these trade-offs are appropriate to your use-case, generating a CA key on an OpenPGP card is as easy as:

$ openpgp-ca -d test.oca ca init example.org card FFFE:01234567 on-card
Initialized card-backed OpenPGP CA instance:

    CA Domain: example.org
  Fingerprint: E28CF8D53763F763648E489D7ED924B756E24C40
Creation time: 2022-09-23 23:17:50 UTC
   CA Backend: OpenPGP card FFFE:01234567 [User PIN 78076756]

The resulting CA can be used in the usual ways, as shown above.


[This article was originally published on Sep 03rd 2022, and updated on Sep 24rd to reflect progress in OpenPGP CA development: initialization of card-based CAs is now decidedly more automated.]