blob: 80a4d3271eefb3c0fa0167254e7353ee29fb1133 [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.security.cts;
import static org.junit.Assert.assertThrows;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@RunWith(AndroidJUnit4.class)
public class ZipPathValidatorTest {
@Test
public void newZipFile_whenZipFileHasDangerousEntriesAndChangeEnabled_throws() throws
Exception {
final String[] dangerousEntryNames = {
"../foo.bar",
"foo/../bar.baz",
"foo/../../bar.baz",
"foo.bar/..",
"foo.bar/../",
"..",
"../",
"/foo",
};
for (String entryName : dangerousEntryNames) {
final File tempFile = File.createTempFile("smdc", "zip");
try {
writeZipFileOutputStreamWithEmptyEntry(tempFile, entryName);
assertThrows(
"ZipException expected for entry: " + entryName,
ZipException.class,
() -> {
new ZipFile(tempFile);
});
} finally {
tempFile.delete();
}
}
}
@Test
public void zipInputStreamGetNextEntry_whenZipFileHasDangerousEntriesAndChangeEnabled_throws()
throws Exception {
final String[] dangerousEntryNames = {
"../foo.bar",
"foo/../bar.baz",
"foo/../../bar.baz",
"foo.bar/..",
"foo.bar/../",
"..",
"../",
"/foo",
};
for (String entryName : dangerousEntryNames) {
byte[] badZipBytes = getZipBytesFromZipOutputStreamWithEmptyEntry(entryName);
try (ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(badZipBytes))) {
assertThrows(
"ZipException expected for entry: " + entryName,
ZipException.class,
() -> {
zis.getNextEntry();
});
}
}
}
@Test
public void newZipFile_whenZipFileHasNormalEntriesAndChangeEnabled_doesNotThrow() throws
Exception {
final String[] normalEntryNames = {
"foo", "foo.bar", "foo..bar",
};
for (String entryName : normalEntryNames) {
final File tempFile = File.createTempFile("smdc", "zip");
try {
writeZipFileOutputStreamWithEmptyEntry(tempFile, entryName);
ZipFile zipFile = new ZipFile((tempFile));
} finally {
tempFile.delete();
}
}
}
@Test
public void
zipInputStreamGetNextEntry_whenZipFileHasNormalEntriesAndChangeEnabled_doesNotThrow()
throws Exception {
final String[] normalEntryNames = {
"foo", "foo.bar", "foo..bar",
};
for (String entryName : normalEntryNames) {
byte[] zipBytes = getZipBytesFromZipOutputStreamWithEmptyEntry(entryName);
ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(zipBytes));
ZipEntry zipEntry = zis.getNextEntry();
}
}
@Test
public void newZipFile_whenZipFileHasNormalAndDangerousEntriesAndChangeDisabled_doesNotThrow()
throws Exception {
final String[] entryNames = {
"../foo.bar",
"foo/../bar.baz",
"foo/../../bar.baz",
"foo.bar/..",
"foo.bar/../",
"..",
"../",
"/foo",
"foo",
"foo.bar",
"foo..bar",
};
for (String entryName : entryNames) {
final File tempFile = File.createTempFile("smdc", "zip");
try {
writeZipFileOutputStreamWithEmptyEntry(tempFile, entryName);
ZipFile zipFile = new ZipFile((tempFile));
} finally {
tempFile.delete();
}
}
}
@Test
public void
zipInputStreamGetNextEntry_whenZipFileHasNormalAndDangerousEntriesAndChangeDisabled_doesNotThrow()
throws Exception {
final String[] entryNames = {
"../foo.bar",
"foo/../bar.baz",
"foo/../../bar.baz",
"foo.bar/..",
"foo.bar/../",
"..",
"../",
"/foo",
"foo",
"foo.bar",
"foo..bar",
};
for (String entryName : entryNames) {
byte[] zipBytes = getZipBytesFromZipOutputStreamWithEmptyEntry(entryName);
ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(zipBytes));
ZipEntry zipEntry = zis.getNextEntry();
}
}
private void writeZipFileOutputStreamWithEmptyEntry(File tempFile, String entryName)
throws IOException {
FileOutputStream tempFileStream = new FileOutputStream(tempFile);
writeZipOutputStreamWithEmptyEntry(tempFileStream, entryName);
tempFileStream.close();
}
private byte[] getZipBytesFromZipOutputStreamWithEmptyEntry(String entryName)
throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
writeZipOutputStreamWithEmptyEntry(bos, entryName);
return bos.toByteArray();
}
private void writeZipOutputStreamWithEmptyEntry(OutputStream os, String entryName)
throws IOException {
ZipOutputStream zos = new ZipOutputStream(os);
ZipEntry entry = new ZipEntry(entryName);
zos.putNextEntry(entry);
zos.write(new byte[2]);
zos.closeEntry();
zos.close();
}
}