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