| /* |
| * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| /* |
| * @test |
| * @bug 6802846 8172529 8227758 8260960 |
| * @summary jarsigner needs enhanced cert validation(options) |
| * @library /test/lib |
| * @run main/timeout=240 ConciseJarsigner |
| */ |
| |
| import jdk.test.lib.Asserts; |
| import jdk.test.lib.SecurityTools; |
| import jdk.test.lib.process.OutputAnalyzer; |
| |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.util.Calendar; |
| import java.util.List; |
| |
| public class ConciseJarsigner { |
| |
| static OutputAnalyzer kt(String cmd) throws Exception { |
| // Choose 2048-bit RSA to make sure it runs fine and fast. In |
| // fact, every keyalg/keysize combination is OK for this test. |
| return SecurityTools.keytool("-storepass changeit -keypass changeit " |
| + "-keystore ks -keyalg rsa -keysize 2048 " + cmd); |
| } |
| |
| static void gencert(String owner, String cmd) throws Exception { |
| kt("-certreq -alias " + owner + " -file tmp.req"); |
| kt("-gencert -infile tmp.req -outfile tmp.cert " + cmd); |
| kt("-import -alias " + owner + " -file tmp.cert"); |
| } |
| |
| static OutputAnalyzer js(String cmd) throws Exception { |
| return SecurityTools.jarsigner("-debug " + cmd); |
| } |
| |
| public static void main(String[] args) throws Exception { |
| |
| Files.write(Path.of("A1"), List.of("a1")); |
| Files.write(Path.of("A2"), List.of("a2")); |
| Files.write(Path.of("A3"), List.of("a3")); |
| Files.write(Path.of("A4"), List.of("a4")); |
| Files.write(Path.of("A5"), List.of("a5")); |
| Files.write(Path.of("A6"), List.of("a6")); |
| |
| String year = "" + Calendar.getInstance().get(Calendar.YEAR); |
| |
| // ========================================================== |
| // First part: output format |
| // ========================================================== |
| |
| kt("-genkeypair -alias a1 -dname CN=a1 -validity 366"); |
| kt("-genkeypair -alias a2 -dname CN=a2 -validity 366"); |
| |
| // a.jar includes 8 unsigned, 2 signed by a1 and a2, 2 signed by a3 |
| SecurityTools.jar("cvf a.jar A1 A2"); |
| js("-keystore ks -storepass changeit a.jar a1"); |
| SecurityTools.jar("uvf a.jar A3 A4"); |
| js("-keystore ks -storepass changeit a.jar a2"); |
| SecurityTools.jar("uvf a.jar A5 A6"); |
| |
| // Verify OK |
| js("-verify a.jar").shouldHaveExitValue(0); |
| |
| // 4(chainNotValidated)+16(hasUnsignedEntry) |
| js("-verify a.jar -strict").shouldHaveExitValue(20); |
| |
| // 16(hasUnsignedEntry) |
| js("-verify a.jar -strict -keystore ks -storepass changeit") |
| .shouldHaveExitValue(16); |
| |
| // 16(hasUnsignedEntry)+32(notSignedByAlias) |
| js("-verify a.jar a1 -strict -keystore ks -storepass changeit") |
| .shouldHaveExitValue(48); |
| |
| // 16(hasUnsignedEntry) |
| js("-verify a.jar a1 a2 -strict -keystore ks -storepass changeit") |
| .shouldHaveExitValue(16); |
| |
| // 12 entries all together |
| Asserts.assertTrue(js("-verify a.jar -verbose") |
| .asLines().stream() |
| .filter(s -> s.contains(year)) |
| .count() == 12); |
| |
| // 12 entries all listed |
| Asserts.assertTrue(js("-verify a.jar -verbose:grouped") |
| .asLines().stream() |
| .filter(s -> s.contains(year)) |
| .count() == 12); |
| |
| // 5 groups: MANIFEST, signature related entries, directory entries, |
| // signed entries, and unsigned entries. |
| Asserts.assertTrue(js("-verify a.jar -verbose:summary") |
| .asLines().stream() |
| .filter(s -> s.contains(year)) |
| .count() == 5); |
| |
| // still 5 groups, but MANIFEST group and directiry entry group |
| // have no other file |
| Asserts.assertTrue(js("-verify a.jar -verbose:summary") |
| .asLines().stream() |
| .filter(s -> s.contains("more)")) |
| .count() == 3); |
| |
| // 6 groups: MANIFEST, signature related entries, directory entries, |
| // signed entries by a1/a2, signed entries by a2, and unsigned entries. |
| Asserts.assertTrue(js("-verify a.jar -verbose:summary -certs") |
| .asLines().stream() |
| .filter(s -> s.contains(year)) |
| .count() == 6); |
| |
| // 2 for MANIFEST, 2*2 for A1/A2, 2 for A3/A4 |
| Asserts.assertTrue(js("-verify a.jar -verbose -certs") |
| .asLines().stream() |
| .filter(s -> s.contains("[certificate")) |
| .count() == 8); |
| |
| // a1,a2 for MANIFEST, a1,a2 for A1/A2, a2 for A3/A4 |
| Asserts.assertTrue(js("-verify a.jar -verbose:grouped -certs") |
| .asLines().stream() |
| .filter(s -> s.contains("[certificate")) |
| .count() == 5); |
| |
| // a1,a2 for MANIFEST, a1,a2 for A1/A2, a2 for A3/A4 |
| Asserts.assertTrue(js("-verify a.jar -verbose:summary -certs") |
| .asLines().stream() |
| .filter(s -> s.contains("[certificate")) |
| .count() == 5); |
| |
| // still 6 groups, but MANIFEST group and directory entry group |
| // have no other file |
| Asserts.assertTrue(js("-verify a.jar -verbose:summary -certs") |
| .asLines().stream() |
| .filter(s -> s.contains("more)")) |
| .count() == 4); |
| |
| // ========================================================== |
| // Second part: exit code 2, 4, 8. |
| // 16 and 32 already covered in the first part |
| // ========================================================== |
| |
| kt("-genkeypair -alias ca -dname CN=ca -ext bc -validity 365"); |
| kt("-genkeypair -alias expired -dname CN=expired"); |
| gencert("expired", "-alias ca -startdate -10m"); |
| kt("-genkeypair -alias notyetvalid -dname CN=notyetvalid"); |
| gencert("notyetvalid", "-alias ca -startdate +1m"); |
| kt("-genkeypair -alias badku -dname CN=badku"); |
| gencert("badku", "-alias ca -ext KU=cRLSign -validity 365"); |
| kt("-genkeypair -alias badeku -dname CN=badeku"); |
| gencert("badeku", "-alias ca -ext EKU=sa -validity 365"); |
| kt("-genkeypair -alias goodku -dname CN=goodku"); |
| gencert("goodku", "-alias ca -ext KU=dig -validity 365"); |
| kt("-genkeypair -alias goodeku -dname CN=goodeku"); |
| gencert("goodeku", "-alias ca -ext EKU=codesign -validity 365"); |
| |
| js("-strict -keystore ks -storepass changeit a.jar expired") |
| .shouldHaveExitValue(4); |
| |
| js("-strict -keystore ks -storepass changeit a.jar notyetvalid") |
| .shouldHaveExitValue(4); |
| |
| js("-strict -keystore ks -storepass changeit a.jar badku") |
| .shouldHaveExitValue(8); |
| |
| js("-strict -keystore ks -storepass changeit a.jar badeku") |
| .shouldHaveExitValue(8); |
| |
| js("-strict -keystore ks -storepass changeit a.jar goodku") |
| .shouldHaveExitValue(0); |
| |
| js("-strict -keystore ks -storepass changeit a.jar goodeku") |
| .shouldHaveExitValue(0); |
| |
| // badchain signed by ca1, but ca1 is removed later |
| kt("-genkeypair -alias badchain -dname CN=badchain -validity 365"); |
| kt("-genkeypair -alias ca1 -dname CN=ca1 -ext bc -validity 365"); |
| gencert("badchain", "-alias ca1 -validity 365"); |
| |
| // save ca1.cert for easy replay |
| kt("-exportcert -file ca1.cert -alias ca1"); |
| kt("-delete -alias ca1"); |
| |
| js("-strict -keystore ks -storepass changeit a.jar badchain") |
| .shouldHaveExitValue(4); |
| |
| js("-verify a.jar").shouldHaveExitValue(0); |
| |
| // ========================================================== |
| // Third part: -certchain test |
| // ========================================================== |
| |
| // altchain signed by ca2 |
| kt("-genkeypair -alias altchain -dname CN=altchain -validity 365"); |
| kt("-genkeypair -alias ca2 -dname CN=ca2 -ext bc -validity 365"); |
| kt("-certreq -alias altchain -file altchain.req"); |
| Files.write(Path.of("certchain"), List.of( |
| kt("-gencert -alias ca2 -validity 365 -rfc -infile altchain.req") |
| .getOutput(), |
| kt("-exportcert -alias ca2 -rfc").getOutput())); |
| |
| // Self-signed cert does not work |
| js("-strict -keystore ks -storepass changeit a.jar altchain") |
| .shouldHaveExitValue(4); |
| |
| // -certchain works |
| js("-strict -keystore ks -storepass changeit -certchain certchain " |
| + "a.jar altchain") |
| .shouldHaveExitValue(0); |
| |
| // if ca2 is removed and cert is imported, -certchain won't work |
| // because this certificate entry is not trusted |
| // save ca2.cert for easy replay |
| kt("-exportcert -file ca2.cert -alias ca2"); |
| kt("-delete -alias ca2"); |
| kt("-importcert -file certchain -alias altchain -noprompt"); |
| js("-strict -keystore ks -storepass changeit " |
| + "-certchain certchain a.jar altchain") |
| .shouldHaveExitValue(4); |
| |
| js("-verify a.jar").shouldHaveExitValue(0); |
| |
| // ========================================================== |
| // 8172529 |
| // ========================================================== |
| |
| kt("-genkeypair -alias ee -dname CN=ee"); |
| kt("-genkeypair -alias caone -dname CN=caone -ext bc:c"); |
| kt("-genkeypair -alias catwo -dname CN=catwo -ext bc:c"); |
| |
| kt("-certreq -alias ee -file ee.req"); |
| kt("-certreq -alias catwo -file catwo.req"); |
| |
| // This certchain contains a cross-signed weak catwo.cert |
| Files.write(Path.of("ee2"), List.of( |
| kt("-gencert -alias catwo -rfc -infile ee.req").getOutput(), |
| kt("-gencert -alias caone -sigalg MD5withRSA -rfc " |
| + "-infile catwo.req").getOutput())); |
| |
| kt("-importcert -alias ee -file ee2"); |
| |
| SecurityTools.jar("cvf a.jar A1"); |
| js("-strict -keystore ks -storepass changeit a.jar ee") |
| .shouldHaveExitValue(0); |
| js("-strict -keystore ks -storepass changeit -verify a.jar") |
| .shouldHaveExitValue(0); |
| } |
| } |