aboutsummaryrefslogtreecommitdiff
path: root/src/devices/tech/ota/sign_builds.jd
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/tech/ota/sign_builds.jd')
-rwxr-xr-xsrc/devices/tech/ota/sign_builds.jd269
1 files changed, 269 insertions, 0 deletions
diff --git a/src/devices/tech/ota/sign_builds.jd b/src/devices/tech/ota/sign_builds.jd
new file mode 100755
index 00000000..e9869205
--- /dev/null
+++ b/src/devices/tech/ota/sign_builds.jd
@@ -0,0 +1,269 @@
+page.title=Signing Builds for Release
+@jd:body
+
+<!--
+ Copyright 2015 The Android Open Source Project
+
+ Licensed 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.
+-->
+
+<div id="qv-wrapper">
+ <div id="qv">
+ <h2>In this document</h2>
+ <ol id="auto-toc">
+ </ol>
+ </div>
+</div>
+
+<p>Android uses 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>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>
+<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>
+<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
+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>
+<p>The standard Android build uses four keys, all of which reside in <code>
+build/target/product/security</code>:</p>
+
+<dl>
+<dt>testkey</dt>
+<dd>Generic default key for packages that do not otherwise specify a key.</dd>
+<dt>platform</dt>
+<dd>Test key for packages that are part of the core platform.</dd>
+<dt>shared</dt>
+<dd>Test key for things that are shared in the home/contacts process.</dd>
+<dt>media</dt>
+<dd>Test key for packages that are part of the media/download system.</dd></dl>
+
+<p>Individual packages specify one of these keys by setting LOCAL_CERTIFICATE
+in their Android.mk file. (testkey is used if this variable is not set.) You
+can also specify an entirely different key by pathname, e.g.:</p>
+
+<p><code>device/yoyodyne/apps/SpecialApp/Android.mk</code></p>
+<pre>
+ [...]
+
+LOCAL_CERTIFICATE := device/yoyodyne/security/special
+</pre>
+
+<p>Now the build uses the <code>device/yoyodyne/security/special.{x509.pem,pk8}
+</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>
+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>
+build/target/product/security/testkey = dir/releasekey
+build/target/product/security/platform = dir/platform
+build/target/product/security/shared = dir/shared
+build/target/product/security/media = dir/media
+</pre>
+
+<p>For the hypothetical tardis product, you need five password-protected keys:
+four to replace the four in <code>build/target/product/security</code>, and
+one to replace the additional <code>keydevice/yoyodyne/security/special</code>
+required by SpecialApp in the example above. If the keys were in the following
+files:</p>
+
+<pre>
+vendor/yoyodyne/security/tardis/releasekey.x509.pem
+vendor/yoyodyne/security/tardis/releasekey.pk8
+vendor/yoyodyne/security/tardis/platform.x509.pem
+vendor/yoyodyne/security/tardis/platform.pk8
+vendor/yoyodyne/security/tardis/shared.x509.pem
+vendor/yoyodyne/security/tardis/shared.pk8
+vendor/yoyodyne/security/tardis/media.x509.pem
+vendor/yoyodyne/security/tardis/media.pk8
+vendor/yoyodyne/security/special.x509.pem
+vendor/yoyodyne/security/special.pk8 # NOT password protected
+vendor/yoyodyne/security/special-release.x509.pem
+vendor/yoyodyne/security/special-release.pk8 # password protected
+</pre>
+
+<p>Then you would sign all the apps like this:</p>
+
+<pre>
+% <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>
+ tardis-target_files.zip signed-tardis-target_files.zip</b>
+Enter password for vendor/yoyodyne/security/special-release key&gt;
+Enter password for vendor/yoyodyne/security/tardis/media key&gt;
+Enter password for vendor/yoyodyne/security/tardis/platform key&gt;
+Enter password for vendor/yoyodyne/security/tardis/releasekey key&gt;
+Enter password for vendor/yoyodyne/security/tardis/shared key&gt;
+ signing: Phone.apk (vendor/yoyodyne/security/tardis/platform)
+ signing: Camera.apk (vendor/yoyodyne/security/tardis/media)
+ signing: Special.apk (vendor/yoyodyne/security/special-release)
+ signing: Email.apk (vendor/yoyodyne/security/tardis/releasekey)
+ [...]
+ signing: ContactsProvider.apk (vendor/yoyodyne/security/tardis/shared)
+ signing: Launcher.apk (vendor/yoyodyne/security/tardis/shared)
+rewriting SYSTEM/build.prop:
+ replace: ro.build.description=tardis-user Eclair ERC91 15449 test-keys
+ with: ro.build.description=tardis-user Eclair ERC91 15449 release-keys
+ replace: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/test-keys
+ with: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/release-keys
+ signing: framework-res.apk (vendor/yoyodyne/security/tardis/platform)
+rewriting RECOVERY/RAMDISK/default.prop:
+ replace: ro.build.description=tardis-user Eclair ERC91 15449 test-keys
+ with: ro.build.description=tardis-user Eclair ERC91 15449 release-keys
+ replace: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/test-keys
+ with: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/release-keys
+using:
+ vendor/yoyodyne/security/tardis/releasekey.x509.pem
+for OTA package verification
+done.
+</pre>
+
+<p>After prompting the user for passwords for all password-protected keys, the
+script re-signs all the .apk files in the input target .zip with the release
+keys. Before running the command, you can also set the ANDROID_PW_FILE
+environment variable to a temporary filename; the script then invokes your
+editor to allow you to enter passwords for all keys (this may be a more
+convenient way to enter passwords).<p>
+<p><code>sign_target_files_apks</code> also rewrites the build description and
+fingerprint in the build properties files to reflect the fact that this is a
+signed build. The <code>-t</code> flag can control what edits are made to the
+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&gt;
+done.</pre></li></ul>
+
+<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>
+
+<p><code>vendor/yoyodyne/tardis/products/tardis.mk</code></p>
+<pre>
+ [...]
+
+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> \ No newline at end of file