| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.security.rsa;  | 
 | 
 | 
 | 
import java.math.BigInteger;  | 
 | 
 | 
 | 
import java.security.*;  | 
 | 
import java.security.interfaces.*;  | 
 | 
import java.security.spec.*;  | 
 | 
 | 
 | 
import sun.security.action.GetPropertyAction;  | 
 | 
import sun.security.x509.AlgorithmId;  | 
 | 
import static sun.security.rsa.RSAUtil.KeyType;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
public class RSAKeyFactory extends KeyFactorySpi { | 
 | 
 | 
 | 
    private static final Class<?> RSA_PUB_KEYSPEC_CLS = RSAPublicKeySpec.class;  | 
 | 
    private static final Class<?> RSA_PRIV_KEYSPEC_CLS =  | 
 | 
            RSAPrivateKeySpec.class;  | 
 | 
    private static final Class<?> RSA_PRIVCRT_KEYSPEC_CLS =  | 
 | 
            RSAPrivateCrtKeySpec.class;  | 
 | 
    private static final Class<?> X509_KEYSPEC_CLS = X509EncodedKeySpec.class;  | 
 | 
    private static final Class<?> PKCS8_KEYSPEC_CLS = PKCS8EncodedKeySpec.class;  | 
 | 
 | 
 | 
    public final static int MIN_MODLEN = 512;  | 
 | 
    public final static int MAX_MODLEN = 16384;  | 
 | 
 | 
 | 
    private final KeyType type;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public final static int MAX_MODLEN_RESTRICT_EXP = 3072;  | 
 | 
    public final static int MAX_RESTRICTED_EXPLEN = 64;  | 
 | 
 | 
 | 
    private static final boolean restrictExpLen =  | 
 | 
        "true".equalsIgnoreCase(AccessController.doPrivileged(  | 
 | 
            new GetPropertyAction(  | 
 | 
                "sun.security.rsa.restrictRSAExponent", "true")));  | 
 | 
 | 
 | 
    static RSAKeyFactory getInstance(KeyType type) { | 
 | 
        return new RSAKeyFactory(type);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private static void checkKeyAlgo(Key key, String expectedAlg)  | 
 | 
            throws InvalidKeyException { | 
 | 
        String keyAlg = key.getAlgorithm();  | 
 | 
        if (keyAlg == null || !(keyAlg.equalsIgnoreCase(expectedAlg))) { | 
 | 
            throw new InvalidKeyException("Expected a " + expectedAlg | 
 | 
                    + " key, but got " + keyAlg);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static RSAKey toRSAKey(Key key) throws InvalidKeyException { | 
 | 
        if (key == null) { | 
 | 
            throw new InvalidKeyException("Key must not be null"); | 
 | 
        }  | 
 | 
        if ((key instanceof RSAPrivateKeyImpl) ||  | 
 | 
            (key instanceof RSAPrivateCrtKeyImpl) ||  | 
 | 
            (key instanceof RSAPublicKeyImpl)) { | 
 | 
            return (RSAKey)key;  | 
 | 
        } else { | 
 | 
            try { | 
 | 
                KeyType type = KeyType.lookup(key.getAlgorithm());  | 
 | 
                RSAKeyFactory kf = RSAKeyFactory.getInstance(type);  | 
 | 
                return (RSAKey) kf.engineTranslateKey(key);  | 
 | 
            } catch (ProviderException e) { | 
 | 
                throw new InvalidKeyException(e);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    static void checkRSAProviderKeyLengths(int modulusLen, BigInteger exponent)  | 
 | 
            throws InvalidKeyException { | 
 | 
        checkKeyLengths(((modulusLen + 7) & ~7), exponent,  | 
 | 
            RSAKeyFactory.MIN_MODLEN, Integer.MAX_VALUE);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
     public static void checkKeyLengths(int modulusLen, BigInteger exponent,  | 
 | 
            int minModulusLen, int maxModulusLen) throws InvalidKeyException { | 
 | 
 | 
 | 
        if ((minModulusLen > 0) && (modulusLen < (minModulusLen))) { | 
 | 
            throw new InvalidKeyException( "RSA keys must be at least " +  | 
 | 
                minModulusLen + " bits long");  | 
 | 
        }  | 
 | 
 | 
 | 
        // Even though our policy file may allow this, we don't want  | 
 | 
        // either value (mod/exp) to be too big.  | 
 | 
 | 
 | 
        int maxLen = Math.min(maxModulusLen, MAX_MODLEN);  | 
 | 
 | 
 | 
        // If a RSAPrivateKey/RSAPublicKey, make sure the  | 
 | 
          | 
 | 
        if (modulusLen > maxLen) { | 
 | 
            throw new InvalidKeyException(  | 
 | 
                "RSA keys must be no longer than " + maxLen + " bits");  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        if (restrictExpLen && (exponent != null) &&  | 
 | 
                (modulusLen > MAX_MODLEN_RESTRICT_EXP) &&  | 
 | 
                (exponent.bitLength() > MAX_RESTRICTED_EXPLEN)) { | 
 | 
            throw new InvalidKeyException(  | 
 | 
                "RSA exponents can be no longer than " +  | 
 | 
                MAX_RESTRICTED_EXPLEN + " bits " +  | 
 | 
                " if modulus is greater than " +  | 
 | 
                MAX_MODLEN_RESTRICT_EXP + " bits");  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private RSAKeyFactory() { | 
 | 
        this.type = KeyType.RSA;  | 
 | 
    }  | 
 | 
 | 
 | 
    public RSAKeyFactory(KeyType type) { | 
 | 
        this.type = type;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    protected Key engineTranslateKey(Key key) throws InvalidKeyException { | 
 | 
        if (key == null) { | 
 | 
            throw new InvalidKeyException("Key must not be null"); | 
 | 
        }  | 
 | 
          | 
 | 
        checkKeyAlgo(key, type.keyAlgo());  | 
 | 
 | 
 | 
          | 
 | 
        if ((key instanceof RSAPrivateKeyImpl) ||  | 
 | 
            (key instanceof RSAPrivateCrtKeyImpl) ||  | 
 | 
            (key instanceof RSAPublicKeyImpl)) { | 
 | 
            return key;  | 
 | 
        }  | 
 | 
        if (key instanceof PublicKey) { | 
 | 
            return translatePublicKey((PublicKey)key);  | 
 | 
        } else if (key instanceof PrivateKey) { | 
 | 
            return translatePrivateKey((PrivateKey)key);  | 
 | 
        } else { | 
 | 
            throw new InvalidKeyException("Neither a public nor a private key"); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    protected PublicKey engineGeneratePublic(KeySpec keySpec)  | 
 | 
            throws InvalidKeySpecException { | 
 | 
        try { | 
 | 
            return generatePublic(keySpec);  | 
 | 
        } catch (InvalidKeySpecException e) { | 
 | 
            throw e;  | 
 | 
        } catch (GeneralSecurityException e) { | 
 | 
            throw new InvalidKeySpecException(e);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    protected PrivateKey engineGeneratePrivate(KeySpec keySpec)  | 
 | 
            throws InvalidKeySpecException { | 
 | 
        try { | 
 | 
            return generatePrivate(keySpec);  | 
 | 
        } catch (InvalidKeySpecException e) { | 
 | 
            throw e;  | 
 | 
        } catch (GeneralSecurityException e) { | 
 | 
            throw new InvalidKeySpecException(e);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private PublicKey translatePublicKey(PublicKey key)  | 
 | 
            throws InvalidKeyException { | 
 | 
        if (key instanceof RSAPublicKey) { | 
 | 
            RSAPublicKey rsaKey = (RSAPublicKey)key;  | 
 | 
            try { | 
 | 
                return new RSAPublicKeyImpl(  | 
 | 
                    RSAUtil.createAlgorithmId(type, rsaKey.getParams()),  | 
 | 
                    rsaKey.getModulus(),  | 
 | 
                    rsaKey.getPublicExponent());  | 
 | 
            } catch (ProviderException e) { | 
 | 
                  | 
 | 
                throw new InvalidKeyException("Invalid key", e); | 
 | 
            }  | 
 | 
        } else if ("X.509".equals(key.getFormat())) { | 
 | 
            RSAPublicKey translated = new RSAPublicKeyImpl(key.getEncoded());  | 
 | 
              | 
 | 
            checkKeyAlgo(translated, type.keyAlgo());  | 
 | 
            return translated;  | 
 | 
        } else { | 
 | 
            throw new InvalidKeyException("Public keys must be instance " | 
 | 
                + "of RSAPublicKey or have X.509 encoding");  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private PrivateKey translatePrivateKey(PrivateKey key)  | 
 | 
            throws InvalidKeyException { | 
 | 
        if (key instanceof RSAPrivateCrtKey) { | 
 | 
            RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey)key;  | 
 | 
            try { | 
 | 
                return new RSAPrivateCrtKeyImpl(  | 
 | 
                    RSAUtil.createAlgorithmId(type, rsaKey.getParams()),  | 
 | 
                    rsaKey.getModulus(),  | 
 | 
                    rsaKey.getPublicExponent(),  | 
 | 
                    rsaKey.getPrivateExponent(),  | 
 | 
                    rsaKey.getPrimeP(),  | 
 | 
                    rsaKey.getPrimeQ(),  | 
 | 
                    rsaKey.getPrimeExponentP(),  | 
 | 
                    rsaKey.getPrimeExponentQ(),  | 
 | 
                    rsaKey.getCrtCoefficient()  | 
 | 
                );  | 
 | 
            } catch (ProviderException e) { | 
 | 
                  | 
 | 
                throw new InvalidKeyException("Invalid key", e); | 
 | 
            }  | 
 | 
        } else if (key instanceof RSAPrivateKey) { | 
 | 
            RSAPrivateKey rsaKey = (RSAPrivateKey)key;  | 
 | 
            try { | 
 | 
                return new RSAPrivateKeyImpl(  | 
 | 
                    RSAUtil.createAlgorithmId(type, rsaKey.getParams()),  | 
 | 
                    rsaKey.getModulus(),  | 
 | 
                    rsaKey.getPrivateExponent()  | 
 | 
                );  | 
 | 
            } catch (ProviderException e) { | 
 | 
                  | 
 | 
                throw new InvalidKeyException("Invalid key", e); | 
 | 
            }  | 
 | 
        } else if ("PKCS#8".equals(key.getFormat())) { | 
 | 
            RSAPrivateKey translated =  | 
 | 
                RSAPrivateCrtKeyImpl.newKey(key.getEncoded());  | 
 | 
              | 
 | 
            checkKeyAlgo(translated, type.keyAlgo());  | 
 | 
            return translated;  | 
 | 
        } else { | 
 | 
            throw new InvalidKeyException("Private keys must be instance " | 
 | 
                + "of RSAPrivate(Crt)Key or have PKCS#8 encoding");  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private PublicKey generatePublic(KeySpec keySpec)  | 
 | 
            throws GeneralSecurityException { | 
 | 
        if (keySpec instanceof X509EncodedKeySpec) { | 
 | 
            X509EncodedKeySpec x509Spec = (X509EncodedKeySpec)keySpec;  | 
 | 
            RSAPublicKey generated = new RSAPublicKeyImpl(x509Spec.getEncoded());  | 
 | 
              | 
 | 
            checkKeyAlgo(generated, type.keyAlgo());  | 
 | 
            return generated;  | 
 | 
        } else if (keySpec instanceof RSAPublicKeySpec) { | 
 | 
            RSAPublicKeySpec rsaSpec = (RSAPublicKeySpec)keySpec;  | 
 | 
            try { | 
 | 
                return new RSAPublicKeyImpl(  | 
 | 
                    RSAUtil.createAlgorithmId(type, rsaSpec.getParams()),  | 
 | 
                    rsaSpec.getModulus(),  | 
 | 
                    rsaSpec.getPublicExponent()  | 
 | 
                );  | 
 | 
            } catch (ProviderException e) { | 
 | 
                throw new InvalidKeySpecException(e);  | 
 | 
            }  | 
 | 
        } else { | 
 | 
            throw new InvalidKeySpecException("Only RSAPublicKeySpec " | 
 | 
                + "and X509EncodedKeySpec supported for RSA public keys");  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    private PrivateKey generatePrivate(KeySpec keySpec)  | 
 | 
            throws GeneralSecurityException { | 
 | 
        if (keySpec instanceof PKCS8EncodedKeySpec) { | 
 | 
            PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec)keySpec;  | 
 | 
            RSAPrivateKey generated = RSAPrivateCrtKeyImpl.newKey(pkcsSpec.getEncoded());  | 
 | 
              | 
 | 
            checkKeyAlgo(generated, type.keyAlgo());  | 
 | 
            return generated;  | 
 | 
        } else if (keySpec instanceof RSAPrivateCrtKeySpec) { | 
 | 
            RSAPrivateCrtKeySpec rsaSpec = (RSAPrivateCrtKeySpec)keySpec;  | 
 | 
            try { | 
 | 
                return new RSAPrivateCrtKeyImpl(  | 
 | 
                    RSAUtil.createAlgorithmId(type, rsaSpec.getParams()),  | 
 | 
                    rsaSpec.getModulus(),  | 
 | 
                    rsaSpec.getPublicExponent(),  | 
 | 
                    rsaSpec.getPrivateExponent(),  | 
 | 
                    rsaSpec.getPrimeP(),  | 
 | 
                    rsaSpec.getPrimeQ(),  | 
 | 
                    rsaSpec.getPrimeExponentP(),  | 
 | 
                    rsaSpec.getPrimeExponentQ(),  | 
 | 
                    rsaSpec.getCrtCoefficient()  | 
 | 
                );  | 
 | 
            } catch (ProviderException e) { | 
 | 
                throw new InvalidKeySpecException(e);  | 
 | 
            }  | 
 | 
        } else if (keySpec instanceof RSAPrivateKeySpec) { | 
 | 
            RSAPrivateKeySpec rsaSpec = (RSAPrivateKeySpec)keySpec;  | 
 | 
            try { | 
 | 
                return new RSAPrivateKeyImpl(  | 
 | 
                    RSAUtil.createAlgorithmId(type, rsaSpec.getParams()),  | 
 | 
                    rsaSpec.getModulus(),  | 
 | 
                    rsaSpec.getPrivateExponent()  | 
 | 
                );  | 
 | 
            } catch (ProviderException e) { | 
 | 
                throw new InvalidKeySpecException(e);  | 
 | 
            }  | 
 | 
        } else { | 
 | 
            throw new InvalidKeySpecException("Only RSAPrivate(Crt)KeySpec " | 
 | 
                + "and PKCS8EncodedKeySpec supported for RSA private keys");  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)  | 
 | 
            throws InvalidKeySpecException { | 
 | 
        try { | 
 | 
            // convert key to one of our keys  | 
 | 
            // this also verifies that the key is a valid RSA key and ensures  | 
 | 
              | 
 | 
            key = engineTranslateKey(key);  | 
 | 
        } catch (InvalidKeyException e) { | 
 | 
            throw new InvalidKeySpecException(e);  | 
 | 
        }  | 
 | 
        if (key instanceof RSAPublicKey) { | 
 | 
            RSAPublicKey rsaKey = (RSAPublicKey)key;  | 
 | 
            if (RSA_PUB_KEYSPEC_CLS.isAssignableFrom(keySpec)) { | 
 | 
                return keySpec.cast(new RSAPublicKeySpec(  | 
 | 
                    rsaKey.getModulus(),  | 
 | 
                    rsaKey.getPublicExponent(),  | 
 | 
                    rsaKey.getParams()  | 
 | 
                ));  | 
 | 
            } else if (X509_KEYSPEC_CLS.isAssignableFrom(keySpec)) { | 
 | 
                return keySpec.cast(new X509EncodedKeySpec(key.getEncoded()));  | 
 | 
            } else { | 
 | 
                throw new InvalidKeySpecException  | 
 | 
                        ("KeySpec must be RSAPublicKeySpec or " | 
 | 
                        + "X509EncodedKeySpec for RSA public keys");  | 
 | 
            }  | 
 | 
        } else if (key instanceof RSAPrivateKey) { | 
 | 
            if (PKCS8_KEYSPEC_CLS.isAssignableFrom(keySpec)) { | 
 | 
                return keySpec.cast(new PKCS8EncodedKeySpec(key.getEncoded()));  | 
 | 
            } else if (RSA_PRIVCRT_KEYSPEC_CLS.isAssignableFrom(keySpec)) { | 
 | 
                if (key instanceof RSAPrivateCrtKey) { | 
 | 
                    RSAPrivateCrtKey crtKey = (RSAPrivateCrtKey)key;  | 
 | 
                    return keySpec.cast(new RSAPrivateCrtKeySpec(  | 
 | 
                        crtKey.getModulus(),  | 
 | 
                        crtKey.getPublicExponent(),  | 
 | 
                        crtKey.getPrivateExponent(),  | 
 | 
                        crtKey.getPrimeP(),  | 
 | 
                        crtKey.getPrimeQ(),  | 
 | 
                        crtKey.getPrimeExponentP(),  | 
 | 
                        crtKey.getPrimeExponentQ(),  | 
 | 
                        crtKey.getCrtCoefficient(),  | 
 | 
                        crtKey.getParams()  | 
 | 
                    ));  | 
 | 
                } else { | 
 | 
                    throw new InvalidKeySpecException  | 
 | 
                    ("RSAPrivateCrtKeySpec can only be used with CRT keys"); | 
 | 
                }  | 
 | 
            } else if (RSA_PRIV_KEYSPEC_CLS.isAssignableFrom(keySpec)) { | 
 | 
                RSAPrivateKey rsaKey = (RSAPrivateKey)key;  | 
 | 
                return keySpec.cast(new RSAPrivateKeySpec(  | 
 | 
                    rsaKey.getModulus(),  | 
 | 
                    rsaKey.getPrivateExponent(),  | 
 | 
                    rsaKey.getParams()  | 
 | 
                ));  | 
 | 
            } else { | 
 | 
                throw new InvalidKeySpecException  | 
 | 
                        ("KeySpec must be RSAPrivate(Crt)KeySpec or " | 
 | 
                        + "PKCS8EncodedKeySpec for RSA private keys");  | 
 | 
            }  | 
 | 
        } else { | 
 | 
              | 
 | 
            throw new InvalidKeySpecException("Neither public nor private key"); | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public static final class Legacy extends RSAKeyFactory { | 
 | 
        public Legacy() { | 
 | 
            super(KeyType.RSA);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    public static final class PSS extends RSAKeyFactory { | 
 | 
        public PSS() { | 
 | 
            super(KeyType.PSS);  | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |