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.
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 ASF 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
= key expires in n days w = key expires in n weeks m = key expires in n months 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)
" Real name:
Enter your name, email and comment:
Real name: Xxx Xxxxxxxxx Email address:
Comment: CODE SIGNING KEY You selected this USER-ID: "Xxx Xxxxxxxxx (CODE SIGNING KEY) " 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
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)
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)
" 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
= key expires in n days w = key expires in n weeks m = key expires in n months 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)
Quit the gpg shell; you now have a subkey.
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)
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)
" 4096-bit RSA key, ID nnnnnnnn, created yyyy-mm-dd Enter passphrase:
Enter a passphrase:
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.
if you find that you need to revoke your certificate, this blog post explains how.
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 (
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.
The armored representation of your public key should be uploaded to your home directory on
people.apache.org, and renamed as
.pgpkey. Make sure this is readable by all.
The armored representation of your public key should be uploaded to your
public_html home directory on
nnnnnnnn.asc. 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:
svn co https://svn.apache.org/repos/private/committers/info
Go to Apache FOAF-a-matic web page to generate the FOAF file text (we copy this text out in a minute):
In the box below, you should have a FOAF file, something like:
<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 publically exported public key
Finally, commit your changes.
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
id.apache.org and ensure that the finger print of your public key is correct.
It is strongly advised that the contributor attend a key signing party at an Apache event, in order that other Apache committers/members can in person verify their identity against the key. The process for this is described here and here.
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>
All edits are reviewed before going live, so feel free to do much more than fix typos or links. If you see a page that could benefit from an entire rewrite, we'd be thrilled to review it. Don't be surprised if we like it so much we ask you for help with other pages :)NOTICE: unless indicated otherwise on the pages in question, all editable content available from apache.org is presumed to be licensed under the Apache License (AL) version 2.0 and hence all submissions to apache.org treated as formal Contributions under the license terms.