1 /* StorePasswdCmd.java -- The storepasswd command handler of the keytool
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.classpath.tools.keytool;
41 import gnu.classpath.Configuration;
42 import gnu.classpath.SystemProperties;
43 import gnu.classpath.tools.common.ClasspathToolParser;
44 import gnu.classpath.tools.getopt.Option;
45 import gnu.classpath.tools.getopt.OptionException;
46 import gnu.classpath.tools.getopt.OptionGroup;
47 import gnu.classpath.tools.getopt.Parser;
49 import java.io.IOException;
50 import java.security.KeyStoreException;
51 import java.security.NoSuchAlgorithmException;
52 import java.security.cert.CertificateException;
53 import java.util.Arrays;
54 import java.util.logging.Logger;
56 import javax.security.auth.callback.Callback;
57 import javax.security.auth.callback.CallbackHandler;
58 import javax.security.auth.callback.PasswordCallback;
59 import javax.security.auth.callback.TextOutputCallback;
60 import javax.security.auth.callback.UnsupportedCallbackException;
63 * The <b>-storepasswd</b> keytool command handler is used to change the
64 * password which protects the integrity of the key store.
66 * Possible options for this command are:
69 * <dt>-new PASSWORD</dt>
70 * <dd>The new, and different, password which will be used to protect the
71 * designated key store.
74 * <dt>-storetype STORE_TYPE</dt>
75 * <dd>Use this option to specify the type of the key store to use. The
76 * default value, if this option is omitted, is that of the property
77 * <code>keystore.type</code> in the security properties file, which is
78 * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
82 * <dt>-keystore URL</dt>
83 * <dd>Use this option to specify the location of the key store to use.
84 * The default value is a file {@link java.net.URL} referencing the file
85 * named <code>.keystore</code> located in the path returned by the call to
86 * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
89 * If a URL was specified, but was found to be malformed --e.g. missing
90 * protocol element-- the tool will attempt to use the URL value as a file-
91 * name (with absolute or relative path-name) of a key store --as if the
92 * protocol was <code>file:</code>.
95 * <dt>-storepass PASSWORD</dt>
96 * <dd>Use this option to specify the password protecting the key store. If
97 * this option is omitted from the command line, you will be prompted to
101 * <dt>-provider PROVIDER_CLASS_NAME</dt>
102 * <dd>A fully qualified class name of a Security Provider to add to the
103 * current list of Security Providers already installed in the JVM in-use.
104 * If a provider class is specified with this option, and was successfully
105 * added to the runtime --i.e. it was not already installed-- then the tool
106 * will attempt to removed this Security Provider before exiting.
110 * <dd>Use this option to enable more verbose output.</dd>
113 class StorePasswdCmd extends Command
115 private static final Logger log = Logger.getLogger(StorePasswdCmd.class.getName());
116 protected String _newPassword;
117 protected String _ksType;
118 protected String _ksURL;
119 protected String _ksPassword;
120 protected String _providerClassName;
121 private char[] newStorePasswordChars;
123 // default 0-arguments constructor
125 // public setters -----------------------------------------------------------
127 /** @param password the new key-store password to use. */
128 public void setNew(String password)
130 this._newPassword = password;
133 /** @param type the key-store type to use. */
134 public void setStoretype(String type)
139 /** @param url the key-store URL to use. */
140 public void setKeystore(String url)
145 /** @param password the key-store password to use. */
146 public void setStorepass(String password)
148 this._ksPassword = password;
151 /** @param className a security provider fully qualified class name to use. */
152 public void setProvider(String className)
154 this._providerClassName = className;
157 // life-cycle methods -------------------------------------------------------
159 void setup() throws Exception
161 setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
162 setNewKeystorePassword(_newPassword);
163 if (Configuration.DEBUG)
165 log.fine("-storepasswd handler will use the following options:"); //$NON-NLS-1$
166 log.fine(" -storetype=" + storeType); //$NON-NLS-1$
167 log.fine(" -keystore=" + storeURL); //$NON-NLS-1$
168 log.fine(" -provider=" + provider); //$NON-NLS-1$
169 log.fine(" -v=" + verbose); //$NON-NLS-1$
173 void start() throws KeyStoreException, NoSuchAlgorithmException,
174 CertificateException, IOException
176 if (Configuration.DEBUG)
177 log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
178 saveKeyStore(newStorePasswordChars);
179 if (Configuration.DEBUG)
180 log.exiting(getClass().getName(), "start"); //$NON-NLS-1$
183 // own methods --------------------------------------------------------------
187 if (Configuration.DEBUG)
188 log.entering(this.getClass().getName(), "getParser"); //$NON-NLS-1$
189 Parser result = new ClasspathToolParser(Main.STOREPASSWD_CMD, true);
190 result.setHeader(Messages.getString("StorePasswdCmd.18")); //$NON-NLS-1$
191 result.setFooter(Messages.getString("StorePasswdCmd.17")); //$NON-NLS-1$
192 OptionGroup options = new OptionGroup(Messages.getString("StorePasswdCmd.16")); //$NON-NLS-1$
193 options.add(new Option(Main.NEW_OPT,
194 Messages.getString("StorePasswdCmd.15"), //$NON-NLS-1$
195 Messages.getString("StorePasswdCmd.8")) //$NON-NLS-1$
197 public void parsed(String argument) throws OptionException
199 _newPassword = argument;
202 options.add(new Option(Main.STORETYPE_OPT,
203 Messages.getString("StorePasswdCmd.13"), //$NON-NLS-1$
204 Messages.getString("StorePasswdCmd.12")) //$NON-NLS-1$
206 public void parsed(String argument) throws OptionException
211 options.add(new Option(Main.KEYSTORE_OPT,
212 Messages.getString("StorePasswdCmd.11"), //$NON-NLS-1$
213 Messages.getString("StorePasswdCmd.10")) //$NON-NLS-1$
215 public void parsed(String argument) throws OptionException
220 options.add(new Option(Main.STOREPASS_OPT,
221 Messages.getString("StorePasswdCmd.9"), //$NON-NLS-1$
222 Messages.getString("StorePasswdCmd.8")) //$NON-NLS-1$
224 public void parsed(String argument) throws OptionException
226 _ksPassword = argument;
229 options.add(new Option(Main.PROVIDER_OPT,
230 Messages.getString("StorePasswdCmd.7"), //$NON-NLS-1$
231 Messages.getString("StorePasswdCmd.6")) //$NON-NLS-1$
233 public void parsed(String argument) throws OptionException
235 _providerClassName = argument;
238 options.add(new Option(Main.VERBOSE_OPT,
239 Messages.getString("StorePasswdCmd.5")) //$NON-NLS-1$
241 public void parsed(String argument) throws OptionException
247 if (Configuration.DEBUG)
248 log.exiting(this.getClass().getName(), "getParser", result); //$NON-NLS-1$
252 protected void setNewKeystorePassword(String password) throws IOException,
253 UnsupportedCallbackException
255 if (password != null)
256 newStorePasswordChars = password.toCharArray();
260 Callback[] prompts = new Callback[1];
261 Callback[] errors = new Callback[1];
262 for (int i = 0; i < 3; i++)
263 if (prompt4NewPassword(getCallbackHandler(), prompts, errors))
269 throw new SecurityException(Messages.getString("StorePasswdCmd.19")); //$NON-NLS-1$
273 private boolean prompt4NewPassword(CallbackHandler handler,
274 Callback[] prompts, Callback[] errors)
275 throws IOException, UnsupportedCallbackException
277 // prompt user (1st time) to provide one
278 String p = Messages.getString("StorePasswdCmd.20"); //$NON-NLS-1$
279 PasswordCallback pcb = new PasswordCallback(p, false);
281 handler.handle(prompts);
282 char[] pwd1 = pcb.getPassword();
284 String ls = SystemProperties.getProperty("line.separator"); //$NON-NLS-1$
285 if (pwd1 == null || pwd1.length < 6)
287 String m = Messages.getString("StorePasswdCmd.21") + ls; //$NON-NLS-1$
288 errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
289 handler.handle(errors);
293 if (Arrays.equals(storePasswordChars, pwd1))
295 String m = Messages.getString("StorePasswdCmd.22") + ls; //$NON-NLS-1$
296 errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
297 handler.handle(errors);
301 // prompt user (2nd time) for confirmation
302 pcb = new PasswordCallback(Messages.getString("StorePasswdCmd.23"), false); //$NON-NLS-1$
304 handler.handle(prompts);
305 char[] pwd2 = pcb.getPassword();
307 if (! Arrays.equals(pwd1, pwd2))
309 String m = Messages.getString("StorePasswdCmd.24") + ls; //$NON-NLS-1$
310 errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
311 handler.handle(errors);
315 newStorePasswordChars = pwd2;