Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2013 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * 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, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 
     17 package android.util.cts;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 import static org.junit.Assert.assertNotNull;
     21 import static org.junit.Assert.assertNull;
     22 import static org.junit.Assert.assertTrue;
     23 import static org.junit.Assert.fail;
     24 
     25 import android.support.test.InstrumentationRegistry;
     26 import android.support.test.filters.SmallTest;
     27 import android.support.test.runner.AndroidJUnit4;
     28 import android.system.OsConstants;
     29 import android.util.jar.StrictJarFile;
     30 
     31 import libcore.io.IoBridge;
     32 import libcore.io.Streams;
     33 
     34 import org.junit.Before;
     35 import org.junit.Test;
     36 import org.junit.runner.RunWith;
     37 
     38 import java.io.File;
     39 import java.io.FileDescriptor;
     40 import java.io.FileOutputStream;
     41 import java.io.IOException;
     42 import java.io.InputStream;
     43 import java.nio.charset.Charset;
     44 import java.util.HashMap;
     45 import java.util.Iterator;
     46 import java.util.zip.ZipEntry;
     47 
     48 @SmallTest
     49 @RunWith(AndroidJUnit4.class)
     50 public class StrictJarFileTest {
     51     // A well formed jar file with 6 entries.
     52     private static final String JAR_1 = "hyts_patch.jar";
     53 
     54     private File mResourcesFile;
     55 
     56     @Before
     57     public void setup() {
     58         try {
     59             mResourcesFile = File.createTempFile("sjf_resources", "", null);
     60             mResourcesFile.delete();
     61             mResourcesFile.mkdirs();
     62         } catch (IOException e) {
     63             throw new RuntimeException("Unable to create temp folder", e);
     64         }
     65         mResourcesFile.deleteOnExit();
     66     }
     67 
     68     @Test(expected=IOException.class)
     69     public void testConstructorWrongFile() throws IOException {
     70         new StrictJarFile("Wrong.file");
     71     }
     72 
     73     @Test(expected=IOException.class)
     74     public void testConstructorWrongFile_FD() throws IOException {
     75         new StrictJarFile(new FileDescriptor());
     76     }
     77 
     78     @Test(expected=NullPointerException.class)
     79     public void testConstructorWrongFile_FD_null() throws IOException {
     80         new StrictJarFile((FileDescriptor) null);
     81     }
     82 
     83     @Test
     84     public void testConstructor() throws Exception {
     85         copyFile(JAR_1);
     86         String fileName = (new File(mResourcesFile, JAR_1)).getCanonicalPath();
     87         StrictJarFile jarFile = new StrictJarFile(fileName);
     88         jarFile.close();
     89     }
     90 
     91     @Test
     92     public void testConstructor_FD() throws Exception {
     93         copyFile(JAR_1);
     94         FileDescriptor fd = IoBridge.open(
     95                 new File(mResourcesFile, JAR_1).getAbsolutePath(), OsConstants.O_RDONLY);
     96         StrictJarFile jarFile = new StrictJarFile(fd);
     97         jarFile.close();
     98     }
     99 
    100     @Test
    101     public void testIteration() throws Exception {
    102         copyFile(JAR_1);
    103         StrictJarFile jarFile =
    104                 new StrictJarFile(new File(mResourcesFile, JAR_1).getAbsolutePath());
    105         checkIteration(jarFile);
    106     }
    107 
    108     @Test
    109     public void testIteration_FD() throws Exception {
    110         copyFile(JAR_1);
    111         FileDescriptor fd = IoBridge.open(
    112                 new File(mResourcesFile, JAR_1).getAbsolutePath(), OsConstants.O_RDONLY);
    113         StrictJarFile jarFile = new StrictJarFile(fd);
    114         checkIteration(jarFile);
    115     }
    116 
    117     private static void checkIteration(StrictJarFile jarFile) throws Exception {
    118         Iterator<ZipEntry> it = jarFile.iterator();
    119         HashMap<String, ZipEntry> entries = new HashMap<>();
    120         while (it.hasNext()) {
    121             final ZipEntry ze = it.next();
    122             entries.put(ze.getName(), ze);
    123         }
    124 
    125         assertEquals(6, entries.size());
    126         assertTrue(entries.containsKey("META-INF/"));
    127 
    128         assertTrue(entries.containsKey("META-INF/MANIFEST.MF"));
    129         ZipEntry ze = entries.get("META-INF/MANIFEST.MF");
    130         assertEquals(62, ze.getSize());
    131         assertEquals(ZipEntry.DEFLATED, ze.getMethod());
    132         assertEquals(61, ze.getCompressedSize());
    133 
    134         assertTrue(entries.containsKey("Blah.txt"));
    135         ze = entries.get("Blah.txt");
    136         assertEquals(4, ze.getSize());
    137         assertEquals(ZipEntry.DEFLATED, ze.getMethod());
    138         assertEquals(6, ze.getCompressedSize());
    139         assertEquals("Blah", new String(Streams.readFully(jarFile.getInputStream(ze)),
    140                 Charset.forName("UTF-8")));
    141 
    142         assertTrue(entries.containsKey("foo/"));
    143         assertTrue(entries.containsKey("foo/bar/"));
    144         assertTrue(entries.containsKey("foo/bar/A.class"));
    145         ze = entries.get("foo/bar/A.class");
    146         assertEquals(311, ze.getSize());
    147         assertEquals(ZipEntry.DEFLATED, ze.getMethod());
    148         assertEquals(225, ze.getCompressedSize());
    149     }
    150 
    151     @Test
    152     public void testFindEntry() throws Exception {
    153         copyFile(JAR_1);
    154         StrictJarFile jarFile =
    155                 new StrictJarFile(new File(mResourcesFile, JAR_1).getAbsolutePath());
    156         checkFindEntry(jarFile);
    157     }
    158 
    159     @Test
    160     public void testFindEntry_FD() throws Exception {
    161         copyFile(JAR_1);
    162         FileDescriptor fd = IoBridge.open(
    163                 new File(mResourcesFile, JAR_1).getAbsolutePath(), OsConstants.O_RDONLY);
    164         StrictJarFile jarFile = new StrictJarFile(fd);
    165         checkFindEntry(jarFile);
    166     }
    167 
    168     private static void checkFindEntry(StrictJarFile jarFile) throws Exception {
    169         assertNull(jarFile.findEntry("foobar"));
    170         assertNull(jarFile.findEntry("blah.txt"));
    171         assertNotNull(jarFile.findEntry("Blah.txt"));
    172         final ZipEntry ze = jarFile.findEntry("Blah.txt");
    173         assertEquals(4, ze.getSize());
    174         assertEquals(ZipEntry.DEFLATED, ze.getMethod());
    175         assertEquals(6, ze.getCompressedSize());
    176         assertEquals("Blah", new String(Streams.readFully(jarFile.getInputStream(ze)),
    177                 Charset.forName("UTF-8")));
    178     }
    179 
    180     @Test
    181     public void testGetManifest() throws Exception {
    182         copyFile(JAR_1);
    183         StrictJarFile jarFile =
    184                 new StrictJarFile(new File(mResourcesFile, JAR_1).getAbsolutePath());
    185         checkGetManifest(jarFile);
    186     }
    187 
    188     @Test
    189     public void testGetManifest_FD() throws Exception {
    190         copyFile(JAR_1);
    191         FileDescriptor fd = IoBridge.open(
    192                 new File(mResourcesFile, JAR_1).getAbsolutePath(), OsConstants.O_RDONLY);
    193         StrictJarFile jarFile = new StrictJarFile(fd);
    194         checkGetManifest(jarFile);
    195     }
    196 
    197     private static void checkGetManifest(StrictJarFile jarFile) throws Exception {
    198         assertNotNull(jarFile.getManifest());
    199         assertEquals("1.4.2 (IBM Corporation)",
    200                 jarFile.getManifest().getMainAttributes().getValue("Created-By"));
    201     }
    202 
    203     @Test
    204     public void testJarSigning_wellFormed() throws IOException {
    205         copyFile("Integrate.jar");
    206         StrictJarFile jarFile =
    207                 new StrictJarFile(new File(mResourcesFile, "Integrate.jar").getAbsolutePath());
    208         checkJarSigning_wellFormed(jarFile);
    209     }
    210 
    211     @Test
    212     public void testJarSigning_wellFormed_FD() throws IOException {
    213         copyFile("Integrate.jar");
    214         FileDescriptor fd = IoBridge.open(
    215                 new File(mResourcesFile, "Integrate.jar").getAbsolutePath(),
    216                         OsConstants.O_RDONLY);
    217         StrictJarFile jarFile = new StrictJarFile(fd);
    218         checkJarSigning_wellFormed(jarFile);
    219     }
    220 
    221     private static void checkJarSigning_wellFormed(StrictJarFile jarFile) throws IOException {
    222         Iterator<ZipEntry> entries = jarFile.iterator();
    223         while (entries.hasNext()) {
    224             ZipEntry zipEntry = entries.next();
    225             jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE);
    226             if ("Test.class".equals(zipEntry.getName())) {
    227                 assertNotNull(jarFile.getCertificates(zipEntry));
    228                 assertNotNull(jarFile.getCertificateChains(zipEntry));
    229             }
    230         }
    231     }
    232 
    233     @Test
    234     public void testJarSigning_fudgedEntry() throws IOException {
    235         copyFile("Integrate.jar");
    236         StrictJarFile jarFile = new StrictJarFile(
    237                 new File(mResourcesFile, "Integrate.jar").getAbsolutePath());
    238         checkJarSigning_fudgedEntry(jarFile);
    239     }
    240 
    241     @Test
    242     public void testJarSigning_fudgedEntry_FD() throws IOException {
    243         copyFile("Integrate.jar");
    244         FileDescriptor fd = IoBridge.open(
    245                 new File(mResourcesFile, "Integrate.jar").getAbsolutePath(),
    246                         OsConstants.O_RDONLY);
    247         StrictJarFile jarFile = new StrictJarFile(fd);
    248         checkJarSigning_fudgedEntry(jarFile);
    249     }
    250 
    251     private static void checkJarSigning_fudgedEntry(StrictJarFile jarFile) throws IOException {
    252         ZipEntry ze = jarFile.findEntry("Test.class");
    253         jarFile.getInputStream(ze).skip(Long.MAX_VALUE);
    254 
    255         // Fudge the size so that certificates do not match.
    256         ze.setSize(ze.getSize() - 1);
    257         try {
    258             jarFile.getInputStream(ze).skip(Long.MAX_VALUE);
    259             fail();
    260         } catch (SecurityException expected) {
    261         }
    262     }
    263 
    264     @Test
    265     public void testJarSigning_modifiedClass() throws IOException {
    266         copyFile("Modified_Class.jar");
    267         StrictJarFile jarFile = new StrictJarFile(
    268                 new File(mResourcesFile,  "Modified_Class.jar").getAbsolutePath());
    269         checkJarSigning_modifiedClass(jarFile);
    270     }
    271 
    272     @Test
    273     public void testJarSigning_modifiedClass_FD() throws IOException {
    274         copyFile("Modified_Class.jar");
    275         FileDescriptor fd = IoBridge.open(
    276                 new File(mResourcesFile, "Modified_Class.jar").getAbsolutePath(),
    277                         OsConstants.O_RDONLY);
    278         StrictJarFile jarFile = new StrictJarFile(fd);
    279         checkJarSigning_modifiedClass(jarFile);
    280     }
    281 
    282     private static void checkJarSigning_modifiedClass(StrictJarFile jarFile)
    283             throws IOException {
    284         ZipEntry ze = jarFile.findEntry("Test.class");
    285         try {
    286             jarFile.getInputStream(ze).skip(Long.MAX_VALUE);
    287             fail();
    288         } catch (SecurityException expected) {
    289         }
    290     }
    291 
    292     @Test
    293     public void testJarSigning_brokenMainAttributes() throws Exception {
    294         verifyThrowsOnInit("Modified_Manifest_MainAttributes.jar");
    295     }
    296 
    297     @Test
    298     public void testJarSigning_brokenMainAttributes_FD() throws Exception {
    299         verifyThrowsOnInitFD("Modified_Manifest_MainAttributes.jar");
    300     }
    301 
    302     @Test
    303     public void testJarSigning_brokenEntryAttributes() throws Exception {
    304         verifyThrowsOnInit("Modified_Manifest_EntryAttributes.jar");
    305     }
    306 
    307     @Test
    308     public void testJarSigning_brokenEntryAttributes_FD() throws Exception {
    309         verifyThrowsOnInitFD("Modified_Manifest_EntryAttributes.jar");
    310     }
    311 
    312     @Test
    313     public void testJarSigning_brokenSignatureFile() throws Exception {
    314         verifyThrowsOnInit("Modified_SF_EntryAttributes.jar");
    315     }
    316 
    317     @Test
    318     public void testJarSigning_brokenSignatureFile_FD() throws Exception {
    319         verifyThrowsOnInitFD("Modified_SF_EntryAttributes.jar");
    320     }
    321 
    322     @Test
    323     public void testJarSigning_removedEntry() throws Exception {
    324         verifyThrowsOnInit("removed.jar");
    325     }
    326 
    327     @Test
    328     public void testJarSigning_removedEntry_FD() throws Exception {
    329         verifyThrowsOnInitFD("removed.jar");
    330     }
    331 
    332     private void verifyThrowsOnInit(String name) throws Exception {
    333         copyFile(name);
    334         try {
    335             new StrictJarFile(new File(mResourcesFile,  name).getAbsolutePath());
    336             fail();
    337         } catch (SecurityException expected) {
    338         }
    339     }
    340 
    341     private void verifyThrowsOnInitFD(String name) throws Exception {
    342         copyFile(name);
    343         FileDescriptor fd = IoBridge.open(
    344                 new File(mResourcesFile, name).getAbsolutePath(),
    345                         OsConstants.O_RDONLY);
    346         try {
    347             new StrictJarFile(fd);
    348             fail();
    349         } catch (SecurityException expected) {
    350         }
    351     }
    352 
    353     private File copyFile(String file) {
    354         File dest = new File(mResourcesFile.toString() + "/" + file);
    355 
    356         if (!dest.exists()) {
    357             try {
    358                 InputStream in = InstrumentationRegistry.getTargetContext().getAssets().open(file);
    359                 FileOutputStream out = new FileOutputStream(dest);
    360                 byte[] buffer = new byte[8192];
    361                 int c;
    362                 while ((c = in.read(buffer)) != -1) {
    363                     out.write(buffer, 0, c);
    364                 }
    365                 out.close();
    366                 dest.deleteOnExit();
    367                 in.close();
    368             } catch (IOException e) {
    369                 throw new RuntimeException("Unable to copy file from resource " + file
    370                         + " to file " + dest, e);
    371             }
    372         }
    373         return dest;
    374     }
    375 }
    376