blob: 17feadfbd12b2f96990cddf4eba1ad49e185a0d9 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.security.ec;
27
28import java.security.*;
29import java.security.interfaces.*;
30import java.security.spec.*;
31
32/**
33 * KeyFactory for EC keys. Keys must be instances of PublicKey or PrivateKey
34 * and getAlgorithm() must return "EC". For such keys, it supports conversion
35 * between the following:
36 *
37 * For public keys:
38 * . PublicKey with an X.509 encoding
39 * . ECPublicKey
40 * . ECPublicKeySpec
41 * . X509EncodedKeySpec
42 *
43 * For private keys:
44 * . PrivateKey with a PKCS#8 encoding
45 * . ECPrivateKey
46 * . ECPrivateKeySpec
47 * . PKCS8EncodedKeySpec
48 *
49 * @since 1.6
50 * @author Andreas Sterbenz
51 */
52public final class ECKeyFactory extends KeyFactorySpi {
53
54 // Used by translateKey() and the SunPKCS11 provider
55 public final static KeyFactory INSTANCE;
56
57 // Internal provider object we can obtain the KeyFactory and
58 // AlgorithmParameters from. Used by ECParameters and AlgorithmId.
59 // This can go away once we have EC always available in the SUN provider.
60 // Used by ECParameters and AlgorithmId.
61 public final static Provider ecInternalProvider;
62
63 static {
64 final Provider p = new Provider("SunEC-Internal", 1.0d, null) {};
65 AccessController.doPrivileged(new PrivilegedAction<Void>() {
66 public Void run() {
67 p.put("KeyFactory.EC", "sun.security.ec.ECKeyFactory");
68 p.put("AlgorithmParameters.EC", "sun.security.ec.ECParameters");
69 p.put("Alg.Alias.AlgorithmParameters.1.2.840.10045.2.1", "EC");
70 return null;
71 }
72 });
73 try {
74 INSTANCE = KeyFactory.getInstance("EC", p);
75 } catch (NoSuchAlgorithmException e) {
76 throw new RuntimeException(e);
77 }
78 ecInternalProvider = p;
79 }
80
81 public ECKeyFactory() {
82 // empty
83 }
84
85 /**
86 * Static method to convert Key into a useable instance of
87 * ECPublicKey or ECPrivateKey. Check the key and convert it
88 * to a Sun key if necessary. If the key is not an EC key
89 * or cannot be used, throw an InvalidKeyException.
90 *
91 * The difference between this method and engineTranslateKey() is that
92 * we do not convert keys of other providers that are already an
93 * instance of ECPublicKey or ECPrivateKey.
94 *
95 * To be used by future Java ECDSA and ECDH implementations.
96 */
97 public static ECKey toECKey(Key key) throws InvalidKeyException {
98 if (key instanceof ECKey) {
99 ECKey ecKey = (ECKey)key;
100 checkKey(ecKey);
101 return ecKey;
102 } else {
103 return (ECKey)INSTANCE.translateKey(key);
104 }
105 }
106
107 /**
108 * Check that the given EC key is valid.
109 */
110 private static void checkKey(ECKey key) throws InvalidKeyException {
111 // check for subinterfaces, omit additional checks for our keys
112 if (key instanceof ECPublicKey) {
113 if (key instanceof ECPublicKeyImpl) {
114 return;
115 }
116 } else if (key instanceof ECPrivateKey) {
117 if (key instanceof ECPrivateKeyImpl) {
118 return;
119 }
120 } else {
121 throw new InvalidKeyException("Neither a public nor a private key");
122 }
123 // ECKey does not extend Key, so we need to do a cast
124 String keyAlg = ((Key)key).getAlgorithm();
125 if (keyAlg.equals("EC") == false) {
126 throw new InvalidKeyException("Not an EC key: " + keyAlg);
127 }
128 // XXX further sanity checks about whether this key uses supported
129 // fields, point formats, etc. would go here
130 }
131
132 /**
133 * Translate an EC key into a Sun EC key. If conversion is
134 * not possible, throw an InvalidKeyException.
135 * See also JCA doc.
136 */
137 protected Key engineTranslateKey(Key key) throws InvalidKeyException {
138 if (key == null) {
139 throw new InvalidKeyException("Key must not be null");
140 }
141 String keyAlg = key.getAlgorithm();
142 if (keyAlg.equals("EC") == false) {
143 throw new InvalidKeyException("Not an EC key: " + keyAlg);
144 }
145 if (key instanceof PublicKey) {
146 return implTranslatePublicKey((PublicKey)key);
147 } else if (key instanceof PrivateKey) {
148 return implTranslatePrivateKey((PrivateKey)key);
149 } else {
150 throw new InvalidKeyException("Neither a public nor a private key");
151 }
152 }
153
154 // see JCA doc
155 protected PublicKey engineGeneratePublic(KeySpec keySpec)
156 throws InvalidKeySpecException {
157 try {
158 return implGeneratePublic(keySpec);
159 } catch (InvalidKeySpecException e) {
160 throw e;
161 } catch (GeneralSecurityException e) {
162 throw new InvalidKeySpecException(e);
163 }
164 }
165
166 // see JCA doc
167 protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
168 throws InvalidKeySpecException {
169 try {
170 return implGeneratePrivate(keySpec);
171 } catch (InvalidKeySpecException e) {
172 throw e;
173 } catch (GeneralSecurityException e) {
174 throw new InvalidKeySpecException(e);
175 }
176 }
177
178 // internal implementation of translateKey() for public keys. See JCA doc
179 private PublicKey implTranslatePublicKey(PublicKey key)
180 throws InvalidKeyException {
181 if (key instanceof ECPublicKey) {
182 if (key instanceof ECPublicKeyImpl) {
183 return key;
184 }
185 ECPublicKey ecKey = (ECPublicKey)key;
186 return new ECPublicKeyImpl(
187 ecKey.getW(),
188 ecKey.getParams()
189 );
190 } else if ("X.509".equals(key.getFormat())) {
191 byte[] encoded = key.getEncoded();
192 return new ECPublicKeyImpl(encoded);
193 } else {
194 throw new InvalidKeyException("Public keys must be instance "
195 + "of ECPublicKey or have X.509 encoding");
196 }
197 }
198
199 // internal implementation of translateKey() for private keys. See JCA doc
200 private PrivateKey implTranslatePrivateKey(PrivateKey key)
201 throws InvalidKeyException {
202 if (key instanceof ECPrivateKey) {
203 if (key instanceof ECPrivateKeyImpl) {
204 return key;
205 }
206 ECPrivateKey ecKey = (ECPrivateKey)key;
207 return new ECPrivateKeyImpl(
208 ecKey.getS(),
209 ecKey.getParams()
210 );
211 } else if ("PKCS#8".equals(key.getFormat())) {
212 return new ECPrivateKeyImpl(key.getEncoded());
213 } else {
214 throw new InvalidKeyException("Private keys must be instance "
215 + "of ECPrivateKey or have PKCS#8 encoding");
216 }
217 }
218
219 // internal implementation of generatePublic. See JCA doc
220 private PublicKey implGeneratePublic(KeySpec keySpec)
221 throws GeneralSecurityException {
222 if (keySpec instanceof X509EncodedKeySpec) {
223 X509EncodedKeySpec x509Spec = (X509EncodedKeySpec)keySpec;
224 return new ECPublicKeyImpl(x509Spec.getEncoded());
225 } else if (keySpec instanceof ECPublicKeySpec) {
226 ECPublicKeySpec ecSpec = (ECPublicKeySpec)keySpec;
227 return new ECPublicKeyImpl(
228 ecSpec.getW(),
229 ecSpec.getParams()
230 );
231 } else {
232 throw new InvalidKeySpecException("Only ECPublicKeySpec "
233 + "and X509EncodedKeySpec supported for EC public keys");
234 }
235 }
236
237 // internal implementation of generatePrivate. See JCA doc
238 private PrivateKey implGeneratePrivate(KeySpec keySpec)
239 throws GeneralSecurityException {
240 if (keySpec instanceof PKCS8EncodedKeySpec) {
241 PKCS8EncodedKeySpec pkcsSpec = (PKCS8EncodedKeySpec)keySpec;
242 return new ECPrivateKeyImpl(pkcsSpec.getEncoded());
243 } else if (keySpec instanceof ECPrivateKeySpec) {
244 ECPrivateKeySpec ecSpec = (ECPrivateKeySpec)keySpec;
245 return new ECPrivateKeyImpl(ecSpec.getS(), ecSpec.getParams());
246 } else {
247 throw new InvalidKeySpecException("Only ECPrivateKeySpec "
248 + "and PKCS8EncodedKeySpec supported for EC private keys");
249 }
250 }
251
252 protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpec)
253 throws InvalidKeySpecException {
254 try {
255 // convert key to one of our keys
256 // this also verifies that the key is a valid EC key and ensures
257 // that the encoding is X.509/PKCS#8 for public/private keys
258 key = engineTranslateKey(key);
259 } catch (InvalidKeyException e) {
260 throw new InvalidKeySpecException(e);
261 }
262 if (key instanceof ECPublicKey) {
263 ECPublicKey ecKey = (ECPublicKey)key;
264 if (ECPublicKeySpec.class.isAssignableFrom(keySpec)) {
265 return (T) new ECPublicKeySpec(
266 ecKey.getW(),
267 ecKey.getParams()
268 );
269 } else if (X509EncodedKeySpec.class.isAssignableFrom(keySpec)) {
270 return (T) new X509EncodedKeySpec(key.getEncoded());
271 } else {
272 throw new InvalidKeySpecException
273 ("KeySpec must be ECPublicKeySpec or "
274 + "X509EncodedKeySpec for EC public keys");
275 }
276 } else if (key instanceof ECPrivateKey) {
277 if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) {
278 return (T) new PKCS8EncodedKeySpec(key.getEncoded());
279 } else if (ECPrivateKeySpec.class.isAssignableFrom(keySpec)) {
280 ECPrivateKey ecKey = (ECPrivateKey)key;
281 return (T) new ECPrivateKeySpec(
282 ecKey.getS(),
283 ecKey.getParams()
284 );
285 } else {
286 throw new InvalidKeySpecException
287 ("KeySpec must be ECPrivateKeySpec or "
288 + "PKCS8EncodedKeySpec for EC private keys");
289 }
290 } else {
291 // should not occur, caught in engineTranslateKey()
292 throw new InvalidKeySpecException("Neither public nor private key");
293 }
294 }
295}