Setting up your own OpenPGP keyserver (why & how)

Hi gang,

I know this turned into a somewhat extensive tutorial with plenty of dry theory. You can skip to the second part which will solely focus on the technical aspects (security/pks). If you didn't notice already: I'm a big fan of GnuPG / OpenPGP so yeah... ;)

(brief) PGP history

Around 1997 Phil Zimmerman took the world by storm when he released his Pretty Good Privacy ("PGP") software. It literally took the community by storm, where the whole thing became legendary when Phil discovered a loophole in the US encryption export regulation. Although it is not permitted for a US citizen (or company) to export (strong) encryption models from the US it was allowed to use these within literature. Books. And so Zimmerman faxed the source code of his program to Europe after which we soon got 2 PGP versions: the "classic" and PGPi ('international') which provided stronger encryption schemes.

OpenPGP / GnuPG ('GPG')

A lot happened and eventually Zimmerman sold the rights for PGP to Symantec which, obviously, quickly tried to monetize the whole thing. Which, in my opinion, was basically the beginning of the end for PGP. Although you could still get the commandline versions for free (more or less) the more popular native Window versions (which provided a GUI for easier usage) were now provided as commercial software.

However... Soon the OpenPGP working group was formed which pushed for setting up a standard based on PGP. Thus RFC4880 was created, and much open source projects have been using this standard, amongst which GnuPG.

So what is this PGP / GPG / OpenPGP all about?

Encryption. As well as identity management, file / data signing and even authentication. So basically providing users with relatively easy access to strong encryption methods and more. OpenPGP is fully based on the so called public key principle. Meaning so much that users create a keypair: a public and private key. The public key can be shared as much as possible thus allowing others to use this key, for example to encrypt data. Data which is encrypted using a public key can then only be decrypted using the associated private key.

Of course there's more. It is also possible to create signatures. Signing is done using a private key and the signature validity can then be checked against the associated public key. You can think of a signature as some kind of CRC checksum, where the main difference is that instead of relying on an hash algorithm such as MD5 you're utilizing a public-key cryptosystem such as RSA.

(public) Key management

The public key principle allows you to more or less rule out a man in the middle attack. By sharing my public key I can provide you with a way to send me something in private. After all: only my private key will be able to decrypt something which was encrypted using my public key. But how can you be sure that a certain public key you're looking at is actually mine?

Fingerprints. First there's a key ID. Mine being AEA05348. But an ID can only get you so far, and so there's also a fingerprint available. Call it a CRC checksum for the key ;) An example of such a fingerprint could be: D1ED0FB32918FD44870794656B252E09AEA05348 (which, you might have guessed, is also mine). So all that's left to do to fully establish my identity is to exchange such information (ID's and fingerprints) through (more) secure channels (a phone call, SMS message, instant messaging, a forum PM, etc.).

But this doesn't address another problem: how to easily obtain my public key. Sure, I could simply dump it into this message (or as an attachment, which I did) but then you could have quite a hassle on your hands. What if you're currently using a desktop computer yet want to use this public key on your FreeBSD server for verification purposes? Maybe SSH / PuTTY can help you out (pscp.exe for example) but surely we can do better?

This is where the OpenPGP public keyservers come into play, the most commonly used being Keyservers provide us with an easy way to utilize the HKP protocol (based on HTTP) to upload, query and retrieve specific public keys. So far, so good. All it takes is a (partial) name or key-id and GPG (or a graphical frontend such as Kleopatra) can do the rest.

But there is a problem... What is uploaded to a keyserver usually remains on that keyserver. Forever. Try looking up A key generated in 2005, revoked, yet still available. Sometimes that is simply unwanted behavior.

Or... what to think about using company keys on a public keyserver? All it takes is one "smart" end user who decides to look up an admin's name or e-mail address on said keyserver and before you know you'll get 1st line support questions in your 3rd line support mailbox. That's no good...

The solution? Simple: set up your own (private) keyserver. The FreeBSD ports collection provides an easy way to do this with security/pks which I'll explain in the next part.


  • shelluser.txt
    1.7 KB · Views: 813
Setting up your private keyserver

Installing security/pks is very easy, all it takes is a mere # make -C /usr/ports/security/pks install clean. The only configurable option is to specify whether to include the documentation or not. The port relies on both GCC as well as BerkelyDB so it's nothing too extensive.

After the port is installed you'll have access to an example configuration file (/usr/local/etc/pksd.conf.sample) which you'll need to copy to pksd.conf and edit accordingly. When I first looked through the example configuration I felt a bit overwhelmed because of the lack of formatting. All options are basically all put together in one huge block of text, and that can make the configuration process a little daunting at first. Or... so it might seem.

Fortunately things are really quite easy. Remember: when in doubt then you can always check the pksd.conf(8) manualpage.

The four section config

The configuration file basically consists of four sections. Please note that this is nothing official, this is simply something I made up, but I think that following this logic makes it much easier to keep an overview of the configuration file: configuration, operation, location, and misc. Where the latter section contains options which could be part of any of the previous three, but I think they won't be too commonly used. As such: miscellaneous.

1 - Configuration

Configuration, or main configuration, are the options which directly affect the way your keyserver will function. These include the used HTTP port (11371 by default), whether or not you want to allow key additions using the HTTP protocol and it also includes options to set up a dedicated userid.

# Main configuration
www_port 11371
www_readonly 0
pksd_uid 1050
pksd_gid 1050
default_language EN
#maintainer_email GPG Key Server Administrator <dontreply@mydomain.lan>
#mail_delivery_client /usr/sbin/sendmail -t -oi -fmailer-daemon
I think the options mostly speak for themselves. You can set the port which the program should use, specify if it should allow read/write or read-only operations and you get to specify the userid. Please note that security/pks does not create an account for you, you'll have to do this yourself. But that's nothing which adduser(8) can't handle.

The mail_delivery_client option (as well as maintainer_email) are only useful if you also plan on using e-mail requests. My server only uses network connections so I kept both options commented out.

2 - Operation

# Operation
max_last 0
max_reply_keys -1
max_last_reply_keys -1
Nothing too extensive here: these options control how the server should react to incoming requests, both through e-mail and network. max_last is only used in response to e-mail requests. It allows a remote client to request sending of all the recently added keys. Setting it to 0 disables the option, -1 allows any argument by the client and you can also set it to a positive integer to indicate how many days back the request can go.

max_reply_keys and max_last_reply_keys are used to set the maximum number of keys to return in a query. Either through the last command or a regular query. Setting these to a positive integer will place a restriction in effect, setting them to -1 allows clients to retrieve any number of keys they want.

3 - Directory settings

# Directory settings
pid_dir /var/run/pks
db_dir /var/db/pks/db
www_dir /var/db/pks
pks_bin_dir /usr/local/bin
mail_dir /var/db/pks/incoming
socket_name /var/run/pks/pks.socket
help_dir /usr/local/share/doc/pks
mail_intro_file /usr/local/share/pks/mail_intro
By default the security/pks port will set up the /var/pks directory in which most data files will be stored. The default location of the database for example is /var/pks/db. However... When it comes to security software then I don't like using default values. Think about it: if you stick to the default then you're basically giving a possible attacker an immediate small advantage.

Of course, within that reasoning I did something just as bad above: I used a directory which should be a pretty obvious second choice when the first doesn't work. Anyway, I prefer datafiles to be kept in /var/db and so that's what I've set up on my system. I think these options speak for themselves.

Note that pksd does not try to access a mailserver or anything. If you want to provide access through e-mail then you'll need to make sure that new e-mail messages get stored in the directory specified with the mail_dir option. You may need to use a specific mail delivery system, I personally prefer mail/procmail for this. Also: don't let the mail_dir option name fool you: this doesn't indicate a mail storage in Maildir format, simply the directory where individual e-mail messages get stored in order to be processed.

4 - Miscellaneous options

These options are purely optional, you won't need to use them in order to run your own keyserver. However, it might be useful to know of their existence. Because I don't use these myself I won't go into too much detail here, please see the pksd.conf(8) manualpage or the default configuration file (/usr/local/etc/pksd.conf.sample).

# syncsite pgp-public-keys@pgp-server-1
# chroot_dir /usr/local
chroot_dir should speak for itself; you can set up a dedicated directory from which to run pksd, just like most other programs which natively provide the chroot functionality. Syncsite can be used if you run multiple keyserver and you need to synchronize these.

Setting up the configuration file

So now that we got the 4 sections sorted out you're ready to set up your own configuration file. You can literally copy all three (or four sections) to /usr/local/etc/pksd.conf, optionally making some changes, and then you'll be done. It really is that simple.

Setting up the database

If you follow my examples then your database directory will reside in /var/db/pks/db, however; there won't be anything there by default. pksd doesn't create an empty database, nor does the port itself. You will need to do that manually using pksclient(8). The functionality of this program is limited (the same applies to pksdctl) but it gets the job done.

To set up your database you'll need to use: pksclient /var/db/pks/db create. You can optionally specify the number of files in which to split the key database, and you can also specify a database type. However, I personally recommend to simply use the defaults. Hopefully needless to say but if you're using another directory to contain your database then you will need to specify that instead.

If you're using a dedicated user account for the PKS server then make sure that the ID has write access to the database directory and all its individual files.

And done!

And that's basically all you need configuration wise. If you decide to use the default location for the configuration file (/usr/local/etc/pksd.conf) then all you have to add to /etc/rc.conf is pksd_enable to actually enable the daemon to start. You can also chose to use different paths, in that case pksd_config can be used to specify your custom location for the main configuration file.

Optional: change your GnuPG skeleton configuration

When a user on your server starts GPG for the first time then the program will create the .gnupg directory in their home directory and copy the default configuration over. Since you now got your own keyserver, why don't you make sure that all users will access this keyserver by default?

The skeleton configuration file for security/gnupg1 is located here: /usr/local/share/gnupg1/options.skel. It's a text file which can be easily edited. Simply find this section:

# Most users just set the name and type of their preferred keyserver.
# Note that most servers (with the notable exception of
# ldap:// synchronize changes with each other.  Note
# also that a single server name may actually point to multiple
# servers via DNS round-robin.  hkp:// is an example of
# such a "server", which spreads the load over a number of physical
# servers.  To see the IP address of the server actually used, you may use
# the "--keyserver-options debug".

#keyserver hkp://
#keyserver ldap://
And add your own (uncommented) keyserver to the end of the list using the hkp:// specification. This will ensure that all new GnuPG users will access your keyserver by default. And don't let the name fool you. Although I also use a (local) domain name to point to my keyserver (hkp://pks.intranet.lan/) you can also easily use an IP address here. So if all you want is use the server to provide easier GPG key access for all your users then simply use something like hkp:// and you're done.

I personally also prefer setting the auto-key-retrieve keyserver option, this ensures that any required keys get automatically fetched. For example: when my local user account checks a signature from the root account then the public key will be retrieved if it wasn't already part of my keyring.

And there you have it!

Why and how to set up your own private keyserver. I hope this can help some of you out.

first of all, a huge thank you for this post.
Im wondering if there is any solution to sign all and/or a specific key directly on the keyserver?
(My users are very lazy when it comes to things like signing a new key)
Im wondering if there is any solution to sign all and/or a specific key directly on the keyserver?
Sort off. You can't really mess with the database directly, but you can list all keys (and their ID's) and then use those.

For example: # pksclient ~pks/db index keys a | grep pub | cut -d " " -f3 | cut -d "/" -f2, this would list all keyid's currently in the database (note: I've set up the homedirectory for pks myself).

You could then use that to download the key, sign it, and upload it again. For example....

for a in `pksclient /var/db/pks/db index keys a 2>/dev/null | grep pub | cut -d " " -f3 | cut -d "/" -f2`; do
        gpg --recv-keys $a;
        gpg --sign-key $a;
        gpg --send-keys $a;
This should do the trick.

Of course I don't recommend doing this because it somewhat defeats the purpose, and depending on the used settings it also remains to be seen if one signature would make a big difference. Even so, this is how I'd do it.