In order that a contributor can make a release it is necessary for them to have generated a key and had that key recognized by other members of the Apache Software Foundation.
For further background information on this topic, see the release signing page and the openpgp page on the Apache wiki.
Install and Configure gpg
Download and install GnuPG (gpg), version 1.4.10 or higher.
~/.gnupg/gpg.conf (on Windows, the file to edit is
C:\Users\xxx\AppData\Roaming\gnupg\gpg.conf) so that the default is to generate a strong key:
personal-digest-preferences SHA512 cert-digest-algo SHA512 default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
The Apache Software Foundation requires that keys are signed with a key (or subkey) based on RSA 4096 bits. To do this:
$ gpg --gen-key gpg (GnuPG) 1.4.11; Copyright (C) 2010 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. Please select what kind of key you want: (1) RSA and RSA (default) (2) DSA and Elgamal (3) DSA (sign only) (4) RSA (sign only) Your selection?
Specify RSA key:
Your selection? 1 RSA keys may be between 1024 and 4096 bits long. What keysize do you want? (2048)
Specify key length as 4096 bits:
What keysize do you want? (2048) 4096 Requested keysize is 4096 bits 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)
Specify key as non-expiring:
Key is valid for? (0) 0 Key does not expire at all Is this correct? (y/N) y You need a user ID to identify your key; the software constructs the user ID from the Real Name, Comment and Email Address in this form: "Heinrich Heine (Der Dichter) <email@example.com>" Real name:
Enter your name, email and comment:
use your apache.org email
the comment should be "CODE SIGNING KEY"
Real name: Xxx Xxxxxxxxx Email address: firstname.lastname@example.org Comment: CODE SIGNING KEY You selected this USER-ID: "Xxx Xxxxxxxxx (CODE SIGNING KEY) email@example.com" Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O You need a Passphrase to protect your secret key. Enter passphrase:
Provide a passphrase to secure your key.
Enter passphrase: Repeat passphrase:
GPG will goes on to generate your key:
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 nnnnnnnn 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: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u pub 4096R/nnnnnnnn yyyy-mm-dd Key fingerprint = xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx uid Xxx Xxxxxx <firstname.lastname@example.org> sub 4096R/kkkkkkkk yyyy-mm-dd
The public key with id nnnnnnnn should now be stored in
~/.gnupg/pubring.pgp (on Windows 7, this is in
To confirm the key has been generated, use:
$ gpg --list-keys --fingerprint
The key Id is the one true way to identify the key, and is also the last 8 digits of the fingerprint.
The corresponding secret key for id
nnnnnnnn is stored in
~/.gnupg/secring.pgp (on Windows 7, this is in
It’s also worth confirming the key has the correct preference of algorithms (reflecting the initial configuration we did earlier). For this, enter the gpg shell for your new key:
$ gpg --edit-key nnnnnnnnn >gpg
nnnnnnnn is your key id.
Now, use the 'showpref' subcommand to list details:
gpg> showpref [ultimate] (1). Xxx Xxxxxxxx (CODE SIGNING KEY) <email@example.com> Cipher: AES256, AES192, AES, CAST5, 3DES Digest: SHA512, SHA384, SHA256, SHA224, SHA1 Compression: ZLIB, BZIP2, ZIP, Uncompressed Features: MDC, Keyserver no-modify gpg>
The Digest line should list SHA-512 first and SHA-1 last. If it doesn’t, use the "setpref" command:
setpref SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
Finally, remember to take a backup of your key and the keyring (ie, backup the
.gnupg directory and its contents).
It’s recommended to use a subkey with an expiry date to sign releases, rather than your main, non-expiring key. If a subkey is present, then gpg will use it for signing in preference to the main key.
After (binary) release artifacts are created, they are deployed to the ASF’s Nexus staging repository. However, Nexus seems unable to retrieve a subkey from the public key server. Until we find a fix/workaround for this, all releases should be signed just with a regular non-expiring main key.
To create a subkey Enter the gpg shell using (the identifier of) your main key:
gpg --edit-key xxxxxxxx gpg>
Type 'addkey' to create a subkey, and enter your passphrase for the main key:
gpg> addkey Key is protected. [enter your secret passphrase] You need a passphrase to unlock the secret key for user: "Dan Haywood (CODE SIGNING KEY) <firstname.lastname@example.org>" 4096-bit RSA key, ID xxxxxxxx, created 2011-02-01 Please select what kind of key you want: (3) DSA (sign only) (4) RSA (sign only) (5) Elgamal (encrypt only) (6) RSA (encrypt only) Your selection?
Select (6) to choose an RSA key for encryption:
It would seem that Nexus repository manager does not recognize RSA subkeys with an 'S’ign usage; see this discussion on a mailing list and this issue on Sonatype’s JIRA
Your selection? 6 RSA keys may be between 1024 and 4096 bits long. What keysize do you want? (2048) 4096 Requested keysize is 4096 bits 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?
Specify that the key is valid for 1 year:
Key is valid for? (0) 1y Key expires at yy/MM/dd hh:mm:ss Is this correct? (y/N) y Really create? (y/N) y 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. ...+++++ .+++++ pub 4096R/xxxxxxxx created: yyyy-mm-dd expires: never usage: SC trust: ultimate validity: ultimate sub 4096R/xxxxxxxx created: yyyy-mm-dd expires: yyYY-mm-dd usage: E [ultimate] (1). Dan Haywood (CODE SIGNING KEY) <email@example.com> gpg>
Quit the gpg shell; you now have a subkey.
Generate a Revocation Certificate
It’s good practice to generate a number of revocation certificates so that the key can be revoked if it happens to be compromised. See the gpg page on the Apache wiki for more background on this topic.
First, generate a "no reason specified" key:
$ gpg --output revoke-nnnnnnnn-0.asc --armor --gen-revoke nnnnnnnn sec 4096R/nnnnnnnn yyyy-mm-dd Xxx Xxxxxxx (CODE SIGNING KEY) <firstname.lastname@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?
Your decision? 0 Enter an optional description; end it with an empty line:
Provide a description:
> Generic certificate to revoke key, generated at time of key creation. > Reason for revocation: No reason specified Generic certificate to revoke key, generated at time of key creation. Is this okay? (y/N)
Confirm this is ok.
Is this okay? y You need a passphrase to unlock the secret key for user: "Xxx Xxxxxxx (CODE SIGNING KEY) <email@example.com>" 4096-bit RSA key, ID nnnnnnnn, created yyyy-mm-dd Enter passphrase: </pre> Enter a passphrase: <pre> Enter passphrase: Revocation certificate created. Please move it to a medium which you can hide away; if Mallory gets access to this certificate he can use it to make your key unusable. It is smart to print this certificate and store it away, just in case your media become unreadable. But have some caution: The print system of your machine might store the data and make it available to others!
revoke-nnnnnnnn-0.asc should be created: Then, backup this file.
Now repeat the process to create two further revocation certificates:
gpg --output revoke-nnnnnnnn-1.asc --armor --gen-revoke nnnnnnnn
Specify reason as "1 = Key has been compromised"
gpg --output revoke-nnnnnnnn-3.asc --armor --gen-revoke nnnnnnnn
Specify reason as "3 = Key is no longer used"
Backup these files also.
It is also necessary to publish your key. There are several places where this should be done. In most cases, you’ll need the “armored” (ie ASCII) representation of your key. This can be generated using:
$ gpg --armor --export nnnnnnnn > nnnnnnnn.asc
nnnnnnnn is the id of your public key.
You’ll also need the fingerprint of your key. This can be generated using:
$ gpg --fingerprint nnnnnnnn
The output from this command includes a line beginning "Key fingerprint", followed by a (space delimited) 40 character hexadecimal fingerprint.
The last 8 characters should be the same as the key id (
Publish to a public key server
To a publish your key to a public key server (eg the MIT key server hosted at http://pgp.mit.edu), use the procedure below. Public key servers synchronize with each other, so publishing to one key server should be sufficient. For background reading on this, see the release signing page on the Apache wiki, and the gpg key page on the Maven wiki.
To send the key up to the key server:
$ gpg --send-keys --keyserver pgp.mit.edu nnnnnnnn
nnnnnnnn is the key Id.
Alternatively, you can browse to the MIT key server and paste in the armored representation of your key.
Confirm the key has been added by browsing to submitting the following URL:
nnnnnnnn is the key Id.
Publish to your Apache home directory
The armored representation of your public key should be uploaded to your home directory on
people.apache.org, and renamed as
Make sure this is readable by all.
Publish to your Apache HTML home directory
The armored representation of your public key should be uploaded to your
public_html home directory on
Make sure this is readable by all.
Check the file is accessible by browsing to:
xxxxxxxxis your apache LDAP user name
nnnnnnnnis your public key id.
First, check out the committers/info directory:
Go to Apache FOAF-a-matic web page to generate the FOAF file text (we copy this text out in a minute):
enter ASF LDAP user name
enter First name, Last name
for PGP key fingerprints, add Key
paste in the key id
paste in the fingerprint
In the box below, you should have a FOAF file, something like:
<?xml version="1.0" encoding="UTF-8"?> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:pm="http://www.web-semantics.org/ns/pm#" xmlns:wot="http://xmlns.com/wot/0.1/" xmlns:rss="http://purl.org/rss/1.0/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:ical="http://www.w3.org/2002/12/cal/ical#" xmlns:doap="http://usefulinc.com/ns/doap#"> <foaf:Person rdf:ID="danhaywood"> <foaf:name>Xxx Xxxxxxxx</foaf:name> <foaf:givenname>Xxx</foaf:givenname> <foaf:family_name>Xxxxxxxx</foaf:family_name> <wot:hasKey> <wot:PubKey> <wot:fingerprint>nnnn nnnn nnnn nnnn nnnn nnnn nnnn nnnn nnnn nnnn</wot:fingerprint> <wot:hex_id>nnnnnnnn</wot:hex_id> </wot:PubKey> </wot:hasKey> </foaf:Person> </rdf:RDF>
(If you are creating the FOAF file for the first time, you may want to add additional details).
From this, copy out the
wot:key, and paste into your FDF file in
<wot:hasKey> <wot:PubKey> <wot:fingerprint>nnnn nnnn nnnn nnnn nnnn nnnn nnnn nnnn nnnn nnnn</wot:fingerprint> <wot:hex_id>nnnnnnnn</wot:hex_id> </wot:PubKey> </wot:hasKey>
Then, manually add in a
<wot:pubkeyAddress> element within
<wot:hasKey> <wot:PubKey> <wot:fingerprint>nnnn nnnn nnnn nnnn nnnn nnnn nnnn nnnn nnnn nnnn</wot:fingerprint> <wot:hex_id>nnnnnnnn</wot:hex_id> <wot:pubkeyAddress rdf:resource="http://people.apache.org/~username/nnnnnnnn.asc/"/> </wot:PubKey> </wot:hasKey>
ie, referencing your publicly exported public key
Finally, commit your changes.
The armored representation of the public key should be saved to Apache Isis'
KEYS file, http://www.apache.org/dist/isis/KEYS (that is, in the ASF distribution directory for Apache Isis).
First, in a new directory, checkout this file:
svn -N co https://svn.apache.org/repos/asf/isis/ .
This should bring down the
Then, export your signature and armored representation.
gpg --list-sigs nnnnnnnn >>KEYS gpg --armor --export nnnnnnnn >>KEYS
Attend Key Signing Party (Apache web of trust)
Update Maven Settings file (
The Maven release plugin will automatically sign the release, however it is necessary to update the
~/.m2/settings.xml file with your GPG acronym passphrase in order that it can use your secret key.
This is defined under a profile so that it is activated only when we perform a release (as defined by
[org,apache:apache] parent POM.
Therefore, make the following edits:
<settings> ... <profiles> <profile> <id>apache-release</id> <properties> <gpg.passphrase>xxx xxx xxx xxx xxx xxx xxx</gpg.passphrase> </properties> </profile> </profiles> </settings>
In addition, to allow the release plugin to tag SVN changes, you must either add in your LDAP username/password or configure
<settings> ... <servers> ... <server> <id>apache.releases.https</id> <username>xxxx</username> <password>xxxx</password> </server> </servers> </settings>