Home | History | Annotate | Download | only in backup
      1 /*
      2  * Copyright (C) 2016 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 package com.android.server.pm.backup;
     17 
     18 import static com.google.common.truth.Truth.assertThat;
     19 
     20 import static org.junit.Assert.assertFalse;
     21 import static org.junit.Assert.assertTrue;
     22 import static org.junit.Assert.assertEquals;
     23 import static org.mockito.Mockito.doReturn;
     24 import static org.mockito.Mockito.mock;
     25 import static org.mockito.Mockito.when;
     26 
     27 import android.content.pm.ApplicationInfo;
     28 import android.content.pm.PackageInfo;
     29 import android.content.pm.PackageManagerInternal;
     30 import android.content.pm.PackageParser;
     31 import android.content.pm.PackageParser.Package;
     32 import android.content.pm.Signature;
     33 import android.content.pm.SigningInfo;
     34 import android.test.MoreAsserts;
     35 import android.platform.test.annotations.Presubmit;
     36 import android.support.test.filters.SmallTest;
     37 import android.support.test.runner.AndroidJUnit4;
     38 
     39 import com.android.server.backup.BackupUtils;
     40 
     41 import org.junit.Before;
     42 import org.junit.Test;
     43 import org.junit.runner.RunWith;
     44 
     45 import java.util.ArrayList;
     46 import java.util.Arrays;
     47 
     48 @SmallTest
     49 @Presubmit
     50 @RunWith(AndroidJUnit4.class)
     51 public class BackupUtilsTest {
     52 
     53     private static final Signature SIGNATURE_1 = generateSignature((byte) 1);
     54     private static final Signature SIGNATURE_2 = generateSignature((byte) 2);
     55     private static final Signature SIGNATURE_3 = generateSignature((byte) 3);
     56     private static final Signature SIGNATURE_4 = generateSignature((byte) 4);
     57     private static final byte[] SIGNATURE_HASH_1 = BackupUtils.hashSignature(SIGNATURE_1);
     58     private static final byte[] SIGNATURE_HASH_2 = BackupUtils.hashSignature(SIGNATURE_2);
     59     private static final byte[] SIGNATURE_HASH_3 = BackupUtils.hashSignature(SIGNATURE_3);
     60     private static final byte[] SIGNATURE_HASH_4 = BackupUtils.hashSignature(SIGNATURE_4);
     61 
     62     private PackageManagerInternal mMockPackageManagerInternal;
     63 
     64     @Before
     65     public void setUp() throws Exception {
     66         mMockPackageManagerInternal = mock(PackageManagerInternal.class);
     67     }
     68 
     69     @Test
     70     public void signaturesMatch_targetIsNull_returnsFalse() throws Exception {
     71         ArrayList<byte[]> storedSigHashes = new ArrayList<>();
     72         storedSigHashes.add(SIGNATURE_HASH_1);
     73         boolean result = BackupUtils.signaturesMatch(storedSigHashes, null,
     74                 mMockPackageManagerInternal);
     75 
     76         assertThat(result).isFalse();
     77     }
     78 
     79     @Test
     80     public void signaturesMatch_systemApplication_returnsTrue() throws Exception {
     81         PackageInfo packageInfo = new PackageInfo();
     82         packageInfo.packageName = "test";
     83         packageInfo.applicationInfo = new ApplicationInfo();
     84         packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
     85 
     86         ArrayList<byte[]> storedSigHashes = new ArrayList<>();
     87         storedSigHashes.add(SIGNATURE_HASH_1);
     88         boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
     89                 mMockPackageManagerInternal);
     90 
     91         assertThat(result).isTrue();
     92     }
     93 
     94     @Test
     95     public void signaturesMatch_disallowsUnsignedApps_storedSignatureNull_returnsFalse()
     96             throws Exception {
     97         PackageInfo packageInfo = new PackageInfo();
     98         packageInfo.packageName = "test";
     99         packageInfo.signingInfo = new SigningInfo(
    100                 new PackageParser.SigningDetails(
    101                         new Signature[] {SIGNATURE_1},
    102                         PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
    103                         null,
    104                         null,
    105                         null));
    106         packageInfo.applicationInfo = new ApplicationInfo();
    107 
    108         boolean result = BackupUtils.signaturesMatch(null, packageInfo,
    109                 mMockPackageManagerInternal);
    110 
    111         assertThat(result).isFalse();
    112     }
    113 
    114     @Test
    115     public void signaturesMatch_disallowsUnsignedApps_storedSignatureEmpty_returnsFalse()
    116             throws Exception {
    117         PackageInfo packageInfo = new PackageInfo();
    118         packageInfo.packageName = "test";
    119         packageInfo.signingInfo = new SigningInfo(
    120                 new PackageParser.SigningDetails(
    121                         new Signature[] {SIGNATURE_1},
    122                         PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
    123                         null,
    124                         null,
    125                         null));
    126         packageInfo.applicationInfo = new ApplicationInfo();
    127 
    128         ArrayList<byte[]> storedSigHashes = new ArrayList<>();
    129         boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
    130                 mMockPackageManagerInternal);
    131 
    132         assertThat(result).isFalse();
    133     }
    134 
    135 
    136     @Test
    137     public void
    138     signaturesMatch_disallowsUnsignedApps_targetSignatureEmpty_returnsFalse()
    139             throws Exception {
    140         PackageInfo packageInfo = new PackageInfo();
    141         packageInfo.packageName = "test";
    142         packageInfo.signingInfo = null;
    143         packageInfo.applicationInfo = new ApplicationInfo();
    144 
    145         ArrayList<byte[]> storedSigHashes = new ArrayList<>();
    146         storedSigHashes.add(SIGNATURE_HASH_1);
    147         boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
    148                 mMockPackageManagerInternal);
    149 
    150         assertThat(result).isFalse();
    151     }
    152 
    153     @Test
    154     public void
    155     signaturesMatch_disallowsUnsignedApps_targetSignatureNull_returnsFalse()
    156             throws Exception {
    157         PackageInfo packageInfo = new PackageInfo();
    158         packageInfo.packageName = "test";
    159         packageInfo.signingInfo = null;
    160         packageInfo.applicationInfo = new ApplicationInfo();
    161 
    162         ArrayList<byte[]> storedSigHashes = new ArrayList<>();
    163         storedSigHashes.add(SIGNATURE_HASH_1);
    164         boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
    165                 mMockPackageManagerInternal);
    166 
    167         assertThat(result).isFalse();
    168     }
    169 
    170     @Test
    171     public void signaturesMatch_disallowsUnsignedApps_bothSignaturesNull_returnsFalse()
    172             throws Exception {
    173         PackageInfo packageInfo = new PackageInfo();
    174         packageInfo.packageName = "test";
    175         packageInfo.signingInfo = null;
    176         packageInfo.applicationInfo = new ApplicationInfo();
    177 
    178         boolean result = BackupUtils.signaturesMatch(null, packageInfo,
    179                 mMockPackageManagerInternal);
    180 
    181         assertThat(result).isFalse();
    182     }
    183 
    184     @Test
    185     public void signaturesMatch_disallowsUnsignedApps_bothSignaturesEmpty_returnsFalse()
    186             throws Exception {
    187         PackageInfo packageInfo = new PackageInfo();
    188         packageInfo.packageName = "test";
    189         packageInfo.signingInfo = null;
    190         packageInfo.applicationInfo = new ApplicationInfo();
    191 
    192         ArrayList<byte[]> storedSigHashes = new ArrayList<>();
    193         boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
    194                 mMockPackageManagerInternal);
    195 
    196         assertThat(result).isFalse();
    197     }
    198 
    199     @Test
    200     public void signaturesMatch_equalSignatures_returnsTrue() throws Exception {
    201         PackageInfo packageInfo = new PackageInfo();
    202         packageInfo.packageName = "test";
    203         packageInfo.signingInfo = new SigningInfo(
    204                 new PackageParser.SigningDetails(
    205                         new Signature[] {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3},
    206                         PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
    207                         null,
    208                         null,
    209                         null));
    210         packageInfo.applicationInfo = new ApplicationInfo();
    211 
    212         ArrayList<byte[]> storedSigHashes = new ArrayList<>();
    213         storedSigHashes.add(SIGNATURE_HASH_1);
    214         storedSigHashes.add(SIGNATURE_HASH_2);
    215         storedSigHashes.add(SIGNATURE_HASH_3);
    216         boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
    217                 mMockPackageManagerInternal);
    218 
    219         assertThat(result).isTrue();
    220     }
    221 
    222     @Test
    223     public void signaturesMatch_extraSignatureInTarget_returnsTrue() throws Exception {
    224         PackageInfo packageInfo = new PackageInfo();
    225         packageInfo.packageName = "test";
    226         packageInfo.signingInfo = new SigningInfo(
    227                 new PackageParser.SigningDetails(
    228                         new Signature[] {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3},
    229                         PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
    230                         null,
    231                         null,
    232                         null));
    233         packageInfo.applicationInfo = new ApplicationInfo();
    234 
    235         ArrayList<byte[]> storedSigHashes = new ArrayList<>();
    236         storedSigHashes.add(SIGNATURE_HASH_1);
    237         storedSigHashes.add(SIGNATURE_HASH_2);
    238         boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
    239                 mMockPackageManagerInternal);
    240 
    241         assertThat(result).isTrue();
    242     }
    243 
    244     @Test
    245     public void signaturesMatch_extraSignatureInStored_returnsFalse() throws Exception {
    246         PackageInfo packageInfo = new PackageInfo();
    247         packageInfo.packageName = "test";
    248         packageInfo.signingInfo = new SigningInfo(
    249                 new PackageParser.SigningDetails(
    250                         new Signature[] {SIGNATURE_1, SIGNATURE_2},
    251                         PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
    252                         null,
    253                         null,
    254                         null));
    255         packageInfo.applicationInfo = new ApplicationInfo();
    256 
    257         ArrayList<byte[]> storedSigHashes = new ArrayList<>();
    258         storedSigHashes.add(SIGNATURE_HASH_1);
    259         storedSigHashes.add(SIGNATURE_HASH_2);
    260         storedSigHashes.add(SIGNATURE_HASH_3);
    261         boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
    262                 mMockPackageManagerInternal);
    263 
    264         assertThat(result).isFalse();
    265     }
    266 
    267     @Test
    268     public void signaturesMatch_oneNonMatchingSignature_returnsFalse() throws Exception {
    269         PackageInfo packageInfo = new PackageInfo();
    270         packageInfo.packageName = "test";
    271         packageInfo.signingInfo = new SigningInfo(
    272                 new PackageParser.SigningDetails(
    273                         new Signature[] {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3},
    274                         PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
    275                         null,
    276                         null,
    277                         null));
    278         packageInfo.applicationInfo = new ApplicationInfo();
    279 
    280         ArrayList<byte[]> storedSigHashes = new ArrayList<>();
    281         storedSigHashes.add(SIGNATURE_HASH_1);
    282         storedSigHashes.add(SIGNATURE_HASH_2);
    283         storedSigHashes.add(SIGNATURE_HASH_4);
    284         boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
    285                 mMockPackageManagerInternal);
    286 
    287         assertThat(result).isFalse();
    288     }
    289 
    290     @Test
    291     public void signaturesMatch_singleStoredSignatureNoRotation_returnsTrue()
    292             throws Exception {
    293         PackageInfo packageInfo = new PackageInfo();
    294         packageInfo.packageName = "test";
    295         packageInfo.signingInfo = new SigningInfo(
    296                 new PackageParser.SigningDetails(
    297                         new Signature[] {SIGNATURE_1},
    298                         PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
    299                         null,
    300                         null,
    301                         null));
    302         packageInfo.applicationInfo = new ApplicationInfo();
    303 
    304         doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1,
    305                 packageInfo.packageName);
    306 
    307         ArrayList<byte[]> storedSigHashes = new ArrayList<>();
    308         storedSigHashes.add(SIGNATURE_HASH_1);
    309         boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
    310                 mMockPackageManagerInternal);
    311 
    312         assertThat(result).isTrue();
    313     }
    314 
    315     @Test
    316     public void signaturesMatch_singleStoredSignatureWithRotationAssumeDataCapability_returnsTrue()
    317             throws Exception {
    318         PackageInfo packageInfo = new PackageInfo();
    319         packageInfo.packageName = "test";
    320         packageInfo.signingInfo = new SigningInfo(
    321                 new PackageParser.SigningDetails(
    322                         new Signature[] {SIGNATURE_1, SIGNATURE_2},
    323                         PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
    324                         null,
    325                         null,
    326                         null));
    327         packageInfo.applicationInfo = new ApplicationInfo();
    328 
    329         // we know SIGNATURE_1 is in history, and we want to assume it has
    330         // SigningDetails.CertCapabilities.INSTALLED_DATA capability
    331         doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1,
    332                 packageInfo.packageName);
    333 
    334         ArrayList<byte[]> storedSigHashes = new ArrayList<>();
    335         storedSigHashes.add(SIGNATURE_HASH_1);
    336         boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
    337                 mMockPackageManagerInternal);
    338 
    339         assertThat(result).isTrue();
    340     }
    341 
    342     @Test
    343     public void
    344             signaturesMatch_singleStoredSignatureWithRotationAssumeNoDataCapability_returnsFalse()
    345             throws Exception {
    346         PackageInfo packageInfo = new PackageInfo();
    347         packageInfo.packageName = "test";
    348         packageInfo.signingInfo = new SigningInfo(
    349                 new PackageParser.SigningDetails(
    350                         new Signature[] {SIGNATURE_1, SIGNATURE_2},
    351                         PackageParser.SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
    352                         null,
    353                         null,
    354                         null));
    355         packageInfo.applicationInfo = new ApplicationInfo();
    356 
    357         // we know SIGNATURE_1 is in history, but we want to assume it does not have
    358         // SigningDetails.CertCapabilities.INSTALLED_DATA capability
    359         doReturn(false).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1,
    360                 packageInfo.packageName);
    361 
    362         ArrayList<byte[]> storedSigHashes = new ArrayList<>();
    363         storedSigHashes.add(SIGNATURE_HASH_1);
    364         boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
    365                 mMockPackageManagerInternal);
    366 
    367         assertThat(result).isFalse();
    368     }
    369 
    370     @Test
    371     public void testHashSignature() {
    372         final byte[] sig1 = "abc".getBytes();
    373         final byte[] sig2 = "def".getBytes();
    374 
    375         final byte[] hash1a = BackupUtils.hashSignature(sig1);
    376         final byte[] hash1b = BackupUtils.hashSignature(new Signature(sig1));
    377 
    378         final byte[] hash2a = BackupUtils.hashSignature(sig2);
    379         final byte[] hash2b = BackupUtils.hashSignature(new Signature(sig2));
    380 
    381         assertEquals(32, hash1a.length);
    382         MoreAsserts.assertEquals(hash1a, hash1b);
    383 
    384         assertEquals(32, hash2a.length);
    385         MoreAsserts.assertEquals(hash2a, hash2b);
    386 
    387         assertFalse(Arrays.equals(hash1a, hash2a));
    388 
    389         final ArrayList<byte[]> listA = BackupUtils.hashSignatureArray(Arrays.asList(
    390                 "abc".getBytes(), "def".getBytes()));
    391 
    392         final ArrayList<byte[]> listB = BackupUtils.hashSignatureArray(new Signature[]{
    393                 new Signature("abc".getBytes()), new Signature("def".getBytes())});
    394 
    395         assertEquals(2, listA.size());
    396         assertEquals(2, listB.size());
    397 
    398         MoreAsserts.assertEquals(hash1a, listA.get(0));
    399         MoreAsserts.assertEquals(hash1a, listB.get(0));
    400 
    401         MoreAsserts.assertEquals(hash2a, listA.get(1));
    402         MoreAsserts.assertEquals(hash2a, listB.get(1));
    403     }
    404 
    405     private static Signature generateSignature(byte i) {
    406         byte[] signatureBytes = new byte[256];
    407         signatureBytes[0] = i;
    408         return new Signature(signatureBytes);
    409     }
    410 }
    411