Skip to content

GPG

One of the requirements for publishing your artifacts to the Central Repository, is that they have been signed with PGP. GnuPG (aka 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 the binary of GnuPG from https//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) 2.2.19
libgcrypt 1.8.5
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <https://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: /home/mylocaluser/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

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

Enter your name and email when asked for it and also, the time of validity for the key defaults to 2 years. Once they key is expired you can extend it, provided you own the key and therefore know the passphrase.

$ gpg --gen-key
gpg (GnuPG) 2.2.19; Copyright (C) 2019 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.

Note: Use "gpg --full-generate-key" for a full featured key generation dialog.

GnuPG needs to construct a user ID to identify your key.

Real name: Central Repo Test
Email address: central@example.com
You selected this USER-ID:
    "Central Repo Test <central@example.com>"

Change (N)ame, (E)mail, or (O)kay/(Q)uit? O
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
gpg: key 8190C4130ABA0F98 marked as ultimately trusted
gpg: revocation certificate stored as
'/home/mylocaluser/.gnupg/openpgp-revocs.d/CA925CD6C9E8D064FF05B4728190C4130ABA0F98.rev'
public and secret key created and signed.

pub   rsa3072 2021-06-23 [SC] [expires: 2023-06-23]
      CA925CD6C9E8D064FF05B4728190C4130ABA0F98
uid                      Central Repo Test <central@example.com>
sub   rsa3072 2021-06-23 [E] [expires: 2023-06-23]

You have to provide your name and email. 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:

$ gpg --list-keys
/home/mylocaluser/.gnupg/pubring.kbx
---------------------------------
pub   rsa3072 2021-06-23 [SC] [expires: 2023-06-23]
      CA925CD6C9E8D064FF05B4728190C4130ABA0F98
uid           [ultimate] Central Repo Test <central@example.com>
sub   rsa3072 2021-06-23 [E] [expires: 2023-06-23]

The output displays the path to the public keyring file. The line starting with pub shows the size (rsa3072), the keyid (CA925CD6C9E8D064FF05B4728190C4130ABA0F98), and the creation date (2023-06-23) of the public key. Some values may vary depending on your GnuPG version, but you will definitely see the keyid or part of it (called shortID, last 8 characters of the keyid, in this example 0ABA0F98, which you can ask gpg to output using gpg --list-keys --keyid-format short).

The next line shows the UID of the key, which is composed of a name, a comment, and an email.

Hint

In case you have multiple keys, the local gpg will use the first listed signature key (gpg --list-signatures) for any publishing steps, if you need to use a specific key you could add the details of the gpg key inside a <configuration> section in your pom.xml and use local settings.xml to discover the passphrase via the signature keyname. You may need to use the signature keyid in hexadecimal format:

$ gpg --list-signatures --keyid-format 0xshort
/home/mylocaluser/.gnupg/pubring.kbx
---------------------------------
pub   rsa3072/0x3ABDEC12 2021-01-27 [SC] [expires: 2023-01-27]
      74524542545300A398653AB5242798823ABDEC12
uid           [ultimate] Other Name <otheremail@example.com>
sig 3        0x3ABDEC12 2021-01-27  Other Name <alarconj@gmail.com>
sub   rsa3072 2021-01-27 [E] [expires: 2023-01-27]
sig          0x3ABDEC12 2021-01-27  Julian Alarcon <alarconj@gmail.com>

pub   rsa3072/0x0ABA0F98 2021-06-23 [SC] [expires: 2022-03-21]
      CA925CD6C9E8D064FF05B4728190C4130ABA0F98
uid           [ultimate] Central Repo Test <central@example.com>
sig 3        0x0ABA0F98 2021-06-24  Central Repo Test <central@example.com>
sub   rsa3072/0x7C17C93B 2021-06-23 [E] [expires: 2023-06-23]
sig          0x0ABA0F98 2021-06-23  Central Repo Test <central@example.com>

You will find in the line that starts with sig 3 that 0x3ABDEC12 is the signature keyid that you can use in your pom.xml.

Signing a File⚓︎

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

gpg -ab myfile.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 recommended protection.

GPG will create a file like temp.java.asc, which is the signature of myfile.java.

You will want to distribute it along with the main file so the other can verify the main file using your public key:

$ gpg --verify myfile.java.asc 
gpg: assuming signed data in 'myfile.java'
gpg: Signature made mié 23 jun 2021 16:06:54 -05
gpg:                using RSA key CA925CD6C9E8D064FF05B4728190C4130ABA0F98
gpg: Good signature from "Central Repo Test <central@example.com>" [ultimate]

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:

gpg --keyserver keyserver.ubuntu.com --send-keys CA925CD6C9E8D064FF05B4728190C4130ABA0F98

Important

As SKS Keyserver Network is being deprecated we recommend the use an specific GPG keyserver. Current GPG Keyservers supported by Central Servers are:

  • keyserver.ubuntu.com
  • keys.openpgp.org
  • pgp.mit.edu

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.

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

gpg --keyserver keyserver.ubuntu.com --recv-keys CA925CD6C9E8D064FF05B4728190C4130ABA0F98

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 its valid time.

For example, this is key pair which expires on 2023-06-23:

$ gpg --list-keys
/Users/mylocaluser/.gnupg/pubring.gpg
-------------------------------
pub   rsa3072 2021-06-23 [SC] [expires: 2023-06-23]
      CA925CD6C9E8D064FF05B4728190C4130ABA0F98
uid           [ultimate] Central Repo Test <central@example.com>
sub   rsa3072 2021-06-23 [E] [expires: 2023-06-23]

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

$ gpg --edit-key CA925CD6C9E8D064FF05B4728190C4130ABA0F98
gpg (GnuPG) 2.2.19; Copyright (C) 2019 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.

sec  rsa3072/8190C4130ABA0F98
     created: 2021-06-23  expires: 2023-06-23  usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa3072/4656B4857C17C93B
     created: 2021-06-23  expires: 2023-06-23  usage: E   
[ultimate] (1). Central Repo Test <central@example.com>

gpg>

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

gpg> 1

sec  rsa3072/8190C4130ABA0F98
     created: 2021-06-23  expires: 2023-06-23  usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa3072/4656B4857C17C93B
     created: 2021-06-23  expires: 2023-06-23  usage: E   
[ultimate] (1)* Central Repo Test <central@example.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
Key is valid for? (0) 

Enter what you need, for example 9m (9 months), and confirm it. You will be asked for the passphrase of that key. 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:

$ gpg --list-keys
/home/mylocaluser/.gnupg/pubring.kbx
---------------------------------
pub   rsa3072 2021-06-23 [SC] [expires: 2022-03-21]
      CA925CD6C9E8D064FF05B4728190C4130ABA0F98
uid           [ultimate] Central Repo Test <central@example.com>
sub   rsa3072 2021-06-23 [E] [expires: 2023-06-23]

Finally, distribute your public key again:

gpg --keyserver keyserver.ubuntu.com --send-keys CA925CD6C9E8D064FF05B4728190C4130ABA0F98

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.

Sub keys are a problem if you use them to sign and deploy artifacts to the Central Repository, because Maven and 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 the command below with your own key ID:

$ gpg --edit-key CA925CD6C9E8D064FF05B4728190C4130ABA0F98
gpg (GnuPG) 2.2.19; Copyright (C) 2019 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.

sec  rsa3072/8190C4130ABA0F98
     created: 2021-06-23  expires: 2022-03-21  usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa3072/4656B4857C17C93B
     created: 2021-06-23  expires: 2023-06-23  usage: E   
ssb  rsa3072/01265B6DAB6DEA96
     created: 2021-06-24  expires: never       usage: S   
[ultimate] (1). Central Repo Test <central@example.com>

As you can see from above example, this key has 2 sub keys with ID 4656B4857C17C93B and 01265B6DAB6DEA96 . 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 4656B4857C17C93B is used for encryption only, S stands for Signing so sub key 01265B6DAB6DEA96 is used for Signing only.

If a primary key has a S sub key it will use the sub key for signing rather than the primary key. So, in our example, we want to delete the sub key 01265B6DAB6DEA96.

First select the sub key to delete (since indices start with 0 its index is 2) and run the command:

gpg> key 2

sec  rsa3072/8190C4130ABA0F98
     created: 2021-06-23  expires: 2022-03-21  usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa3072/4656B4857C17C93B
     created: 2021-06-23  expires: 2023-06-23  usage: E   
ssb* rsa3072/01265B6DAB6DEA96
     created: 2021-06-24  expires: never       usage: S   
[ultimate] (1). Central Repo Test <central@example.com>

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

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

sec  rsa3072/8190C4130ABA0F98
     created: 2021-06-23  expires: 2022-03-21  usage: SC  
     trust: ultimate      validity: ultimate
ssb  rsa3072/4656B4857C17C93B
     created: 2021-06-23  expires: 2023-06-23  usage: E   
[ultimate] (1). Central Repo Test <central@example.com>

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 01265B6DAB6DEA96 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 *************************
gpg:                using RSA key [YOUR-PRIMARY-KEY-ID]