1 /*
   2  * Copyright (c) 2003, 2011, 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 sun.security.rsa;
  27 
  28 import java.math.BigInteger;
  29 
  30 import java.security.*;
  31 import java.security.interfaces.*;
  32 import java.security.spec.*;
  33 
  34 import sun.security.action.GetPropertyAction;
  35 
  36 /**
  37  * KeyFactory for RSA keys. Keys must be instances of PublicKey or PrivateKey
  38  * and getAlgorithm() must return "RSA". For such keys, it supports conversion
  39  * between the following:
  40  *
  41  * For public keys:
  42  *  . PublicKey with an X.509 encoding
  43  *  . RSAPublicKey
  44  *  . RSAPublicKeySpec
  45  *  . X509EncodedKeySpec
  46  *
  47  * For private keys:
  48  *  . PrivateKey with a PKCS#8 encoding
  49  *  . RSAPrivateKey
  50  *  . RSAPrivateCrtKey
  51  *  . RSAPrivateKeySpec
  52  *  . RSAPrivateCrtKeySpec
  53  *  . PKCS8EncodedKeySpec
  54  * (of course, CRT variants only for CRT keys)
  55  *
  56  * Note: as always, RSA keys should be at least 512 bits long
  57  *
  58  * @since   1.5
  59  * @author  Andreas Sterbenz
  60  */
  61 public final class RSAKeyFactory extends KeyFactorySpi {
  62 
  63     private static final Class<?> rsaPublicKeySpecClass =
  64                                                 RSAPublicKeySpec.class;
  65     private static final Class<?> rsaPrivateKeySpecClass =
  66                                                 RSAPrivateKeySpec.class;
  67     private static final Class<?> rsaPrivateCrtKeySpecClass =
  68                                                 RSAPrivateCrtKeySpec.class;
  69 
  70     private static final Class<?> x509KeySpecClass  = X509EncodedKeySpec.class;
  71     private static final Class<?> pkcs8KeySpecClass = PKCS8EncodedKeySpec.class;
  72 
  73     public static final int MIN_MODLEN = 512;
  74     public static final int MAX_MODLEN = 16384;
  75 
  76     /*
  77      * If the modulus length is above this value, restrict the size of
  78      * the exponent to something that can be reasonably computed.  We
  79      * could simply hardcode the exp len to something like 64 bits, but
  80      * this approach allows flexibility in case impls would like to use
  81      * larger module and exponent values.
  82      */
  83     public static final int MAX_MODLEN_RESTRICT_EXP = 3072;
  84     public static final int MAX_RESTRICTED_EXPLEN = 64;
  85 
  86     private static final boolean restrictExpLen =
  87         "true".equalsIgnoreCase(AccessController.doPrivileged(
  88             new GetPropertyAction(
  89                 "sun.security.rsa.restrictRSAExponent", "true")));
  90 
  91     // instance used for static translateKey();
  92     private static final RSAKeyFactory INSTANCE = new RSAKeyFactory();
  93 
  94     public RSAKeyFactory() {
  95         // empty
  96     }
  97 
  98     /**
  99      * Static method to convert Key into an instance of RSAPublicKeyImpl
 100      * or RSAPrivate(Crt)KeyImpl. If the key is not an RSA key or cannot be
 101      * used, throw an InvalidKeyException.
 102      *
 103      * Used by RSASignature and RSACipher.
 104      */
 105     public static RSAKey toRSAKey(Key key) throws InvalidKeyException {
 106         if ((key instanceof RSAPrivateKeyImpl) ||
 107             (key instanceof RSAPrivateCrtKeyImpl) ||
 108             (key instanceof RSAPublicKeyImpl)) {
 109             return (RSAKey)key;
 110         } else {
 111             return (RSAKey)INSTANCE.engineTranslateKey(key);
 112         }
 113     }
 114 
 115     /*
 116      * Single test entry point for all of the mechanisms in the SunRsaSign
 117      * provider (RSA*KeyImpls).  All of the tests are the same.
 118      *
 119      * For compatibility, we round up to the nearest byte here:
 120      * some Key impls might pass in a value within a byte of the
 121      * real value.
 122      */
 123     static void checkRSAProviderKeyLengths(int modulusLen, BigInteger exponent)
 124             throws InvalidKeyException {
 125         checkKeyLengths(((modulusLen + 7) & ~7), exponent,
 126             RSAKeyFactory.MIN_MODLEN, Integer.MAX_VALUE);
 127     }
 128 
 129     /**
 130      * Check the length of an RSA key modulus/exponent to make sure it
 131      * is not too short or long.  Some impls have their own min and
 132      * max key sizes that may or may not match with a system defined value.
 133      *
 134      * @param modulusLen the bit length of the RSA modulus.
 135      * @param exponent the RSA exponent
 136      * @param minModulusLen if {@literal > 0}, check to see if modulusLen is at
 137      *        least this long, otherwise unused.
 138      * @param maxModulusLen caller will allow this max number of bits.
 139      *        Allow the smaller of the system-defined maximum and this param.
 140      *
 141      * @throws InvalidKeyException if any of the values are unacceptable.
 142      */
 143      public static void checkKeyLengths(int modulusLen, BigInteger exponent,
 144             int minModulusLen, int maxModulusLen) throws InvalidKeyException {
 145 
 146         if ((minModulusLen > 0) && (modulusLen < (minModulusLen))) {
 147             throw new InvalidKeyException( "RSA keys must be at least " +
 148                 minModulusLen + " bits long");
 149         }
 150 
 151         // Even though our policy file may allow this, we don't want
 152         // either value (mod/exp) to be too big.
 153 
 154         int maxLen = Math.min(maxModulusLen, MAX_MODLEN);
 155 
 156         // If a RSAPrivateKey/RSAPublicKey, make sure the
 157         // modulus len isn't too big.
 158         if (modulusLen > maxLen) {
 159             throw new InvalidKeyException(
 160                 "RSA keys must be no longer than " + maxLen + " bits");
 161         }
 162 
 163         // If a RSAPublicKey, make sure the exponent isn't too big.
 164         if (restrictExpLen && (exponent != null) &&
 165                 (modulusLen > MAX_MODLEN_RESTRICT_EXP) &&
 166                 (exponent.bitLength() > MAX_RESTRICTED_EXPLEN)) {
 167             throw new InvalidKeyException(
 168                 "RSA exponents can be no longer than " +
 169                 MAX_RESTRICTED_EXPLEN + " bits " +
 170                 " if modulus is greater than " +
 171                 MAX_MODLEN_RESTRICT_EXP + " bits");
 172         }
 173     }
 174 
 175     /**
 176      * Translate an RSA key into a SunRsaSign RSA key. If conversion is
 177      * not possible, throw an InvalidKeyException.
 178      * See also JCA doc.
 179      */
 180     protected Key engineTranslateKey(Key key) throws InvalidKeyException {
 181         if (key == null) {
 182             throw new InvalidKeyException("Key must not be null");
 183         }
 184         String keyAlg = key.getAlgorithm();
 185         if (keyAlg.equals("RSA") == false) {
 186             throw new InvalidKeyException("Not an RSA key: " + keyAlg);
 187         }
 188         if (key instanceof PublicKey) {
 189             return translatePublicKey((PublicKey)key);
 190         } else if (key instanceof PrivateKey) {
 191             return translatePrivateKey((PrivateKey)key);
 192         } else {
 193             throw new InvalidKeyException("Neither a public nor a private key");
 194         }
 195     }
 196 
 197     // see JCA doc
 198     protected PublicKey engineGeneratePublic(KeySpec keySpec)
 199             throws InvalidKeySpecException {
 200         try {
 201             return generatePublic(keySpec);
 202         } catch (InvalidKeySpecException e) {
 203             throw e;
 204         } catch (GeneralSecurityException e) {
 205             throw new InvalidKeySpecException(e);
 206         }
 207     }
 208 
 209     // see JCA doc
 210     protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
 211             throws InvalidKeySpecException {
 212         try {
 213             return generatePrivate(keySpec);
 214         } catch (InvalidKeySpecException e) {
 215             throw e;
 216         } catch (GeneralSecurityException e) {
 217             throw new InvalidKeySpecException(e);
 218         }
 219     }
 220 
 221     // internal implementation of translateKey() for public keys. See JCA doc
 222     private PublicKey translatePublicKey(PublicKey key)
 223             throws InvalidKeyException {
 224         if (key instanceof RSAPublicKey) {
 225             if (key instanceof RSAPublicKeyImpl) {
 226                 return key;
 227             }
 228             RSAPublicKey rsaKey = (RSAPublicKey)key;
 229             try {
 230                 return new RSAPublicKeyImpl(
 231                     rsaKey.getModulus(),
 232                     rsaKey.getPublicExponent()
 233                 );
 234             } catch (RuntimeException e) {
 235                 // catch providers that incorrectly implement RSAPublicKey
 236                 throw new InvalidKeyException("Invalid key", e);
 237             }
 238         } else if ("X.509".equals(key.getFormat())) {
 239             byte[] encoded = key.getEncoded();
 240             return new RSAPublicKeyImpl(encoded);
 241         } else {
 242             throw new InvalidKeyException("Public keys must be instance "
 243                 + "of RSAPublicKey or have X.509 encoding");
 244         }
 245     }
 246 
 247     // internal implementation of translateKey() for private keys. See JCA doc
 248     private PrivateKey translatePrivateKey(PrivateKey key)
 249             throws InvalidKeyException {
 250         if (key instanceof RSAPrivateCrtKey) {
 251             if (key instanceof RSAPrivateCrtKeyImpl) {
 252                 return key;
 253             }
 254             RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey)key;
 255             try {
 256                 return new RSAPrivateCrtKeyImpl(
 257                     rsaKey.getModulus(),
 258                     rsaKey.getPublicExponent(),
 259                     rsaKey.getPrivateExponent(),
 260                     rsaKey.getPrimeP(),
 261                     rsaKey.getPrimeQ(),
 262                     rsaKey.getPrimeExponentP(),
 263                     rsaKey.getPrimeExponentQ(),
 264                     rsaKey.getCrtCoefficient()
 265                 );
 266             } catch (RuntimeException e) {
 267                 // catch providers that incorrectly implement RSAPrivateCrtKey
 268                 throw new InvalidKeyException("Invalid key", e);
 269             }
 270         } else if (key instanceof RSAPrivateKey) {
 271             if (key instanceof RSAPrivateKeyImpl) {
 272                 return key;
 273             }
 274             RSAPrivateKey rsaKey = (RSAPrivateKey)key;
 275             try {
 276                 return new RSAPrivateKeyImpl(
 277                     rsaKey.getModulus(),
 278                     rsaKey.getPrivateExponent()
 279                 );
 280             } catch (RuntimeException e) {
 281                 // catch providers that incorrectly implement RSAPrivateKey
 282                 throw new InvalidKeyException("Invalid key", e);
 283             }
 284         } else if ("PKCS#8".equals(key.getFormat())) {
 285             byte[] encoded = key.getEncoded();
 286             return RSAPrivateCrtKeyImpl.newKey(encoded);
 287         } else {
 288             throw new InvalidKeyException("Private keys must be instance "
 289                 + "of RSAPrivate(Crt)Key or have PKCS#8 encoding");
 290         }
 291     }
 292 
 293     // internal implementation of generatePublic. See JCA doc
 294     private PublicKey generatePublic(KeySpec keySpec)
 295             throws GeneralSecurityException {
 296         if (keySpec instanceof X509EncodedKeySpec) {
 297             X509EncodedKeySpec x509Spec = (X509EncodedKeySpec)keySpec;
 298             return new RSAPublicKeyImpl(x509Spec.getEncoded());
 299         } else if (keySpec instanceof RSAPublicKeySpec) {
 300             RSAPublicKeySpec rsaSpec = (RSAPublicKeySpec)keySpec;
 301             return new RSAPublicKeyImpl(
 302                 rsaSpec.getModulus(),
 303                 rsaSpec.getPublicExponent()
 304             );
 305         } else {
 306             throw new InvalidKeySpecException("Only RSAPublicKeySpec "
 307                 + "and X509EncodedKeySpec supported for RSA public keys");
 308         }
 309     }
 310 
 311     // internal implementation of generatePrivate. See JCA doc
 312     private PrivateKey generatePrivate(KeySpec keySpec)
 313             throws GeneralSecurityException {
 314         if (keySpec instanceof PKCS8EncodedKeySpec) {
 315             PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec)keySpec;
 316             return RSAPrivateCrtKeyImpl.newKey(pkcsSpec.getEncoded());
 317         } else if (keySpec instanceof RSAPrivateCrtKeySpec) {
 318             RSAPrivateCrtKeySpec rsaSpec = (RSAPrivateCrtKeySpec)keySpec;
 319             return new RSAPrivateCrtKeyImpl(
 320                 rsaSpec.getModulus(),
 321                 rsaSpec.getPublicExponent(),
 322                 rsaSpec.getPrivateExponent(),
 323                 rsaSpec.getPrimeP(),
 324                 rsaSpec.getPrimeQ(),
 325                 rsaSpec.getPrimeExponentP(),
 326                 rsaSpec.getPrimeExponentQ(),
 327                 rsaSpec.getCrtCoefficient()
 328             );
 329         } else if (keySpec instanceof RSAPrivateKeySpec) {
 330             RSAPrivateKeySpec rsaSpec = (RSAPrivateKeySpec)keySpec;
 331             return new RSAPrivateKeyImpl(
 332                 rsaSpec.getModulus(),
 333                 rsaSpec.getPrivateExponent()
 334             );
 335         } else {
 336             throw new InvalidKeySpecException("Only RSAPrivate(Crt)KeySpec "
 337                 + "and PKCS8EncodedKeySpec supported for RSA private keys");
 338         }
 339     }
 340 
 341     protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
 342             throws InvalidKeySpecException {
 343         try {
 344             // convert key to one of our keys
 345             // this also verifies that the key is a valid RSA key and ensures
 346             // that the encoding is X.509/PKCS#8 for public/private keys
 347             key = engineTranslateKey(key);
 348         } catch (InvalidKeyException e) {
 349             throw new InvalidKeySpecException(e);
 350         }
 351         if (key instanceof RSAPublicKey) {
 352             RSAPublicKey rsaKey = (RSAPublicKey)key;
 353             if (rsaPublicKeySpecClass.isAssignableFrom(keySpec)) {
 354                 return keySpec.cast(new RSAPublicKeySpec(
 355                     rsaKey.getModulus(),
 356                     rsaKey.getPublicExponent()
 357                 ));
 358             } else if (x509KeySpecClass.isAssignableFrom(keySpec)) {
 359                 return keySpec.cast(new X509EncodedKeySpec(key.getEncoded()));
 360             } else {
 361                 throw new InvalidKeySpecException
 362                         ("KeySpec must be RSAPublicKeySpec or "
 363                         + "X509EncodedKeySpec for RSA public keys");
 364             }
 365         } else if (key instanceof RSAPrivateKey) {
 366             if (pkcs8KeySpecClass.isAssignableFrom(keySpec)) {
 367                 return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded()));
 368             } else if (rsaPrivateCrtKeySpecClass.isAssignableFrom(keySpec)) {
 369                 if (key instanceof RSAPrivateCrtKey) {
 370                     RSAPrivateCrtKey crtKey = (RSAPrivateCrtKey)key;
 371                     return keySpec.cast(new RSAPrivateCrtKeySpec(
 372                         crtKey.getModulus(),
 373                         crtKey.getPublicExponent(),
 374                         crtKey.getPrivateExponent(),
 375                         crtKey.getPrimeP(),
 376                         crtKey.getPrimeQ(),
 377                         crtKey.getPrimeExponentP(),
 378                         crtKey.getPrimeExponentQ(),
 379                         crtKey.getCrtCoefficient()
 380                     ));
 381                 } else {
 382                     throw new InvalidKeySpecException
 383                     ("RSAPrivateCrtKeySpec can only be used with CRT keys");
 384                 }
 385             } else if (rsaPrivateKeySpecClass.isAssignableFrom(keySpec)) {
 386                 RSAPrivateKey rsaKey = (RSAPrivateKey)key;
 387                 return keySpec.cast(new RSAPrivateKeySpec(
 388                     rsaKey.getModulus(),
 389                     rsaKey.getPrivateExponent()
 390                 ));
 391             } else {
 392                 throw new InvalidKeySpecException
 393                         ("KeySpec must be RSAPrivate(Crt)KeySpec or "
 394                         + "PKCS8EncodedKeySpec for RSA private keys");
 395             }
 396         } else {
 397             // should not occur, caught in engineTranslateKey()
 398             throw new InvalidKeySpecException("Neither public nor private key");
 399         }
 400     }
 401 }