blob: 37c3266795a8bc80aaea188380292d643bc2a251 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-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 java.security;
27
28import java.util.*;
29
30import java.security.Provider.Service;
31import java.security.spec.KeySpec;
32import java.security.spec.InvalidKeySpecException;
33
34import sun.security.util.Debug;
35import sun.security.jca.*;
36import sun.security.jca.GetInstance.Instance;
37
38/**
39 * Key factories are used to convert <I>keys</I> (opaque
40 * cryptographic keys of type <code>Key</code>) into <I>key specifications</I>
41 * (transparent representations of the underlying key material), and vice
42 * versa.
43 *
44 * <P> Key factories are bi-directional. That is, they allow you to build an
45 * opaque key object from a given key specification (key material), or to
46 * retrieve the underlying key material of a key object in a suitable format.
47 *
48 * <P> Multiple compatible key specifications may exist for the same key.
49 * For example, a DSA public key may be specified using
50 * <code>DSAPublicKeySpec</code> or
51 * <code>X509EncodedKeySpec</code>. A key factory can be used to translate
52 * between compatible key specifications.
53 *
54 * <P> The following is an example of how to use a key factory in order to
55 * instantiate a DSA public key from its encoding.
56 * Assume Alice has received a digital signature from Bob.
57 * Bob also sent her his public key (in encoded format) to verify
58 * his signature. Alice then performs the following actions:
59 *
60 * <pre>
61 * X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(bobEncodedPubKey);
62 * KeyFactory keyFactory = KeyFactory.getInstance("DSA");
63 * PublicKey bobPubKey = keyFactory.generatePublic(bobPubKeySpec);
64 * Signature sig = Signature.getInstance("DSA");
65 * sig.initVerify(bobPubKey);
66 * sig.update(data);
67 * sig.verify(signature);
68 * </pre>
69 *
70 * @author Jan Luehe
71 *
72 *
73 * @see Key
74 * @see PublicKey
75 * @see PrivateKey
76 * @see java.security.spec.KeySpec
77 * @see java.security.spec.DSAPublicKeySpec
78 * @see java.security.spec.X509EncodedKeySpec
79 *
80 * @since 1.2
81 */
82
83public class KeyFactory {
84
85 private static final Debug debug =
86 Debug.getInstance("jca", "KeyFactory");
87
88 // The algorithm associated with this key factory
89 private final String algorithm;
90
91 // The provider
92 private Provider provider;
93
94 // The provider implementation (delegate)
95 private volatile KeyFactorySpi spi;
96
97 // lock for mutex during provider selection
98 private final Object lock = new Object();
99
100 // remaining services to try in provider selection
101 // null once provider is selected
102 private Iterator<Service> serviceIterator;
103
104 /**
105 * Creates a KeyFactory object.
106 *
107 * @param keyFacSpi the delegate
108 * @param provider the provider
109 * @param algorithm the name of the algorithm
110 * to associate with this <tt>KeyFactory</tt>
111 */
112 protected KeyFactory(KeyFactorySpi keyFacSpi, Provider provider,
113 String algorithm) {
114 this.spi = keyFacSpi;
115 this.provider = provider;
116 this.algorithm = algorithm;
117 }
118
119 private KeyFactory(String algorithm) throws NoSuchAlgorithmException {
120 this.algorithm = algorithm;
121 List<Service> list = GetInstance.getServices("KeyFactory", algorithm);
122 serviceIterator = list.iterator();
123 // fetch and instantiate initial spi
124 if (nextSpi(null) == null) {
125 throw new NoSuchAlgorithmException
126 (algorithm + " KeyFactory not available");
127 }
128 }
129
130 /**
131 * Returns a KeyFactory object that converts
132 * public/private keys of the specified algorithm.
133 *
134 * <p> This method traverses the list of registered security Providers,
135 * starting with the most preferred Provider.
136 * A new KeyFactory object encapsulating the
137 * KeyFactorySpi implementation from the first
138 * Provider that supports the specified algorithm is returned.
139 *
140 * <p> Note that the list of registered providers may be retrieved via
141 * the {@link Security#getProviders() Security.getProviders()} method.
142 *
143 * @param algorithm the name of the requested key algorithm.
144 * See Appendix A in the <a href=
145 * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
146 * Java Cryptography Architecture API Specification &amp; Reference </a>
147 * for information about standard algorithm names.
148 *
149 * @return the new KeyFactory object.
150 *
151 * @exception NoSuchAlgorithmException if no Provider supports a
152 * KeyFactorySpi implementation for the
153 * specified algorithm.
154 *
155 * @see Provider
156 */
157 public static KeyFactory getInstance(String algorithm)
158 throws NoSuchAlgorithmException {
159 return new KeyFactory(algorithm);
160 }
161
162 /**
163 * Returns a KeyFactory object that converts
164 * public/private keys of the specified algorithm.
165 *
166 * <p> A new KeyFactory object encapsulating the
167 * KeyFactorySpi implementation from the specified provider
168 * is returned. The specified provider must be registered
169 * in the security provider list.
170 *
171 * <p> Note that the list of registered providers may be retrieved via
172 * the {@link Security#getProviders() Security.getProviders()} method.
173 *
174 * @param algorithm the name of the requested key algorithm.
175 * See Appendix A in the <a href=
176 * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
177 * Java Cryptography Architecture API Specification &amp; Reference </a>
178 * for information about standard algorithm names.
179 *
180 * @param provider the name of the provider.
181 *
182 * @return the new KeyFactory object.
183 *
184 * @exception NoSuchAlgorithmException if a KeyFactorySpi
185 * implementation for the specified algorithm is not
186 * available from the specified provider.
187 *
188 * @exception NoSuchProviderException if the specified provider is not
189 * registered in the security provider list.
190 *
191 * @exception IllegalArgumentException if the provider name is null
192 * or empty.
193 *
194 * @see Provider
195 */
196 public static KeyFactory getInstance(String algorithm, String provider)
197 throws NoSuchAlgorithmException, NoSuchProviderException {
198 Instance instance = GetInstance.getInstance("KeyFactory",
199 KeyFactorySpi.class, algorithm, provider);
200 return new KeyFactory((KeyFactorySpi)instance.impl,
201 instance.provider, algorithm);
202 }
203
204 /**
205 * Returns a KeyFactory object that converts
206 * public/private keys of the specified algorithm.
207 *
208 * <p> A new KeyFactory object encapsulating the
209 * KeyFactorySpi implementation from the specified Provider
210 * object is returned. Note that the specified Provider object
211 * does not have to be registered in the provider list.
212 *
213 * @param algorithm the name of the requested key algorithm.
214 * See Appendix A in the <a href=
215 * "../../../technotes/guides/security/crypto/CryptoSpec.html#AppA">
216 * Java Cryptography Architecture API Specification &amp; Reference </a>
217 * for information about standard algorithm names.
218 *
219 * @param provider the provider.
220 *
221 * @return the new KeyFactory object.
222 *
223 * @exception NoSuchAlgorithmException if a KeyFactorySpi
224 * implementation for the specified algorithm is not available
225 * from the specified Provider object.
226 *
227 * @exception IllegalArgumentException if the specified provider is null.
228 *
229 * @see Provider
230 *
231 * @since 1.4
232 */
233 public static KeyFactory getInstance(String algorithm, Provider provider)
234 throws NoSuchAlgorithmException {
235 Instance instance = GetInstance.getInstance("KeyFactory",
236 KeyFactorySpi.class, algorithm, provider);
237 return new KeyFactory((KeyFactorySpi)instance.impl,
238 instance.provider, algorithm);
239 }
240
241 /**
242 * Returns the provider of this key factory object.
243 *
244 * @return the provider of this key factory object
245 */
246 public final Provider getProvider() {
247 synchronized (lock) {
248 // disable further failover after this call
249 serviceIterator = null;
250 return provider;
251 }
252 }
253
254 /**
255 * Gets the name of the algorithm
256 * associated with this <tt>KeyFactory</tt>.
257 *
258 * @return the name of the algorithm associated with this
259 * <tt>KeyFactory</tt>
260 */
261 public final String getAlgorithm() {
262 return this.algorithm;
263 }
264
265 /**
266 * Update the active KeyFactorySpi of this class and return the next
267 * implementation for failover. If no more implemenations are
268 * available, this method returns null. However, the active spi of
269 * this class is never set to null.
270 */
271 private KeyFactorySpi nextSpi(KeyFactorySpi oldSpi) {
272 synchronized (lock) {
273 // somebody else did a failover concurrently
274 // try that spi now
275 if ((oldSpi != null) && (oldSpi != spi)) {
276 return spi;
277 }
278 if (serviceIterator == null) {
279 return null;
280 }
281 while (serviceIterator.hasNext()) {
282 Service s = serviceIterator.next();
283 try {
284 Object obj = s.newInstance(null);
285 if (obj instanceof KeyFactorySpi == false) {
286 continue;
287 }
288 KeyFactorySpi spi = (KeyFactorySpi)obj;
289 provider = s.getProvider();
290 this.spi = spi;
291 return spi;
292 } catch (NoSuchAlgorithmException e) {
293 // ignore
294 }
295 }
296 serviceIterator = null;
297 return null;
298 }
299 }
300
301 /**
302 * Generates a public key object from the provided key specification
303 * (key material).
304 *
305 * @param keySpec the specification (key material) of the public key.
306 *
307 * @return the public key.
308 *
309 * @exception InvalidKeySpecException if the given key specification
310 * is inappropriate for this key factory to produce a public key.
311 */
312 public final PublicKey generatePublic(KeySpec keySpec)
313 throws InvalidKeySpecException {
314 if (serviceIterator == null) {
315 return spi.engineGeneratePublic(keySpec);
316 }
317 Exception failure = null;
318 KeyFactorySpi mySpi = spi;
319 do {
320 try {
321 return mySpi.engineGeneratePublic(keySpec);
322 } catch (Exception e) {
323 if (failure == null) {
324 failure = e;
325 }
326 mySpi = nextSpi(mySpi);
327 }
328 } while (mySpi != null);
329 if (failure instanceof RuntimeException) {
330 throw (RuntimeException)failure;
331 }
332 if (failure instanceof InvalidKeySpecException) {
333 throw (InvalidKeySpecException)failure;
334 }
335 throw new InvalidKeySpecException
336 ("Could not generate public key", failure);
337 }
338
339 /**
340 * Generates a private key object from the provided key specification
341 * (key material).
342 *
343 * @param keySpec the specification (key material) of the private key.
344 *
345 * @return the private key.
346 *
347 * @exception InvalidKeySpecException if the given key specification
348 * is inappropriate for this key factory to produce a private key.
349 */
350 public final PrivateKey generatePrivate(KeySpec keySpec)
351 throws InvalidKeySpecException {
352 if (serviceIterator == null) {
353 return spi.engineGeneratePrivate(keySpec);
354 }
355 Exception failure = null;
356 KeyFactorySpi mySpi = spi;
357 do {
358 try {
359 return mySpi.engineGeneratePrivate(keySpec);
360 } catch (Exception e) {
361 if (failure == null) {
362 failure = e;
363 }
364 mySpi = nextSpi(mySpi);
365 }
366 } while (mySpi != null);
367 if (failure instanceof RuntimeException) {
368 throw (RuntimeException)failure;
369 }
370 if (failure instanceof InvalidKeySpecException) {
371 throw (InvalidKeySpecException)failure;
372 }
373 throw new InvalidKeySpecException
374 ("Could not generate private key", failure);
375 }
376
377 /**
378 * Returns a specification (key material) of the given key object.
379 * <code>keySpec</code> identifies the specification class in which
380 * the key material should be returned. It could, for example, be
381 * <code>DSAPublicKeySpec.class</code>, to indicate that the
382 * key material should be returned in an instance of the
383 * <code>DSAPublicKeySpec</code> class.
384 *
385 * @param key the key.
386 *
387 * @param keySpec the specification class in which
388 * the key material should be returned.
389 *
390 * @return the underlying key specification (key material) in an instance
391 * of the requested specification class.
392 *
393 * @exception InvalidKeySpecException if the requested key specification is
394 * inappropriate for the given key, or the given key cannot be processed
395 * (e.g., the given key has an unrecognized algorithm or format).
396 */
397 public final <T extends KeySpec> T getKeySpec(Key key, Class<T> keySpec)
398 throws InvalidKeySpecException {
399 if (serviceIterator == null) {
400 return spi.engineGetKeySpec(key, keySpec);
401 }
402 Exception failure = null;
403 KeyFactorySpi mySpi = spi;
404 do {
405 try {
406 return mySpi.engineGetKeySpec(key, keySpec);
407 } catch (Exception e) {
408 if (failure == null) {
409 failure = e;
410 }
411 mySpi = nextSpi(mySpi);
412 }
413 } while (mySpi != null);
414 if (failure instanceof RuntimeException) {
415 throw (RuntimeException)failure;
416 }
417 if (failure instanceof InvalidKeySpecException) {
418 throw (InvalidKeySpecException)failure;
419 }
420 throw new InvalidKeySpecException
421 ("Could not get key spec", failure);
422 }
423
424 /**
425 * Translates a key object, whose provider may be unknown or potentially
426 * untrusted, into a corresponding key object of this key factory.
427 *
428 * @param key the key whose provider is unknown or untrusted.
429 *
430 * @return the translated key.
431 *
432 * @exception InvalidKeyException if the given key cannot be processed
433 * by this key factory.
434 */
435 public final Key translateKey(Key key) throws InvalidKeyException {
436 if (serviceIterator == null) {
437 return spi.engineTranslateKey(key);
438 }
439 Exception failure = null;
440 KeyFactorySpi mySpi = spi;
441 do {
442 try {
443 return mySpi.engineTranslateKey(key);
444 } catch (Exception e) {
445 if (failure == null) {
446 failure = e;
447 }
448 mySpi = nextSpi(mySpi);
449 }
450 } while (mySpi != null);
451 if (failure instanceof RuntimeException) {
452 throw (RuntimeException)failure;
453 }
454 if (failure instanceof InvalidKeyException) {
455 throw (InvalidKeyException)failure;
456 }
457 throw new InvalidKeyException
458 ("Could not translate key", failure);
459 }
460
461}