8168882: keytool doesn't print certificate info if disabled algorithm was used for signing a jar
authorasmotrak
Tue, 08 Nov 2016 15:55:11 -0800
changeset 41960 916bb3d29d7b
parent 41959 3b3918911a15
child 41961 12edcce2cb80
8168882: keytool doesn't print certificate info if disabled algorithm was used for signing a jar Reviewed-by: weijun, mullan
jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java
jdk/test/lib/security/SecurityTools.java
jdk/test/sun/security/tools/keytool/KeyToolTest.java
jdk/test/sun/security/tools/keytool/PrintSSL.java
jdk/test/sun/security/tools/keytool/ReadJar.java
jdk/test/sun/security/tools/keytool/readjar.sh
--- a/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java	Tue Nov 08 14:29:14 2016 -0800
+++ b/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java	Tue Nov 08 15:55:11 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -84,8 +84,10 @@
 import sun.security.x509.*;
 
 import static java.security.KeyStore.*;
+import java.security.Security;
 import static sun.security.tools.keytool.Main.Command.*;
 import static sun.security.tools.keytool.Main.Option.*;
+import sun.security.util.DisabledAlgorithmConstraints;
 
 /**
  * This tool manages keystores.
@@ -2428,6 +2430,10 @@
 
     private void doPrintCert(final PrintStream out) throws Exception {
         if (jarfile != null) {
+            // reset "jdk.certpath.disabledAlgorithms" security property
+            // to be able to read jars which were signed with weak algorithms
+            Security.setProperty(DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS, "");
+
             JarFile jf = new JarFile(jarfile, true);
             Enumeration<JarEntry> entries = jf.entries();
             Set<CodeSigner> ss = new HashSet<>();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/lib/security/SecurityTools.java	Tue Nov 08 15:55:11 2016 -0800
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import jdk.testlibrary.JDKToolLauncher;
+import jdk.testlibrary.OutputAnalyzer;
+import jdk.testlibrary.ProcessTools;
+
+public class SecurityTools {
+
+    public static final String NO_ALIAS = null;
+
+    // keytool
+
+    public static OutputAnalyzer keytool(List<String> options)
+            throws Throwable {
+
+        JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("keytool")
+                .addVMArg("-Duser.language=en")
+                .addVMArg("-Duser.country=US");
+        for (String option : options) {
+            if (option.startsWith("-J")) {
+                launcher.addVMArg(option.substring(2));
+            } else {
+                launcher.addToolArg(option);
+            }
+        }
+        return ProcessTools.executeCommand(launcher.getCommand());
+    }
+
+    public static OutputAnalyzer keytool(String options) throws Throwable {
+        return keytool(options.split("\\s+"));
+    }
+
+    public static OutputAnalyzer keytool(String... options) throws Throwable {
+        return keytool(List.of(options));
+    }
+
+    // jarsigner
+
+    public static OutputAnalyzer jarsigner(String jar, String alias,
+            List<String> options) throws Throwable {
+        JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jarsigner")
+                .addVMArg("-Duser.language=en")
+                .addVMArg("-Duser.country=US");
+        for (String option : options) {
+            if (option.startsWith("-J")) {
+                launcher.addVMArg(option.substring(2));
+            } else {
+                launcher.addToolArg(option);
+            }
+        }
+        launcher.addToolArg(jar);
+        if (alias != null) {
+            launcher.addToolArg(alias);
+        }
+        return ProcessTools.executeCommand(launcher.getCommand());
+    }
+
+    public static OutputAnalyzer jarsigner(String jar, String alias,
+            String options) throws Throwable {
+
+        return jarsigner(jar, alias, options.split("\\s+"));
+    }
+
+    public static OutputAnalyzer jarsigner(String jar, String alias,
+            String... options) throws Throwable {
+
+        return jarsigner(jar, alias, List.of(options));
+    }
+
+    public static OutputAnalyzer sign(String jar, String alias, String... options)
+            throws Throwable {
+
+        return jarsigner(jar, alias,
+                mergeOptions("-J-Djava.security.egd=file:/dev/./urandom", options));
+    }
+
+    public static OutputAnalyzer verify(String jar, String... options)
+            throws Throwable {
+
+        return jarsigner(jar, NO_ALIAS, mergeOptions("-verify", options));
+    }
+
+    // helper methods
+
+    private static List<String> mergeOptions(
+            String firstOption, String... secondPart) {
+
+        return mergeOptions(List.of(firstOption), secondPart);
+    }
+
+    private static List<String> mergeOptions(
+            List<String> firstPart, String... secondPart) {
+
+        List<String> options = new ArrayList<>(firstPart);
+        Collections.addAll(options, secondPart);
+        return options;
+    }
+}
--- a/jdk/test/sun/security/tools/keytool/KeyToolTest.java	Tue Nov 08 14:29:14 2016 -0800
+++ b/jdk/test/sun/security/tools/keytool/KeyToolTest.java	Tue Nov 08 15:55:11 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2016, 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
@@ -1211,18 +1211,26 @@
     void sqePrintcertTest() throws Exception {
         remove("x.jks");
         remove("mykey.cert");
+        remove("myweakkey.cert");
         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
                 "-keypass changeit -genkeypair -dname CN=olala");
         testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
                 "-export -file mykey.cert -alias mykey");
+        testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
+                "-keypass changeit -genkeypair -dname CN=weak -keyalg rsa " +
+                "-keysize 512 -sigalg MD5withRSA -alias myweakkey");
+        testOK("", "-keystore x.jks -storetype JKS -storepass changeit " +
+                "-export -file myweakkey.cert -alias myweakkey");
         testFail("", "-printcert -file badkeystore");
         testFail("", "-printcert -file a/b/c/d");
         testOK("", "-printcert -file mykey.cert");
+        testOK("", "-printcert -file myweakkey.cert");
         FileInputStream fin = new FileInputStream("mykey.cert");
         testOK(fin, "-printcert");
         fin.close();
         remove("x.jks");
         remove("mykey.cert");
+        remove("myweakkey.cert");
     }
 
     // 8074935: jdk8 keytool doesn't validate pem files for RFC 1421 correctness
--- a/jdk/test/sun/security/tools/keytool/PrintSSL.java	Tue Nov 08 14:29:14 2016 -0800
+++ b/jdk/test/sun/security/tools/keytool/PrintSSL.java	Tue Nov 08 15:55:11 2016 -0800
@@ -24,20 +24,32 @@
 /*
  * @test
  * @bug 6480981 8160624
- * @modules java.base/sun.security.tools.keytool
  * @summary keytool should be able to import certificates from remote SSL server
+ * @library /lib/security
+ * @library /lib/testlibrary
  * @run main/othervm PrintSSL
  */
 
-import java.io.IOException;
 import java.net.ServerSocket;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.util.concurrent.CountDownLatch;
 import javax.net.ssl.SSLServerSocketFactory;
 import javax.net.ssl.SSLSocket;
+import jdk.testlibrary.OutputAnalyzer;
 
 public class PrintSSL {
 
-    public static void main(String[] args) throws Exception {
+    public static void main(String[] args) throws Throwable {
+        Files.deleteIfExists(Paths.get("keystore"));
+
+        // make sure that "-printcert" works with weak algorithms
+        OutputAnalyzer out = SecurityTools.keytool("-genkeypair "
+                + "-keystore keystore -storepass passphrase "
+                + "-keypass passphrase -keyalg rsa -keysize 512 "
+                + "-sigalg MD5withRSA -alias rsa_alias -dname CN=Server");
+        System.out.println(out.getOutput());
+        out.shouldHaveExitValue(0);
 
         int port = new Server().start();
         if(port == -1) {
@@ -47,7 +59,10 @@
         String cmd = String.format(
                 "-debug %s -printcert -sslserver localhost:%s",
                 ((vmOpt == null) ? "" : vmOpt ), port);
-        sun.security.tools.keytool.Main.main(cmd.split("\\s+"));
+
+        out = SecurityTools.keytool(cmd);
+        System.out.println(out.getOutput());
+        out.shouldHaveExitValue(0);
     }
 
     private static class Server implements Runnable {
@@ -68,9 +83,7 @@
         public void run() {
 
             System.setProperty("javax.net.ssl.keyStorePassword", "passphrase");
-            System.setProperty("javax.net.ssl.keyStore",
-                    System.getProperty("test.src", "./")
-                    + "/../../../../javax/net/ssl/etc/keystore");
+            System.setProperty("javax.net.ssl.keyStore", "keystore");
             SSLServerSocketFactory sslssf =
                     (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
             try (ServerSocket server = sslssf.createServerSocket(0)) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/tools/keytool/ReadJar.java	Tue Nov 08 15:55:11 2016 -0800
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2016, 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 6890872 8168882
+ * @summary keytool -printcert to recognize signed jar files
+ * @library /lib/security
+ * @library /lib/testlibrary
+ */
+
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import jdk.testlibrary.JarUtils;
+import jdk.testlibrary.OutputAnalyzer;
+
+public class ReadJar {
+
+    public static void main(String[] args) throws Throwable {
+        testWithMD5();
+    }
+
+    // make sure that -printcert option works
+    // if a weak algorithm was used for signing a jar
+    private static void testWithMD5() throws Throwable {
+        // create jar files
+        JarUtils.createJar("test_md5.jar", "test");
+        JarUtils.createJar("test_rsa.jar", "test");
+
+        // create a keystore and generate keys for jar signing
+        Files.deleteIfExists(Paths.get("keystore"));
+
+        OutputAnalyzer out = SecurityTools.keytool("-genkeypair "
+                + "-keystore keystore -storepass password "
+                + "-keypass password -keyalg rsa -alias rsa_alias -dname CN=A");
+        System.out.println(out.getOutput());
+        out.shouldHaveExitValue(0);
+
+        out = SecurityTools.jarsigner("test_rsa.jar", "rsa_alias",
+                "-keystore keystore -storepass password ");
+        System.out.println(out.getOutput());
+        out.shouldHaveExitValue(0);
+
+        printCert("test_rsa.jar");
+
+        out = SecurityTools.jarsigner("test_md5.jar", "rsa_alias",
+                "-keystore keystore -storepass password "
+                        + "-sigalg MD5withRSA -digestalg MD5");
+        System.out.println(out.getOutput());
+        out.shouldHaveExitValue(0);
+
+        printCert("test_md5.jar");
+    }
+
+    private static void printCert(String jar) throws Throwable {
+        OutputAnalyzer out = SecurityTools.keytool("-printcert -jarfile " + jar);
+        System.out.println(out.getOutput());
+        out.shouldHaveExitValue(0);
+        out.shouldNotContain("Not a signed jar file");
+
+        out = SecurityTools.keytool("-printcert -rfc -jarfile " + jar);
+        System.out.println(out.getOutput());
+        out.shouldHaveExitValue(0);
+        out.shouldNotContain("Not a signed jar file");
+    }
+}
--- a/jdk/test/sun/security/tools/keytool/readjar.sh	Tue Nov 08 14:29:14 2016 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-#
-# Copyright (c) 2009, 2013, 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 6890872
-# @summary keytool -printcert to recognize signed jar files
-#
-
-if [ "${TESTJAVA}" = "" ] ; then
-  JAVAC_CMD=`which javac`
-  TESTJAVA=`dirname $JAVAC_CMD`/..
-  COMPILEJAVA=${TESTJAVA}
-fi
-
-# set platform-dependent variables
-OS=`uname -s`
-case "$OS" in
-  Windows_* )
-    FS="\\"
-    ;;
-  * )
-    FS="/"
-    ;;
-esac
-
-KS=readjar.jks
-rm $KS
-$TESTJAVA${FS}bin${FS}keytool ${TESTTOOLVMOPTS}  -storepass changeit -keypass changeit -keystore $KS \
-        -keyalg rsa -alias x -dname CN=X -genkeypair
-$COMPILEJAVA${FS}bin${FS}jar ${TESTTOOLVMOPTS} cvf readjar.jar $KS
-$COMPILEJAVA${FS}bin${FS}jarsigner ${TESTTOOLVMOPTS} -storepass changeit -keystore $KS readjar.jar x
-
-$TESTJAVA${FS}bin${FS}keytool ${TESTTOOLVMOPTS} -printcert -jarfile readjar.jar || exit 1
-$TESTJAVA${FS}bin${FS}keytool ${TESTTOOLVMOPTS} -printcert -jarfile readjar.jar -rfc || exit 1
-
-exit 0
-