Working with PGP Signatures

One of the requirements for publishing your artifacts to the Central Repository, is that they have been signed with PGP. GnuPG or GPG is a freely available implementation of the OpenPGP standard. GPG provides you with the capability to generate a signature, manage keys, and verify signatures. This page documents usage of GPG as it relates to the Central Repository. In a nutshell you will have to

  • create your own key pair
  • and distribute it to a key server so that users can validate it

Installing GnuPG

Download GPG from http://www.gnupg.org/download/ or install it with your favorite package manager and verify it by running a gpg command with the version flag.

$ gpg --version
gpg (GnuPG) 1.4.18
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: ~/.gnupg
Supported algorithms:
Pubkey: RSA, RSA-E, RSA-S, ELG-E, DSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: MD5, SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

Note that on some systems the newer gpg2 will be used:

$ gpg2 --version
gpg (GnuPG) 2.0.28
libgcrypt 1.6.3
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
...

Generating a Key Pair

A key pair allows you to sign artifacts with GPG and users can subsequently validate that artifacts have been signed by you. You can generate a key with

$ gpg --gen-key

Select the default value when asked for the kind (RSA) and the size (2048bit) of the key. The time of validity for the key defaults to never expire. However it is commonly suggested to use a value of less than 2 years. Once they key is expired you can extend it, provided you own the key and therefore know the passphrase.

As a next step you have to provide your name, email, and a comment for the key. These identifiers are essential as they will be seen by anyone downloading a software artifact and validating a signature. Finally, you can provide a passphrase to protect your secret key. It is essential that you choose a secure passphrase and that you do not divulge it to any one. This passphrase and your private key are all that is needed to sign artifacts with your signature.

Listing Keys

Once key pair is generated, we can list them along with any other keys installed:

$ gpg2 --list-keys

/home/juven/.gnupg/pubring.gpg
------------------------------
pub   1024D/C6EED57A 2010-01-13
uid                  Juven Xu (Juven Xu works at Sonatype) <juven@sonatype.com>
sub   2048g/D704745C 2010-01-13

The output displays the path to the public keyring file. The line starting with pub shows the length (1204D), the keyid (C6EED57A), and the creation date (2010-01-13) of the public key.

The next line shows the UID of the key, which is composed of a name, a comment, and an email. The last line shows sub-keys, we don’t need to worried about this for now.

To list the private keys you can use

$ gpg2 --list-secret-keys

/home/juven/.gnupg/secring.gpg
------------------------------
sec   1024D/C6EED57A 2010-01-13
uid                  Juven Xu (Juven Xu works at Sonatype)
ssb   2048g/D704745C 2010-01-13

The output is similar to the one provided for the public keys.

Signing a File

To create an ASCII formatted signature for any file, run the following gpg command:

$ gpg2 -ab temp.java

The -a option tells gpg to create ASCII armored output, the -b option tells gpg to make a detached signature. If your private key has a passphrase, you will be asked for it. Without a passphrase, all someone needs to forge an artifact signature is your private key. The passphrase is an extra level of protection.

GPG will create a file like temp.java.asc , which is the signature of temp.java . You will want to distribute it along with the main file so the other can verify the main file using your public key:

$ gpg2 --verify temp.java.asc

Distributing Your Public Key

Since other people need your public key to verify your files, you have to distribute your public key to a key server:

$ gpg2 --keyserver hkp://pool.sks-keyservers.net --send-keys C6EED57A

The --keyserver parameter identifies the target key server address and use --send-keys is the keyid of the key you want to distribute. You can get your keyid by listing the public keys. Once submitted to a key server, your public key will be synchronized to other key servers.

Now other people can import your public key from the key server to their local machines:

$ gpg2 --keyserver hkp://pool.sks-keyservers.net --recv-keys C6EED57A

Using Build Tools for Signing

Now that you have created and distributed your key, you can proceed to get the components automatically signed as part of your build. Depending on your build tool this setup will be different and you can find out more about these next steps in the specific sections:

Dealing with Expired Keys

When you generate your PGP key, you need to specify how long the key should be valid. After that period you can edit your existing key to extend it's valid time.

For example, I have a key pair which expires on 2012-02-27:

$ gpg2 --list-keys
/Users/juven/.gnupg/pubring.gpg
-------------------------------
pub   2048R/A6BAB25C 2011-08-31 [expires: 2012-02-27]
uid                  Juven Xu (for testing) <test@juvenxu.com>
sub   2048R/DD289F64 2011-08-31 [expires: 2011-02-27]

You can edit a key with the following command using the key id as parameter:

$ gpg2 --edit-key A6BAB25C
gpg (GnuPG/MacGPG2) 2.0.17; Copyright (C) 2011 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.

Secret key is available.

pub  2048R/A6BAB25C  created: 2011-08-31  expires: 2012-02-27  usage: SC
                     trust: ultimate      validity: ultimate
sub  2048R/DD289F64  created: 2011-08-31  expires: 2011-02-27  usage: E
(1). Juven Xu (for testing) <test@juvenxu.com>

There is only one key to edit, so I choose 1:

gpg> 1 
pub  2048R/A6BAB25C  created: 2011-08-31  expires: 2012-02-27  usage: SC
                     trust: ultimate      validity: ultimate
sub  2048R/DD289F64  created: 2011-08-31  expires: 2011-02-27  usage: E
(1)* Juven Xu (for testing) <test@juvenxu.com>

You will see the * after (1), which mean you've selected this key to edit. To edit the keys expiration time, enter the following command:

gpg> expire
Changing expiration time for the primary key.
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

Enter what you need, for example 10m (10 months), and confirm it. The last step about editing is saving it what you've done:

gpg> save

Now you can see your key's expires time is updated:

$ gpg2 --list-keys
pub   2048R/A6BAB25C 2011-08-31 [expires: 2012-06-26]
uid                  Juven Xu (for testing) &lt;test@juvenxu.com&gt;
sub   2048R/DD289F64 2011-08-31 [expires: 2011-02-27]

Finally, distribute your public key again:

$ gpg2 --keyserver hkp://pool.sks-keyservers.net --send-keys A6BAB25C

Delete a Sub Key

Some PGP tools generates sub keys and use them for signing by default, but to make Maven tools recognize the signature, you must use the primary key to sign your artifacts.

Some PGP tools by default generate a sub signing key and use it for signing instead of using the primary key. This is a problem if you use it to sign artifacts and deploy artifacts to the Central Repository, because Maven as well as Nexus Repository Manager can only verify against a primary key.

To fix this problem you have to delete the sub signing key so PGP will use the primary key for signing. To get an idea whether you have a sub signing key, run command below with your own key ID:

$ gpg2 --edit-key A6BAB25C
gpg (GnuPG/MacGPG2) 2.0.17; Copyright (C) 2011 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.

Secret key is available.

pub  2048R/A6BAB25C  created: 2011-08-31  expires: 2012-06-26  usage: SC
                     trust: ultimate      validity: ultimate
sub  2048R/DD289F64  created: 2011-08-31  expired: 2011-09-30  usage: E
sub  2048R/8738EC86  created: 2011-12-19  expires: 2012-06-16  usage: S
(1). Juven Xu (for testing) &lt;test@juvenxu.com&gt;

As you can see from above example, this key has 2 sub keys with ID DD289F64 and 8738EC86 . The output also shows the creation time and expiration time. What's important here is the usage of these keys. E stands for Encryption so sub key DD289F64 is used for encryption only, S stands for Signing so sub key 8738EC86 is used for Signing only.

If a primary key has a S sub key, it will use it for signing, otherwise itself will do signing job. So, in our example, we want to delete the sub key 8738EC86 .

First select the sub key we want to delete, since its index is 2 (indices starts with 0), we run command:

gpg> key 2
pub  2048R/A6BAB25C  created: 2011-08-31  expires: 2012-06-26  usage: SC
                     trust: ultimate      validity: ultimate
sub  2048R/DD289F64  created: 2011-08-31  expired: 2011-09-30  usage: E
sub* 2048R/8738EC86  created: 2011-12-19  expires: 2012-06-16  usage: S
[ultimate] (1). Juven Xu (for testing) &lt;test@juvenxu.com&gt;

As you can see from the output, the sub key 8738EC86 is marked with *. Now delete it:

gpg> delkey
Do you really want to delete this key? (y/N) y

pub  2048R/A6BAB25C  created: 2011-08-31  expires: 2012-06-26  usage: SC
                     trust: ultimate      validity: ultimate
sub  2048R/DD289F64  created: 2011-08-31  expired: 2011-09-30  usage: E
[ultimate] (1). Juven Xu (for testing) &lt;test@juvenxu.com&gt;

Tip

If you've already distributed your public key, it's better to revoke the sub signing key instead of deleting it, although either way you can make your primary key as the signing key. To revoke a sub key, use the revkey command instead of delkey.

Now that 8738EC86 is not listed any more, the final step is saving our change:

gpg> save

That's it! Now you can test the change by signing a file, and then verify it. The output should contain something like:

gpg: Signature made ************************* using *** key ID [YOUR-PRIMARY-KEY-ID]