1 /*
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
4 *
5 *
6 *
7 *
8 *
9 *
10 *
11 *
12 *
13 *
14 *
15 *
16 *
17 *
18 *
19 *
20 *
21 *
22 *
23 *
24 */
25
26 package java.security;
27
28 import java.util.*;
29
30 import java.security.Provider.Service;
31 import java.security.spec.KeySpec;
32 import java.security.spec.InvalidKeySpecException;
33
34 import sun.security.util.Debug;
35 import sun.security.jca.*;
36 import 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}) 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} or
51 * {@code X509EncodedKeySpec}. 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 * <p> Every implementation of the Java platform is required to support the
71 * following standard {@code KeyFactory} algorithms:
72 * <ul>
73 * <li>{@code DiffieHellman}</li>
74 * <li>{@code DSA}</li>
75 * <li>{@code RSA}</li>
76 * </ul>
77 * These algorithms are described in the <a href=
78 * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">
79 * KeyFactory section</a> of the
80 * Java Cryptography Architecture Standard Algorithm Name Documentation.
81 * Consult the release documentation for your implementation to see if any
82 * other algorithms are supported.
83 *
84 * @author Jan Luehe
85 *
86 * @see Key
87 * @see PublicKey
88 * @see PrivateKey
89 * @see java.security.spec.KeySpec
90 * @see java.security.spec.DSAPublicKeySpec
91 * @see java.security.spec.X509EncodedKeySpec
92 *
93 * @since 1.2
94 */
95
96 public class KeyFactory {
97
98 private static final Debug debug =
99 Debug.getInstance("jca", "KeyFactory");
100
101 // The algorithm associated with this key factory
102 private final String algorithm;
103
104 // The provider
105 private Provider provider;
106
107 // The provider implementation (delegate)
108 private volatile KeyFactorySpi spi;
109
110 // lock for mutex during provider selection
111 private final Object lock = new Object();
112
113 // remaining services to try in provider selection
114 // null once provider is selected
115 private Iterator<Service> serviceIterator;
116
117 /**
118 * Creates a KeyFactory object.
119 *
120 * @param keyFacSpi the delegate
121 * @param provider the provider
122 * @param algorithm the name of the algorithm
123 * to associate with this {@code KeyFactory}
124 */
125 protected KeyFactory(KeyFactorySpi keyFacSpi, Provider provider,
126 String algorithm) {
127 this.spi = keyFacSpi;
128 this.provider = provider;
129 this.algorithm = algorithm;
130 }
131
132 private KeyFactory(String algorithm) throws NoSuchAlgorithmException {
133 this.algorithm = algorithm;
134 List<Service> list = GetInstance.getServices("KeyFactory", algorithm);
135 serviceIterator = list.iterator();
136 // fetch and instantiate initial spi
137 if (nextSpi(null) == null) {
138 throw new NoSuchAlgorithmException
139 (algorithm + " KeyFactory not available");
140 }
141 }
142
143 /**
144 * Returns a KeyFactory object that converts
145 * public/private keys of the specified algorithm.
146 *
147 * <p> This method traverses the list of registered security Providers,
148 * starting with the most preferred Provider.
149 * A new KeyFactory object encapsulating the
150 * KeyFactorySpi implementation from the first
151 * Provider that supports the specified algorithm is returned.
152 *
153 * <p> Note that the list of registered providers may be retrieved via
154 * the {@link Security#getProviders() Security.getProviders()} method.
155 *
156 * @param algorithm the name of the requested key algorithm.
157 * See the KeyFactory section in the <a href=
158 * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">
159 * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
160 * for information about standard algorithm names.
161 *
162 * @return the new KeyFactory object.
163 *
164 * @exception NoSuchAlgorithmException if no Provider supports a
165 * KeyFactorySpi implementation for the
166 * specified algorithm.
167 *
168 * @see Provider
169 */
170 public static KeyFactory getInstance(String algorithm)
171 throws NoSuchAlgorithmException {
172 return new KeyFactory(algorithm);
173 }
174
175 /**
176 * Returns a KeyFactory object that converts
177 * public/private keys of the specified algorithm.
178 *
179 * <p> A new KeyFactory object encapsulating the
180 * KeyFactorySpi implementation from the specified provider
181 * is returned. The specified provider must be registered
182 * in the security provider list.
183 *
184 * <p> Note that the list of registered providers may be retrieved via
185 * the {@link Security#getProviders() Security.getProviders()} method.
186 *
187 * @param algorithm the name of the requested key algorithm.
188 * See the KeyFactory section in the <a href=
189 * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">
190 * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
191 * for information about standard algorithm names.
192 *
193 * @param provider the name of the provider.
194 *
195 * @return the new KeyFactory object.
196 *
197 * @exception NoSuchAlgorithmException if a KeyFactorySpi
198 * implementation for the specified algorithm is not
199 * available from the specified provider.
200 *
201 * @exception NoSuchProviderException if the specified provider is not
202 * registered in the security provider list.
203 *
204 * @exception IllegalArgumentException if the provider name is null
205 * or empty.
206 *
207 * @see Provider
208 */
209 public static KeyFactory getInstance(String algorithm, String provider)
210 throws NoSuchAlgorithmException, NoSuchProviderException {
211 Instance instance = GetInstance.getInstance("KeyFactory",
212 KeyFactorySpi.class, algorithm, provider);
213 return new KeyFactory((KeyFactorySpi)instance.impl,
214 instance.provider, algorithm);
215 }
216
217 /**
218 * Returns a KeyFactory object that converts
219 * public/private keys of the specified algorithm.
220 *
221 * <p> A new KeyFactory object encapsulating the
222 * KeyFactorySpi implementation from the specified Provider
223 * object is returned. Note that the specified Provider object
224 * does not have to be registered in the provider list.
225 *
226 * @param algorithm the name of the requested key algorithm.
227 * See the KeyFactory section in the <a href=
228 * "{@docRoot}/../technotes/guides/security/StandardNames.html#KeyFactory">
229 * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
230 * for information about standard algorithm names.
231 *
232 * @param provider the provider.
233 *
234 * @return the new KeyFactory object.
235 *
236 * @exception NoSuchAlgorithmException if a KeyFactorySpi
237 * implementation for the specified algorithm is not available
238 * from the specified Provider object.
239 *
240 * @exception IllegalArgumentException if the specified provider is null.
241 *
242 * @see Provider
243 *
244 * @since 1.4
245 */
246 public static KeyFactory getInstance(String algorithm, Provider provider)
247 throws NoSuchAlgorithmException {
248 Instance instance = GetInstance.getInstance("KeyFactory",
249 KeyFactorySpi.class, algorithm, provider);
250 return new KeyFactory((KeyFactorySpi)instance.impl,
251 instance.provider, algorithm);
252 }
253
254 /**
255 * Returns the provider of this key factory object.
256 *
257 * @return the provider of this key factory object
258 */
259 public final Provider getProvider() {
260 synchronized (lock) {
261 // disable further failover after this call
262 serviceIterator = null;
263 return provider;
264 }
265 }
266
267 /**
268 * Gets the name of the algorithm
269 * associated with this {@code KeyFactory}.
270 *
271 * @return the name of the algorithm associated with this
272 * {@code KeyFactory}
273 */
274 public final String getAlgorithm() {
275 return this.algorithm;
276 }
277
278 /**
279 * Update the active KeyFactorySpi of this class and return the next
280 * implementation for failover. If no more implemenations are
281 * available, this method returns null. However, the active spi of
282 * this class is never set to null.
283 */
284 private KeyFactorySpi nextSpi(KeyFactorySpi oldSpi) {
285 synchronized (lock) {
286 // somebody else did a failover concurrently
287 // try that spi now
288 if ((oldSpi != null) && (oldSpi != spi)) {
289 return spi;
290 }
291 if (serviceIterator == null) {
292 return null;
293 }
294 while (serviceIterator.hasNext()) {
295 Service s = serviceIterator.next();
296 try {
297 Object obj = s.newInstance(null);
298 if (obj instanceof KeyFactorySpi == false) {
299 continue;
300 }
301 KeyFactorySpi spi = (KeyFactorySpi)obj;
302 provider = s.getProvider();
303 this.spi = spi;
304 return spi;
305 } catch (NoSuchAlgorithmException e) {
306 // ignore
307 }
308 }
309 serviceIterator = null;
310 return null;
311 }
312 }
313
314 /**
315 * Generates a public key object from the provided key specification
316 * (key material).
317 *
318 * @param keySpec the specification (key material) of the public key.
319 *
320 * @return the public key.
321 *
322 * @exception InvalidKeySpecException if the given key specification
323 * is inappropriate for this key factory to produce a public key.
324 */
325 public final PublicKey generatePublic(KeySpec keySpec)
326 throws InvalidKeySpecException {
327 if (serviceIterator == null) {
328 return spi.engineGeneratePublic(keySpec);
329 }
330 Exception failure = null;
331 KeyFactorySpi mySpi = spi;
332 do {
333 try {
334 return mySpi.engineGeneratePublic(keySpec);
335 } catch (Exception e) {
336 if (failure == null) {
337 failure = e;
338 }
339 mySpi = nextSpi(mySpi);
340 }
341 } while (mySpi != null);
342 if (failure instanceof RuntimeException) {
343 throw (RuntimeException)failure;
344 }
345 if (failure instanceof InvalidKeySpecException) {
346 throw (InvalidKeySpecException)failure;
347 }
348 throw new InvalidKeySpecException
349 ("Could not generate public key", failure);
350 }
351
352 /**
353 * Generates a private key object from the provided key specification
354 * (key material).
355 *
356 * @param keySpec the specification (key material) of the private key.
357 *
358 * @return the private key.
359 *
360 * @exception InvalidKeySpecException if the given key specification
361 * is inappropriate for this key factory to produce a private key.
362 */
363 public final PrivateKey generatePrivate(KeySpec keySpec)
364 throws InvalidKeySpecException {
365 if (serviceIterator == null) {
366 return spi.engineGeneratePrivate(keySpec);
367 }
368 Exception failure = null;
369 KeyFactorySpi mySpi = spi;
370 do {
371 try {
372 return mySpi.engineGeneratePrivate(keySpec);
373 } catch (Exception e) {
374 if (failure == null) {
375 failure = e;
376 }
377 mySpi = nextSpi(mySpi);
378 }
379 } while (mySpi != null);
380 if (failure instanceof RuntimeException) {
381 throw (RuntimeException)failure;
382 }
383 if (failure instanceof InvalidKeySpecException) {
384 throw (InvalidKeySpecException)failure;
385 }
386 throw new InvalidKeySpecException
387 ("Could not generate private key", failure);
388 }
389
390 /**
391 * Returns a specification (key material) of the given key object.
392 * {@code keySpec} identifies the specification class in which
393 * the key material should be returned. It could, for example, be
394 * {@code DSAPublicKeySpec.class}, to indicate that the
395 * key material should be returned in an instance of the
396 * {@code DSAPublicKeySpec} class.
397 *
398 * @param <T> the type of the key specification to be returned
399 *
400 * @param key the key.
401 *
402 * @param keySpec the specification class in which
403 * the key material should be returned.
404 *
405 * @return the underlying key specification (key material) in an instance
406 * of the requested specification class.
407 *
408 * @exception InvalidKeySpecException if the requested key specification is
409 * inappropriate for the given key, or the given key cannot be processed
410 * (e.g., the given key has an unrecognized algorithm or format).
411 */
412 public final <T extends KeySpec> T getKeySpec(Key key, Class<T> keySpec)
413 throws InvalidKeySpecException {
414 if (serviceIterator == null) {
415 return spi.engineGetKeySpec(key, keySpec);
416 }
417 Exception failure = null;
418 KeyFactorySpi mySpi = spi;
419 do {
420 try {
421 return mySpi.engineGetKeySpec(key, keySpec);
422 } catch (Exception e) {
423 if (failure == null) {
424 failure = e;
425 }
426 mySpi = nextSpi(mySpi);
427 }
428 } while (mySpi != null);
429 if (failure instanceof RuntimeException) {
430 throw (RuntimeException)failure;
431 }
432 if (failure instanceof InvalidKeySpecException) {
433 throw (InvalidKeySpecException)failure;
434 }
435 throw new InvalidKeySpecException
436 ("Could not get key spec", failure);
437 }
438
439 /**
440 * Translates a key object, whose provider may be unknown or potentially
441 * untrusted, into a corresponding key object of this key factory.
442 *
443 * @param key the key whose provider is unknown or untrusted.
444 *
445 * @return the translated key.
446 *
447 * @exception InvalidKeyException if the given key cannot be processed
448 * by this key factory.
449 */
450 public final Key translateKey(Key key) throws InvalidKeyException {
451 if (serviceIterator == null) {
452 return spi.engineTranslateKey(key);
453 }
454 Exception failure = null;
455 KeyFactorySpi mySpi = spi;
456 do {
457 try {
458 return mySpi.engineTranslateKey(key);
459 } catch (Exception e) {
460 if (failure == null) {
461 failure = e;
462 }
463 mySpi = nextSpi(mySpi);
464 }
465 } while (mySpi != null);
466 if (failure instanceof RuntimeException) {
467 throw (RuntimeException)failure;
468 }
469 if (failure instanceof InvalidKeyException) {
470 throw (InvalidKeyException)failure;
471 }
472 throw new InvalidKeyException
473 ("Could not translate key", failure);
474 }
475
476 }
477