8219861: Add new keytool -showinfo -tls command for displaying TLS configuration information
authorweijun
Thu, 04 Apr 2019 20:22:16 +0800
changeset 54421 a7df0de0835a
parent 54420 724b9e361cb6
child 54422 f562f8318ebd
8219861: Add new keytool -showinfo -tls command for displaying TLS configuration information Reviewed-by: mullan
src/java.base/share/classes/sun/security/tools/keytool/Main.java
src/java.base/share/classes/sun/security/tools/keytool/Resources.java
src/java.base/share/classes/sun/security/tools/keytool/ShowInfo.java
--- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java	Tue Mar 26 01:46:06 2019 -0700
+++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java	Thu Apr 04 20:22:16 2019 +0800
@@ -175,6 +175,8 @@
     private Set<char[]> passwords = new HashSet<>();
     private String startDate = null;
 
+    private boolean tlsInfo = false;
+
     private List<String> ids = new ArrayList<>();   // used in GENCRL
     private List<String> v3ext = new ArrayList<>();
 
@@ -260,6 +262,8 @@
         STOREPASSWD("Changes.the.store.password.of.a.keystore",
             NEW, KEYSTORE, CACERTS, STOREPASS, STORETYPE, PROVIDERNAME,
             ADDPROVIDER, PROVIDERCLASS, PROVIDERPATH, V),
+        SHOWINFO("showinfo.command.help",
+            TLS, V),
 
         // Undocumented start here, KEYCLONE is used a marker in -help;
 
@@ -365,6 +369,7 @@
         STARTDATE("startdate", "<date>", "certificate.validity.start.date.time"),
         STOREPASS("storepass", "<arg>", "keystore.password"),
         STORETYPE("storetype", "<type>", "keystore.type"),
+        TLS("tls", null, "tls.option.help"),
         TRUSTCACERTS("trustcacerts", null, "trust.certificates.from.cacerts"),
         V("v", null, "verbose.output"),
         VALIDITY("validity", "<days>", "validity.number.of.days");
@@ -678,6 +683,8 @@
                 protectedPath = true;
             } else if (collator.compare(flags, "-srcprotected") == 0) {
                 srcprotectedPath = true;
+            } else if (collator.compare(flags, "-tls") == 0) {
+                tlsInfo = true;
             } else  {
                 System.err.println(rb.getString("Illegal.option.") + flags);
                 tinyHelp();
@@ -705,7 +712,7 @@
     }
 
     boolean isKeyStoreRelated(Command cmd) {
-        return cmd != PRINTCERT && cmd != PRINTCERTREQ;
+        return cmd != PRINTCERT && cmd != PRINTCERTREQ && cmd != SHOWINFO;
     }
 
     /**
@@ -874,8 +881,7 @@
         // Check if keystore exists.
         // If no keystore has been specified at the command line, try to use
         // the default, which is located in $HOME/.keystore.
-        // If the command is "genkey", "identitydb", "import", or "printcert",
-        // it is OK not to have a keystore.
+        // No need to check if isKeyStoreRelated(command) is false.
 
         // DO NOT open the existing keystore if this is an in-place import.
         // The keystore should be created as brand new.
@@ -889,6 +895,9 @@
                 }
                 ksStream = new FileInputStream(ksfile);
             } catch (FileNotFoundException e) {
+                // These commands do not need the keystore to be existing.
+                // Either it will create a new one or the keystore is
+                // optional (i.e. PRINTCRL).
                 if (command != GENKEYPAIR &&
                         command != GENSECKEY &&
                         command != IDENTITYDB &&
@@ -1311,6 +1320,8 @@
             }
         } else if (command == PRINTCRL) {
             doPrintCRL(filename, out);
+        } else if (command == SHOWINFO) {
+            doShowInfo();
         }
 
         // If we need to save the keystore, do so.
@@ -2707,6 +2718,14 @@
         }
     }
 
+    private void doShowInfo() throws Exception {
+        if (tlsInfo) {
+            ShowInfo.tls(verbose);
+        } else {
+            System.out.println(rb.getString("showinfo.no.option"));
+        }
+    }
+
     private Collection<? extends Certificate> generateCertificates(InputStream in)
             throws CertificateException, IOException {
         byte[] data = in.readAllBytes();
--- a/src/java.base/share/classes/sun/security/tools/keytool/Resources.java	Tue Mar 26 01:46:06 2019 -0700
+++ b/src/java.base/share/classes/sun/security/tools/keytool/Resources.java	Thu Apr 04 20:22:16 2019 +0800
@@ -96,6 +96,8 @@
                 "Generates a self-signed certificate"}, //-selfcert
         {"Changes.the.store.password.of.a.keystore",
                 "Changes the store password of a keystore"}, //-storepasswd
+        {"showinfo.command.help", "Displays security-related information"},
+
         // keytool: help: options
         {"alias.name.of.the.entry.to.process",
                 "alias name of the entry to process"}, //-alias
@@ -141,6 +143,7 @@
                 "do not prompt"}, //-noprompt
         {"password.through.protected.mechanism",
                 "password through protected mechanism"}, //-protected
+        {"tls.option.help", "Displays TLS configuration information"},
 
         // The following 2 values should span 2 lines, the first for the
         // option itself, the second for its -providerArg value.
@@ -472,6 +475,8 @@
         {"backup.keystore.warning", "The original keystore \"%1$s\" is backed up as \"%3$s\"..."},
         {"importing.keystore.status", "Importing keystore %1$s to %2$s..."},
         {"keyalg.option.1.missing.warning", "No -keyalg option. The default key algorithm (%s) is a legacy algorithm and is no longer recommended. In a subsequent release of the JDK, the default will be removed and the -keyalg option must be specified."},
+
+        {"showinfo.no.option", "Missing option for -showinfo. Try \"keytool -showinfo -tls\"."},
     };
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/tools/keytool/ShowInfo.java	Thu Apr 04 20:22:16 2019 +0800
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package sun.security.tools.keytool;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+
+class ShowInfo {
+
+    // verbose is not used yet.
+    static void tls(boolean verbose) throws Exception {
+
+        SSLSocket ssls = (SSLSocket)
+                SSLContext.getDefault().getSocketFactory().createSocket();
+
+        System.out.println("Enabled Protocols");
+        System.out.println("-----------------");
+        for (String s : ssls.getEnabledProtocols()) {
+            System.out.println(s);
+        }
+
+        System.out.println();
+
+        System.out.println("Enabled Cipher Suites");
+        System.out.println("---------------------");
+        for (String s : ssls.getEnabledCipherSuites()) {
+            System.out.println(s);
+        }
+    }
+}