changeset 1711:e782a9564eae

Merge
author michaelm
date Fri, 02 Oct 2009 13:59:37 +0100
parents f0fdc4dd97d5 a6046f6e720e
children 9fcca0aae3da
files
diffstat 17 files changed, 1075 insertions(+), 581 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/sun/security/krb5/Credentials.java	Fri Oct 02 13:57:41 2009 +0100
+++ b/src/share/classes/sun/security/krb5/Credentials.java	Fri Oct 02 13:59:37 2009 +0100
@@ -33,16 +33,11 @@
 
 import sun.security.krb5.internal.*;
 import sun.security.krb5.internal.ccache.CredentialsCache;
-import java.util.StringTokenizer;
 import sun.security.krb5.internal.ktab.*;
 import sun.security.krb5.internal.crypto.EType;
 import java.io.File;
 import java.io.IOException;
 import java.util.Date;
-import java.util.Vector;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
 import java.net.InetAddress;
 
 /**
@@ -378,9 +373,9 @@
 
                 KRBError error = ke.getError();
                 // update salt in PrincipalName
-                byte[] newSalt = error.getSalt();
-                if (newSalt != null && newSalt.length > 0) {
-                    princ.setSalt(new String(newSalt));
+                String newSalt = error.getSalt();
+                if (newSalt != null && newSalt.length() > 0) {
+                    princ.setSalt(newSalt);
                 }
 
                 // refresh keys
--- a/src/share/classes/sun/security/krb5/KrbAsReq.java	Fri Oct 02 13:57:41 2009 +0100
+++ b/src/share/classes/sun/security/krb5/KrbAsReq.java	Fri Oct 02 13:59:37 2009 +0100
@@ -1,5 +1,5 @@
 /*
- * Portions Copyright 2000-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Portions Copyright 2000-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
@@ -56,7 +56,7 @@
     private boolean PA_ENC_TIMESTAMP_REQUIRED = false;
     private boolean pa_exists = false;
     private int pa_etype = 0;
-    private byte[] pa_salt = null;
+    private String pa_salt = null;
     private byte[] pa_s2kparams = null;
 
     // default is address-less tickets
@@ -88,7 +88,7 @@
      * with pre-authentication values
      */
     KrbAsReq(PrincipalName principal, EncryptionKey[] keys,
-        boolean pa_exists, int etype, byte[] salt, byte[] s2kparams)
+        boolean pa_exists, int etype, String salt, byte[] s2kparams)
         throws KrbException, IOException {
         this(keys, // for pre-authentication
              pa_exists, etype, salt, s2kparams, // pre-auth values
@@ -112,7 +112,7 @@
      }
 
     // update with pre-auth info
-    public void updatePA(int etype, byte[] salt, byte[] params, PrincipalName name) {
+    public void updatePA(int etype, String salt, byte[] params, PrincipalName name) {
         // set the pre-auth values
         pa_exists = true;
         pa_etype = etype;
@@ -120,9 +120,8 @@
         pa_s2kparams = params;
 
         // update salt in PrincipalName
-        if (salt != null && salt.length > 0) {
-            String newSalt = new String(salt);
-            name.setSalt(newSalt);
+        if (salt != null && salt.length() > 0) {
+            name.setSalt(salt);
             if (DEBUG) {
                 System.out.println("Updated salt from pre-auth = " + name.getSalt());
             }
@@ -161,7 +160,7 @@
                     char[] password,
                     boolean pa_exists,
                     int etype,
-                    byte[] salt,
+                    String salt,
                     byte[] s2kparams,
                     KDCOptions options,
                     PrincipalName cname,
@@ -246,7 +245,7 @@
                     EncryptionKey[] keys,
                     boolean pa_exists,
                     int etype,
-                    byte[] salt,
+                    String salt,
                     byte[] s2kparams,
                     KDCOptions options,
                     PrincipalName cname,
--- a/src/share/classes/sun/security/krb5/PrincipalName.java	Fri Oct 02 13:57:41 2009 +0100
+++ b/src/share/classes/sun/security/krb5/PrincipalName.java	Fri Oct 02 13:59:37 2009 +0100
@@ -38,6 +38,7 @@
 import java.io.IOException;
 import java.math.BigInteger;
 import sun.security.krb5.internal.ccache.CCacheOutputStream;
+import sun.security.krb5.internal.util.KerberosString;
 
 
 /**
@@ -246,7 +247,7 @@
             DerValue subSubDer;
             while(subDer.getData().available() > 0) {
                 subSubDer = subDer.getData().getDerValue();
-                v.addElement(subSubDer.getGeneralString());
+                v.addElement(new KerberosString(subSubDer).toString());
             }
             if (v.size() > 0) {
                 nameStrings = new String[v.size()];
@@ -554,7 +555,7 @@
         temp = new DerOutputStream();
         DerValue der[] = new DerValue[nameStrings.length];
         for (int i = 0; i < nameStrings.length; i++) {
-            der[i] = new DerValue(DerValue.tag_GeneralString, nameStrings[i]);
+            der[i] = new KerberosString(nameStrings[i]).toDerValue();
         }
         temp.putSequence(der);
         bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x01), temp);
--- a/src/share/classes/sun/security/krb5/Realm.java	Fri Oct 02 13:57:41 2009 +0100
+++ b/src/share/classes/sun/security/krb5/Realm.java	Fri Oct 02 13:59:37 2009 +0100
@@ -31,11 +31,6 @@
 
 package sun.security.krb5;
 
-import sun.security.krb5.Config;
-import sun.security.krb5.PrincipalName;
-import sun.security.krb5.KrbException;
-import sun.security.krb5.Asn1Exception;
-import sun.security.krb5.RealmException;
 import sun.security.krb5.internal.Krb5;
 import sun.security.util.*;
 import java.io.IOException;
@@ -43,6 +38,7 @@
 import java.util.Vector;
 import java.util.Stack;
 import java.util.EmptyStackException;
+import sun.security.krb5.internal.util.KerberosString;
 
 /**
  * Implements the ASN.1 Realm type.
@@ -109,7 +105,7 @@
         if (encoding == null) {
             throw new IllegalArgumentException("encoding can not be null");
         }
-        realm = encoding.getGeneralString();
+        realm = new KerberosString(encoding).toString();
         if (realm == null || realm.length() == 0)
             throw new RealmException(Krb5.REALM_NULL);
         if (!isValidRealmString(realm))
@@ -206,7 +202,7 @@
      */
     public byte[] asn1Encode() throws Asn1Exception, IOException {
         DerOutputStream out = new DerOutputStream();
-        out.putGeneralString(this.realm);
+        out.putDerValue(new KerberosString(this.realm).toDerValue());
         return out.toByteArray();
     }
 
--- a/src/share/classes/sun/security/krb5/internal/ETypeInfo.java	Fri Oct 02 13:57:41 2009 +0100
+++ b/src/share/classes/sun/security/krb5/internal/ETypeInfo.java	Fri Oct 02 13:59:37 2009 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright 2005-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2005-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
@@ -28,6 +28,7 @@
 import sun.security.util.*;
 import sun.security.krb5.Asn1Exception;
 import java.io.IOException;
+import sun.security.krb5.internal.util.KerberosString;
 
 /**
  * Implements the ASN.1 ETYPE-INFO-ENTRY type.
@@ -43,7 +44,7 @@
 public class ETypeInfo {
 
     private int etype;
-    private byte[] salt = null;
+    private String salt = null;
 
     private static final byte TAG_TYPE = 0;
     private static final byte TAG_VALUE = 1;
@@ -51,21 +52,13 @@
     private ETypeInfo() {
     }
 
-    public ETypeInfo(int etype, byte[] salt) {
+    public ETypeInfo(int etype, String salt) {
         this.etype = etype;
-        if (salt != null) {
-            this.salt = salt.clone();
-        }
+        this.salt = salt;
     }
 
     public Object clone() {
-        ETypeInfo etypeInfo = new ETypeInfo();
-        etypeInfo.etype = etype;
-        if (salt != null) {
-            etypeInfo.salt = new byte[salt.length];
-            System.arraycopy(salt, 0, etypeInfo.salt, 0, salt.length);
-        }
-        return etypeInfo;
+        return new ETypeInfo(etype, salt);
     }
 
     /**
@@ -94,7 +87,22 @@
         if (encoding.getData().available() > 0) {
             der = encoding.getData().getDerValue();
             if ((der.getTag() & 0x1F) == 0x01) {
-                this.salt = der.getData().getOctetString();
+                byte[] saltBytes = der.getData().getOctetString();
+
+                // Although salt is defined as an OCTET STRING, it's the
+                // encoding from of a string. As RFC 4120 says:
+                //
+                // "The salt, ..., is also completely unspecified with respect
+                // to character set and is probably locale-specific".
+                //
+                // It's known that this field is using the same encoding as
+                // KerberosString in most implementations.
+
+                if (KerberosString.MSNAME) {
+                    this.salt = new String(saltBytes, "UTF8");
+                } else {
+                    this.salt = new String(saltBytes);
+                }
             }
         }
 
@@ -120,7 +128,11 @@
 
         if (salt != null) {
             temp = new DerOutputStream();
-            temp.putOctetString(salt);
+            if (KerberosString.MSNAME) {
+                temp.putOctetString(salt.getBytes("UTF8"));
+            } else {
+                temp.putOctetString(salt.getBytes());
+            }
             bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
                                         TAG_VALUE), temp);
         }
@@ -135,8 +147,8 @@
         return etype;
     }
 
-    public byte[] getSalt() {
-        return ((salt == null) ? null : salt.clone());
+    public String getSalt() {
+        return salt;
     }
 
 }
--- a/src/share/classes/sun/security/krb5/internal/ETypeInfo2.java	Fri Oct 02 13:57:41 2009 +0100
+++ b/src/share/classes/sun/security/krb5/internal/ETypeInfo2.java	Fri Oct 02 13:59:37 2009 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright 2005-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2005-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
@@ -28,6 +28,7 @@
 import sun.security.util.*;
 import sun.security.krb5.Asn1Exception;
 import java.io.IOException;
+import sun.security.krb5.internal.util.KerberosString;
 
 /**
  * Implements the ASN.1 ETYPE-INFO-ENTRY type.
@@ -54,11 +55,9 @@
     private ETypeInfo2() {
     }
 
-    public ETypeInfo2(int etype, byte[] salt, byte[] s2kparams) {
+    public ETypeInfo2(int etype, String salt, byte[] s2kparams) {
         this.etype = etype;
-        if (salt != null) {
-            this.saltStr = new String(salt);
-        }
+        this.saltStr = salt;
         if (s2kparams != null) {
             this.s2kparams = s2kparams.clone();
         }
@@ -102,7 +101,8 @@
         if (encoding.getData().available() > 0) {
             if ((encoding.getData().peekByte() & 0x1F) == 0x01) {
                 der = encoding.getData().getDerValue();
-                this.saltStr = der.getData().getGeneralString();
+                this.saltStr = new KerberosString(
+                        der.getData().getDerValue()).toString();
             }
         }
 
@@ -136,7 +136,7 @@
 
         if (saltStr != null) {
             temp = new DerOutputStream();
-            temp.putGeneralString(saltStr);
+            temp.putDerValue(new KerberosString(saltStr).toDerValue());
             bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true,
                                         TAG_VALUE1), temp);
         }
@@ -157,8 +157,8 @@
         return etype;
     }
 
-    public byte[] getSalt() {
-        return ((saltStr == null) ? null : saltStr.getBytes());
+    public String getSalt() {
+        return saltStr;
     }
 
     public byte[] getParams() {
--- a/src/share/classes/sun/security/krb5/internal/KRBError.java	Fri Oct 02 13:57:41 2009 +0100
+++ b/src/share/classes/sun/security/krb5/internal/KRBError.java	Fri Oct 02 13:59:37 2009 +0100
@@ -1,5 +1,5 @@
 /*
- * Portions Copyright 2000-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * Portions Copyright 2000-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
@@ -42,6 +42,7 @@
 import java.io.ObjectInputStream;
 import java.math.BigInteger;
 import java.util.Arrays;
+import sun.security.krb5.internal.util.KerberosString;
 /**
  * Implements the ASN.1 KRBError type.
  *
@@ -97,7 +98,7 @@
 
     // pre-auth info
     private int etype = 0;
-    private byte[] salt = null;
+    private String salt = null;
     private byte[] s2kparams = null;
 
     private static boolean DEBUG = Krb5.DEBUG;
@@ -334,8 +335,8 @@
     }
 
     // access pre-auth info
-    public final byte[] getSalt() {
-        return ((salt == null) ? null : salt.clone());
+    public final String getSalt() {
+        return salt;
     }
 
     // access pre-auth info
@@ -415,7 +416,8 @@
         if (der.getData().available() >0) {
             if ((der.getData().peekByte() & 0x1F) == 0x0B) {
                 subDer = der.getData().getDerValue();
-                eText = subDer.getData().getGeneralString();
+                eText = new KerberosString(subDer.getData().getDerValue())
+                        .toString();
             }
         }
         if (der.getData().available() >0) {
@@ -515,7 +517,7 @@
 
         if (eText != null) {
             temp = new DerOutputStream();
-            temp.putGeneralString(eText);
+            temp.putDerValue(new KerberosString(eText).toDerValue());
             bytes.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte)0x0B), temp);
         }
         if (eData != null) {
--- a/src/share/classes/sun/security/krb5/internal/crypto/Des.java	Fri Oct 02 13:57:41 2009 +0100
+++ b/src/share/classes/sun/security/krb5/internal/crypto/Des.java	Fri Oct 02 13:59:37 2009 +0100
@@ -34,17 +34,29 @@
 import javax.crypto.spec.SecretKeySpec;
 import javax.crypto.SecretKeyFactory;
 import javax.crypto.SecretKey;
-import java.security.Security;
-import java.security.Provider;
 import java.security.GeneralSecurityException;
 import javax.crypto.spec.IvParameterSpec;
 import sun.security.krb5.KrbCryptoException;
-import sun.security.krb5.internal.Krb5;
-import java.io.UnsupportedEncodingException;
 import java.util.Arrays;
+import sun.security.action.GetPropertyAction;
 
 public final class Des {
 
+    // RFC 3961 demands that UTF-8 encoding be used in DES's
+    // string-to-key function. For historical reasons, some
+    // implementations use a locale-specific encoding. Even
+    // so, when the client and server use different locales,
+    // they must agree on a common value, normally the one
+    // used when the password is set/reset.
+    //
+    // The following system property is provided to perform the
+    // string-to-key encoding. When set, the specified charset
+    // name is used. Otherwise, the system default charset.
+
+    private final static String CHARSET =
+            java.security.AccessController.doPrivileged(
+            new GetPropertyAction("sun.security.krb5.msinterop.des.s2kcharset"));
+
     private static final long[] bad_keys = {
         0x0101010101010101L, 0xfefefefefefefefeL,
         0x1f1f1f1f1f1f1f1fL, 0xe0e0e0e0e0e0e0e0L,
@@ -226,7 +238,11 @@
 
         // Convert password to byte array
         try {
-            cbytes = (new String(passwdChars)).getBytes();
+            if (CHARSET == null) {
+                cbytes = (new String(passwdChars)).getBytes();
+            } else {
+                cbytes = (new String(passwdChars)).getBytes(CHARSET);
+            }
         } catch (Exception e) {
             // clear-up sensitive information
             if (cbytes != null) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/krb5/internal/util/KerberosString.java	Fri Oct 02 13:59:37 2009 +0100
@@ -0,0 +1,82 @@
+/*
+ * 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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 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.
+ */
+
+package sun.security.krb5.internal.util;
+
+import java.io.IOException;
+import java.security.AccessController;
+import sun.security.action.GetBooleanAction;
+import sun.security.util.DerValue;
+
+/**
+ * Implements the ASN.1 KerberosString type.
+ *
+ * <pre>
+ * KerberosString  ::= GeneralString (IA5String)
+ * </pre>
+ *
+ * This definition reflects the Network Working Group RFC 4120
+ * specification available at
+ * <a href="http://www.ietf.org/rfc/rfc4120.txt">
+ * http://www.ietf.org/rfc/rfc4120.txt</a>.
+ */
+public final class KerberosString {
+    /**
+     * RFC 4120 defines KerberosString as GeneralString (IA5String), which
+     * only includes ASCII characters. However, other implementations have been
+     * known to use GeneralString to contain UTF-8 encoding. To interop
+     * with these implementations, the following system property is defined.
+     * When set as true, KerberosString is encoded as UTF-8. Note that this
+     * only affects the byte encoding, the tag of the ASN.1 type is still
+     * GeneralString.
+     */
+    public static final boolean MSNAME = AccessController.doPrivileged(
+            new GetBooleanAction("sun.security.krb5.msinterop.kstring"));
+
+    private final String s;
+
+    public KerberosString(String s) {
+        this.s = s;
+    }
+
+    public KerberosString(DerValue der) throws IOException {
+        if (der.tag != DerValue.tag_GeneralString) {
+            throw new IOException(
+                "KerberosString's tag is incorrect: " + der.tag);
+        }
+        s = new String(der.getDataBytes(), MSNAME?"UTF8":"ASCII");
+    }
+
+    public String toString() {
+        return s;
+    }
+
+    public DerValue toDerValue() throws IOException {
+        // No need to cache the result since this method is
+        // only called once.
+        return new DerValue(DerValue.tag_GeneralString,
+                s.getBytes(MSNAME?"UTF8":"ASCII"));
+    }
+}
--- a/src/share/classes/sun/security/tools/JarSigner.java	Fri Oct 02 13:57:41 2009 +0100
+++ b/src/share/classes/sun/security/tools/JarSigner.java	Fri Oct 02 13:59:37 2009 +0100
@@ -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/src/share/classes/sun/security/tools/KeyTool.java	Fri Oct 02 13:57:41 2009 +0100
+++ b/src/share/classes/sun/security/tools/KeyTool.java	Fri Oct 02 13:59:37 2009 +0100
@@ -76,6 +76,7 @@
 import sun.security.x509.*;
 
 import static java.security.KeyStore.*;
+import static sun.security.tools.KeyTool.Command.*;
 
 /**
  * This tool manages keystores.
@@ -92,7 +93,7 @@
 public final class KeyTool {
 
     private boolean debug = false;
-    private int command = -1;
+    private Command command = null;
     private String sigAlgName = null;
     private String keyAlgName = null;
     private boolean verbose = false;
@@ -146,24 +147,132 @@
 
     private List <String> v3ext = new ArrayList <String> ();
 
-    private static final int CERTREQ = 1;
-    private static final int CHANGEALIAS = 2;
-    private static final int DELETE = 3;
-    private static final int EXPORTCERT = 4;
-    private static final int GENKEYPAIR = 5;
-    private static final int GENSECKEY = 6;
-    // there is no HELP
-    private static final int IDENTITYDB = 7;
-    private static final int IMPORTCERT = 8;
-    private static final int IMPORTKEYSTORE = 9;
-    private static final int KEYCLONE = 10;
-    private static final int KEYPASSWD = 11;
-    private static final int LIST = 12;
-    private static final int PRINTCERT = 13;
-    private static final int SELFCERT = 14;
-    private static final int STOREPASSWD = 15;
-    private static final int GENCERT = 16;
-    private static final int PRINTCERTREQ = 17;
+    enum Command {
+        CERTREQ("Generates a certificate request",
+            "-alias", "-sigalg", "-file", "-keypass", "-keystore",
+            "-storepass", "-storetype", "-providername", "-providerclass",
+            "-providerarg", "-providerpath", "-v", "-protected"),
+        CHANGEALIAS("Changes an entry's alias",
+            "-alias", "-destalias", "-keypass", "-keystore", "-storepass",
+            "-storetype", "-providername", "-providerclass", "-providerarg",
+            "-providerpath", "-v", "-protected"),
+        DELETE("Deletes an entry",
+            "-alias", "-keystore", "-storepass", "-storetype",
+            "-providername", "-providerclass", "-providerarg",
+            "-providerpath", "-v", "-protected"),
+        EXPORTCERT("Exports certificate",
+            "-rfc", "-alias", "-file", "-keystore", "-storepass",
+            "-storetype", "-providername", "-providerclass", "-providerarg",
+            "-providerpath", "-v", "-protected"),
+        GENKEYPAIR("Generates a key pair",
+            "-alias", "-keyalg", "-keysize", "-sigalg", "-destalias",
+            "-startdate", "-ext", "-validity", "-keypass", "-keystore",
+            "-storepass", "-storetype", "-providername", "-providerclass",
+            "-providerarg", "-providerpath", "-v", "-protected"),
+        GENSECKEY("Generates a secret key",
+            "-alias", "-keypass", "-keyalg", "-keysize", "-keystore",
+            "-storepass", "-storetype", "-providername", "-providerclass",
+            "-providerarg", "-providerpath", "-v", "-protected"),
+        GENCERT("Generates certificate from a certificate request",
+            "-rfc", "-infile", "-outfile", "-alias", "-sigalg",
+            "-startdate", "-ext", "-validity", "-keypass", "-keystore",
+            "-storepass", "-storetype", "-providername", "-providerclass",
+            "-providerarg", "-providerpath", "-v", "-protected"),
+        IDENTITYDB("Imports entries from a JDK 1.1.x-style identity database",
+            "-file", "-storetype", "-keystore", "-storepass", "-providername",
+            "-providerclass", "-providerarg", "-providerpath", "-v"),
+        IMPORTCERT("Imports a certificate or a certificate chain",
+            "-noprompt", "-trustcacerts", "-protected", "-alias", "-file",
+            "-keypass", "-keystore", "-storepass", "-storetype",
+            "-providername", "-providerclass", "-providerarg",
+            "-providerpath", "-v"),
+        IMPORTKEYSTORE("Imports one or all entries from another keystore",
+            "-srckeystore", "-destkeystore", "-srcstoretype",
+            "-deststoretype", "-srcstorepass", "-deststorepass",
+            "-srcprotected", "-srcprovidername", "-destprovidername",
+            "-srcalias", "-destalias", "-srckeypass", "-destkeypass",
+            "-noprompt", "-providerclass", "-providerarg", "-providerpath",
+            "-v"),
+        KEYCLONE("Clones a key entry",
+            "-alias", "-destalias", "-keypass", "-new", "-storetype",
+            "-keystore", "-storepass", "-providername", "-providerclass",
+            "-providerarg", "-providerpath", "-v"),
+        KEYPASSWD("Changes the key password of an entry",
+            "-alias", "-keypass", "-new", "-keystore", "-storepass",
+            "-storetype", "-providername", "-providerclass", "-providerarg",
+            "-providerpath", "-v"),
+        LIST("Lists entries in a keystore",
+            "-rfc", "-alias", "-keystore", "-storepass", "-storetype",
+            "-providername", "-providerclass", "-providerarg",
+            "-providerpath", "-v", "-protected"),
+        PRINTCERT("Prints the content of a certificate",
+            "-rfc", "-file", "-sslserver", "-v"),
+        PRINTCERTREQ("Prints the content of a certificate request",
+            "-file", "-v"),
+        SELFCERT("Generates a self-signed certificate",
+            "-alias", "-sigalg", "-dname", "-startdate", "-validity", "-keypass",
+            "-storetype", "-keystore", "-storepass", "-providername",
+            "-providerclass", "-providerarg", "-providerpath", "-v"),
+        STOREPASSWD("Changes the store password of a keystore",
+            "-new", "-keystore", "-storepass", "-storetype", "-providername",
+            "-providerclass", "-providerarg", "-providerpath", "-v");
+
+        final String description;
+        final String[] options;
+        Command(String d, String... o) {
+            description = d;
+            options = o;
+        }
+        @Override
+        public String toString() {
+            return "-" + name().toLowerCase(Locale.ENGLISH);
+        }
+    };
+
+    private static String[][] options = {
+        // name, arg, description
+        {"-alias", "<alias>", "alias name of the entry to process"},
+        {"-destalias", "<destalias>", "destination alias"},
+        {"-destkeypass", "<arg>", "destination key password"},
+        {"-destkeystore", "<destkeystore>", "destination keystore name"},
+        {"-destprotected", null, "destination keystore password protected"},
+        {"-destprovidername", "<destprovidername>", "destination keystore provider name"},
+        {"-deststorepass", "<arg>", "destination keystore password"},
+        {"-deststoretype", "<deststoretype>", "destination keystore type"},
+        {"-dname", "<dname>", "distinguished name"},
+        {"-ext", "<value>", "X.509 extension"},
+        {"-file", "<filename>", "output file name"},
+        {"-file", "<filename>", "input file name"},
+        {"-infile", "<filename>", "input file name"},
+        {"-keyalg", "<keyalg>", "key algorithm name"},
+        {"-keypass", "<arg>", "key password"},
+        {"-keysize", "<keysize>", "key bit size"},
+        {"-keystore", "<keystore>", "keystore name"},
+        {"-new", "<arg>", "new password"},
+        {"-noprompt", null, "do not prompt"},
+        {"-outfile", "<filename>", "output file name"},
+        {"-protected", null, "password through protected mechanism"},
+        {"-providerarg", "<arg>", "provider argument"},
+        {"-providerclass", "<providerclass>", "provider class name"},
+        {"-providername", "<providername>", "provider name"},
+        {"-providerpath", "<pathlist>", "provider classpath"},
+        {"-rfc", null, "output in RFC style"},
+        {"-sigalg", "<sigalg>", "signature algorithm name"},
+        {"-srcalias", "<srcalias>", "source alias"},
+        {"-srckeypass", "<arg>", "source keystore password"},
+        {"-srckeystore", "<srckeystore>", "source keystore name"},
+        {"-srcprotected", null, "source keystore password protected"},
+        {"-srcprovidername", "<srcprovidername>", "source keystore provider name"},
+        {"-srcstorepass", "<arg>", "source keystore password"},
+        {"-srcstoretype", "<srcstoretype>", "source keystore type"},
+        {"-sslserver", "<server[:port]>", "SSL server host and port"},
+        {"-startdate", "<startdate>", "certificate validity start date/time"},
+        {"-storepass", "<arg>", "keystore password"},
+        {"-storetype", "<storetype>", "keystore type"},
+        {"-trustcacerts", null, "trust certificates from cacerts"},
+        {"-v", null, "verbose output"},
+        {"-validity", "<valDays>", "validity number of days"},
+    };
 
     private static final Class[] PARAM_STRING = { String.class };
 
@@ -192,7 +301,7 @@
     private void run(String[] args, PrintStream out) throws Exception {
         try {
             parseArgs(args);
-            if (command != -1) {
+            if (command != null) {
                 doCommands(out);
             }
         } catch (Exception e) {
@@ -224,59 +333,59 @@
      */
     void parseArgs(String[] args) {
 
-        if (args.length == 0) {
-            usage();
-            return;
-        }
-
         int i=0;
+        boolean help = args.length == 0;
 
         for (i=0; (i < args.length) && args[i].startsWith("-"); i++) {
 
             String flags = args[i];
+
+            // Check if the last option needs an arg
+            if (i == args.length - 1) {
+                for (String[] option: options) {
+                    // Only options with an arg need to be checked
+                    if (collator.compare(flags, option[0]) == 0) {
+                        if (option[1] != null) errorNeedArgument(flags);
+                        break;
+                    }
+                }
+            }
+
+            /*
+             * Check modifiers
+             */
+            String modifier = null;
+            int pos = flags.indexOf(':');
+            if (pos > 0) {
+                modifier = flags.substring(pos+1);
+                flags = flags.substring(0, pos);
+            }
             /*
              * command modes
              */
-            if (collator.compare(flags, "-certreq") == 0) {
-                command = CERTREQ;
-            } else if (collator.compare(flags, "-delete") == 0) {
-                command = DELETE;
-            } else if (collator.compare(flags, "-export") == 0 ||
-                    collator.compare(flags, "-exportcert") == 0) {
+            boolean isCommand = false;
+            for (Command c: Command.values()) {
+                if (collator.compare(flags, c.toString()) == 0) {
+                    command = c;
+                    isCommand = true;
+                    break;
+                }
+            }
+
+            if (isCommand) {
+                // already recognized as a command
+            } else if (collator.compare(flags, "-export") == 0) {
                 command = EXPORTCERT;
-            } else if (collator.compare(flags, "-genkey") == 0 ||
-                    collator.compare(flags, "-genkeypair") == 0) {
+            } else if (collator.compare(flags, "-genkey") == 0) {
                 command = GENKEYPAIR;
-            } else if (collator.compare(flags, "-help") == 0) {
-                usage();
-                return;
-            } else if (collator.compare(flags, "-identitydb") == 0) { // obsolete
-                command = IDENTITYDB;
-            } else if (collator.compare(flags, "-import") == 0 ||
-                    collator.compare(flags, "-importcert") == 0) {
+            } else if (collator.compare(flags, "-import") == 0) {
                 command = IMPORTCERT;
-            } else if (collator.compare(flags, "-keyclone") == 0) { // obsolete
-                command = KEYCLONE;
-            } else if (collator.compare(flags, "-changealias") == 0) {
-                command = CHANGEALIAS;
-            } else if (collator.compare(flags, "-keypasswd") == 0) {
-                command = KEYPASSWD;
-            } else if (collator.compare(flags, "-list") == 0) {
-                command = LIST;
-            } else if (collator.compare(flags, "-printcert") == 0) {
-                command = PRINTCERT;
-            } else if (collator.compare(flags, "-selfcert") == 0) {     // obsolete
-                command = SELFCERT;
-            } else if (collator.compare(flags, "-storepasswd") == 0) {
-                command = STOREPASSWD;
-            } else if (collator.compare(flags, "-importkeystore") == 0) {
-                command = IMPORTKEYSTORE;
-            } else if (collator.compare(flags, "-genseckey") == 0) {
-                command = GENSECKEY;
-            } else if (collator.compare(flags, "-gencert") == 0) {
-                command = GENCERT;
-            } else if (collator.compare(flags, "-printcertreq") == 0) {
-                command = PRINTCERTREQ;
+            }
+            /*
+             * Help
+             */
+            else if (collator.compare(flags, "-help") == 0) {
+                help = true;
             }
 
             /*
@@ -284,101 +393,74 @@
              */
             else if (collator.compare(flags, "-keystore") == 0 ||
                     collator.compare(flags, "-destkeystore") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                ksfname = args[i];
+                ksfname = args[++i];
             } else if (collator.compare(flags, "-storepass") == 0 ||
                     collator.compare(flags, "-deststorepass") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                storePass = args[i].toCharArray();
+                storePass = getPass(modifier, args[++i]);
                 passwords.add(storePass);
             } else if (collator.compare(flags, "-storetype") == 0 ||
                     collator.compare(flags, "-deststoretype") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                storetype = args[i];
+                storetype = args[++i];
             } else if (collator.compare(flags, "-srcstorepass") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                srcstorePass = args[i].toCharArray();
+                srcstorePass = getPass(modifier, args[++i]);
                 passwords.add(srcstorePass);
             } else if (collator.compare(flags, "-srcstoretype") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                srcstoretype = args[i];
+                srcstoretype = args[++i];
             } else if (collator.compare(flags, "-srckeypass") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                srckeyPass = args[i].toCharArray();
+                srckeyPass = getPass(modifier, args[++i]);
                 passwords.add(srckeyPass);
             } else if (collator.compare(flags, "-srcprovidername") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                srcProviderName = args[i];
+                srcProviderName = args[++i];
             } else if (collator.compare(flags, "-providername") == 0 ||
                     collator.compare(flags, "-destprovidername") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                providerName = args[i];
+                providerName = args[++i];
             } else if (collator.compare(flags, "-providerpath") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                pathlist = args[i];
+                pathlist = args[++i];
             } else if (collator.compare(flags, "-keypass") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                keyPass = args[i].toCharArray();
+                keyPass = getPass(modifier, args[++i]);
                 passwords.add(keyPass);
             } else if (collator.compare(flags, "-new") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                newPass = args[i].toCharArray();
+                newPass = getPass(modifier, args[++i]);
                 passwords.add(newPass);
             } else if (collator.compare(flags, "-destkeypass") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                destKeyPass = args[i].toCharArray();
+                destKeyPass = getPass(modifier, args[++i]);
                 passwords.add(destKeyPass);
             } else if (collator.compare(flags, "-alias") == 0 ||
                     collator.compare(flags, "-srcalias") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                alias = args[i];
+                alias = args[++i];
             } else if (collator.compare(flags, "-dest") == 0 ||
                     collator.compare(flags, "-destalias") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                dest = args[i];
+                dest = args[++i];
             } else if (collator.compare(flags, "-dname") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                dname = args[i];
+                dname = args[++i];
             } else if (collator.compare(flags, "-keysize") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                keysize = Integer.parseInt(args[i]);
+                keysize = Integer.parseInt(args[++i]);
             } else if (collator.compare(flags, "-keyalg") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                keyAlgName = args[i];
+                keyAlgName = args[++i];
             } else if (collator.compare(flags, "-sigalg") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                sigAlgName = args[i];
+                sigAlgName = args[++i];
             } else if (collator.compare(flags, "-startdate") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                startDate = args[i];
+                startDate = args[++i];
             } else if (collator.compare(flags, "-validity") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                validity = Long.parseLong(args[i]);
+                validity = Long.parseLong(args[++i]);
             } else if (collator.compare(flags, "-ext") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                v3ext.add(args[i]);
+                v3ext.add(args[++i]);
             } else if (collator.compare(flags, "-file") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                filename = args[i];
+                filename = args[++i];
             } else if (collator.compare(flags, "-infile") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                infilename = args[i];
+                infilename = args[++i];
             } else if (collator.compare(flags, "-outfile") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                outfilename = args[i];
+                outfilename = args[++i];
             } else if (collator.compare(flags, "-sslserver") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                sslserver = args[i];
+                sslserver = args[++i];
             } else if (collator.compare(flags, "-srckeystore") == 0) {
-                if (++i == args.length) errorNeedArgument(flags);
-                srcksfname = args[i];
+                srcksfname = args[++i];
             } else if ((collator.compare(flags, "-provider") == 0) ||
                         (collator.compare(flags, "-providerclass") == 0)) {
-                if (++i == args.length) errorNeedArgument(flags);
                 if (providers == null) {
                     providers = new HashSet<Pair <String, String>> (3);
                 }
-                String providerClass = args[i];
+                String providerClass = args[++i];
                 String providerArg = null;
 
                 if (args.length > (i+1)) {
@@ -418,19 +500,24 @@
         }
 
         if (i<args.length) {
-            MessageFormat form = new MessageFormat
-                (rb.getString("Usage error, <arg> is not a legal command"));
-            Object[] source = {args[i]};
-            throw new RuntimeException(form.format(source));
-        }
-
-        if (command == -1) {
-            System.err.println(rb.getString("Usage error: no command provided"));
+            System.err.println(rb.getString("Illegal option:  ") + args[i]);
             tinyHelp();
         }
+
+        if (command == null) {
+            if (help) {
+                usage();
+            } else {
+                System.err.println(rb.getString("Usage error: no command provided"));
+                tinyHelp();
+            }
+        } else if (help) {
+            usage();
+            command = null;
+        }
     }
 
-    boolean isKeyStoreRelated(int cmd) {
+    boolean isKeyStoreRelated(Command cmd) {
         return cmd != PRINTCERT && cmd != PRINTCERTREQ;
     }
 
@@ -2600,7 +2687,7 @@
         do {
             if (maxRetry-- < 0) {
                 throw new RuntimeException(rb.getString(
-                        "Too may retries, program terminated"));
+                        "Too many retries, program terminated"));
             }
             commonName = inputString(in,
                     rb.getString("What is your first and last name?"),
@@ -3086,7 +3173,7 @@
         do {
             if (maxRetry-- < 0) {
                 throw new RuntimeException(rb.getString(
-                        "Too may retries, program terminated"));
+                        "Too many retries, program terminated"));
             }
             System.err.print(prompt);
             System.err.flush();
@@ -3258,7 +3345,8 @@
         int nmatch = 0;
         for (int i = 0; i<list.length; i++) {
             String one = list[i];
-            if (one.toLowerCase().startsWith(s.toLowerCase())) {
+            if (one.toLowerCase(Locale.ENGLISH)
+                    .startsWith(s.toLowerCase(Locale.ENGLISH))) {
                 match[nmatch++] = i;
             } else {
                 StringBuffer sb = new StringBuffer();
@@ -3368,9 +3456,9 @@
             // Honoring requested extensions
             if (reqex != null) {
                 for(String extstr: extstrs) {
-                    if (extstr.toLowerCase().startsWith("honored=")) {
+                    if (extstr.toLowerCase(Locale.ENGLISH).startsWith("honored=")) {
                         List<String> list = Arrays.asList(
-                                extstr.toLowerCase().substring(8).split(","));
+                                extstr.toLowerCase(Locale.ENGLISH).substring(8).split(","));
                         // First check existence of "all"
                         if (list.contains("all")) {
                             ext = reqex;    // we know ext was null
@@ -3687,227 +3775,69 @@
      * Prints the usage of this tool.
      */
     private void usage() {
-        System.err.println(rb.getString("keytool usage:\n"));
-
-        System.err.println(rb.getString
-                ("-certreq     [-v] [-protected]"));
-        System.err.println(rb.getString
-                ("\t     [-alias <alias>] [-sigalg <sigalg>]"));
-        System.err.println(rb.getString
-                ("\t     [-dname <dname>]"));
-        System.err.println(rb.getString
-                ("\t     [-file <csr_file>] [-keypass <keypass>]"));
-        System.err.println(rb.getString
-                ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
-        System.err.println(rb.getString
-                ("\t     [-storetype <storetype>] [-providername <name>]"));
-        System.err.println(rb.getString
-                ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
-        System.err.println(rb.getString
-                ("\t     [-providerpath <pathlist>]"));
-        System.err.println();
-
-        System.err.println(rb.getString
-                ("-changealias [-v] [-protected] -alias <alias> -destalias <destalias>"));
-        System.err.println(rb.getString
-                ("\t     [-keypass <keypass>]"));
-        System.err.println(rb.getString
-                ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
-        System.err.println(rb.getString
-                ("\t     [-storetype <storetype>] [-providername <name>]"));
-        System.err.println(rb.getString
-                ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
-        System.err.println(rb.getString
-                ("\t     [-providerpath <pathlist>]"));
-        System.err.println();
-
-        System.err.println(rb.getString
-                ("-delete      [-v] [-protected] -alias <alias>"));
-        System.err.println(rb.getString
-                ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
-        System.err.println(rb.getString
-                ("\t     [-storetype <storetype>] [-providername <name>]"));
-        System.err.println(rb.getString
-                ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
-        System.err.println(rb.getString
-                ("\t     [-providerpath <pathlist>]"));
-        System.err.println();
-
-        System.err.println(rb.getString
-                ("-exportcert  [-v] [-rfc] [-protected]"));
-        System.err.println(rb.getString
-                ("\t     [-alias <alias>] [-file <cert_file>]"));
-        System.err.println(rb.getString
-                ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
-        System.err.println(rb.getString
-                ("\t     [-storetype <storetype>] [-providername <name>]"));
-        System.err.println(rb.getString
-                ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
-        System.err.println(rb.getString
-                ("\t     [-providerpath <pathlist>]"));
-        System.err.println();
-
-        System.err.println(rb.getString
-                ("-genkeypair  [-v] [-protected]"));
-        System.err.println(rb.getString
-                ("\t     [-alias <alias>]"));
-        System.err.println(rb.getString
-                ("\t     [-keyalg <keyalg>] [-keysize <keysize>]"));
-        System.err.println(rb.getString
-                ("\t     [-sigalg <sigalg>] [-dname <dname>]"));
-        System.err.println(rb.getString
-                ("\t     [-startdate <startdate>]"));
-        System.err.println(rb.getString
-                ("\t     [-ext <key>[:critical][=<value>]]..."));
-        System.err.println(rb.getString
-                ("\t     [-validity <valDays>] [-keypass <keypass>]"));
-        System.err.println(rb.getString
-                ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
-        System.err.println(rb.getString
-                ("\t     [-storetype <storetype>] [-providername <name>]"));
-        System.err.println(rb.getString
-                ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
-        System.err.println(rb.getString
-                ("\t     [-providerpath <pathlist>]"));
-        System.err.println();
-
-        System.err.println(rb.getString
-                ("-gencert     [-v] [-rfc] [-protected]"));
-        System.err.println(rb.getString
-                ("\t     [-infile <infile>] [-outfile <outfile>]"));
-        System.err.println(rb.getString
-                ("\t     [-alias <alias>]"));
-        System.err.println(rb.getString
-                ("\t     [-dname <dname>]"));
-        System.err.println(rb.getString
-                ("\t     [-sigalg <sigalg>]"));
-        System.err.println(rb.getString
-                ("\t     [-startdate <startdate>]"));
-        System.err.println(rb.getString
-                ("\t     [-ext <key>[:critical][=<value>]]..."));
-        System.err.println(rb.getString
-                ("\t     [-validity <valDays>] [-keypass <keypass>]"));
-        System.err.println(rb.getString
-                ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
-        System.err.println(rb.getString
-                ("\t     [-storetype <storetype>] [-providername <name>]"));
-        System.err.println(rb.getString
-                ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
-        System.err.println(rb.getString
-                ("\t     [-providerpath <pathlist>]"));
-        System.err.println();
-
-        System.err.println(rb.getString
-                ("-genseckey   [-v] [-protected]"));
-        System.err.println(rb.getString
-                ("\t     [-alias <alias>] [-keypass <keypass>]"));
-        System.err.println(rb.getString
-                ("\t     [-keyalg <keyalg>] [-keysize <keysize>]"));
-        System.err.println(rb.getString
-                ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
-        System.err.println(rb.getString
-                ("\t     [-storetype <storetype>] [-providername <name>]"));
-        System.err.println(rb.getString
-                ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
-        System.err.println(rb.getString
-                ("\t     [-providerpath <pathlist>]"));
-        System.err.println();
-
-        System.err.println(rb.getString("-help"));
-        System.err.println();
-
-        System.err.println(rb.getString
-                ("-importcert  [-v] [-noprompt] [-trustcacerts] [-protected]"));
-        System.err.println(rb.getString
-                ("\t     [-alias <alias>]"));
-        System.err.println(rb.getString
-                ("\t     [-file <cert_file>] [-keypass <keypass>]"));
-        System.err.println(rb.getString
-                ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
-        System.err.println(rb.getString
-                ("\t     [-storetype <storetype>] [-providername <name>]"));
-        System.err.println(rb.getString
-                ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
-        System.err.println(rb.getString
-                ("\t     [-providerpath <pathlist>]"));
-        System.err.println();
-
-        System.err.println(rb.getString
-                ("-importkeystore [-v] "));
-        System.err.println(rb.getString
-                ("\t     [-srckeystore <srckeystore>] [-destkeystore <destkeystore>]"));
-        System.err.println(rb.getString
-                ("\t     [-srcstoretype <srcstoretype>] [-deststoretype <deststoretype>]"));
-        System.err.println(rb.getString
-                ("\t     [-srcstorepass <srcstorepass>] [-deststorepass <deststorepass>]"));
-        System.err.println(rb.getString
-                ("\t     [-srcprotected] [-destprotected]"));
-        System.err.println(rb.getString
-                ("\t     [-srcprovidername <srcprovidername>]\n\t     [-destprovidername <destprovidername>]"));
-        System.err.println(rb.getString
-                ("\t     [-srcalias <srcalias> [-destalias <destalias>]"));
-        System.err.println(rb.getString
-                ("\t       [-srckeypass <srckeypass>] [-destkeypass <destkeypass>]]"));
-        System.err.println(rb.getString
-                ("\t     [-noprompt]"));
-        System.err.println(rb.getString
-                ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
-        System.err.println(rb.getString
-                ("\t     [-providerpath <pathlist>]"));
-        System.err.println();
-
-        System.err.println(rb.getString
-                ("-keypasswd   [-v] [-alias <alias>]"));
-        System.err.println(rb.getString
-                ("\t     [-keypass <old_keypass>] [-new <new_keypass>]"));
-        System.err.println(rb.getString
-                ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
-        System.err.println(rb.getString
-                ("\t     [-storetype <storetype>] [-providername <name>]"));
-        System.err.println(rb.getString
-                ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
-        System.err.println(rb.getString
-                ("\t     [-providerpath <pathlist>]"));
-        System.err.println();
-
-        System.err.println(rb.getString
-                ("-list        [-v | -rfc] [-protected]"));
-        System.err.println(rb.getString
-                ("\t     [-alias <alias>]"));
-        System.err.println(rb.getString
-                ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
-        System.err.println(rb.getString
-                ("\t     [-storetype <storetype>] [-providername <name>]"));
-        System.err.println(rb.getString
-                ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
-        System.err.println(rb.getString
-                ("\t     [-providerpath <pathlist>]"));
-        System.err.println();
-
-        System.err.println(rb.getString
-                ("-printcert   [-v] [-rfc] [-file <cert_file> | -sslserver <host[:port]>]"));
-        System.err.println();
-
-        System.err.println(rb.getString
-                ("-printcertreq   [-v] [-file <cert_file>]"));
-        System.err.println();
-
-        System.err.println(rb.getString
-                ("-storepasswd [-v] [-new <new_storepass>]"));
-        System.err.println(rb.getString
-                ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
-        System.err.println(rb.getString
-                ("\t     [-storetype <storetype>] [-providername <name>]"));
-        System.err.println(rb.getString
-                ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
-        System.err.println(rb.getString
-                ("\t     [-providerpath <pathlist>]"));
+        if (command != null) {
+            System.err.println("keytool " + command +
+                    rb.getString(" [OPTION]..."));
+            System.err.println();
+            System.err.println(rb.getString(command.description));
+            System.err.println();
+            System.err.println(rb.getString("Options:"));
+            System.err.println();
+
+            // Left and right sides of the options list
+            String[] left = new String[command.options.length];
+            String[] right = new String[command.options.length];
+
+            // Check if there's an unknown option
+            boolean found = false;
+
+            // Length of left side of options list
+            int lenLeft = 0;
+            for (int j=0; j<left.length; j++) {
+                for (String[] opt: options) {
+                    if (collator.compare(opt[0], command.options[j]) == 0) {
+                        left[j] = opt[0];
+                        if (opt[1] != null) left[j] += " " + opt[1];
+                        if (left[j].length() > lenLeft) {
+                            lenLeft = left[j].length();
+                        }
+                        right[j] = rb.getString(opt[2]);
+                        found = true;
+                        break;
+                    }
+                }
+                if (!found) {
+                    throw new RuntimeException("ERROR: CANNOT FIND " + command.options[j]);
+                }
+            }
+            for (int j=0; j<left.length; j++) {
+                System.err.printf(" %-" + lenLeft + "s  %s\n",
+                        left[j], right[j]);
+            }
+            System.err.println();
+            System.err.println(rb.getString(
+                    "Use \"keytool -help\" for all available commands"));
+        } else {
+            System.err.println(rb.getString(
+                    "Key and Certificate Management Tool"));
+            System.err.println();
+            System.err.println(rb.getString("Commands:"));
+            System.err.println();
+            for (Command c: Command.values()) {
+                if (c != IDENTITYDB
+                        && c != KEYCLONE
+                        && c != SELFCERT) {     // Deprecated commands
+                    System.err.printf(" %-20s%s\n", c, rb.getString(c.description));
+                }
+            }
+            System.err.println();
+            System.err.println(rb.getString(
+                    "Use \"keytool -command_name -help\" for usage of command_name"));
+        }
     }
 
     private void tinyHelp() {
-        System.err.println(rb.getString("Try keytool -help"));
-
-        // do not drown user with the help lines.
+        usage();
         if (debug) {
             throw new RuntimeException("NO BIG ERROR, SORRY");
         } else {
@@ -3921,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,
@@ -3960,3 +3945,4 @@
         return new Pair<A,B>(a,b);
     }
 }
+
--- a/src/share/classes/sun/security/util/Resources.java	Fri Oct 02 13:57:41 2009 +0100
+++ b/src/share/classes/sun/security/util/Resources.java	Fri Oct 02 13:59:37 2009 +0100
@@ -46,18 +46,149 @@
         {"*******************************************\n\n",
                 "*******************************************\n\n"},
 
-        // keytool
+        // keytool: Help part
+        {" [OPTION]...", " [OPTION]..."},
+        {"Options:", "Options:"},
+        {"Use \"keytool -help\" for all available commands",
+                 "Use \"keytool -help\" for all available commands"},
+        {"Key and Certificate Management Tool",
+                 "Key and Certificate Management Tool"},
+        {"Commands:", "Commands:"},
+        {"Use \"keytool -command_name -help\" for usage of command_name",
+                "Use \"keytool -command_name -help\" for usage of command_name"},
+        // keytool: help: commands
+        {"Generates a certificate request",
+                "Generates a certificate request"}, //-certreq
+        {"Changes an entry's alias",
+                "Changes an entry's alias"}, //-changealias
+        {"Deletes an entry",
+                "Deletes an entry"}, //-delete
+        {"Exports certificate",
+                "Exports certificate"}, //-exportcert
+        {"Generates a key pair",
+                "Generates a key pair"}, //-genkeypair
+        {"Generates a secret key",
+                "Generates a secret key"}, //-genseckey
+        {"Generates certificate from a certificate request",
+                "Generates certificate from a certificate request"}, //-gencert
+        {"Imports entries from a JDK 1.1.x-style identity database",
+                "Imports entries from a JDK 1.1.x-style identity database"}, //-identitydb
+        {"Imports a certificate or a certificate chain",
+                "Imports a certificate or a certificate chain"}, //-importcert
+        {"Imports one or all entries from another keystore",
+                "Imports one or all entries from another keystore"}, //-importkeystore
+        {"Clones a key entry",
+                "Clones a key entry"}, //-keyclone
+        {"Changes the key password of an entry",
+                "Changes the key password of an entry"}, //-keypasswd
+        {"Lists entries in a keystore",
+                "Lists entries in a keystore"}, //-list
+        {"Prints the content of a certificate",
+                "Prints the content of a certificate"}, //-printcert
+        {"Prints the content of a certificate request",
+                "Prints the content of a certificate request"}, //-printcertreq
+        {"Generates a self-signed certificate",
+                "Generates a self-signed certificate"}, //-selfcert
+        {"Changes the store password of a keystore",
+                "Changes the store password of a keystore"}, //-storepasswd
+        // keytool: help: options
+        {"alias name of the entry to process",
+                "alias name of the entry to process"}, //-alias
+        {"destination alias",
+                "destination alias"}, //-destalias
+        {"destination key password",
+                "destination key password"}, //-destkeypass
+        {"destination keystore name",
+                "destination keystore name"}, //-destkeystore
+        {"destination keystore password protected",
+                "destination keystore password protected"}, //-destprotected
+        {"destination keystore provider name",
+                "destination keystore provider name"}, //-destprovidername
+        {"destination keystore password",
+                "destination keystore password"}, //-deststorepass
+        {"destination keystore type",
+                "destination keystore type"}, //-deststoretype
+        {"distinguished name",
+                "distinguished name"}, //-dname
+        {"X.509 extension",
+                "X.509 extension"}, //-ext
+        {"output file name",
+                "output file name"}, //-file
+        {"input file name",
+                "input file name"}, //-file
+        {"input file name",
+                "input file name"}, //-infile
+        {"key algorithm name",
+                "key algorithm name"}, //-keyalg
+        {"key password",
+                "key password"}, //-keypass
+        {"key bit size",
+                "key bit size"}, //-keysize
+        {"keystore name",
+                "keystore name"}, //-keystore
+        {"new password",
+                "new password"}, //-new
+        {"do not prompt",
+                "do not prompt"}, //-noprompt
+        {"output file name",
+                "output file name"}, //-outfile
+        {"password through protected mechanism",
+                "password through protected mechanism"}, //-protected
+        {"provider argument",
+                "provider argument"}, //-providerarg
+        {"provider class name",
+                "provider class name"}, //-providerclass
+        {"provider name",
+                "provider name"}, //-providername
+        {"provider classpath",
+                "provider classpath"}, //-providerpath
+        {"output in RFC style",
+                "output in RFC style"}, //-rfc
+        {"signature algorithm name",
+                "signature algorithm name"}, //-sigalg
+        {"source alias",
+                "source alias"}, //-srcalias
+        {"source keystore password",
+                "source keystore password"}, //-srckeypass
+        {"source keystore name",
+                "source keystore name"}, //-srckeystore
+        {"source keystore password protected",
+                "source keystore password protected"}, //-srcprotected
+        {"source keystore provider name",
+                "source keystore provider name"}, //-srcprovidername
+        {"source keystore password",
+                "source keystore password"}, //-srcstorepass
+        {"source keystore type",
+                "source keystore type"}, //-srcstoretype
+        {"SSL server host and port",
+                "SSL server host and port"}, //-sslserver
+        {"certificate validity start date/time",
+                "certificate validity start date/time"}, //-startdate
+        {"keystore password",
+                "keystore password"}, //-storepass
+        {"keystore type",
+                "keystore type"}, //-storetype
+        {"trust certificates from cacerts",
+                "trust certificates from cacerts"}, //-trustcacerts
+        {"verbose output",
+                "verbose output"}, //-v
+        {"validity number of days",
+                "validity number of days"}, //-validity
+        // keytool: Running part
         {"keytool error: ", "keytool error: "},
         {"Illegal option:  ", "Illegal option:  "},
         {"Illegal value: ", "Illegal value: "},
-        {"Try keytool -help","Try keytool -help"},
+        {"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."},
         {"-keystore must be NONE if -storetype is {0}",
                 "-keystore must be NONE if -storetype is {0}"},
-        {"Too may retries, program terminated",
-                 "Too may retries, program terminated"},
+        {"Too many retries, program terminated",
+                 "Too many retries, program terminated"},
         {"-storepasswd and -keypasswd commands not supported if -storetype is {0}",
                 "-storepasswd and -keypasswd commands not supported if -storetype is {0}"},
         {"-keypasswd commands not supported if -storetype is PKCS12",
@@ -77,7 +208,6 @@
                 "Validity must be greater than zero"},
         {"provName not a provider", "{0} not a provider"},
         {"Usage error: no command provided", "Usage error: no command provided"},
-        {"Usage error, <arg> is not a legal command", "Usage error, {0} is not a legal command"},
         {"Source keystore file exists, but is empty: ", "Source keystore file exists, but is empty: "},
         {"Please specify -srckeystore", "Please specify -srckeystore"},
         {"Must not specify both -v and -rfc with 'list' command",
@@ -279,7 +409,6 @@
                 "Secret Key not generated, alias <{0}> already exists"},
         {"Please provide -keysize for secret key generation",
                 "Please provide -keysize for secret key generation"},
-        {"keytool usage:\n", "keytool usage:\n"},
 
         {"Extensions: ", "Extensions: "},
         {"(Empty value)", "(Empty value)"},
@@ -297,139 +426,6 @@
         {"Odd number of hex digits found: ", "Odd number of hex digits found: "},
         {"command {0} is ambiguous:", "command {0} is ambiguous:"},
 
-        {"-certreq     [-v] [-protected]",
-                "-certreq     [-v] [-protected]"},
-        {"\t     [-alias <alias>] [-sigalg <sigalg>]",
-                "\t     [-alias <alias>] [-sigalg <sigalg>]"},
-        {"\t     [-dname <dname>]", "\t     [-dname <dname>]"},
-        {"\t     [-file <csr_file>] [-keypass <keypass>]",
-                "\t     [-file <csr_file>] [-keypass <keypass>]"},
-        {"\t     [-keystore <keystore>] [-storepass <storepass>]",
-                "\t     [-keystore <keystore>] [-storepass <storepass>]"},
-        {"\t     [-storetype <storetype>] [-providername <name>]",
-                "\t     [-storetype <storetype>] [-providername <name>]"},
-        {"\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ...",
-                "\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."},
-        {"\t     [-providerpath <pathlist>]",
-                "\t     [-providerpath <pathlist>]"},
-        {"-delete      [-v] [-protected] -alias <alias>",
-                "-delete      [-v] [-protected] -alias <alias>"},
-        /** rest is same as -certreq starting from -keystore **/
-
-        //{"-export      [-v] [-rfc] [-protected]",
-        //       "-export      [-v] [-rfc] [-protected]"},
-        {"-exportcert  [-v] [-rfc] [-protected]",
-                "-exportcert  [-v] [-rfc] [-protected]"},
-        {"\t     [-alias <alias>] [-file <cert_file>]",
-                "\t     [-alias <alias>] [-file <cert_file>]"},
-        /** rest is same as -certreq starting from -keystore **/
-
-        //{"-genkey      [-v] [-protected]",
-        //        "-genkey      [-v] [-protected]"},
-        {"-genkeypair  [-v] [-protected]",
-                "-genkeypair  [-v] [-protected]"},
-        {"\t     [-alias <alias>]", "\t     [-alias <alias>]"},
-        {"\t     [-keyalg <keyalg>] [-keysize <keysize>]",
-                "\t     [-keyalg <keyalg>] [-keysize <keysize>]"},
-        {"\t     [-sigalg <sigalg>] [-dname <dname>]",
-                "\t     [-sigalg <sigalg>] [-dname <dname>]"},
-        {"\t     [-startdate <startdate>]",
-                "\t     [-startdate <startdate>]"},
-        {"\t     [-validity <valDays>] [-keypass <keypass>]",
-                "\t     [-validity <valDays>] [-keypass <keypass>]"},
-        /** rest is same as -certreq starting from -keystore **/
-        {"-gencert     [-v] [-rfc] [-protected]",
-                "-gencert     [-v] [-rfc] [-protected]"},
-        {"\t     [-infile <infile>] [-outfile <outfile>]",
-                 "\t     [-infile <infile>] [-outfile <outfile>]"},
-        {"\t     [-sigalg <sigalg>]",
-                "\t     [-sigalg <sigalg>]"},
-        {"\t     [-ext <key>[:critical][=<value>]]...",
-                "\t     [-ext <key>[:critical][=<value>]]..."},
-
-        {"-genseckey   [-v] [-protected]",
-                "-genseckey   [-v] [-protected]"},
-        /** rest is same as -certreq starting from -keystore **/
-
-        {"-help", "-help"},
-        //{"-identitydb  [-v] [-protected]",
-        //      "-identitydb  [-v] [-protected]"},
-        //{"\t     [-file <idb_file>]", "\t     [-file <idb_file>]"},
-        /** rest is same as -certreq starting from -keystore **/
-
-        //{"-import      [-v] [-noprompt] [-trustcacerts] [-protected]",
-        //       "-import      [-v] [-noprompt] [-trustcacerts] [-protected]"},
-        {"-importcert  [-v] [-noprompt] [-trustcacerts] [-protected]",
-                "-importcert  [-v] [-noprompt] [-trustcacerts] [-protected]"},
-        {"\t     [-alias <alias>]", "\t     [-alias <alias>]"},
-        {"\t     [-alias <alias>] [-keypass <keypass>]",
-            "\t     [-alias <alias>] [-keypass <keypass>]"},
-        {"\t     [-file <cert_file>] [-keypass <keypass>]",
-                "\t     [-file <cert_file>] [-keypass <keypass>]"},
-        /** rest is same as -certreq starting from -keystore **/
-
-        {"-importkeystore [-v] ",
-                "-importkeystore [-v] "},
-        {"\t     [-srckeystore <srckeystore>] [-destkeystore <destkeystore>]",
-                "\t     [-srckeystore <srckeystore>] [-destkeystore <destkeystore>]"},
-        {"\t     [-srcstoretype <srcstoretype>] [-deststoretype <deststoretype>]",
-                "\t     [-srcstoretype <srcstoretype>] [-deststoretype <deststoretype>]"},
-        {"\t     [-srcprotected] [-destprotected]",
-                "\t     [-srcprotected] [-destprotected]"},
-        {"\t     [-srcstorepass <srcstorepass>] [-deststorepass <deststorepass>]",
-                "\t     [-srcstorepass <srcstorepass>] [-deststorepass <deststorepass>]"},
-        {"\t     [-srcprovidername <srcprovidername>]\n\t     [-destprovidername <destprovidername>]",  // line too long, split to 2
-                 "\t     [-srcprovidername <srcprovidername>]\n\t     [-destprovidername <destprovidername>]"},
-        {"\t     [-srcalias <srcalias> [-destalias <destalias>]",
-                "\t     [-srcalias <srcalias> [-destalias <destalias>]"},
-        {"\t       [-srckeypass <srckeypass>] [-destkeypass <destkeypass>]]",
-                "\t       [-srckeypass <srckeypass>] [-destkeypass <destkeypass>]]"},
-        {"\t     [-noprompt]", "\t     [-noprompt]"},
-        /** rest is same as -certreq starting from -keystore **/
-
-        {"-changealias [-v] [-protected] -alias <alias> -destalias <destalias>",
-                "-changealias [-v] [-protected] -alias <alias> -destalias <destalias>"},
-        {"\t     [-keypass <keypass>]", "\t     [-keypass <keypass>]"},
-
-        //{"-keyclone    [-v] [-protected]",
-        //      "-keyclone    [-v] [-protected]"},
-        //{"\t     [-alias <alias>] -dest <dest_alias>",
-        //      "\t     [-alias <alias>] -dest <dest_alias>"},
-        //{"\t     [-keypass <keypass>] [-new <new_keypass>]",
-        //      "\t     [-keypass <keypass>] [-new <new_keypass>]"},
-        /** rest is same as -certreq starting from -keystore **/
-
-        {"-keypasswd   [-v] [-alias <alias>]",
-                "-keypasswd   [-v] [-alias <alias>]"},
-        {"\t     [-keypass <old_keypass>] [-new <new_keypass>]",
-                "\t     [-keypass <old_keypass>] [-new <new_keypass>]"},
-        /** rest is same as -certreq starting from -keystore **/
-
-        {"-list        [-v | -rfc] [-protected]",
-                "-list        [-v | -rfc] [-protected]"},
-        {"\t     [-alias <alias>]", "\t     [-alias <alias>]"},
-        /** rest is same as -certreq starting from -keystore **/
-
-        {"-printcert   [-v] [-rfc] [-file <cert_file> | -sslserver <host[:port]>]",
-                "-printcert   [-v] [-rfc] [-file <cert_file> | -sslserver <host[:port]>]"},
-        {"-printcertreq   [-v] [-file <cert_file>]",
-                 "-printcertreq   [-v] [-file <cert_file>]"},
-        {"No certificate from the SSL server",
-                "No certificate from the SSL server"},
-
-        //{"-selfcert    [-v] [-protected]",
-        //      "-selfcert    [-v] [-protected]"},
-        {"\t     [-alias <alias>]", "\t     [-alias <alias>]"},
-        //{"\t     [-dname <dname>] [-validity <valDays>]",
-        //      "\t     [-dname <dname>] [-validity <valDays>]"},
-        //{"\t     [-keypass <keypass>] [-sigalg <sigalg>]",
-        //      "\t     [-keypass <keypass>] [-sigalg <sigalg>]"},
-        /** rest is same as -certreq starting from -keystore **/
-
-        {"-storepasswd [-v] [-new <new_storepass>]",
-                "-storepasswd [-v] [-new <new_storepass>]"},
-        /** rest is same as -certreq starting from -keystore **/
-
         // policytool
         {"Warning: A public key for alias 'signers[i]' does not exist.  Make sure a KeyStore is properly configured.",
                 "Warning: A public key for alias {0} does not exist.  Make sure a KeyStore is properly configured."},
@@ -679,3 +675,4 @@
         return contents;
     }
 }
+
--- a/src/windows/classes/sun/security/krb5/internal/tools/Kinit.java	Fri Oct 02 13:57:41 2009 +0100
+++ b/src/windows/classes/sun/security/krb5/internal/tools/Kinit.java	Fri Oct 02 13:59:37 2009 +0100
@@ -1,5 +1,5 @@
 /*
- * Portions Copyright 2000-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Portions Copyright 2000-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
@@ -252,15 +252,15 @@
                 }
                 KRBError error = ke.getError();
                 int etype = error.getEType();
-                byte[] salt = error.getSalt();
+                String salt = error.getSalt();
                 byte[] s2kparams = error.getParams();
                 if (useKeytab) {
-                    as_req = new KrbAsReq(skeys, true, etype, salt, s2kparams,
-                                        opt, principal, sname,
+                    as_req = new KrbAsReq(skeys, true, etype, salt,
+                                        s2kparams, opt, principal, sname,
                                         null, null, null, null, addresses, null);
                 } else {
-                    as_req = new KrbAsReq(psswd, true, etype, salt, s2kparams,
-                                        opt, principal, sname,
+                    as_req = new KrbAsReq(psswd, true, etype, salt,
+                                        s2kparams, opt, principal, sname,
                                         null, null, null, null, addresses, null);
                 }
                 as_rep = sendASRequest(as_req, useKeytab, realm, psswd, skeys);
--- a/src/windows/classes/sun/security/krb5/internal/tools/Klist.java	Fri Oct 02 13:57:41 2009 +0100
+++ b/src/windows/classes/sun/security/krb5/internal/tools/Klist.java	Fri Oct 02 13:59:37 2009 +0100
@@ -30,17 +30,12 @@
 
 package sun.security.krb5.internal.tools;
 
+import java.net.InetAddress;
 import sun.security.krb5.*;
 import sun.security.krb5.internal.*;
 import sun.security.krb5.internal.ccache.*;
 import sun.security.krb5.internal.ktab.*;
 import sun.security.krb5.internal.crypto.EType;
-import sun.security.krb5.KrbCryptoException;
-import java.lang.RuntimeException;
-import java.io.IOException;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.io.File;
 
 /**
  * This class can execute as a command-line tool to list entries in
@@ -51,9 +46,9 @@
  */
 public class Klist {
     Object target;
-    // for credentials cache, options are 'f'  and 'e';
+    // for credentials cache, options are 'f', 'e', 'a' and 'n';
     // for  keytab, optionsare 't' and 'K' and 'e'
-    char[] options = new char[3];
+    char[] options = new char[4];
     String name;       // the name of credentials cache and keytable.
     char action;       // actions would be 'c' for credentials cache
     // and 'k' for keytable.
@@ -62,7 +57,7 @@
     /**
      * The main program that can be invoked at command line.
      * <br>Usage: klist
-     * [[-c] [-f] [-e]] [-k [-t] [-K]] [name]
+     * [[-c] [-f] [-e] [-a [-n]]] [-k [-t] [-K]] [name]
      * -c specifes that credential cache is to be listed
      * -k specifies that key tab is to be listed
      * name name of the credentials cache or keytab
@@ -70,6 +65,8 @@
      * <ul>
      * <li><b>-f</b>  shows credentials flags
      * <li><b>-e</b>  shows the encryption type
+     * <li><b>-a</b>  shows addresses
+     * <li><b>-n</b>  do not reverse-resolve addresses
      * </ul>
      * available options for keytabs:
      * <li><b>-t</b> shows keytab entry timestamps
@@ -141,6 +138,12 @@
                 case 'k':
                     action = 'k';
                     break;
+                case 'a':
+                    options[2] = 'a';
+                    break;
+                case 'n':
+                    options[3] = 'n';
+                    break;
                 case 'f':
                     options[1] = 'f';
                     break;
@@ -202,7 +205,7 @@
                 }
                 if (options[2] == 't') {
                     System.out.println("\t Time stamp: " +
-                                       reformat(entries[i].getTimeStamp().toDate().toString()));
+                            reformat(entries[i].getTimeStamp().toDate().toString()));
                 }
             }
         }
@@ -249,12 +252,33 @@
                     System.out.println("     Expires:         " + endtime);
                     if (options[0] == 'e') {
                         etype = EType.toString(creds[i].getEType());
-                        System.out.println("\t Encryption type: " + etype);
+                        System.out.println("     Encryption type: " + etype);
                     }
                     if (options[1] == 'f') {
-                        System.out.println("\t Flags:           " +
+                        System.out.println("     Flags:           " +
                                            creds[i].getTicketFlags().toString());
                     }
+                    if (options[2] == 'a') {
+                        boolean first = true;
+                        InetAddress[] caddr
+                                = creds[i].setKrbCreds().getClientAddresses();
+                        if (caddr != null) {
+                            for (InetAddress ia: caddr) {
+                                String out;
+                                if (options[3] == 'n') {
+                                    out = ia.getHostAddress();
+                                } else {
+                                    out = ia.getCanonicalHostName();
+                                }
+                                System.out.println("     " +
+                                        (first?"Addresses:":"          ") +
+                                        "       " + out);
+                                first = false;
+                            }
+                        } else {
+                            System.out.println("     [No host addresses info]");
+                        }
+                    }
                 } catch (RealmException e) {
                     System.out.println("Error reading principal from "+
                                        "the entry.");
@@ -295,7 +319,7 @@
      */
     void printHelp() {
         System.out.println("\nUsage: klist " +
-                           "[[-c] [-f] [-e]] [-k [-t] [-K]] [name]");
+                           "[[-c] [-f] [-e] [-a [-n]]] [-k [-t] [-K]] [name]");
         System.out.println("   name\t name of credentials cache or " +
                            " keytab with the prefix. File-based cache or "
                            + "keytab's prefix is FILE:.");
@@ -305,6 +329,8 @@
         System.out.println("   options for credentials caches:");
         System.out.println("\t-f \t shows credentials flags");
         System.out.println("\t-e \t shows the encryption type");
+        System.out.println("\t-a \t shows addresses");
+        System.out.println("\t  -n \t   do not reverse-resolve addresses");
         System.out.println("   options for keytabs:");
         System.out.println("\t-t \t shows keytab entry timestamps");
         System.out.println("\t-K \t shows keytab entry key value");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/krb5/RFC396xTest.java	Fri Oct 02 13:59:37 2009 +0100
@@ -0,0 +1,248 @@
+/*
+ * 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 6862679
+ * @summary ESC: AD Authentication with user with umlauts fails
+ */
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import sun.security.krb5.EncryptedData;
+import sun.security.krb5.internal.crypto.Des;
+import sun.security.krb5.internal.crypto.EType;
+import sun.security.krb5.internal.crypto.crc32;
+import sun.security.krb5.internal.crypto.dk.AesDkCrypto;
+import sun.security.krb5.internal.crypto.dk.Des3DkCrypto;
+import sun.security.krb5.internal.crypto.dk.DkCrypto;
+import java.nio.*;
+import javax.crypto.*;
+import javax.crypto.spec.*;
+
+public class RFC396xTest {
+
+    static final String gclef = new String(Character.toChars(0x1d11e));
+
+    /** Creates a new instance of NewClass */
+    public static void main(String[] args) throws Exception {
+        System.setProperty("sun.security.krb5.msinterop.des.s2kcharset",
+                "utf-8");
+        test();
+    }
+
+    static void test() throws Exception {
+        // RFC 3961
+        // A.1
+        Method nfold = DkCrypto.class.getDeclaredMethod("nfold", byte[].class, Integer.TYPE);
+        nfold.setAccessible(true);
+        assertStringEquals(hex((byte[])nfold.invoke(null, "012345".getBytes("UTF-8"), 64)), "be072631276b1955");
+        assertStringEquals(hex((byte[])nfold.invoke(null, "password".getBytes("UTF-8"), 56)), "78a07b6caf85fa");
+        assertStringEquals(hex((byte[])nfold.invoke(null, "Rough Consensus, and Running Code".getBytes("UTF-8"), 64)), "bb6ed30870b7f0e0");
+        assertStringEquals(hex((byte[])nfold.invoke(null, "password".getBytes("UTF-8"), 168)), "59e4a8ca7c0385c3c37b3f6d2000247cb6e6bd5b3e");
+        assertStringEquals(hex((byte[])nfold.invoke(null, "MASSACHVSETTS INSTITVTE OF TECHNOLOGY".getBytes("UTF-8"), 192)), "db3b0d8f0b061e603282b308a50841229ad798fab9540c1b");
+        assertStringEquals(hex((byte[])nfold.invoke(null, "Q".getBytes("UTF-8"), 168)), "518a54a215a8452a518a54a215a8452a518a54a215");
+        assertStringEquals(hex((byte[])nfold.invoke(null, "ba".getBytes("UTF-8"), 168)), "fb25d531ae8974499f52fd92ea9857c4ba24cf297e");
+        assertStringEquals(hex((byte[])nfold.invoke(null, "kerberos".getBytes("UTF-8"), 64)), "6b65726265726f73");
+        assertStringEquals(hex((byte[])nfold.invoke(null, "kerberos".getBytes("UTF-8"), 128)), "6b65726265726f737b9b5b2b93132b93");
+        assertStringEquals(hex((byte[])nfold.invoke(null, "kerberos".getBytes("UTF-8"), 168)), "8372c236344e5f1550cd0747e15d62ca7a5a3bcea4");
+        assertStringEquals(hex((byte[])nfold.invoke(null, "kerberos".getBytes("UTF-8"), 256)), "6b65726265726f737b9b5b2b93132b935c9bdcdad95c9899c4cae4dee6d6cae4");
+
+        // A.2
+        assertStringEquals(hex(Des.string_to_key_bytes("passwordATHENA.MIT.EDUraeburn".toCharArray())), "cbc22fae235298e3");
+        assertStringEquals(hex(Des.string_to_key_bytes("potatoeWHITEHOUSE.GOVdanny".toCharArray())), "df3d32a74fd92a01");
+        assertStringEquals(hex(Des.string_to_key_bytes((gclef+"EXAMPLE.COMpianist").toCharArray())), "4ffb26bab0cd9413");
+        assertStringEquals(hex(Des.string_to_key_bytes("\u00dfATHENA.MIT.EDUJuri\u0161i\u0107".toCharArray())), "62c81a5232b5e69d");
+        // Next 2 won't pass, since there's no real weak key here
+        //assertStringEquals(hex(Des.string_to_key_bytes("11119999AAAAAAAA".toCharArray())), "984054d0f1a73e31");
+        //assertStringEquals(hex(Des.string_to_key_bytes("NNNN6666FFFFAAAA".toCharArray())), "c4bf6b25adf7a4f8");
+
+        // A.3
+        Object o = Des3DkCrypto.class.getConstructor().newInstance();
+        Method dr = DkCrypto.class.getDeclaredMethod("dr", byte[].class, byte[].class);
+        Method randomToKey = DkCrypto.class.getDeclaredMethod("randomToKey", byte[].class);
+        dr.setAccessible(true);
+        randomToKey.setAccessible(true);
+        assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
+                xeh("dce06b1f64c857a11c3db57c51899b2cc1791008ce973b92"),
+                xeh("0000000155")))),
+                "925179d04591a79b5d3192c4a7e9c289b049c71f6ee604cd");
+        assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
+                xeh("5e13d31c70ef765746578531cb51c15bf11ca82c97cee9f2"),
+                xeh("00000001aa")))),
+                "9e58e5a146d9942a101c469845d67a20e3c4259ed913f207");
+        assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
+                xeh("98e6fd8a04a4b6859b75a176540b9752bad3ecd610a252bc"),
+                xeh("0000000155")))),
+                "13fef80d763e94ec6d13fd2ca1d085070249dad39808eabf");
+        assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
+                xeh("622aec25a2fe2cad7094680b7c64940280084c1a7cec92b5"),
+                xeh("00000001aa")))),
+                "f8dfbf04b097e6d9dc0702686bcb3489d91fd9a4516b703e");
+        assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
+                xeh("d3f8298ccb166438dcb9b93ee5a7629286a491f838f802fb"),
+                xeh("6b65726265726f73")))),
+                "2370da575d2a3da864cebfdc5204d56df779a7df43d9da43");
+        assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
+                xeh("c1081649ada74362e6a1459d01dfd30d67c2234c940704da"),
+                xeh("0000000155")))),
+                "348057ec98fdc48016161c2a4c7a943e92ae492c989175f7");
+        assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
+                xeh("5d154af238f46713155719d55e2f1f790dd661f279a7917c"),
+                xeh("00000001aa")))),
+                "a8808ac267dada3dcbe9a7c84626fbc761c294b01315e5c1");
+        assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
+                xeh("798562e049852f57dc8c343ba17f2ca1d97394efc8adc443"),
+                xeh("0000000155")))),
+                "c813f88a3be3b334f75425ce9175fbe3c8493b89c8703b49");
+        assertStringEquals(hex((byte[])randomToKey.invoke(o, (byte[])dr.invoke(o,
+                xeh("26dce334b545292f2feab9a8701a89a4b99eb9942cecd016"),
+                xeh("00000001aa")))),
+                "f48ffd6e83f83e7354e694fd252cf83bfe58f7d5ba37ec5d");
+
+        // A.4
+        assertStringEquals(hex(new Des3DkCrypto().stringToKey("passwordATHENA.MIT.EDUraeburn".toCharArray())), "850bb51358548cd05e86768c313e3bfef7511937dcf72c3e");
+        assertStringEquals(hex(new Des3DkCrypto().stringToKey("potatoeWHITEHOUSE.GOVdanny".toCharArray())), "dfcd233dd0a43204ea6dc437fb15e061b02979c1f74f377a");
+        assertStringEquals(hex(new Des3DkCrypto().stringToKey("pennyEXAMPLE.COMbuckaroo".toCharArray())), "6d2fcdf2d6fbbc3ddcadb5da5710a23489b0d3b69d5d9d4a");
+        assertStringEquals(hex(new Des3DkCrypto().stringToKey("\u00DFATHENA.MIT.EDUJuri\u0161i\u0107".toCharArray())), "16d5a40e1ce3bacb61b9dce00470324c831973a7b952feb0");
+        assertStringEquals(hex(new Des3DkCrypto().stringToKey((gclef+"EXAMPLE.COMpianist").toCharArray())), "85763726585dbc1cce6ec43e1f751f07f1c4cbb098f40b19");
+
+        // A.5
+        assertStringEquals(hex(crc32.byte2crc32sum_bytes("foo".getBytes("UTF-8"))), "33bc3273");
+        assertStringEquals(hex(crc32.byte2crc32sum_bytes("test0123456789".getBytes("UTF-8"))), "d6883eb8");
+        assertStringEquals(hex(crc32.byte2crc32sum_bytes("MASSACHVSETTS INSTITVTE OF TECHNOLOGY".getBytes("UTF-8"))), "f78041e3");
+        assertStringEquals(hex(crc32.byte2crc32sum_bytes(new byte[] {(byte)0x80, 0})), "4b98833b");
+        assertStringEquals(hex(crc32.byte2crc32sum_bytes(new byte[] {0, 8})), "3288db0e");
+        assertStringEquals(hex(crc32.byte2crc32sum_bytes(new byte[] {0, (byte)0x80})), "2083b8ed");
+        assertStringEquals(hex(crc32.byte2crc32sum_bytes(new byte[] {(byte)0x80})), "2083b8ed");
+        assertStringEquals(hex(crc32.byte2crc32sum_bytes(new byte[] {(byte)0x80, 0, 0, 0})), "3bb659ed");
+        assertStringEquals(hex(crc32.byte2crc32sum_bytes(new byte[] {0, 0, 0, 1})), "96300777");
+
+        // RFC 3962
+        AesDkCrypto a1 = new AesDkCrypto(128);
+        Method pbkdf2 = AesDkCrypto.class.getDeclaredMethod("PBKDF2", char[].class, byte[].class, Integer.TYPE, Integer.TYPE);
+        Method s2k = AesDkCrypto.class.getDeclaredMethod("stringToKey", char[].class, byte[].class, byte[].class);
+        pbkdf2.setAccessible(true);
+        s2k.setAccessible(true);
+        assertStringEquals(hex((byte[])pbkdf2.invoke(null, "password".toCharArray(), "ATHENA.MIT.EDUraeburn".getBytes("UTF-8"), 1, 128)), "cd ed b5 28 1b b2 f8 01 56 5a 11 22 b2 56 35 15");
+        assertStringEquals(hex(a1.stringToKey("password".toCharArray(), "ATHENA.MIT.EDUraeburn", i2b(1))), "42 26 3c 6e 89 f4 fc 28 b8 df 68 ee 09 79 9f 15");
+        assertStringEquals(hex((byte[])pbkdf2.invoke(null, "password".toCharArray(), "ATHENA.MIT.EDUraeburn".getBytes("UTF-8"), 1, 256)), "cd ed b5 28 1b b2 f8 01 56 5a 11 22 b2 56 35 15  0a d1 f7 a0 4b b9 f3 a3 33 ec c0 e2 e1 f7 08 37");
+        assertStringEquals(hex((byte[])pbkdf2.invoke(null, "password".toCharArray(), "ATHENA.MIT.EDUraeburn".getBytes("UTF-8"), 2, 128)), "01 db ee 7f 4a 9e 24 3e 98 8b 62 c7 3c da 93 5d");
+        assertStringEquals(hex(a1.stringToKey("password".toCharArray(), "ATHENA.MIT.EDUraeburn", i2b(2))), "c6 51 bf 29 e2 30 0a c2 7f a4 69 d6 93 bd da 13");
+        assertStringEquals(hex((byte[])pbkdf2.invoke(null, "password".toCharArray(), "ATHENA.MIT.EDUraeburn".getBytes("UTF-8"), 2, 256)), "01 db ee 7f 4a 9e 24 3e 98 8b 62 c7 3c da 93 5d  a0 53 78 b9 32 44 ec 8f 48 a9 9e 61 ad 79 9d 86");
+        assertStringEquals(hex((byte[])pbkdf2.invoke(null, "password".toCharArray(), "ATHENA.MIT.EDUraeburn".getBytes("UTF-8"), 1200, 128)), "5c 08 eb 61 fd f7 1e 4e 4e c3 cf 6b a1 f5 51 2b");
+        assertStringEquals(hex(a1.stringToKey("password".toCharArray(), "ATHENA.MIT.EDUraeburn", i2b(1200))), "4c 01 cd 46 d6 32 d0 1e 6d be 23 0a 01 ed 64 2a");
+        assertStringEquals(hex((byte[])pbkdf2.invoke(null, "password".toCharArray(), "ATHENA.MIT.EDUraeburn".getBytes("UTF-8"), 1200, 256)), "5c 08 eb 61 fd f7 1e 4e 4e c3 cf 6b a1 f5 51 2b  a7 e5 2d db c5 e5 14 2f 70 8a 31 e2 e6 2b 1e 13");
+        assertStringEquals(hex((byte[])pbkdf2.invoke(null, "password".toCharArray(), xeh("1234567878563412"), 5, 128)), "d1 da a7 86 15 f2 87 e6 a1 c8 b1 20 d7 06 2a 49");
+        assertStringEquals(hex((byte[])s2k.invoke(a1, "password".toCharArray(), xeh("1234567878563412"), i2b(5))), "e9 b2 3d 52 27 37 47 dd 5c 35 cb 55 be 61 9d 8e");
+        assertStringEquals(hex((byte[])pbkdf2.invoke(null, "password".toCharArray(), xeh("1234567878563412"), 5, 256)), "d1 da a7 86 15 f2 87 e6 a1 c8 b1 20 d7 06 2a 49  3f 98 d2 03 e6 be 49 a6 ad f4 fa 57 4b 6e 64 ee");
+        assertStringEquals(hex((byte[])pbkdf2.invoke(null, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".toCharArray(), "pass phrase equals block size".getBytes("UTF-8"), 1200, 128)), "13 9c 30 c0 96 6b c3 2b a5 5f db f2 12 53 0a c9");
+        assertStringEquals(hex(a1.stringToKey("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".toCharArray(), "pass phrase equals block size", i2b(1200))), "59 d1 bb 78 9a 82 8b 1a a5 4e f9 c2 88 3f 69 ed");
+        assertStringEquals(hex((byte[])pbkdf2.invoke(null, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".toCharArray(), "pass phrase equals block size".getBytes("UTF-8"), 1200, 256)), "13 9c 30 c0 96 6b c3 2b a5 5f db f2 12 53 0a c9  c5 ec 59 f1 a4 52 f5 cc 9a d9 40 fe a0 59 8e d1");
+        assertStringEquals(hex((byte[])pbkdf2.invoke(null, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".toCharArray(), "pass phrase exceeds block size".getBytes("UTF-8"), 1200, 128)), "9c ca d6 d4 68 77 0c d5 1b 10 e6 a6 87 21 be 61");
+        assertStringEquals(hex(a1.stringToKey("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".toCharArray(), "pass phrase exceeds block size", i2b(1200))), "cb 80 05 dc 5f 90 17 9a 7f 02 10 4c 00 18 75 1d");
+        assertStringEquals(hex((byte[])pbkdf2.invoke(null, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".toCharArray(), "pass phrase exceeds block size".getBytes("UTF-8"), 1200, 256)), "9c ca d6 d4 68 77 0c d5 1b 10 e6 a6 87 21 be 61  1a 8b 4d 28 26 01 db 3b 36 be 92 46 91 5e c8 2a");
+        assertStringEquals(hex((byte[])pbkdf2.invoke(null, gclef.toCharArray(), "EXAMPLE.COMpianist".getBytes("UTF-8"), 50, 128)), "6b 9c f2 6d 45 45 5a 43 a5 b8 bb 27 6a 40 3b 39");
+        assertStringEquals(hex(a1.stringToKey(gclef.toCharArray(), "EXAMPLE.COMpianist", i2b(50))), "f1 49 c1 f2 e1 54 a7 34 52 d4 3e 7f e6 2a 56 e5");
+        assertStringEquals(hex((byte[])pbkdf2.invoke(null, gclef.toCharArray(), "EXAMPLE.COMpianist".getBytes("UTF-8"), 50, 256)), "6b 9c f2 6d 45 45 5a 43 a5 b8 bb 27 6a 40 3b 39  e7 fe 37 a0 c4 1e 02 c2 81 ff 30 69 e1 e9 4f 52");
+
+        if (EType.isSupported(EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96)) {
+            AesDkCrypto a2 = new AesDkCrypto(256);
+            assertStringEquals(hex(a2.stringToKey("password".toCharArray(), "ATHENA.MIT.EDUraeburn", i2b(1))), "fe 69 7b 52 bc 0d 3c e1 44 32 ba 03 6a 92 e6 5b  bb 52 28 09 90 a2 fa 27 88 39 98 d7 2a f3 01 61");
+            assertStringEquals(hex(a2.stringToKey("password".toCharArray(), "ATHENA.MIT.EDUraeburn", i2b(2))), "a2 e1 6d 16 b3 60 69 c1 35 d5 e9 d2 e2 5f 89 61  02 68 56 18 b9 59 14 b4 67 c6 76 22 22 58 24 ff");
+            assertStringEquals(hex(a2.stringToKey("password".toCharArray(), "ATHENA.MIT.EDUraeburn", i2b(1200))), "55 a6 ac 74 0a d1 7b 48 46 94 10 51 e1 e8 b0 a7  54 8d 93 b0 ab 30 a8 bc 3f f1 62 80 38 2b 8c 2a");
+            assertStringEquals(hex((byte[])s2k.invoke(a2, "password".toCharArray(), xeh("1234567878563412"), i2b(5))), "97 a4 e7 86 be 20 d8 1a 38 2d 5e bc 96 d5 90 9c  ab cd ad c8 7c a4 8f 57 45 04 15 9f 16 c3 6e 31");
+            assertStringEquals(hex(a2.stringToKey("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".toCharArray(), "pass phrase equals block size", i2b(1200))), "89 ad ee 36 08 db 8b c7 1f 1b fb fe 45 94 86 b0  56 18 b7 0c ba e2 20 92 53 4e 56 c5 53 ba 4b 34");
+            assertStringEquals(hex(a2.stringToKey("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX".toCharArray(), "pass phrase exceeds block size", i2b(1200))), "d7 8c 5c 9c b8 72 a8 c9 da d4 69 7f 0b b5 b2 d2 14 96 c8 2b eb 2c ae da 21 12 fc ee a0 57 40 1b");
+            assertStringEquals(hex(a2.stringToKey(gclef.toCharArray(), "EXAMPLE.COMpianist", i2b(50))), "4b 6d 98 39 f8 44 06 df 1f 09 cc 16 6d b4 b8 3c  57 18 48 b7 84 a3 d6 bd c3 46 58 9a 3e 39 3f 9e");
+        }
+
+        Cipher cipher = Cipher.getInstance("AES/CTS/NoPadding");
+
+        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(
+                xeh("63 68 69 63 6b 65 6e 20 74 65 72 69 79 61 6b 69"), "AES"),
+                new IvParameterSpec(
+                xeh("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"), 0, 16));
+        assertStringEquals(hex(cipher.doFinal(
+                xeh("49 20 77 6f 75 6c 64 20 6c 69 6b 65 20 74 68 65 20"))),
+                "c6 35 35 68 f2 bf 8c b4 d8 a5 80 36 2d a7 ff 7f  97");
+        assertStringEquals(hex(cipher.doFinal(
+                xeh("49 20 77 6f 75 6c 64 20 6c 69 6b 65 20 74 68 65  20 47 65 6e 65 72 61 6c 20 47 61 75 27 73 20"))),
+                "fc 00 78 3e 0e fd b2 c1 d4 45 d4 c8 ef f7 ed 22  97 68 72 68 d6 ec cc c0 c0 7b 25 e2 5e cf e5");
+        assertStringEquals(hex(cipher.doFinal(
+                xeh("49 20 77 6f 75 6c 64 20 6c 69 6b 65 20 74 68 65  20 47 65 6e 65 72 61 6c 20 47 61 75 27 73 20 43"))),
+                "39 31 25 23 a7 86 62 d5 be 7f cb cc 98 eb f5 a8  97 68 72 68 d6 ec cc c0 c0 7b 25 e2 5e cf e5 84");
+        assertStringEquals(hex(cipher.doFinal(
+                xeh("49 20 77 6f 75 6c 64 20 6c 69 6b 65 20 74 68 65  20 47 65 6e 65 72 61 6c 20 47 61 75 27 73 20 43  68 69 63 6b 65 6e 2c 20 70 6c 65 61 73 65 2c"))),
+                "97 68 72 68 d6 ec cc c0 c0 7b 25 e2 5e cf e5 84  b3 ff fd 94 0c 16 a1 8c 1b 55 49 d2 f8 38 02 9e  39 31 25 23 a7 86 62 d5 be 7f cb cc 98 eb f5");
+        assertStringEquals(hex(cipher.doFinal(
+                xeh("49 20 77 6f 75 6c 64 20 6c 69 6b 65 20 74 68 65  20 47 65 6e 65 72 61 6c 20 47 61 75 27 73 20 43  68 69 63 6b 65 6e 2c 20 70 6c 65 61 73 65 2c 20"))),
+                "97 68 72 68 d6 ec cc c0 c0 7b 25 e2 5e cf e5 84  9d ad 8b bb 96 c4 cd c0 3b c1 03 e1 a1 94 bb d8  39 31 25 23 a7 86 62 d5 be 7f cb cc 98 eb f5 a8");
+        assertStringEquals(hex(cipher.doFinal(
+                xeh("49 20 77 6f 75 6c 64 20 6c 69 6b 65 20 74 68 65  20 47 65 6e 65 72 61 6c 20 47 61 75 27 73 20 43  68 69 63 6b 65 6e 2c 20 70 6c 65 61 73 65 2c 20  61 6e 64 20 77 6f 6e 74 6f 6e 20 73 6f 75 70 2e"))),
+                "97 68 72 68 d6 ec cc c0 c0 7b 25 e2 5e cf e5 84  39 31 25 23 a7 86 62 d5 be 7f cb cc 98 eb f5 a8  48 07 ef e8 36 ee 89 a5 26 73 0d bc 2f 7b c8 40  9d ad 8b bb 96 c4 cd c0 3b c1 03 e1 a1 94 bb d8");
+    }
+
+    static byte[] i2b(int i) {
+        ByteBuffer bb = ByteBuffer.allocate(4);
+        byte[] b = new byte[4];
+        bb.putInt(i);
+        bb.flip();
+        bb.get(b);
+        return b;
+    }
+
+    static String hex(byte[] bs) {
+        StringBuffer sb = new StringBuffer(bs.length * 2);
+        for(byte b: bs) {
+            char c = (char)((b+256)%256);
+            if (c / 16 < 10)
+                sb.append((char)(c/16+'0'));
+            else
+                sb.append((char)(c/16-10+'a'));
+            if (c % 16 < 10)
+                sb.append((char)(c%16+'0'));
+            else
+                sb.append((char)(c%16-10+'a'));
+        }
+        return new String(sb);
+    }
+
+    static byte[] xeh(String in) {
+        in = in.replaceAll(" ", "");
+        int len = in.length()/2;
+        byte[] out = new byte[len];
+        for (int i=0; i<len; i++) {
+            out[i] = (byte)Integer.parseInt(in.substring(i*2, i*2+2), 16);
+        }
+        return out;
+    }
+
+    static void assertStringEquals(String a, String b) {
+        a = a.replaceAll(" ", "");
+        b = b.replaceAll(" ", "");
+        if (!a.equals(b)) {
+            throw new RuntimeException("Not equal: " + a + " AND " + b);
+        }
+        System.err.print(".");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/tools/jarsigner/passtype.sh	Fri Oct 02 13:59:37 2009 +0100
@@ -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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/tools/keytool/newhelp.sh	Fri Oct 02 13:59:37 2009 +0100
@@ -0,0 +1,53 @@
+#
+# 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 6324292
+# @summary keytool -help is unhelpful
+#
+
+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
+
+LANG=C
+$TESTJAVA${FS}bin${FS}keytool -help 2> h1 || exit 1
+$TESTJAVA${FS}bin${FS}keytool -help -list 2> h2 || exit 2
+
+grep Commands: h1 || exit 3
+grep Options: h2 || exit 4
+
+exit 0
+