[[key-generation]]
= Key Generation

:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR  CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
:page-partial:






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 http://www.apache.org/dev/release-signing.html[release signing page] and the http://www.apache.org/dev/openpgp.html#generate-key[openpgp page] on the Apache wiki.

== Install and Configure gpg

Download and install GnuPG (gpg), version 1.4.10 or higher.

Then, edit `~/.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:

[source,bash]
----
personal-digest-preferences SHA512
cert-digest-algo SHA512
default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
----

== Key Generation

The Apache Software Foundation requires that keys are signed with a key (or subkey) based on RSA 4096 bits.
To do this:

[source]
----
$ 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:

[source]
----
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:

[source]
----
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:

[source]
----
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) <heinrichh@duesseldorf.de>"

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: xxx@apache.org
Comment: CODE SIGNING KEY
You selected this USER-ID:
 "Xxx Xxxxxxxxx (CODE SIGNING KEY) xxx@apache.org"

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.

[source]
----
Enter passphrase:
Repeat passphrase:
----

GPG will goes on to generate your key:

[source]
----
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 <xxx@apache.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 `c:/Users/xxx/AppData/Roaming/gnupg/pubring.pgp`).

To confirm the key has been generated, use:

[source]
----
$ 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 `c:/Users/xxx/AppData/Roaming/gnupg/secring.pgp`).

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:

[source]
----
$ gpg --edit-key nnnnnnnnn
>gpg
----

where `nnnnnnnn` is your key id.
Now, use the 'showpref' subcommand to list details:

[source]
----
gpg> showpref
[ultimate] (1). Xxx Xxxxxxxx (CODE SIGNING KEY) <xxx@apache.org>
     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:

[source]
----
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).

== Subkey Generation

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.

[NOTE]
====
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:

[source]
----
gpg --edit-key xxxxxxxx
gpg>
----

Type 'addkey' to create a subkey, and enter your passphrase for the main key:

[source]
----
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) <danhaywood@apache.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:

[NOTE]
====
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
====

[source]
----
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:

[source]
----
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) <danhaywood@apache.org>

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 http://www.apache.org/dev/openpgp.html#revocation-certs[gpg page] on the Apache wiki for more background on this topic.

First, generate a "no reason specified" key:

[source]
----
$ gpg --output revoke-nnnnnnnn-0.asc --armor --gen-revoke nnnnnnnn

sec  4096R/nnnnnnnn yyyy-mm-dd Xxx Xxxxxxx (CODE SIGNING KEY) <xx@apache.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?
----

Select 0.

[source]
----
Your decision? 0

Enter an optional description; end it with an empty line:
----

Provide a description:

[source]
----
> 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.

[source]
----
Is this okay? y

You need a passphrase to unlock the secret key for
user: "Xxx Xxxxxxx (CODE SIGNING KEY) <xxx@apache.org>"
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!
----

The file `revoke-nnnnnnnn-0.asc` should be created: Then, backup this file.

Now repeat the process to create two further revocation certificates:

[source,bash]
----
gpg --output revoke-nnnnnnnn-1.asc --armor --gen-revoke nnnnnnnn
----

Specify reason as "1 = Key has been compromised"

and:

[source,bash]
----
gpg --output revoke-nnnnnnnn-3.asc --armor --gen-revoke nnnnnnnn
----

Specify reason as "3 = Key is no longer used"

Backup these files also.

== Publish Key

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:

[source]
----
$ gpg --armor --export nnnnnnnn > nnnnnnnn.asc
----

where `nnnnnnnn` is the id of your public key.

You'll also need the fingerprint of your key.
This can be generated using:

[source]
----
$ 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 (`nnnnnnnn`).

=== 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[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 http://www.apache.org/dev/release-signing.html#keyserver-upload[release signing page] on the Apache wiki, and the http://maven.apache.org/developers/release/pmc-gpg-keys.html[gpg key page] on the Maven wiki.

To send the key up to the key server:

[source]
----
$ gpg --send-keys --keyserver pgp.mit.edu nnnnnnnn
----

where `nnnnnnnn` is the key Id.

Alternatively, you can browse to the http://pgp.mit.edu/[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:

`http://pgp.mit.edu:11371/pks/lookup?search=0xnnnnnnnnn&amp;op=vindex`

again, where `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 `.pgpkey`.
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 `people.apache.org`, named `nnnnnnnn.asc`.
Make sure this is readable by all.

Check the file is accessible by browsing to:

`http://people.apache.org/~xxxxxxxx/nnnnnnnn.asc`

where

* `xxxxxxxx` is your apache LDAP user name
* `nnnnnnnn` is your public key id.

=== FOAF

First, check out the committers/info directory:

Go to Apache http://people.apache.org/foaf/foafamatic.html[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
* press "Create"

In the box below, you should have a FOAF file, something like:

[source,xml]
----
<?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 `committers/info`:

[source,xml]
----
<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:PubKey>`:

[source,xml]
----
<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.

=== Save to `KEYS`

The armored representation of the public key should be saved to Apache Isis' `KEYS` file, http://www.apache.org/dist/isis/KEYS[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:

[source]
----
svn -N co https://svn.apache.org/repos/asf/isis/ .
----

This should bring down the `KEYS` file.

Then, export your signature and armored representation.

[source]
----
gpg --list-sigs nnnnnnnn >>KEYS
gpg --armor --export nnnnnnnn >>KEYS
----

Then commit.

=== id.apache.org

Log onto `id.apache.org` and ensure that the finger print of your public key is correct.

== Attend Key Signing Party (Apache web of trust)

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 http://www.apache.org/dev/release-signing.html#key-signing-party[here] and http://wiki.apache.org/apachecon/PgpKeySigning[here].

== Update Maven Settings file (`~/.m2/settings.xml`)

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:

[source,xml]
----
<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 `.ssh`:

[source,xml]
----
<settings>
  ...
  <servers>
    ...
    <server>
      <id>apache.releases.https</id>
      <username>xxxx</username>
      <password>xxxx</password>
    </server>
  </servers>
</settings>
----
