1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.  Oracle designates this
9 * particular file as subject to the "Classpath" exception as provided
10 * by Oracle in the LICENSE file that accompanied this code.
11 *
12 * This code is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 * version 2 for more details (a copy is included in the LICENSE file that
16 * accompanied this code).
17 *
18 * You should have received a copy of the GNU General Public License version
19 * 2 along with this work; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23 * or visit www.oracle.com if you need additional information or have any
24 * questions.
25 */
26
27package sun.security.ec;
28
29import java.security.*;
30import java.security.interfaces.*;
31import java.security.spec.*;
32
33/**
34 * KeyFactory for EC keys. Keys must be instances of PublicKey or PrivateKey
35 * and getAlgorithm() must return "EC". For such keys, it supports conversion
36 * between the following:
37 *
38 * For public keys:
39 *  . PublicKey with an X.509 encoding
40 *  . ECPublicKey
41 *  . ECPublicKeySpec
42 *  . X509EncodedKeySpec
43 *
44 * For private keys:
45 *  . PrivateKey with a PKCS#8 encoding
46 *  . ECPrivateKey
47 *  . ECPrivateKeySpec
48 *  . PKCS8EncodedKeySpec
49 *
50 * @since   1.6
51 * @author  Andreas Sterbenz
52 */
53public final class ECKeyFactory extends KeyFactorySpi {
54
55    // Used by translateKey() and the SunPKCS11 provider
56    public final static KeyFactory INSTANCE;
57
58    // Internal provider object we can obtain the KeyFactory and
59    // AlgorithmParameters from. Used by ECParameters and AlgorithmId.
60    // This can go away once we have EC always available in the SUN provider.
61    // Used by ECParameters and AlgorithmId.
62    public final static Provider ecInternalProvider;
63
64    static {
65        final Provider p = new Provider("SunEC-Internal", 1.0d, null) {};
66        AccessController.doPrivileged(new PrivilegedAction<Void>() {
67            public Void run() {
68                // Android changed : replace string reference with class name. It
69                // makes no difference in this case since these classes are already
70                // in direct use here.
71                p.put("KeyFactory.EC", ECKeyFactory.class.getName());
72                p.put("AlgorithmParameters.EC", ECParameters.class.getName());
73                p.put("Alg.Alias.AlgorithmParameters.1.2.840.10045.2.1", "EC");
74                return null;
75            }
76        });
77        try {
78            INSTANCE = KeyFactory.getInstance("EC", p);
79        } catch (NoSuchAlgorithmException e) {
80            throw new RuntimeException(e);
81        }
82        ecInternalProvider = p;
83    }
84
85    public ECKeyFactory() {
86        // empty
87    }
88
89    /**
90     * Static method to convert Key into a useable instance of
91     * ECPublicKey or ECPrivateKey. Check the key and convert it
92     * to a Sun key if necessary. If the key is not an EC key
93     * or cannot be used, throw an InvalidKeyException.
94     *
95     * The difference between this method and engineTranslateKey() is that
96     * we do not convert keys of other providers that are already an
97     * instance of ECPublicKey or ECPrivateKey.
98     *
99     * To be used by future Java ECDSA and ECDH implementations.
100     */
101    public static ECKey toECKey(Key key) throws InvalidKeyException {
102        if (key instanceof ECKey) {
103            ECKey ecKey = (ECKey)key;
104            checkKey(ecKey);
105            return ecKey;
106        } else {
107            return (ECKey)INSTANCE.translateKey(key);
108        }
109    }
110
111    /**
112     * Check that the given EC key is valid.
113     */
114    private static void checkKey(ECKey key) throws InvalidKeyException {
115        // check for subinterfaces, omit additional checks for our keys
116        if (key instanceof ECPublicKey) {
117            if (key instanceof ECPublicKeyImpl) {
118                return;
119            }
120        } else if (key instanceof ECPrivateKey) {
121            if (key instanceof ECPrivateKeyImpl) {
122                return;
123            }
124        } else {
125            throw new InvalidKeyException("Neither a public nor a private key");
126        }
127        // ECKey does not extend Key, so we need to do a cast
128        String keyAlg = ((Key)key).getAlgorithm();
129        if (keyAlg.equals("EC") == false) {
130            throw new InvalidKeyException("Not an EC key: " + keyAlg);
131        }
132        // XXX further sanity checks about whether this key uses supported
133        // fields, point formats, etc. would go here
134    }
135
136    /**
137     * Translate an EC key into a Sun EC key. If conversion is
138     * not possible, throw an InvalidKeyException.
139     * See also JCA doc.
140     */
141    protected Key engineTranslateKey(Key key) throws InvalidKeyException {
142        if (key == null) {
143            throw new InvalidKeyException("Key must not be null");
144        }
145        String keyAlg = key.getAlgorithm();
146        if (keyAlg.equals("EC") == false) {
147            throw new InvalidKeyException("Not an EC key: " + keyAlg);
148        }
149        if (key instanceof PublicKey) {
150            return implTranslatePublicKey((PublicKey)key);
151        } else if (key instanceof PrivateKey) {
152            return implTranslatePrivateKey((PrivateKey)key);
153        } else {
154            throw new InvalidKeyException("Neither a public nor a private key");
155        }
156    }
157
158    // see JCA doc
159    protected PublicKey engineGeneratePublic(KeySpec keySpec)
160            throws InvalidKeySpecException {
161        try {
162            return implGeneratePublic(keySpec);
163        } catch (InvalidKeySpecException e) {
164            throw e;
165        } catch (GeneralSecurityException e) {
166            throw new InvalidKeySpecException(e);
167        }
168    }
169
170    // see JCA doc
171    protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
172            throws InvalidKeySpecException {
173        try {
174            return implGeneratePrivate(keySpec);
175        } catch (InvalidKeySpecException e) {
176            throw e;
177        } catch (GeneralSecurityException e) {
178            throw new InvalidKeySpecException(e);
179        }
180    }
181
182    // internal implementation of translateKey() for public keys. See JCA doc
183    private PublicKey implTranslatePublicKey(PublicKey key)
184            throws InvalidKeyException {
185        if (key instanceof ECPublicKey) {
186            if (key instanceof ECPublicKeyImpl) {
187                return key;
188            }
189            ECPublicKey ecKey = (ECPublicKey)key;
190            return new ECPublicKeyImpl(
191                ecKey.getW(),
192                ecKey.getParams()
193            );
194        } else if ("X.509".equals(key.getFormat())) {
195            byte[] encoded = key.getEncoded();
196            return new ECPublicKeyImpl(encoded);
197        } else {
198            throw new InvalidKeyException("Public keys must be instance "
199                + "of ECPublicKey or have X.509 encoding");
200        }
201    }
202
203    // internal implementation of translateKey() for private keys. See JCA doc
204    private PrivateKey implTranslatePrivateKey(PrivateKey key)
205            throws InvalidKeyException {
206        if (key instanceof ECPrivateKey) {
207            if (key instanceof ECPrivateKeyImpl) {
208                return key;
209            }
210            ECPrivateKey ecKey = (ECPrivateKey)key;
211            return new ECPrivateKeyImpl(
212                ecKey.getS(),
213                ecKey.getParams()
214            );
215        } else if ("PKCS#8".equals(key.getFormat())) {
216            return new ECPrivateKeyImpl(key.getEncoded());
217        } else {
218            throw new InvalidKeyException("Private keys must be instance "
219                + "of ECPrivateKey or have PKCS#8 encoding");
220        }
221    }
222
223    // internal implementation of generatePublic. See JCA doc
224    private PublicKey implGeneratePublic(KeySpec keySpec)
225            throws GeneralSecurityException {
226        if (keySpec instanceof X509EncodedKeySpec) {
227            X509EncodedKeySpec x509Spec = (X509EncodedKeySpec)keySpec;
228            return new ECPublicKeyImpl(x509Spec.getEncoded());
229        } else if (keySpec instanceof ECPublicKeySpec) {
230            ECPublicKeySpec ecSpec = (ECPublicKeySpec)keySpec;
231            return new ECPublicKeyImpl(
232                ecSpec.getW(),
233                ecSpec.getParams()
234            );
235        } else {
236            throw new InvalidKeySpecException("Only ECPublicKeySpec "
237                + "and X509EncodedKeySpec supported for EC public keys");
238        }
239    }
240
241    // internal implementation of generatePrivate. See JCA doc
242    private PrivateKey implGeneratePrivate(KeySpec keySpec)
243            throws GeneralSecurityException {
244        if (keySpec instanceof PKCS8EncodedKeySpec) {
245            PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec)keySpec;
246            return new ECPrivateKeyImpl(pkcsSpec.getEncoded());
247        } else if (keySpec instanceof ECPrivateKeySpec) {
248            ECPrivateKeySpec ecSpec = (ECPrivateKeySpec)keySpec;
249            return new ECPrivateKeyImpl(ecSpec.getS(), ecSpec.getParams());
250        } else {
251            throw new InvalidKeySpecException("Only ECPrivateKeySpec "
252                + "and PKCS8EncodedKeySpec supported for EC private keys");
253        }
254    }
255
256    protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
257            throws InvalidKeySpecException {
258        try {
259            // convert key to one of our keys
260            // this also verifies that the key is a valid EC key and ensures
261            // that the encoding is X.509/PKCS#8 for public/private keys
262            key = engineTranslateKey(key);
263        } catch (InvalidKeyException e) {
264            throw new InvalidKeySpecException(e);
265        }
266        if (key instanceof ECPublicKey) {
267            ECPublicKey ecKey = (ECPublicKey)key;
268            if (ECPublicKeySpec.class.isAssignableFrom(keySpec)) {
269                return (T) new ECPublicKeySpec(
270                    ecKey.getW(),
271                    ecKey.getParams()
272                );
273            } else if (X509EncodedKeySpec.class.isAssignableFrom(keySpec)) {
274                return (T) new X509EncodedKeySpec(key.getEncoded());
275            } else {
276                throw new InvalidKeySpecException
277                        ("KeySpec must be ECPublicKeySpec or "
278                        + "X509EncodedKeySpec for EC public keys");
279            }
280        } else if (key instanceof ECPrivateKey) {
281            if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) {
282                return (T) new PKCS8EncodedKeySpec(key.getEncoded());
283            } else if (ECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
284                ECPrivateKey ecKey = (ECPrivateKey)key;
285                return (T) new ECPrivateKeySpec(
286                    ecKey.getS(),
287                    ecKey.getParams()
288                );
289            } else {
290                throw new InvalidKeySpecException
291                        ("KeySpec must be ECPrivateKeySpec or "
292                        + "PKCS8EncodedKeySpec for EC private keys");
293            }
294        } else {
295            // should not occur, caught in engineTranslateKey()
296            throw new InvalidKeySpecException("Neither public nor private key");
297        }
298    }
299}
300