diff options
Diffstat (limited to 'bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/security/BundleToJarInputStreamTest.java')
-rw-r--r-- | bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/security/BundleToJarInputStreamTest.java | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/security/BundleToJarInputStreamTest.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/security/BundleToJarInputStreamTest.java new file mode 100644 index 000000000..52ffb2f1d --- /dev/null +++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/security/BundleToJarInputStreamTest.java @@ -0,0 +1,152 @@ +/******************************************************************************* + * Copyright (c) 2021 IBM Corporation and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ + +package org.eclipse.osgi.tests.security; + +import static org.eclipse.osgi.tests.security.BaseSecurityTest.copy; +import static org.eclipse.osgi.tests.security.BaseSecurityTest.getEntryFile; +import static org.eclipse.osgi.tests.security.BaseSecurityTest.getTestJarPath; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipInputStream; +import org.eclipse.osgi.internal.signedcontent.BundleToJarInputStream; +import org.eclipse.osgi.storage.bundlefile.DirBundleFile; +import org.eclipse.osgi.tests.OSGiTestsActivator; +import org.junit.Test; +import org.osgi.framework.BundleContext; + +public class BundleToJarInputStreamTest { + + static private final List<String> testJarNames = Arrays.asList("multiply_signed", "SHA1withDSA", "SHA1withRSA", + "SHA256withRSA", "SHA384withRSA", "SHA512withRSA", "signed_tsa", "signed_with_corrupt", + "signed_with_metadata_added", "signed_with_metadata_corrupt", "signed_with_metadata_removed", + "signed_with_metadata", "signed_with_missing_digest", "signed_with_sf_corrupted", "signed", "signedJava16", + "test.bug252098", "unsigned"); + + @Test + public void testInputStreamEquality() throws IOException { + for (String testJarName : testJarNames) { + compareContent(testJarName); + } + } + + private void compareContent(String testJarName) throws IOException { + File jar = getEntryFile(getTestJarPath(testJarName)); + File extracted = extract(jar); + compare(jar, extracted); + } + + private void compare(File jar, File extracted) throws IOException { + // Using ZipFile and ZipInputStream to avoid validation + try (ZipFile jarFile = new ZipFile(jar)) { + Set<String> validated = new LinkedHashSet<>(); + BundleToJarInputStream inputToJar = new BundleToJarInputStream(new DirBundleFile(extracted, false)); + try (ZipInputStream jarInput = new ZipInputStream(inputToJar)) { + for (ZipEntry extractedEntry = jarInput + .getNextEntry(); extractedEntry != null; extractedEntry = jarInput.getNextEntry()) { + if (!extractedEntry.isDirectory()) { + byte[] extractedBytes = getBytes(jarInput); + byte[] originalBytes = getBytes( + jarFile.getInputStream(jarFile.getEntry(extractedEntry.getName()))); + assertArrayEquals("Wrong entry content: " + extractedEntry.getName(), originalBytes, + extractedBytes); + validated.add(extractedEntry.getName()); + } + } + } + // make sure manifest and signature files are first + Iterator<String> validpaths = validated.iterator(); + String first = validpaths.next(); + if (first.toUpperCase().endsWith("META-INF/")) { + first = validpaths.next(); + } + assertEquals("Expected manifest.", JarFile.MANIFEST_NAME, first.toUpperCase()); + // If there are signature files, make sure they are before all other entries + AtomicReference<String> foundNonSignatureFile = new AtomicReference<>(); + validpaths.forEachRemaining((s) -> { + if (isSignatureFile(s)) { + assertNull("Found non signature file before.", foundNonSignatureFile.get()); + } else { + foundNonSignatureFile.compareAndSet(null, s); + } + }); + + for (Enumeration<? extends ZipEntry> originalEntries = jarFile.entries(); originalEntries + .hasMoreElements();) { + ZipEntry originalEntry = originalEntries.nextElement(); + validated.remove(originalEntry.getName()); + } + assertTrue("More paths extracted content: " + validated, validated.isEmpty()); + } + } + + private boolean isSignatureFile(String s) { + s = s.toUpperCase(); + if (s.startsWith("META-INF/") && s.indexOf('/', "META-INF/".length()) == -1) { //$NON-NLS-1$ //$NON-NLS-2$ + return s.endsWith(".SF") //$NON-NLS-1$ + || s.endsWith(".DSA") //$NON-NLS-1$ + || s.endsWith(".RSA") //$NON-NLS-1$ + || s.endsWith(".EC"); //$NON-NLS-1$ + } + return false; + } + + byte[] getBytes(InputStream in) throws IOException { + ByteArrayOutputStream content = new ByteArrayOutputStream(); + byte[] drain = new byte[4096]; + for (int read = in.read(drain, 0, drain.length); read != -1; read = in.read(drain, 0, drain.length)) { + content.write(drain, 0, read); + } + return content.toByteArray(); + } + + private File extract(File jar) throws IOException { + BundleContext bc = OSGiTestsActivator.getContext(); + File dir = bc.getDataFile("extracted/" + jar.getName()); + if (dir.isDirectory()) { + return dir; + } + dir.mkdirs(); + try (ZipFile jarFile = new ZipFile(jar)) { + for (Enumeration<? extends ZipEntry> entries = jarFile.entries(); entries.hasMoreElements();) { + ZipEntry entry = entries.nextElement(); + if (!entry.isDirectory()) { + try (InputStream in = jarFile.getInputStream(entry)) { + File destination = new File(dir, entry.getName()); + destination.getParentFile().mkdirs(); + copy(in, destination); + } + } + } + } + return dir; + } +} |