Home | History | Annotate | Download | only in ota
      1 <html devsite>
      2   <head>
      3     <title>Signing Builds for Release</title>
      4     <meta name="project_path" value="/_project.yaml" />
      5     <meta name="book_path" value="/_book.yaml" />
      6   </head>
      7   <body>
      8   <!--
      9       Copyright 2017 The Android Open Source Project
     10 
     11       Licensed under the Apache License, Version 2.0 (the "License");
     12       you may not use this file except in compliance with the License.
     13       You may obtain a copy of the License at
     14 
     15           http://www.apache.org/licenses/LICENSE-2.0
     16 
     17       Unless required by applicable law or agreed to in writing, software
     18       distributed under the License is distributed on an "AS IS" BASIS,
     19       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     20       See the License for the specific language governing permissions and
     21       limitations under the License.
     22   -->
     23 
     24 
     25 
     26 <p>Android OS images use cryptographic signatures in two places:</p>
     27 <ol>
     28 <li>Each .apk file inside the image must be signed. Android's Package Manager
     29 uses an .apk signature in two ways:<ul>
     30 <li>When an application is replaced, it must be signed by the same key as the
     31 old application in order to get access to the old application's data. This
     32 holds true both for updating user apps by overwriting the .apk, and for
     33 overriding a system app with a newer version installed under
     34 <code>/data</code>.</li>
     35 <li>If two or more applications want to share a user ID (so they can share
     36 data, etc.), they must be signed with the same key.</li></ul>
     37 <li>OTA update packages must be signed with one of the keys expected by the
     38 system or the installation process will reject them.</li>
     39 </ol>
     40 
     41 <h2 id="release-keys">Release keys</h2>
     42 
     43 <p>The Android tree includes <i>test-keys</i> under
     44 <code>build/target/product/security</code>. Building an Android OS image
     45 using <code>make</code> will sign all .apk files using the test-keys.
     46 Since the test-keys are publicly known, anybody can sign their own .apk files
     47 with the same keys, which may allow them to replace or hijack system
     48 apps built into your OS image. For this reason it is critical to sign any
     49 publicly released or deployed Android OS image with a special set of
     50 <i>release-keys</i> that only you have access to.</p>
     51 
     52 <p>To generate your own unique set of release-keys, run these commands from
     53 the root of your Android tree:</p>
     54 
     55 <pre class="devsite-click-to-copy">
     56 <code class="devsite-terminal">subject='/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android (a] android.com'</code>
     57 <code class="devsite-terminal">mkdir ~/.android-certs</code>
     58 <code class="devsite-terminal">for x in releasekey platform shared media; do \
     59     ./development/tools/make_key ~/.android-certs/$x "$subject"; \
     60 done</code>
     61 </pre>
     62 
     63 <p><code>$subject</code> should be changed to reflect your organization's
     64 information. You can use any directory, but be careful to pick a
     65 location that is backed up and secure. Some vendors choose to encrypt
     66 their private key with a strong passphrase and store the encrypted key
     67 in source control; others store their release keys somewhere else entirely,
     68 such as on an air-gapped computer.</p>
     69 
     70 <p>To generate a release image, use:</p>
     71 
     72 <pre class="devsite-click-to-copy">
     73 <code class="devsite-terminal">make dist</code>
     74 <code class="devsite-terminal">./build/tools/releasetools/sign_target_files_apks \
     75     -o \    # explained in the next section
     76     -d ~/.android-certs out/dist/*-target_files-*.zip \
     77     signed-target_files.zip</code>
     78 </pre>
     79 
     80 <p>The <code>sign_target_files_apks</code> script takes a target-files .zip
     81 as input and produces a new target-files .zip in which all the .apks have
     82 been signed with new keys. The newly signed images can be found under
     83 <code>IMAGES/</code> in <code>signed-target_files.zip</code>.</p>
     84 
     85 <h2 id="sign-ota-packages">Signing OTA packages</h2>
     86 
     87 A signed target-files zip can be converted into a signed OTA update zip
     88 using the following procedure:
     89 
     90 <pre class="devsite-click-to-copy">
     91 <code class="devsite-terminal">./build/tools/releasetools/ota_from_target_files \
     92     -k ~/.android-certs/releasekey \
     93     signed-target_files.zip \
     94     signed-ota_update.zip</code>
     95 </pre>
     96 
     97 <h3 id="signatures-sideloading">Signatures and sideloading</h3>
     98 <p>Sideloading does not bypass recovery's normal package signature
     99 verification mechanismbefore installing a package, recovery will verify that
    100 it is signed with one of the private keys matching the public keys stored in
    101 the recovery partition, just as it would for a package delivered over-the-air.
    102 </p>
    103 
    104 <p>Update packages received from the main system are typically verified twice:
    105 once by the main system, using the
    106 <code><a href="http://developer.android.com/reference/android/os/RecoverySystem.html#verifyPackage">RecoverySystem.verifyPackage()</a></code>
    107 method in the android API, and then again by
    108 recovery. The RecoverySystem API checks the signature against public keys
    109 stored in the main system, in the file <code>/system/etc/security/otacerts.zip
    110 </code> (by default). Recovery checks the signature against public keys stored
    111 in the recovery partition RAM disk, in the file <code>/res/keys</code>.</p>
    112 
    113 <p>By default, the target-files .zip produced by the build sets the OTA
    114 certificate to match the test key. On a released image, a
    115 different certificate must be used so that devices can verify the
    116 authenticity of the update package. Passing the <code>-o</code> flag to
    117 <code>sign_target_files_apks</code>, as shown in the previous section, replaces
    118 the test key certificate with the release key certificate from your certs
    119 directory.</p>
    120 
    121 <p>Normally the system image and recovery image store the same set of OTA
    122 public keys.  By adding a key to <i>just</i> the recovery set of keys, it is
    123 possible to sign packages that can be installed only via sideloading
    124 (assuming the main system's update download mechanism is correctly doing
    125 verification against otacerts.zip). You can specify extra keys to be
    126 included only in recovery by setting the PRODUCT_EXTRA_RECOVERY_KEYS
    127 variable in your product definition:</p>
    128 
    129 <pre class="devsite-click-to-copy">
    130 vendor/yoyodyne/tardis/products/tardis.mk
    131 </pre>
    132 <pre class="devsite-click-to-copy">
    133  [...]
    134 
    135 PRODUCT_EXTRA_RECOVERY_KEYS := vendor/yoyodyne/security/tardis/sideload
    136 </pre>
    137 
    138 <p>This includes the public key
    139 <code>vendor/yoyodyne/security/tardis/sideload.x509.pem</code> in the recovery
    140 keys file so it can install packages signed
    141 with it. The extra key is <i>not</i> included in otacerts.zip though, so
    142 systems that correctly verify downloaded packages do not invoke recovery for
    143 packages signed with this key.</p>
    144 
    145 <h2 id="certificates-keys">Certificates and private keys</h2>
    146 <p>Each key comes in two files: the <i>certificate</i>, which has the
    147 extension .x509.pem, and the <i>private key</i>, which has the extension .pk8.
    148 The private key should be kept secret and is needed to sign a package. The key
    149 may itself be protected by a password. The certificate, in
    150 contrast, contains only the public half of the key, so it can be distributed
    151 widely. It is used to verify a package has been signed by the corresponding
    152 private key.</p>
    153 <p>The standard Android build uses four keys, all of which reside in <code>
    154 build/target/product/security</code>:</p>
    155 
    156 <dl>
    157 <dt>testkey</dt>
    158 <dd>Generic default key for packages that do not otherwise specify a key.</dd>
    159 <dt>platform</dt>
    160 <dd>Test key for packages that are part of the core platform.</dd>
    161 <dt>shared</dt>
    162 <dd>Test key for things that are shared in the home/contacts process.</dd>
    163 <dt>media</dt>
    164 <dd>Test key for packages that are part of the media/download system.</dd></dl>
    165 
    166 <p>Individual packages specify one of these keys by setting LOCAL_CERTIFICATE
    167 in their Android.mk file. (testkey is used if this variable is not set.) You
    168 can also specify an entirely different key by pathname, e.g.:</p>
    169 
    170 <pre class="devsite-click-to-copy">
    171 device/yoyodyne/apps/SpecialApp/Android.mk
    172 </pre>
    173 <pre class="devsite-click-to-copy">
    174  [...]
    175 
    176 LOCAL_CERTIFICATE := device/yoyodyne/security/special
    177 </pre>
    178 
    179 <p>Now the build uses the <code>device/yoyodyne/security/special.{x509.pem,pk8}
    180 </code> key to sign SpecialApp.apk. The build can use only private keys that
    181 are <i>not </i>password protected.</p>
    182 
    183 <h2 id="advanced-signing-options">Advanced signing options</h2>
    184 <p>When you run the <code>sign_target_files_apks</code> script, you must
    185 specify on the command line a replacement key for each key used in the build.
    186 The <code>-k <i>src_key</i>=<i>
    187 dest_key</i></code> flag specifies key replacements one at a time. The flag
    188 <code>-d <i>dir</i></code> lets you specify a directory with four keys to
    189 replace all those in <code>build/target/product/security</code>; it is
    190 equivalent to using <code>-k</code> four times to specify the mappings:</p>
    191 
    192 <pre class="devsite-click-to-copy">
    193 build/target/product/security/testkey  = dir/releasekey
    194 build/target/product/security/platform = dir/platform
    195 build/target/product/security/shared   = dir/shared
    196 build/target/product/security/media    = dir/media
    197 </pre>
    198 
    199 <p>For the hypothetical tardis product, you need five password-protected keys:
    200 four to replace the four in <code>build/target/product/security</code>, and
    201 one to replace the additional <code>keydevice/yoyodyne/security/special</code>
    202 required by SpecialApp in the example above. If the keys were in the following
    203 files:</p>
    204 
    205 <pre class="devsite-click-to-copy">
    206 vendor/yoyodyne/security/tardis/releasekey.x509.pem
    207 vendor/yoyodyne/security/tardis/releasekey.pk8
    208 vendor/yoyodyne/security/tardis/platform.x509.pem
    209 vendor/yoyodyne/security/tardis/platform.pk8
    210 vendor/yoyodyne/security/tardis/shared.x509.pem
    211 vendor/yoyodyne/security/tardis/shared.pk8
    212 vendor/yoyodyne/security/tardis/media.x509.pem
    213 vendor/yoyodyne/security/tardis/media.pk8
    214 vendor/yoyodyne/security/special.x509.pem
    215 vendor/yoyodyne/security/special.pk8           # NOT password protected
    216 vendor/yoyodyne/security/special-release.x509.pem
    217 vendor/yoyodyne/security/special-release.pk8   # password protected
    218 </pre>
    219 
    220 <p>Then you would sign all the apps like this:</p>
    221 
    222 <pre class="devsite-click-to-copy">
    223 <code class="devsite-terminal">./build/tools/releasetools/sign_target_files_apks -d vendor/yoyodyne/security/tardis -k vendor/yoyodyne/special=vendor/yoyodyne/special-release -o tardis-target_files.zip signed-tardis-target_files.zip</code>
    224 </pre>
    225 
    226 <p>This brings up the following:</p>
    227 <pre class="devsite-click-to-copy">
    228 Enter password for vendor/yoyodyne/security/special-release key&gt;
    229 Enter password for vendor/yoyodyne/security/tardis/media key&gt;
    230 Enter password for vendor/yoyodyne/security/tardis/platform key&gt;
    231 Enter password for vendor/yoyodyne/security/tardis/releasekey key&gt;
    232 Enter password for vendor/yoyodyne/security/tardis/shared key&gt;
    233     signing: Phone.apk (vendor/yoyodyne/security/tardis/platform)
    234     signing: Camera.apk (vendor/yoyodyne/security/tardis/media)
    235     signing: Special.apk (vendor/yoyodyne/security/special-release)
    236     signing: Email.apk (vendor/yoyodyne/security/tardis/releasekey)
    237         [...]
    238     signing: ContactsProvider.apk (vendor/yoyodyne/security/tardis/shared)
    239     signing: Launcher.apk (vendor/yoyodyne/security/tardis/shared)
    240 rewriting SYSTEM/build.prop:
    241   replace:  ro.build.description=tardis-user Eclair ERC91 15449 test-keys
    242      with:  ro.build.description=tardis-user Eclair ERC91 15449 release-keys
    243   replace: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/test-keys
    244      with: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/release-keys
    245     signing: framework-res.apk (vendor/yoyodyne/security/tardis/platform)
    246 rewriting RECOVERY/RAMDISK/default.prop:
    247   replace:  ro.build.description=tardis-user Eclair ERC91 15449 test-keys
    248      with:  ro.build.description=tardis-user Eclair ERC91 15449 release-keys
    249   replace: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/test-keys
    250      with: ro.build.fingerprint=generic/tardis/tardis/tardis:Eclair/ERC91/15449:user/release-keys
    251 using:
    252     vendor/yoyodyne/security/tardis/releasekey.x509.pem
    253 for OTA package verification
    254 done.
    255 </pre>
    256 
    257 <p>After prompting the user for passwords for all password-protected keys, the
    258 script re-signs all the .apk files in the input target .zip with the release
    259 keys. Before running the command, you can also set the ANDROID_PW_FILE
    260 environment variable to a temporary filename; the script then invokes your
    261 editor to allow you to enter passwords for all keys (this may be a more
    262 convenient way to enter passwords).<p>
    263 <p><code>sign_target_files_apks</code> also rewrites the build description and
    264 fingerprint in the build properties files to reflect the fact that this is a
    265 signed build. The <code>-t</code> flag can control what edits are made to the
    266 fingerprint. Run the script with <code>-h</code> to see documentation on all
    267 flags.</p>
    268 
    269 <h2 id="manually-generating-keys">Manually generating keys</h2>
    270 <p>Android uses 2048-bit RSA keys with public exponent 3. You can generate
    271 certificate/private key pairs using the openssl tool from
    272 <a href="https://www.openssl.org/">openssl.org</a>:</p>
    273 
    274 <pre class="devsite-click-to-copy">
    275 # generate RSA key
    276 <code class="devsite-terminal">openssl genrsa -3 -out temp.pem 2048</code>
    277 Generating RSA private key, 2048 bit long modulus
    278 ....+++
    279 .....................+++
    280 e is 3 (0x3)
    281 
    282 # create a certificate with the public part of the key
    283 <code class="devsite-terminal">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 (a] example.com'</code>
    284 
    285 # create a PKCS#8-formatted version of the private key
    286 <code class="devsite-terminal">openssl pkcs8 -in temp.pem -topk8 -outform DER -out releasekey.pk8 -nocrypt</code>
    287 
    288 # securely delete the temp.pem file
    289 <code class="devsite-terminal">shred --remove temp.pem</code>
    290 </pre>
    291 
    292 <p>The openssl pkcs8 command given above creates a .pk8 file with <i>no</i>
    293 password, suitable for use with the build system. To create a .pk8 secured
    294 with a password (which you should do for all actual release keys), replace the
    295 <code>-nocrypt</code> argument with <code>-passout stdin</code>; then openssl
    296 will encrypt the private key with a password read from standard input. No
    297 prompt is printed, so if stdin is the terminal the program will appear to hang
    298 when it's really just waiting for you to enter a password. Other values can be
    299 used for the-passout argument to read the password from other locations; for
    300 details, see the
    301 <a href="http://www.openssl.org/docs/man1.0.1/apps/openssl.html#PASS-PHRASE-ARGUMENTS">
    302 openssl documentation</a>.</p>
    303 <p>The temp.pem intermediate file contains the private key without any kind of
    304 password protection, so dispose of it thoughtfully when generating release
    305 keys. In particular, the GNUshred utility may not be effective on network or
    306 journaled filesystems. You can use a working directory located in a RAM disk
    307 (such as a tmpfs partition) when generating keys to ensure the intermediates
    308 are not inadvertently exposed.</p>
    309 
    310 <h2 id="creating-image-files">Creating image files</h2>
    311 
    312 <p>
    313 Once you have signed-target-files.zip, you need to
    314 create the image so you can put it onto a device.
    315 To create the signed image from the target files, run
    316 the following command from the root of the Android
    317 tree:
    318 </p>
    319 
    320 <pre class="devsite-terminal devsite-click-to-copy">
    321 ./build/tools/releasetools/img_from_target_files signed-target-files.zip signed-img.zip
    322 </pre>
    323 
    324 The resulting file, <code>signed-img.zip</code>, contains all the .img files.
    325 
    326 To load an image onto a device, use fastboot as
    327 follows:
    328 
    329 <pre class="devsite-terminal devsite-click-to-copy">
    330 fastboot update signed-img.zip
    331 </pre>
    332 
    333   </body>
    334 </html>
    335