1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package org.apache.harmony.security.tests.java.security;
19
20import java.security.InvalidKeyException;
21import java.security.KeyFactory;
22import java.security.KeyPair;
23import java.security.KeyPairGenerator;
24import java.security.NoSuchAlgorithmException;
25import java.security.NoSuchProviderException;
26import java.security.PrivateKey;
27import java.security.Provider;
28import java.security.PublicKey;
29import java.security.SecureRandom;
30import java.security.Security;
31import java.security.spec.InvalidKeySpecException;
32import java.security.spec.KeySpec;
33import java.security.spec.PKCS8EncodedKeySpec;
34import java.security.spec.X509EncodedKeySpec;
35import java.util.Arrays;
36import java.util.Enumeration;
37import java.util.Vector;
38
39public class KeyFactory2Test extends junit.framework.TestCase {
40
41	private static final String KEYFACTORY_ID = "KeyFactory.";
42
43	private String[] keyfactAlgs = null;
44
45	private String providerName = null;
46
47	static class KeepAlive extends Thread {
48		int sleepTime, iterations;
49
50		public KeepAlive(int sleepTime, int iterations) {
51			this.sleepTime = sleepTime;
52			this.iterations = iterations;
53		}
54
55		public void run() {
56			synchronized (this) {
57				this.notify();
58			}
59			for (int i = 0; i < iterations; i++) {
60				try {
61					Thread.sleep(sleepTime);
62					System.out.print("[KA]");
63				} catch (InterruptedException e) {
64					System.out.print("[I]");
65					break;
66				}
67			}
68		}
69	}
70
71	private KeepAlive createKeepAlive(String alg) {
72		if (alg.equals("RSA")) {
73			// 32 minutes
74			KeepAlive keepalive = new KeepAlive(240000, 8);
75			synchronized (keepalive) {
76				keepalive.start();
77				try {
78					keepalive.wait();
79				} catch (InterruptedException e) {
80					// ignore
81				}
82			}
83			return keepalive;
84		}
85		return null;
86	}
87
88	/**
89	 * @tests java.security.KeyFactory#generatePrivate(java.security.spec.KeySpec)
90	 */
91	public void test_generatePrivateLjava_security_spec_KeySpec() {
92		// Test for method java.security.PrivateKey
93		// java.security.KeyFactory.generatePrivate(java.security.spec.KeySpec)
94		for (int i = 0; i < keyfactAlgs.length; i++) {
95			try {
96				KeyFactory fact = KeyFactory.getInstance(keyfactAlgs[i],
97						providerName);
98				KeyPairGenerator keyGen = KeyPairGenerator
99						.getInstance(keyfactAlgs[i]);
100				SecureRandom random = new SecureRandom(); // We don't use
101				// getInstance
102				keyGen.initialize(1024, random);
103				KeepAlive keepalive = createKeepAlive(keyfactAlgs[i]);
104				KeyPair keys = keyGen.generateKeyPair();
105				if (keepalive != null) {
106					keepalive.interrupt();
107				}
108
109				KeySpec privateKeySpec = fact.getKeySpec(keys.getPrivate(),
110						getPrivateKeySpecClass(keyfactAlgs[i]));
111				PrivateKey privateKey = fact.generatePrivate(privateKeySpec);
112				boolean samePrivate = Arrays.equals(keys.getPrivate()
113						.getEncoded(), privateKey.getEncoded());
114				assertTrue(
115						"generatePrivate generated different key for algorithm "
116								+ keyfactAlgs[i], samePrivate);
117				fact.generatePrivate(new PKCS8EncodedKeySpec(keys.getPrivate()
118						.getEncoded()));
119			} catch (InvalidKeySpecException e) {
120				fail("invalid key spec for algorithm " + keyfactAlgs[i]);
121			} catch (NoSuchAlgorithmException e) {
122				fail("getInstance did not find algorithm " + keyfactAlgs[i]);
123			} catch (NoSuchProviderException e) {
124				fail("getInstance did not find provider " + providerName);
125			}
126		}
127	}
128
129	/**
130	 * @tests java.security.KeyFactory#generatePublic(java.security.spec.KeySpec)
131	 */
132	public void test_generatePublicLjava_security_spec_KeySpec() {
133		// Test for method java.security.PublicKey
134		// java.security.KeyFactory.generatePublic(java.security.spec.KeySpec)
135		for (int i = 0; i < keyfactAlgs.length; i++) {
136			try {
137				KeyFactory fact = KeyFactory.getInstance(keyfactAlgs[i],
138						providerName);
139				KeyPairGenerator keyGen = KeyPairGenerator
140						.getInstance(keyfactAlgs[i]);
141				// We don't use getInstance
142				SecureRandom random = new SecureRandom();
143				keyGen.initialize(1024, random);
144				KeepAlive keepalive = createKeepAlive(keyfactAlgs[i]);
145				KeyPair keys = keyGen.generateKeyPair();
146				if (keepalive != null) {
147					keepalive.interrupt();
148				}
149				KeySpec publicKeySpec = fact.getKeySpec(keys.getPublic(),
150						getPublicKeySpecClass(keyfactAlgs[i]));
151				PublicKey publicKey = fact.generatePublic(publicKeySpec);
152				boolean samePublic = Arrays.equals(keys.getPublic()
153						.getEncoded(), publicKey.getEncoded());
154				assertTrue(
155						"generatePublic generated different key for algorithm "
156								+ keyfactAlgs[i], samePublic);
157			} catch (NoSuchAlgorithmException e) {
158				fail("getInstance did not find algorithm " + keyfactAlgs[i]);
159			} catch (NoSuchProviderException e) {
160				fail("getInstance did not find provider " + providerName);
161			} catch (InvalidKeySpecException e) {
162				fail("invalid key spec for algorithm " + keyfactAlgs[i]);
163			}
164		}
165	}
166
167	/**
168	 * @tests java.security.KeyFactory#getAlgorithm()
169	 */
170	public void test_getAlgorithm() {
171		// Test for method java.lang.String
172		// java.security.KeyFactory.getAlgorithm()
173		for (int i = 0; i < keyfactAlgs.length; i++) {
174			try {
175				KeyFactory fact = KeyFactory.getInstance(keyfactAlgs[i],
176						providerName);
177				assertTrue("getAlgorithm ok for algorithm " + keyfactAlgs[i],
178						fact.getAlgorithm().equals(keyfactAlgs[i]));
179			} catch (NoSuchAlgorithmException e) {
180				fail("getInstance did not find algorithm " + keyfactAlgs[i]);
181			} catch (NoSuchProviderException e) {
182				fail("getInstance did not find provider " + providerName);
183			}
184		}// end for
185	}
186
187	/**
188	 * @tests java.security.KeyFactory#getInstance(java.lang.String)
189	 */
190	public void test_getInstanceLjava_lang_String() {
191		// Test for method java.security.KeyFactory
192		// java.security.KeyFactory.getInstance(java.lang.String)
193		for (int i = 0; i < keyfactAlgs.length; i++) {
194			try {
195				assertNotNull(KeyFactory.getInstance(keyfactAlgs[i]));
196			} catch (NoSuchAlgorithmException e) {
197				fail("getInstance did not find algorithm " + keyfactAlgs[i]);
198			}
199		}// end for
200	}
201
202	/**
203	 * @tests java.security.KeyFactory#getInstance(java.lang.String,
204	 *        java.lang.String)
205	 */
206	public void test_getInstanceLjava_lang_StringLjava_lang_String() throws Exception {
207
208		// Test1: Test for method java.security.KeyFactory
209		// java.security.KeyFactory.getInstance(java.lang.String,
210		// java.lang.String)
211		try {
212			Provider[] providers = Security.getProviders("KeyFactory.DSA");
213			if (providers != null) {
214				for (int i = 0; i < providers.length; i++) {
215					KeyFactory.getInstance("DSA", providers[i].getName());
216				}// end for
217			} else {
218				fail("No providers support KeyFactory.DSA");
219			}
220		} catch (NoSuchAlgorithmException e) {
221			fail("getInstance did not find algorithm");
222		} catch (NoSuchProviderException e) {
223			fail("getInstance did not find the provider");
224		}
225
226		// Test2: Test with null provider name
227		try {
228			KeyFactory.getInstance("DSA", (String) null);
229            fail("Expected IllegalArgumentException");
230		} catch (IllegalArgumentException e) {
231			// Expected
232		}
233	}
234
235	/**
236	 * @tests java.security.KeyFactory#getKeySpec(java.security.Key,
237	 *        java.lang.Class)
238	 */
239	public void test_getKeySpecLjava_security_KeyLjava_lang_Class() {
240		// Test for method java.security.spec.KeySpec
241		// java.security.KeyFactory.getKeySpec(java.security.Key,
242		// java.lang.Class)
243		for (int i = 0; i < keyfactAlgs.length; i++) {
244			try {
245				KeyFactory fact = KeyFactory.getInstance(keyfactAlgs[i],
246						providerName);
247				KeyPairGenerator keyGen = KeyPairGenerator
248						.getInstance(keyfactAlgs[i]);
249
250				// We don't use getInstance
251				SecureRandom random = new SecureRandom();
252				keyGen.initialize(1024, random);
253				KeepAlive keepalive = createKeepAlive(keyfactAlgs[i]);
254				KeyPair keys = keyGen.generateKeyPair();
255				if (keepalive != null) {
256					keepalive.interrupt();
257				}
258				KeySpec privateKeySpec = fact.getKeySpec(keys.getPrivate(),
259						getPrivateKeySpecClass(keyfactAlgs[i]));
260				KeySpec publicKeySpec = fact.getKeySpec(keys.getPublic(),
261						getPublicKeySpecClass(keyfactAlgs[i]));
262				PrivateKey privateKey = fact.generatePrivate(privateKeySpec);
263				PublicKey publicKey = fact.generatePublic(publicKeySpec);
264				boolean samePublic = Arrays.equals(keys.getPublic()
265						.getEncoded(), publicKey.getEncoded());
266				boolean samePrivate = Arrays.equals(keys.getPrivate()
267						.getEncoded(), privateKey.getEncoded());
268				assertTrue(
269						"generatePrivate generated different key for algorithm "
270								+ keyfactAlgs[i], samePrivate);
271				assertTrue(
272						"generatePublic generated different key for algorithm "
273								+ keyfactAlgs[i], samePublic);
274				KeySpec encodedSpec = fact.getKeySpec(keys.getPublic(),
275						X509EncodedKeySpec.class);
276				assertTrue("improper key spec for encoded public key",
277						encodedSpec.getClass().equals(X509EncodedKeySpec.class));
278				encodedSpec = fact.getKeySpec(keys.getPrivate(),
279						PKCS8EncodedKeySpec.class);
280				assertTrue("improper key spec for encoded private key",
281						encodedSpec.getClass()
282								.equals(PKCS8EncodedKeySpec.class));
283			} catch (NoSuchAlgorithmException e) {
284				fail("getInstance did not find algorithm " + keyfactAlgs[i]);
285			} catch (NoSuchProviderException e) {
286				fail("getInstance did not find provider " + providerName);
287			} catch (InvalidKeySpecException e) {
288				fail("invalid key spec for algorithm " + keyfactAlgs[i]);
289			}
290		}
291	}
292
293	/**
294	 * @tests java.security.KeyFactory#getProvider()
295	 */
296	public void test_getProvider() {
297		// Test for method java.security.Provider
298		// java.security.KeyFactory.getProvider()
299		for (int i = 0; i < keyfactAlgs.length; i++) {
300			try {
301				KeyFactory fact = KeyFactory.getInstance(keyfactAlgs[i]);
302				Provider p = fact.getProvider();
303				assertNotNull("provider is null for algorithm "
304						+ keyfactAlgs[i], p);
305			} catch (NoSuchAlgorithmException e) {
306				fail("getInstance did not find algorithm " + keyfactAlgs[i]);
307			}
308		}// end for
309	}
310
311	/**
312	 * @tests java.security.KeyFactory#translateKey(java.security.Key)
313	 */
314	public void test_translateKeyLjava_security_Key() {
315		// Test for method java.security.Key
316		// java.security.KeyFactory.translateKey(java.security.Key)
317		for (int i = 0; i < keyfactAlgs.length; i++) {
318			try {
319				KeyFactory fact = KeyFactory.getInstance(keyfactAlgs[i],
320						providerName);
321				KeyPairGenerator keyGen = KeyPairGenerator
322						.getInstance(keyfactAlgs[i]);
323
324				// We don't use getInstance
325				SecureRandom random = new SecureRandom();
326				keyGen.initialize(1024, random);
327				KeepAlive keepalive = createKeepAlive(keyfactAlgs[i]);
328				KeyPair keys = keyGen.generateKeyPair();
329				if (keepalive != null) {
330					keepalive.interrupt();
331				}
332				fact.translateKey(keys.getPrivate());
333			} catch (NoSuchAlgorithmException e) {
334				fail("getInstance did not find algorithm " + keyfactAlgs[i]);
335			} catch (NoSuchProviderException e) {
336				fail("getInstance did not find provider " + providerName);
337			} catch (InvalidKeyException e) {
338				fail("generatePublic did not generate right spec for algorithm "
339						+ keyfactAlgs[i]);
340			}
341		}
342	}
343
344	protected void setUp() {
345		if (keyfactAlgs == null) {
346            Provider[] providers = Security.getProviders();
347            // Arbitrarily use the first provider that supports
348            // KeyFactory algorithms
349            for (Provider provider : providers) {
350                providerName = provider.getName();
351                keyfactAlgs = getKeyFactoryAlgorithms(providerName);
352                if (keyfactAlgs.length != 0) {
353                    break;
354                }
355            }
356        }
357	}
358
359	/*
360	 * Returns the key algorithms that the given provider supports.
361	 */
362	private String[] getKeyFactoryAlgorithms(String providerName) {
363		Vector algs = new Vector();
364
365		Provider provider = Security.getProvider(providerName);
366		if (provider == null)
367			return new String[0];
368		Enumeration e = provider.keys();
369		while (e.hasMoreElements()) {
370			String algorithm = (String) e.nextElement();
371			if (algorithm.startsWith(KEYFACTORY_ID) && !algorithm.contains(" ")) {
372				algs.addElement(algorithm.substring(KEYFACTORY_ID.length()));
373			}
374		}
375
376		return (String[]) algs.toArray(new String[algs.size()]);
377	}
378
379	/**
380	 * Returns the public key spec class for a given algorithm, or null if it is
381	 * not known.
382	 */
383	private Class getPrivateKeySpecClass(String algName) {
384		if (algName.equals("RSA")) {
385			return java.security.spec.RSAPrivateCrtKeySpec.class;
386		}
387		if (algName.equals("DSA")) {
388			return java.security.spec.DSAPrivateKeySpec.class;
389		}
390		return null;
391	}
392
393	/**
394	 * Returns the private key spec class for a given algorithm, or null if it
395	 * is not known.
396	 */
397	private Class getPublicKeySpecClass(String algName) {
398		if (algName.equals("RSA")) {
399			return java.security.spec.RSAPublicKeySpec.class;
400		}
401		if (algName.equals("DSA")) {
402			return java.security.spec.DSAPublicKeySpec.class;
403		}
404		return null;
405	}
406}
407