Path: blob/master/test/jdk/sun/security/tools/jarsigner/EntriesOrder.java
41152 views
/*1* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/**24* @test25* @bug 803157226* @summary jarsigner -verify exits with 0 when a jar file is not properly signed27* @modules java.base/sun.security.tools.keytool28* jdk.jartool/sun.security.tools.jarsigner29* jdk.jartool/sun.tools.jar30* @run main EntriesOrder31*/3233import java.io.FileInputStream;34import java.io.FileOutputStream;35import java.nio.file.Files;36import java.nio.file.Paths;37import java.security.cert.Certificate;38import java.util.*;39import java.util.jar.JarEntry;40import java.util.jar.JarFile;41import java.util.jar.JarInputStream;42import java.util.zip.ZipEntry;43import java.util.zip.ZipOutputStream;4445public class EntriesOrder {4647public static void main(String[] args) throws Exception {4849String[] entries = {50"META-INF/",51"META-INF/MANIFEST.MF",52"META-INF/A.RSA",53"META-INF/A.SF",54"META-INF/inf",55"a"};5657Map<String,byte[]> content = new HashMap<>();5859// We will create a jar containing entries above. Try all permutations60// and confirm 1) When opened as a JarFile, we can always get 3 signed61// ones (MANIFEST, inf, a), and 2) When opened as a JarInputStream,62// when the order is correct (MANIFEST at beginning, followed by RSA/SF,63// directory ignored), we can get 2 signed ones (inf, a).6465// Prepares raw files66Files.write(Paths.get("a"), List.of("a"));67Files.createDirectory(Paths.get("META-INF/"));68Files.write(Paths.get("META-INF/inf"), List.of("inf"));6970// Pack, sign, and extract to get all files71sun.tools.jar.Main m =72new sun.tools.jar.Main(System.out, System.err, "jar");73if (!m.run("cvf a.jar a META-INF/inf".split(" "))) {74throw new Exception("jar creation failed");75}76sun.security.tools.keytool.Main.main(77("-keystore jks -storepass changeit -keypass changeit -dname" +78" CN=A -alias a -genkeypair -keyalg rsa").split(" "));79sun.security.tools.jarsigner.Main.main(80"-keystore jks -storepass changeit a.jar a".split(" "));81m = new sun.tools.jar.Main(System.out, System.err, "jar");82if (!m.run("xvf a.jar".split(" "))) {83throw new Exception("jar extraction failed");84}8586// Data87for (String s: entries) {88if (!s.endsWith("/")) {89content.put(s, Files.readAllBytes(Paths.get(s)));90}91}9293// Test94for (List<String> perm: Permute(entries)) {9596// Recreate a jar97try (ZipOutputStream zos98= new ZipOutputStream(new FileOutputStream("x.jar"))) {99for (String e: perm) {100zos.putNextEntry(new ZipEntry(e));101if (Paths.get(e).toFile().isDirectory()) continue;102zos.write(content.get(e));103}104}105106// Open with JarFile, number of signed entries should be 3.107int cc = 0;108try (JarFile jf = new JarFile("x.jar")) {109Enumeration<JarEntry> jes = jf.entries();110while (jes.hasMoreElements()) {111JarEntry je = jes.nextElement();112jf.getInputStream(je).readAllBytes();113Certificate[] certs = je.getCertificates();114if (certs != null && certs.length > 0) {115cc++;116}117}118}119120if (cc != 3) {121System.out.println(perm + " - jf - " + cc);122throw new Exception();123}124125// Open with JarInputStream126int signed;127128perm.remove("META-INF/");129if (perm.get(0).equals("META-INF/MANIFEST.MF") &&130perm.get(1).contains("/A.") &&131perm.get(2).contains("/A.")) {132signed = 2; // Good order133} else {134signed = 0; // Bad order. In this case, the number of signed135// entries is not documented. Just test impl.136}137138cc = 0;139try (JarInputStream jis140= new JarInputStream(new FileInputStream("x.jar"))) {141while (true) {142JarEntry je = jis.getNextJarEntry();143if (je == null) break;144jis.readAllBytes();145Certificate[] certs = je.getCertificates();146if (certs != null && certs.length > 0) {147cc++;148}149}150}151152if (cc != signed) {153System.out.println(perm + " - jis - " + cc + " " + signed);154throw new Exception();155}156}157}158159// Helper method to return all permutations of an array. Each output can160// be altered without damaging the iteration process.161static Iterable<List<String>> Permute(String[] entries) {162return new Iterable<List<String>>() {163164int s = entries.length;165long c = factorial(s) - 1; // number of permutations166167private long factorial(int n) {168return (n == 1) ? 1: (n * factorial(n-1));169}170171@Override172public Iterator<List<String>> iterator() {173return new Iterator<List<String>>() {174@Override175public boolean hasNext() {176return c >= 0;177}178179@Override180public List<String> next() {181if (c < 0) return null;182List<String> result = new ArrayList<>(s);183LinkedList<String> source = new LinkedList<>(184Arrays.asList(entries));185// Treat c as a integer with different radixes at186// different digits, i.e. at digit 0, radix is s;187// at digit 1, radix is s-1. Thus a s-digit number188// is able to represent s! different values.189long n = c;190for (int i=s; i>=1; i--) {191int x = (int)(n % i);192result.add(source.remove(x));193n = n / i;194}195c--;196return result;197}198};199}200};201}202}203204205