• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.appsecurity.cts.v3rotationtests;
18 
19 import static org.junit.Assert.assertArrayEquals;
20 
21 import android.content.pm.PackageInfo;
22 import android.content.pm.PackageManager;
23 import android.content.pm.Signature;
24 import android.test.AndroidTestCase;
25 
26 import java.security.MessageDigest;
27 import java.security.NoSuchAlgorithmException;
28 import java.util.Arrays;
29 import java.util.HashSet;
30 import java.util.Set;
31 
32 /**
33  * On-device tests for APK Signature Scheme v3 based signing certificate rotation
34  */
35 public class V3RotationTest extends AndroidTestCase {
36 
37     private static final String PKG = "android.appsecurity.cts.tinyapp";
38     private static final String COMPANION_PKG = "android.appsecurity.cts.tinyapp_companion";
39     private static final String PERMISSION_NAME = "android.appsecurity.cts.tinyapp.perm";
40 
41     private static final String FIRST_CERT_HEX =
42             "308203773082025fa0030201020204357f7a97300d06092a864886f70d01010b0500306c310b3009060355"
43             + "040613025553310b3009060355040813024341311630140603550407130d4d6f756e7461696e20566965"
44             + "773110300e060355040a1307416e64726f69643110300e060355040b1307556e6b6e6f776e3114301206"
45             + "03550403130b477265656e2044726f6964301e170d3138303133313138303331345a170d343530363138"
46             + "3138303331345a306c310b3009060355040613025553310b300906035504081302434131163014060355"
47             + "0407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355"
48             + "040b1307556e6b6e6f776e311430120603550403130b477265656e2044726f696430820122300d06092a"
49             + "864886f70d01010105000382010f003082010a0282010100bce0517978db6e1eb0255b4704c10fca31b8"
50             + "d8b7465d1512a36712f425009143d418743cbde9c9f7df219907fff376e44298462fb14f5dd7d0edd46e"
51             + "d764f93e82b277146f100616c4d93e97279aefdcf449a5ff000eb72445816039c7afdcd9340f39fc5f0b"
52             + "b4d0e6c4d67a0ec876bf28007cf709667250142385248af89c5fa87b8ef9cc1270577b1721c235bdde97"
53             + "87c04536706947193d38d244c8c6590e54c90b3843506b3e19c5f2c22c38a1a2893c749ad4ddce67b86f"
54             + "f5dcd7dd0d63265fa50036f4bf31f28f2b4c067fb58c95e09ab6c1686c257c3730616659b352b966ed66"
55             + "d93952c60563c9d863aa37c097f646d55c825b450f511eca39198cd70203010001a321301f301d060355"
56             + "1d0e04160414831074e3173e51fbd2ac8ed8c6681f61eca81318300d06092a864886f70d01010b050003"
57             + "820101001fa412618659f40395e38698cd8b7ca9425f63e231e39a6c8e2909af951bbdc5e6307813e25e"
58             + "31502578a56b6e6f08442a400de19449f1c7f87357e55191fd7f30b8735e1298d4c668b9cde563e143d4"
59             + "72bf8005443d8ee386f955136ad0aa16dda7f5b977dc0dee858f954aff2ae4d7473259fb1b1acc1d6161"
60             + "49b12659371ae0298222974be10817156279c9dd8f6cae5265bf15b63fa9f084e789d06b3a9b86d82749"
61             + "c95793acded24b321a31cc20fd12774c7b207325df50c2efcb78a5cf9749f62aafd86d303254880a4476"
62             + "a67801452e82d1e6c91aeb97ca837a91bcefd8324fca491de4ef648d80c6d74f4b66533684040ddad550"
63             + "0ff140edcdacf0a4";
64 
65     private static final String SECOND_CERT_HEX =
66             "3082037b30820263a00302010202044c4a644a300d06092a864886f70d01010b0500306e310b3009060355"
67             + "040613025553310b3009060355040813024341311630140603550407130d4d6f756e7461696e20566965"
68             + "773110300e060355040a1307416e64726f69643110300e060355040b1307556e6b6e6f776e3116301406"
69             + "03550403130d477265656e65722044726f6964301e170d3138303133313138303533385a170d34353036"
70             + "31383138303533385a306e310b3009060355040613025553310b30090603550408130243413116301406"
71             + "03550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e06"
72             + "0355040b1307556e6b6e6f776e311630140603550403130d477265656e65722044726f69643082012230"
73             + "0d06092a864886f70d01010105000382010f003082010a0282010100a4f3741edf04e32e7047aaadc2ce"
74             + "de0164a2847149aa7fad054dab59e70c1078dd2d5946cec64809f79551395478b08f3e0286d452fa39b9"
75             + "e6804e965a44210a61bd5cfe3c8ac0ec86017c0e91260248daa1fd7a11b1b1b519216a40d02db49e754a"
76             + "6380357c45ef1531996e4c37c13e2f507f3a9296eb52235248d0172efe4ed7bac537fe2435f03d66c5e3"
77             + "e5cbf60d77f3088bc22718ded09009d6414106d1301d1a5abf71aa5dc6469bb73b29b2cc9c09b9c42e8f"
78             + "8e81e7fc9b24ad1cb0c3e2e2832d0570bdeb87a3ff8f49aae05b03164fb3c225745b70134c6b7aaf081f"
79             + "514058776bd28a0c0a152bf45b3eddc7f2c4aaed4eace0cab67ef4650213303f0203010001a321301f30"
80             + "1d0603551d0e04160414f0c3dacf02d9583200d4d386a40341aee82dd859300d06092a864886f70d0101"
81             + "0b050003820101003a63a93be986740158574239310e987cdcdc86f735867789c2b56f8ffa7ce901a9f2"
82             + "2b0c374d345aa996a37c7474824dbf72186d1eedaa6aae0574fd1996f501def32e62703ee4010a7058df"
83             + "f0d608df1176bdbe93ebd3910172fc146307d0961a57d95806eeabc1e54b81273d9449f0f68511288377"
84             + "c82f87a032d1379260365ef83c93f1bf4c0af959b426794c558c0357fe61271ed0fb054e916e0bab8600"
85             + "3bcc16ce53f7d2c8d05b83072115b0fb2c671c2266813f1a407ca911c47f27665debfa63bc4e4071730a"
86             + "a477acbe6eecc8d575511b2b77a3551f040ccf21792f74cd95c84e3ff87ad03851db81d164c836830e31"
87             + "8208a52dcdc77e376f73b96d";
88 
89     // These are the hex encodings of the der form of the pkgsigverify/ec-p256[_2] certs used to
90     // sign APKs that are part of this test.
91     private static final String EC_P256_FIRST_CERT_HEX =
92             "3082016c30820111a003020102020900ca0fb64dfb66e772300a06082a86"
93                     + "48ce3d04030230123110300e06035504030c0765632d70323536301e170d"
94                     + "3136303333313134353830365a170d3433303831373134353830365a3012"
95                     + "3110300e06035504030c0765632d703235363059301306072a8648ce3d02"
96                     + "0106082a8648ce3d03010703420004a65f113d22cb4913908307ac31ee2b"
97                     + "a0e9138b785fac6536d14ea2ce90d2b4bfe194b50cdc8e169f54a73a991e"
98                     + "f0fa76329825be078cc782740703da44b4d7eba350304e301d0603551d0e"
99                     + "04160414d4133568b95b30158b322071ea8c43ff5b05ccc8301f0603551d"
100                     + "23041830168014d4133568b95b30158b322071ea8c43ff5b05ccc8300c06"
101                     + "03551d13040530030101ff300a06082a8648ce3d04030203490030460221"
102                     + "00f504a0866caef029f417142c5cb71354c79ffcd1d640618dfca4f19e16"
103                     + "db78d6022100f8eea4829799c06cad08c6d3d2d2ec05e0574154e747ea0f"
104                     + "dbb8042cb655aadd";
105 
106     private static final String EC_P256_SECOND_CERT_HEX =
107             "3082016d30820113a0030201020209008855bd1dd2b2b225300a06082a86"
108                     + "48ce3d04030230123110300e06035504030c0765632d70323536301e170d"
109                     + "3138303731333137343135315a170d3238303731303137343135315a3014"
110                     + "3112301006035504030c0965632d703235365f323059301306072a8648ce"
111                     + "3d020106082a8648ce3d030107034200041d4cca0472ad97ee3cecef0da9"
112                     + "3d62b450c6788333b36e7553cde9f74ab5df00bbba6ba950e68461d70bbc"
113                     + "271b62151dad2de2bf6203cd2076801c7a9d4422e1a350304e301d060355"
114                     + "1d0e041604147991d92b0208fc448bf506d4efc9fff428cb5e5f301f0603"
115                     + "551d23041830168014d4133568b95b30158b322071ea8c43ff5b05ccc830"
116                     + "0c0603551d13040530030101ff300a06082a8648ce3d0403020348003045"
117                     + "02202769abb1b49fc2f53479c4ae92a6631dabfd522c9acb0bba2b43ebeb"
118                     + "99c63011022100d260fb1d1f176cf9b7fa60098bfd24319f4905a3e5fda1"
119                     + "00a6fe1a2ab19ff09e";
120 
121     private static final String EC_P256_THIRD_CERT_HEX =
122             "3082016e30820115a0030201020209008394f5cad16a89a7300a06082a86"
123                     + "48ce3d04030230143112301006035504030c0965632d703235365f32301e"
124                     + "170d3138303731343030303532365a170d3238303731313030303532365a"
125                     + "30143112301006035504030c0965632d703235365f333059301306072a86"
126                     + "48ce3d020106082a8648ce3d03010703420004f31e62430e9db6fc5928d9"
127                     + "75fc4e47419bacfcb2e07c89299e6cd7e344dd21adfd308d58cb49a1a2a3"
128                     + "fecacceea4862069f30be1643bcc255040d8089dfb3743a350304e301d06"
129                     + "03551d0e041604146f8d0828b13efaf577fc86b0e99fa3e54bcbcff0301f"
130                     + "0603551d230418301680147991d92b0208fc448bf506d4efc9fff428cb5e"
131                     + "5f300c0603551d13040530030101ff300a06082a8648ce3d040302034700"
132                     + "30440220256bdaa2784c273e4cc291a595a46779dee9de9044dc9f7ab820"
133                     + "309567df9fe902201a4ad8c69891b5a8c47434fe9540ed1f4979b5fad348"
134                     + "3f3fa04d5677355a579e";
135 
136     private static final String EC_P256_FOURTH_CERT_HEX =
137             "3082017b30820120a00302010202146c8cb8a818433c1e6431fb16fb3ae0"
138                     + "fb5ad60aa7300a06082a8648ce3d04030230143112301006035504030c09"
139                     + "65632d703235365f33301e170d3230303531333139313532385a170d3330"
140                     + "303531313139313532385a30143112301006035504030c0965632d703235"
141                     + "365f343059301306072a8648ce3d020106082a8648ce3d03010703420004"
142                     + "db4a60031e79ad49cb759007d6855d4469b91c8bab065434f2fba971ade7"
143                     + "e4d19599a0f67b5e708cfda7543e5630c3769d37e093640d7c768a15144c"
144                     + "d0e5dcf4a350304e301d0603551d0e041604146e78970332554336b6ee89"
145                     + "24eaa70230e393f678301f0603551d230418301680146f8d0828b13efaf5"
146                     + "77fc86b0e99fa3e54bcbcff0300c0603551d13040530030101ff300a0608"
147                     + "2a8648ce3d0403020349003046022100ce786e79ec7547446082e9caf910"
148                     + "614ff80758f9819fb0f148695067abe0fcd4022100a4881e332ddec2116a"
149                     + "d2b59cf891d0f331ff7e27e77b7c6206c7988d9b539330";
150 
151     private static final String EC_P256_FIFTH_CERT_HEX =
152             "3082017930820120a003020102021450e1ee31d9f9259eadd3514a988dfa"
153                     + "4bf0e7153a300a06082a8648ce3d04030230143112301006035504030c09"
154                     + "65632d703235365f34301e170d3232303331353031303530385a170d3332"
155                     + "303331323031303530385a30143112301006035504030c0965632d703235"
156                     + "365f353059301306072a8648ce3d020106082a8648ce3d03010703420004"
157                     + "75703c54a432df580e86848817b491ee028324257dc31e891fc4af93d9bd"
158                     + "4bf026b39c7a145213753c344c2a12056ce7ccc21b40be8f9fad28639dca"
159                     + "dbe63b4ea350304e301d0603551d0e04160414e8cc32db6a21f86c75f3c1"
160                     + "96c0b199885498b73b301f0603551d230418301680146e78970332554336"
161                     + "b6ee8924eaa70230e393f678300c0603551d13040530030101ff300a0608"
162                     + "2a8648ce3d040302034700304402202ded97f7ddcd3229ad26783436186f"
163                     + "1e74247a4422baf99f1eeb715dfe7e895502207814248b1b7742f3009602"
164                     + "bdc96f66529884fc605a070ff25c84648c8fccb44b";
165 
testHasPerm()166     public void testHasPerm() throws Exception {
167         PackageManager pm = getContext().getPackageManager();
168         assertTrue(PERMISSION_NAME + " not granted to " + COMPANION_PKG,
169                 pm.checkPermission(PERMISSION_NAME, COMPANION_PKG)
170                         == PackageManager.PERMISSION_GRANTED);
171     }
172 
testHasNoPerm()173     public void testHasNoPerm() throws Exception {
174         PackageManager pm = getContext().getPackageManager();
175         assertFalse(PERMISSION_NAME + " granted to " + COMPANION_PKG,
176                 pm.checkPermission(PERMISSION_NAME, COMPANION_PKG)
177                         == PackageManager.PERMISSION_GRANTED);
178     }
179 
testGetSignaturesShowsOld()180     public void testGetSignaturesShowsOld() throws Exception {
181         // to prevent breakage due to signing certificate rotation, we report the oldest signing
182         // certificate in the now-deprecated PackageInfo signatures field.  Make sure that when
183         // rotating, it still displays the older cert.
184         PackageManager pm = getContext().getPackageManager();
185         PackageInfo pi = pm.getPackageInfo(PKG, PackageManager.GET_SIGNATURES);
186         assertNotNull("Failed to get signatures in PackageInfo of " + PKG, pi.signatures);
187         assertEquals("PackageInfo for " + PKG + "contains multiple entries",
188                 1, pi.signatures.length);
189         assertEquals("signature mismatch for " + PKG + ", expected old signing certificate",
190                 pi.signatures[0].toCharsString(), FIRST_CERT_HEX);
191     }
192 
testGetSigningCertificatesShowsAll()193     public void testGetSigningCertificatesShowsAll() throws Exception {
194         // make sure our shiny new GET_SIGNATURES replacement does its job.  It should return all of
195         // the certificates in an app's provided history, including its current one
196         PackageManager pm = getContext().getPackageManager();
197         PackageInfo pi = pm.getPackageInfo(PKG, PackageManager.GET_SIGNING_CERTIFICATES);
198         assertNotNull("Failed to get signatures in PackageInfo of " + PKG,
199                 pi.signingInfo);
200         assertFalse("Multiple signing certificates found in signing certificate history for " + PKG,
201                 pi.signingInfo.hasMultipleSigners());
202         Signature[] signingHistory = pi.signingInfo.getSigningCertificateHistory();
203         int numSigningSets = signingHistory.length;
204         assertEquals("PackageInfo for " + PKG + "contains the wrong number of signing certificat "
205                 + " rotations.  Expected 2 (corresponding to one rotation). Found: "
206                 + numSigningSets, 2, numSigningSets);
207         // check to see if we match the certs for which we're looking
208         boolean matchedFirst = false;
209         boolean matchedSecond = false;
210         for (int i = 0; i < numSigningSets; i++) {
211             String reportedCert = signingHistory[i].toCharsString();
212             if (FIRST_CERT_HEX.equals(reportedCert)) {
213                 matchedFirst = true;
214             } else if (SECOND_CERT_HEX.equals(reportedCert)) {
215                 matchedSecond = true;
216             }
217         }
218         assertTrue("Old signing certificate not found for " + PKG + " expected "
219                 + FIRST_CERT_HEX, matchedFirst);
220         assertTrue("Current signing certificate not found for " + PKG + " expected "
221                 + SECOND_CERT_HEX, matchedSecond);
222     }
223 
testGetApkContentsSignersShowsCurrent()224     public void testGetApkContentsSignersShowsCurrent() throws Exception {
225         // The SigningInfo instance returned from GET_SIGNING_CERTIFICATES provides an option to
226         // obtain only the current signer through getApkContentsSigners.
227         PackageManager pm = getContext().getPackageManager();
228         PackageInfo pi = pm.getPackageInfo(PKG, PackageManager.GET_SIGNING_CERTIFICATES);
229         assertNotNull("Failed to get signatures in Package Info of " + PKG, pi.signingInfo);
230         assertFalse("Multiple signing certificates found in signing certificate history for " + PKG,
231                 pi.signingInfo.hasMultipleSigners());
232         assertExpectedSignatures(pi.signingInfo.getApkContentsSigners(), EC_P256_SECOND_CERT_HEX);
233     }
234 
testGetApkContentsSignersShowsMultipleSigners()235     public void testGetApkContentsSignersShowsMultipleSigners() throws Exception {
236         // Similar to the test above when GET_SIGNING_CERTIFICATES is used to obtain the signers
237         // getApkContentSigners should return all of the current signatures when there are multiple
238         // V1 / V2 signers.
239         PackageManager pm = getContext().getPackageManager();
240         PackageInfo pi = pm.getPackageInfo(PKG, PackageManager.GET_SIGNING_CERTIFICATES);
241         assertNotNull("Failed to get signatures in PackageInfo of " + PKG,
242                 pi.signingInfo);
243         assertTrue("Multiple signing certificates should have been reported for " + PKG,
244                 pi.signingInfo.hasMultipleSigners());
245         assertExpectedSignatures(pi.signingInfo.getApkContentsSigners(), EC_P256_FIRST_CERT_HEX,
246                 EC_P256_SECOND_CERT_HEX);
247     }
248 
testGetSigningCertificateHistoryReturnsSignersInOrder()249     public void testGetSigningCertificateHistoryReturnsSignersInOrder() throws Exception {
250         // The test package used for this should be signed with five keys in the signing lineage,
251         // and the signatures returned from SigningInfo#getSigningCertificateHistory should be
252         // returned in their rotated order.
253         final String[] expectedSignatures = new String[]{
254                 EC_P256_FIRST_CERT_HEX,
255                 EC_P256_SECOND_CERT_HEX,
256                 EC_P256_THIRD_CERT_HEX,
257                 EC_P256_FOURTH_CERT_HEX,
258                 EC_P256_FIFTH_CERT_HEX,
259         };
260 
261         PackageManager pm = getContext().getPackageManager();
262         PackageInfo pi = pm.getPackageInfo(PKG, PackageManager.GET_SIGNING_CERTIFICATES);
263         assertNotNull("Failed to get signatures in PackageInfo of " + PKG,
264                 pi.signingInfo);
265         String[] actualSignatures = Arrays.stream(pi.signingInfo.getSigningCertificateHistory())
266                 .map(Signature::toCharsString)
267                 .toArray(String[]::new);
268         assertArrayEquals(expectedSignatures, actualSignatures);
269     }
270 
testHasSigningCertificate()271     public void testHasSigningCertificate() throws Exception {
272         // make sure that hasSigningCertificate() reports that both certificates in the signing
273         // history are present
274         PackageManager pm = getContext().getPackageManager();
275         byte[] firstCertBytes = fromHexToByteArray(FIRST_CERT_HEX);
276         assertTrue("Old signing certificate not found for " + PKG,
277                pm.hasSigningCertificate(PKG, firstCertBytes, PackageManager.CERT_INPUT_RAW_X509));
278         byte[] secondCertBytes = fromHexToByteArray(SECOND_CERT_HEX);
279         assertTrue("Current signing certificate not found for " + PKG,
280                 pm.hasSigningCertificate(PKG, secondCertBytes, PackageManager.CERT_INPUT_RAW_X509));
281     }
282 
testHasSigningCertificateSha256()283     public void testHasSigningCertificateSha256() throws Exception {
284         // make sure that hasSigningCertificate() reports that both certificates in the signing
285         // history are present
286         PackageManager pm = getContext().getPackageManager();
287         byte[] firstCertBytes = computeSha256DigestBytes(fromHexToByteArray(FIRST_CERT_HEX));
288 
289         assertTrue("Old signing certificate not found for " + PKG,
290                 pm.hasSigningCertificate(PKG, firstCertBytes, PackageManager.CERT_INPUT_SHA256));
291         byte[] secondCertBytes = computeSha256DigestBytes(fromHexToByteArray(SECOND_CERT_HEX));
292         assertTrue("Current signing certificate not found for " + PKG,
293                 pm.hasSigningCertificate(PKG, secondCertBytes, PackageManager.CERT_INPUT_SHA256));
294     }
295 
testHasSigningCertificateByUid()296     public void testHasSigningCertificateByUid() throws Exception {
297         // make sure that hasSigningCertificate() reports that both certificates in the signing
298         // history are present
299         PackageManager pm = getContext().getPackageManager();
300         int uid = pm.getPackageUid(PKG, 0);
301         byte[] firstCertBytes = fromHexToByteArray(FIRST_CERT_HEX);
302         assertTrue("Old signing certificate not found for " + PKG,
303                 pm.hasSigningCertificate(uid, firstCertBytes, PackageManager.CERT_INPUT_RAW_X509));
304         byte[] secondCertBytes = fromHexToByteArray(SECOND_CERT_HEX);
305         assertTrue("Current signing certificate not found for " + PKG,
306                 pm.hasSigningCertificate(uid, secondCertBytes, PackageManager.CERT_INPUT_RAW_X509));
307     }
308 
testHasSigningCertificateByUidSha256()309     public void testHasSigningCertificateByUidSha256() throws Exception {
310         // make sure that hasSigningCertificate() reports that both certificates in the signing
311         // history are present
312         PackageManager pm = getContext().getPackageManager();
313         int uid = pm.getPackageUid(PKG, 0);
314         byte[] firstCertBytes = computeSha256DigestBytes(fromHexToByteArray(FIRST_CERT_HEX));
315 
316         assertTrue("Old signing certificate not found for " + PKG,
317                 pm.hasSigningCertificate(uid, firstCertBytes, PackageManager.CERT_INPUT_SHA256));
318         byte[] secondCertBytes = computeSha256DigestBytes(fromHexToByteArray(SECOND_CERT_HEX));
319         assertTrue("Current signing certificate not found for " + PKG,
320                 pm.hasSigningCertificate(uid, secondCertBytes, PackageManager.CERT_INPUT_SHA256));
321     }
322 
testUsingOriginalSigner()323     public void testUsingOriginalSigner() throws Exception {
324         // Verifies the platform only recognized the original signing key during installation.
325         PackageManager pm = getContext().getPackageManager();
326         PackageInfo pi = pm.getPackageInfo(PKG, PackageManager.GET_SIGNING_CERTIFICATES);
327         assertFalse(
328                 "APK is expected to use the original signing key, but past signing certificates "
329                         + "were reported",
330                 pi.signingInfo.hasPastSigningCertificates());
331         assertExpectedSignatures(pi.signingInfo.getApkContentsSigners(), EC_P256_FIRST_CERT_HEX);
332         byte[] secondCertBytes = fromHexToByteArray(EC_P256_SECOND_CERT_HEX);
333         assertFalse("APK is not expected to have the rotated key in its signing lineage",
334                 pm.hasSigningCertificate(PKG, secondCertBytes, PackageManager.CERT_INPUT_RAW_X509));
335     }
336 
testUsingRotatedSigner()337     public void testUsingRotatedSigner() throws Exception {
338         // Verifies the platform recognized the rotated signing key during installation.
339         PackageManager pm = getContext().getPackageManager();
340         PackageInfo pi = pm.getPackageInfo(PKG, PackageManager.GET_SIGNING_CERTIFICATES);
341         assertTrue(
342                 "APK is expected to be signed with the rotated signing key, but past signing "
343                         + "certificates were not reported",
344                 pi.signingInfo.hasPastSigningCertificates());
345         assertExpectedSignatures(pi.signingInfo.getApkContentsSigners(), EC_P256_SECOND_CERT_HEX);
346         assertExpectedSignatures(pi.signingInfo.getSigningCertificateHistory(),
347                 EC_P256_FIRST_CERT_HEX, EC_P256_SECOND_CERT_HEX);
348         byte[] firstCertBytes = fromHexToByteArray(EC_P256_FIRST_CERT_HEX);
349         assertTrue("APK is expected to have the original key in its signing lineage",
350                 pm.hasSigningCertificate(PKG, firstCertBytes, PackageManager.CERT_INPUT_RAW_X509));
351     }
352 
fromHexToByteArray(String str)353     private  static byte[] fromHexToByteArray(String str) {
354         if (str == null || str.length() == 0 || str.length() % 2 != 0) {
355             return null;
356         }
357 
358         final char[] chars = str.toCharArray();
359         final int charLength = chars.length;
360         final byte[] bytes = new byte[charLength / 2];
361 
362         for (int i = 0; i < bytes.length; i++) {
363             bytes[i] =
364                     (byte)(((getIndex(chars[i * 2]) << 4) & 0xF0)
365                             | (getIndex(chars[i * 2 + 1]) & 0x0F));
366         }
367         return bytes;
368     }
369 
370     // copy of ByteStringUtils - lowercase version (to match inputs)
getIndex(char c)371     private static int getIndex(char c) {
372         final char[] HEX_ARRAY = "0123456789abcdef".toCharArray();
373         for (int i = 0; i < HEX_ARRAY.length; i++) {
374             if (HEX_ARRAY[i] == c) {
375                 return i;
376             }
377         }
378         return -1;
379     }
380 
computeSha256DigestBytes(byte[] data)381     private static byte[] computeSha256DigestBytes(byte[] data) throws NoSuchAlgorithmException {
382         MessageDigest messageDigest = MessageDigest.getInstance("SHA256");
383         messageDigest.update(data);
384         return messageDigest.digest();
385     }
386 
assertExpectedSignatures(Signature[] signatures, String... expectedSignatures)387     private static void assertExpectedSignatures(Signature[] signatures,
388             String... expectedSignatures) throws Exception {
389         int numSigners = signatures.length;
390         assertEquals("An unexpected number of signatures was returned, expected "
391                         + expectedSignatures.length + ", but received " + signatures.length,
392                 expectedSignatures.length, numSigners);
393         Set<String> expectedSignatureSet = new HashSet<>(Arrays.asList(expectedSignatures));
394         for (int i = 0; i < numSigners; i++) {
395             String reportedCert = signatures[i].toCharsString();
396             // Remove the reported certificate from the set to ensure duplicates are not matched.
397             if (!expectedSignatureSet.remove(reportedCert)) {
398                 fail("Received an unexpected signature during the test: " + reportedCert);
399             }
400         }
401     }
402 }
403