Path: blob/master/test/jdk/sun/security/tools/jarsigner/InsufficientSectionDelimiter.java
41152 views
/*1* Copyright (c) 2019, 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*/2223import java.io.File;24import java.io.IOException;25import java.io.OutputStream;26import java.nio.file.Files;27import java.nio.file.Path;28import java.util.Map;29import java.util.stream.Stream;30import java.util.jar.Attributes.Name;31import java.util.jar.Manifest;32import jdk.test.lib.util.JarUtils;33import jdk.test.lib.SecurityTools;34import org.testng.annotations.BeforeTest;35import org.testng.annotations.BeforeMethod;36import org.testng.annotations.DataProvider;37import org.testng.annotations.Factory;38import org.testng.annotations.Test;3940import static java.nio.charset.StandardCharsets.UTF_8;4142/**43* @test44* @bug 821737545* @library /test/lib46* @run testng InsufficientSectionDelimiter47* @summary Checks some cases signing a jar the manifest of which has no or48* only one line break at the end and no proper delimiting blank line does not49* result in an invalid signed jar without jarsigner noticing and failing.50*51* <p>See also<ul>52* <li>{@link PreserveRawManifestEntryAndDigest} with an update of a signed53* jar with a different signer whereas this test just signs with one signer54* </li>55* <li>{@link WasSignedByOtherSigner} for a test that detects if56* {@code wasSigned} in {@link jdk.security.jarsigner.JarSigner#sign0} was set57* correctly determining whether or not to re-write the manifest, and</li>58* <li>{@code diffend.sh} for another similar test</li></ul>59*/60public class InsufficientSectionDelimiter {6162static final String KEYSTORE_FILENAME = "test.jks";6364@BeforeTest65public void prepareCertificate() throws Exception {66SecurityTools.keytool("-genkeypair -keyalg EC -keystore "67+ KEYSTORE_FILENAME + " -storepass changeit -keypass changeit"68+ " -alias a -dname CN=A").shouldHaveExitValue(0);69}7071@BeforeTest72public void prepareFakeSfFile() throws IOException {73new File("META-INF").mkdir();74Files.write(Path.of("META-INF/.SF"), (75Name.SIGNATURE_VERSION + ": 1.0\r\n" +76"-Digest-Manifest: \r\n\r\n").getBytes(UTF_8));77}7879@DataProvider(name = "parameters")80public static Object[][] parameters() {81return new String[][] { { "" }, { "\n" }, { "\r" }, { "\r\n" } };82}8384@Factory(dataProvider = "parameters")85public static Object[] createTests(String lineBreak) {86return new Object[] { new InsufficientSectionDelimiter(lineBreak) };87}8889final String lineBreak;90final String jarFilenameSuffix;9192InsufficientSectionDelimiter(String lineBreak) {93this.lineBreak = lineBreak;94jarFilenameSuffix = Utils.escapeStringWithNumbers(lineBreak);95}9697@BeforeMethod98public void verbose() {99System.out.println("lineBreak = "100+ Utils.escapeStringWithNumbers(lineBreak));101}102103void test(String jarFilenamePrefix, String... files) throws Exception {104String jarFilename = jarFilenamePrefix + jarFilenameSuffix + ".jar";105JarUtils.createJarFile(Path.of(jarFilename), new Manifest() {106@Override public void write(OutputStream out) throws IOException {107out.write((Name.MANIFEST_VERSION + ": 1.0" +108lineBreak).getBytes(UTF_8));109}110}, Path.of("."), Stream.of(files).map(Path::of).toArray(Path[]::new)111);112Utils.echoManifest(Utils.readJarManifestBytes(113jarFilename), "unsigned jar");114try {115SecurityTools.jarsigner("-keystore " + KEYSTORE_FILENAME +116" -storepass changeit -verbose -debug " + jarFilename +117" a").shouldHaveExitValue(0);118Utils.echoManifest(Utils.readJarManifestBytes(119jarFilename), "signed jar");120} catch (Exception e) {121if (lineBreak.isEmpty()) {122return; // invalid manifest without trailing line break123}124throw e;125}126127// remove META-INF/.SF from signed jar which would not validate128// (not added in all the test cases)129JarUtils.updateJar(jarFilename, "verify-" + jarFilename,130Map.of("META-INF/.SF", false));131SecurityTools.jarsigner("-verify -strict -keystore " +132KEYSTORE_FILENAME + " -storepass changeit -debug -verbose " +133"verify-" + jarFilename + " a").shouldHaveExitValue(0);134}135136/**137* Test that signing a jar which has never been signed yet and contains138* no signature related files with a manifest that ends immediately after139* the last main attributes value byte or only one line break and no blank140* line produces a valid signed jar or an error if the manifest ends141* without line break.142*/143@Test144public void testOnlyMainAttrs() throws Exception {145test("testOnlyMainAttrs");146}147148/**149* Test that signing a jar with a manifest that ends immediately after150* the last main attributes value byte or with too few line break151* characters to properly delimit an individual section and has a fake152* signing related file to trigger a signature update or more specifically153* wasSigned in JarSigner.sign0 to become true produces a valid signed jar154* or an error if the manifest ends without line break.155* <p>156* Only one line break and hence no blank line ('\r', '\n', or '\r\n')157* after last main attributes value byte is too little to delimit an158* individual section to hold a file's digest but acceptable if no159* individual section has to be added because no contained file has to be160* signed as is the case in this test.161*162* @see #testMainAttrsWasSignedAddFile163*/164@Test165public void testMainAttrsWasSigned() throws Exception {166test("testMainAttrsWasSigned", "META-INF/.SF");167}168169/**170* Test that signing a jar with a manifest that ends immediately after171* the last main attributes value byte or with too few line break172* characters to properly delimit an individual section and has a fake173* signing related file to trigger a signature update or more specifically174* wasSigned in JarSigner.sign0 to become true produces no invalid signed175* jar or an error if the manifest ends without line break.176* <p>177* Only one line break and hence no blank line ('\r', '\n', or '\r\n')178* after the last main attributes value byte is too little to delimit an179* individual section which would be required here to save the digest of a180* contained file to be signed.181* <p>182* Changing the delimiters after the main attributes changes the main183* attributes digest but184* {@link SignatureFileVerifier#verifyManifestMainAttrs} and185* {@link ManifestDigester#digestWorkaround} work around it.186*/187@Test188public void testMainAttrsWasSignedAddFile() throws Exception {189Files.write(Path.of("test.txt"), "test.txt".getBytes(UTF_8));190test("testMainAttrsWasSignedAddFile", "META-INF/.SF", "test.txt");191}192193}194195196