Docs: Update sign_builds.jd
Add a new "release-keys" section and provide easy recipes for signing
flashable images and OTAs. Reorganize the document to put the most widely
used information at the top, and move advanced topics into "appendices."
Explain the pitfalls of shipping images built with test-keys.
Bug: 21365053
Change-Id: I696591abd5b54d9e9d56bc15bcf198951a338d18
Signed-off-by: Kevin Cernekee <cernekee@google.com>
diff --git a/src/devices/tech/ota/sign_builds.jd b/src/devices/tech/ota/sign_builds.jd
index e986920..5e400be 100755
--- a/src/devices/tech/ota/sign_builds.jd
+++ b/src/devices/tech/ota/sign_builds.jd
@@ -25,24 +25,128 @@
</div>
</div>
-<p>Android uses cryptographic signatures in two places:</p>
+<p>Android OS images use cryptographic signatures in two places:</p>
<ol>
-<li>Each .apk file must be signed. Android's Package Manager uses an .apk
-signature in two ways:<ul>
+<li>Each .apk file inside the image must be signed. Android's Package Manager
+uses an .apk signature in two ways:<ul>
<li>When an application is replaced, it must be signed by the same key as the
-old application in order to get access to the old application's data.</li>
+old application in order to get access to the old application's data. This
+holds true both for updating user apps by overwriting the .apk, and for
+overriding a system app with a newer version installed under
+<code>/data</code>.</li>
<li>If two or more applications want to share a user ID (so they can share
data, etc.), they must be signed with the same key.</ul></li>
<li>OTA update packages must be signed with one of the keys expected by the
system or the installation process will reject them.</ul></li>
</ol>
-<h2 id="certificates-keys">Certificates and keys</h2>
+
+<h2 id="release-keys">Release keys</h2>
+
+<p>The Android tree includes <i>test-keys</i> under
+<code>build/target/product/security</code>. Building an Android OS image
+using <code>make</code> will sign all .apk files using the test-keys.
+Since the test-keys are publicly known, anybody can sign their own .apk files
+with the same keys, which may allow them to replace or hijack system
+apps built into your OS image. For this reason it is critical to sign any
+publicly released or deployed Android OS image with a special set of
+<i>release-keys</i> that only you have access to.</p>
+
+<p>To generate your own unique set of release-keys, run these commands from
+the root of your Android tree:</p>
+
+<pre class="no-pretty-print">
+subject='/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'
+mkdir ~/.android-certs
+for x in releasekey platform shared media; do \
+ ./development/tools/make_key ~/.android-certs/$x "$subject"; \
+done
+</pre>
+
+<p><code>$subject</code> should be changed to reflect your organization's
+information. You can use any directory, but be careful to pick a
+location that is backed up and secure. Some vendors choose to encrypt
+their private key with a strong passphrase and store the encrypted key
+in source control; others store their release keys somewhere else entirely,
+such as on an air-gapped computer.</p>
+
+<p>To generate a release image, use:</p>
+
+<pre class="no-pretty-print">
+make dist
+./build/tools/releasetools/sign_target_files_apks \
+ -o \ # explained in the next section
+ -d ~/.android-certs out/dist/*-target_files-*.zip \
+ signed-target_files.zip
+</pre>
+
+<p>The <code>sign_target_files_apks</code> script takes a target-files .zip
+as input and produces a new target-files .zip in which all the .apks have
+been signed with new keys. The newly signed images can be found under
+<code>IMAGES/</code> in <code>signed-target_files.zip</code>.</p>
+
+<h2 id="sign-ota-packages">Signing OTA packages</h2>
+
+A signed target-files zip can be converted into a signed OTA update zip
+using the following procedure:
+
+<pre class="no-pretty-print">
+./build/tools/releasetools/ota_from_target_files \
+ -k ~/.android-certs/releasekey \
+ signed-target_files.zip \
+ signed-ota_update.zip
+</pre>
+
+<h3 id="signatures-sideloading">Signatures and sideloading</h3>
+<p>Sideloading does not bypass recovery's normal package signature
+verification mechanism—before installing a package, recovery will verify that
+it is signed with one of the private keys matching the public keys stored in
+the recovery partition, just as it would for a package delivered over-the-air.
+</p>
+
+<p>Update packages received from the main system are typically verified twice:
+once by the main system, using the
+<code><a href="http://developer.android.com/reference/android/os/RecoverySystem.html#verifyPackage">RecoverySystem.verifyPackage()</a></code>
+method in the android API, and then again by
+recovery. The RecoverySystem API checks the signature against public keys
+stored in the main system, in the file <code>/system/etc/security/otacerts.zip
+</code> (by default). Recovery checks the signature against public keys stored
+in the recovery partition RAM disk, in the file <code>/res/keys</code>.</p>
+
+<p>By default, the target-files .zip produced by the build sets the OTA
+certificate to match the test key. On a released image, a
+different certificate must be used so that devices can verify the
+authenticity of the update package. Passing the <code>-o</code> flag to
+<code>sign_target_files_apks</code>, as shown in the previous section, replaces
+the test key certificate with the release key certificate from your certs
+directory.</p>
+
+<p>Normally the system image and recovery image store the same set of OTA
+public keys. By adding a key to <i>just</i> the recovery set of keys, it is
+possible to sign packages that can be installed only via sideloading
+(assuming the main system's update download mechanism is correctly doing
+verification against otacerts.zip). You can specify extra keys to be
+included only in recovery by setting the PRODUCT_EXTRA_RECOVERY_KEYS
+variable in your product definition:</p>
+
+<p><code>vendor/yoyodyne/tardis/products/tardis.mk</code></p>
+<pre class="no-pretty-print">
+ [...]
+
+PRODUCT_EXTRA_RECOVERY_KEYS := vendor/yoyodyne/security/tardis/sideload
+</pre>
+
+<p>This includes the public key
+<code>vendor/yoyodyne/security/tardis/sideload.x509.pem</code> in the recovery
+keys file so it can install packages signed
+with it. The extra key is <i>not</i> included in otacerts.zip though, so
+systems that correctly verify downloaded packages do not invoke recovery for
+packages signed with this key.</p>
+
+<h2 id="certificates-keys">Certificates and private keys</h2>
<p>Each key comes in two files: the <i>certificate</i>, which has the
extension .x509.pem, and the <i>private key</i>, which has the extension .pk8.
The private key should be kept secret and is needed to sign a package. The key
-may itself be protected by a password—a reasonable strategy is to store your
-keys in source control along with the code—but keep them protected by a
-password known only to the people who make final releases. The certificate, in
+may itself be protected by a password. The certificate, in
contrast, contains only the public half of the key, so it can be distributed
widely. It is used to verify a package has been signed by the corresponding
private key.</p>
@@ -64,7 +168,7 @@
can also specify an entirely different key by pathname, e.g.:</p>
<p><code>device/yoyodyne/apps/SpecialApp/Android.mk</code></p>
-<pre>
+<pre class="no-pretty-print">
[...]
LOCAL_CERTIFICATE := device/yoyodyne/security/special
@@ -74,63 +178,16 @@
</code> key to sign SpecialApp.apk. The build can use only private keys that
are <i>not </i>password protected.</p>
-<h2>Generating keys</h2>
-<p>Android uses 2048-bit RSA keys with public exponent 3. You can generate
-certificate/private key pairs using the openssl tool from
-<a href="http://www.openssl.org/">openssl.org</a>:</p>
-
-<pre>
-# generate RSA key
-% <b>openssl genrsa -3 -out temp.pem 2048</b>
-Generating RSA private key, 2048 bit long modulus
-....+++
-.....................+++
-e is 3 (0x3)
-
-# create a certificate with the public part of the key
-% <b>openssl req -new -x509 -key temp.pem -out releasekey.x509.pem \
- -days 10000 \
- -subj '/C=US/ST=California/L=San Narciso/O=Yoyodyne, Inc./OU=Yoyodyne Mobility/CN=Yoyodyne/emailAddress=yoyodyne@example.com'</b>
-
-# create a PKCS#8-formatted version of the private key
-% <b>openssl pkcs8 -in temp.pem -topk8 -outform DER -out releasekey.pk8 -nocrypt</b>
-
-# securely delete the temp.pem file
-% <b>shred --remove temp.pem</b>
-</pre>
-
-<p>The openssl pkcs8 command given above creates a .pk8 file with <i>no</i>
-password, suitable for use with the build system. To create a .pk8 secured
-with a password (which you should do for all actual release keys), replace the
-<code>-nocrypt</code> argument with <code>-passout stdin</code>; then openssl
-will encrypt the private key with a password read from standard input. No
-prompt is printed, so if stdin is the terminal the program will appear to hang
-when it's really just waiting for you to enter a password. Other values can be
-used for the-passout argument to read the password from other locations; for
-details, see the
-<a href="http://www.openssl.org/docs/apps/openssl.html#PASS_PHRASE_ARGUMENTS">
-openssl documentation</a>.</p>
-<p>The temp.pem intermediate file contains the private key without any kind of
-password protection, so dispose of it thoughtfully when generating release
-keys. In particular, the GNUshred utility may not be effective on network or
-journaled filesystems. You can use a working directory located in a RAM disk
-(such as a tmpfs partition) when generating keys to ensure the intermediates
-are not inadvertently exposed.</p>
-
-<h2 id="sign-apps-for-release">Signing apps for release</h2>
-<p>The first step in preparing a build for release is to sign all the .apk
-files in it, replacing the test keys used by the build system. This is done
-with the <code>sign_target_files_apks</code> script. It takes a target-files
-.zip as input and produces a new target-files .zip in which all the .apks have
-been signed with new keys.</p>
-<p>When you run this script, you must specify on the command line a
-replacement key for each key used in the build. The <code>-k <i>src_key</i>=<i>
+<h2 id="advanced-signing-options">Advanced signing options</h2>
+<p>When you run the <code>sign_target_files_apks</code> script, you must
+specify on the command line a replacement key for each key used in the build.
+The <code>-k <i>src_key</i>=<i>
dest_key</i></code> flag specifies key replacements one at a time. The flag
<code>-d <i>dir</i></code> lets you specify a directory with four keys to
replace all those in <code>build/target/product/security</code>; it is
equivalent to using <code>-k</code> four times to specify the mappings:</p>
-<pre>
+<pre class="no-pretty-print">
build/target/product/security/testkey = dir/releasekey
build/target/product/security/platform = dir/platform
build/target/product/security/shared = dir/shared
@@ -143,7 +200,7 @@
required by SpecialApp in the example above. If the keys were in the following
files:</p>
-<pre>
+<pre class="no-pretty-print">
vendor/yoyodyne/security/tardis/releasekey.x509.pem
vendor/yoyodyne/security/tardis/releasekey.pk8
vendor/yoyodyne/security/tardis/platform.x509.pem
@@ -160,11 +217,11 @@
<p>Then you would sign all the apps like this:</p>
-<pre>
+<pre class="no-pretty-print">
% <b>./build/tools/releasetools/sign_target_files_apks \
-d vendor/yoyodyne/security/tardis \
-k vendor/yoyodyne/special=vendor/yoyodyne/special-release \
- -o \ </b># explained in the next section<b>
+ -o \
tardis-target_files.zip signed-tardis-target_files.zip</b>
Enter password for vendor/yoyodyne/security/special-release key>
Enter password for vendor/yoyodyne/security/tardis/media key>
@@ -207,63 +264,45 @@
fingerprint. Run the script with <code>-h</code> to see documentation on all
flags.</p>
-<h2 id="sign-ota-packages">Signing OTA packages</h2>
-<p>You need the following components to sign OTA packages:</p>
-<ol>
-<li>Certificates of the keys you want this build to accept.</li>
-<li>Sign the newly-created package with the private key (must correspond to
-the certificate embedded in the current build of any device to which you want
-to send this package).</li>
-</ol>
-<p>To achieve these components:</p>
-<ul>
-<li>The target-files .zip produced by the build sets the OTA certificate to
-the certificate of the test key. Passing the <code>-o</code> flag to <code>
-sign_target_files_apks</code> replaces this key with the release key from your
-build.</li>
-<li>To sign the OTA update package, use the <code>-k</code> option when
-generating it to specify the key. You should give <code>ota_from_target_files
-</code> the <i>signed</i> version of the target-files .zip as well:
-<pre>
-% <b>./build/tools/releasetools/ota_from_target_files \
- -k vendor/yoyodyne/security/tardis/releasekey \
- signed-tardis-target_files.zip \
- signed-ota_update.zip</b>
-unzipping target target-files...
-(using device-specific extensions from target_files)
-Enter password for vendor/yoyodyne/security/tardis/releasekey key>
-done.</pre></li></ul>
+<h2 id="manually-generating-keys">Manually generating keys</h2>
+<p>Android uses 2048-bit RSA keys with public exponent 3. You can generate
+certificate/private key pairs using the openssl tool from
+<a href="http://www.openssl.org/">openssl.org</a>:</p>
-<h3 id="signatures-sideloading">Signatures and sideloading</h3>
-<p>Sideloading does not bypass recovery's normal package signature
-verification mechanism—before installing a package, recovery will verify that
-it is signed with one of the private keys matching the public keys stored in
-the recovery partition, just as it would for a package delivered over-the-air.
-</p>
-<p>Update packages received from the main system are typically verified twice:
-once by the main system, using the <code><a href="http://developer.android.com/
-reference/android/os/RecoverySystem.html#verifyPackage">RecoverySystem.
-verifyPackage()</a></code> method in the android API, and then again by
-recovery. The RecoverySystem API checks the signature against public keys
-stored in the main system, in the file <code>/system/etc/security/otacerts.zip
-</code> (by default). Recovery checks the signature against public keys stored
-in the recovery partition RAM disk, in the file <code>/res/keys</code>.</p>
-<p>Normally these two locations store the same set of keys. By adding a key to
-<i>just</i> the recovery set of keys, it's possible to sign packages that can
-be installed only via sideloading (assuming the main system's update download
-mechanism is correctly doing verification against otacerts.zip). You can
-specify extra keys to be included only in recovery by setting the
-PRODUCT_EXTRA_RECOVERY_KEYS variable in your product definition:</p>
+<pre class="no-pretty-print">
+# generate RSA key
+% <b>openssl genrsa -3 -out temp.pem 2048</b>
+Generating RSA private key, 2048 bit long modulus
+....+++
+.....................+++
+e is 3 (0x3)
-<p><code>vendor/yoyodyne/tardis/products/tardis.mk</code></p>
-<pre>
- [...]
+# create a certificate with the public part of the key
+% <b>openssl req -new -x509 -key temp.pem -out releasekey.x509.pem \
+ -days 10000 \
+ -subj '/C=US/ST=California/L=San Narciso/O=Yoyodyne, Inc./OU=Yoyodyne Mobility/CN=Yoyodyne/emailAddress=yoyodyne@example.com'</b>
-PRODUCT_EXTRA_RECOVERY_KEYS := vendor/yoyodyne/security/tardis/sideload
+# create a PKCS#8-formatted version of the private key
+% <b>openssl pkcs8 -in temp.pem -topk8 -outform DER -out releasekey.pk8 -nocrypt</b>
+
+# securely delete the temp.pem file
+% <b>shred --remove temp.pem</b>
</pre>
-<p>This includes the public key <code>vendor/yoyodyne/security/tardis/sideload.
-x509.pem</code> in the recovery keys file so it can install packages signed
-with it. The extra key is <i>not</i> included in otacerts.zip though, so
-systems that correctly verify downloaded packages do not invoke recovery for
-packages signed with this key.</p>
\ No newline at end of file
+<p>The openssl pkcs8 command given above creates a .pk8 file with <i>no</i>
+password, suitable for use with the build system. To create a .pk8 secured
+with a password (which you should do for all actual release keys), replace the
+<code>-nocrypt</code> argument with <code>-passout stdin</code>; then openssl
+will encrypt the private key with a password read from standard input. No
+prompt is printed, so if stdin is the terminal the program will appear to hang
+when it's really just waiting for you to enter a password. Other values can be
+used for the-passout argument to read the password from other locations; for
+details, see the
+<a href="http://www.openssl.org/docs/apps/openssl.html#PASS_PHRASE_ARGUMENTS">
+openssl documentation</a>.</p>
+<p>The temp.pem intermediate file contains the private key without any kind of
+password protection, so dispose of it thoughtfully when generating release
+keys. In particular, the GNUshred utility may not be effective on network or
+journaled filesystems. You can use a working directory located in a RAM disk
+(such as a tmpfs partition) when generating keys to ensure the intermediates
+are not inadvertently exposed.</p>