Merge from mainline.
[official-gcc.git] / libjava / classpath / tools / gnu / classpath / tools / keytool / KeyPasswdCmd.java
blob9dc7b8164c763dea6e5cbdbb8b417fd6c01755ca
1 /* KeyPasswdCmd.java -- The keypasswd 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)
9 any later version.
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
19 02110-1301 USA.
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
24 combination.
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.SystemProperties;
43 import java.io.IOException;
44 import java.security.Key;
45 import java.security.KeyStoreException;
46 import java.security.NoSuchAlgorithmException;
47 import java.security.UnrecoverableKeyException;
48 import java.security.cert.Certificate;
49 import java.security.cert.CertificateException;
50 import java.util.Arrays;
51 import java.util.logging.Logger;
53 import javax.security.auth.callback.Callback;
54 import javax.security.auth.callback.CallbackHandler;
55 import javax.security.auth.callback.PasswordCallback;
56 import javax.security.auth.callback.TextOutputCallback;
57 import javax.security.auth.callback.UnsupportedCallbackException;
59 /**
60 * The <b>-keypasswd</b> keytool command handler is used to change the password
61 * protecting the private key associated to a designated alias.
62 * <p>
63 * Possible options for this command are:
64 * <p>
65 * <dl>
66 * <dt>-alias ALIAS</dt>
67 * <dd>Every entry, be it a <i>Key Entry</i> or a <i>Trusted
68 * Certificate</i>, in a key store is uniquely identified by a user-defined
69 * <i>Alias</i> string. Use this option to specify the <i>Alias</i> to use
70 * when referring to an entry in the key store. Unless specified otherwise,
71 * a default value of <code>mykey</code> shall be used when this option is
72 * omitted from the command line.
73 * <p></dd>
75 * <dt>-keypass PASSWORD</dt>
76 * <dd>Use this option to specify the password which the tool will use to
77 * unlock the <i>Key Entry</i> associated with the designated <i>Alias</i>.
78 * <p>
79 * If this option is omitted, the tool will first attempt to unlock the
80 * <i>Key Entry</i> using the same password protecting the key store. If
81 * this fails, you will then be prompted to provide a password.
82 * <p></dd>
84 * <dt>-new PASSWORD</dt>
85 * <dd>The new, and different, password which will be used to protect the
86 * private key material of the designated Key Entry.
87 * <p></dd>
89 * <dt>-storetype STORE_TYP}</dt>
90 * <dd>Use this option to specify the type of the key store to use. The
91 * default value, if this option is omitted, is that of the property
92 * <code>keystore.type</code> in the security properties file, which is
93 * obtained by invoking the {@link java.security.KeyStore#getDefaultType()}
94 * static method.
95 * <p></dd>
97 * <dt>-keystore URL</dt>
98 * <dd>Use this option to specify the location of the key store to use.
99 * The default value is a file {@link java.net.URL} referencing the file
100 * named <code>.keystore</code> located in the path returned by the call to
101 * {@link java.lang.System#getProperty(String)} using <code>user.home</code>
102 * as argument.
103 * <p>
104 * If a URL was specified, but was found to be malformed --e.g. missing
105 * protocol element-- the tool will attempt to use the URL value as a file-
106 * name (with absolute or relative path-name) of a key store --as if the
107 * protocol was <code>file:</code>.
108 * <p></dd>
110 * <dt>-storepass PASSWORD</dt>
111 * <dd>Use this option to specify the password protecting the key store. If
112 * this option is omitted from the command line, you will be prompted to
113 * provide a password.
114 * <p></dd>
116 * <dt>-provider PROVIDER_CLASS_NAME</dt>
117 * <dd>A fully qualified class name of a Security Provider to add to the
118 * current list of Security Providers already installed in the JVM in-use.
119 * If a provider class is specified with this option, and was successfully
120 * added to the runtime --i.e. it was not already installed-- then the tool
121 * will attempt to removed this Security Provider before exiting.
122 * <p></dd>
124 * <dt>-v</dt>
125 * <dd>Use this option to enable more verbose output.</dd>
126 * </dl>
128 class KeyPasswdCmd extends Command
130 private static final Logger log = Logger.getLogger(KeyPasswdCmd.class.getName());
131 private String _alias;
132 private String _password;
133 private String _newPassword;
134 private String _ksType;
135 private String _ksURL;
136 private String _ksPassword;
137 private String _providerClassName;
138 private char[] newPasswordChars;
140 // default 0-arguments constructor
142 // public setters -----------------------------------------------------------
144 /** @param alias the alias to use. */
145 public void setAlias(String alias)
147 this._alias = alias;
150 /** @param password the existing (private) key password to use. */
151 public void setKeypass(String password)
153 this._password = password;
156 /** @param password the new (private) key password to use. */
157 public void setNew(String password)
159 this._newPassword = password;
162 /** @param type the key-store type to use. */
163 public void setStoretype(String type)
165 this._ksType = type;
168 /** @param url the key-store URL to use. */
169 public void setKeystore(String url)
171 this._ksURL = url;
174 /** @param password the key-store password to use. */
175 public void setStorepass(String password)
177 this._ksPassword = password;
180 /** @param className a security provider fully qualified class name to use. */
181 public void setProvider(String className)
183 this._providerClassName = className;
186 // life-cycle methods -------------------------------------------------------
188 int processArgs(String[] args, int i)
190 int limit = args.length;
191 String opt;
192 while (++i < limit)
194 opt = args[i];
195 log.finest("args[" + i + "]=" + opt); //$NON-NLS-1$ //$NON-NLS-2$
196 if (opt == null || opt.length() == 0)
197 continue;
199 if ("-alias".equals(opt)) // -alias ALIAS //$NON-NLS-1$
200 _alias = args[++i];
201 else if ("-keypass".equals(opt)) // -keypass PASSWORD //$NON-NLS-1$
202 _password = args[++i];
203 else if ("-new".equals(opt)) // -new PASSWORD //$NON-NLS-1$
204 _newPassword = args[++i];
205 else if ("-storetype".equals(opt)) // -storetype STORE_TYPE //$NON-NLS-1$
206 _ksType = args[++i];
207 else if ("-keystore".equals(opt)) // -keystore URL //$NON-NLS-1$
208 _ksURL = args[++i];
209 else if ("-storepass".equals(opt)) // -storepass PASSWORD //$NON-NLS-1$
210 _ksPassword = args[++i];
211 else if ("-provider".equals(opt)) // -provider PROVIDER_CLASS_NAME //$NON-NLS-1$
212 _providerClassName = args[++i];
213 else if ("-v".equals(opt)) //$NON-NLS-1$
214 verbose = true;
215 else
216 break;
219 return i;
222 void setup() throws Exception
224 setKeyStoreParams(_providerClassName, _ksType, _ksPassword, _ksURL);
225 setAliasParam(_alias);
226 setKeyPasswordNoPrompt(_password);
227 // setNewKeyPassword(_newPassword);
229 log.finer("-keypasswd handler will use the following options:"); //$NON-NLS-1$
230 log.finer(" -alias=" + alias); //$NON-NLS-1$
231 log.finer(" -keypass=" + _password); //$NON-NLS-1$
232 log.finer(" -new=" + _newPassword); //$NON-NLS-1$
233 log.finer(" -storetype=" + storeType); //$NON-NLS-1$
234 log.finer(" -keystore=" + storeURL); //$NON-NLS-1$
235 log.finer(" -storepass=" + String.valueOf(storePasswordChars)); //$NON-NLS-1$
236 log.finer(" -provider=" + provider); //$NON-NLS-1$
237 log.finer(" -v=" + verbose); //$NON-NLS-1$
240 void start() throws KeyStoreException, NoSuchAlgorithmException, IOException,
241 UnsupportedCallbackException, UnrecoverableKeyException,
242 CertificateException
244 log.entering(this.getClass().getName(), "start"); //$NON-NLS-1$
246 // 1. get the key entry and certificate chain associated to alias
247 Key privateKey = getAliasPrivateKey();
248 Certificate[] chain = store.getCertificateChain(alias);
250 // 2. replace the old entry
251 setNewKeyPassword(_newPassword);
252 store.setKeyEntry(alias, privateKey, newPasswordChars, chain);
254 // 3. persist the key store
255 saveKeyStore();
257 log.exiting(this.getClass().getName(), "start"); //$NON-NLS-1$
260 // own methods --------------------------------------------------------------
263 * Set the new password to use for protecting Alias's private key.
265 * @param password the new key password. if <code>null</code> prompt the
266 * user to provide one. When prompting, the password is entered twice
267 * and compared for a match.
268 * @throws IOException if an I/O related exception occurs during the process.
269 * @throws UnsupportedCallbackException if no implementation of a password
270 * callback handler was found.
272 private void setNewKeyPassword(String password) throws IOException,
273 UnsupportedCallbackException
275 if (password != null)
276 newPasswordChars = password.toCharArray();
277 else
279 boolean ok = false;
280 Callback[] prompts = new Callback[1];
281 Callback[] errors = new Callback[1];
282 for (int i = 0; i < 3; i++)
283 if (prompt4NewPassword(getCallbackHandler(), prompts, errors))
285 ok = true;
286 break;
288 if (! ok)
289 throw new SecurityException(Messages.getString("StorePasswdCmd.19")); //$NON-NLS-1$
293 private boolean prompt4NewPassword(CallbackHandler handler,
294 Callback[] prompts, Callback[] errors)
295 throws IOException, UnsupportedCallbackException
297 // prompt user (1st time) to provide one
298 String p = Messages.getFormattedString("KeyPasswdCmd.24", alias); //$NON-NLS-1$
299 PasswordCallback pcb = new PasswordCallback(p, false);
300 prompts[0] = pcb;
301 handler.handle(prompts);
302 char[] pwd1 = pcb.getPassword();
303 pcb.clearPassword();
304 String ls = SystemProperties.getProperty("line.separator"); //$NON-NLS-1$
305 if (pwd1 == null || pwd1.length < 6)
307 String m = Messages.getString("StorePasswdCmd.21") + ls; //$NON-NLS-1$
308 errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
309 handler.handle(errors);
310 return false;
313 if (Arrays.equals(keyPasswordChars, pwd1))
315 String m = Messages.getString("StorePasswdCmd.22") + ls; //$NON-NLS-1$
316 errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
317 handler.handle(errors);
318 return false;
321 // prompt user (2nd time) for confirmation
322 p = Messages.getFormattedString("KeyPasswdCmd.28", alias); //$NON-NLS-1$
323 pcb = new PasswordCallback(p, false);
324 prompts[0] = pcb;
325 handler.handle(prompts);
326 char[] pwd2 = pcb.getPassword();
327 pcb.clearPassword();
328 if (! Arrays.equals(pwd1, pwd2))
330 String m = Messages.getString("StorePasswdCmd.24") + ls; //$NON-NLS-1$
331 errors[0] = new TextOutputCallback(TextOutputCallback.ERROR, m);
332 handler.handle(errors);
333 return false;
336 newPasswordChars = pwd2;
337 return true;