OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [tools/] [gnu/] [classpath/] [tools/] [keytool/] [Command.java] - Blame information for rev 779

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 779 jeremybenn
/* Command.java -- Abstract implementation of a keytool command handler
2
   Copyright (C) 2006 Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
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.
10
 
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.
15
 
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.
20
 
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.
25
 
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. */
37
 
38
 
39
package gnu.classpath.tools.keytool;
40
 
41
import gnu.classpath.Configuration;
42
import gnu.classpath.SystemProperties;
43
import gnu.classpath.tools.common.CallbackUtil;
44
import gnu.classpath.tools.common.ProviderUtil;
45
import gnu.classpath.tools.common.SecurityProviderInfo;
46
import gnu.classpath.tools.getopt.Parser;
47
import gnu.java.security.OID;
48
import gnu.java.security.Registry;
49
import gnu.java.security.der.BitString;
50
import gnu.java.security.der.DER;
51
import gnu.java.security.der.DERReader;
52
import gnu.java.security.der.DERValue;
53
import gnu.java.security.der.DERWriter;
54
import gnu.java.security.hash.IMessageDigest;
55
import gnu.java.security.hash.MD5;
56
import gnu.java.security.hash.Sha160;
57
import gnu.java.security.util.Util;
58
import gnu.java.security.x509.X500DistinguishedName;
59
 
60
import java.io.ByteArrayOutputStream;
61
import java.io.File;
62
import java.io.FileInputStream;
63
import java.io.FileNotFoundException;
64
import java.io.FileOutputStream;
65
import java.io.IOException;
66
import java.io.InputStream;
67
import java.io.OutputStream;
68
import java.io.PrintWriter;
69
import java.math.BigInteger;
70
import java.net.URL;
71
import java.net.URLConnection;
72
import java.security.InvalidKeyException;
73
import java.security.InvalidParameterException;
74
import java.security.Key;
75
import java.security.KeyPairGenerator;
76
import java.security.KeyStore;
77
import java.security.KeyStoreException;
78
import java.security.NoSuchAlgorithmException;
79
import java.security.PrivateKey;
80
import java.security.Provider;
81
import java.security.PublicKey;
82
import java.security.Signature;
83
import java.security.SignatureException;
84
import java.security.UnrecoverableKeyException;
85
import java.security.cert.Certificate;
86
import java.security.cert.CertificateEncodingException;
87
import java.security.cert.CertificateException;
88
import java.security.cert.X509Certificate;
89
import java.security.interfaces.DSAKey;
90
import java.security.interfaces.RSAKey;
91
import java.util.ArrayList;
92
import java.util.Date;
93
import java.util.logging.Logger;
94
import java.util.prefs.Preferences;
95
 
96
import javax.security.auth.callback.Callback;
97
import javax.security.auth.callback.CallbackHandler;
98
import javax.security.auth.callback.NameCallback;
99
import javax.security.auth.callback.PasswordCallback;
100
import javax.security.auth.callback.UnsupportedCallbackException;
101
 
102
/**
103
 * A base class of the keytool command to facilitate implementation of concrete
104
 * keytool Handlers.
105
 */
106
abstract class Command
107
{
108
  // Fields and constants -----------------------------------------------------
109
 
110
  private static final Logger log = Logger.getLogger(Command.class.getName());
111
  /** Default value for the ALIAS argument. */
112
  private static final String DEFAULT_ALIAS = "mykey"; //$NON-NLS-1$
113
  /** Default algorithm for key-pair generation. */
114
  private static final String DEFAULT_KEY_ALGORITHM = "DSA"; //$NON-NLS-1$
115
  /** Default DSA digital signature algorithm to use with DSA keys. */
116
  private static final String DSA_SIGNATURE_ALGORITHM = "SHA1withDSA"; //$NON-NLS-1$
117
  /** Default RSA digital signature algorithm to use with RSA keys. */
118
  private static final String RSA_SIGNATURE_ALGORITHM = "MD5withRSA"; //$NON-NLS-1$
119
  /** Default validity (in days) of newly generated certificates. */
120
  private static final int DEFAULT_VALIDITY = 90;
121
  /** OID of SHA1withDSA signature algorithm as stated in RFC-2459. */
122
  protected static final OID SHA1_WITH_DSA = new OID("1.2.840.10040.4.3"); //$NON-NLS-1$
123
  /** OID of MD2withRSA signature algorithm as stated in RFC-2459. */
124
  private static final OID MD2_WITH_RSA = new OID("1.2.840.113549.1.1.2"); //$NON-NLS-1$
125
  /** OID of MD5withRSA signature algorithm as stated in RFC-2459. */
126
  private static final OID MD5_WITH_RSA = new OID("1.2.840.113549.1.1.4"); //$NON-NLS-1$
127
  /** OID of SHA1withRSA signature algorithm as stated in RFC-2459. */
128
  private static final OID SHA1_WITH_RSA = new OID("1.2.840.113549.1.1.5"); //$NON-NLS-1$
129
  /** Number of milliseconds in one day. */
130
  private static final long MILLIS_IN_A_DAY = 24 * 60 * 60 * 1000L;
131
 
132
  /** The Alias to use. */
133
  protected String alias;
134
  /** The password characters protecting a Key Entry. */
135
  protected char[] keyPasswordChars;
136
  /** A security provider to add. */
137
  protected Provider provider;
138
  /** The key store type. */
139
  protected String storeType;
140
  /** The password characters protecting the key store. */
141
  protected char[] storePasswordChars;
142
  /** The key store URL. */
143
  protected URL storeURL;
144
  /** The input stream from the key store URL. */
145
  protected InputStream storeStream;
146
  /** The key store instance to use. */
147
  protected KeyStore store;
148
  /** The output stream the concrete handler will use. */
149
  protected OutputStream outStream;
150
  /** Whether we are printing to System.out. */
151
  protected boolean systemOut;
152
  /** The key-pair generation algorithm instance to use. */
153
  protected KeyPairGenerator keyPairGenerator;
154
  /** The digital signature algorithm instance to use. */
155
  protected Signature signatureAlgorithm;
156
  /** Validity period, in number of days, to use when generating certificates. */
157
  protected int validityInDays;
158
  /** The input stream the concrete handler will use. */
159
  protected InputStream inStream;
160
  /** Whether verbose output is required or not. */
161
  protected boolean verbose;
162
 
163
  /** MD5 hash to use when generating certificate fingerprints. */
164
  private IMessageDigest md5 = new MD5();
165
  /** SHA1 hash to use when generating certificate fingerprints. */
166
  private IMessageDigest sha = new Sha160();
167
  /** The new position of a user-defined provider if it is not already installed. */
168
  private int providerNdx = -2;
169
  /** The callback handler to use when needing to interact with user. */
170
  private CallbackHandler handler;
171
  /** The shutdown hook. */
172
  private ShutdownHook shutdownThread;
173
 
174
  // Constructor(s) -----------------------------------------------------------
175
 
176
  protected Command()
177
  {
178
    super();
179
    shutdownThread = new ShutdownHook();
180
    Runtime.getRuntime().addShutdownHook(shutdownThread);
181
  }
182
 
183
  // Methods ------------------------------------------------------------------
184
 
185
  /**
186
   * A public method to allow using any keytool command handler programmatically
187
   * by using a JavaBeans style of parameter(s) initialization. The user is
188
   * assumed to have set individually the required options through their
189
   * respective setters before invoking this method.
190
   * <p>
191
   * If an exception is encountered during the processing of the command, this
192
   * implementation attempts to release any resources that may have been
193
   * allocated at the time the exception occurs, before re-throwing that
194
   * exception.
195
   *
196
   * @throws Exception if an exception occurs during the processing of this
197
   *           command. For a more comprehensive list of exceptions that may
198
   *           occur, see the documentation of the {@link #setup()} and
199
   *           {@link #start()} methods.
200
   */
201
  public void doCommand() throws Exception
202
  {
203
    try
204
      {
205
        setup();
206
        start();
207
      }
208
    finally
209
      {
210
        teardown();
211
        if (shutdownThread != null)
212
          Runtime.getRuntime().removeShutdownHook(shutdownThread);
213
      }
214
  }
215
 
216
  /**
217
   * @param flag whether to use, or not, more verbose output while processing
218
   *          the command.
219
   */
220
  public void setVerbose(String flag)
221
  {
222
    this.verbose = Boolean.valueOf(flag).booleanValue();
223
  }
224
 
225
  // life-cycle methods -------------------------------------------------------
226
 
227
  /**
228
   * Given a potential sub-array of options for this concrete handler, starting
229
   * at position <code>startIndex + 1</code>, potentially followed by other
230
   * commands and their options, this method sets up this concrete command
231
   * handler with its own options and returns the index of the first unprocessed
232
   * argument in the array.
233
   * <p>
234
   * The general contract of this method is that it is invoked with the
235
   * <code>startIndex</code> argument pointing to the keyword argument that
236
   * uniquelly identifies the command itself; e.g. <code>-genkey</code> or
237
   * <code>-list</code>, etc...
238
   *
239
   * @param args an array of options for this handler and possibly other
240
   *          commands and their options.
241
   * @return the remaining un-processed <code>args</code>.
242
   */
243
  String[] processArgs(String[] args)
244
  {
245
    if (Configuration.DEBUG)
246
      log.entering(this.getClass().getName(), "processArgs", args); //$NON-NLS-1$
247
    Parser cmdOptionsParser = getParser();
248
    String[] result = cmdOptionsParser.parse(args);
249
    if (Configuration.DEBUG)
250
      log.exiting(this.getClass().getName(), "processArgs", result); //$NON-NLS-1$
251
    return result;
252
  }
253
 
254
  /**
255
   * Initialize this concrete command handler for later invocation of the
256
   * {@link #start()} or {@link #doCommand()} methods.
257
   * <p>
258
   * Handlers usually initialize their local variables and resources within the
259
   * scope of this call.
260
   *
261
   * @throws IOException if an I/O related exception, such as opening an input
262
   *           stream, occurs during the execution of this method.
263
   * @throws UnsupportedCallbackException if a requested callback handler
264
   *           implementation was not found, or was found but encountered an
265
   *           exception during its processing.
266
   * @throws ClassNotFoundException if a designated security provider class was
267
   *           not found.
268
   * @throws IllegalAccessException no 0-arguments constructor for the
269
   *           designated security provider class was found.
270
   * @throws InstantiationException the designated security provider class is
271
   *           not instantiable.
272
   * @throws KeyStoreException if an exception occurs during the instantiation
273
   *           of the KeyStore.
274
   * @throws CertificateException if a certificate related exception, such as
275
   *           expiry, occurs during the loading of the KeyStore.
276
   * @throws NoSuchAlgorithmException if no current security provider can
277
   *           provide a needed algorithm referenced by the KeyStore or one of
278
   *           its Key Entries or Certificates.
279
   */
280
  abstract void setup() throws Exception;
281
 
282
  /**
283
   * Do the real work this handler is supposed to do.
284
   * <p>
285
   * The code in this (abstract) class throws a <i>Not implemented yet</i>
286
   * runtime exception. Concrete implementations MUST override this method.
287
   *
288
   * @throws CertificateException If no concrete implementation was found for a
289
   *           certificate Factory of a designated type. In this tool, the type
290
   *           is usually X.509 v1.
291
   * @throws KeyStoreException if a keys-store related exception occurs; e.g.
292
   *           the key store has not been initialized.
293
   * @throws IOException if an I/O related exception occurs during the process.
294
   * @throws SignatureException if a digital signature related exception occurs.
295
   * @throws InvalidKeyException if the genereated keys are invalid.
296
   * @throws UnrecoverableKeyException if the password used to unlock a key in
297
   *           the key store was invalid.
298
   * @throws NoSuchAlgorithmException if a concrete implementation of an
299
   *           algorithm used to store a Key Entry was not found at runtime.
300
   * @throws UnsupportedCallbackException if a requested callback handler
301
   *           implementation was not found, or was found but encountered an
302
   *           exception during its processing.
303
   */
304
  void start() throws Exception
305
  {
306
    throw new RuntimeException("Not implemented yet"); //$NON-NLS-1$
307
  }
308
 
309
  /**
310
   * Tear down the handler, releasing any resources which may have been
311
   * allocated at setup time.
312
   */
313
  void teardown()
314
  {
315
    if (Configuration.DEBUG)
316
      log.entering(this.getClass().getName(), "teardown"); //$NON-NLS-1$
317
    if (storeStream != null)
318
      try
319
        {
320
          storeStream.close();
321
        }
322
      catch (IOException ignored)
323
        {
324
          if (Configuration.DEBUG)
325
            log.fine("Exception while closing key store URL stream. Ignored: " //$NON-NLS-1$
326
                     + ignored);
327
        }
328
 
329
    if (outStream != null)
330
      {
331
        try
332
          {
333
            outStream.flush();
334
          }
335
        catch (IOException ignored)
336
          {
337
          }
338
 
339
        if (! systemOut)
340
          try
341
            {
342
              outStream.close();
343
            }
344
          catch (IOException ignored)
345
            {
346
            }
347
      }
348
 
349
    if (inStream != null)
350
      try
351
        {
352
          inStream.close();
353
        }
354
      catch (IOException ignored)
355
        {
356
        }
357
 
358
    if (providerNdx > 0)
359
      ProviderUtil.removeProvider(provider.getName());
360
 
361
    if (Configuration.DEBUG)
362
      log.exiting(this.getClass().getName(), "teardown"); //$NON-NLS-1$
363
  }
364
 
365
  // parameter setup and validation methods -----------------------------------
366
 
367
  /**
368
   * @return a {@link Parser} that knows how to parse the concrete command's
369
   *         options.
370
   */
371
  abstract Parser getParser();
372
 
373
  /**
374
   * Convenience method to setup the key store given its type, its password, its
375
   * location and portentially a specialized security provider.
376
   * <p>
377
   * Calls the method with the same name and 5 arguments passing
378
   * <code>false</code> to the first argument implying that no attempt to
379
   * create the keystore will be made if one was not found at the designated
380
   * location.
381
   *
382
   * @param className the potentially null fully qualified class name of a
383
   *          security provider to add at runtime, if no installed provider is
384
   *          able to provide a key store implementation of the desired type.
385
   * @param type the potentially null type of the key store to request from the
386
   *          key store factory.
387
   * @param password the potentially null password protecting the key store.
388
   * @param url the URL of the key store.
389
   */
390
  protected void setKeyStoreParams(String className, String type,
391
                                   String password, String url)
392
      throws IOException, UnsupportedCallbackException, KeyStoreException,
393
      NoSuchAlgorithmException, CertificateException
394
  {
395
    setKeyStoreParams(false, className, type, password, url);
396
  }
397
 
398
  /**
399
   * Convenience method to setup the key store given its type, its password, its
400
   * location and portentially a specialized security provider.
401
   *
402
   * @param createIfNotFound if <code>true</code> then create the keystore if
403
   *          it was not found; otherwise do not.
404
   * @param className the potentially null fully qualified class name of a
405
   *          security provider to add at runtime, if no installed provider is
406
   *          able to provide a key store implementation of the desired type.
407
   * @param type the potentially null type of the key store to request from the
408
   *          key store factory.
409
   * @param password the potentially null password protecting the key store.
410
   * @param url the URL of the key store.
411
   */
412
  protected void setKeyStoreParams(boolean createIfNotFound, String className,
413
                                   String type, String password, String url)
414
      throws IOException, UnsupportedCallbackException, KeyStoreException,
415
      NoSuchAlgorithmException, CertificateException
416
  {
417
    setProviderClassNameParam(className);
418
    setKeystoreTypeParam(type);
419
    setKeystoreURLParam(createIfNotFound, url, password);
420
  }
421
 
422
  /**
423
   * Set a security provider class name to (install and) use for key store
424
   * related operations.
425
   *
426
   * @param className the possibly null, fully qualified class name of a
427
   *          security provider to add, if it is not already installed, to the
428
   *          set of available providers.
429
   */
430
  private void setProviderClassNameParam(String className)
431
  {
432
    if (Configuration.DEBUG)
433
      log.fine("setProviderClassNameParam(" + className + ")"); //$NON-NLS-1$ //$NON-NLS-2$
434
    if (className != null && className.trim().length() > 0)
435
      {
436
        className = className.trim();
437
        SecurityProviderInfo spi = ProviderUtil.addProvider(className);
438
        provider = spi.getProvider();
439
        if (provider == null)
440
          {
441
            if (Configuration.DEBUG)
442
              log.fine("Was unable to add provider from class " + className);
443
          }
444
        providerNdx = spi.getPosition();
445
      }
446
  }
447
 
448
  /**
449
   * Set the type of key store to initialize, load and use.
450
   *
451
   * @param type the possibly null type of the key store. if this argument is
452
   *          <code>null</code>, or is an empty string, then this method sets
453
   *          the type of the key store to be the default value returned from
454
   *          the invocation of the {@link KeyStore#getDefaultType()} method.
455
   *          For GNU Classpath this is <i>gkr</i> which stands for the "Gnu
456
   *          KeyRing" specifications.
457
   */
458
  private void setKeystoreTypeParam(String type)
459
  {
460
    if (Configuration.DEBUG)
461
      log.fine("setKeystoreTypeParam(" + type + ")"); //$NON-NLS-1$ //$NON-NLS-2$
462
    if (type == null || type.trim().length() == 0)
463
      storeType = KeyStore.getDefaultType();
464
    else
465
      storeType = type.trim();
466
  }
467
 
468
  /**
469
   * Set the key password given a command line option argument. If no value was
470
   * present on the command line then prompt the user to provide one.
471
   *
472
   * @param password a possibly null key password gleaned from the command line.
473
   * @throws IOException if an I/O related exception occurs.
474
   * @throws UnsupportedCallbackException if no concrete implementation of a
475
   *         password callback was found at runtime.
476
   */
477
  protected void setKeyPasswordParam(String password) throws IOException,
478
      UnsupportedCallbackException
479
  {
480
    setKeyPasswordNoPrompt(password);
481
    if (keyPasswordChars == null)
482
      setKeyPasswordParam();
483
  }
484
 
485
  /**
486
   * Set the Alias to use when associating Key Entries and Trusted Certificates
487
   * in the current key store.
488
   *
489
   * @param name the possibly null alias to use. If this arfument is
490
   *          <code>null</code>, then a default value of <code>mykey</code>
491
   *          will be used instead.
492
   */
493
  protected void setAliasParam(String name)
494
  {
495
    alias = name == null ? DEFAULT_ALIAS : name.trim();
496
  }
497
 
498
  /**
499
   * Set the key password given a command line option argument.
500
   *
501
   * @param password a possibly null key password gleaned from the command line.
502
   */
503
  protected void setKeyPasswordNoPrompt(String password)
504
  {
505
    if (password != null)
506
      keyPasswordChars = password.toCharArray();
507
  }
508
 
509
  /**
510
   * Prompt the user to provide a password to protect a Key Entry in the key
511
   * store.
512
   *
513
   * @throws IOException if an I/O related exception occurs.
514
   * @throws UnsupportedCallbackException if no concrete implementation of a
515
   *           password callback was found at runtime.
516
   * @throws SecurityException if no password is available, even after prompting
517
   *           the user.
518
   */
519
  private void setKeyPasswordParam() throws IOException,
520
      UnsupportedCallbackException
521
  {
522
    String prompt = Messages.getFormattedString("Command.21", alias); //$NON-NLS-1$
523
    PasswordCallback pcb = new PasswordCallback(prompt, false);
524
    getCallbackHandler().handle(new Callback[] { pcb });
525
    keyPasswordChars = pcb.getPassword();
526
    pcb.clearPassword();
527
    if (keyPasswordChars == null)
528
      throw new SecurityException(Messages.getString("Command.23")); //$NON-NLS-1$
529
  }
530
 
531
  private void setKeystorePasswordParam(String password) throws IOException,
532
      UnsupportedCallbackException
533
  {
534
    if (password != null)
535
      storePasswordChars = password.toCharArray();
536
    else // ask the user to provide one
537
      {
538
        String prompt = Messages.getString("Command.24"); //$NON-NLS-1$
539
        PasswordCallback pcb = new PasswordCallback(prompt, false);
540
        getCallbackHandler().handle(new Callback[] { pcb });
541
        storePasswordChars = pcb.getPassword();
542
        pcb.clearPassword();
543
      }
544
  }
545
 
546
  /**
547
   * Set the key store URL to use.
548
   *
549
   * @param createIfNotFound when <code>true</code> an attempt to create a
550
   *          keystore at the designated location will be made. If
551
   *          <code>false</code> then no file creation is carried out, which
552
   *          may cause an exception to be thrown later.
553
   * @param url the full, or partial, URL to the keystore location.
554
   * @param password an eventually null string to use when loading the keystore.
555
   * @throws IOException
556
   * @throws KeyStoreException
557
   * @throws UnsupportedCallbackException
558
   * @throws NoSuchAlgorithmException
559
   * @throws CertificateException
560
   */
561
  private void setKeystoreURLParam(boolean createIfNotFound, String url,
562
                                     String password) throws IOException,
563
      KeyStoreException, UnsupportedCallbackException, NoSuchAlgorithmException,
564
      CertificateException
565
  {
566
    if (Configuration.DEBUG)
567
      log.fine("setKeystoreURLParam(" + url + ")"); //$NON-NLS-1$ //$NON-NLS-2$
568
    if (url == null || url.trim().length() == 0)
569
      {
570
        String userHome = SystemProperties.getProperty("user.home"); //$NON-NLS-1$
571
        if (userHome == null || userHome.trim().length() == 0)
572
          throw new InvalidParameterException(Messages.getString("Command.36")); //$NON-NLS-1$
573
 
574
        url = userHome.trim() + "/.keystore"; //$NON-NLS-1$
575
        // if it does not exist create it if required
576
        if (createIfNotFound)
577
          new File(url).createNewFile();
578
        url = "file:" + url; //$NON-NLS-1$
579
      }
580
    else
581
      {
582
        url = url.trim();
583
        if (url.indexOf(":") == -1) // if it does not exist create it //$NON-NLS-1$
584
          {
585
            if (createIfNotFound)
586
              new File(url).createNewFile();
587
          }
588
        url = "file:" + url; //$NON-NLS-1$
589
      }
590
 
591
    boolean newKeyStore = false;
592
    storeURL = new URL(url);
593
    storeStream = storeURL.openStream();
594
    if (storeStream.available() == 0)
595
      {
596
        if (Configuration.DEBUG)
597
          log.fine("Store is empty. Will use <null> when loading, to create it"); //$NON-NLS-1$
598
        newKeyStore = true;
599
      }
600
 
601
    try
602
      {
603
        store = KeyStore.getInstance(storeType);
604
      }
605
    catch (KeyStoreException x)
606
      {
607
        if (provider != null)
608
          throw x;
609
 
610
        if (Configuration.DEBUG)
611
          log.fine("Exception while getting key store with default provider(s)." //$NON-NLS-1$
612
                   + " Will prompt user for another provider and continue"); //$NON-NLS-1$
613
        String prompt = Messages.getString("Command.40"); //$NON-NLS-1$
614
        NameCallback ncb = new NameCallback(prompt);
615
        getCallbackHandler().handle(new Callback[] { ncb });
616
        String className = ncb.getName();
617
        setProviderClassNameParam(className); // we may have a Provider
618
        if (provider == null)
619
          {
620
            x.fillInStackTrace();
621
            throw x;
622
          }
623
        // try again
624
        store = KeyStore.getInstance(storeType, provider);
625
      }
626
 
627
    setKeystorePasswordParam(password);
628
 
629
    // now we have a KeyStore instance. load it
630
    // KeyStore public API claims: "...In order to create an empty keystore,
631
    // you pass null as the InputStream argument to the load method.
632
    if (newKeyStore)
633
      store.load(null, storePasswordChars);
634
    else
635
      store.load(storeStream, storePasswordChars);
636
 
637
    // close the stream
638
    try
639
    {
640
      storeStream.close();
641
      storeStream = null;
642
    }
643
    catch (IOException x)
644
    {
645
      if (Configuration.DEBUG)
646
        log.fine("Exception while closing the key store input stream: " + x //$NON-NLS-1$
647
                 + ". Ignore"); //$NON-NLS-1$
648
    }
649
  }
650
 
651
  protected void setOutputStreamParam(String fileName) throws SecurityException,
652
      IOException
653
  {
654
    if (fileName == null || fileName.trim().length() == 0)
655
      {
656
        outStream = System.out;
657
        systemOut = true;
658
      }
659
    else
660
      {
661
        fileName = fileName.trim();
662
        File outFile = new File(fileName);
663
        if (! outFile.exists())
664
          {
665
            boolean ok = outFile.createNewFile();
666
            if (!ok)
667
              throw new InvalidParameterException(Messages.getFormattedString("Command.19", //$NON-NLS-1$
668
                                                                              fileName));
669
          }
670
        else
671
          {
672
            if (! outFile.isFile())
673
              throw new InvalidParameterException(Messages.getFormattedString("Command.42", //$NON-NLS-1$
674
                                                                              fileName));
675
            if (! outFile.canWrite())
676
              throw new InvalidParameterException(Messages.getFormattedString("Command.44", //$NON-NLS-1$
677
                                                                              fileName));
678
          }
679
        outStream = new FileOutputStream(outFile);
680
      }
681
  }
682
 
683
  protected void setInputStreamParam(String fileName)
684
      throws FileNotFoundException
685
  {
686
    if (fileName == null || fileName.trim().length() == 0)
687
      inStream = System.in;
688
    else
689
      {
690
        fileName = fileName.trim();
691
        File inFile = new File(fileName);
692
        if (! (inFile.exists() && inFile.isFile() && inFile.canRead()))
693
          throw new InvalidParameterException(Messages.getFormattedString("Command.46", //$NON-NLS-1$
694
                                                                          fileName));
695
        inStream = new FileInputStream(inFile);
696
      }
697
  }
698
 
699
  /**
700
   * Set both the key-pair generation algorithm, and the digital signature
701
   * algorithm instances to use when generating new entries.
702
   *
703
   * @param kpAlg the possibly null name of a key-pair generator algorithm.
704
   *          if this argument is <code>null</code> or is an empty string, the
705
   *          "DSS" algorithm will be used.
706
   * @param sigAlg the possibly null name of a digital signature algorithm.
707
   *          If this argument is <code>null</code> or is an empty string, this
708
   *          method uses the "SHA1withDSA" (Digital Signature Standard, a.k.a.
709
   *          DSA, with the Secure Hash Algorithm function) as the default
710
   *          algorithm if, and only if, the key-pair generation algorithm ends
711
   *          up being "DSS"; otherwise, if the key-pair generation algorithm
712
   *          was "RSA", then the "MD5withRSA" signature algorithm will be used.
713
   *          If the key-pair generation algorithm is neither "DSS" (or its
714
   *          alias "DSA"), nor is it "RSA", then an exception is thrown.
715
   * @throws NoSuchAlgorithmException if no concrete implementation of the
716
   *           designated algorithm is available.
717
   */
718
  protected void setAlgorithmParams(String kpAlg, String sigAlg)
719
      throws NoSuchAlgorithmException
720
  {
721
    if (kpAlg == null || kpAlg.trim().length() == 0)
722
      kpAlg = DEFAULT_KEY_ALGORITHM;
723
    else
724
      kpAlg = kpAlg.trim().toLowerCase();
725
 
726
    keyPairGenerator = KeyPairGenerator.getInstance(kpAlg);
727
 
728
    if (sigAlg == null || sigAlg.trim().length() == 0)
729
      if (kpAlg.equalsIgnoreCase(Registry.DSS_KPG)
730
          || kpAlg.equalsIgnoreCase(Registry.DSA_KPG))
731
        sigAlg = DSA_SIGNATURE_ALGORITHM;
732
      else if (kpAlg.equalsIgnoreCase(Registry.RSA_KPG))
733
        sigAlg = RSA_SIGNATURE_ALGORITHM;
734
      else
735
        throw new IllegalArgumentException(
736
            Messages.getFormattedString("Command.20", //$NON-NLS-1$
737
                                        new String[] { sigAlg, kpAlg }));
738
    else
739
      sigAlg = sigAlg.trim().toLowerCase();
740
 
741
    signatureAlgorithm = Signature.getInstance(sigAlg);
742
  }
743
 
744
  /**
745
   * Set the signature algorithm to use when digitally signing private keys,
746
   * certificates, etc...
747
   * <p>
748
   * If the designated algorithm name is <code>null</code> or is an empty
749
   * string, this method checks the private key (the second argument) and based
750
   * on its type decides which algorithm to use. The keytool public
751
   * specification states that if the private key is a DSA key, then the
752
   * signature algorithm will be <code>SHA1withDSA</code>, otherwise if it is
753
   * an RSA private key, then the signature algorithm will be
754
   * <code>MD5withRSA</code>. If the private key is neither a private DSA nor
755
   * a private RSA key, then this method throws an
756
   * {@link IllegalArgumentException}.
757
   *
758
   * @param algorithm the possibly null name of a digital signature algorithm.
759
   * @param privateKey an instance of a private key to use as a fal-back option
760
   *          when <code>algorithm</code> is invalid.
761
   * @throws NoSuchAlgorithmException if no concrete implementation of the
762
   *           designated, or default, signature algorithm is available.
763
   */
764
  protected void setSignatureAlgorithmParam(String algorithm, Key privateKey)
765
      throws NoSuchAlgorithmException
766
  {
767
    if (algorithm == null || algorithm.trim().length() == 0)
768
      if (privateKey instanceof DSAKey)
769
        algorithm = DSA_SIGNATURE_ALGORITHM;
770
      else if (privateKey instanceof RSAKey)
771
        algorithm = RSA_SIGNATURE_ALGORITHM;
772
      else
773
        throw new InvalidParameterException(Messages.getString("Command.48")); //$NON-NLS-1$
774
    else
775
      algorithm = algorithm.trim();
776
 
777
    signatureAlgorithm = Signature.getInstance(algorithm);
778
  }
779
 
780
  /**
781
   * Set the validity period, in number of days, to use when issuing new
782
   * certificates.
783
   *
784
   * @param days the number of days, as a string, the generated certificate will
785
   *          be valid for, starting from today's date. if this argument is
786
   *          <code>null</code>, a default value of <code>90</code> days
787
   *          will be used.
788
   * @throws NumberFormatException if the designated string is not a decimal
789
   *           integer.
790
   * @throws InvalidParameterException if the integer value of the non-null
791
   *           string is not greater than zero.
792
   */
793
  protected void setValidityParam(String days)
794
  {
795
    if (days == null || days.trim().length() == 0)
796
      validityInDays = DEFAULT_VALIDITY;
797
    else
798
      {
799
        days = days.trim();
800
        validityInDays = Integer.parseInt(days);
801
        if (validityInDays < 1)
802
          throw new InvalidParameterException(Messages.getString("Command.51")); //$NON-NLS-1$
803
      }
804
  }
805
 
806
  /**
807
   * RFC-2459 (http://rfc.net/rfc2459.html) fully describes the structure and
808
   * semantics of X.509 certificates. The ASN.1 structures below are gleaned
809
   * from that reference.
810
   *
811
   * <pre>
812
   *  Certificate ::= SEQUENCE {
813
   *    tbsCertificate      TBSCertificate,
814
   *    signatureAlgorithm  AlgorithmIdentifier,
815
   *    signatureValue      BIT STRING
816
   *  }
817
   *
818
   *  TBSCertificate ::= SEQUENCE {
819
   *    version           [0] EXPLICIT Version DEFAULT v1,
820
   *    serialNumber          CertificateSerialNumber,
821
   *    signature             AlgorithmIdentifier,
822
   *    issuer                Name,
823
   *    validity              Validity,
824
   *    subject               Name,
825
   *    subjectPublicKeyInfo  SubjectPublicKeyInfo
826
   *  }
827
   *
828
   *  Version ::= INTEGER { v1(0), v2(1), v3(2) }
829
   *
830
   *  CertificateSerialNumber ::= INTEGER
831
   *
832
   *  Validity ::= SEQUENCE {
833
   *    notBefore  Time,
834
   *    notAfter   Time
835
   *  }
836
   *
837
   *  Time ::= CHOICE {
838
   *    utcTime      UTCTime,
839
   *    generalTime  GeneralizedTime
840
   *  }
841
   *
842
   *  UniqueIdentifier ::= BIT STRING
843
   *
844
   *  SubjectPublicKeyInfo ::= SEQUENCE {
845
   *    algorithm         AlgorithmIdentifier,
846
   *    subjectPublicKey  BIT STRING
847
   *  }
848
   * </pre>
849
   *
850
   * @param distinguishedName the X.500 Distinguished Name to use as both the
851
   *          Issuer and Subject of the self-signed certificate to generate.
852
   * @param publicKey the public key of the issuer/subject.
853
   * @param privateKey the private key of the issuer/signer.
854
   * @return the DER encoded form of a self-signed X.509 v1 certificate.
855
   * @throws IOException If an I/O related exception occurs during the process.
856
   * @throws SignatureException If a digital signature related exception occurs.
857
   * @throws InvalidKeyException if the designated private key is invalid.
858
   * @throws InvalidParameterException if the concrete signature algorithm does
859
   *           not know its name, no OID is known/supported for that name, or we
860
   *           were unable to match the name to a known string for which we can
861
   *           use a standard OID.
862
   */
863
  protected byte[] getSelfSignedCertificate(X500DistinguishedName distinguishedName,
864
                                            PublicKey publicKey,
865
                                            PrivateKey privateKey)
866
      throws IOException, SignatureException, InvalidKeyException
867
  {
868
    if (Configuration.DEBUG)
869
      log.entering(this.getClass().getName(), "getSelfSignedCertificate", //$NON-NLS-1$
870
                   new Object[] { distinguishedName, publicKey, privateKey });
871
    byte[] versionBytes = new DERValue(DER.INTEGER, BigInteger.ZERO).getEncoded();
872
    DERValue derVersion = new DERValue(DER.CONSTRUCTED | DER.CONTEXT | 0,
873
                                       versionBytes.length, versionBytes, null);
874
 
875
    // NOTE (rsn): the next 3 lines should be atomic but they're not.
876
    Preferences prefs = Preferences.systemNodeForPackage(this.getClass());
877
    int lastSerialNumber = prefs.getInt(Main.LAST_SERIAL_NUMBER, 0) + 1;
878
    prefs.putInt(Main.LAST_SERIAL_NUMBER, lastSerialNumber);
879
    DERValue derSerialNumber = new DERValue(DER.INTEGER,
880
                                            BigInteger.valueOf(lastSerialNumber));
881
 
882
    OID signatureID = getSignatureAlgorithmOID();
883
    DERValue derSignatureID = new DERValue(DER.OBJECT_IDENTIFIER, signatureID);
884
    ArrayList signature = new ArrayList(1);
885
    signature.add(derSignatureID);
886
    // rfc-2459 states the following:
887
    //
888
    // for the DSA signature:
889
    // ...Where the id-dsa-with-sha1 algorithm identifier appears as the
890
    // algorithm field in an AlgorithmIdentifier, the encoding shall omit
891
    // the parameters field.  That is, the AlgorithmIdentifier shall be a
892
    // SEQUENCE of one component - the OBJECT IDENTIFIER id-dsa-with-sha1.
893
    //
894
    // for RSA signatures:
895
    // ...When any of these three OIDs (i.e. xxxWithRSAEncryption) appears
896
    // within the ASN.1 type AlgorithmIdentifier, the parameters component of
897
    // that type shall be the ASN.1 type NULL.
898
    if (! signatureID.equals(SHA1_WITH_DSA))
899
      signature.add(new DERValue(DER.NULL, null));
900
 
901
    DERValue derSignature = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
902
                                         signature);
903
 
904
    DERValue derIssuer = new DERReader(distinguishedName.getDer()).read();
905
 
906
    long notBefore = System.currentTimeMillis();
907
    long notAfter = notBefore + validityInDays * MILLIS_IN_A_DAY;
908
 
909
    ArrayList validity = new ArrayList(2);
910
    validity.add(new DERValue(DER.UTC_TIME, new Date(notBefore)));
911
    validity.add(new DERValue(DER.UTC_TIME, new Date(notAfter)));
912
    DERValue derValidity = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
913
                                        validity);
914
 
915
    // for a self-signed certificate subject and issuer are identical
916
    DERValue derSubject = derIssuer;
917
 
918
    DERValue derSubjectPublicKeyInfo = new DERReader(publicKey.getEncoded()).read();
919
 
920
    ArrayList tbsCertificate = new ArrayList(7);
921
    tbsCertificate.add(derVersion);
922
    tbsCertificate.add(derSerialNumber);
923
    tbsCertificate.add(derSignature);
924
    tbsCertificate.add(derIssuer);
925
    tbsCertificate.add(derValidity);
926
    tbsCertificate.add(derSubject);
927
    tbsCertificate.add(derSubjectPublicKeyInfo);
928
    DERValue derTBSCertificate = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
929
                                              tbsCertificate);
930
 
931
    // The 'signature' field MUST contain the same algorithm identifier as the
932
    // 'signatureAlgorithm' field in the sequence Certificate.
933
    DERValue derSignatureAlgorithm = derSignature;
934
 
935
    signatureAlgorithm.initSign(privateKey);
936
    signatureAlgorithm.update(derTBSCertificate.getEncoded());
937
    byte[] sigBytes = signatureAlgorithm.sign();
938
    DERValue derSignatureValue = new DERValue(DER.BIT_STRING,
939
                                              new BitString(sigBytes));
940
 
941
    ArrayList certificate = new ArrayList(3);
942
    certificate.add(derTBSCertificate);
943
    certificate.add(derSignatureAlgorithm);
944
    certificate.add(derSignatureValue);
945
    DERValue derCertificate = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE,
946
                                           certificate);
947
 
948
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
949
    DERWriter.write(baos, derCertificate);
950
    byte[] result = baos.toByteArray();
951
    if (Configuration.DEBUG)
952
      log.exiting(this.getClass().getName(), "getSelfSignedCertificate"); //$NON-NLS-1$
953
    return result;
954
  }
955
 
956
  /**
957
   * This method attempts to find, and return, an OID representing the digital
958
   * signature algorithm used to sign the certificate. The OIDs returned are
959
   * those described in RFC-2459. They are listed here for the sake of
960
   * completness.
961
   *
962
   * <pre>
963
   *  id-dsa-with-sha1 OBJECT IDENTIFIER ::= {
964
   *    iso(1) member-body(2) us(840) x9-57 (10040) x9cm(4) 3
965
   *  }
966
   *
967
   *  md2WithRSAEncryption OBJECT IDENTIFIER ::= {
968
   *    iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) 2
969
   *  }
970
   *
971
   *  md5WithRSAEncryption OBJECT IDENTIFIER ::= {
972
   *    iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) 4
973
   *  }
974
   *
975
   *  sha-1WithRSAEncryption OBJECT IDENTIFIER ::= {
976
   *    iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) 5
977
   *  }
978
   * </pre>
979
   *
980
   * <b>IMPORTANT</b>: This method checks the signature algorithm name against
981
   * (a) The GNU algorithm implementation's name, and (b) publicly referenced
982
   * names of the same algorithm. In other words this search is not
983
   * comprehensive and may fail for uncommon names of the same algorithms.
984
   *
985
   * @return the OID of the signature algorithm in use.
986
   * @throws InvalidParameterException if the concrete signature algorithm does
987
   *           not know its name, no OID is known/supported for that name, or we
988
   *           were unable to match the name to a known string for which we can
989
   *           return an OID.
990
   */
991
  protected OID getSignatureAlgorithmOID()
992
  {
993
    String algorithm = signatureAlgorithm.getAlgorithm();
994
    // if we already have a non-null signature then the name was valid.  the
995
    // only case where algorithm is invalid would be if the implementation is
996
    // flawed.  check anyway
997
    if (algorithm == null || algorithm.trim().length() == 0)
998
      throw new InvalidParameterException(Messages.getString("Command.52")); //$NON-NLS-1$
999
 
1000
    algorithm = algorithm.trim();
1001
    if (algorithm.equalsIgnoreCase(Registry.DSS_SIG)
1002
        || algorithm.equalsIgnoreCase("SHA1withDSA")) //$NON-NLS-1$
1003
      return SHA1_WITH_DSA;
1004
 
1005
    if (algorithm.equalsIgnoreCase(Registry.RSA_PKCS1_V1_5_SIG + "-" //$NON-NLS-1$
1006
                                   + Registry.MD2_HASH)
1007
        || algorithm.equalsIgnoreCase("MD2withRSA")) //$NON-NLS-1$
1008
      return MD2_WITH_RSA;
1009
 
1010
    if (algorithm.equalsIgnoreCase(Registry.RSA_PKCS1_V1_5_SIG + "-" //$NON-NLS-1$
1011
                                   + Registry.MD5_HASH)
1012
        || algorithm.equalsIgnoreCase("MD5withRSA") //$NON-NLS-1$
1013
        || algorithm.equalsIgnoreCase("rsa")) //$NON-NLS-1$
1014
      return MD5_WITH_RSA;
1015
 
1016
    if (algorithm.equalsIgnoreCase(Registry.RSA_PKCS1_V1_5_SIG + "-" //$NON-NLS-1$
1017
                                   + Registry.SHA160_HASH)
1018
        || algorithm.equalsIgnoreCase("SHA1withRSA")) //$NON-NLS-1$
1019
      return SHA1_WITH_RSA;
1020
 
1021
    throw new InvalidParameterException(Messages.getFormattedString("Command.60", //$NON-NLS-1$
1022
                                                                    algorithm));
1023
  }
1024
 
1025
  /**
1026
   * Saves the key store using the designated password. This operation is called
1027
   * by handlers if/when the key store password has changed, or amendements have
1028
   * been made to the contents of the store; e.g. addition of a new Key Entry or
1029
   * a Trusted Certificate.
1030
   *
1031
   * @param password the password protecting the key store.
1032
   * @throws IOException if an I/O related exception occurs during the process.
1033
   * @throws CertificateException if any of the certificates in the current key
1034
   *           store could not be persisted.
1035
   * @throws NoSuchAlgorithmException if a required data integrity algorithm
1036
   *           implementation was not found.
1037
   * @throws KeyStoreException if the key store has not been loaded previously.
1038
   */
1039
  protected void saveKeyStore(char[] password) throws IOException,
1040
      KeyStoreException, NoSuchAlgorithmException, CertificateException
1041
  {
1042
    if (Configuration.DEBUG)
1043
      log.entering(this.getClass().getName(), "saveKeyStore"); //$NON-NLS-1$
1044
    URLConnection con = storeURL.openConnection();
1045
    con.setDoOutput(true);
1046
    con.setUseCaches(false);
1047
    OutputStream out = con.getOutputStream();
1048
    if (verbose)
1049
      System.out.println(Messages.getFormattedString("Command.63", storeURL.getPath())); //$NON-NLS-1$
1050
 
1051
    store.store(out, password);
1052
    out.flush();
1053
    out.close();
1054
    if (Configuration.DEBUG)
1055
      log.exiting(this.getClass().getName(), "saveKeyStore"); //$NON-NLS-1$
1056
  }
1057
 
1058
  /**
1059
   * Convenience method. Calls the method with the same name passing it the
1060
   * same password characters used to initially load the key-store.
1061
   *
1062
   * @throws IOException if an I/O related exception occurs during the process.
1063
   * @throws KeyStoreException if the key store has not been loaded previously.
1064
   * @throws NoSuchAlgorithmException if a required data integrity algorithm
1065
   *           implementation was not found.
1066
   * @throws CertificateException if any of the certificates in the current key
1067
   *           store could not be persisted.
1068
   */
1069
  protected void saveKeyStore() throws IOException, KeyStoreException,
1070
      NoSuchAlgorithmException, CertificateException
1071
  {
1072
    saveKeyStore(storePasswordChars);
1073
  }
1074
 
1075
  /**
1076
   * Prints a human-readable form of the designated certificate to a designated
1077
   * {@link PrintWriter}.
1078
   *
1079
   * @param certificate the certificate to process.
1080
   * @param writer where to print it.
1081
   * @throws CertificateEncodingException if an exception occurs while obtaining
1082
   *           the DER encoded form <code>certificate</code>.
1083
   */
1084
  protected void printVerbose(Certificate certificate, PrintWriter writer)
1085
      throws CertificateEncodingException
1086
  {
1087
    X509Certificate x509 = (X509Certificate) certificate;
1088
    writer.println(Messages.getFormattedString("Command.66", x509.getSubjectDN())); //$NON-NLS-1$
1089
    writer.println(Messages.getFormattedString("Command.67", x509.getIssuerDN())); //$NON-NLS-1$
1090
    writer.println(Messages.getFormattedString("Command.68", x509.getSerialNumber())); //$NON-NLS-1$
1091
    writer.println(Messages.getFormattedString("Command.69", x509.getNotBefore())); //$NON-NLS-1$
1092
    writer.println(Messages.getFormattedString("Command.70", x509.getNotAfter())); //$NON-NLS-1$
1093
    writer.println(Messages.getString("Command.71")); //$NON-NLS-1$
1094
    byte[] derBytes = certificate.getEncoded();
1095
    writer.println(Messages.getFormattedString("Command.72", digest(md5, derBytes))); //$NON-NLS-1$
1096
    writer.println(Messages.getFormattedString("Command.73", digest(sha, derBytes))); //$NON-NLS-1$
1097
  }
1098
 
1099
  /**
1100
   * Convenience method. Prints a human-readable form of the designated
1101
   * certificate to <code>System.out</code>.
1102
   *
1103
   * @param certificate the certificate to process.
1104
   * @throws CertificateEncodingException if an exception occurs while obtaining
1105
   *           the DER encoded form <code>certificate</code>.
1106
   */
1107
  protected void printVerbose(Certificate certificate)
1108
      throws CertificateEncodingException
1109
  {
1110
    printVerbose(certificate, new PrintWriter(System.out, true));
1111
  }
1112
 
1113
  /**
1114
   * Digest the designated contents with MD5 and return a string representation
1115
   * suitable for use as a fingerprint; i.e. sequence of hexadecimal pairs of
1116
   * characters separated by a colon.
1117
   *
1118
   * @param contents the non-null contents to digest.
1119
   * @return a sequence of hexadecimal pairs of characters separated by colons.
1120
   */
1121
  protected String digestWithMD5(byte[] contents)
1122
  {
1123
    return digest(md5, contents);
1124
  }
1125
 
1126
  private String digest(IMessageDigest hash, byte[] encoded)
1127
  {
1128
    hash.update(encoded);
1129
    byte[] b = hash.digest();
1130
    StringBuilder sb = new StringBuilder().append(Util.toString(b, 0, 1));
1131
    for (int i = 1; i < b.length; i++)
1132
      sb.append(":").append(Util.toString(b, i, 1)); //$NON-NLS-1$
1133
 
1134
    String result = sb.toString();
1135
    return result;
1136
  }
1137
 
1138
  /**
1139
   * Ensure that the currently set Alias is contained in the currently set key
1140
   * store; otherwise throw an exception.
1141
   *
1142
   * @throws KeyStoreException if the keystore has not been loaded.
1143
   * @throws IllegalArgumentException if the currently set alias is not known to
1144
   *           the currently set key store.
1145
   */
1146
  protected void ensureStoreContainsAlias() throws KeyStoreException
1147
  {
1148
    if (! store.containsAlias(alias))
1149
      throw new IllegalArgumentException(Messages.getFormattedString("Command.75", //$NON-NLS-1$
1150
                                                                     alias));
1151
  }
1152
 
1153
  /**
1154
   * Ensure that the currently set Alias is associated with a Key Entry in the
1155
   * currently set key store; otherwise throw an exception.
1156
   *
1157
   * @throws KeyStoreException if the keystore has not been loaded.
1158
   * @throws SecurityException if the currently set alias is not a Key Entry in
1159
   *           the currently set key store.
1160
   */
1161
  protected void ensureAliasIsKeyEntry() throws KeyStoreException
1162
  {
1163
    if (! store.isKeyEntry(alias))
1164
      throw new SecurityException(Messages.getFormattedString("Command.77", //$NON-NLS-1$
1165
                                                              alias));
1166
  }
1167
 
1168
  protected Key getAliasPrivateKey() throws KeyStoreException,
1169
      NoSuchAlgorithmException, IOException, UnsupportedCallbackException,
1170
      UnrecoverableKeyException
1171
  {
1172
    ensureAliasIsKeyEntry();
1173
    Key result;
1174
    if (keyPasswordChars == null)
1175
      try
1176
        {
1177
          result = store.getKey(alias, storePasswordChars);
1178
          // it worked. assign to keyPasswordChars for later use
1179
          keyPasswordChars = storePasswordChars;
1180
        }
1181
      catch (UnrecoverableKeyException x)
1182
        {
1183
          // prompt the user to provide one
1184
          setKeyPasswordParam();
1185
          result = store.getKey(alias, keyPasswordChars);
1186
        }
1187
    else
1188
      result = store.getKey(alias, keyPasswordChars);
1189
 
1190
    return result;
1191
  }
1192
 
1193
  /**
1194
   * Return a CallbackHandler which uses the Console (System.in and System.out)
1195
   * for interacting with the user.
1196
   * <p>
1197
   * This method first finds all currently installed security providers capable
1198
   * of providing such service and then in turn attempts to instantiate the
1199
   * handler from those providers. As soon as one provider returns a non-null
1200
   * instance of the callback handler, the search stops and that instance is
1201
   * set to be used from now on.
1202
   * <p>
1203
   * If no installed providers were found, this method falls back on the GNU
1204
   * provider, by-passing the Security search mechanism. The default console
1205
   * callback handler implementation is
1206
   * {@link gnu.javax.security.auth.callback.ConsoleCallbackHandler}.
1207
   *
1208
   * @return a console-based {@link CallbackHandler}.
1209
   */
1210
  protected CallbackHandler getCallbackHandler()
1211
  {
1212
    if (handler == null)
1213
      handler = CallbackUtil.getConsoleHandler();
1214
 
1215
    return handler;
1216
  }
1217
 
1218
  // Inner class(es) ==========================================================
1219
 
1220
  private class ShutdownHook
1221
      extends Thread
1222
  {
1223
    public void run()
1224
    {
1225
      teardown();
1226
    }
1227
  }
1228
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.