1 /*
   2  * Copyright (c) 1997, 2017, Oracle and/or its affiliates. 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.security;
  27 
  28 import java.util.*;
  29 
  30 import java.security.spec.AlgorithmParameterSpec;
  31 
  32 import java.security.Provider.Service;
  33 
  34 import sun.security.jca.*;
  35 import sun.security.jca.GetInstance.Instance;
  36 import sun.security.util.Debug;
  37 
  38 /**
  39  * The KeyPairGenerator class is used to generate pairs of
  40  * public and private keys. Key pair generators are constructed using the
  41  * {@code getInstance} factory methods (static methods that
  42  * return instances of a given class).
  43  *
  44  * <p>A Key pair generator for a particular algorithm creates a public/private
  45  * key pair that can be used with this algorithm. It also associates
  46  * algorithm-specific parameters with each of the generated keys.
  47  *
  48  * <p>There are two ways to generate a key pair: in an algorithm-independent
  49  * manner, and in an algorithm-specific manner.
  50  * The only difference between the two is the initialization of the object:
  51  *
  52  * <ul>
  53  * <li><b>Algorithm-Independent Initialization</b>
  54  * <p>All key pair generators share the concepts of a keysize and a
  55  * source of randomness. The keysize is interpreted differently for different
  56  * algorithms (e.g., in the case of the <i>DSA</i> algorithm, the keysize
  57  * corresponds to the length of the modulus).
  58  * There is an
  59  * {@link #initialize(int, java.security.SecureRandom) initialize}
  60  * method in this KeyPairGenerator class that takes these two universally
  61  * shared types of arguments. There is also one that takes just a
  62  * {@code keysize} argument, and uses the {@code SecureRandom}
  63  * implementation of the highest-priority installed provider as the source
  64  * of randomness. (If none of the installed providers supply an implementation
  65  * of {@code SecureRandom}, a system-provided source of randomness is
  66  * used.)
  67  *
  68  * <p>Since no other parameters are specified when you call the above
  69  * algorithm-independent {@code initialize} methods, it is up to the
  70  * provider what to do about the algorithm-specific parameters (if any) to be
  71  * associated with each of the keys.
  72  *
  73  * <p>If the algorithm is the <i>DSA</i> algorithm, and the keysize (modulus
  74  * size) is 512, 768, 1024, or 2048, then the <i>Sun</i> provider uses a set of
  75  * precomputed values for the {@code p}, {@code q}, and
  76  * {@code g} parameters. If the modulus size is not one of the above
  77  * values, the <i>Sun</i> provider creates a new set of parameters. Other
  78  * providers might have precomputed parameter sets for more than just the
  79  * modulus sizes mentioned above. Still others might not have a list of
  80  * precomputed parameters at all and instead always create new parameter sets.
  81  *
  82  * <li><b>Algorithm-Specific Initialization</b>
  83  * <p>For situations where a set of algorithm-specific parameters already
  84  * exists (e.g., so-called <i>community parameters</i> in DSA), there are two
  85  * {@link #initialize(java.security.spec.AlgorithmParameterSpec)
  86  * initialize} methods that have an {@code AlgorithmParameterSpec}
  87  * argument. One also has a {@code SecureRandom} argument, while the
  88  * the other uses the {@code SecureRandom}
  89  * implementation of the highest-priority installed provider as the source
  90  * of randomness. (If none of the installed providers supply an implementation
  91  * of {@code SecureRandom}, a system-provided source of randomness is
  92  * used.)
  93  * </ul>
  94  *
  95  * <p>In case the client does not explicitly initialize the KeyPairGenerator
  96  * (via a call to an {@code initialize} method), each provider must
  97  * supply (and document) a default initialization.
  98  * For example, the <i>Sun</i> provider uses a default modulus size (keysize)
  99  * of 1024 bits for DSA key pairs.
 100  *
 101  * <p>Note that this class is abstract and extends from
 102  * {@code KeyPairGeneratorSpi} for historical reasons.
 103  * Application developers should only take notice of the methods defined in
 104  * this {@code KeyPairGenerator} class; all the methods in
 105  * the superclass are intended for cryptographic service providers who wish to
 106  * supply their own implementations of key pair generators.
 107  *
 108  * <p> Every implementation of the Java platform is required to support the
 109  * following standard {@code KeyPairGenerator} algorithms and keysizes in
 110  * parentheses:
 111  * <ul>
 112  * <li>{@code DiffieHellman} (1024, 2048, 4096)</li>
 113  * <li>{@code DSA} (1024, 2048)</li>
 114  * <li>{@code RSA} (1024, 2048, 4096)</li>
 115  * </ul>
 116  * These algorithms are described in the <a href=
 117  * "{@docRoot}/../specs/security/standard-names.html#keypairgenerator-algorithms">
 118  * KeyPairGenerator section</a> of the
 119  * Java Security Standard Algorithm Names Specification.
 120  * Consult the release documentation for your implementation to see if any
 121  * other algorithms are supported.
 122  *
 123  * @author Benjamin Renaud
 124  *
 125  * @see java.security.spec.AlgorithmParameterSpec
 126  */
 127 
 128 public abstract class KeyPairGenerator extends KeyPairGeneratorSpi {
 129 
 130     private static final Debug pdebug =
 131                         Debug.getInstance("provider", "Provider");
 132     private static final boolean skipDebug =
 133         Debug.isOn("engine=") && !Debug.isOn("keypairgenerator");
 134 
 135     private final String algorithm;
 136 
 137     // The provider
 138     Provider provider;
 139 
 140     /**
 141      * Creates a KeyPairGenerator object for the specified algorithm.
 142      *
 143      * @param algorithm the standard string name of the algorithm.
 144      * See the KeyPairGenerator section in the <a href=
 145      * "{@docRoot}/../specs/security/standard-names.html#keypairgenerator-algorithms">
 146      * Java Security Standard Algorithm Names Specification</a>
 147      * for information about standard algorithm names.
 148      */
 149     protected KeyPairGenerator(String algorithm) {
 150         this.algorithm = algorithm;
 151     }
 152 
 153     /**
 154      * Returns the standard name of the algorithm for this key pair generator.
 155      * See the KeyPairGenerator section in the <a href=
 156      * "{@docRoot}/../specs/security/standard-names.html#keypairgenerator-algorithms">
 157      * Java Security Standard Algorithm Names Specification</a>
 158      * for information about standard algorithm names.
 159      *
 160      * @return the standard string name of the algorithm.
 161      */
 162     public String getAlgorithm() {
 163         return this.algorithm;
 164     }
 165 
 166     private static KeyPairGenerator getInstance(Instance instance,
 167             String algorithm) {
 168         KeyPairGenerator kpg;
 169         if (instance.impl instanceof KeyPairGenerator) {
 170             kpg = (KeyPairGenerator)instance.impl;
 171         } else {
 172             KeyPairGeneratorSpi spi = (KeyPairGeneratorSpi)instance.impl;
 173             kpg = new Delegate(spi, algorithm);
 174         }
 175         kpg.provider = instance.provider;
 176 
 177         if (!skipDebug && pdebug != null) {
 178             pdebug.println("KeyPairGenerator." + algorithm +
 179                 " algorithm from: " + kpg.provider.getName());
 180         }
 181 
 182         return kpg;
 183     }
 184 
 185     /**
 186      * Returns a KeyPairGenerator object that generates public/private
 187      * key pairs for the specified algorithm.
 188      *
 189      * <p> This method traverses the list of registered security Providers,
 190      * starting with the most preferred Provider.
 191      * A new KeyPairGenerator object encapsulating the
 192      * KeyPairGeneratorSpi implementation from the first
 193      * Provider that supports the specified algorithm is returned.
 194      *
 195      * <p> Note that the list of registered providers may be retrieved via
 196      * the {@link Security#getProviders() Security.getProviders()} method.
 197      *
 198      * @implNote
 199      * The JDK Reference Implementation additionally uses the
 200      * {@code jdk.security.provider.preferred}
 201      * {@link Security#getProperty(String) Security} property to determine
 202      * the preferred provider order for the specified algorithm. This
 203      * may be different than the order of providers returned by
 204      * {@link Security#getProviders() Security.getProviders()}.
 205      *
 206      * @param algorithm the standard string name of the algorithm.
 207      * See the KeyPairGenerator section in the <a href=
 208      * "{@docRoot}/../specs/security/standard-names.html#keypairgenerator-algorithms">
 209      * Java Security Standard Algorithm Names Specification</a>
 210      * for information about standard algorithm names.
 211      *
 212      * @return the new {@code KeyPairGenerator} object
 213      *
 214      * @throws NoSuchAlgorithmException if no {@code Provider} supports a
 215      *         {@code KeyPairGeneratorSpi} implementation for the
 216      *         specified algorithm
 217      *
 218      * @throws NullPointerException if {@code algorithm} is {@code null}
 219      *
 220      * @see Provider
 221      */
 222     public static KeyPairGenerator getInstance(String algorithm)
 223             throws NoSuchAlgorithmException {
 224         Objects.requireNonNull(algorithm, "null algorithm name");
 225         List<Service> list =
 226                 GetInstance.getServices("KeyPairGenerator", algorithm);
 227         Iterator<Service> t = list.iterator();
 228         if (t.hasNext() == false) {
 229             throw new NoSuchAlgorithmException
 230                 (algorithm + " KeyPairGenerator not available");
 231         }
 232         // find a working Spi or KeyPairGenerator subclass
 233         NoSuchAlgorithmException failure = null;
 234         do {
 235             Service s = t.next();
 236             try {
 237                 Instance instance =
 238                     GetInstance.getInstance(s, KeyPairGeneratorSpi.class);
 239                 if (instance.impl instanceof KeyPairGenerator) {
 240                     return getInstance(instance, algorithm);
 241                 } else {
 242                     return new Delegate(instance, t, algorithm);
 243                 }
 244             } catch (NoSuchAlgorithmException e) {
 245                 if (failure == null) {
 246                     failure = e;
 247                 }
 248             }
 249         } while (t.hasNext());
 250         throw failure;
 251     }
 252 
 253     /**
 254      * Returns a KeyPairGenerator object that generates public/private
 255      * key pairs for the specified algorithm.
 256      *
 257      * <p> A new KeyPairGenerator object encapsulating the
 258      * KeyPairGeneratorSpi implementation from the specified provider
 259      * is returned.  The specified provider must be registered
 260      * in the security provider list.
 261      *
 262      * <p> Note that the list of registered providers may be retrieved via
 263      * the {@link Security#getProviders() Security.getProviders()} method.
 264      *
 265      * @param algorithm the standard string name of the algorithm.
 266      * See the KeyPairGenerator section in the <a href=
 267      * "{@docRoot}/../specs/security/standard-names.html#keypairgenerator-algorithms">
 268      * Java Security Standard Algorithm Names Specification</a>
 269      * for information about standard algorithm names.
 270      *
 271      * @param provider the string name of the provider.
 272      *
 273      * @return the new {@code KeyPairGenerator} object
 274      *
 275      * @throws IllegalArgumentException if the provider name is {@code null}
 276      *         or empty
 277      *
 278      * @throws NoSuchAlgorithmException if a {@code KeyPairGeneratorSpi}
 279      *         implementation for the specified algorithm is not
 280      *         available from the specified provider
 281      *
 282      * @throws NoSuchProviderException if the specified provider is not
 283      *         registered in the security provider list
 284      *
 285      * @throws NullPointerException if {@code algorithm} is {@code null}
 286      *
 287      * @see Provider
 288      */
 289     public static KeyPairGenerator getInstance(String algorithm,
 290             String provider)
 291             throws NoSuchAlgorithmException, NoSuchProviderException {
 292         Objects.requireNonNull(algorithm, "null algorithm name");
 293         Instance instance = GetInstance.getInstance("KeyPairGenerator",
 294                 KeyPairGeneratorSpi.class, algorithm, provider);
 295         return getInstance(instance, algorithm);
 296     }
 297 
 298     /**
 299      * Returns a KeyPairGenerator object that generates public/private
 300      * key pairs for the specified algorithm.
 301      *
 302      * <p> A new KeyPairGenerator object encapsulating the
 303      * KeyPairGeneratorSpi implementation from the specified Provider
 304      * object is returned.  Note that the specified Provider object
 305      * does not have to be registered in the provider list.
 306      *
 307      * @param algorithm the standard string name of the algorithm.
 308      * See the KeyPairGenerator section in the <a href=
 309      * "{@docRoot}/../specs/security/standard-names.html#keypairgenerator-algorithms">
 310      * Java Security Standard Algorithm Names Specification</a>
 311      * for information about standard algorithm names.
 312      *
 313      * @param provider the provider.
 314      *
 315      * @return the new {@code KeyPairGenerator} object
 316      *
 317      * @throws IllegalArgumentException if the specified provider is
 318      *         {@code null}
 319      *
 320      * @throws NoSuchAlgorithmException if a {@code KeyPairGeneratorSpi}
 321      *         implementation for the specified algorithm is not available
 322      *         from the specified {@code Provider} object
 323      *
 324      * @throws NullPointerException if {@code algorithm} is {@code null}
 325      *
 326      * @see Provider
 327      *
 328      * @since 1.4
 329      */
 330     public static KeyPairGenerator getInstance(String algorithm,
 331             Provider provider) throws NoSuchAlgorithmException {
 332         Objects.requireNonNull(algorithm, "null algorithm name");
 333         Instance instance = GetInstance.getInstance("KeyPairGenerator",
 334                 KeyPairGeneratorSpi.class, algorithm, provider);
 335         return getInstance(instance, algorithm);
 336     }
 337 
 338     /**
 339      * Returns the provider of this key pair generator object.
 340      *
 341      * @return the provider of this key pair generator object
 342      */
 343     public final Provider getProvider() {
 344         disableFailover();
 345         return this.provider;
 346     }
 347 
 348     void disableFailover() {
 349         // empty, overridden in Delegate
 350     }
 351 
 352     /**
 353      * Initializes the key pair generator for a certain keysize using
 354      * a default parameter set and the {@code SecureRandom}
 355      * implementation of the highest-priority installed provider as the source
 356      * of randomness.
 357      * (If none of the installed providers supply an implementation of
 358      * {@code SecureRandom}, a system-provided source of randomness is
 359      * used.)
 360      *
 361      * @param keysize the keysize. This is an
 362      * algorithm-specific metric, such as modulus length, specified in
 363      * number of bits.
 364      *
 365      * @exception InvalidParameterException if the {@code keysize} is not
 366      * supported by this KeyPairGenerator object.
 367      */
 368     public void initialize(int keysize) {
 369         initialize(keysize, JCAUtil.getSecureRandom());
 370     }
 371 
 372     /**
 373      * Initializes the key pair generator for a certain keysize with
 374      * the given source of randomness (and a default parameter set).
 375      *
 376      * @param keysize the keysize. This is an
 377      * algorithm-specific metric, such as modulus length, specified in
 378      * number of bits.
 379      * @param random the source of randomness.
 380      *
 381      * @exception InvalidParameterException if the {@code keysize} is not
 382      * supported by this KeyPairGenerator object.
 383      *
 384      * @since 1.2
 385      */
 386     public void initialize(int keysize, SecureRandom random) {
 387         // This does nothing, because either
 388         // 1. the implementation object returned by getInstance() is an
 389         //    instance of KeyPairGenerator which has its own
 390         //    initialize(keysize, random) method, so the application would
 391         //    be calling that method directly, or
 392         // 2. the implementation returned by getInstance() is an instance
 393         //    of Delegate, in which case initialize(keysize, random) is
 394         //    overridden to call the corresponding SPI method.
 395         // (This is a special case, because the API and SPI method have the
 396         // same name.)
 397     }
 398 
 399     /**
 400      * Initializes the key pair generator using the specified parameter
 401      * set and the {@code SecureRandom}
 402      * implementation of the highest-priority installed provider as the source
 403      * of randomness.
 404      * (If none of the installed providers supply an implementation of
 405      * {@code SecureRandom}, a system-provided source of randomness is
 406      * used.)
 407      *
 408      * <p>This concrete method has been added to this previously-defined
 409      * abstract class.
 410      * This method calls the KeyPairGeneratorSpi
 411      * {@link KeyPairGeneratorSpi#initialize(
 412      * java.security.spec.AlgorithmParameterSpec,
 413      * java.security.SecureRandom) initialize} method,
 414      * passing it {@code params} and a source of randomness (obtained
 415      * from the highest-priority installed provider or system-provided if none
 416      * of the installed providers supply one).
 417      * That {@code initialize} method always throws an
 418      * UnsupportedOperationException if it is not overridden by the provider.
 419      *
 420      * @param params the parameter set used to generate the keys.
 421      *
 422      * @exception InvalidAlgorithmParameterException if the given parameters
 423      * are inappropriate for this key pair generator.
 424      *
 425      * @since 1.2
 426      */
 427     public void initialize(AlgorithmParameterSpec params)
 428             throws InvalidAlgorithmParameterException {
 429         initialize(params, JCAUtil.getSecureRandom());
 430     }
 431 
 432     /**
 433      * Initializes the key pair generator with the given parameter
 434      * set and source of randomness.
 435      *
 436      * <p>This concrete method has been added to this previously-defined
 437      * abstract class.
 438      * This method calls the KeyPairGeneratorSpi {@link
 439      * KeyPairGeneratorSpi#initialize(
 440      * java.security.spec.AlgorithmParameterSpec,
 441      * java.security.SecureRandom) initialize} method,
 442      * passing it {@code params} and {@code random}.
 443      * That {@code initialize}
 444      * method always throws an
 445      * UnsupportedOperationException if it is not overridden by the provider.
 446      *
 447      * @param params the parameter set used to generate the keys.
 448      * @param random the source of randomness.
 449      *
 450      * @exception InvalidAlgorithmParameterException if the given parameters
 451      * are inappropriate for this key pair generator.
 452      *
 453      * @since 1.2
 454      */
 455     public void initialize(AlgorithmParameterSpec params,
 456                            SecureRandom random)
 457         throws InvalidAlgorithmParameterException
 458     {
 459         // This does nothing, because either
 460         // 1. the implementation object returned by getInstance() is an
 461         //    instance of KeyPairGenerator which has its own
 462         //    initialize(params, random) method, so the application would
 463         //    be calling that method directly, or
 464         // 2. the implementation returned by getInstance() is an instance
 465         //    of Delegate, in which case initialize(params, random) is
 466         //    overridden to call the corresponding SPI method.
 467         // (This is a special case, because the API and SPI method have the
 468         // same name.)
 469     }
 470 
 471     /**
 472      * Generates a key pair.
 473      *
 474      * <p>If this KeyPairGenerator has not been initialized explicitly,
 475      * provider-specific defaults will be used for the size and other
 476      * (algorithm-specific) values of the generated keys.
 477      *
 478      * <p>This will generate a new key pair every time it is called.
 479      *
 480      * <p>This method is functionally equivalent to
 481      * {@link #generateKeyPair() generateKeyPair}.
 482      *
 483      * @return the generated key pair
 484      *
 485      * @since 1.2
 486      */
 487     public final KeyPair genKeyPair() {
 488         return generateKeyPair();
 489     }
 490 
 491     /**
 492      * Generates a key pair.
 493      *
 494      * <p>If this KeyPairGenerator has not been initialized explicitly,
 495      * provider-specific defaults will be used for the size and other
 496      * (algorithm-specific) values of the generated keys.
 497      *
 498      * <p>This will generate a new key pair every time it is called.
 499      *
 500      * <p>This method is functionally equivalent to
 501      * {@link #genKeyPair() genKeyPair}.
 502      *
 503      * @return the generated key pair
 504      */
 505     public KeyPair generateKeyPair() {
 506         // This does nothing (except returning null), because either:
 507         //
 508         // 1. the implementation object returned by getInstance() is an
 509         //    instance of KeyPairGenerator which has its own implementation
 510         //    of generateKeyPair (overriding this one), so the application
 511         //    would be calling that method directly, or
 512         //
 513         // 2. the implementation returned by getInstance() is an instance
 514         //    of Delegate, in which case generateKeyPair is
 515         //    overridden to invoke the corresponding SPI method.
 516         //
 517         // (This is a special case, because in JDK 1.1.x the generateKeyPair
 518         // method was used both as an API and a SPI method.)
 519         return null;
 520     }
 521 
 522 
 523     /*
 524      * The following class allows providers to extend from KeyPairGeneratorSpi
 525      * rather than from KeyPairGenerator. It represents a KeyPairGenerator
 526      * with an encapsulated, provider-supplied SPI object (of type
 527      * KeyPairGeneratorSpi).
 528      * If the provider implementation is an instance of KeyPairGeneratorSpi,
 529      * the getInstance() methods above return an instance of this class, with
 530      * the SPI object encapsulated.
 531      *
 532      * Note: All SPI methods from the original KeyPairGenerator class have been
 533      * moved up the hierarchy into a new class (KeyPairGeneratorSpi), which has
 534      * been interposed in the hierarchy between the API (KeyPairGenerator)
 535      * and its original parent (Object).
 536      */
 537 
 538     //
 539     // error failover notes:
 540     //
 541     //  . we failover if the implementation throws an error during init
 542     //    by retrying the init on other providers
 543     //
 544     //  . we also failover if the init succeeded but the subsequent call
 545     //    to generateKeyPair() fails. In order for this to work, we need
 546     //    to remember the parameters to the last successful call to init
 547     //    and initialize() the next spi using them.
 548     //
 549     //  . although not specified, KeyPairGenerators could be thread safe,
 550     //    so we make sure we do not interfere with that
 551     //
 552     //  . failover is not available, if:
 553     //    . getInstance(algorithm, provider) was used
 554     //    . a provider extends KeyPairGenerator rather than
 555     //      KeyPairGeneratorSpi (JDK 1.1 style)
 556     //    . once getProvider() is called
 557     //
 558 
 559     private static final class Delegate extends KeyPairGenerator {
 560 
 561         // The provider implementation (delegate)
 562         private volatile KeyPairGeneratorSpi spi;
 563 
 564         private final Object lock = new Object();
 565 
 566         private Iterator<Service> serviceIterator;
 567 
 568         private static final int I_NONE   = 1;
 569         private static final int I_SIZE   = 2;
 570         private static final int I_PARAMS = 3;
 571 
 572         private int initType;
 573         private int initKeySize;
 574         private AlgorithmParameterSpec initParams;
 575         private SecureRandom initRandom;
 576 
 577         // constructor
 578         Delegate(KeyPairGeneratorSpi spi, String algorithm) {
 579             super(algorithm);
 580             this.spi = spi;
 581         }
 582 
 583         Delegate(Instance instance, Iterator<Service> serviceIterator,
 584                 String algorithm) {
 585             super(algorithm);
 586             spi = (KeyPairGeneratorSpi)instance.impl;
 587             provider = instance.provider;
 588             this.serviceIterator = serviceIterator;
 589             initType = I_NONE;
 590 
 591             if (!skipDebug && pdebug != null) {
 592                 pdebug.println("KeyPairGenerator." + algorithm +
 593                     " algorithm from: " + provider.getName());
 594             }
 595         }
 596 
 597         /**
 598          * Update the active spi of this class and return the next
 599          * implementation for failover. If no more implemenations are
 600          * available, this method returns null. However, the active spi of
 601          * this class is never set to null.
 602          */
 603         private KeyPairGeneratorSpi nextSpi(KeyPairGeneratorSpi oldSpi,
 604                 boolean reinit) {
 605             synchronized (lock) {
 606                 // somebody else did a failover concurrently
 607                 // try that spi now
 608                 if ((oldSpi != null) && (oldSpi != spi)) {
 609                     return spi;
 610                 }
 611                 if (serviceIterator == null) {
 612                     return null;
 613                 }
 614                 while (serviceIterator.hasNext()) {
 615                     Service s = serviceIterator.next();
 616                     try {
 617                         Object inst = s.newInstance(null);
 618                         // ignore non-spis
 619                         if (inst instanceof KeyPairGeneratorSpi == false) {
 620                             continue;
 621                         }
 622                         if (inst instanceof KeyPairGenerator) {
 623                             continue;
 624                         }
 625                         KeyPairGeneratorSpi spi = (KeyPairGeneratorSpi)inst;
 626                         if (reinit) {
 627                             if (initType == I_SIZE) {
 628                                 spi.initialize(initKeySize, initRandom);
 629                             } else if (initType == I_PARAMS) {
 630                                 spi.initialize(initParams, initRandom);
 631                             } else if (initType != I_NONE) {
 632                                 throw new AssertionError
 633                                     ("KeyPairGenerator initType: " + initType);
 634                             }
 635                         }
 636                         provider = s.getProvider();
 637                         this.spi = spi;
 638                         return spi;
 639                     } catch (Exception e) {
 640                         // ignore
 641                     }
 642                 }
 643                 disableFailover();
 644                 return null;
 645             }
 646         }
 647 
 648         void disableFailover() {
 649             serviceIterator = null;
 650             initType = 0;
 651             initParams = null;
 652             initRandom = null;
 653         }
 654 
 655         // engine method
 656         public void initialize(int keysize, SecureRandom random) {
 657             if (serviceIterator == null) {
 658                 spi.initialize(keysize, random);
 659                 return;
 660             }
 661             RuntimeException failure = null;
 662             KeyPairGeneratorSpi mySpi = spi;
 663             do {
 664                 try {
 665                     mySpi.initialize(keysize, random);
 666                     initType = I_SIZE;
 667                     initKeySize = keysize;
 668                     initParams = null;
 669                     initRandom = random;
 670                     return;
 671                 } catch (RuntimeException e) {
 672                     if (failure == null) {
 673                         failure = e;
 674                     }
 675                     mySpi = nextSpi(mySpi, false);
 676                 }
 677             } while (mySpi != null);
 678             throw failure;
 679         }
 680 
 681         // engine method
 682         public void initialize(AlgorithmParameterSpec params,
 683                 SecureRandom random) throws InvalidAlgorithmParameterException {
 684             if (serviceIterator == null) {
 685                 spi.initialize(params, random);
 686                 return;
 687             }
 688             Exception failure = null;
 689             KeyPairGeneratorSpi mySpi = spi;
 690             do {
 691                 try {
 692                     mySpi.initialize(params, random);
 693                     initType = I_PARAMS;
 694                     initKeySize = 0;
 695                     initParams = params;
 696                     initRandom = random;
 697                     return;
 698                 } catch (Exception e) {
 699                     if (failure == null) {
 700                         failure = e;
 701                     }
 702                     mySpi = nextSpi(mySpi, false);
 703                 }
 704             } while (mySpi != null);
 705             if (failure instanceof RuntimeException) {
 706                 throw (RuntimeException)failure;
 707             }
 708             // must be an InvalidAlgorithmParameterException
 709             throw (InvalidAlgorithmParameterException)failure;
 710         }
 711 
 712         // engine method
 713         public KeyPair generateKeyPair() {
 714             if (serviceIterator == null) {
 715                 return spi.generateKeyPair();
 716             }
 717             RuntimeException failure = null;
 718             KeyPairGeneratorSpi mySpi = spi;
 719             do {
 720                 try {
 721                     return mySpi.generateKeyPair();
 722                 } catch (RuntimeException e) {
 723                     if (failure == null) {
 724                         failure = e;
 725                     }
 726                     mySpi = nextSpi(mySpi, true);
 727                 }
 728             } while (mySpi != null);
 729             throw failure;
 730         }
 731     }
 732 
 733 }