blob: f15428e67f5e230a1ecb1f4bb3ae6a8c1d5cf10d [file] [log] [blame]
<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>