| <html devsite> |
| <head> |
| <title>APK Signature Scheme v3</title> |
| <meta name="project_path" value="/_project.yaml" /> |
| <meta name="book_path" value="/_book.yaml" /> |
| </head> |
| <body> |
| <!-- |
| Copyright 2018 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 |
| |
| //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. |
| --> |
| |
| <p> |
| Android 9 supports <a |
| href="https://developer.android.com/preview/features/security#apk-key-rotation">APK |
| key rotation</a>, which gives apps the ability to change their signing key as |
| part of an APK update. To make rotation practical, APKs must indicate levels of |
| trust between the new and old signing key. To support key rotation, we updated |
| the <a href="/security/apksigning/v2">APK signature |
| scheme</a> from v2 to v3 to allow the new and old keys to be used. V3 adds |
| information about the supported SDK versions and a proof-of-rotation struct to |
| the APK signing block. |
| </p> |
| <h2 id="apk-signing-block">APK Signing Block</h2> |
| <p> |
| To maintain backward-compatibility with the v1 APK format, v2 and v3 APK |
| signatures are stored inside an APK Signing Block, located immediately before |
| the ZIP Central Directory. |
| </p> |
| <p> |
| The v3 APK Signing Block format is the <a |
| href="/security/apksigning/v2#apk-signing-block-format">same |
| as v2</a>. The v3 signature of the APK is stored as an ID-value pair with ID |
| 0xf05368c0. |
| </p> |
| <h2 id="apk-signature-scheme-v3-block">APK Signature Scheme v3 Block</h2> |
| <p> |
| The v3 scheme is designed to be very similar to the <a |
| href="/security/apksigning/v2#apk-signature-scheme-v2-block">v2 |
| scheme</a>. It has the same general format and supports the same <a |
| href="/security/apksigning/v2#signature-algorithm-ids">signature |
| algorithm IDs</a>, key sizes, and EC curves. |
| </p> |
| <p> |
| However, the v3 scheme adds information about the supported SDK versions and the |
| proof-of-rotation struct. |
| </p> |
| <h3 id="format">Format</h3> |
| <p> |
| APK Signature Scheme v3 Block is stored inside the APK Signing Block under ID |
| <code>0xf05368c0</code>. |
| </p> |
| <p> |
| The format of the APK Signature Scheme v3 Block follows that of v2: |
| </p> |
| |
| <ul> |
| <li>length-prefixed sequence of length-prefixed <code>signer</code>: |
| <ul> |
| <li>length-prefixed <code>signed data</code>: |
| <ul> |
| <li>length-prefixed sequence of length-prefixed <code>digests</code>: |
| <ul> |
| <li><code>signature algorithm ID</code> (4 bytes)</li> |
| <li><code>digest</code> (length-prefixed)</li> |
| </ul> |
| </li> |
| <li>length-prefixed sequence of X.509 <code>certificates</code>: |
| <ul> |
| <li>length-prefixed X.509 <code>certificate</code> (ASN.1 DER form)</li> |
| </ul> |
| </li> |
| <li><code>minSDK</code> (uint32) - this signer should be ignored if |
| platform version is below this number.</li> |
| <li><code>maxSDK</code> (uint32) - this signer should be ignored if |
| platform version is above this number.</li> |
| <li>length-prefixed sequence of length-prefixed <code>additional |
| attributes</code>: |
| <ul> |
| <li><code>ID</code> (uint32)</li> |
| <li><code>value</code> (variable-length: length of the additional |
| attribute - 4 bytes)</li> |
| <li><code>ID -<strong> 0x3ba06f8c</strong></code></li> |
| <li><code>value -</code> Proof-of-rotation struct</li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li><code>minSDK</code> (uint32) - duplicate of minSDK value in signed data |
| section - used to skip verification of this signature if the current platform is |
| not in range. Must match signed data value.</li> |
| <li><code>maxSDK</code> (uint32) - duplicate of the maxSDK value in the signed |
| data section - used to skip verification of this signature if the current |
| platform is not in range. Must match signed data value.</li> |
| <li>length-prefixed sequence of length-prefixed <code>signatures</code>: |
| <ul> |
| <li><code>signature algorithm ID</code> (uint32)</li> |
| <li>length-prefixed <code>signature</code> over <code>signed data</code></li> |
| </ul> |
| </li> |
| <li>length-prefixed <code>public key</code> (SubjectPublicKeyInfo, ASN.1 DER |
| form)</li> |
| </ul> |
| </li> |
| </ul> |
| |
| <h2 id="proof-of-rotation-and-self-trusted-old-certs-structs">Proof-of-rotation |
| and self-trusted-old-certs structs</h2> |
| <p> |
| The proof-of rotation struct allows apps to rotate their signing cert without |
| being blocked on other apps with which they communicate. To accomplish this, app |
| signatures contain two new pieces of data: |
| </p> |
| <ul> |
| <li>assertion for third parties that the app's signing cert can be trusted |
| wherever its predecessors are trusted</li> |
| <li>app's older signing certs which the app itself still trusts</li> |
| </ul> |
| <p> |
| The proof-of-rotation attribute in the signed-data section consists of a |
| singly-linked list, with each node containing a signing certificate used to sign |
| previous versions of the app. This attribute is meant to contain the conceptual |
| proof-of-rotation and self-trusted-old-certs data structures. The list is |
| ordered by version with the oldest signing cert corresponding to the root node. |
| The proof-of-rotation data structure is built by having the cert in each node |
| sign the next in the list, and thus imbuing each new key with evidence that it |
| should be as trusted as the older key(s). |
| </p> |
| <p> |
| The self-trusted-old-certs data structure is constructed by adding flags to each |
| node indicating its membership and properties in the set. For example, a flag |
| may be present indicating that the signing certificate at a given node is |
| trusted for obtaining Android signature permissions. This flag allows other apps |
| signed by the older certificate to still be granted a signature permission |
| defined by an app signed with the new signing certificate. Because the whole |
| proof-of-rotation attribute resides in the signed data section of the v3 |
| <code>signer</code> field, it is protected by the key used to sign the containing apk. |
| </p> |
| <p> |
| This format precludes <a href="#multiple-certificates">multiple signing keys</a> |
| and convergence of <a |
| href="#multiple-ancestors">different ancestor |
| signing certificates</a> to one (multiple starting nodes to a common sink). |
| </p> |
| |
| <h3 id="proof-of-rotation-format">Format</h3> |
| <p> |
| The proof-of-rotation is stored inside the APK Signature Scheme v3 Block under |
| ID <code>0x3ba06f8c</code>. Its format is: |
| </p> |
| |
| <ul> |
| <li>length-prefixed sequence of length-prefixed <code>levels</code>: |
| <ul> |
| <li>length-prefixed <code>signed data</code> (by previous cert - if exists) |
| <ul> |
| <li>length-prefixed X.509 <code>certificate</code> (ASN.1 DER form)</li> |
| <li><code>signature algorithm ID</code> (uint32) - algorithm used by cert in |
| previous level</li> |
| </ul> |
| </li> |
| <li><code>flags</code> (uint32) - flags indicating whether or not this cert |
| should be in the self-trusted-old-certs struct, and for which operations.</li> |
| <li><code>signature algorithm ID</code> (uint32) - must match the one from the |
| signed data section in the next level.</li> |
| <li>length-prefixed <code>signature</code> over the above <code>signed |
| data</code></li> |
| </ul> |
| </li> |
| </ul> |
| |
| <h3 id="multiple-certificates">Multiple certificates</h3> |
| <p> |
| Android currently treats an APK signed with multiple certificates as having a |
| unique signing identity separate from the comprising certs. Thus, the |
| proof-of-rotation attribute in the signed-data section forms a directed acyclic |
| graph, that could better be viewed as a singly-linked list, with each set of |
| signers for a given version representing one node. This adds extra complexity to |
| the proof-of-rotation struct (multi-signer version below). In particular, |
| ordering becomes a concern. What's more, it is no longer possible to sign APKs |
| independently, because the proof-of-rotation structure must have the old signing |
| certs signing the new set of certs, rather than signing them one-by-one. For |
| example, an APK signed by key A that wishes to be signed by two new keys B and C |
| could not have the B signer just include a signature by A or B, because that is |
| a different signing identity than B and C. This would mean that the signers must |
| coordinate before building up such a struct. |
| </p> |
| <h4 id="multiple-signers-proof-of-rotation-attribute">Multiple signers |
| proof-of-rotation attribute</h4> |
| <ul> |
| <li>length-prefixed sequence of length-prefixed <code>sets</code>: |
| <ul> |
| <li><code>signed data</code> (by previous set - if exists) |
| <ul> |
| <li>length-prefixed sequence of <code>certificates</code> |
| <ul> |
| <li>length-prefixed X.509 <code>certificate</code> (ASN.1 DER form)</li> |
| </ul> |
| </li> |
| <li>Sequence of <code>signature algorithm IDs </code>(uint32) - one for each |
| certificate from the previous set, in the same order.</li> |
| </ul> |
| </li> |
| <li><code>flags </code>(uint32) - flags indicating whether or not this set of |
| certs should be in the self-trusted-old-certs struct, and for which |
| operations.</li> |
| <li>length-prefixed sequence of length-prefixed <code>signatures</code>: |
| <ul> |
| <li><code>signature algorithm ID</code> (uint32) - must match the one from the |
| signed data section</li> |
| <li>length-prefixed <code>signature</code> over the above |
| <code>signed data</code></li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| |
| <h3 id="multiple-ancestors">Multiple ancestors in proof-of-rotation struct</h3> |
| <p> |
| v3 scheme also doesn't handle two different keys rotating to the same signing |
| key for the same app. This differs from the case of an acquisition, where the |
| acquiring company would like to move the acquired app to use its signing key to |
| share permissions. The acquisition is viewed as a supported use-case because the |
| new app would be distinguished by its package name and could contain its own |
| proof-of-rotation struct. The unsupported case, of the same app having two |
| different paths to get to the same cert, breaks a lot of the assumptions made in |
| the key rotation design. |
| </p> |
| <h2 id="verification">Verification</h2> |
| <p>In Android 9 and higher, APKs can be verified according to the APK Signature |
| Scheme v3, v2 scheme, or v1 scheme. Older platforms ignore v3 signatures and try |
| to verify v2 signatures, then v1. |
| <p> |
| <img src="../images/apk-validation-process.png" alt="APK signature verification process" id="figure1" /> |
| </p> |
| <p class="img-caption"><strong>Figure 1.</strong> APK signature verification |
| process</p> |
| |
| <h3 id="v3-verification">APK Signature Scheme v3 verification</h3> |
| <ol> |
| <li>Locate the APK Signing Block and verify that: |
| <ol> |
| <li>Two size fields of APK Signing Block contain the same value.</li> |
| <li>ZIP Central Directory is immediately followed by ZIP End of Central |
| Directory record.</li> |
| <li>ZIP End of Central Directory is not followed by more data.</li> |
| </ol> |
| </li> |
| <li>Locate the first APK Signature Scheme v3 Block inside the APK Signing Block. |
| If the v3 Block is present, proceed to step 3. Otherwise, fall back to verifying |
| the APK <a href="/security/apksigning/v2#v2-verification">using v2 scheme</a>.</li> |
| <li>For each <code>signer</code> in the APK Signature Scheme v3 Block with a min |
| and max SDK version that is in range of the current platform: |
| <ol> |
| <li>Choose the strongest supported <code>signature algorithm ID</code> from |
| <code>signatures</code>. The strength ordering is up to each |
| implementation/platform version.</li> |
| <li>Verify the corresponding <code>signature</code> from |
| <code>signatures</code> against <code>signed data</code> using <code>public |
| key</code>. (It is now safe to parse <code>signed data</code>.)</li> |
| <li>Verify the min and max SDK versions in the signed data match those |
| specified for the <code>signer</code>.</li> |
| <li>Verify that the ordered list of signature algorithm IDs in |
| <code>digests</code> and <code>signatures</code> is identical. (This is |
| to prevent signature stripping/addition.)</li> |
| <li><a href="/security/apksigning/v2#integrity-protected-contents">Compute |
| the digest of APK contents</a> using the same digest algorithm as the digest |
| algorithm used by the signature algorithm.</li> |
| <li>Verify that the computed digest is identical to the corresponding |
| <code>digest</code> from <code>digests</code>.</li> |
| <li>Verify that SubjectPublicKeyInfo of the first <code>certificate</code> of |
| <code>certificates</code> is identical to <code>public key</code>.</li> |
| <li>If the proof-of-rotation attribute exists for the <code>signer</code> verify |
| that the struct is valid and this <code>signer</code> is the last |
| certificate in the list.</li> |
| </ol> |
| </li> |
| <li>Verification succeeds if exactly one <code>signer</code> was found in range |
| of the current platform and step 3 succeeded for that <code>signer</code>.</li> |
| </ol> |
| |
| <aside class="caution"> |
| <strong>Caution</strong>: APK must not be verified using the v1 or v2 scheme if a |
| failure occurs in step 3 or 4. |
| </aside> |
| |
| <h2 id="validation">Validation</h2> |
| <p> |
| To test that your device supports v3 properly, run the |
| <code>PkgInstallSignatureVerificationTest.java</code> CTS tests in |
| <code>cts/hostsidetests/appsecurity/src/android/appsecurity/cts/</code>. |
| </p> |
| </body> |
| </html> |