Signing RPMs using the Nitrokey hardware security module (HSM)
The CloudRouter project takes security very seriously. Cryptographic signatures are used to ensure the integrity of the software we distribute. CloudRouter 1.0 beta is a Fedora Remix. Most packages are provided by the Fedora repositories. For details on how these packages are signed, see the Fedora documentation. Additional packages such as OpenDaylight are provided by the CloudRouter repositories. These packages are signed using the CloudRouter Project key.
In order to ensure maximum security for our community, we are using a dedicated signing server with a hardware security module (HSM) that is not connected to the Internet. This drastically reduces the risk of a remote attacker compromising the CloudRouter Project key and attempting to sign malicious packages as legitimate components.
Selecting a HSM
A huge variety of HSMs are available. We went with Nitrokey as it had several key benefits:
- Completely open source, including hardware
- Low cost
- Standard USB interface
- Successfully used by mozilla for a similar use-case
Installing the HSM
Nitrokey provides great installation documentation, but it is Debian-specific, and we’re using Fedora. On Fedora 21 or RHEL/CentOS 7, the following steps are required to install the Nitrokey:
- # yum install -y libusb
- Copy 40-nitrokey.rules to /etc/udev/rules.d/
- # udevadm control –reload
At this point the system is able to communicate with the Nitrokey device. To complete installation we need to upgrade to the latest firmware package. Upgrading firmware is clearly documented by Nitrokey. There is one gotcha – Nitrokey App’s graphical interface is based on a QT system tray widget. If you are using a non-KDE Linux desktop environment that does not support system tray widgets, then you may be unable to access the graphical interface. On Fedora 21, we had to temporarily switch from GNOME to KDE to make it work.
Preparing the key
Preparing the key is straightforward, but we ran into two limitations of Nitrokey that took some time to figure out. First, Nitrokey does not yet consistently support keys greater than 2048 bits in length. Second, making an off-card backup of the encryption key would consistently fail. With those constraints in mind, here is the process we used to generate the actual CloudRouter Project key:
$ gpg2 --card-edit gpg/card> admin Admin commands are allowed gpg/card> generate Make off-card backup of encryption key? (Y/n) n gpg: NOTE: keys are already stored on the card! Replace existing keys? (y/N) y What keysize do you want for the Signature key? (2048) What keysize do you want for the Encryption key? (2048) What keysize do you want for the Authentication key? (2048) Please specify how long the key should be valid. 0 = key does not expire <n> = key expires in n days <n>w = key expires in n weeks <n>m = key expires in n months <n>y = key expires in n years Key is valid for? (0) Key does not expire at all Is this correct? (y/N) y GnuPG needs to construct a user ID to identify your key. Real name: CloudRouter Project Email address: security@cloudrouter.org Comment: You selected this USER-ID: "CloudRouter Project <security@cloudrouter.org>" Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? o gpg: key 191F16B0 marked as ultimately trusted public and secret key created and signed. gpg: checking the trustdb gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model gpg: depth: 0 valid: 4 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 4u pub 2048R/191F16B0 2015-02-10 Key fingerprint = 0FE8 73A5 A682 EFB1 8B05 D8B6 0A1E 8B12 191F 16B0 uid [ultimate] CloudRouter Project <security@cloudrouter.org> sub 2048R/85F05C49 2015-02-10 sub 2048R/9EE6A049 2015-02-10
Signing packages
The CloudRouter Project maintains a dedicated signing server that is not connected to the internet. To ensure that the HSM-based key is used, the following line is added to ~/.rpmmacros on the signing server:
%_gpg_name CloudRouter Project <security@cloudrouter.org>
Signing can then be performed using the command:
$ rpm --resign <package>.rpm
GPG is invoked and asks for a pass phase for the key:
Enter pass phrase:
Since we’re using a HSM, this is actually asking for the device PIN. As we continue to enhance our build infrastructure, we aim to completely automate this process. Mozilla have developed an automatic PIN entry tool that we intend to use. Stay tuned for more details as our build infrastructure moves forward!