Save This Page
Home » openjdk-7 » sun.security » tools » [javadoc | source]
    1   /*
    2    * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package sun.security.tools;
   27   
   28   import java.io;
   29   import java.math.BigInteger;
   30   import java.security.GeneralSecurityException;
   31   import java.security.InvalidParameterException;
   32   import java.security.KeyStore;
   33   import java.security.KeyStoreException;
   34   import java.security.MessageDigest;
   35   import java.security.NoSuchAlgorithmException;
   36   import java.security.Key;
   37   import java.security.PublicKey;
   38   import java.security.PrivateKey;
   39   import java.security.Security;
   40   import java.security.Signature;
   41   import java.security.SignatureException;
   42   import java.security.UnrecoverableEntryException;
   43   import java.security.UnrecoverableKeyException;
   44   import java.security.Principal;
   45   import java.security.Provider;
   46   import java.security.Identity;
   47   import java.security.Signer;
   48   import java.security.cert.Certificate;
   49   import java.security.cert.CertificateFactory;
   50   import java.security.cert.X509Certificate;
   51   import java.security.cert.CertificateException;
   52   import java.security.interfaces.DSAParams;
   53   import java.security.interfaces.DSAPrivateKey;
   54   import java.security.interfaces.DSAPublicKey;
   55   import java.security.interfaces.RSAPrivateCrtKey;
   56   import java.security.interfaces.RSAPrivateKey;
   57   import java.security.interfaces.RSAPublicKey;
   58   import java.text.Collator;
   59   import java.text.MessageFormat;
   60   import java.util;
   61   import java.lang.reflect.Constructor;
   62   import java.net.URL;
   63   import java.net.URLClassLoader;
   64   
   65   import sun.misc.BASE64Decoder;
   66   import sun.misc.BASE64Encoder;
   67   import sun.security.util.ObjectIdentifier;
   68   import sun.security.pkcs.PKCS10;
   69   import sun.security.provider.IdentityDatabase;
   70   import sun.security.provider.SystemSigner;
   71   import sun.security.provider.SystemIdentity;
   72   import sun.security.provider.X509Factory;
   73   import sun.security.util.DerOutputStream;
   74   import sun.security.util.Password;
   75   import sun.security.util.Resources;
   76   import sun.security.util.PathList;
   77   import javax.crypto.KeyGenerator;
   78   import javax.crypto.SecretKey;
   79   
   80   import sun.security.x509;
   81   
   82   import static java.security.KeyStore.*;
   83   
   84   /**
   85    * This tool manages keystores.
   86    *
   87    * @author Jan Luehe
   88    *
   89    *
   90    * @see java.security.KeyStore
   91    * @see sun.security.provider.KeyProtector
   92    * @see sun.security.provider.JavaKeyStore
   93    *
   94    * @since 1.2
   95    */
   96   
   97   public final class KeyTool {
   98   
   99       private boolean debug = false;
  100       private int command = -1;
  101       private String sigAlgName = null;
  102       private String keyAlgName = null;
  103       private boolean verbose = false;
  104       private int keysize = -1;
  105       private boolean rfc = false;
  106       private long validity = (long)90;
  107       private String alias = null;
  108       private String dname = null;
  109       private String dest = null;
  110       private String filename = null;
  111       private String srcksfname = null;
  112   
  113       // User-specified providers are added before any command is called.
  114       // However, they are not removed before the end of the main() method.
  115       // If you're calling KeyTool.main() directly in your own Java program,
  116       // please programtically add any providers you need and do not specify
  117       // them through the command line.
  118   
  119       private Set<Pair <String, String>> providers = null;
  120       private String storetype = null;
  121       private String srcProviderName = null;
  122       private String providerName = null;
  123       private String pathlist = null;
  124       private char[] storePass = null;
  125       private char[] storePassNew = null;
  126       private char[] keyPass = null;
  127       private char[] keyPassNew = null;
  128       private char[] oldPass = null;
  129       private char[] newPass = null;
  130       private char[] destKeyPass = null;
  131       private char[] srckeyPass = null;
  132       private String ksfname = null;
  133       private File ksfile = null;
  134       private InputStream ksStream = null; // keystore stream
  135       private KeyStore keyStore = null;
  136       private boolean token = false;
  137       private boolean nullStream = false;
  138       private boolean kssave = false;
  139       private boolean noprompt = false;
  140       private boolean trustcacerts = false;
  141       private boolean protectedPath = false;
  142       private boolean srcprotectedPath = false;
  143       private CertificateFactory cf = null;
  144       private KeyStore caks = null; // "cacerts" keystore
  145       private char[] srcstorePass = null;
  146       private String srcstoretype = null;
  147       private Set<char[]> passwords = new HashSet<char[]> ();
  148       private String startDate = null;
  149   
  150       private static final int CERTREQ = 1;
  151       private static final int CHANGEALIAS = 2;
  152       private static final int DELETE = 3;
  153       private static final int EXPORTCERT = 4;
  154       private static final int GENKEYPAIR = 5;
  155       private static final int GENSECKEY = 6;
  156       // there is no HELP
  157       private static final int IDENTITYDB = 7;
  158       private static final int IMPORTCERT = 8;
  159       private static final int IMPORTKEYSTORE = 9;
  160       private static final int KEYCLONE = 10;
  161       private static final int KEYPASSWD = 11;
  162       private static final int LIST = 12;
  163       private static final int PRINTCERT = 13;
  164       private static final int SELFCERT = 14;
  165       private static final int STOREPASSWD = 15;
  166   
  167       private static final Class[] PARAM_STRING = { String.class };
  168   
  169       private static final String JKS = "jks";
  170       private static final String NONE = "NONE";
  171       private static final String P11KEYSTORE = "PKCS11";
  172       private static final String P12KEYSTORE = "PKCS12";
  173       private final String keyAlias = "mykey";
  174   
  175       // for i18n
  176       private static final java.util.ResourceBundle rb =
  177           java.util.ResourceBundle.getBundle("sun.security.util.Resources");
  178       private static final Collator collator = Collator.getInstance();
  179       static {
  180           // this is for case insensitive string comparisons
  181           collator.setStrength(Collator.PRIMARY);
  182       };
  183   
  184       private KeyTool() { }
  185   
  186       public static void main(String[] args) throws Exception {
  187           KeyTool kt = new KeyTool();
  188           kt.run(args, System.out);
  189       }
  190   
  191       private void run(String[] args, PrintStream out) throws Exception {
  192           try {
  193               parseArgs(args);
  194               doCommands(out);
  195           } catch (Exception e) {
  196               System.out.println(rb.getString("keytool error: ") + e);
  197               if (verbose) {
  198                   e.printStackTrace(System.out);
  199               }
  200               if (!debug) {
  201                   System.exit(1);
  202               } else {
  203                   throw e;
  204               }
  205           } finally {
  206               for (char[] pass : passwords) {
  207                   if (pass != null) {
  208                       Arrays.fill(pass, ' ');
  209                       pass = null;
  210                   }
  211               }
  212   
  213               if (ksStream != null) {
  214                   ksStream.close();
  215               }
  216           }
  217       }
  218   
  219       /**
  220        * Parse command line arguments.
  221        */
  222       void parseArgs(String[] args) {
  223   
  224           if (args.length == 0) usage();
  225   
  226           int i=0;
  227   
  228           for (i=0; (i < args.length) && args[i].startsWith("-"); i++) {
  229   
  230               String flags = args[i];
  231               /*
  232                * command modes
  233                */
  234               if (collator.compare(flags, "-certreq") == 0) {
  235                   command = CERTREQ;
  236               } else if (collator.compare(flags, "-delete") == 0) {
  237                   command = DELETE;
  238               } else if (collator.compare(flags, "-export") == 0 ||
  239                       collator.compare(flags, "-exportcert") == 0) {
  240                   command = EXPORTCERT;
  241               } else if (collator.compare(flags, "-genkey") == 0 ||
  242                       collator.compare(flags, "-genkeypair") == 0) {
  243                   command = GENKEYPAIR;
  244               } else if (collator.compare(flags, "-help") == 0) {
  245                   usage();
  246                   return;
  247               } else if (collator.compare(flags, "-identitydb") == 0) { // obsolete
  248                   command = IDENTITYDB;
  249               } else if (collator.compare(flags, "-import") == 0 ||
  250                       collator.compare(flags, "-importcert") == 0) {
  251                   command = IMPORTCERT;
  252               } else if (collator.compare(flags, "-keyclone") == 0) { // obsolete
  253                   command = KEYCLONE;
  254               } else if (collator.compare(flags, "-changealias") == 0) {
  255                   command = CHANGEALIAS;
  256               } else if (collator.compare(flags, "-keypasswd") == 0) {
  257                   command = KEYPASSWD;
  258               } else if (collator.compare(flags, "-list") == 0) {
  259                   command = LIST;
  260               } else if (collator.compare(flags, "-printcert") == 0) {
  261                   command = PRINTCERT;
  262               } else if (collator.compare(flags, "-selfcert") == 0) {     // obsolete
  263                   command = SELFCERT;
  264               } else if (collator.compare(flags, "-storepasswd") == 0) {
  265                   command = STOREPASSWD;
  266               } else if (collator.compare(flags, "-importkeystore") == 0) {
  267                   command = IMPORTKEYSTORE;
  268               } else if (collator.compare(flags, "-genseckey") == 0) {
  269                   command = GENSECKEY;
  270               }
  271   
  272               /*
  273                * specifiers
  274                */
  275               else if (collator.compare(flags, "-keystore") == 0 ||
  276                       collator.compare(flags, "-destkeystore") == 0) {
  277                   if (++i == args.length) errorNeedArgument(flags);
  278                   ksfname = args[i];
  279               } else if (collator.compare(flags, "-storepass") == 0 ||
  280                       collator.compare(flags, "-deststorepass") == 0) {
  281                   if (++i == args.length) errorNeedArgument(flags);
  282                   storePass = args[i].toCharArray();
  283                   passwords.add(storePass);
  284               } else if (collator.compare(flags, "-storetype") == 0 ||
  285                       collator.compare(flags, "-deststoretype") == 0) {
  286                   if (++i == args.length) errorNeedArgument(flags);
  287                   storetype = args[i];
  288               } else if (collator.compare(flags, "-srcstorepass") == 0) {
  289                   if (++i == args.length) errorNeedArgument(flags);
  290                   srcstorePass = args[i].toCharArray();
  291                   passwords.add(srcstorePass);
  292               } else if (collator.compare(flags, "-srcstoretype") == 0) {
  293                   if (++i == args.length) errorNeedArgument(flags);
  294                   srcstoretype = args[i];
  295               } else if (collator.compare(flags, "-srckeypass") == 0) {
  296                   if (++i == args.length) errorNeedArgument(flags);
  297                   srckeyPass = args[i].toCharArray();
  298                   passwords.add(srckeyPass);
  299               } else if (collator.compare(flags, "-srcprovidername") == 0) {
  300                   if (++i == args.length) errorNeedArgument(flags);
  301                   srcProviderName = args[i];
  302               } else if (collator.compare(flags, "-providername") == 0 ||
  303                       collator.compare(flags, "-destprovidername") == 0) {
  304                   if (++i == args.length) errorNeedArgument(flags);
  305                   providerName = args[i];
  306               } else if (collator.compare(flags, "-providerpath") == 0) {
  307                   if (++i == args.length) errorNeedArgument(flags);
  308                   pathlist = args[i];
  309               } else if (collator.compare(flags, "-keypass") == 0) {
  310                   if (++i == args.length) errorNeedArgument(flags);
  311                   keyPass = args[i].toCharArray();
  312                   passwords.add(keyPass);
  313               } else if (collator.compare(flags, "-new") == 0) {
  314                   if (++i == args.length) errorNeedArgument(flags);
  315                   newPass = args[i].toCharArray();
  316                   passwords.add(newPass);
  317               } else if (collator.compare(flags, "-destkeypass") == 0) {
  318                   if (++i == args.length) errorNeedArgument(flags);
  319                   destKeyPass = args[i].toCharArray();
  320                   passwords.add(destKeyPass);
  321               } else if (collator.compare(flags, "-alias") == 0 ||
  322                       collator.compare(flags, "-srcalias") == 0) {
  323                   if (++i == args.length) errorNeedArgument(flags);
  324                   alias = args[i];
  325               } else if (collator.compare(flags, "-dest") == 0 ||
  326                       collator.compare(flags, "-destalias") == 0) {
  327                   if (++i == args.length) errorNeedArgument(flags);
  328                   dest = args[i];
  329               } else if (collator.compare(flags, "-dname") == 0) {
  330                   if (++i == args.length) errorNeedArgument(flags);
  331                   dname = args[i];
  332               } else if (collator.compare(flags, "-keysize") == 0) {
  333                   if (++i == args.length) errorNeedArgument(flags);
  334                   keysize = Integer.parseInt(args[i]);
  335               } else if (collator.compare(flags, "-keyalg") == 0) {
  336                   if (++i == args.length) errorNeedArgument(flags);
  337                   keyAlgName = args[i];
  338               } else if (collator.compare(flags, "-sigalg") == 0) {
  339                   if (++i == args.length) errorNeedArgument(flags);
  340                   sigAlgName = args[i];
  341               } else if (collator.compare(flags, "-startdate") == 0) {
  342                   if (++i == args.length) errorNeedArgument(flags);
  343                   startDate = args[i];
  344               } else if (collator.compare(flags, "-validity") == 0) {
  345                   if (++i == args.length) errorNeedArgument(flags);
  346                   validity = Long.parseLong(args[i]);
  347               } else if (collator.compare(flags, "-file") == 0) {
  348                   if (++i == args.length) errorNeedArgument(flags);
  349                   filename = args[i];
  350               } else if (collator.compare(flags, "-srckeystore") == 0) {
  351                   if (++i == args.length) errorNeedArgument(flags);
  352                   srcksfname = args[i];
  353               } else if ((collator.compare(flags, "-provider") == 0) ||
  354                           (collator.compare(flags, "-providerclass") == 0)) {
  355                   if (++i == args.length) errorNeedArgument(flags);
  356                   if (providers == null) {
  357                       providers = new HashSet<Pair <String, String>> (3);
  358                   }
  359                   String providerClass = args[i];
  360                   String providerArg = null;
  361   
  362                   if (args.length > (i+1)) {
  363                       flags = args[i+1];
  364                       if (collator.compare(flags, "-providerarg") == 0) {
  365                           if (args.length == (i+2)) errorNeedArgument(flags);
  366                           providerArg = args[i+2];
  367                           i += 2;
  368                       }
  369                   }
  370                   providers.add(
  371                           new Pair<String, String>(providerClass, providerArg));
  372               }
  373   
  374               /*
  375                * options
  376                */
  377               else if (collator.compare(flags, "-v") == 0) {
  378                   verbose = true;
  379               } else if (collator.compare(flags, "-debug") == 0) {
  380                   debug = true;
  381               } else if (collator.compare(flags, "-rfc") == 0) {
  382                   rfc = true;
  383               } else if (collator.compare(flags, "-noprompt") == 0) {
  384                   noprompt = true;
  385               } else if (collator.compare(flags, "-trustcacerts") == 0) {
  386                   trustcacerts = true;
  387               } else if (collator.compare(flags, "-protected") == 0 ||
  388                       collator.compare(flags, "-destprotected") == 0) {
  389                   protectedPath = true;
  390               } else if (collator.compare(flags, "-srcprotected") == 0) {
  391                   srcprotectedPath = true;
  392               } else  {
  393                   System.err.println(rb.getString("Illegal option:  ") + flags);
  394                   tinyHelp();
  395               }
  396           }
  397   
  398           if (i<args.length) {
  399               MessageFormat form = new MessageFormat
  400                   (rb.getString("Usage error, <arg> is not a legal command"));
  401               Object[] source = {args[i]};
  402               throw new RuntimeException(form.format(source));
  403           }
  404   
  405           if (command == -1) {
  406               System.err.println(rb.getString("Usage error: no command provided"));
  407               tinyHelp();
  408           }
  409       }
  410   
  411       /**
  412        * Execute the commands.
  413        */
  414       void doCommands(PrintStream out) throws Exception {
  415   
  416           if (storetype == null) {
  417               storetype = KeyStore.getDefaultType();
  418           }
  419           storetype = KeyStoreUtil.niceStoreTypeName(storetype);
  420   
  421           if (srcstoretype == null) {
  422               srcstoretype = KeyStore.getDefaultType();
  423           }
  424           srcstoretype = KeyStoreUtil.niceStoreTypeName(srcstoretype);
  425   
  426           if (P11KEYSTORE.equalsIgnoreCase(storetype) ||
  427                   KeyStoreUtil.isWindowsKeyStore(storetype)) {
  428               token = true;
  429               if (ksfname == null) {
  430                   ksfname = NONE;
  431               }
  432           }
  433           if (NONE.equals(ksfname)) {
  434               nullStream = true;
  435           }
  436   
  437           if (token && !nullStream) {
  438               System.err.println(MessageFormat.format(rb.getString
  439                   ("-keystore must be NONE if -storetype is {0}"), storetype));
  440               System.err.println();
  441               tinyHelp();
  442           }
  443   
  444           if (token &&
  445               (command == KEYPASSWD || command == STOREPASSWD)) {
  446               throw new UnsupportedOperationException(MessageFormat.format(rb.getString
  447                           ("-storepasswd and -keypasswd commands not supported " +
  448                           "if -storetype is {0}"), storetype));
  449           }
  450   
  451           if (P12KEYSTORE.equalsIgnoreCase(storetype) && command == KEYPASSWD) {
  452               throw new UnsupportedOperationException(rb.getString
  453                           ("-keypasswd commands not supported " +
  454                           "if -storetype is PKCS12"));
  455           }
  456   
  457           if (token && (keyPass != null || newPass != null || destKeyPass != null)) {
  458               throw new IllegalArgumentException(MessageFormat.format(rb.getString
  459                   ("-keypass and -new " +
  460                   "can not be specified if -storetype is {0}"), storetype));
  461           }
  462   
  463           if (protectedPath) {
  464               if (storePass != null || keyPass != null ||
  465                       newPass != null || destKeyPass != null) {
  466                   throw new IllegalArgumentException(rb.getString
  467                           ("if -protected is specified, " +
  468                           "then -storepass, -keypass, and -new " +
  469                           "must not be specified"));
  470               }
  471           }
  472   
  473           if (srcprotectedPath) {
  474               if (srcstorePass != null || srckeyPass != null) {
  475                   throw new IllegalArgumentException(rb.getString
  476                           ("if -srcprotected is specified, " +
  477                           "then -srcstorepass and -srckeypass " +
  478                           "must not be specified"));
  479               }
  480           }
  481   
  482           if (KeyStoreUtil.isWindowsKeyStore(storetype)) {
  483               if (storePass != null || keyPass != null ||
  484                       newPass != null || destKeyPass != null) {
  485                   throw new IllegalArgumentException(rb.getString
  486                           ("if keystore is not password protected, " +
  487                           "then -storepass, -keypass, and -new " +
  488                           "must not be specified"));
  489               }
  490           }
  491   
  492           if (KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
  493               if (srcstorePass != null || srckeyPass != null) {
  494                   throw new IllegalArgumentException(rb.getString
  495                           ("if source keystore is not password protected, " +
  496                           "then -srcstorepass and -srckeypass " +
  497                           "must not be specified"));
  498               }
  499           }
  500   
  501           if (validity <= (long)0) {
  502               throw new Exception
  503                   (rb.getString("Validity must be greater than zero"));
  504           }
  505   
  506           // Try to load and install specified provider
  507           if (providers != null) {
  508               ClassLoader cl = null;
  509               if (pathlist != null) {
  510                   String path = null;
  511                   path = PathList.appendPath(
  512                           path, System.getProperty("java.class.path"));
  513                   path = PathList.appendPath(
  514                           path, System.getProperty("env.class.path"));
  515                   path = PathList.appendPath(path, pathlist);
  516   
  517                   URL[] urls = PathList.pathToURLs(path);
  518                   cl = new URLClassLoader(urls);
  519               } else {
  520                   cl = ClassLoader.getSystemClassLoader();
  521               }
  522   
  523               for (Pair <String, String> provider: providers) {
  524                   String provName = provider.fst;
  525                   Class<?> provClass;
  526                   if (cl != null) {
  527                       provClass = cl.loadClass(provName);
  528                   } else {
  529                       provClass = Class.forName(provName);
  530                   }
  531   
  532                   String provArg = provider.snd;
  533                   Object obj;
  534                   if (provArg == null) {
  535                       obj = provClass.newInstance();
  536                   } else {
  537                       Constructor<?> c = provClass.getConstructor(PARAM_STRING);
  538                       obj = c.newInstance(provArg);
  539                   }
  540                   if (!(obj instanceof Provider)) {
  541                       MessageFormat form = new MessageFormat
  542                           (rb.getString("provName not a provider"));
  543                       Object[] source = {provName};
  544                       throw new Exception(form.format(source));
  545                   }
  546                   Security.addProvider((Provider)obj);
  547               }
  548           }
  549   
  550           if (command == LIST && verbose && rfc) {
  551               System.err.println(rb.getString
  552                   ("Must not specify both -v and -rfc with 'list' command"));
  553               tinyHelp();
  554           }
  555   
  556           // Make sure provided passwords are at least 6 characters long
  557           if (command == GENKEYPAIR && keyPass!=null && keyPass.length < 6) {
  558               throw new Exception(rb.getString
  559                   ("Key password must be at least 6 characters"));
  560           }
  561           if (newPass != null && newPass.length < 6) {
  562               throw new Exception(rb.getString
  563                   ("New password must be at least 6 characters"));
  564           }
  565           if (destKeyPass != null && destKeyPass.length < 6) {
  566               throw new Exception(rb.getString
  567                   ("New password must be at least 6 characters"));
  568           }
  569   
  570           // Check if keystore exists.
  571           // If no keystore has been specified at the command line, try to use
  572           // the default, which is located in $HOME/.keystore.
  573           // If the command is "genkey", "identitydb", "import", or "printcert",
  574           // it is OK not to have a keystore.
  575           if (command != PRINTCERT) {
  576               if (ksfname == null) {
  577                   ksfname = System.getProperty("user.home") + File.separator
  578                       + ".keystore";
  579               }
  580   
  581               if (!nullStream) {
  582                   try {
  583                       ksfile = new File(ksfname);
  584                       // Check if keystore file is empty
  585                       if (ksfile.exists() && ksfile.length() == 0) {
  586                           throw new Exception(rb.getString
  587                           ("Keystore file exists, but is empty: ") + ksfname);
  588                       }
  589                       ksStream = new FileInputStream(ksfile);
  590                   } catch (FileNotFoundException e) {
  591                       if (command != GENKEYPAIR &&
  592                           command != GENSECKEY &&
  593                           command != IDENTITYDB &&
  594                           command != IMPORTCERT &&
  595                           command != IMPORTKEYSTORE) {
  596                           throw new Exception(rb.getString
  597                                   ("Keystore file does not exist: ") + ksfname);
  598                       }
  599                   }
  600               }
  601           }
  602   
  603           if ((command == KEYCLONE || command == CHANGEALIAS)
  604                   && dest == null) {
  605               dest = getAlias("destination");
  606               if ("".equals(dest)) {
  607                   throw new Exception(rb.getString
  608                           ("Must specify destination alias"));
  609               }
  610           }
  611   
  612           if (command == DELETE && alias == null) {
  613               alias = getAlias(null);
  614               if ("".equals(alias)) {
  615                   throw new Exception(rb.getString("Must specify alias"));
  616               }
  617           }
  618   
  619           // Create new keystore
  620           if (providerName == null) {
  621               keyStore = KeyStore.getInstance(storetype);
  622           } else {
  623               keyStore = KeyStore.getInstance(storetype, providerName);
  624           }
  625   
  626           /*
  627            * Load the keystore data.
  628            *
  629            * At this point, it's OK if no keystore password has been provided.
  630            * We want to make sure that we can load the keystore data, i.e.,
  631            * the keystore data has the right format. If we cannot load the
  632            * keystore, why bother asking the user for his or her password?
  633            * Only if we were able to load the keystore, and no keystore
  634            * password has been provided, will we prompt the user for the
  635            * keystore password to verify the keystore integrity.
  636            * This means that the keystore is loaded twice: first load operation
  637            * checks the keystore format, second load operation verifies the
  638            * keystore integrity.
  639            *
  640            * If the keystore password has already been provided (at the
  641            * command line), however, the keystore is loaded only once, and the
  642            * keystore format and integrity are checked "at the same time".
  643            *
  644            * Null stream keystores are loaded later.
  645            */
  646           if (!nullStream) {
  647               keyStore.load(ksStream, storePass);
  648               if (ksStream != null) {
  649                   ksStream.close();
  650               }
  651           }
  652   
  653           // All commands that create or modify the keystore require a keystore
  654           // password.
  655   
  656           if (nullStream && storePass != null) {
  657               keyStore.load(null, storePass);
  658           } else if (!nullStream && storePass != null) {
  659               // If we are creating a new non nullStream-based keystore,
  660               // insist that the password be at least 6 characters
  661               if (ksStream == null && storePass.length < 6) {
  662                   throw new Exception(rb.getString
  663                           ("Keystore password must be at least 6 characters"));
  664               }
  665           } else if (storePass == null) {
  666   
  667               // only prompt if (protectedPath == false)
  668   
  669               if (!protectedPath && !KeyStoreUtil.isWindowsKeyStore(storetype) &&
  670                   (command == CERTREQ ||
  671                           command == DELETE ||
  672                           command == GENKEYPAIR ||
  673                           command == GENSECKEY ||
  674                           command == IMPORTCERT ||
  675                           command == IMPORTKEYSTORE ||
  676                           command == KEYCLONE ||
  677                           command == CHANGEALIAS ||
  678                           command == SELFCERT ||
  679                           command == STOREPASSWD ||
  680                           command == KEYPASSWD ||
  681                           command == IDENTITYDB)) {
  682                   int count = 0;
  683                   do {
  684                       if (command == IMPORTKEYSTORE) {
  685                           System.err.print
  686                                   (rb.getString("Enter destination keystore password:  "));
  687                       } else {
  688                           System.err.print
  689                                   (rb.getString("Enter keystore password:  "));
  690                       }
  691                       System.err.flush();
  692                       storePass = Password.readPassword(System.in);
  693                       passwords.add(storePass);
  694   
  695                       // If we are creating a new non nullStream-based keystore,
  696                       // insist that the password be at least 6 characters
  697                       if (!nullStream && (storePass == null || storePass.length < 6)) {
  698                           System.err.println(rb.getString
  699                                   ("Keystore password is too short - " +
  700                                   "must be at least 6 characters"));
  701                           storePass = null;
  702                       }
  703   
  704                       // If the keystore file does not exist and needs to be
  705                       // created, the storepass should be prompted twice.
  706                       if (storePass != null && !nullStream && ksStream == null) {
  707                           System.err.print(rb.getString("Re-enter new password: "));
  708                           char[] storePassAgain = Password.readPassword(System.in);
  709                           passwords.add(storePassAgain);
  710                           if (!Arrays.equals(storePass, storePassAgain)) {
  711                               System.err.println
  712                                   (rb.getString("They don't match. Try again"));
  713                               storePass = null;
  714                           }
  715                       }
  716   
  717                       count++;
  718                   } while ((storePass == null) && count < 3);
  719   
  720   
  721                   if (storePass == null) {
  722                       System.err.println
  723                           (rb.getString("Too many failures - try later"));
  724                       return;
  725                   }
  726               } else if (!protectedPath
  727                       && !KeyStoreUtil.isWindowsKeyStore(storetype)
  728                       && !(command == PRINTCERT)) {
  729                   // here we have EXPORTCERT and LIST (info valid until STOREPASSWD)
  730                   System.err.print(rb.getString("Enter keystore password:  "));
  731                   System.err.flush();
  732                   storePass = Password.readPassword(System.in);
  733                   passwords.add(storePass);
  734               }
  735   
  736               // Now load a nullStream-based keystore,
  737               // or verify the integrity of an input stream-based keystore
  738               if (nullStream) {
  739                   keyStore.load(null, storePass);
  740               } else if (ksStream != null) {
  741                   ksStream = new FileInputStream(ksfile);
  742                   keyStore.load(ksStream, storePass);
  743                   ksStream.close();
  744               }
  745           }
  746   
  747           if (storePass != null && P12KEYSTORE.equalsIgnoreCase(storetype)) {
  748               MessageFormat form = new MessageFormat(rb.getString(
  749                   "Warning:  Different store and key passwords not supported " +
  750                   "for PKCS12 KeyStores. Ignoring user-specified <command> value."));
  751               if (keyPass != null && !Arrays.equals(storePass, keyPass)) {
  752                   Object[] source = {"-keypass"};
  753                   System.err.println(form.format(source));
  754                   keyPass = storePass;
  755               }
  756               if (newPass != null && !Arrays.equals(storePass, newPass)) {
  757                   Object[] source = {"-new"};
  758                   System.err.println(form.format(source));
  759                   newPass = storePass;
  760               }
  761               if (destKeyPass != null && !Arrays.equals(storePass, destKeyPass)) {
  762                   Object[] source = {"-destkeypass"};
  763                   System.err.println(form.format(source));
  764                   destKeyPass = storePass;
  765               }
  766           }
  767   
  768           // Create a certificate factory
  769           if (command == PRINTCERT || command == IMPORTCERT
  770                  || command == IDENTITYDB) {
  771               cf = CertificateFactory.getInstance("X509");
  772           }
  773   
  774           if (trustcacerts) {
  775               caks = getCacertsKeyStore();
  776           }
  777   
  778           // Perform the specified command
  779           if (command == CERTREQ) {
  780               PrintStream ps = null;
  781               if (filename != null) {
  782                   ps = new PrintStream(new FileOutputStream
  783                                                    (filename));
  784                   out = ps;
  785               }
  786               try {
  787                   doCertReq(alias, sigAlgName, out);
  788               } finally {
  789                   if (ps != null) {
  790                       ps.close();
  791                   }
  792               }
  793               if (verbose && filename != null) {
  794                   MessageFormat form = new MessageFormat(rb.getString
  795                           ("Certification request stored in file <filename>"));
  796                   Object[] source = {filename};
  797                   System.err.println(form.format(source));
  798                   System.err.println(rb.getString("Submit this to your CA"));
  799               }
  800           } else if (command == DELETE) {
  801               doDeleteEntry(alias);
  802               kssave = true;
  803           } else if (command == EXPORTCERT) {
  804               PrintStream ps = null;
  805               if (filename != null) {
  806                   ps = new PrintStream(new FileOutputStream
  807                                                    (filename));
  808                   out = ps;
  809               }
  810               try {
  811                   doExportCert(alias, out);
  812               } finally {
  813                   if (ps != null) {
  814                       ps.close();
  815                   }
  816               }
  817               if (filename != null) {
  818                   MessageFormat form = new MessageFormat(rb.getString
  819                           ("Certificate stored in file <filename>"));
  820                   Object[] source = {filename};
  821                   System.err.println(form.format(source));
  822               }
  823           } else if (command == GENKEYPAIR) {
  824               if (keyAlgName == null) {
  825                   keyAlgName = "DSA";
  826               }
  827               doGenKeyPair(alias, dname, keyAlgName, keysize, sigAlgName);
  828               kssave = true;
  829           } else if (command == GENSECKEY) {
  830               if (keyAlgName == null) {
  831                   keyAlgName = "DES";
  832               }
  833               doGenSecretKey(alias, keyAlgName, keysize);
  834               kssave = true;
  835           } else if (command == IDENTITYDB) {
  836               InputStream inStream = System.in;
  837               if (filename != null) {
  838                   inStream = new FileInputStream(filename);
  839               }
  840               try {
  841                   doImportIdentityDatabase(inStream);
  842               } finally {
  843                   if (inStream != System.in) {
  844                       inStream.close();
  845                   }
  846               }
  847           } else if (command == IMPORTCERT) {
  848               InputStream inStream = System.in;
  849               if (filename != null) {
  850                   inStream = new FileInputStream(filename);
  851               }
  852               try {
  853                   String importAlias = (alias!=null)?alias:keyAlias;
  854                   if (keyStore.entryInstanceOf(importAlias, KeyStore.PrivateKeyEntry.class)) {
  855                       kssave = installReply(importAlias, inStream);
  856                       if (kssave) {
  857                           System.err.println(rb.getString
  858                               ("Certificate reply was installed in keystore"));
  859                       } else {
  860                           System.err.println(rb.getString
  861                               ("Certificate reply was not installed in keystore"));
  862                       }
  863                   } else if (!keyStore.containsAlias(importAlias) ||
  864                           keyStore.entryInstanceOf(importAlias,
  865                               KeyStore.TrustedCertificateEntry.class)) {
  866                       kssave = addTrustedCert(importAlias, inStream);
  867                       if (kssave) {
  868                           System.err.println(rb.getString
  869                               ("Certificate was added to keystore"));
  870                       } else {
  871                           System.err.println(rb.getString
  872                               ("Certificate was not added to keystore"));
  873                       }
  874                   }
  875               } finally {
  876                   if (inStream != System.in) {
  877                       inStream.close();
  878                   }
  879               }
  880           } else if (command == IMPORTKEYSTORE) {
  881               doImportKeyStore();
  882               kssave = true;
  883           } else if (command == KEYCLONE) {
  884               keyPassNew = newPass;
  885   
  886               // added to make sure only key can go thru
  887               if (alias == null) {
  888                   alias = keyAlias;
  889               }
  890               if (keyStore.containsAlias(alias) == false) {
  891                   MessageFormat form = new MessageFormat
  892                       (rb.getString("Alias <alias> does not exist"));
  893                   Object[] source = {alias};
  894                   throw new Exception(form.format(source));
  895               }
  896               if (!keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) {
  897                   MessageFormat form = new MessageFormat(rb.getString(
  898                           "Alias <alias> references an entry type that is not a private key entry.  " +
  899                           "The -keyclone command only supports cloning of private key entries"));
  900                   Object[] source = {alias};
  901                   throw new Exception(form.format(source));
  902               }
  903   
  904               doCloneEntry(alias, dest, true);  // Now everything can be cloned
  905               kssave = true;
  906           } else if (command == CHANGEALIAS) {
  907               if (alias == null) {
  908                   alias = keyAlias;
  909               }
  910               doCloneEntry(alias, dest, false);
  911               // in PKCS11, clone a PrivateKeyEntry will delete the old one
  912               if (keyStore.containsAlias(alias)) {
  913                   doDeleteEntry(alias);
  914               }
  915               kssave = true;
  916           } else if (command == KEYPASSWD) {
  917               keyPassNew = newPass;
  918               doChangeKeyPasswd(alias);
  919               kssave = true;
  920           } else if (command == LIST) {
  921               if (alias != null) {
  922                   doPrintEntry(alias, out, true);
  923               } else {
  924                   doPrintEntries(out);
  925               }
  926           } else if (command == PRINTCERT) {
  927               InputStream inStream = System.in;
  928               if (filename != null) {
  929                   inStream = new FileInputStream(filename);
  930               }
  931               try {
  932                   doPrintCert(inStream, out);
  933               } finally {
  934                   if (inStream != System.in) {
  935                       inStream.close();
  936                   }
  937               }
  938           } else if (command == SELFCERT) {
  939               doSelfCert(alias, dname, sigAlgName);
  940               kssave = true;
  941           } else if (command == STOREPASSWD) {
  942               storePassNew = newPass;
  943               if (storePassNew == null) {
  944                   storePassNew = getNewPasswd("keystore password", storePass);
  945               }
  946               kssave = true;
  947           }
  948   
  949           // If we need to save the keystore, do so.
  950           if (kssave) {
  951               if (verbose) {
  952                   MessageFormat form = new MessageFormat
  953                           (rb.getString("[Storing ksfname]"));
  954                   Object[] source = {nullStream ? "keystore" : ksfname};
  955                   System.err.println(form.format(source));
  956               }
  957   
  958               if (token) {
  959                   keyStore.store(null, null);
  960               } else {
  961                   FileOutputStream fout = null;
  962                   try {
  963                       fout = (nullStream ?
  964                                           (FileOutputStream)null :
  965                                           new FileOutputStream(ksfname));
  966                       keyStore.store
  967                           (fout,
  968                           (storePassNew!=null) ? storePassNew : storePass);
  969                   } finally {
  970                       if (fout != null) {
  971                           fout.close();
  972                       }
  973                   }
  974               }
  975           }
  976       }
  977   
  978       /**
  979        * Creates a PKCS#10 cert signing request, corresponding to the
  980        * keys (and name) associated with a given alias.
  981        */
  982       private void doCertReq(String alias, String sigAlgName, PrintStream out)
  983           throws Exception
  984       {
  985           if (alias == null) {
  986               alias = keyAlias;
  987           }
  988   
  989           Object[] objs = recoverKey(alias, storePass, keyPass);
  990           PrivateKey privKey = (PrivateKey)objs[0];
  991           if (keyPass == null) {
  992               keyPass = (char[])objs[1];
  993           }
  994   
  995           Certificate cert = keyStore.getCertificate(alias);
  996           if (cert == null) {
  997               MessageFormat form = new MessageFormat
  998                   (rb.getString("alias has no public key (certificate)"));
  999               Object[] source = {alias};
 1000               throw new Exception(form.format(source));
 1001           }
 1002           PKCS10 request = new PKCS10(cert.getPublicKey());
 1003   
 1004           // Construct an X500Signer object, so that we can sign the request
 1005           if (sigAlgName == null) {
 1006               // If no signature algorithm was specified at the command line,
 1007               // we choose one that is compatible with the selected private key
 1008               String keyAlgName = privKey.getAlgorithm();
 1009               if ("DSA".equalsIgnoreCase(keyAlgName)
 1010                      || "DSS".equalsIgnoreCase(keyAlgName)) {
 1011                   sigAlgName = "SHA1WithDSA";
 1012               } else if ("RSA".equalsIgnoreCase(keyAlgName)) {
 1013                   sigAlgName = "SHA1WithRSA";
 1014               } else {
 1015                   throw new Exception(rb.getString
 1016                           ("Cannot derive signature algorithm"));
 1017               }
 1018           }
 1019   
 1020           Signature signature = Signature.getInstance(sigAlgName);
 1021           signature.initSign(privKey);
 1022           X500Name subject =
 1023               new X500Name(((X509Certificate)cert).getSubjectDN().toString());
 1024           X500Signer signer = new X500Signer(signature, subject);
 1025   
 1026           // Sign the request and base-64 encode it
 1027           request.encodeAndSign(signer);
 1028           request.print(out);
 1029       }
 1030   
 1031       /**
 1032        * Deletes an entry from the keystore.
 1033        */
 1034       private void doDeleteEntry(String alias) throws Exception {
 1035           if (keyStore.containsAlias(alias) == false) {
 1036               MessageFormat form = new MessageFormat
 1037                   (rb.getString("Alias <alias> does not exist"));
 1038               Object[] source = {alias};
 1039               throw new Exception(form.format(source));
 1040           }
 1041           keyStore.deleteEntry(alias);
 1042       }
 1043   
 1044       /**
 1045        * Exports a certificate from the keystore.
 1046        */
 1047       private void doExportCert(String alias, PrintStream out)
 1048           throws Exception
 1049       {
 1050           if (storePass == null
 1051                   && !KeyStoreUtil.isWindowsKeyStore(storetype)) {
 1052               printWarning();
 1053           }
 1054           if (alias == null) {
 1055               alias = keyAlias;
 1056           }
 1057           if (keyStore.containsAlias(alias) == false) {
 1058               MessageFormat form = new MessageFormat
 1059                   (rb.getString("Alias <alias> does not exist"));
 1060               Object[] source = {alias};
 1061               throw new Exception(form.format(source));
 1062           }
 1063   
 1064           X509Certificate cert = (X509Certificate)keyStore.getCertificate(alias);
 1065           if (cert == null) {
 1066               MessageFormat form = new MessageFormat
 1067                   (rb.getString("Alias <alias> has no certificate"));
 1068               Object[] source = {alias};
 1069               throw new Exception(form.format(source));
 1070           }
 1071           dumpCert(cert, out);
 1072       }
 1073   
 1074       /**
 1075        * Prompt the user for a keypass when generating a key entry.
 1076        * @param alias the entry we will set password for
 1077        * @param orig the original entry of doing a dup, null if generate new
 1078        * @param origPass the password to copy from if user press ENTER
 1079        */
 1080       private char[] promptForKeyPass(String alias, String orig, char[] origPass) throws Exception{
 1081           if (P12KEYSTORE.equalsIgnoreCase(storetype)) {
 1082               return origPass;
 1083           } else if (!token) {
 1084               // Prompt for key password
 1085               int count;
 1086               for (count = 0; count < 3; count++) {
 1087                   MessageFormat form = new MessageFormat(rb.getString
 1088                           ("Enter key password for <alias>"));
 1089                   Object[] source = {alias};
 1090                   System.err.println(form.format(source));
 1091                   if (orig == null) {
 1092                       System.err.print(rb.getString
 1093                               ("\t(RETURN if same as keystore password):  "));
 1094                   } else {
 1095                       form = new MessageFormat(rb.getString
 1096                               ("\t(RETURN if same as for <otherAlias>)"));
 1097                       Object[] src = {orig};
 1098                       System.err.print(form.format(src));
 1099                   }
 1100                   System.err.flush();
 1101                   char[] entered = Password.readPassword(System.in);
 1102                   passwords.add(entered);
 1103                   if (entered == null) {
 1104                       return origPass;
 1105                   } else if (entered.length >= 6) {
 1106                       System.err.print(rb.getString("Re-enter new password: "));
 1107                       char[] passAgain = Password.readPassword(System.in);
 1108                       passwords.add(passAgain);
 1109                       if (!Arrays.equals(entered, passAgain)) {
 1110                           System.err.println
 1111                               (rb.getString("They don't match. Try again"));
 1112                           continue;
 1113                       }
 1114                       return entered;
 1115                   } else {
 1116                       System.err.println(rb.getString
 1117                           ("Key password is too short - must be at least 6 characters"));
 1118                   }
 1119               }
 1120               if (count == 3) {
 1121                   if (command == KEYCLONE) {
 1122                       throw new Exception(rb.getString
 1123                           ("Too many failures. Key entry not cloned"));
 1124                   } else {
 1125                       throw new Exception(rb.getString
 1126                               ("Too many failures - key not added to keystore"));
 1127                   }
 1128               }
 1129           }
 1130           return null;    // PKCS11
 1131       }
 1132       /**
 1133        * Creates a new secret key.
 1134        */
 1135       private void doGenSecretKey(String alias, String keyAlgName,
 1136                                 int keysize)
 1137           throws Exception
 1138       {
 1139           if (alias == null) {
 1140               alias = keyAlias;
 1141           }
 1142           if (keyStore.containsAlias(alias)) {
 1143               MessageFormat form = new MessageFormat(rb.getString
 1144                   ("Secret key not generated, alias <alias> already exists"));
 1145               Object[] source = {alias};
 1146               throw new Exception(form.format(source));
 1147           }
 1148   
 1149           SecretKey secKey = null;
 1150           KeyGenerator keygen = KeyGenerator.getInstance(keyAlgName);
 1151           if (keysize != -1) {
 1152               keygen.init(keysize);
 1153           } else if ("DES".equalsIgnoreCase(keyAlgName)) {
 1154               keygen.init(56);
 1155           } else if ("DESede".equalsIgnoreCase(keyAlgName)) {
 1156               keygen.init(168);
 1157           } else {
 1158               throw new Exception(rb.getString
 1159                   ("Please provide -keysize for secret key generation"));
 1160           }
 1161   
 1162           secKey = keygen.generateKey();
 1163           if (keyPass == null) {
 1164               keyPass = promptForKeyPass(alias, null, storePass);
 1165           }
 1166           keyStore.setKeyEntry(alias, secKey, keyPass, null);
 1167       }
 1168   
 1169       /**
 1170        * Creates a new key pair and self-signed certificate.
 1171        */
 1172       private void doGenKeyPair(String alias, String dname, String keyAlgName,
 1173                                 int keysize, String sigAlgName)
 1174           throws Exception
 1175       {
 1176           if (keysize == -1) {
 1177               if ("EC".equalsIgnoreCase(keyAlgName)) {
 1178                   keysize = 256;
 1179               } else {
 1180                   keysize = 1024;
 1181               }
 1182           }
 1183   
 1184           if (alias == null) {
 1185               alias = keyAlias;
 1186           }
 1187   
 1188           if (keyStore.containsAlias(alias)) {
 1189               MessageFormat form = new MessageFormat(rb.getString
 1190                   ("Key pair not generated, alias <alias> already exists"));
 1191               Object[] source = {alias};
 1192               throw new Exception(form.format(source));
 1193           }
 1194   
 1195           if (sigAlgName == null) {
 1196               if ("DSA".equalsIgnoreCase(keyAlgName)) {
 1197                   sigAlgName = "SHA1WithDSA";
 1198               } else if ("RSA".equalsIgnoreCase(keyAlgName)) {
 1199                   sigAlgName = "SHA1WithRSA";
 1200               } else if ("EC".equalsIgnoreCase(keyAlgName)) {
 1201                   sigAlgName = "SHA1withECDSA";
 1202               } else {
 1203                   throw new Exception(rb.getString
 1204                           ("Cannot derive signature algorithm"));
 1205               }
 1206           }
 1207           CertAndKeyGen keypair =
 1208                   new CertAndKeyGen(keyAlgName, sigAlgName, providerName);
 1209   
 1210   
 1211           // If DN is provided, parse it. Otherwise, prompt the user for it.
 1212           X500Name x500Name;
 1213           if (dname == null) {
 1214               x500Name = getX500Name();
 1215           } else {
 1216               x500Name = new X500Name(dname);
 1217           }
 1218   
 1219           keypair.generate(keysize);
 1220           PrivateKey privKey = keypair.getPrivateKey();
 1221   
 1222           X509Certificate[] chain = new X509Certificate[1];
 1223           chain[0] = keypair.getSelfCertificate(
 1224                   x500Name, getStartDate(startDate), validity*24L*60L*60L);
 1225   
 1226           if (verbose) {
 1227               MessageFormat form = new MessageFormat(rb.getString
 1228                   ("Generating keysize bit keyAlgName key pair and self-signed certificate " +
 1229                       "(sigAlgName) with a validity of validality days\n\tfor: x500Name"));
 1230               Object[] source = {new Integer(keysize),
 1231                                   privKey.getAlgorithm(),
 1232                                   chain[0].getSigAlgName(),
 1233                                   new Long(validity),
 1234                                   x500Name};
 1235               System.err.println(form.format(source));
 1236           }
 1237   
 1238           if (keyPass == null) {
 1239               keyPass = promptForKeyPass(alias, null, storePass);
 1240           }
 1241           keyStore.setKeyEntry(alias, privKey, keyPass, chain);
 1242       }
 1243   
 1244       /**
 1245        * Clones an entry
 1246        * @param orig original alias
 1247        * @param dest destination alias
 1248        * @changePassword if the password can be changed
 1249        */
 1250       private void doCloneEntry(String orig, String dest, boolean changePassword)
 1251           throws Exception
 1252       {
 1253           if (orig == null) {
 1254               orig = keyAlias;
 1255           }
 1256   
 1257           if (keyStore.containsAlias(dest)) {
 1258               MessageFormat form = new MessageFormat
 1259                   (rb.getString("Destination alias <dest> already exists"));
 1260               Object[] source = {dest};
 1261               throw new Exception(form.format(source));
 1262           }
 1263   
 1264           Object[] objs = recoverEntry(keyStore, orig, storePass, keyPass);
 1265           Entry entry = (Entry)objs[0];
 1266           keyPass = (char[])objs[1];
 1267   
 1268           PasswordProtection pp = null;
 1269   
 1270           if (keyPass != null) {  // protected
 1271               if (!changePassword || P12KEYSTORE.equalsIgnoreCase(storetype)) {
 1272                   keyPassNew = keyPass;
 1273               } else {
 1274                   if (keyPassNew == null) {
 1275                       keyPassNew = promptForKeyPass(dest, orig, keyPass);
 1276                   }
 1277               }
 1278               pp = new PasswordProtection(keyPassNew);
 1279           }
 1280           keyStore.setEntry(dest, entry, pp);
 1281       }
 1282   
 1283       /**
 1284        * Changes a key password.
 1285        */
 1286       private void doChangeKeyPasswd(String alias) throws Exception
 1287       {
 1288   
 1289           if (alias == null) {
 1290               alias = keyAlias;
 1291           }
 1292           Object[] objs = recoverKey(alias, storePass, keyPass);
 1293           Key privKey = (Key)objs[0];
 1294           if (keyPass == null) {
 1295               keyPass = (char[])objs[1];
 1296           }
 1297   
 1298           if (keyPassNew == null) {
 1299               MessageFormat form = new MessageFormat
 1300                   (rb.getString("key password for <alias>"));
 1301               Object[] source = {alias};
 1302               keyPassNew = getNewPasswd(form.format(source), keyPass);
 1303           }
 1304           keyStore.setKeyEntry(alias, privKey, keyPassNew,
 1305                                keyStore.getCertificateChain(alias));
 1306       }
 1307   
 1308       /**
 1309        * Imports a JDK 1.1-style identity database. We can only store one
 1310        * certificate per identity, because we use the identity's name as the
 1311        * alias (which references a keystore entry), and aliases must be unique.
 1312        */
 1313       private void doImportIdentityDatabase(InputStream in)
 1314           throws Exception
 1315       {
 1316           byte[] encoded;
 1317           ByteArrayInputStream bais;
 1318           java.security.cert.X509Certificate newCert;
 1319           java.security.cert.Certificate[] chain = null;
 1320           PrivateKey privKey;
 1321           boolean modified = false;
 1322   
 1323           IdentityDatabase idb = IdentityDatabase.fromStream(in);
 1324           for (Enumeration<Identity> enum_ = idb.identities();
 1325                                           enum_.hasMoreElements();) {
 1326               Identity id = enum_.nextElement();
 1327               newCert = null;
 1328               // only store trusted identities in keystore
 1329               if ((id instanceof SystemSigner && ((SystemSigner)id).isTrusted())
 1330                   || (id instanceof SystemIdentity
 1331                       && ((SystemIdentity)id).isTrusted())) {
 1332                   // ignore if keystore entry with same alias name already exists
 1333                   if (keyStore.containsAlias(id.getName())) {
 1334                       MessageFormat form = new MessageFormat
 1335                           (rb.getString("Keystore entry for <id.getName()> already exists"));
 1336                       Object[] source = {id.getName()};
 1337                       System.err.println(form.format(source));
 1338                       continue;
 1339                   }
 1340                   java.security.Certificate[] certs = id.certificates();
 1341                   if (certs!=null && certs.length>0) {
 1342                       // we can only store one user cert per identity.
 1343                       // convert old-style to new-style cert via the encoding
 1344                       DerOutputStream dos = new DerOutputStream();
 1345                       certs[0].encode(dos);
 1346                       encoded = dos.toByteArray();
 1347                       bais = new ByteArrayInputStream(encoded);
 1348                       newCert = (X509Certificate)cf.generateCertificate(bais);
 1349                       bais.close();
 1350   
 1351                       // if certificate is self-signed, make sure it verifies
 1352                       if (isSelfSigned(newCert)) {
 1353                           PublicKey pubKey = newCert.getPublicKey();
 1354                           try {
 1355                               newCert.verify(pubKey);
 1356                           } catch (Exception e) {
 1357                               // ignore this cert
 1358                               continue;
 1359                           }
 1360                       }
 1361   
 1362                       if (id instanceof SystemSigner) {
 1363                           MessageFormat form = new MessageFormat(rb.getString
 1364                               ("Creating keystore entry for <id.getName()> ..."));
 1365                           Object[] source = {id.getName()};
 1366                           System.err.println(form.format(source));
 1367                           if (chain==null) {
 1368                               chain = new java.security.cert.Certificate[1];
 1369                           }
 1370                           chain[0] = newCert;
 1371                           privKey = ((SystemSigner)id).getPrivateKey();
 1372                           keyStore.setKeyEntry(id.getName(), privKey, storePass,
 1373                                                chain);
 1374                       } else {
 1375                           keyStore.setCertificateEntry(id.getName(), newCert);
 1376                       }
 1377                       kssave = true;
 1378                   }
 1379               }
 1380           }
 1381           if (!kssave) {
 1382               System.err.println(rb.getString
 1383                   ("No entries from identity database added"));
 1384           }
 1385       }
 1386   
 1387       /**
 1388        * Prints a single keystore entry.
 1389        */
 1390       private void doPrintEntry(String alias, PrintStream out,
 1391                                 boolean printWarning)
 1392           throws Exception
 1393       {
 1394           if (storePass == null && printWarning
 1395                   && !KeyStoreUtil.isWindowsKeyStore(storetype)) {
 1396               printWarning();
 1397           }
 1398   
 1399           if (keyStore.containsAlias(alias) == false) {
 1400               MessageFormat form = new MessageFormat
 1401                   (rb.getString("Alias <alias> does not exist"));
 1402               Object[] source = {alias};
 1403               throw new Exception(form.format(source));
 1404           }
 1405   
 1406           if (verbose || rfc || debug) {
 1407               MessageFormat form = new MessageFormat
 1408                   (rb.getString("Alias name: alias"));
 1409               Object[] source = {alias};
 1410               out.println(form.format(source));
 1411   
 1412               if (!token) {
 1413                   form = new MessageFormat(rb.getString
 1414                       ("Creation date: keyStore.getCreationDate(alias)"));
 1415                   Object[] src = {keyStore.getCreationDate(alias)};
 1416                   out.println(form.format(src));
 1417               }
 1418           } else {
 1419               if (!token) {
 1420                   MessageFormat form = new MessageFormat
 1421                       (rb.getString("alias, keyStore.getCreationDate(alias), "));
 1422                   Object[] source = {alias, keyStore.getCreationDate(alias)};
 1423                   out.print(form.format(source));
 1424               } else {
 1425                   MessageFormat form = new MessageFormat
 1426                       (rb.getString("alias, "));
 1427                   Object[] source = {alias};
 1428                   out.print(form.format(source));
 1429               }
 1430           }
 1431   
 1432           if (keyStore.entryInstanceOf(alias, KeyStore.SecretKeyEntry.class)) {
 1433               if (verbose || rfc || debug) {
 1434                   Object[] source = {"SecretKeyEntry"};
 1435                   out.println(new MessageFormat(
 1436                           rb.getString("Entry type: <type>")).format(source));
 1437               } else {
 1438                   out.println("SecretKeyEntry, ");
 1439               }
 1440           } else if (keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class)) {
 1441               if (verbose || rfc || debug) {
 1442                   Object[] source = {"PrivateKeyEntry"};
 1443                   out.println(new MessageFormat(
 1444                           rb.getString("Entry type: <type>")).format(source));
 1445               } else {
 1446                   out.println("PrivateKeyEntry, ");
 1447               }
 1448   
 1449               // Get the chain
 1450               Certificate[] chain = keyStore.getCertificateChain(alias);
 1451               if (chain != null) {
 1452                   if (verbose || rfc || debug) {
 1453                       out.println(rb.getString
 1454                           ("Certificate chain length: ") + chain.length);
 1455                       for (int i = 0; i < chain.length; i ++) {
 1456                           MessageFormat form = new MessageFormat
 1457                                   (rb.getString("Certificate[(i + 1)]:"));
 1458                           Object[] source = {new Integer((i + 1))};
 1459                           out.println(form.format(source));
 1460                           if (verbose && (chain[i] instanceof X509Certificate)) {
 1461                               printX509Cert((X509Certificate)(chain[i]), out);
 1462                           } else if (debug) {
 1463                               out.println(chain[i].toString());
 1464                           } else {
 1465                               dumpCert(chain[i], out);
 1466                           }
 1467                       }
 1468                   } else {
 1469                       // Print the digest of the user cert only
 1470                       out.println
 1471                           (rb.getString("Certificate fingerprint (MD5): ") +
 1472                           getCertFingerPrint("MD5", chain[0]));
 1473                   }
 1474               }
 1475           } else if (keyStore.entryInstanceOf(alias,
 1476                   KeyStore.TrustedCertificateEntry.class)) {
 1477               // We have a trusted certificate entry
 1478               Certificate cert = keyStore.getCertificate(alias);
 1479               if (verbose && (cert instanceof X509Certificate)) {
 1480                   out.println(rb.getString("Entry type: trustedCertEntry\n"));
 1481                   printX509Cert((X509Certificate)cert, out);
 1482               } else if (rfc) {
 1483                   out.println(rb.getString("Entry type: trustedCertEntry\n"));
 1484                   dumpCert(cert, out);
 1485               } else if (debug) {
 1486                   out.println(cert.toString());
 1487               } else {
 1488                   out.println(rb.getString("trustedCertEntry,"));
 1489                   out.println(rb.getString("Certificate fingerprint (MD5): ")
 1490                               + getCertFingerPrint("MD5", cert));
 1491               }
 1492           } else {
 1493               out.println(rb.getString("Unknown Entry Type"));
 1494           }
 1495       }
 1496   
 1497       /**
 1498        * Load the srckeystore from a stream, used in -importkeystore
 1499        * @returns the src KeyStore
 1500        */
 1501       KeyStore loadSourceKeyStore() throws Exception {
 1502           boolean isPkcs11 = false;
 1503   
 1504           InputStream is = null;
 1505   
 1506           if (P11KEYSTORE.equalsIgnoreCase(srcstoretype) ||
 1507                   KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
 1508               if (!NONE.equals(srcksfname)) {
 1509                   System.err.println(MessageFormat.format(rb.getString
 1510                       ("-keystore must be NONE if -storetype is {0}"), srcstoretype));
 1511                   System.err.println();
 1512                   tinyHelp();
 1513               }
 1514               isPkcs11 = true;
 1515           } else {
 1516               if (srcksfname != null) {
 1517                   File srcksfile = new File(srcksfname);
 1518                       if (srcksfile.exists() && srcksfile.length() == 0) {
 1519                           throw new Exception(rb.getString
 1520                                   ("Source keystore file exists, but is empty: ") +
 1521                                   srcksfname);
 1522                   }
 1523                   is = new FileInputStream(srcksfile);
 1524               } else {
 1525                   throw new Exception(rb.getString
 1526                           ("Please specify -srckeystore"));
 1527               }
 1528           }
 1529   
 1530           KeyStore store;
 1531           try {
 1532               if (srcProviderName == null) {
 1533                   store = KeyStore.getInstance(srcstoretype);
 1534               } else {
 1535                   store = KeyStore.getInstance(srcstoretype, srcProviderName);
 1536               }
 1537   
 1538               if (srcstorePass == null
 1539                       && !srcprotectedPath
 1540                       && !KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
 1541                   System.err.print(rb.getString("Enter source keystore password:  "));
 1542                   System.err.flush();
 1543                   srcstorePass = Password.readPassword(System.in);
 1544                   passwords.add(srcstorePass);
 1545               }
 1546   
 1547               // always let keypass be storepass when using pkcs12
 1548               if (P12KEYSTORE.equalsIgnoreCase(srcstoretype)) {
 1549                   if (srckeyPass != null && srcstorePass != null &&
 1550                           !Arrays.equals(srcstorePass, srckeyPass)) {
 1551                       MessageFormat form = new MessageFormat(rb.getString(
 1552                           "Warning:  Different store and key passwords not supported " +
 1553                           "for PKCS12 KeyStores. Ignoring user-specified <command> value."));
 1554                       Object[] source = {"-srckeypass"};
 1555                       System.err.println(form.format(source));
 1556                       srckeyPass = srcstorePass;
 1557                   }
 1558               }
 1559   
 1560               store.load(is, srcstorePass);   // "is" already null in PKCS11
 1561           } finally {
 1562               if (is != null) {
 1563                   is.close();
 1564               }
 1565           }
 1566   
 1567           if (srcstorePass == null
 1568                   && !KeyStoreUtil.isWindowsKeyStore(srcstoretype)) {
 1569               // anti refactoring, copied from printWarning(),
 1570               // but change 2 lines
 1571               System.err.println();
 1572               System.err.println(rb.getString
 1573                   ("*****************  WARNING WARNING WARNING  *****************"));
 1574               System.err.println(rb.getString
 1575                   ("* The integrity of the information stored in the srckeystore*"));
 1576               System.err.println(rb.getString
 1577                   ("* has NOT been verified!  In order to verify its integrity, *"));
 1578               System.err.println(rb.getString
 1579                   ("* you must provide the srckeystore password.                *"));
 1580               System.err.println(rb.getString
 1581                   ("*****************  WARNING WARNING WARNING  *****************"));
 1582               System.err.println();
 1583           }
 1584   
 1585           return store;
 1586       }
 1587   
 1588       /**
 1589        * import all keys and certs from importkeystore.
 1590        * keep alias unchanged if no name conflict, otherwise, prompt.
 1591        * keep keypass unchanged for keys
 1592        */
 1593       private void doImportKeyStore() throws Exception {
 1594   
 1595           if (alias != null) {
 1596               doImportKeyStoreSingle(loadSourceKeyStore(), alias);
 1597           } else {
 1598               if (dest != null || srckeyPass != null || destKeyPass != null) {
 1599                   throw new Exception(rb.getString(
 1600                           "if alias not specified, destalias, srckeypass, " +
 1601                           "and destkeypass must not be specified"));
 1602               }
 1603               doImportKeyStoreAll(loadSourceKeyStore());
 1604           }
 1605           /*
 1606            * Information display rule of -importkeystore
 1607            * 1. inside single, shows failure
 1608            * 2. inside all, shows sucess
 1609            * 3. inside all where there is a failure, prompt for continue
 1610            * 4. at the final of all, shows summary
 1611            */
 1612       }
 1613   
 1614       /**
 1615        * Import a single entry named alias from srckeystore
 1616        * @returns 1 if the import action succeed
 1617        *          0 if user choose to ignore an alias-dumplicated entry
 1618        *          2 if setEntry throws Exception
 1619        */
 1620       private int doImportKeyStoreSingle(KeyStore srckeystore, String alias)
 1621               throws Exception {
 1622   
 1623           String newAlias = (dest==null) ? alias : dest;
 1624   
 1625           if (keyStore.containsAlias(newAlias)) {
 1626               Object[] source = {alias};
 1627               if (noprompt) {
 1628                   System.err.println(new MessageFormat(rb.getString(
 1629                           "Warning: Overwriting existing alias <alias> in destination keystore")).format(source));
 1630               } else {
 1631                   String reply = getYesNoReply(new MessageFormat(rb.getString(
 1632                           "Existing entry alias <alias> exists, overwrite? [no]:  ")).format(source));
 1633                   if ("NO".equals(reply)) {
 1634                       newAlias = inputStringFromStdin(rb.getString
 1635                               ("Enter new alias name\t(RETURN to cancel import for this entry):  "));
 1636                       if ("".equals(newAlias)) {
 1637                           System.err.println(new MessageFormat(rb.getString(
 1638                                   "Entry for alias <alias> not imported.")).format(
 1639                                   source));
 1640                           return 0;
 1641                       }
 1642                   }
 1643               }
 1644           }
 1645   
 1646           Object[] objs = recoverEntry(srckeystore, alias, srcstorePass, srckeyPass);
 1647           Entry entry = (Entry)objs[0];
 1648   
 1649           PasswordProtection pp = null;
 1650   
 1651           // According to keytool.html, "The destination entry will be protected
 1652           // using destkeypass. If destkeypass is not provided, the destination
 1653           // entry will be protected with the source entry password."
 1654           // so always try to protect with destKeyPass.
 1655           if (destKeyPass != null) {
 1656               pp = new PasswordProtection(destKeyPass);
 1657           } else if (objs[1] != null) {
 1658               pp = new PasswordProtection((char[])objs[1]);
 1659           }
 1660   
 1661           try {
 1662               keyStore.setEntry(newAlias, entry, pp);
 1663               return 1;
 1664           } catch (KeyStoreException kse) {
 1665               Object[] source2 = {alias, kse.toString()};
 1666               MessageFormat form = new MessageFormat(rb.getString(
 1667                       "Problem importing entry for alias <alias>: <exception>.\nEntry for alias <alias> not imported."));
 1668               System.err.println(form.format(source2));
 1669               return 2;
 1670           }
 1671       }
 1672   
 1673       private void doImportKeyStoreAll(KeyStore srckeystore) throws Exception {
 1674   
 1675           int ok = 0;
 1676           int count = srckeystore.size();
 1677           for (Enumeration<String> e = srckeystore.aliases();
 1678                                           e.hasMoreElements(); ) {
 1679               String alias = e.nextElement();
 1680               int result = doImportKeyStoreSingle(srckeystore, alias);
 1681               if (result == 1) {
 1682                   ok++;
 1683                   Object[] source = {alias};
 1684                   MessageFormat form = new MessageFormat(rb.getString("Entry for alias <alias> successfully imported."));
 1685                   System.err.println(form.format(source));
 1686               } else if (result == 2) {
 1687                   if (!noprompt) {
 1688                       String reply = getYesNoReply("Do you want to quit the import process? [no]:  ");
 1689                       if ("YES".equals(reply)) {
 1690                           break;
 1691                       }
 1692                   }
 1693               }
 1694           }
 1695           Object[] source = {ok, count-ok};
 1696           MessageFormat form = new MessageFormat(rb.getString(
 1697                   "Import command completed:  <ok> entries successfully imported, <fail> entries failed or cancelled"));
 1698           System.err.println(form.format(source));
 1699       }
 1700   
 1701       /**
 1702        * Prints all keystore entries.
 1703        */
 1704       private void doPrintEntries(PrintStream out)
 1705           throws Exception
 1706       {
 1707           if (storePass == null
 1708                   && !KeyStoreUtil.isWindowsKeyStore(storetype)) {
 1709               printWarning();
 1710           } else {
 1711               out.println();
 1712           }
 1713   
 1714           out.println(rb.getString("Keystore type: ") + keyStore.getType());
 1715           out.println(rb.getString("Keystore provider: ") +
 1716                   keyStore.getProvider().getName());
 1717           out.println();
 1718   
 1719           MessageFormat form;
 1720           form = (keyStore.size() == 1) ?
 1721                   new MessageFormat(rb.getString
 1722                           ("Your keystore contains keyStore.size() entry")) :
 1723                   new MessageFormat(rb.getString
 1724                           ("Your keystore contains keyStore.size() entries"));
 1725           Object[] source = {new Integer(keyStore.size())};
 1726           out.println(form.format(source));
 1727           out.println();
 1728   
 1729           for (Enumeration<String> e = keyStore.aliases();
 1730                                           e.hasMoreElements(); ) {
 1731               String alias = e.nextElement();
 1732               doPrintEntry(alias, out, false);
 1733               if (verbose || rfc) {
 1734                   out.println(rb.getString("\n"));
 1735                   out.println(rb.getString
 1736                           ("*******************************************"));
 1737                   out.println(rb.getString
 1738                           ("*******************************************\n\n"));
 1739               }
 1740           }
 1741       }
 1742   
 1743       /**
 1744        * Reads a certificate (or certificate chain) and prints its contents in
 1745        * a human readbable format.
 1746        */
 1747       private void doPrintCert(InputStream in, PrintStream out)
 1748           throws Exception
 1749       {
 1750           Collection<? extends Certificate> c = null;
 1751           try {
 1752               c = cf.generateCertificates(in);
 1753           } catch (CertificateException ce) {
 1754               throw new Exception(rb.getString("Failed to parse input"), ce);
 1755           }
 1756           if (c.isEmpty()) {
 1757               throw new Exception(rb.getString("Empty input"));
 1758           }
 1759           Certificate[] certs = c.toArray(new Certificate[c.size()]);
 1760           for (int i=0; i<certs.length; i++) {
 1761               X509Certificate x509Cert = null;
 1762               try {
 1763                   x509Cert = (X509Certificate)certs[i];
 1764               } catch (ClassCastException cce) {
 1765                   throw new Exception(rb.getString("Not X.509 certificate"));
 1766               }
 1767               if (certs.length > 1) {
 1768                   MessageFormat form = new MessageFormat
 1769                           (rb.getString("Certificate[(i + 1)]:"));
 1770                   Object[] source = {new Integer(i + 1)};
 1771                   out.println(form.format(source));
 1772               }
 1773               printX509Cert(x509Cert, out);
 1774               if (i < (certs.length-1)) {
 1775                   out.println();
 1776               }
 1777           }
 1778       }
 1779   
 1780       /**
 1781        * Creates a self-signed certificate, and stores it as a single-element
 1782        * certificate chain.
 1783        */
 1784       private void doSelfCert(String alias, String dname, String sigAlgName)
 1785           throws Exception
 1786       {
 1787           if (alias == null) {
 1788               alias = keyAlias;
 1789           }
 1790   
 1791           Object[] objs = recoverKey(alias, storePass, keyPass);
 1792           PrivateKey privKey = (PrivateKey)objs[0];
 1793           if (keyPass == null)
 1794               keyPass = (char[])objs[1];
 1795   
 1796           // Determine the signature algorithm
 1797           if (sigAlgName == null) {
 1798               // If no signature algorithm was specified at the command line,
 1799               // we choose one that is compatible with the selected private key
 1800               String keyAlgName = privKey.getAlgorithm();
 1801               if ("DSA".equalsIgnoreCase(keyAlgName)
 1802                      || "DSS".equalsIgnoreCase(keyAlgName)) {
 1803                   sigAlgName = "SHA1WithDSA";
 1804               } else if ("RSA".equalsIgnoreCase(keyAlgName)) {
 1805                   sigAlgName = "SHA1WithRSA";
 1806               } else if ("EC".equalsIgnoreCase(keyAlgName)) {
 1807                   sigAlgName = "SHA1withECDSA";
 1808               } else {
 1809                   throw new Exception
 1810                           (rb.getString("Cannot derive signature algorithm"));
 1811               }
 1812           }
 1813   
 1814           // Get the old certificate
 1815           Certificate oldCert = keyStore.getCertificate(alias);
 1816           if (oldCert == null) {
 1817               MessageFormat form = new MessageFormat
 1818                   (rb.getString("alias has no public key"));
 1819               Object[] source = {alias};
 1820               throw new Exception(form.format(source));
 1821           }
 1822           if (!(oldCert instanceof X509Certificate)) {
 1823               MessageFormat form = new MessageFormat
 1824                   (rb.getString("alias has no X.509 certificate"));
 1825               Object[] source = {alias};
 1826               throw new Exception(form.format(source));
 1827           }
 1828   
 1829           // convert to X509CertImpl, so that we can modify selected fields
 1830           // (no public APIs available yet)
 1831           byte[] encoded = oldCert.getEncoded();
 1832           X509CertImpl certImpl = new X509CertImpl(encoded);
 1833           X509CertInfo certInfo = (X509CertInfo)certImpl.get(X509CertImpl.NAME
 1834                                                              + "." +
 1835                                                              X509CertImpl.INFO);
 1836   
 1837           // Extend its validity
 1838           Date firstDate = getStartDate(startDate);
 1839           Date lastDate = new Date();
 1840           lastDate.setTime(firstDate.getTime() + validity*1000L*24L*60L*60L);
 1841           CertificateValidity interval = new CertificateValidity(firstDate,
 1842                                                                  lastDate);
 1843           certInfo.set(X509CertInfo.VALIDITY, interval);
 1844   
 1845           // Make new serial number
 1846           certInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber
 1847                        ((int)(firstDate.getTime()/1000)));
 1848   
 1849           // Set owner and issuer fields
 1850           X500Name owner;
 1851           if (dname == null) {
 1852               // Get the owner name from the certificate
 1853               owner = (X500Name)certInfo.get(X509CertInfo.SUBJECT + "." +
 1854                                              CertificateSubjectName.DN_NAME);
 1855           } else {
 1856               // Use the owner name specified at the command line
 1857               owner = new X500Name(dname);
 1858               certInfo.set(X509CertInfo.SUBJECT + "." +
 1859                            CertificateSubjectName.DN_NAME, owner);
 1860           }
 1861           // Make issuer same as owner (self-signed!)
 1862           certInfo.set(X509CertInfo.ISSUER + "." +
 1863                        CertificateIssuerName.DN_NAME, owner);
 1864   
 1865           // The inner and outer signature algorithms have to match.
 1866           // The way we achieve that is really ugly, but there seems to be no
 1867           // other solution: We first sign the cert, then retrieve the
 1868           // outer sigalg and use it to set the inner sigalg
 1869           X509CertImpl newCert = new X509CertImpl(certInfo);
 1870           newCert.sign(privKey, sigAlgName);
 1871           AlgorithmId sigAlgid = (AlgorithmId)newCert.get(X509CertImpl.SIG_ALG);
 1872           certInfo.set(CertificateAlgorithmId.NAME + "." +
 1873                        CertificateAlgorithmId.ALGORITHM, sigAlgid);
 1874   
 1875           // first upgrade to version 3
 1876   
 1877           certInfo.set(X509CertInfo.VERSION,
 1878                           new CertificateVersion(CertificateVersion.V3));
 1879   
 1880           // Sign the new certificate
 1881           newCert = new X509CertImpl(certInfo);
 1882           newCert.sign(privKey, sigAlgName);
 1883   
 1884           // Store the new certificate as a single-element certificate chain
 1885           keyStore.setKeyEntry(alias, privKey,
 1886                                (keyPass != null) ? keyPass : storePass,
 1887                                new Certificate[] { newCert } );
 1888   
 1889           if (verbose) {
 1890               System.err.println(rb.getString("New certificate (self-signed):"));
 1891               System.err.print(newCert.toString());
 1892               System.err.println();
 1893           }
 1894       }
 1895   
 1896       /**
 1897        * Processes a certificate reply from a certificate authority.
 1898        *
 1899        * <p>Builds a certificate chain on top of the certificate reply,
 1900        * using trusted certificates from the keystore. The chain is complete
 1901        * after a self-signed certificate has been encountered. The self-signed
 1902        * certificate is considered a root certificate authority, and is stored
 1903        * at the end of the chain.
 1904        *
 1905        * <p>The newly generated chain replaces the old chain associated with the
 1906        * key entry.
 1907        *
 1908        * @return true if the certificate reply was installed, otherwise false.
 1909        */
 1910       private boolean installReply(String alias, InputStream in)
 1911           throws Exception
 1912       {
 1913           if (alias == null) {
 1914               alias = keyAlias;
 1915           }
 1916   
 1917           Object[] objs = recoverKey(alias, storePass, keyPass);
 1918           PrivateKey privKey = (PrivateKey)objs[0];
 1919           if (keyPass == null) {
 1920               keyPass = (char[])objs[1];
 1921           }
 1922   
 1923           Certificate userCert = keyStore.getCertificate(alias);
 1924           if (userCert == null) {
 1925               MessageFormat form = new MessageFormat
 1926                   (rb.getString("alias has no public key (certificate)"));
 1927               Object[] source = {alias};
 1928               throw new Exception(form.format(source));
 1929           }
 1930   
 1931           // Read the certificates in the reply
 1932           Collection<? extends Certificate> c = cf.generateCertificates(in);
 1933           if (c.isEmpty()) {
 1934               throw new Exception(rb.getString("Reply has no certificates"));
 1935           }
 1936           Certificate[] replyCerts = c.toArray(new Certificate[c.size()]);
 1937           Certificate[] newChain;
 1938           if (replyCerts.length == 1) {
 1939               // single-cert reply
 1940               newChain = establishCertChain(userCert, replyCerts[0]);
 1941           } else {
 1942               // cert-chain reply (e.g., PKCS#7)
 1943               newChain = validateReply(alias, userCert, replyCerts);
 1944           }
 1945   
 1946           // Now store the newly established chain in the keystore. The new
 1947           // chain replaces the old one.
 1948           if (newChain != null) {
 1949               keyStore.setKeyEntry(alias, privKey,
 1950                                    (keyPass != null) ? keyPass : storePass,
 1951                                    newChain);
 1952               return true;
 1953           } else {
 1954               return false;
 1955           }
 1956       }
 1957   
 1958       /**
 1959        * Imports a certificate and adds it to the list of trusted certificates.
 1960        *
 1961        * @return true if the certificate was added, otherwise false.
 1962        */
 1963       private boolean addTrustedCert(String alias, InputStream in)
 1964           throws Exception
 1965       {
 1966           if (alias == null) {
 1967               throw new Exception(rb.getString("Must specify alias"));
 1968           }
 1969           if (keyStore.containsAlias(alias)) {
 1970               MessageFormat form = new MessageFormat(rb.getString
 1971                   ("Certificate not imported, alias <alias> already exists"));
 1972               Object[] source = {alias};
 1973               throw new Exception(form.format(source));
 1974           }
 1975   
 1976           // Read the certificate
 1977           X509Certificate cert = null;
 1978           try {
 1979               cert = (X509Certificate)cf.generateCertificate(in);
 1980           } catch (ClassCastException cce) {
 1981               throw new Exception(rb.getString("Input not an X.509 certificate"));
 1982           } catch (CertificateException ce) {
 1983               throw new Exception(rb.getString("Input not an X.509 certificate"));
 1984           }
 1985   
 1986           // if certificate is self-signed, make sure it verifies
 1987           boolean selfSigned = false;
 1988           if (isSelfSigned(cert)) {
 1989               cert.verify(cert.getPublicKey());
 1990               selfSigned = true;
 1991           }
 1992   
 1993           if (noprompt) {
 1994               keyStore.setCertificateEntry(alias, cert);
 1995               return true;
 1996           }
 1997   
 1998           // check if cert already exists in keystore
 1999           String reply = null;
 2000           String trustalias = keyStore.getCertificateAlias(cert);
 2001           if (trustalias != null) {
 2002               MessageFormat form = new MessageFormat(rb.getString
 2003                   ("Certificate already exists in keystore under alias <trustalias>"));
 2004               Object[] source = {trustalias};
 2005               System.err.println(form.format(source));
 2006               reply = getYesNoReply
 2007                   (rb.getString("Do you still want to add it? [no]:  "));
 2008           } else if (selfSigned) {
 2009               if (trustcacerts && (caks != null) &&
 2010                       ((trustalias=caks.getCertificateAlias(cert)) != null)) {
 2011                   MessageFormat form = new MessageFormat(rb.getString
 2012                           ("Certificate already exists in system-wide CA keystore under alias <trustalias>"));
 2013                   Object[] source = {trustalias};
 2014                   System.err.println(form.format(source));
 2015                   reply = getYesNoReply
 2016                           (rb.getString("Do you still want to add it to your own keystore? [no]:  "));
 2017               }
 2018               if (trustalias == null) {
 2019                   // Print the cert and ask user if they really want to add
 2020                   // it to their keystore
 2021                   printX509Cert(cert, System.out);
 2022                   reply = getYesNoReply
 2023                           (rb.getString("Trust this certificate? [no]:  "));
 2024               }
 2025           }
 2026           if (reply != null) {
 2027               if ("YES".equals(reply)) {
 2028                   keyStore.setCertificateEntry(alias, cert);
 2029                   return true;
 2030               } else {
 2031                   return false;
 2032               }
 2033           }
 2034   
 2035           // Try to establish trust chain
 2036           try {
 2037               Certificate[] chain = establishCertChain(null, cert);
 2038               if (chain != null) {
 2039                   keyStore.setCertificateEntry(alias, cert);
 2040                   return true;
 2041               }
 2042           } catch (Exception e) {
 2043               // Print the cert and ask user if they really want to add it to
 2044               // their keystore
 2045               printX509Cert(cert, System.out);
 2046               reply = getYesNoReply
 2047                   (rb.getString("Trust this certificate? [no]:  "));
 2048               if ("YES".equals(reply)) {
 2049                   keyStore.setCertificateEntry(alias, cert);
 2050                   return true;
 2051               } else {
 2052                   return false;
 2053               }
 2054           }
 2055   
 2056           return false;
 2057       }
 2058   
 2059       /**
 2060        * Prompts user for new password. New password must be different from
 2061        * old one.
 2062        *
 2063        * @param prompt the message that gets prompted on the screen
 2064        * @param oldPasswd the current (i.e., old) password
 2065        */
 2066       private char[] getNewPasswd(String prompt, char[] oldPasswd)
 2067           throws Exception
 2068       {
 2069           char[] entered = null;
 2070           char[] reentered = null;
 2071   
 2072           for (int count = 0; count < 3; count++) {
 2073               MessageFormat form = new MessageFormat
 2074                   (rb.getString("New prompt: "));
 2075               Object[] source = {prompt};
 2076               System.err.print(form.format(source));
 2077               entered = Password.readPassword(System.in);
 2078               passwords.add(entered);
 2079               if (entered == null || entered.length < 6) {
 2080                   System.err.println(rb.getString
 2081                       ("Password is too short - must be at least 6 characters"));
 2082               } else if (Arrays.equals(entered, oldPasswd)) {
 2083                   System.err.println(rb.getString("Passwords must differ"));
 2084               } else {
 2085                   form = new MessageFormat
 2086                           (rb.getString("Re-enter new prompt: "));
 2087                   Object[] src = {prompt};
 2088                   System.err.print(form.format(src));
 2089                   reentered = Password.readPassword(System.in);
 2090                   passwords.add(reentered);
 2091                   if (!Arrays.equals(entered, reentered)) {
 2092                       System.err.println
 2093                           (rb.getString("They don't match. Try again"));
 2094                   } else {
 2095                       Arrays.fill(reentered, ' ');
 2096                       return entered;
 2097                   }
 2098               }
 2099               if (entered != null) {
 2100                   Arrays.fill(entered, ' ');
 2101                   entered = null;
 2102               }
 2103               if (reentered != null) {
 2104                   Arrays.fill(reentered, ' ');
 2105                   reentered = null;
 2106               }
 2107           }
 2108           throw new Exception(rb.getString("Too many failures - try later"));
 2109       }
 2110   
 2111       /**
 2112        * Prompts user for alias name.
 2113        * @param prompt the {0} of "Enter {0} alias name:  " in prompt line
 2114        * @returns the string entered by the user, without the \n at the end
 2115        */
 2116       private String getAlias(String prompt) throws Exception {
 2117           if (prompt != null) {
 2118               MessageFormat form = new MessageFormat
 2119                   (rb.getString("Enter prompt alias name:  "));
 2120               Object[] source = {prompt};
 2121               System.err.print(form.format(source));
 2122           } else {
 2123               System.err.print(rb.getString("Enter alias name:  "));
 2124           }
 2125           return (new BufferedReader(new InputStreamReader(
 2126                                           System.in))).readLine();
 2127       }
 2128   
 2129       /**
 2130        * Prompts user for an input string from the command line (System.in)
 2131        * @prompt the prompt string printed
 2132        * @returns the string entered by the user, without the \n at the end
 2133        */
 2134       private String inputStringFromStdin(String prompt) throws Exception {
 2135           System.err.print(prompt);
 2136           return (new BufferedReader(new InputStreamReader(
 2137                                           System.in))).readLine();
 2138       }
 2139   
 2140       /**
 2141        * Prompts user for key password. User may select to choose the same
 2142        * password (<code>otherKeyPass</code>) as for <code>otherAlias</code>.
 2143        */
 2144       private char[] getKeyPasswd(String alias, String otherAlias,
 2145                                   char[] otherKeyPass)
 2146           throws Exception
 2147       {
 2148           int count = 0;
 2149           char[] keyPass = null;
 2150   
 2151           do {
 2152               if (otherKeyPass != null) {
 2153                   MessageFormat form = new MessageFormat(rb.getString
 2154                           ("Enter key password for <alias>"));
 2155                   Object[] source = {alias};
 2156                   System.err.println(form.format(source));
 2157   
 2158                   form = new MessageFormat(rb.getString
 2159                           ("\t(RETURN if same as for <otherAlias>)"));
 2160                   Object[] src = {otherAlias};
 2161                   System.err.print(form.format(src));
 2162               } else {
 2163                   MessageFormat form = new MessageFormat(rb.getString
 2164                           ("Enter key password for <alias>"));
 2165                   Object[] source = {alias};
 2166                   System.err.print(form.format(source));
 2167               }
 2168               System.err.flush();
 2169               keyPass = Password.readPassword(System.in);
 2170               passwords.add(keyPass);
 2171               if (keyPass == null) {
 2172                   keyPass = otherKeyPass;
 2173               }
 2174               count++;
 2175           } while ((keyPass == null) && count < 3);
 2176   
 2177           if (keyPass == null) {
 2178               throw new Exception(rb.getString("Too many failures - try later"));
 2179           }
 2180   
 2181           return keyPass;
 2182       }
 2183   
 2184       /**
 2185        * Prints a certificate in a human readable format.
 2186        */
 2187       private void printX509Cert(X509Certificate cert, PrintStream out)
 2188           throws Exception
 2189       {
 2190           /*
 2191           out.println("Owner: "
 2192                       + cert.getSubjectDN().toString()
 2193                       + "\n"
 2194                       + "Issuer: "
 2195                       + cert.getIssuerDN().toString()
 2196                       + "\n"
 2197                       + "Serial number: " + cert.getSerialNumber().toString(16)
 2198                       + "\n"
 2199                       + "Valid from: " + cert.getNotBefore().toString()
 2200                       + " until: " + cert.getNotAfter().toString()
 2201                       + "\n"
 2202                       + "Certificate fingerprints:\n"
 2203                       + "\t MD5:  " + getCertFingerPrint("MD5", cert)
 2204                       + "\n"
 2205                       + "\t SHA1: " + getCertFingerPrint("SHA1", cert));
 2206           */
 2207   
 2208           MessageFormat form = new MessageFormat
 2209                   (rb.getString("*PATTERN* printX509Cert"));
 2210           Object[] source = {cert.getSubjectDN().toString(),
 2211                           cert.getIssuerDN().toString(),
 2212                           cert.getSerialNumber().toString(16),
 2213                           cert.getNotBefore().toString(),
 2214                           cert.getNotAfter().toString(),
 2215                           getCertFingerPrint("MD5", cert),
 2216                           getCertFingerPrint("SHA1", cert),
 2217                           cert.getSigAlgName(),
 2218                           cert.getVersion()
 2219                           };
 2220           out.println(form.format(source));
 2221   
 2222           int extnum = 0;
 2223           if (cert instanceof X509CertImpl) {
 2224               X509CertImpl impl = (X509CertImpl)cert;
 2225               if (cert.getCriticalExtensionOIDs() != null) {
 2226                   for (String extOID : cert.getCriticalExtensionOIDs()) {
 2227                       if (extnum == 0) {
 2228                           out.println();
 2229                           out.println(rb.getString("Extensions: "));
 2230                           out.println();
 2231                       }
 2232                       out.println("#"+(++extnum)+": "+
 2233                               impl.getExtension(new ObjectIdentifier(extOID)));
 2234                   }
 2235               }
 2236               if (cert.getNonCriticalExtensionOIDs() != null) {
 2237                   for (String extOID : cert.getNonCriticalExtensionOIDs()) {
 2238                       if (extnum == 0) {
 2239                           out.println();
 2240                           out.println(rb.getString("Extensions: "));
 2241                           out.println();
 2242                       }
 2243                       Extension ext = impl.getExtension(new ObjectIdentifier(extOID));
 2244                       if (ext != null) {
 2245                           out.println("#"+(++extnum)+": "+ ext);
 2246                       } else {
 2247                           out.println("#"+(++extnum)+": "+
 2248                                   impl.getUnparseableExtension(new ObjectIdentifier(extOID)));
 2249                       }
 2250                   }
 2251               }
 2252           }
 2253       }
 2254   
 2255       /**
 2256        * Returns true if the certificate is self-signed, false otherwise.
 2257        */
 2258       private boolean isSelfSigned(X509Certificate cert) {
 2259           return cert.getSubjectDN().equals(cert.getIssuerDN());
 2260       }
 2261   
 2262       /**
 2263        * Returns true if the given certificate is trusted, false otherwise.
 2264        */
 2265       private boolean isTrusted(Certificate cert)
 2266           throws Exception
 2267       {
 2268           if (keyStore.getCertificateAlias(cert) != null) {
 2269               return true; // found in own keystore
 2270           }
 2271           if (trustcacerts && (caks != null) &&
 2272                   (caks.getCertificateAlias(cert) != null)) {
 2273               return true; // found in CA keystore
 2274           }
 2275           return false;
 2276       }
 2277   
 2278       /**
 2279        * Gets an X.500 name suitable for inclusion in a certification request.
 2280        */
 2281       private X500Name getX500Name() throws IOException {
 2282           BufferedReader in;
 2283           in = new BufferedReader(new InputStreamReader(System.in));
 2284           String commonName = "Unknown";
 2285           String organizationalUnit = "Unknown";
 2286           String organization = "Unknown";
 2287           String city = "Unknown";
 2288           String state = "Unknown";
 2289           String country = "Unknown";
 2290           X500Name name;
 2291           String userInput = null;
 2292   
 2293           int maxRetry = 20;
 2294           do {
 2295               if (maxRetry-- < 0) {
 2296                   throw new RuntimeException(rb.getString(
 2297                           "Too may retries, program terminated"));
 2298               }
 2299               commonName = inputString(in,
 2300                       rb.getString("What is your first and last name?"),
 2301                       commonName);
 2302               organizationalUnit = inputString(in,
 2303                       rb.getString
 2304                           ("What is the name of your organizational unit?"),
 2305                       organizationalUnit);
 2306               organization = inputString(in,
 2307                       rb.getString("What is the name of your organization?"),
 2308                       organization);
 2309               city = inputString(in,
 2310                       rb.getString("What is the name of your City or Locality?"),
 2311                       city);
 2312               state = inputString(in,
 2313                       rb.getString("What is the name of your State or Province?"),
 2314                       state);
 2315               country = inputString(in,
 2316                       rb.getString
 2317                           ("What is the two-letter country code for this unit?"),
 2318                       country);
 2319               name = new X500Name(commonName, organizationalUnit, organization,
 2320                                   city, state, country);
 2321               MessageFormat form = new MessageFormat
 2322                   (rb.getString("Is <name> correct?"));
 2323               Object[] source = {name};
 2324               userInput = inputString
 2325                   (in, form.format(source), rb.getString("no"));
 2326           } while (collator.compare(userInput, rb.getString("yes")) != 0 &&
 2327                    collator.compare(userInput, rb.getString("y")) != 0);
 2328   
 2329           System.err.println();
 2330           return name;
 2331       }
 2332   
 2333       private String inputString(BufferedReader in, String prompt,
 2334                                  String defaultValue)
 2335           throws IOException
 2336       {
 2337           System.err.println(prompt);
 2338           MessageFormat form = new MessageFormat
 2339                   (rb.getString("  [defaultValue]:  "));
 2340           Object[] source = {defaultValue};
 2341           System.err.print(form.format(source));
 2342           System.err.flush();
 2343   
 2344           String value = in.readLine();
 2345           if (value == null || collator.compare(value, "") == 0) {
 2346               value = defaultValue;
 2347           }
 2348           return value;
 2349       }
 2350   
 2351       /**
 2352        * Writes an X.509 certificate in base64 or binary encoding to an output
 2353        * stream.
 2354        */
 2355       private void dumpCert(Certificate cert, PrintStream out)
 2356           throws IOException, CertificateException
 2357       {
 2358           if (rfc) {
 2359               BASE64Encoder encoder = new BASE64Encoder();
 2360               out.println(X509Factory.BEGIN_CERT);
 2361               encoder.encodeBuffer(cert.getEncoded(), out);
 2362               out.println(X509Factory.END_CERT);
 2363           } else {
 2364               out.write(cert.getEncoded()); // binary
 2365           }
 2366       }
 2367   
 2368       /**
 2369        * Converts a byte to hex digit and writes to the supplied buffer
 2370        */
 2371       private void byte2hex(byte b, StringBuffer buf) {
 2372           char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
 2373                               '9', 'A', 'B', 'C', 'D', 'E', 'F' };
 2374           int high = ((b & 0xf0) >> 4);
 2375           int low = (b & 0x0f);
 2376           buf.append(hexChars[high]);
 2377           buf.append(hexChars[low]);
 2378       }
 2379   
 2380       /**
 2381        * Converts a byte array to hex string
 2382        */
 2383       private String toHexString(byte[] block) {
 2384           StringBuffer buf = new StringBuffer();
 2385           int len = block.length;
 2386           for (int i = 0; i < len; i++) {
 2387                byte2hex(block[i], buf);
 2388                if (i < len-1) {
 2389                    buf.append(":");
 2390                }
 2391           }
 2392           return buf.toString();
 2393       }
 2394   
 2395       /**
 2396        * Recovers (private) key associated with given alias.
 2397        *
 2398        * @return an array of objects, where the 1st element in the array is the
 2399        * recovered private key, and the 2nd element is the password used to
 2400        * recover it.
 2401        */
 2402       private Object[] recoverKey(String alias, char[] storePass,
 2403                                          char[] keyPass)
 2404           throws Exception
 2405       {
 2406           Key key = null;
 2407   
 2408           if (keyStore.containsAlias(alias) == false) {
 2409               MessageFormat form = new MessageFormat
 2410                   (rb.getString("Alias <alias> does not exist"));
 2411               Object[] source = {alias};
 2412               throw new Exception(form.format(source));
 2413           }
 2414           if (!keyStore.entryInstanceOf(alias, KeyStore.PrivateKeyEntry.class) &&
 2415                   !keyStore.entryInstanceOf(alias, KeyStore.SecretKeyEntry.class)) {
 2416               MessageFormat form = new MessageFormat
 2417                   (rb.getString("Alias <alias> has no key"));
 2418               Object[] source = {alias};
 2419               throw new Exception(form.format(source));
 2420           }
 2421   
 2422           if (keyPass == null) {
 2423               // Try to recover the key using the keystore password
 2424               try {
 2425                   key = keyStore.getKey(alias, storePass);
 2426   
 2427                   keyPass = storePass;
 2428                   passwords.add(keyPass);
 2429               } catch (UnrecoverableKeyException e) {
 2430                   // Did not work out, so prompt user for key password
 2431                   if (!token) {
 2432                       keyPass = getKeyPasswd(alias, null, null);
 2433                       key = keyStore.getKey(alias, keyPass);
 2434                   } else {
 2435                       throw e;
 2436                   }
 2437               }
 2438           } else {
 2439               key = keyStore.getKey(alias, keyPass);
 2440           }
 2441   
 2442           return new Object[] {key, keyPass};
 2443       }
 2444   
 2445       /**
 2446        * Recovers entry associated with given alias.
 2447        *
 2448        * @return an array of objects, where the 1st element in the array is the
 2449        * recovered entry, and the 2nd element is the password used to
 2450        * recover it (null if no password).
 2451        */
 2452       private Object[] recoverEntry(KeyStore ks,
 2453                               String alias,
 2454                               char[] pstore,
 2455                               char[] pkey) throws Exception {
 2456   
 2457           if (ks.containsAlias(alias) == false) {
 2458               MessageFormat form = new MessageFormat
 2459                   (rb.getString("Alias <alias> does not exist"));
 2460               Object[] source = {alias};
 2461               throw new Exception(form.format(source));
 2462           }
 2463   
 2464           PasswordProtection pp = null;
 2465           Entry entry;
 2466   
 2467           try {
 2468               // First attempt to access entry without key password
 2469               // (PKCS11 entry or trusted certificate entry, for example)
 2470   
 2471               entry = ks.getEntry(alias, pp);
 2472               pkey = null;
 2473           } catch (UnrecoverableEntryException une) {
 2474   
 2475               if(P11KEYSTORE.equalsIgnoreCase(ks.getType()) ||
 2476                   KeyStoreUtil.isWindowsKeyStore(ks.getType())) {
 2477                   // should not happen, but a possibility
 2478                   throw une;
 2479               }
 2480   
 2481               // entry is protected
 2482   
 2483               if (pkey != null) {
 2484   
 2485                   // try provided key password
 2486   
 2487                   pp = new PasswordProtection(pkey);
 2488                   entry = ks.getEntry(alias, pp);
 2489   
 2490               } else {
 2491   
 2492                   // try store pass
 2493   
 2494                   try {
 2495                       pp = new PasswordProtection(pstore);
 2496                       entry = ks.getEntry(alias, pp);
 2497                       pkey = pstore;
 2498                   } catch (UnrecoverableEntryException une2) {
 2499                       if (P12KEYSTORE.equalsIgnoreCase(ks.getType())) {
 2500   
 2501                           // P12 keystore currently does not support separate
 2502                           // store and entry passwords
 2503   
 2504                           throw une2;
 2505                       } else {
 2506   
 2507                           // prompt for entry password
 2508   
 2509                           pkey = getKeyPasswd(alias, null, null);
 2510                           pp = new PasswordProtection(pkey);
 2511                           entry = ks.getEntry(alias, pp);
 2512                       }
 2513                   }
 2514               }
 2515           }
 2516   
 2517           return new Object[] {entry, pkey};
 2518       }
 2519       /**
 2520        * Gets the requested finger print of the certificate.
 2521        */
 2522       private String getCertFingerPrint(String mdAlg, Certificate cert)
 2523           throws Exception
 2524       {
 2525           byte[] encCertInfo = cert.getEncoded();
 2526           MessageDigest md = MessageDigest.getInstance(mdAlg);
 2527           byte[] digest = md.digest(encCertInfo);
 2528           return toHexString(digest);
 2529       }
 2530   
 2531       /**
 2532        * Prints warning about missing integrity check.
 2533        */
 2534       private void printWarning() {
 2535           System.err.println();
 2536           System.err.println(rb.getString
 2537               ("*****************  WARNING WARNING WARNING  *****************"));
 2538           System.err.println(rb.getString
 2539               ("* The integrity of the information stored in your keystore  *"));
 2540           System.err.println(rb.getString
 2541               ("* has NOT been verified!  In order to verify its integrity, *"));
 2542           System.err.println(rb.getString
 2543               ("* you must provide your keystore password.                  *"));
 2544           System.err.println(rb.getString
 2545               ("*****************  WARNING WARNING WARNING  *****************"));
 2546           System.err.println();
 2547       }
 2548   
 2549       /**
 2550        * Validates chain in certification reply, and returns the ordered
 2551        * elements of the chain (with user certificate first, and root
 2552        * certificate last in the array).
 2553        *
 2554        * @param alias the alias name
 2555        * @param userCert the user certificate of the alias
 2556        * @param replyCerts the chain provided in the reply
 2557        */
 2558       private Certificate[] validateReply(String alias,
 2559                                           Certificate userCert,
 2560                                           Certificate[] replyCerts)
 2561           throws Exception
 2562       {
 2563           // order the certs in the reply (bottom-up).
 2564           // we know that all certs in the reply are of type X.509, because
 2565           // we parsed them using an X.509 certificate factory
 2566           int i;
 2567           PublicKey userPubKey = userCert.getPublicKey();
 2568           for (i=0; i<replyCerts.length; i++) {
 2569               if (userPubKey.equals(replyCerts[i].getPublicKey())) {
 2570                   break;
 2571               }
 2572           }
 2573           if (i == replyCerts.length) {
 2574               MessageFormat form = new MessageFormat(rb.getString
 2575                   ("Certificate reply does not contain public key for <alias>"));
 2576               Object[] source = {alias};
 2577               throw new Exception(form.format(source));
 2578           }
 2579   
 2580           Certificate tmpCert = replyCerts[0];
 2581           replyCerts[0] = replyCerts[i];
 2582           replyCerts[i] = tmpCert;
 2583           Principal issuer = ((X509Certificate)replyCerts[0]).getIssuerDN();
 2584   
 2585           for (i=1; i < replyCerts.length-1; i++) {
 2586               // find a cert in the reply whose "subject" is the same as the
 2587               // given "issuer"
 2588               int j;
 2589               for (j=i; j<replyCerts.length; j++) {
 2590                   Principal subject;
 2591                   subject = ((X509Certificate)replyCerts[j]).getSubjectDN();
 2592                   if (subject.equals(issuer)) {
 2593                       tmpCert = replyCerts[i];
 2594                       replyCerts[i] = replyCerts[j];
 2595                       replyCerts[j] = tmpCert;
 2596                       issuer = ((X509Certificate)replyCerts[i]).getIssuerDN();
 2597                       break;
 2598                   }
 2599               }
 2600               if (j == replyCerts.length) {
 2601                   throw new Exception
 2602                       (rb.getString("Incomplete certificate chain in reply"));
 2603               }
 2604           }
 2605   
 2606           // now verify each cert in the ordered chain
 2607           for (i=0; i<replyCerts.length-1; i++) {
 2608               PublicKey pubKey = replyCerts[i+1].getPublicKey();
 2609               try {
 2610                   replyCerts[i].verify(pubKey);
 2611               } catch (Exception e) {
 2612                   throw new Exception(rb.getString
 2613                           ("Certificate chain in reply does not verify: ") +
 2614                           e.getMessage());
 2615               }
 2616           }
 2617   
 2618           if (noprompt) {
 2619               return replyCerts;
 2620           }
 2621   
 2622           // do we trust the (root) cert at the top?
 2623           Certificate topCert = replyCerts[replyCerts.length-1];
 2624           if (!isTrusted(topCert)) {
 2625               boolean verified = false;
 2626               Certificate rootCert = null;
 2627               if (trustcacerts && (caks!= null)) {
 2628                   for (Enumeration<String> aliases = caks.aliases();
 2629                        aliases.hasMoreElements(); ) {
 2630                       String name = aliases.nextElement();
 2631                       rootCert = caks.getCertificate(name);
 2632                       if (rootCert != null) {
 2633                           try {
 2634                               topCert.verify(rootCert.getPublicKey());
 2635                               verified = true;
 2636                               break;
 2637                           } catch (Exception e) {
 2638                           }
 2639                       }
 2640                   }
 2641               }
 2642               if (!verified) {
 2643                   System.err.println();
 2644                   System.err.println
 2645                           (rb.getString("Top-level certificate in reply:\n"));
 2646                   printX509Cert((X509Certificate)topCert, System.out);
 2647                   System.err.println();
 2648                   System.err.print(rb.getString("... is not trusted. "));
 2649                   String reply = getYesNoReply
 2650                           (rb.getString("Install reply anyway? [no]:  "));
 2651                   if ("NO".equals(reply)) {
 2652                       return null;
 2653                   }
 2654               } else {
 2655                   if (!isSelfSigned((X509Certificate)topCert)) {
 2656                       // append the (self-signed) root CA cert to the chain
 2657                       Certificate[] tmpCerts =
 2658                           new Certificate[replyCerts.length+1];
 2659                       System.arraycopy(replyCerts, 0, tmpCerts, 0,
 2660                                        replyCerts.length);
 2661                       tmpCerts[tmpCerts.length-1] = rootCert;
 2662                       replyCerts = tmpCerts;
 2663                   }
 2664               }
 2665           }
 2666   
 2667           return replyCerts;
 2668       }
 2669   
 2670       /**
 2671        * Establishes a certificate chain (using trusted certificates in the
 2672        * keystore), starting with the user certificate
 2673        * and ending at a self-signed certificate found in the keystore.
 2674        *
 2675        * @param userCert the user certificate of the alias
 2676        * @param certToVerify the single certificate provided in the reply
 2677        */
 2678       private Certificate[] establishCertChain(Certificate userCert,
 2679                                                Certificate certToVerify)
 2680           throws Exception
 2681       {
 2682           if (userCert != null) {
 2683               // Make sure that the public key of the certificate reply matches
 2684               // the original public key in the keystore
 2685               PublicKey origPubKey = userCert.getPublicKey();
 2686               PublicKey replyPubKey = certToVerify.getPublicKey();
 2687               if (!origPubKey.equals(replyPubKey)) {
 2688                   throw new Exception(rb.getString
 2689                           ("Public keys in reply and keystore don't match"));
 2690               }
 2691   
 2692               // If the two certs are identical, we're done: no need to import
 2693               // anything
 2694               if (certToVerify.equals(userCert)) {
 2695                   throw new Exception(rb.getString
 2696                           ("Certificate reply and certificate in keystore are identical"));
 2697               }
 2698           }
 2699   
 2700           // Build a hash table of all certificates in the keystore.
 2701           // Use the subject distinguished name as the key into the hash table.
 2702           // All certificates associated with the same subject distinguished
 2703           // name are stored in the same hash table entry as a vector.
 2704           Hashtable<Principal, Vector<Certificate>> certs = null;
 2705           if (keyStore.size() > 0) {
 2706               certs = new Hashtable<Principal, Vector<Certificate>>(11);
 2707               keystorecerts2Hashtable(keyStore, certs);
 2708           }
 2709           if (trustcacerts) {
 2710               if (caks!=null && caks.size()>0) {
 2711                   if (certs == null) {
 2712                       certs = new Hashtable<Principal, Vector<Certificate>>(11);
 2713                   }
 2714                   keystorecerts2Hashtable(caks, certs);
 2715               }
 2716           }
 2717   
 2718           // start building chain
 2719           Vector<Certificate> chain = new Vector<Certificate>(2);
 2720           if (buildChain((X509Certificate)certToVerify, chain, certs)) {
 2721               Certificate[] newChain = new Certificate[chain.size()];
 2722               // buildChain() returns chain with self-signed root-cert first and
 2723               // user-cert last, so we need to invert the chain before we store
 2724               // it
 2725               int j=0;
 2726               for (int i=chain.size()-1; i>=0; i--) {
 2727                   newChain[j] = chain.elementAt(i);
 2728                   j++;
 2729               }
 2730               return newChain;
 2731           } else {
 2732               throw new Exception
 2733                   (rb.getString("Failed to establish chain from reply"));
 2734           }
 2735       }
 2736   
 2737       /**
 2738        * Recursively tries to establish chain from pool of trusted certs.
 2739        *
 2740        * @param certToVerify the cert that needs to be verified.
 2741        * @param chain the chain that's being built.
 2742        * @param certs the pool of trusted certs
 2743        *
 2744        * @return true if successful, false otherwise.
 2745        */
 2746       private boolean buildChain(X509Certificate certToVerify,
 2747                           Vector<Certificate> chain,
 2748                           Hashtable<Principal, Vector<Certificate>> certs) {
 2749           Principal subject = certToVerify.getSubjectDN();
 2750           Principal issuer = certToVerify.getIssuerDN();
 2751           if (subject.equals(issuer)) {
 2752               // reached self-signed root cert;
 2753               // no verification needed because it's trusted.
 2754               chain.addElement(certToVerify);
 2755               return true;
 2756           }
 2757   
 2758           // Get the issuer's certificate(s)
 2759           Vector<Certificate> vec = certs.get(issuer);
 2760           if (vec == null) {
 2761               return false;
 2762           }
 2763   
 2764           // Try out each certificate in the vector, until we find one
 2765           // whose public key verifies the signature of the certificate
 2766           // in question.
 2767           for (Enumeration<Certificate> issuerCerts = vec.elements();
 2768                issuerCerts.hasMoreElements(); ) {
 2769               X509Certificate issuerCert
 2770                   = (X509Certificate)issuerCerts.nextElement();
 2771               PublicKey issuerPubKey = issuerCert.getPublicKey();
 2772               try {
 2773                   certToVerify.verify(issuerPubKey);
 2774               } catch (Exception e) {
 2775                   continue;
 2776               }
 2777               if (buildChain(issuerCert, chain, certs)) {
 2778                   chain.addElement(certToVerify);
 2779                   return true;
 2780               }
 2781           }
 2782           return false;
 2783       }
 2784   
 2785       /**
 2786        * Prompts user for yes/no decision.
 2787        *
 2788        * @return the user's decision, can only be "YES" or "NO"
 2789        */
 2790       private String getYesNoReply(String prompt)
 2791           throws IOException
 2792       {
 2793           String reply = null;
 2794           int maxRetry = 20;
 2795           do {
 2796               if (maxRetry-- < 0) {
 2797                   throw new RuntimeException(rb.getString(
 2798                           "Too may retries, program terminated"));
 2799               }
 2800               System.err.print(prompt);
 2801               System.err.flush();
 2802               reply = (new BufferedReader(new InputStreamReader
 2803                                           (System.in))).readLine();
 2804               if (collator.compare(reply, "") == 0 ||
 2805                   collator.compare(reply, rb.getString("n")) == 0 ||
 2806                   collator.compare(reply, rb.getString("no")) == 0) {
 2807                   reply = "NO";
 2808               } else if (collator.compare(reply, rb.getString("y")) == 0 ||
 2809                          collator.compare(reply, rb.getString("yes")) == 0) {
 2810                   reply = "YES";
 2811               } else {
 2812                   System.err.println(rb.getString("Wrong answer, try again"));
 2813                   reply = null;
 2814               }
 2815           } while (reply == null);
 2816           return reply;
 2817       }
 2818   
 2819       /**
 2820        * Returns the keystore with the configured CA certificates.
 2821        */
 2822       private KeyStore getCacertsKeyStore()
 2823           throws Exception
 2824       {
 2825           String sep = File.separator;
 2826           File file = new File(System.getProperty("java.home") + sep
 2827                                + "lib" + sep + "security" + sep
 2828                                + "cacerts");
 2829           if (!file.exists()) {
 2830               return null;
 2831           }
 2832           FileInputStream fis = null;
 2833           KeyStore caks = null;
 2834           try {
 2835               fis = new FileInputStream(file);
 2836               caks = KeyStore.getInstance(JKS);
 2837               caks.load(fis, null);
 2838           } finally {
 2839               if (fis != null) {
 2840                   fis.close();
 2841               }
 2842           }
 2843           return caks;
 2844       }
 2845   
 2846       /**
 2847        * Stores the (leaf) certificates of a keystore in a hashtable.
 2848        * All certs belonging to the same CA are stored in a vector that
 2849        * in turn is stored in the hashtable, keyed by the CA's subject DN
 2850        */
 2851       private void keystorecerts2Hashtable(KeyStore ks,
 2852                   Hashtable<Principal, Vector<Certificate>> hash)
 2853           throws Exception {
 2854   
 2855           for (Enumeration<String> aliases = ks.aliases();
 2856                                           aliases.hasMoreElements(); ) {
 2857               String alias = aliases.nextElement();
 2858               Certificate cert = ks.getCertificate(alias);
 2859               if (cert != null) {
 2860                   Principal subjectDN = ((X509Certificate)cert).getSubjectDN();
 2861                   Vector<Certificate> vec = hash.get(subjectDN);
 2862                   if (vec == null) {
 2863                       vec = new Vector<Certificate>();
 2864                       vec.addElement(cert);
 2865                   } else {
 2866                       if (!vec.contains(cert)) {
 2867                           vec.addElement(cert);
 2868                       }
 2869                   }
 2870                   hash.put(subjectDN, vec);
 2871               }
 2872           }
 2873       }
 2874   
 2875       /**
 2876        * Returns the issue time that's specified the -startdate option
 2877        * @param s the value of -startdate option
 2878        */
 2879       private static Date getStartDate(String s) throws IOException {
 2880           Calendar c = new GregorianCalendar();
 2881           if (s != null) {
 2882               IOException ioe = new IOException(
 2883                       rb.getString("Illegal startdate value"));
 2884               int len = s.length();
 2885               if (len == 0) {
 2886                   throw ioe;
 2887               }
 2888               if (s.charAt(0) == '-' || s.charAt(0) == '+') {
 2889                   // Form 1: ([+-]nnn[ymdHMS])+
 2890                   int start = 0;
 2891                   while (start < len) {
 2892                       int sign = 0;
 2893                       switch (s.charAt(start)) {
 2894                           case '+': sign = 1; break;
 2895                           case '-': sign = -1; break;
 2896                           default: throw ioe;
 2897                       }
 2898                       int i = start+1;
 2899                       for (; i<len; i++) {
 2900                           char ch = s.charAt(i);
 2901                           if (ch < '0' || ch > '9') break;
 2902                       }
 2903                       if (i == start+1) throw ioe;
 2904                       int number = Integer.parseInt(s.substring(start+1, i));
 2905                       if (i >= len) throw ioe;
 2906                       int unit = 0;
 2907                       switch (s.charAt(i)) {
 2908                           case 'y': unit = Calendar.YEAR; break;
 2909                           case 'm': unit = Calendar.MONTH; break;
 2910                           case 'd': unit = Calendar.DATE; break;
 2911                           case 'H': unit = Calendar.HOUR; break;
 2912                           case 'M': unit = Calendar.MINUTE; break;
 2913                           case 'S': unit = Calendar.SECOND; break;
 2914                           default: throw ioe;
 2915                       }
 2916                       c.add(unit, sign * number);
 2917                       start = i + 1;
 2918                   }
 2919               } else  {
 2920                   // Form 2: [yyyy/mm/dd] [HH:MM:SS]
 2921                   String date = null, time = null;
 2922                   if (len == 19) {
 2923                       date = s.substring(0, 10);
 2924                       time = s.substring(11);
 2925                       if (s.charAt(10) != ' ')
 2926                           throw ioe;
 2927                   } else if (len == 10) {
 2928                       date = s;
 2929                   } else if (len == 8) {
 2930                       time = s;
 2931                   } else {
 2932                       throw ioe;
 2933                   }
 2934                   if (date != null) {
 2935                       if (date.matches("\\d\\d\\d\\d\\/\\d\\d\\/\\d\\d")) {
 2936                           c.set(Integer.valueOf(date.substring(0, 4)),
 2937                                   Integer.valueOf(date.substring(5, 7))-1,
 2938                                   Integer.valueOf(date.substring(8, 10)));
 2939                       } else {
 2940                           throw ioe;
 2941                       }
 2942                   }
 2943                   if (time != null) {
 2944                       if (time.matches("\\d\\d:\\d\\d:\\d\\d")) {
 2945                           c.set(Calendar.HOUR_OF_DAY, Integer.valueOf(time.substring(0, 2)));
 2946                           c.set(Calendar.MINUTE, Integer.valueOf(time.substring(0, 2)));
 2947                           c.set(Calendar.SECOND, Integer.valueOf(time.substring(0, 2)));
 2948                           c.set(Calendar.MILLISECOND, 0);
 2949                       } else {
 2950                           throw ioe;
 2951                       }
 2952                   }
 2953               }
 2954           }
 2955           return c.getTime();
 2956       }
 2957   
 2958       /**
 2959        * Prints the usage of this tool.
 2960        */
 2961       private void usage() {
 2962           System.err.println(rb.getString("keytool usage:\n"));
 2963   
 2964           System.err.println(rb.getString
 2965                   ("-certreq     [-v] [-protected]"));
 2966           System.err.println(rb.getString
 2967                   ("\t     [-alias <alias>] [-sigalg <sigalg>]"));
 2968           System.err.println(rb.getString
 2969                   ("\t     [-file <csr_file>] [-keypass <keypass>]"));
 2970           System.err.println(rb.getString
 2971                   ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
 2972           System.err.println(rb.getString
 2973                   ("\t     [-storetype <storetype>] [-providername <name>]"));
 2974           System.err.println(rb.getString
 2975                   ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
 2976           System.err.println(rb.getString
 2977                   ("\t     [-providerpath <pathlist>]"));
 2978           System.err.println();
 2979   
 2980           System.err.println(rb.getString
 2981                   ("-changealias [-v] [-protected] -alias <alias> -destalias <destalias>"));
 2982           System.err.println(rb.getString
 2983                   ("\t     [-keypass <keypass>]"));
 2984           System.err.println(rb.getString
 2985                   ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
 2986           System.err.println(rb.getString
 2987                   ("\t     [-storetype <storetype>] [-providername <name>]"));
 2988           System.err.println(rb.getString
 2989                   ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
 2990           System.err.println(rb.getString
 2991                   ("\t     [-providerpath <pathlist>]"));
 2992           System.err.println();
 2993   
 2994           System.err.println(rb.getString
 2995                   ("-delete      [-v] [-protected] -alias <alias>"));
 2996           System.err.println(rb.getString
 2997                   ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
 2998           System.err.println(rb.getString
 2999                   ("\t     [-storetype <storetype>] [-providername <name>]"));
 3000           System.err.println(rb.getString
 3001                   ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
 3002           System.err.println(rb.getString
 3003                   ("\t     [-providerpath <pathlist>]"));
 3004           System.err.println();
 3005   
 3006           System.err.println(rb.getString
 3007                   ("-exportcert  [-v] [-rfc] [-protected]"));
 3008           System.err.println(rb.getString
 3009                   ("\t     [-alias <alias>] [-file <cert_file>]"));
 3010           System.err.println(rb.getString
 3011                   ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
 3012           System.err.println(rb.getString
 3013                   ("\t     [-storetype <storetype>] [-providername <name>]"));
 3014           System.err.println(rb.getString
 3015                   ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
 3016           System.err.println(rb.getString
 3017                   ("\t     [-providerpath <pathlist>]"));
 3018           System.err.println();
 3019   
 3020           System.err.println(rb.getString
 3021                   ("-genkeypair  [-v] [-protected]"));
 3022           System.err.println(rb.getString
 3023                   ("\t     [-alias <alias>]"));
 3024           System.err.println(rb.getString
 3025                   ("\t     [-keyalg <keyalg>] [-keysize <keysize>]"));
 3026           System.err.println(rb.getString
 3027                   ("\t     [-sigalg <sigalg>] [-dname <dname>]"));
 3028           System.err.println(rb.getString
 3029                   ("\t     [-startdate <startdate>]"));
 3030           System.err.println(rb.getString
 3031                   ("\t     [-validity <valDays>] [-keypass <keypass>]"));
 3032           System.err.println(rb.getString
 3033                   ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
 3034           System.err.println(rb.getString
 3035                   ("\t     [-storetype <storetype>] [-providername <name>]"));
 3036           System.err.println(rb.getString
 3037                   ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
 3038           System.err.println(rb.getString
 3039                   ("\t     [-providerpath <pathlist>]"));
 3040           System.err.println();
 3041   
 3042           System.err.println(rb.getString
 3043                   ("-genseckey   [-v] [-protected]"));
 3044           System.err.println(rb.getString
 3045                   ("\t     [-alias <alias>] [-keypass <keypass>]"));
 3046           System.err.println(rb.getString
 3047                   ("\t     [-keyalg <keyalg>] [-keysize <keysize>]"));
 3048           System.err.println(rb.getString
 3049                   ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
 3050           System.err.println(rb.getString
 3051                   ("\t     [-storetype <storetype>] [-providername <name>]"));
 3052           System.err.println(rb.getString
 3053                   ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
 3054           System.err.println(rb.getString
 3055                   ("\t     [-providerpath <pathlist>]"));
 3056           System.err.println();
 3057   
 3058           System.err.println(rb.getString("-help"));
 3059           System.err.println();
 3060   
 3061           System.err.println(rb.getString
 3062                   ("-importcert  [-v] [-noprompt] [-trustcacerts] [-protected]"));
 3063           System.err.println(rb.getString
 3064                   ("\t     [-alias <alias>]"));
 3065           System.err.println(rb.getString
 3066                   ("\t     [-file <cert_file>] [-keypass <keypass>]"));
 3067           System.err.println(rb.getString
 3068                   ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
 3069           System.err.println(rb.getString
 3070                   ("\t     [-storetype <storetype>] [-providername <name>]"));
 3071           System.err.println(rb.getString
 3072                   ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
 3073           System.err.println(rb.getString
 3074                   ("\t     [-providerpath <pathlist>]"));
 3075           System.err.println();
 3076   
 3077           System.err.println(rb.getString
 3078                   ("-importkeystore [-v] "));
 3079           System.err.println(rb.getString
 3080                   ("\t     [-srckeystore <srckeystore>] [-destkeystore <destkeystore>]"));
 3081           System.err.println(rb.getString
 3082                   ("\t     [-srcstoretype <srcstoretype>] [-deststoretype <deststoretype>]"));
 3083           System.err.println(rb.getString
 3084                   ("\t     [-srcstorepass <srcstorepass>] [-deststorepass <deststorepass>]"));
 3085           System.err.println(rb.getString
 3086                   ("\t     [-srcprotected] [-destprotected]"));
 3087           System.err.println(rb.getString
 3088                   ("\t     [-srcprovidername <srcprovidername>]\n\t     [-destprovidername <destprovidername>]"));
 3089           System.err.println(rb.getString
 3090                   ("\t     [-srcalias <srcalias> [-destalias <destalias>]"));
 3091           System.err.println(rb.getString
 3092                   ("\t       [-srckeypass <srckeypass>] [-destkeypass <destkeypass>]]"));
 3093           System.err.println(rb.getString
 3094                   ("\t     [-noprompt]"));
 3095           System.err.println(rb.getString
 3096                   ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
 3097           System.err.println(rb.getString
 3098                   ("\t     [-providerpath <pathlist>]"));
 3099           System.err.println();
 3100   
 3101           System.err.println(rb.getString
 3102                   ("-keypasswd   [-v] [-alias <alias>]"));
 3103           System.err.println(rb.getString
 3104                   ("\t     [-keypass <old_keypass>] [-new <new_keypass>]"));
 3105           System.err.println(rb.getString
 3106                   ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
 3107           System.err.println(rb.getString
 3108                   ("\t     [-storetype <storetype>] [-providername <name>]"));
 3109           System.err.println(rb.getString
 3110                   ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
 3111           System.err.println(rb.getString
 3112                   ("\t     [-providerpath <pathlist>]"));
 3113           System.err.println();
 3114   
 3115           System.err.println(rb.getString
 3116                   ("-list        [-v | -rfc] [-protected]"));
 3117           System.err.println(rb.getString
 3118                   ("\t     [-alias <alias>]"));
 3119           System.err.println(rb.getString
 3120                   ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
 3121           System.err.println(rb.getString
 3122                   ("\t     [-storetype <storetype>] [-providername <name>]"));
 3123           System.err.println(rb.getString
 3124                   ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
 3125           System.err.println(rb.getString
 3126                   ("\t     [-providerpath <pathlist>]"));
 3127           System.err.println();
 3128   
 3129           System.err.println(rb.getString
 3130                   ("-printcert   [-v] [-file <cert_file>]"));
 3131           System.err.println();
 3132   
 3133           System.err.println(rb.getString
 3134                   ("-storepasswd [-v] [-new <new_storepass>]"));
 3135           System.err.println(rb.getString
 3136                   ("\t     [-keystore <keystore>] [-storepass <storepass>]"));
 3137           System.err.println(rb.getString
 3138                   ("\t     [-storetype <storetype>] [-providername <name>]"));
 3139           System.err.println(rb.getString
 3140                   ("\t     [-providerclass <provider_class_name> [-providerarg <arg>]] ..."));
 3141           System.err.println(rb.getString
 3142                   ("\t     [-providerpath <pathlist>]"));
 3143   
 3144           if (debug) {
 3145               throw new RuntimeException("NO ERROR, SORRY");
 3146           } else {
 3147               System.exit(1);
 3148           }
 3149       }
 3150   
 3151       private void tinyHelp() {
 3152           System.err.println(rb.getString("Try keytool -help"));
 3153   
 3154           // do not drown user with the help lines.
 3155           if (debug) {
 3156               throw new RuntimeException("NO BIG ERROR, SORRY");
 3157           } else {
 3158               System.exit(1);
 3159           }
 3160       }
 3161   
 3162       private void errorNeedArgument(String flag) {
 3163           Object[] source = {flag};
 3164           System.err.println(new MessageFormat(
 3165                   rb.getString("Command option <flag> needs an argument.")).format(source));
 3166           tinyHelp();
 3167       }
 3168   }
 3169   
 3170   // This class is exactly the same as com.sun.tools.javac.util.Pair,
 3171   // it's copied here since the original one is not included in JRE.
 3172   class Pair<A, B> {
 3173   
 3174       public final A fst;
 3175       public final B snd;
 3176   
 3177       public Pair(A fst, B snd) {
 3178           this.fst = fst;
 3179           this.snd = snd;
 3180       }
 3181   
 3182       public String toString() {
 3183           return "Pair[" + fst + "," + snd + "]";
 3184       }
 3185   
 3186       private static boolean equals(Object x, Object y) {
 3187           return (x == null && y == null) || (x != null && x.equals(y));
 3188       }
 3189   
 3190       public boolean equals(Object other) {
 3191           return
 3192               other instanceof Pair &&
 3193               equals(fst, ((Pair)other).fst) &&
 3194               equals(snd, ((Pair)other).snd);
 3195       }
 3196   
 3197       public int hashCode() {
 3198           if (fst == null) return (snd == null) ? 0 : snd.hashCode() + 1;
 3199           else if (snd == null) return fst.hashCode() + 2;
 3200           else return fst.hashCode() * 17 + snd.hashCode();
 3201       }
 3202   }

Save This Page
Home » openjdk-7 » sun.security » tools » [javadoc | source]