RSAKeyFactory.java revision 12745:f068a4ffddd2
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
26package sun.security.rsa;
27
28import java.math.BigInteger;
29
30import java.security.*;
31import java.security.interfaces.*;
32import java.security.spec.*;
33
34import 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 */
61public 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}
402