1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.harmony.archive.tests.java.util.jar; 18 19 20 import junit.framework.TestCase; 21 22 import tests.support.Support_PlatformFile; 23 import tests.support.resource.Support_Resources; 24 25 import java.io.ByteArrayOutputStream; 26 import java.io.File; 27 import java.io.FileOutputStream; 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.net.URL; 31 import java.security.Permission; 32 import java.security.cert.Certificate; 33 import java.util.Enumeration; 34 import java.util.Vector; 35 import java.util.jar.Attributes; 36 import java.util.jar.JarEntry; 37 import java.util.jar.JarFile; 38 import java.util.jar.JarOutputStream; 39 import java.util.jar.Manifest; 40 import java.util.zip.ZipEntry; 41 import java.util.zip.ZipException; 42 import java.util.zip.ZipFile; 43 44 45 public class JarFileTest extends TestCase { 46 47 // BEGIN android-added 48 public byte[] getAllBytesFromStream(InputStream is) throws IOException { 49 ByteArrayOutputStream bs = new ByteArrayOutputStream(); 50 byte[] buf = new byte[666]; 51 int iRead; 52 int off; 53 while (is.available() > 0) { 54 iRead = is.read(buf, 0, buf.length); 55 if (iRead > 0) bs.write(buf, 0, iRead); 56 } 57 return bs.toByteArray(); 58 } 59 60 // END android-added 61 62 private final String jarName = "hyts_patch.jar"; // a 'normal' jar file 63 64 private final String jarName2 = "hyts_patch2.jar"; 65 66 private final String jarName3 = "hyts_manifest1.jar"; 67 68 private final String jarName4 = "hyts_signed.jar"; 69 70 private final String jarName5 = "hyts_signed_inc.jar"; 71 72 private final String jarName6 = "hyts_signed_sha256withrsa.jar"; 73 74 private final String jarName7 = "hyts_signed_sha256digest_sha256withrsa.jar"; 75 76 private final String jarName8 = "hyts_signed_sha512digest_sha512withecdsa.jar"; 77 78 private final String authAttrsJar = "hyts_signed_authAttrs.jar"; 79 80 private final String entryName = "foo/bar/A.class"; 81 82 private final String entryName3 = "coucou/FileAccess.class"; 83 84 private final String integrateJar = "Integrate.jar"; 85 86 private final String integrateJarEntry = "Test.class"; 87 88 private final String emptyEntryJar = "EmptyEntries_signed.jar"; 89 90 private final String emptyEntry1 = "subfolder/internalSubset01.js"; 91 92 private final String emptyEntry2 = "svgtest.js"; 93 94 private final String emptyEntry3 = "svgunit.js"; 95 96 private File resources; 97 98 // custom security manager 99 SecurityManager sm = new SecurityManager() { 100 final String forbidenPermissionName = "user.dir"; 101 102 public void checkPermission(Permission perm) { 103 if (perm.getName().equals(forbidenPermissionName)) { 104 throw new SecurityException(); 105 } 106 } 107 }; 108 109 @Override 110 protected void setUp() { 111 resources = Support_Resources.createTempFolder(); 112 } 113 114 /** 115 * java.util.jar.JarFile#JarFile(java.io.File) 116 */ 117 public void test_ConstructorLjava_io_File() { 118 try { 119 JarFile jarFile = new JarFile(new File("Wrong.file")); 120 fail("Should throw IOException"); 121 } catch (IOException e) { 122 // expected 123 } 124 125 try { 126 Support_Resources.copyFile(resources, null, jarName); 127 JarFile jarFile = new JarFile(new File(resources, jarName)); 128 } catch (IOException e) { 129 fail("Should not throw IOException"); 130 } 131 } 132 133 /** 134 * java.util.jar.JarFile#JarFile(java.lang.String) 135 */ 136 public void test_ConstructorLjava_lang_String() { 137 try { 138 JarFile jarFile = new JarFile("Wrong.file"); 139 fail("Should throw IOException"); 140 } catch (IOException e) { 141 // expected 142 } 143 144 try { 145 Support_Resources.copyFile(resources, null, jarName); 146 String fileName = (new File(resources, jarName)).getCanonicalPath(); 147 JarFile jarFile = new JarFile(fileName); 148 } catch (IOException e) { 149 fail("Should not throw IOException"); 150 } 151 } 152 153 /** 154 * java.util.jar.JarFile#JarFile(java.lang.String, boolean) 155 */ 156 public void test_ConstructorLjava_lang_StringZ() { 157 try { 158 JarFile jarFile = new JarFile("Wrong.file", false); 159 fail("Should throw IOException"); 160 } catch (IOException e) { 161 // expected 162 } 163 164 try { 165 Support_Resources.copyFile(resources, null, jarName); 166 String fileName = (new File(resources, jarName)).getCanonicalPath(); 167 JarFile jarFile = new JarFile(fileName, true); 168 } catch (IOException e) { 169 fail("Should not throw IOException"); 170 } 171 } 172 173 /** 174 * java.util.jar.JarFile#JarFile(java.io.File, boolean) 175 */ 176 public void test_ConstructorLjava_io_FileZ() { 177 try { 178 JarFile jarFile = new JarFile(new File("Wrong.file"), true); 179 fail("Should throw IOException"); 180 } catch (IOException e) { 181 // expected 182 } 183 184 try { 185 Support_Resources.copyFile(resources, null, jarName); 186 JarFile jarFile = new JarFile(new File(resources, jarName), false); 187 } catch (IOException e) { 188 fail("Should not throw IOException"); 189 } 190 } 191 192 /** 193 * java.util.jar.JarFile#JarFile(java.io.File, boolean, int) 194 */ 195 public void test_ConstructorLjava_io_FileZI() { 196 try { 197 JarFile jarFile = new JarFile(new File("Wrong.file"), true, 198 ZipFile.OPEN_READ); 199 fail("Should throw IOException"); 200 } catch (IOException e) { 201 // expected 202 } 203 204 try { 205 Support_Resources.copyFile(resources, null, jarName); 206 JarFile jarFile = new JarFile(new File(resources, jarName), false, 207 ZipFile.OPEN_READ); 208 } catch (IOException e) { 209 fail("Should not throw IOException"); 210 } 211 212 try { 213 Support_Resources.copyFile(resources, null, jarName); 214 JarFile jarFile = new JarFile(new File(resources, jarName), false, 215 ZipFile.OPEN_READ | ZipFile.OPEN_DELETE + 33); 216 fail("Should throw IllegalArgumentException"); 217 } catch (IOException e) { 218 fail("Should not throw IOException"); 219 } catch (IllegalArgumentException e) { 220 // expected 221 } 222 } 223 224 /** 225 * Constructs JarFile object. 226 * 227 * java.util.jar.JarFile#JarFile(java.io.File) 228 * java.util.jar.JarFile#JarFile(java.lang.String) 229 */ 230 public void testConstructor_file() throws IOException { 231 File f = new File(resources, jarName); 232 Support_Resources.copyFile(resources, null, jarName); 233 assertTrue(new JarFile(f).getEntry(entryName).getName().equals( 234 entryName)); 235 assertTrue(new JarFile(f.getPath()).getEntry(entryName).getName() 236 .equals(entryName)); 237 } 238 239 /** 240 * java.util.jar.JarFile#entries() 241 */ 242 public void test_entries() throws Exception { 243 /* 244 * Note only (and all of) the following should be contained in the file 245 * META-INF/ META-INF/MANIFEST.MF foo/ foo/bar/ foo/bar/A.class Blah.txt 246 */ 247 Support_Resources.copyFile(resources, null, jarName); 248 JarFile jarFile = new JarFile(new File(resources, jarName)); 249 Enumeration<JarEntry> e = jarFile.entries(); 250 int i; 251 for (i = 0; e.hasMoreElements(); i++) { 252 e.nextElement(); 253 } 254 assertEquals(jarFile.size(), i); 255 jarFile.close(); 256 assertEquals(6, i); 257 } 258 259 public void test_entries2() throws Exception { 260 Support_Resources.copyFile(resources, null, jarName); 261 JarFile jarFile = new JarFile(new File(resources, jarName)); 262 Enumeration<JarEntry> enumeration = jarFile.entries(); 263 jarFile.close(); 264 try { 265 enumeration.hasMoreElements(); 266 fail("hasMoreElements() did not detect a closed jar file"); 267 } catch (IllegalStateException e) { 268 } 269 Support_Resources.copyFile(resources, null, jarName); 270 jarFile = new JarFile(new File(resources, jarName)); 271 enumeration = jarFile.entries(); 272 jarFile.close(); 273 try { 274 enumeration.nextElement(); 275 fail("nextElement() did not detect closed jar file"); 276 } catch (IllegalStateException e) { 277 } 278 } 279 280 /** 281 * @throws IOException 282 * java.util.jar.JarFile#getJarEntry(java.lang.String) 283 */ 284 public void test_getEntryLjava_lang_String() throws IOException { 285 try { 286 Support_Resources.copyFile(resources, null, jarName); 287 JarFile jarFile = new JarFile(new File(resources, jarName)); 288 assertEquals("Error in returned entry", 311, jarFile.getEntry( 289 entryName).getSize()); 290 jarFile.close(); 291 } catch (Exception e) { 292 fail("Exception during test: " + e.toString()); 293 } 294 295 Support_Resources.copyFile(resources, null, jarName); 296 JarFile jarFile = new JarFile(new File(resources, jarName)); 297 Enumeration<JarEntry> enumeration = jarFile.entries(); 298 assertTrue(enumeration.hasMoreElements()); 299 while (enumeration.hasMoreElements()) { 300 JarEntry je = enumeration.nextElement(); 301 jarFile.getEntry(je.getName()); 302 } 303 304 enumeration = jarFile.entries(); 305 assertTrue(enumeration.hasMoreElements()); 306 JarEntry je = enumeration.nextElement(); 307 try { 308 jarFile.close(); 309 jarFile.getEntry(je.getName()); 310 // fail("IllegalStateException expected."); 311 } catch (IllegalStateException ee) { // Per documentation exception 312 // may be thrown. 313 // expected 314 } 315 } 316 317 /** 318 * @throws IOException 319 * java.util.jar.JarFile#getJarEntry(java.lang.String) 320 */ 321 public void test_getJarEntryLjava_lang_String() throws IOException { 322 try { 323 Support_Resources.copyFile(resources, null, jarName); 324 JarFile jarFile = new JarFile(new File(resources, jarName)); 325 assertEquals("Error in returned entry", 311, jarFile.getJarEntry( 326 entryName).getSize()); 327 jarFile.close(); 328 } catch (Exception e) { 329 fail("Exception during test: " + e.toString()); 330 } 331 332 Support_Resources.copyFile(resources, null, jarName); 333 JarFile jarFile = new JarFile(new File(resources, jarName)); 334 Enumeration<JarEntry> enumeration = jarFile.entries(); 335 assertTrue(enumeration.hasMoreElements()); 336 while (enumeration.hasMoreElements()) { 337 JarEntry je = enumeration.nextElement(); 338 jarFile.getJarEntry(je.getName()); 339 } 340 341 enumeration = jarFile.entries(); 342 assertTrue(enumeration.hasMoreElements()); 343 JarEntry je = enumeration.nextElement(); 344 try { 345 jarFile.close(); 346 jarFile.getJarEntry(je.getName()); 347 // fail("IllegalStateException expected."); 348 } catch (IllegalStateException ee) { // Per documentation exception 349 // may be thrown. 350 // expected 351 } 352 } 353 354 355 /** 356 * java.util.jar.JarFile#getJarEntry(java.lang.String) 357 */ 358 public void testGetJarEntry() throws Exception { 359 Support_Resources.copyFile(resources, null, jarName); 360 JarFile jarFile = new JarFile(new File(resources, jarName)); 361 assertEquals("Error in returned entry", 311, jarFile.getEntry( 362 entryName).getSize()); 363 jarFile.close(); 364 365 // tests for signed jars 366 // test all signed jars in the /Testres/Internal/SignedJars directory 367 String jarDirUrl = Support_Resources 368 .getResourceURL("/../internalres/signedjars"); 369 Vector<String> signedJars = new Vector<String>(); 370 try { 371 InputStream is = new URL(jarDirUrl + "/jarlist.txt").openStream(); 372 while (is.available() > 0) { 373 StringBuilder linebuff = new StringBuilder(80); // Typical line 374 // length 375 done: while (true) { 376 int nextByte = is.read(); 377 switch (nextByte) { 378 case -1: 379 break done; 380 case (byte) '\r': 381 if (linebuff.length() == 0) { 382 // ignore 383 } 384 break done; 385 case (byte) '\n': 386 if (linebuff.length() == 0) { 387 // ignore 388 } 389 break done; 390 default: 391 linebuff.append((char) nextByte); 392 } 393 } 394 if (linebuff.length() == 0) { 395 break; 396 } 397 String line = linebuff.toString(); 398 signedJars.add(line); 399 } 400 is.close(); 401 } catch (IOException e) { 402 // no list of jars found 403 } 404 405 for (int i = 0; i < signedJars.size(); i++) { 406 String jarName = signedJars.get(i); 407 try { 408 File file = Support_Resources.getExternalLocalFile(jarDirUrl 409 + "/" + jarName); 410 jarFile = new JarFile(file, true); 411 boolean foundCerts = false; 412 Enumeration<JarEntry> e = jarFile.entries(); 413 while (e.hasMoreElements()) { 414 JarEntry entry = e.nextElement(); 415 InputStream is = jarFile.getInputStream(entry); 416 is.skip(100000); 417 is.close(); 418 Certificate[] certs = entry.getCertificates(); 419 if (certs != null && certs.length > 0) { 420 foundCerts = true; 421 break; 422 } 423 } 424 assertTrue( 425 "No certificates found during signed jar test for jar \"" 426 + jarName + "\"", foundCerts); 427 } catch (IOException e) { 428 fail("Exception during signed jar test for jar \"" + jarName 429 + "\": " + e.toString()); 430 } 431 } 432 } 433 434 /** 435 * java.util.jar.JarFile#getManifest() 436 */ 437 public void test_getManifest() { 438 // Test for method java.util.jar.Manifest 439 // java.util.jar.JarFile.getManifest() 440 try { 441 Support_Resources.copyFile(resources, null, jarName); 442 JarFile jarFile = new JarFile(new File(resources, jarName)); 443 assertNotNull("Error--Manifest not returned", jarFile.getManifest()); 444 jarFile.close(); 445 } catch (Exception e) { 446 fail("Exception during 1st test: " + e.toString()); 447 } 448 try { 449 Support_Resources.copyFile(resources, null, jarName2); 450 JarFile jarFile = new JarFile(new File(resources, jarName2)); 451 assertNull("Error--should have returned null", jarFile 452 .getManifest()); 453 jarFile.close(); 454 } catch (Exception e) { 455 fail("Exception during 2nd test: " + e.toString()); 456 } 457 458 try { 459 // jarName3 was created using the following test 460 Support_Resources.copyFile(resources, null, jarName3); 461 JarFile jarFile = new JarFile(new File(resources, jarName3)); 462 assertNotNull("Should find manifest without verifying", jarFile 463 .getManifest()); 464 jarFile.close(); 465 } catch (Exception e) { 466 fail("Exception during 3rd test: " + e.toString()); 467 } 468 469 try { 470 // this is used to create jarName3 used in the previous test 471 Manifest manifest = new Manifest(); 472 Attributes attributes = manifest.getMainAttributes(); 473 attributes.put(new Attributes.Name("Manifest-Version"), "1.0"); 474 ByteArrayOutputStream manOut = new ByteArrayOutputStream(); 475 manifest.write(manOut); 476 byte[] manBytes = manOut.toByteArray(); 477 File file = File.createTempFile( 478 Support_PlatformFile.getNewPlatformFile("hyts_manifest1", 479 ""), ".jar"); 480 JarOutputStream jarOut = new JarOutputStream(new FileOutputStream( 481 file.getAbsolutePath())); 482 ZipEntry entry = new ZipEntry("META-INF/"); 483 entry.setSize(0); 484 jarOut.putNextEntry(entry); 485 entry = new ZipEntry(JarFile.MANIFEST_NAME); 486 entry.setSize(manBytes.length); 487 jarOut.putNextEntry(entry); 488 jarOut.write(manBytes); 489 entry = new ZipEntry("myfile"); 490 entry.setSize(1); 491 jarOut.putNextEntry(entry); 492 jarOut.write(65); 493 jarOut.close(); 494 JarFile jar = new JarFile(file.getAbsolutePath(), false); 495 assertNotNull("Should find manifest without verifying", jar 496 .getManifest()); 497 jar.close(); 498 file.delete(); 499 } catch (IOException e) { 500 fail("IOException 3"); 501 } 502 try { 503 Support_Resources.copyFile(resources, null, jarName2); 504 JarFile jF = new JarFile(new File(resources, jarName2)); 505 jF.close(); 506 jF.getManifest(); 507 fail("FAILED: expected IllegalStateException"); 508 } catch (IllegalStateException ise) { 509 // expected; 510 } catch (Exception e) { 511 fail("Exception during 4th test: " + e.toString()); 512 } 513 514 Support_Resources.copyFile(resources, null, "Broken_manifest.jar"); 515 JarFile jf; 516 try { 517 jf = new JarFile(new File(resources, "Broken_manifest.jar")); 518 jf.getManifest(); 519 fail("IOException expected."); 520 } catch (IOException e) { 521 // expected. 522 } 523 } 524 525 /** 526 * java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry) 527 */ 528 // This test doesn't pass on RI. If entry size is set up incorrectly, 529 // SecurityException is thrown. But SecurityException is thrown on RI only 530 // if jar file is signed incorrectly. 531 public void test_getInputStreamLjava_util_jar_JarEntry_subtest0() throws Exception { 532 File signedFile = null; 533 try { 534 Support_Resources.copyFile(resources, null, jarName4); 535 signedFile = new File(resources, jarName4); 536 } catch (Exception e) { 537 fail("Failed to create local file 2: " + e); 538 } 539 540 try { 541 JarFile jar = new JarFile(signedFile); 542 JarEntry entry = new JarEntry(entryName3); 543 InputStream in = jar.getInputStream(entry); 544 in.read(); 545 } catch (Exception e) { 546 fail("Exception during test 3: " + e); 547 } 548 549 try { 550 JarFile jar = new JarFile(signedFile); 551 JarEntry entry = new JarEntry(entryName3); 552 InputStream in = jar.getInputStream(entry); 553 // BEGIN android-added 554 byte[] dummy = getAllBytesFromStream(in); 555 // END android-added 556 assertNull("found certificates", entry.getCertificates()); 557 } catch (Exception e) { 558 fail("Exception during test 4: " + e); 559 } 560 561 try { 562 JarFile jar = new JarFile(signedFile); 563 JarEntry entry = new JarEntry(entryName3); 564 entry.setSize(1076); 565 InputStream in = jar.getInputStream(entry); 566 // BEGIN android-added 567 byte[] dummy = getAllBytesFromStream(in); 568 // END android-added 569 fail("SecurityException should be thrown."); 570 } catch (SecurityException e) { 571 // expected 572 } catch (Exception e) { 573 fail("Exception during test 5: " + e); 574 } 575 576 try { 577 Support_Resources.copyFile(resources, null, jarName5); 578 signedFile = new File(resources, jarName5); 579 } catch (Exception e) { 580 fail("Failed to create local file 5: " + e); 581 } 582 583 try { 584 JarFile jar = new JarFile(signedFile); 585 JarEntry entry = new JarEntry(entryName3); 586 InputStream in = jar.getInputStream(entry); 587 fail("SecurityException should be thrown."); 588 } catch (SecurityException e) { 589 // expected 590 } catch (Exception e) { 591 fail("Exception during test 5: " + e); 592 } 593 594 // SHA1 digest, SHA256withRSA signed JAR 595 checkSignedJar(jarName6); 596 597 // SHA-256 digest, SHA256withRSA signed JAR 598 checkSignedJar(jarName7); 599 600 // SHA-512 digest, SHA512withECDSA signed JAR 601 checkSignedJar(jarName8); 602 603 // JAR with a signature that has PKCS#7 Authenticated Attributes 604 checkSignedJar(authAttrsJar); 605 } 606 607 private void checkSignedJar(String jarName) throws Exception { 608 Support_Resources.copyFile(resources, null, jarName); 609 610 File file = new File(resources, jarName); 611 612 JarFile jarFile = new JarFile(file, true); 613 614 boolean foundCerts = false; 615 616 Enumeration<JarEntry> e = jarFile.entries(); 617 while (e.hasMoreElements()) { 618 JarEntry entry = e.nextElement(); 619 InputStream is = jarFile.getInputStream(entry); 620 is.skip(100000); 621 is.close(); 622 Certificate[] certs = entry.getCertificates(); 623 if (certs != null && certs.length > 0) { 624 foundCerts = true; 625 break; 626 } 627 } 628 629 assertTrue( 630 "No certificates found during signed jar test for jar \"" 631 + jarName + "\"", foundCerts); 632 } 633 634 /* 635 * The jar created by 1.4 which does not provide a 636 * algorithm-Digest-Manifest-Main-Attributes entry in .SF file. 637 */ 638 public void test_Jar_created_before_java_5() throws IOException { 639 String modifiedJarName = "Created_by_1_4.jar"; 640 Support_Resources.copyFile(resources, null, modifiedJarName); 641 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 642 true); 643 Enumeration<JarEntry> entries = jarFile.entries(); 644 while (entries.hasMoreElements()) { 645 ZipEntry zipEntry = entries.nextElement(); 646 jarFile.getInputStream(zipEntry); 647 } 648 } 649 650 /* The jar is intact, then everything is all right. */ 651 public void test_JarFile_Integrate_Jar() throws IOException { 652 String modifiedJarName = "Integrate.jar"; 653 Support_Resources.copyFile(resources, null, modifiedJarName); 654 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 655 true); 656 Enumeration<JarEntry> entries = jarFile.entries(); 657 while (entries.hasMoreElements()) { 658 ZipEntry zipEntry = entries.nextElement(); 659 jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE); 660 } 661 } 662 663 /** 664 * The jar is intact, but the entry object is modified. 665 */ 666 public void testJarVerificationModifiedEntry() throws IOException { 667 Support_Resources.copyFile(resources, null, integrateJar); 668 File f = new File(resources, integrateJar); 669 670 JarFile jarFile = new JarFile(f); 671 ZipEntry zipEntry = jarFile.getJarEntry(integrateJarEntry); 672 zipEntry.setSize(zipEntry.getSize() + 1); 673 jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE); 674 675 jarFile = new JarFile(f); 676 zipEntry = jarFile.getJarEntry(integrateJarEntry); 677 zipEntry.setSize(zipEntry.getSize() - 1); 678 try { 679 //jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE); 680 jarFile.getInputStream(zipEntry).read(new byte[5000], 0, 5000); 681 fail("SecurityException expected"); 682 } catch (SecurityException e) { 683 // desired 684 } 685 } 686 687 /* 688 * If another entry is inserted into Manifest, no security exception will be 689 * thrown out. 690 */ 691 public void test_JarFile_InsertEntry_in_Manifest_Jar() throws IOException { 692 String modifiedJarName = "Inserted_Entry_Manifest.jar"; 693 Support_Resources.copyFile(resources, null, modifiedJarName); 694 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 695 true); 696 Enumeration<JarEntry> entries = jarFile.entries(); 697 int count = 0; 698 while (entries.hasMoreElements()) { 699 700 ZipEntry zipEntry = entries.nextElement(); 701 jarFile.getInputStream(zipEntry); 702 count++; 703 } 704 assertEquals(5, count); 705 } 706 707 /* 708 * If another entry is inserted into Manifest, no security exception will be 709 * thrown out. 710 */ 711 public void test_Inserted_Entry_Manifest_with_DigestCode() 712 throws IOException { 713 String modifiedJarName = "Inserted_Entry_Manifest_with_DigestCode.jar"; 714 Support_Resources.copyFile(resources, null, modifiedJarName); 715 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 716 true); 717 Enumeration<JarEntry> entries = jarFile.entries(); 718 int count = 0; 719 while (entries.hasMoreElements()) { 720 ZipEntry zipEntry = entries.nextElement(); 721 jarFile.getInputStream(zipEntry); 722 count++; 723 } 724 assertEquals(5, count); 725 } 726 727 /* 728 * The content of Test.class is modified, jarFile.getInputStream will not 729 * throw security Exception, but it will anytime before the inputStream got 730 * from getInputStream method has been read to end. 731 */ 732 public void test_JarFile_Modified_Class() throws IOException { 733 String modifiedJarName = "Modified_Class.jar"; 734 Support_Resources.copyFile(resources, null, modifiedJarName); 735 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 736 true); 737 Enumeration<JarEntry> entries = jarFile.entries(); 738 while (entries.hasMoreElements()) { 739 ZipEntry zipEntry = entries.nextElement(); 740 jarFile.getInputStream(zipEntry); 741 } 742 /* The content of Test.class has been tampered. */ 743 ZipEntry zipEntry = jarFile.getEntry("Test.class"); 744 InputStream in = jarFile.getInputStream(zipEntry); 745 byte[] buffer = new byte[1024]; 746 try { 747 while (in.available() > 0) { 748 in.read(buffer); 749 } 750 fail("SecurityException expected"); 751 } catch (SecurityException e) { 752 // desired 753 } 754 } 755 756 /* 757 * In the Modified.jar, the main attributes of META-INF/MANIFEST.MF is 758 * tampered manually. Hence the RI 5.0 JarFile.getInputStream of any 759 * JarEntry will throw security exception. 760 */ 761 public void test_JarFile_Modified_Manifest_MainAttributes() 762 throws IOException { 763 String modifiedJarName = "Modified_Manifest_MainAttributes.jar"; 764 Support_Resources.copyFile(resources, null, modifiedJarName); 765 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 766 true); 767 Enumeration<JarEntry> entries = jarFile.entries(); 768 while (entries.hasMoreElements()) { 769 ZipEntry zipEntry = entries.nextElement(); 770 try { 771 jarFile.getInputStream(zipEntry); 772 fail("SecurityException expected"); 773 } catch (SecurityException e) { 774 // desired 775 } 776 } 777 } 778 779 /* 780 * It is all right in our original JarFile. If the Entry Attributes, for 781 * example Test.class in our jar, the jarFile.getInputStream will throw 782 * Security Exception. 783 */ 784 public void test_JarFile_Modified_Manifest_EntryAttributes() 785 throws IOException { 786 String modifiedJarName = "Modified_Manifest_EntryAttributes.jar"; 787 Support_Resources.copyFile(resources, null, modifiedJarName); 788 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 789 true); 790 Enumeration<JarEntry> entries = jarFile.entries(); 791 while (entries.hasMoreElements()) { 792 ZipEntry zipEntry = entries.nextElement(); 793 try { 794 jarFile.getInputStream(zipEntry); 795 fail("should throw Security Exception"); 796 } catch (SecurityException e) { 797 // desired 798 } 799 } 800 } 801 802 /* 803 * If the content of the .SA file is modified, no matter what it resides, 804 * JarFile.getInputStream of any JarEntry will throw Security Exception. 805 */ 806 public void test_JarFile_Modified_SF_EntryAttributes() throws IOException { 807 String modifiedJarName = "Modified_SF_EntryAttributes.jar"; 808 Support_Resources.copyFile(resources, null, modifiedJarName); 809 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 810 true); 811 Enumeration<JarEntry> entries = jarFile.entries(); 812 while (entries.hasMoreElements()) { 813 ZipEntry zipEntry = entries.nextElement(); 814 try { 815 jarFile.getInputStream(zipEntry); 816 fail("should throw Security Exception"); 817 } catch (SecurityException e) { 818 // desired 819 } 820 } 821 } 822 823 public void test_close() throws IOException { 824 String modifiedJarName = "Modified_SF_EntryAttributes.jar"; 825 Support_Resources.copyFile(resources, null, modifiedJarName); 826 JarFile jarFile = new JarFile(new File(resources, modifiedJarName), 827 true); 828 Enumeration<JarEntry> entries = jarFile.entries(); 829 830 jarFile.close(); 831 jarFile.close(); 832 833 // Can not check IOException 834 } 835 836 /** 837 * @throws IOException 838 * java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry) 839 */ 840 public void test_getInputStreamLjava_util_jar_JarEntry() throws IOException { 841 File localFile = null; 842 try { 843 Support_Resources.copyFile(resources, null, jarName); 844 localFile = new File(resources, jarName); 845 } catch (Exception e) { 846 fail("Failed to create local file: " + e); 847 } 848 849 byte[] b = new byte[1024]; 850 try { 851 JarFile jf = new JarFile(localFile); 852 java.io.InputStream is = jf.getInputStream(jf.getEntry(entryName)); 853 // BEGIN android-removed 854 // jf.close(); 855 // END android-removed 856 assertTrue("Returned invalid stream", is.available() > 0); 857 int r = is.read(b, 0, 1024); 858 is.close(); 859 StringBuffer sb = new StringBuffer(r); 860 for (int i = 0; i < r; i++) { 861 sb.append((char) (b[i] & 0xff)); 862 } 863 String contents = sb.toString(); 864 assertTrue("Incorrect stream read", contents.indexOf("bar") > 0); 865 // BEGIN android-added 866 jf.close(); 867 // END android-added 868 } catch (Exception e) { 869 fail("Exception during test: " + e.toString()); 870 } 871 872 try { 873 JarFile jf = new JarFile(localFile); 874 InputStream in = jf.getInputStream(new JarEntry("invalid")); 875 assertNull("Got stream for non-existent entry", in); 876 } catch (Exception e) { 877 fail("Exception during test 2: " + e); 878 } 879 880 try { 881 Support_Resources.copyFile(resources, null, jarName); 882 File signedFile = new File(resources, jarName); 883 JarFile jf = new JarFile(signedFile); 884 JarEntry jre = new JarEntry("foo/bar/A.class"); 885 jf.getInputStream(jre); 886 // InputStream returned in any way, exception can be thrown in case 887 // of reading from this stream only. 888 // fail("Should throw ZipException"); 889 } catch (ZipException ee) { 890 // expected 891 } 892 893 try { 894 Support_Resources.copyFile(resources, null, jarName); 895 File signedFile = new File(resources, jarName); 896 JarFile jf = new JarFile(signedFile); 897 JarEntry jre = new JarEntry("foo/bar/A.class"); 898 jf.close(); 899 jf.getInputStream(jre); 900 // InputStream returned in any way, exception can be thrown in case 901 // of reading from this stream only. 902 // The same for IOException 903 fail("Should throw IllegalStateException"); 904 } catch (IllegalStateException ee) { 905 // expected 906 } 907 } 908 909 /** 910 * The jar is intact, but the entry object is modified. 911 */ 912 // Regression test for issue introduced by HARMONY-4569: signed archives containing files with size 0 could not get verified. 913 public void testJarVerificationEmptyEntry() throws IOException { 914 Support_Resources.copyFile(resources, null, emptyEntryJar); 915 File f = new File(resources, emptyEntryJar); 916 917 JarFile jarFile = new JarFile(f); 918 919 ZipEntry zipEntry = jarFile.getJarEntry(emptyEntry1); 920 int res = jarFile.getInputStream(zipEntry).read(new byte[100], 0, 100); 921 assertEquals("Wrong length of empty jar entry", -1, res); 922 923 zipEntry = jarFile.getJarEntry(emptyEntry2); 924 res = jarFile.getInputStream(zipEntry).read(new byte[100], 0, 100); 925 assertEquals("Wrong length of empty jar entry", -1, res); 926 927 zipEntry = jarFile.getJarEntry(emptyEntry3); 928 res = jarFile.getInputStream(zipEntry).read(); 929 assertEquals("Wrong length of empty jar entry", -1, res); 930 } 931 } 932