Home | History | Annotate | Download | only in security
      1 /*
      2  * Copyright (c) 1997, 2013, 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 import java.security.Provider.Service;
     30 import java.security.spec.KeySpec;
     31 import java.security.spec.InvalidKeySpecException;
     32 import java.security.spec.RSAPrivateKeySpec;
     33 
     34 import sun.security.util.Debug;
     35 import sun.security.jca.*;
     36 import sun.security.jca.GetInstance.Instance;
     37 
     38 /**
     39  * Key factories are used to convert <I>keys</I> (opaque
     40  * cryptographic keys of type {@code Key}) into <I>key specifications</I>
     41  * (transparent representations of the underlying key material), and vice
     42  * versa.
     43  *
     44  * <P> Key factories are bi-directional. That is, they allow you to build an
     45  * opaque key object from a given key specification (key material), or to
     46  * retrieve the underlying key material of a key object in a suitable format.
     47  *
     48  * <P> Multiple compatible key specifications may exist for the same key.
     49  * For example, a DSA public key may be specified using
     50  * {@code DSAPublicKeySpec} or
     51  * {@code X509EncodedKeySpec}. A key factory can be used to translate
     52  * between compatible key specifications.
     53  *
     54  * <P> The following is an example of how to use a key factory in order to
     55  * instantiate a DSA public key from its encoding.
     56  * Assume Alice has received a digital signature from Bob.
     57  * Bob also sent her his public key (in encoded format) to verify
     58  * his signature. Alice then performs the following actions:
     59  *
     60  * <pre>
     61  * X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey);
     62  * KeyFactory keyFactory = KeyFactory.getInstance("DSA");
     63  * PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);
     64  * Signature sig = Signature.getInstance("DSA");
     65  * sig.initVerify(bobPubKey);
     66  * sig.update(data);
     67  * sig.verify(signature);
     68  * </pre>
     69  *
     70  * <p> Android provides the following <code>KeyFactory</code> algorithms:
     71  * <table>
     72  *   <thead>
     73  *     <tr>
     74  *       <th>Algorithm</th>
     75  *       <th>Supported API Levels</th>
     76  *     </tr>
     77  *   </thead>
     78  *   <tbody>
     79  *     <tr>
     80  *       <td>DH</td>
     81  *       <td>1+</td>
     82  *     </tr>
     83  *     <tr>
     84  *       <td>DSA</td>
     85  *       <td>1+</td>
     86  *     </tr>
     87  *     <tr>
     88  *       <td>EC</td>
     89  *       <td>11+</td>
     90  *     </tr>
     91  *     <tr>
     92  *       <td>RSA</td>
     93  *       <td>1+</td>
     94  *     </tr>
     95  *     <tr class="deprecated">
     96  *       <td>X.509</td>
     97  *       <td>1-8</td>
     98  *     </tr>
     99  *   </tbody>
    100  * </table>
    101  *
    102  * These algorithms are described in the <a href=
    103  * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyFactory">
    104  * KeyFactory section</a> of the
    105  * Java Cryptography Architecture Standard Algorithm Name Documentation.
    106  *
    107  * @author Jan Luehe
    108  *
    109  * @see Key
    110  * @see PublicKey
    111  * @see PrivateKey
    112  * @see java.security.spec.KeySpec
    113  * @see java.security.spec.DSAPublicKeySpec
    114  * @see java.security.spec.X509EncodedKeySpec
    115  *
    116  * @since 1.2
    117  */
    118 
    119 public class KeyFactory {
    120 
    121     private static final Debug debug =
    122                         Debug.getInstance("jca", "KeyFactory");
    123 
    124     // The algorithm associated with this key factory
    125     private final String algorithm;
    126 
    127     // The provider
    128     private Provider provider;
    129 
    130     // The provider implementation (delegate)
    131     private volatile KeyFactorySpi spi;
    132 
    133     // lock for mutex during provider selection
    134     private final Object lock = new Object();
    135 
    136     // remaining services to try in provider selection
    137     // null once provider is selected
    138     private Iterator<Service> serviceIterator;
    139 
    140     /**
    141      * Creates a KeyFactory object.
    142      *
    143      * @param keyFacSpi the delegate
    144      * @param provider the provider
    145      * @param algorithm the name of the algorithm
    146      * to associate with this {@code KeyFactory}
    147      */
    148     protected KeyFactory(KeyFactorySpi keyFacSpi, Provider provider,
    149                          String algorithm) {
    150         this.spi = keyFacSpi;
    151         this.provider = provider;
    152         this.algorithm = algorithm;
    153     }
    154 
    155     private KeyFactory(String algorithm) throws NoSuchAlgorithmException {
    156         this.algorithm = algorithm;
    157         List<Service> list = GetInstance.getServices("KeyFactory", algorithm);
    158         serviceIterator = list.iterator();
    159         // fetch and instantiate initial spi
    160         if (nextSpi(null) == null) {
    161             throw new NoSuchAlgorithmException
    162                 (algorithm + " KeyFactory not available");
    163         }
    164     }
    165 
    166     /**
    167      * Returns a KeyFactory object that converts
    168      * public/private keys of the specified algorithm.
    169      *
    170      * <p> This method traverses the list of registered security Providers,
    171      * starting with the most preferred Provider.
    172      * A new KeyFactory object encapsulating the
    173      * KeyFactorySpi implementation from the first
    174      * Provider that supports the specified algorithm is returned.
    175      *
    176      * <p> Note that the list of registered providers may be retrieved via
    177      * the {@link Security#getProviders() Security.getProviders()} method.
    178      *
    179      * @param algorithm the name of the requested key algorithm.
    180      * See the KeyFactory section in the <a href=
    181      * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyFactory">
    182      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
    183      * for information about standard algorithm names.
    184      *
    185      * @return the new KeyFactory object.
    186      *
    187      * @exception NoSuchAlgorithmException if no Provider supports a
    188      *          KeyFactorySpi implementation for the
    189      *          specified algorithm.
    190      *
    191      * @see Provider
    192      */
    193     public static KeyFactory getInstance(String algorithm)
    194             throws NoSuchAlgorithmException {
    195         return new KeyFactory(algorithm);
    196     }
    197 
    198     /**
    199      * Returns a KeyFactory object that converts
    200      * public/private keys of the specified algorithm.
    201      *
    202      * <p> A new KeyFactory object encapsulating the
    203      * KeyFactorySpi implementation from the specified provider
    204      * is returned.  The specified provider must be registered
    205      * in the security provider list.
    206      *
    207      * <p> Note that the list of registered providers may be retrieved via
    208      * the {@link Security#getProviders() Security.getProviders()} method.
    209      *
    210      * @param algorithm the name of the requested key algorithm.
    211      * See the KeyFactory section in the <a href=
    212      * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyFactory">
    213      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
    214      * for information about standard algorithm names.
    215      *
    216      * @param provider the name of the provider.
    217      *
    218      * @return the new KeyFactory object.
    219      *
    220      * @exception NoSuchAlgorithmException if a KeyFactorySpi
    221      *          implementation for the specified algorithm is not
    222      *          available from the specified provider.
    223      *
    224      * @exception NoSuchProviderException if the specified provider is not
    225      *          registered in the security provider list.
    226      *
    227      * @exception IllegalArgumentException if the provider name is null
    228      *          or empty.
    229      *
    230      * @see Provider
    231      */
    232     public static KeyFactory getInstance(String algorithm, String provider)
    233             throws NoSuchAlgorithmException, NoSuchProviderException {
    234         // Android-added: Check for Bouncy Castle deprecation
    235         Providers.checkBouncyCastleDeprecation(provider, "KeyFactory", algorithm);
    236         Instance instance = GetInstance.getInstance("KeyFactory",
    237             KeyFactorySpi.class, algorithm, provider);
    238         return new KeyFactory((KeyFactorySpi)instance.impl,
    239             instance.provider, algorithm);
    240     }
    241 
    242     /**
    243      * Returns a KeyFactory object that converts
    244      * public/private keys of the specified algorithm.
    245      *
    246      * <p> A new KeyFactory object encapsulating the
    247      * KeyFactorySpi implementation from the specified Provider
    248      * object is returned.  Note that the specified Provider object
    249      * does not have to be registered in the provider list.
    250      *
    251      * @param algorithm the name of the requested key algorithm.
    252      * See the KeyFactory section in the <a href=
    253      * "{@docRoot}openjdk-redirect.html?v=8&path=/technotes/guides/security/StandardNames.html#KeyFactory">
    254      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
    255      * for information about standard algorithm names.
    256      *
    257      * @param provider the provider.
    258      *
    259      * @return the new KeyFactory object.
    260      *
    261      * @exception NoSuchAlgorithmException if a KeyFactorySpi
    262      *          implementation for the specified algorithm is not available
    263      *          from the specified Provider object.
    264      *
    265      * @exception IllegalArgumentException if the specified provider is null.
    266      *
    267      * @see Provider
    268      *
    269      * @since 1.4
    270      */
    271     public static KeyFactory getInstance(String algorithm, Provider provider)
    272             throws NoSuchAlgorithmException {
    273         // Android-added: Check for Bouncy Castle deprecation
    274         Providers.checkBouncyCastleDeprecation(provider, "KeyFactory", algorithm);
    275         Instance instance = GetInstance.getInstance("KeyFactory",
    276             KeyFactorySpi.class, algorithm, provider);
    277         return new KeyFactory((KeyFactorySpi)instance.impl,
    278             instance.provider, algorithm);
    279     }
    280 
    281     /**
    282      * Returns the provider of this key factory object.
    283      *
    284      * @return the provider of this key factory object
    285      */
    286     public final Provider getProvider() {
    287         synchronized (lock) {
    288             // disable further failover after this call
    289             serviceIterator = null;
    290             return provider;
    291         }
    292     }
    293 
    294     /**
    295      * Gets the name of the algorithm
    296      * associated with this {@code KeyFactory}.
    297      *
    298      * @return the name of the algorithm associated with this
    299      * {@code KeyFactory}
    300      */
    301     public final String getAlgorithm() {
    302         return this.algorithm;
    303     }
    304 
    305     /**
    306      * Update the active KeyFactorySpi of this class and return the next
    307      * implementation for failover. If no more implemenations are
    308      * available, this method returns null. However, the active spi of
    309      * this class is never set to null.
    310      */
    311     private KeyFactorySpi nextSpi(KeyFactorySpi oldSpi) {
    312         synchronized (lock) {
    313             // somebody else did a failover concurrently
    314             // try that spi now
    315             if ((oldSpi != null) && (oldSpi != spi)) {
    316                 return spi;
    317             }
    318             if (serviceIterator == null) {
    319                 return null;
    320             }
    321             while (serviceIterator.hasNext()) {
    322                 Service s = serviceIterator.next();
    323                 try {
    324                     Object obj = s.newInstance(null);
    325                     if (obj instanceof KeyFactorySpi == false) {
    326                         continue;
    327                     }
    328                     KeyFactorySpi spi = (KeyFactorySpi)obj;
    329                     provider = s.getProvider();
    330                     this.spi = spi;
    331                     return spi;
    332                 } catch (NoSuchAlgorithmException e) {
    333                     // ignore
    334                 }
    335             }
    336             serviceIterator = null;
    337             return null;
    338         }
    339     }
    340 
    341     /**
    342      * Generates a public key object from the provided key specification
    343      * (key material).
    344      *
    345      * @param keySpec the specification (key material) of the public key.
    346      *
    347      * @return the public key.
    348      *
    349      * @exception InvalidKeySpecException if the given key specification
    350      * is inappropriate for this key factory to produce a public key.
    351      */
    352     public final PublicKey generatePublic(KeySpec keySpec)
    353             throws InvalidKeySpecException {
    354         if (serviceIterator == null) {
    355             return spi.engineGeneratePublic(keySpec);
    356         }
    357         Exception failure = null;
    358         KeyFactorySpi mySpi = spi;
    359         do {
    360             try {
    361                 return mySpi.engineGeneratePublic(keySpec);
    362             } catch (Exception e) {
    363                 if (failure == null) {
    364                     failure = e;
    365                 }
    366                 mySpi = nextSpi(mySpi);
    367             }
    368         } while (mySpi != null);
    369         if (failure instanceof RuntimeException) {
    370             throw (RuntimeException)failure;
    371         }
    372         if (failure instanceof InvalidKeySpecException) {
    373             throw (InvalidKeySpecException)failure;
    374         }
    375         throw new InvalidKeySpecException
    376                 ("Could not generate public key", failure);
    377     }
    378 
    379     /**
    380      * Generates a private key object from the provided key specification
    381      * (key material).
    382      *
    383      * @param keySpec the specification (key material) of the private key.
    384      *
    385      * @return the private key.
    386      *
    387      * @exception InvalidKeySpecException if the given key specification
    388      * is inappropriate for this key factory to produce a private key.
    389      */
    390     public final PrivateKey generatePrivate(KeySpec keySpec)
    391             throws InvalidKeySpecException {
    392         if (serviceIterator == null) {
    393             return spi.engineGeneratePrivate(keySpec);
    394         }
    395         Exception failure = null;
    396         KeyFactorySpi mySpi = spi;
    397         do {
    398             try {
    399                 return mySpi.engineGeneratePrivate(keySpec);
    400             } catch (Exception e) {
    401                 if (failure == null) {
    402                     failure = e;
    403                 }
    404                 mySpi = nextSpi(mySpi);
    405             }
    406         } while (mySpi != null);
    407         if (failure instanceof RuntimeException) {
    408             throw (RuntimeException)failure;
    409         }
    410         if (failure instanceof InvalidKeySpecException) {
    411             throw (InvalidKeySpecException)failure;
    412         }
    413         throw new InvalidKeySpecException
    414                 ("Could not generate private key", failure);
    415     }
    416 
    417     /**
    418      * Returns a specification (key material) of the given key object.
    419      * {@code keySpec} identifies the specification class in which
    420      * the key material should be returned. It could, for example, be
    421      * {@code DSAPublicKeySpec.class}, to indicate that the
    422      * key material should be returned in an instance of the
    423      * {@code DSAPublicKeySpec} class.
    424      *
    425      * @param <T> the type of the key specification to be returned
    426      *
    427      * @param key the key.
    428      *
    429      * @param keySpec the specification class in which
    430      * the key material should be returned.
    431      *
    432      * @return the underlying key specification (key material) in an instance
    433      * of the requested specification class.
    434      *
    435      * @exception InvalidKeySpecException if the requested key specification is
    436      * inappropriate for the given key, or the given key cannot be processed
    437      * (e.g., the given key has an unrecognized algorithm or format).
    438      */
    439     public final <T extends KeySpec> T getKeySpec(Key key, Class<T> keySpec)
    440             throws InvalidKeySpecException {
    441         if (serviceIterator == null) {
    442             return spi.engineGetKeySpec(key, keySpec);
    443         }
    444         Exception failure = null;
    445         KeyFactorySpi mySpi = spi;
    446         do {
    447             try {
    448                 return mySpi.engineGetKeySpec(key, keySpec);
    449             } catch (Exception e) {
    450                 if (failure == null) {
    451                     failure = e;
    452                 }
    453                 mySpi = nextSpi(mySpi);
    454             }
    455         } while (mySpi != null);
    456         if (failure instanceof RuntimeException) {
    457             throw (RuntimeException)failure;
    458         }
    459         if (failure instanceof InvalidKeySpecException) {
    460             throw (InvalidKeySpecException)failure;
    461         }
    462         throw new InvalidKeySpecException
    463                 ("Could not get key spec", failure);
    464     }
    465 
    466     /**
    467      * Translates a key object, whose provider may be unknown or potentially
    468      * untrusted, into a corresponding key object of this key factory.
    469      *
    470      * @param key the key whose provider is unknown or untrusted.
    471      *
    472      * @return the translated key.
    473      *
    474      * @exception InvalidKeyException if the given key cannot be processed
    475      * by this key factory.
    476      */
    477     public final Key translateKey(Key key) throws InvalidKeyException {
    478         if (serviceIterator == null) {
    479             return spi.engineTranslateKey(key);
    480         }
    481         Exception failure = null;
    482         KeyFactorySpi mySpi = spi;
    483         do {
    484             try {
    485                 return mySpi.engineTranslateKey(key);
    486             } catch (Exception e) {
    487                 if (failure == null) {
    488                     failure = e;
    489                 }
    490                 mySpi = nextSpi(mySpi);
    491             }
    492         } while (mySpi != null);
    493         if (failure instanceof RuntimeException) {
    494             throw (RuntimeException)failure;
    495         }
    496         if (failure instanceof InvalidKeyException) {
    497             throw (InvalidKeyException)failure;
    498         }
    499         throw new InvalidKeyException
    500                 ("Could not translate key", failure);
    501     }
    502 
    503 }
    504