6868579: RFE: jarsigner to support reading password from environment variable
authorweijun
Fri, 02 Oct 2009 18:49:46 +0800
changeset 3951 e821908c953e
parent 3950 5e02ff54347b
child 3953 b16e7f05ee06
6868579: RFE: jarsigner to support reading password from environment variable Reviewed-by: xuelei, wetmore
jdk/src/share/classes/sun/security/tools/JarSigner.java
jdk/src/share/classes/sun/security/tools/KeyTool.java
jdk/src/share/classes/sun/security/util/Resources.java
jdk/test/sun/security/tools/jarsigner/passtype.sh
--- a/jdk/src/share/classes/sun/security/tools/JarSigner.java	Fri Oct 02 18:49:05 2009 +0800
+++ b/jdk/src/share/classes/sun/security/tools/JarSigner.java	Fri Oct 02 18:49:46 2009 +0800
@@ -291,13 +291,21 @@
         for (n=0; n < args.length; n++) {
 
             String flags = args[n];
+            String modifier = null;
+            if (flags.charAt(0) == '-') {
+                int pos = flags.indexOf(':');
+                if (pos > 0) {
+                    modifier = flags.substring(pos+1);
+                    flags = flags.substring(0, pos);
+                }
+            }
 
             if (collator.compare(flags, "-keystore") == 0) {
                 if (++n == args.length) usageNoArg();
                 keystore = args[n];
             } else if (collator.compare(flags, "-storepass") ==0) {
                 if (++n == args.length) usageNoArg();
-                storepass = args[n].toCharArray();
+                storepass = getPass(modifier, args[n]);
             } else if (collator.compare(flags, "-storetype") ==0) {
                 if (++n == args.length) usageNoArg();
                 storetype = args[n];
@@ -329,7 +337,7 @@
                 debug = true;
             } else if (collator.compare(flags, "-keypass") ==0) {
                 if (++n == args.length) usageNoArg();
-                keypass = args[n].toCharArray();
+                keypass = getPass(modifier, args[n]);
             } else if (collator.compare(flags, "-sigfile") ==0) {
                 if (++n == args.length) usageNoArg();
                 sigfile = args[n];
@@ -355,13 +363,7 @@
             } else if (collator.compare(flags, "-verify") ==0) {
                 verify = true;
             } else if (collator.compare(flags, "-verbose") ==0) {
-                verbose = "all";
-            } else if (collator.compare(flags, "-verbose:all") ==0) {
-                verbose = "all";
-            } else if (collator.compare(flags, "-verbose:summary") ==0) {
-                verbose = "summary";
-            } else if (collator.compare(flags, "-verbose:grouped") ==0) {
-                verbose = "grouped";
+                verbose = (modifier != null) ? modifier : "all";
             } else if (collator.compare(flags, "-sigalg") ==0) {
                 if (++n == args.length) usageNoArg();
                 sigalg = args[n];
@@ -465,18 +467,25 @@
         }
     }
 
-    void usageNoArg() {
+    static char[] getPass(String modifier, String arg) {
+        char[] output = KeyTool.getPassWithModifier(modifier, arg);
+        if (output != null) return output;
+        usage();
+        return null;    // Useless, usage() already exit
+    }
+
+    static void usageNoArg() {
         System.out.println(rb.getString("Option lacks argument"));
         usage();
     }
 
-    void usage() {
+    static void usage() {
         System.out.println();
         System.out.println(rb.getString("Please type jarsigner -help for usage"));
         System.exit(1);
     }
 
-    void fullusage() {
+    static void fullusage() {
         System.out.println(rb.getString
                 ("Usage: jarsigner [options] jar-file alias"));
         System.out.println(rb.getString
--- a/jdk/src/share/classes/sun/security/tools/KeyTool.java	Fri Oct 02 18:49:05 2009 +0800
+++ b/jdk/src/share/classes/sun/security/tools/KeyTool.java	Fri Oct 02 18:49:46 2009 +0800
@@ -352,6 +352,15 @@
             }
 
             /*
+             * Check modifiers
+             */
+            String modifier = null;
+            int pos = flags.indexOf(':');
+            if (pos > 0) {
+                modifier = flags.substring(pos+1);
+                flags = flags.substring(0, pos);
+            }
+            /*
              * command modes
              */
             boolean isCommand = false;
@@ -387,18 +396,18 @@
                 ksfname = args[++i];
             } else if (collator.compare(flags, "-storepass") == 0 ||
                     collator.compare(flags, "-deststorepass") == 0) {
-                storePass = args[++i].toCharArray();
+                storePass = getPass(modifier, args[++i]);
                 passwords.add(storePass);
             } else if (collator.compare(flags, "-storetype") == 0 ||
                     collator.compare(flags, "-deststoretype") == 0) {
                 storetype = args[++i];
             } else if (collator.compare(flags, "-srcstorepass") == 0) {
-                srcstorePass = args[++i].toCharArray();
+                srcstorePass = getPass(modifier, args[++i]);
                 passwords.add(srcstorePass);
             } else if (collator.compare(flags, "-srcstoretype") == 0) {
                 srcstoretype = args[++i];
             } else if (collator.compare(flags, "-srckeypass") == 0) {
-                srckeyPass = args[++i].toCharArray();
+                srckeyPass = getPass(modifier, args[++i]);
                 passwords.add(srckeyPass);
             } else if (collator.compare(flags, "-srcprovidername") == 0) {
                 srcProviderName = args[++i];
@@ -408,13 +417,13 @@
             } else if (collator.compare(flags, "-providerpath") == 0) {
                 pathlist = args[++i];
             } else if (collator.compare(flags, "-keypass") == 0) {
-                keyPass = args[++i].toCharArray();
+                keyPass = getPass(modifier, args[++i]);
                 passwords.add(keyPass);
             } else if (collator.compare(flags, "-new") == 0) {
-                newPass = args[++i].toCharArray();
+                newPass = getPass(modifier, args[++i]);
                 passwords.add(newPass);
             } else if (collator.compare(flags, "-destkeypass") == 0) {
-                destKeyPass = args[++i].toCharArray();
+                destKeyPass = getPass(modifier, args[++i]);
                 passwords.add(destKeyPass);
             } else if (collator.compare(flags, "-alias") == 0 ||
                     collator.compare(flags, "-srcalias") == 0) {
@@ -3842,6 +3851,61 @@
                 rb.getString("Command option <flag> needs an argument.")).format(source));
         tinyHelp();
     }
+
+    private char[] getPass(String modifier, String arg) {
+        char[] output = getPassWithModifier(modifier, arg);
+        if (output != null) return output;
+        tinyHelp();
+        return null;    // Useless, tinyHelp() already exits.
+    }
+
+    // This method also used by JarSigner
+    public static char[] getPassWithModifier(String modifier, String arg) {
+        if (modifier == null) {
+            return arg.toCharArray();
+        } else if (collator.compare(modifier, "env") == 0) {
+            String value = System.getenv(arg);
+            if (value == null) {
+                System.err.println(rb.getString(
+                        "Cannot find environment variable: ") + arg);
+                return null;
+            } else {
+                return value.toCharArray();
+            }
+        } else if (collator.compare(modifier, "file") == 0) {
+            try {
+                URL url = null;
+                try {
+                    url = new URL(arg);
+                } catch (java.net.MalformedURLException mue) {
+                    File f = new File(arg);
+                    if (f.exists()) {
+                        url = f.toURI().toURL();
+                    } else {
+                        System.err.println(rb.getString(
+                                "Cannot find file: ") + arg);
+                        return null;
+                    }
+                }
+                BufferedReader br = new BufferedReader(new InputStreamReader(
+                            url.openStream()));
+                String value = br.readLine();
+                br.close();
+                if (value == null) {
+                    return new char[0];
+                } else {
+                    return value.toCharArray();
+                }
+            } catch (IOException ioe) {
+                System.err.println(ioe);
+                return null;
+            }
+        } else {
+            System.err.println(rb.getString("Unknown password type: ") +
+                    modifier);
+            return null;
+        }
+    }
 }
 
 // This class is exactly the same as com.sun.tools.javac.util.Pair,
@@ -3881,3 +3945,4 @@
         return new Pair<A,B>(a,b);
     }
 }
+
--- a/jdk/src/share/classes/sun/security/util/Resources.java	Fri Oct 02 18:49:05 2009 +0800
+++ b/jdk/src/share/classes/sun/security/util/Resources.java	Fri Oct 02 18:49:46 2009 +0800
@@ -178,6 +178,10 @@
         {"keytool error: ", "keytool error: "},
         {"Illegal option:  ", "Illegal option:  "},
         {"Illegal value: ", "Illegal value: "},
+        {"Unknown password type: ", "Unknown password type: "},
+        {"Cannot find environment variable: ",
+                "Cannot find environment variable: "},
+        {"Cannot find file: ", "Cannot find file: "},
         {"Command option <flag> needs an argument.", "Command option {0} needs an argument."},
         {"Warning:  Different store and key passwords not supported for PKCS12 KeyStores. Ignoring user-specified <command> value.",
                 "Warning:  Different store and key passwords not supported for PKCS12 KeyStores. Ignoring user-specified {0} value."},
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/tools/jarsigner/passtype.sh	Fri Oct 02 18:49:46 2009 +0800
@@ -0,0 +1,72 @@
+#
+# Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+# @test
+# @bug 6868579
+# @summary RFE: jarsigner to support reading password from environment variable
+#
+
+if [ "${TESTJAVA}" = "" ] ; then
+  JAVAC_CMD=`which javac`
+  TESTJAVA=`dirname $JAVAC_CMD`/..
+fi
+
+# set platform-dependent variables
+OS=`uname -s`
+case "$OS" in
+  Windows_* )
+    FS="\\"
+    ;;
+  * )
+    FS="/"
+    ;;
+esac
+
+KS=pt.jks
+JFILE=pt.jar
+
+KT="$TESTJAVA${FS}bin${FS}keytool -keystore $KS -validity 300"
+JAR=$TESTJAVA${FS}bin${FS}jar
+JARSIGNER=$TESTJAVA${FS}bin${FS}jarsigner
+
+rm $KS $JFILE
+
+$KT -alias a -dname CN=a -keyalg rsa -genkey \
+        -storepass test12 -keypass test12 || exit 1
+PASSENV=test12 $KT -alias b -dname CN=b -keyalg rsa -genkey \
+        -storepass:env PASSENV -keypass:env PASSENV || exit 2
+echo test12 > passfile
+$KT -alias c -dname CN=c -keyalg rsa -genkey \
+        -storepass:file passfile -keypass:file passfile || exit 3
+
+echo A > A
+$JAR cvf $JFILE A
+
+$JARSIGNER -keystore $KS -storepass test12 $JFILE a || exit 4
+PASSENV=test12 $JARSIGNER -keystore $KS -storepass:env PASSENV $JFILE b || exit 5
+$JARSIGNER -keystore $KS -storepass:file passfile $JFILE b || exit 6
+
+$JARSIGNER -keystore $KS -verify -debug -strict $JFILE || exit 7
+
+exit 0
+