aboutsummaryrefslogtreecommitdiff
path: root/en/security/apksigning/v2.html
blob: 4497d6302a014dcd577d8d50e6f9e0a18af0a7f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
<html devsite>
  <head>
    <title>APK Signature Scheme v2</title>
    <meta name="project_path" value="/_project.yaml" />
    <meta name="book_path" value="/_book.yaml" />
  </head>
  <body>
  <!--
      Copyright 2017 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.
  -->



<p>
APK Signature Scheme v2 is a whole-file signature scheme that increases
verification speed and <a
href="#integrity-protected-contents">strengthens integrity guarantees</a> by
detecting any changes to the protected parts of the APK.
</p>

<p>
Signing using APK Signature Scheme v2 inserts an <a
href="#apk-signing-block">APK Signing Block</a> into the APK file immediately
before the ZIP Central Directory section. Inside the APK Signing Block, v2
signatures and signer identity information are stored in an <a
href="#apk-signature-scheme-v2-block">APK Signature Scheme v2 Block</a>.
</p>

<p>
  <img src="../images/apk-before-after-signing.png" alt="APK before and after signing" id="figure1" />
</p>
<p class="img-caption"><strong>Figure 1.</strong> APK before and after signing</p>

<p>
APK Signature Scheme v2 was introduced in Android 7.0 (Nougat). To make
a APK installable on Android 6.0 (Marshmallow) and older devices, the
APK should be signed using <a href="index.html#v1">JAR signing</a> before being
signed with the v2 scheme.
</p>


<h2 id="apk-signing-block">APK Signing Block</h2>
<p>
To maintain backward-compatibility with the current APK format, v2 and newer APK
signatures are stored inside an APK Signing Block, a new container introduced to
support APK Signature Scheme v2. In an APK file, the APK Signing Block is located
immediately before the ZIP Central Directory, which is located at the end of the file.
</p>

<p>
The block contains ID-value pairs wrapped in a way that makes it easier to
locate the block in the APK. The v2 signature of the APK is stored as an ID-value
pair with ID 0x7109871a.
</p>

<h3 id="apk-signing-block-format">Format</h3>
<p>
The format of the APK Signing Block is as follows (all numeric fields are
little-endian):
</p>

<ul>
  <li><code>size of block</code> in bytes (excluding this field) (uint64)</li>
  <li>Sequence of uint64-length-prefixed ID-value pairs:
    <ul>
      <li><code>ID</code> (uint32)</li>
      <li><code>value</code> (variable-length: length of the pair - 4 bytes)</li>
    </ul>
  </li>
  <li><code>size of block</code> in bytes—same as the very first field (uint64)</li>
  <li><code>magic</code> “APK Sig Block 42” (16 bytes)</li>
</ul>

<p>
APK is parsed by first finding the start of the ZIP Central Directory (by
finding the ZIP End of Central Directory record at the end of the file, then
reading the start offset of the Central Directory from the record). The
<code>magic</code> value provides a quick way to establish that what precedes
Central Directory is likely the APK Signing Block. The <code>size of
block</code> value then efficiently points to the start of the block in the
file.
</p>

<p>
ID-value pairs with unknown IDs should be ignored when interpreting the
block.
</p>


<h2 id="apk-signature-scheme-v2-block">APK Signature Scheme v2 Block</h2>
<p>
APK is signed by one or more signers/identities, each represented by a signing
key. This information is stored as an APK Signature Scheme v2 Block. For each
signer, the following information is stored:
</p>

<ul>
  <li>(signature algorithm, digest, signature) tuples. The digest is stored to
decouple  signature verification from integrity checking of the APK’s contents.</li>
  <li>X.509 certificate chain representing the signer’s identity.</li>
  <li>Additional attributes as key-value pairs.</li>
</ul>

<p>
For each signer, the APK is verified using a supported signature from the
provided list. Signatures with unknown signature algorithms are ignored. It is
up to each implementation to choose which signature to use when multiple
supported signatures are encountered. This enables the introduction of stronger
signing methods in the future in a backward-compatible way. The suggested
approach is to verify the strongest signature.
</p>

<h3 id="apk-signature-scheme-v2-block-format">Format</h3>
<p>
APK Signature Scheme v2 Block is stored inside the APK Signing Block under ID
<code>0x7109871a</code>.
</p>

<p>
The format of the APK Signature Scheme v2 Block is as follows (all numeric
values are little-endian, all length-prefixed fields use uint32 for length):
</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> (uint32)</li>
              <li>(length-prefixed) <code>digest</code>—see
              <a href="#integrity-protected-contents">Integrity-protected Contents</a></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>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>
            </ul>
          </li>
        </ul>
      </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>

<h4 id="signature-algorithm-ids">Signature Algorithm IDs</h4>
<ul>
  <li>0x0101—RSASSA-PSS with SHA2-256 digest, SHA2-256 MGF1, 32 bytes of salt,
      trailer: 0xbc</li>
  <li>0x0102—RSASSA-PSS with SHA2-512 digest, SHA2-512 MGF1, 64 bytes of salt,
      trailer: 0xbc</li>
  <li>0x0103—RSASSA-PKCS1-v1_5 with SHA2-256 digest. This is for build systems
      which require deterministic signatures.</li>
  <li>0x0104—RSASSA-PKCS1-v1_5 with SHA2-512 digest. This is for build systems
      which require deterministic signatures.</li>
  <li>0x0201—ECDSA with SHA2-256 digest</li>
  <li>0x0202—ECDSA with SHA2-512 digest</li>
  <li>0x0301—DSA with SHA2-256 digest</li>
</ul>

<p>
All of the above signature algorithms are supported by the Android platform.
Signing tools may support a subset of the algorithms.
</p>

<p>
<strong>Supported keys sizes and EC curves:</strong>
</p>

<ul>
  <li>RSA: 1024, 2048, 4096, 8192, 16384</li>
  <li>EC: NIST P-256, P-384, P-521</li>
  <li>DSA: 1024, 2048, 3072</li>
</ul>

<h2 id="integrity-protected-contents">Integrity-protected contents</h2>

<p>
For the purposes of protecting APK contents, an APK consists of four sections:
</p>

<ol>
  <li>Contents of ZIP entries (from offset 0 until the start of APK Signing Block)</li>
  <li>APK Signing Block</li>
  <li>ZIP Central Directory</li>
  <li>ZIP End of Central Directory</li>
</ol>

<p>
  <img src="../images/apk-sections.png" alt="APK sections after signing" id="figure2" />
</p>
<p class="img-caption"><strong>Figure 2.</strong> APK sections after signing</p>

<p>
APK Signature Scheme v2 protects the integrity of sections 1, 3, 4, and the
<code>signed data</code> blocks of the APK Signature Scheme v2 Block contained
inside section 2.
</p>

<p>
The integrity of sections 1, 3, and 4 is protected by one or more digests of
their contents stored in <code>signed data</code> blocks which are, in
turn, protected by one or more signatures.
</p>

<p>
The digest over sections 1, 3, and 4 is computed as follows, similar to a
two-level <a href="https://en.wikipedia.org/wiki/Merkle_tree">Merkle tree</a>.
Each section is split into consecutive 1 MB (2<sup>20</sup> bytes) chunks. The last chunk
in each section may be shorter. The digest of each chunk is computed over the
concatenation of byte <code>0xa5</code>, the chunk’s length in bytes
(little-endian uint32), and the chunk’s contents. The top-level digest is
computed over the concatenation of byte <code>0x5a</code>, the number of chunks
(little-endian uint32), and the concatenation of digests of the chunks in the
order the chunks appear in the APK. The digest is computed in chunked fashion to
enable to speed up the computation by parallelizing it.
</p>

<p>
  <img src="../images/apk-integrity-protection.png" alt="APK digest" id="figure3" />
</p>
<p class="img-caption"><strong>Figure 3.</strong> APK digest</p>

<p>
Protection of section 4 (ZIP End of Central Directory) is complicated by the
section containing the offset of ZIP Central Directory. The offset changes when
the size of the APK Signing Block changes, for instance, when a new signature is
added. Thus, when computing digest over the ZIP End of Central Directory, the
field containing the offset of ZIP Central Directory must be treated as
containing the offset of the APK Signing Block.
</p>

<h2 id="rollback-protections">Rollback Protections</h2>
<p>
An attacker could attempt to have a v2-signed APK verified as a v1-signed APK on
Android platforms that support verifying v2-signed APK. To mitigate this attack,
v2-signed APKs that are also v1-signed must contain an X-Android-APK-Signed
attribute in the main section of their META-INF/*.SF files. The value of the
attribute is a comma-separated set of APK signature scheme IDs (the ID of this
scheme is 2). When verifying the v1 signature, APK verifier is required to
reject APKs which do not have a signature for the APK signature scheme the
verifier prefers from this set (e.g., v2 scheme). This protection relies on the
fact that contents META-INF/*.SF files are protected by v1 signatures. See the
section on
<a href="#v1-verification">JAR signed APK verification</a>.
</p>

<p>
An attacker could attempt to strip stronger signatures from the APK Signature
Scheme v2 Block. To mitigate this attack, the list of signature algorithm IDs
with which the APK was being signed is stored in the <code>signed data</code>
block which is protected by each signature.
</p>

<h2 id="verification">Verification</h2>

<p>In Android 7.0, APKs can be verified according to the APK Signature Scheme v2
(v2 scheme) or JAR signing (v1 scheme). Older platforms ignore v2 signatures
and only verify v1 signatures.
</p>

<p>
  <img src="../images/apk-validation-process.png" alt="APK signature verification process" id="figure4" />
</p>
<p class="img-caption"><strong>Figure 4.</strong> APK signature verification
process (new steps in red)</p>

<h3 id="v2-verification">APK Signature Scheme v2 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 v2 Block inside the APK Signing Block.
      If the v2 Block if present, proceed to step 3. Otherwise, fall back to
      verifying the APK
      <a href="#v1-verification">using v1 scheme</a>.</li>
  <li>For each <code>signer</code> in the APK Signature Scheme v2 Block:
    <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 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="#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>
    </ol>
  </li>
  <li>Verification succeeds if at least one <code>signer</code> was found and
  step 3 succeeded for each found <code>signer</code>.</li>
</ol>

<p class="note"><strong>Note</strong>: APK must not be verified using
the v1 scheme if a failure occurs in step 3 or 4.
</p>

<h3 id="v1-verification">JAR-signed APK verification (v1 scheme)</h3>
<p>
The JAR-signed APK is a
<a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html#Signed_JAR_File">standard
signed JAR</a>, which must contain exactly the entries listed in
META-INF/MANIFEST.MF and where all entries must be signed by the same set of
signers. Its integrity is verified as follows:
</p>

<ol>
  <li>Each signer is represented by a META-INF/&lt;signer&gt;.SF and
  META-INF/&lt;signer&gt;.(RSA|DSA|EC) JAR entry.</li>
  <li>&lt;signer&gt;.(RSA|DSA|EC) is a
      <a href="https://tools.ietf.org/html/rfc5652">PKCS #7 CMS ContentInfo
      with SignedData structure</a> whose signature is verified over the
      &lt;signer&gt;.SF file.</li>
  <li>&lt;signer&gt;.SF file contains a whole-file digest of the META-INF/MANIFEST.MF
  and digests of each section of META-INF/MANIFEST.MF. The whole-file digest of
  the MANIFEST.MF is verified. If that fails, the digest of each MANIFEST.MF
  section is verified instead.</li>
  <li>META-INF/MANIFEST.MF contains, for each integrity-protected JAR entry, a
  correspondingly named section containing the digest of the entry’s uncompressed
  contents. All these digests are verified.</li>
  <li>APK verification fails if the APK contains JAR entries which are not listed
  in the MANIFEST.MF and are not part of JAR signature.</li>
</ol>

<p>
The protection chain is thus &lt;signer&gt;.(RSA|DSA|EC) -> &lt;signer&gt;.SF -> MANIFEST.MF
-> contents of each integrity-protected JAR entry.
</p>


  </body>
</html>