The typical approach for managing user keys with OpenPGP CA is that users create their own keys and supply their public key to the OpenPGP CA admin.
We call this workflow “decentralized key creation”, because OpenPGP keys do not get created centrally, but decentrally, by each individual user.
Importing user generated keys into OpenPGP CA involves setting up certifications between the CA key and the new user key.
This workflow gives users full control over their own keys. In particular, the OpenPGP CA admin never has access to the user’s private key material.
However, with the current generation of PGP tools, this workflow is more complicated to perform than centralized user key creation.
(The following steps assume that you’ve initialized a CA by following either “Initializing a CA instance” or “The OpenPGP card backend”)
Step 1: Key creation on user’s machine
On the user’s machine, we’re going to generate a new OpenPGP key.
We’re using GnuPG in this example. Other OpenPGP software will have a similar workflow, but details will differ.
Setting up a GnuPG test environment
For testing purposes, we create a separate test environment. Using GnuPG, this can be done as follows:
$ export GNUPGHOME=$(mktemp -d)
$ chmod 0700 $GNUPGHOME
Create a new key for the user
We create a new key for Alice:
$ gpg --quick-generate-key "Alice Adams <alice@example.org>"
gpg: keybox '/tmp/tmp.LSAJszDQLR/pubring.kbx' created
About to create a key for:
"alice@example.org"
Continue? (Y/n)
[...]
public and secret key created and signed.
pub rsa3072 2020-07-02 [SC] [expires: 2022-07-02]
A0A61C7554B3316009C8D3C74FBA1B7EF003F9FA
uid alice@example.org
sub rsa3072 2020-07-02 [E]
Then we export the public part of this key into the file alice.pub
:
$ gpg --export --armor alice@example.org > alice.pub
Optionally generate revocation certificate(s)
If we want the OpenPGP CA admin to be able to revoke Alice’s key, then we need to create revocation certificates. We can generate and store multiple revocation certificates for different scenarios - the individual revocation certificates will show different reasons why a revocation was performed.
We’ll generate three variants here: “Key has been compromised”, “Key is superseded” and “Key is no longer used”.
$ gpg --gen-revoke alice@example.org > alice-revocation-compromised.asc
sec rsa3072/4FBA1B7EF003F9FA 2020-07-02 alice@example.org
Create a revocation certificate for this key? (y/N) y
Please select the reason for the revocation:
0 = No reason specified
1 = Key has been compromised
2 = Key is superseded
3 = Key is no longer used
Q = Cancel
(Probably you want to select 1 here)
Your decision? 1
Enter an optional description; end it with an empty line:
>
Reason for revocation: Key has been compromised
(No description given)
Is this okay? (y/N) y
ASCII armored output forced.
Revocation certificate created.
$ gpg --gen-revoke alice@example.org > alice-revocation-superseded.asc
As above, but using 2
when queried for the “reason” for revocation.
$ gpg --gen-revoke alice@example.org > alice-revocation-nolongerused.asc
As above, but using 3
when queried for the “reason” for revocation.
These revocations cover the typical situations, but they all have the current timestamp. When the user’s key needs to be revoked in the future, we can use the one that shows the appropriate reason. However, the time of revocation will be shown as the time when the revocation certificates were generated.
In the centralized key creation workflow, OpenPGP CA can generate and store hundreds of revocation certificates, showing different revocation times, so when a revocation of that user’s key becomes necessary, the OpenPGP CA admin can use the most suitable revocation certificate, both in terms of the reason for revocation, as well as the time of revocation.
Making the OpenPGP CA key a trusted introducer
Now, as the user, we’re going to mark the OpenPGP CA key as trusted introducer. This means that the user trusts the CA to authenticate keys on their behalf (this is expected in OpenPGP CA).
First, we import the OpenPGP CA’s public key (see Initializing a CA instance):
$ gpg --import openpgp-ca.pub
gpg: key A29FE591ABEF048D: public key "OpenPGP CA <openpgp-ca@example.org>" imported
gpg: Total number processed: 1
gpg: imported: 1
Transporting the OpenPGP CA public key to the user doesn’t require any confidentiality. Any medium is fine (email, a USB key, …). However, the user must verify after import that the key has the expected fingerprint:
$ gpg --fingerprint openpgp-ca@example.org
pub ed25519 2020-07-02 [C]
D3D2 EC7B 5C19 C304 3456 0A00 A29F E591 ABEF 048D
uid [ unknown] OpenPGP CA <openpgp-ca@example.org>
sub ed25519 2020-07-02 [S]
In this example, we imported a key with the fingerprint
D3D2 EC7B 5C19 C304 3456 0A00 A29F E591 ABEF 048D
. This information needs
to be compared against a trustworthy source for that fingerprint. The user
might call their OpenPGP CA admin on the phone, or they might have received a
printout of the fingerprint in a trustworthy manner.
After comparing the complete fingerprint against a trusted source, we’re sure we have the correct key for OpenPGP CA. So we mark the key as a trusted introducer. To do this, we create a trust signature:
$ gpg --edit-key openpgp-ca@example.org
Enter tsign
, 2
, 250
, no domain (just hit Enter
), y
, save
:
gpg (GnuPG) 2.2.12; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
pub ed25519/A29FE591ABEF048D
created: 2020-07-02 expires: never usage: C
trust: unknown validity: unknown
sub ed25519/59C433434D284F57
created: 2020-07-02 expires: never usage: S
[ unknown] (1). OpenPGP CA <openpgp-ca@example.org>
gpg> tsign
pub ed25519/A29FE591ABEF048D
created: 2020-07-02 expires: never usage: C
trust: unknown validity: unknown
Primary key fingerprint: D3D2 EC7B 5C19 C304 3456 0A00 A29F E591 ABEF 048D
OpenPGP CA <openpgp-ca@example.org>
Please decide how far you trust this user to correctly verify other users' keys
(by looking at passports, checking fingerprints from different sources, etc.)
1 = I trust marginally
2 = I trust fully
Your selection? 2
Please enter the depth of this trust signature.
A depth greater than 1 allows the key you are signing to make
trust signatures on your behalf.
Your selection? 250
Please enter a domain to restrict this signature, or enter for none.
Your selection?
Are you sure that you want to sign this key with your
key "alice@example.org" (4FBA1B7EF003F9FA)
Really sign? (y/N) y
gpg> save
Export the CA’s public key
The user now exports the OpenPGP CA key, which now contains the trust signature:
$ gpg --export --armor openpgp-ca@example.org > ca-tsigned.pub
Step 2: OpenPGP CA admin imports the newly created user key
The user transfers ca-tsigned.pub
, alice.pub
- and optionally any
revocation certificates - to the CA admin.
The CA admin then imports all of Alice’s artifacts into the OpenPGP CA database:
$ oca -d example.oca user import --name "Alice Adams" --email alice@example.org --key-file alice.pub --revocation-file alice-revocation-compromised.asc --revocation-file alice-revocation-superseded.asc --revocation-file alice-revocation-nolongerused.asc
$ oca -d example.oca ca import-tsig ca-tsigned.pub
Export Alice’s public key (including the certification by the CA)
When we imported Alice’s public key, OpenPGP CA automatically signed the key. Now, we might want to export her key including that certification and publish it somewhere, so that her key can be integrated into the WoT:
$ oca -d example.oca user export --email alice@example.org
-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: A0A6 1C75 54B3 3160 09C8 D3C7 4FBA 1B7E F003 F9FA
Comment: alice@example.org
xsDNBF7+RLIBDADBl0vzO2JHnFUbazounaSjWN/qKzHM964L3N/8q/B8ZNj19J5f
1eaRu15ssZQcf/nVIYxjX4ZbRQIhsSCCd+wBcBVoEV4/AsoIslfF2xxFDmWLg5Ve
[...]
qsLY89yDDmBOiMipsHEe+PLIRivmQhgIHfPb7AD4g3dbNiOUWsD7bhi4IR8Whz8P
Al1QBfoy5sLFO0rIlxsXGeJSw+rxRt9Wau4=
=9gNp
-----END PGP PUBLIC KEY BLOCK-----
In most cases, we will want to publish an updated wkd export of our OpenPGP CA instance on our WKD server. This way, clients can automatically receive Alice’s key complete with the certification by OpenPGP CA.
Check OpenPGP CA’s user list
To see the resulting state in OpenPGP CA, we can inspect the user list
:
$ oca -d example.oca user list
OpenPGP key for 'Alice Adams'
fingerprint A0A61C7554B3316009C8D3C74FBA1B7EF003F9FA
user cert (or subkey) signed by CA: true
user cert has tsigned CA: true
- email alice@example.org
expires: 02/07/2022
3 revocation certificate(s) available
This should show that Alice’s key has been signed by the CA and that Alice has generated a trust signature over the CA public key
The next chapter shows more examples of inspecting the contents of the OpenPGP CA database.
Importing an updated version of a user’s key
For user keys that are already managed in OpenPGP CA, you can import updated versions (e.g. with an extended expiration date):
$ oca -d example.oca user update --key-file alice.pub
The information of the old and new versions of the key will be automatically merged (that is, no information will get lost in this process).