1package org.apache.harmony.security.tests.java.security;
2
3import junit.framework.TestCase;
4
5import java.lang.reflect.Constructor;
6import java.lang.reflect.InvocationTargetException;
7import java.security.InvalidKeyException;
8import java.security.Key;
9import java.security.KeyFactory;
10import java.security.KeyFactorySpi;
11import java.security.NoSuchAlgorithmException;
12import java.security.NoSuchProviderException;
13import java.security.PrivateKey;
14import java.security.Provider;
15import java.security.PublicKey;
16import java.security.Security;
17import java.security.spec.DSAPublicKeySpec;
18import java.security.spec.InvalidKeySpecException;
19import java.security.spec.KeySpec;
20import java.util.Arrays;
21
22public class KeyFactoryTest extends TestCase {
23
24    Provider provider;
25    boolean exceptionThrown;
26
27    Provider existingProvider;
28
29    @Override
30    protected void setUp() throws Exception {
31        super.setUp();
32        exceptionThrown = false;
33
34        Provider[] providers = Security.getProviders();
35        if (providers.length == 0) {
36            fail("no providers found");
37        }
38
39        existingProvider = providers[0];
40
41        provider = new TestKeyFactoryProvider();
42        Security.addProvider(provider);
43    }
44
45    @Override
46    protected void tearDown() throws Exception {
47        super.tearDown();
48        Security.removeProvider(provider.getName());
49    }
50
51    @SuppressWarnings("unchecked")
52    public void testGetInstanceString() {
53        try {
54            KeyFactory factory = KeyFactory.getInstance(TEST_KEYFACTORY_NAME);
55            assertNotNull(factory);
56        } catch (NoSuchAlgorithmException e) {
57            fail("unexpected exception: " + e);
58        }
59
60        String[] parameters = {
61                "UnknownKeyFactory",
62                null
63        };
64
65        Class[] exceptions = {
66                NoSuchAlgorithmException.class,
67                NullPointerException.class
68        };
69
70        for (int i = 0; i < parameters.length; i++) {
71            String algorithm = parameters[i];
72            exceptionThrown = false;
73            String message = "getInstance(" + (algorithm == null ? "null" : "\"" + algorithm + "\"") + ")";
74            try {
75                KeyFactory.getInstance(algorithm);
76            } catch (Exception e) {
77                checkException(message, e, exceptions[i]);
78            } finally {
79                checkException(message, null, exceptions[i]);
80            }
81        }
82
83    }
84
85    @SuppressWarnings("unchecked")
86    public void testGetInstanceStringString() {
87        try {
88            KeyFactory factory = KeyFactory.getInstance(TEST_KEYFACTORY_NAME, TEST_PROVIDER_NAME);
89            assertNotNull(factory);
90        } catch (NoSuchAlgorithmException e) {
91            fail("unexpected exception: " + e);
92        } catch (NoSuchProviderException e) {
93            fail("unexpected exception: " + e);
94        }
95
96        String[][] combinations = {
97                { "UnknownKeyFactory", TEST_PROVIDER_NAME},
98                { TEST_KEYFACTORY_NAME, "UnknownProvider"},
99                { TEST_KEYFACTORY_NAME, existingProvider.getName() },
100                { null, TEST_PROVIDER_NAME },
101                { TEST_KEYFACTORY_NAME, null },
102                { null, null}
103        };
104
105        Class[] exceptions = {
106                NoSuchAlgorithmException.class,
107                NoSuchProviderException.class,
108                NoSuchAlgorithmException.class,
109                NullPointerException.class,
110                IllegalArgumentException.class,
111                IllegalArgumentException.class
112        };
113
114        for (int i = 0; i < combinations.length; i++) {
115            String[] combination = combinations[i];
116            String message = "getInstance(\"" + combination[0] + "\", \"" + combination[1] + "\")";
117            exceptionThrown = false;
118            try {
119                KeyFactory.getInstance(combination[0], combination[1]);
120            } catch (Exception e) {
121                checkException(message, e, exceptions[i]);
122            } finally {
123                checkException(message, null, exceptions[i]);
124            }
125        }
126    }
127
128    @SuppressWarnings("unchecked")
129    public void testGetInstanceStringProvider() {
130        try {
131            KeyFactory factory = KeyFactory.getInstance(TEST_KEYFACTORY_NAME, provider);
132            assertNotNull(factory);
133        } catch (NoSuchAlgorithmException e) {
134            fail("unexpected exception: " + e);
135        }
136
137        String[] algorithms = {
138                "UnknownKeyFactory",
139                null,
140                TEST_KEYFACTORY_NAME,
141                TEST_KEYFACTORY_NAME
142        };
143
144        Provider[] providers = {
145                provider,
146                provider,
147                existingProvider,
148                null
149        };
150
151        Class[] exceptions = {
152                NoSuchAlgorithmException.class,
153                NullPointerException.class,
154                NoSuchAlgorithmException.class,
155                IllegalArgumentException.class
156        };
157
158        for (int i = 0; i < algorithms.length; i++) {
159            String algorithm = algorithms[i];
160            Provider provider = providers[i];
161            String message = "getInstance(" +
162                (algorithm == null ? "null" : "\"" + algorithm + "\"") +
163                ", " +
164                (provider == null ? "null" : "provider");
165            exceptionThrown = false;
166            try {
167                KeyFactory.getInstance(algorithm, provider);
168            } catch (Exception e) {
169                checkException(message, e, exceptions[i]);
170            } finally {
171                checkException(message, null, exceptions[i]);
172            }
173
174        }
175    }
176
177    @SuppressWarnings("unchecked")
178    public void testGeneratePublic() {
179        KeyFactory factory = null;
180        try {
181            factory = KeyFactory.getInstance(TEST_KEYFACTORY_NAME);
182        } catch (NoSuchAlgorithmException e) {
183            fail("unexpected exception: " + e);
184        }
185
186        assertNotNull(factory);
187
188        try {
189            TestPublicKey key = new TestPublicKey();
190            TestPublicKeySpec keySpec = new TestPublicKeySpec(key);
191            PublicKey publicKey = factory.generatePublic(keySpec);
192            assertNotNull(publicKey);
193            assertTrue(Arrays.equals(key.encoded, publicKey.getEncoded()));
194        } catch (InvalidKeySpecException e) {
195            fail("unexpected exception: " + e);
196        }
197
198        KeySpec[] keySpecs = {
199                new TestPrivateKeySpec(new TestPrivateKey()),
200                null,
201                new DSAPublicKeySpec(null, null, null, null)
202        };
203
204        Class[] exceptions = {
205                InvalidKeySpecException.class,
206                NullPointerException.class,
207                InvalidKeySpecException.class
208        };
209
210        for (int i = 0; i < keySpecs.length; i++) {
211            KeySpec keySpec = keySpecs[i];
212            String message = "generatePublic(" +
213                (keySpec == null ? "null" : keySpec.toString()) + ")";
214
215            try {
216                PublicKey generatePublic = factory.generatePublic(keySpec);
217                assertNotNull(generatePublic);
218            } catch (Exception e) {
219                checkException(message, e, exceptions[i]);
220            } finally {
221                checkException(message, null, exceptions[i]);
222            }
223        }
224    }
225
226    @SuppressWarnings("unchecked")
227    public void testGeneratePrivate() {
228        KeyFactory factory = null;
229        try {
230            factory = KeyFactory.getInstance(TEST_KEYFACTORY_NAME);
231        } catch (NoSuchAlgorithmException e) {
232            fail("unexpected exception: " + e);
233        }
234
235        assertNotNull(factory);
236
237        try {
238            TestPrivateKey key = new TestPrivateKey();
239            TestPrivateKeySpec keySpec = new TestPrivateKeySpec(key);
240            PrivateKey privateKey = factory.generatePrivate(keySpec);
241            assertNotNull(privateKey);
242            assertTrue(Arrays.equals(key.getEncoded(), privateKey.getEncoded()));
243        } catch (InvalidKeySpecException e) {
244            fail("unexpected exception: " + e);
245        }
246
247        KeySpec[] keySpecs = {
248                new TestPublicKeySpec(new TestPublicKey()),
249                null,
250                new DSAPublicKeySpec(null, null, null, null)
251        };
252
253        Class[] exceptions = {
254                InvalidKeySpecException.class,
255                NullPointerException.class,
256                InvalidKeySpecException.class
257        };
258
259        for (int i = 0; i < keySpecs.length; i++) {
260            KeySpec keySpec = keySpecs[i];
261            exceptionThrown = false;
262            String message = "generatePrivate(" +
263                (keySpec == null ? "null" : keySpec.toString()) + ")";
264            try {
265                factory.generatePrivate(keySpec);
266            } catch (Exception e) {
267                checkException(message, e, exceptions[i]);
268            } finally {
269                checkException(message, null, exceptions[i]);
270            }
271        }
272    }
273
274    @SuppressWarnings("unchecked")
275    public void testGetKeySpec() {
276        KeyFactory factory = null;
277        try {
278            factory = KeyFactory.getInstance(TEST_KEYFACTORY_NAME);
279        } catch (NoSuchAlgorithmException e) {
280            fail("unexpected exception: " + e);
281        }
282
283        assertNotNull(factory);
284
285        {
286            Key[] keys = {
287                    new TestPrivateKey(),
288                    new TestPublicKey(),
289                    new TestPrivateKey(new byte[] { 42, 41, 40 }),
290                    new TestPublicKey(new byte[] { 40, 41, 42 })
291            };
292
293            Class[] keySpecs = {
294                    TestPrivateKeySpec.class,
295                    TestPublicKeySpec.class,
296                    TestPrivateKeySpec.class,
297                    TestPublicKeySpec.class,
298            };
299
300            for (int i = 0; i < keys.length; i++) {
301                Key key = keys[i];
302                Class keySpec = keySpecs[i];
303                String message = "getKeySpec(" + key.toString() + ", " + keySpec.toString() + ")";
304                try {
305                    KeySpec spec = factory.getKeySpec(key, keySpec);
306                    assertNotNull(spec);
307                    assertTrue(spec.getClass() == keySpec);
308                } catch (InvalidKeySpecException e) {
309                    fail("unexpected exception: " + e);
310                }
311            }
312        }
313
314        {
315            Key[] keys = {
316                    new AnotherKey(),
317                    null,
318                    new TestPrivateKey(),
319                    null,
320            };
321
322            Class[] keySpecs = {
323                    KeySpec.class,
324                    TestPrivateKeySpec.class,
325                    null,
326                    null,
327            };
328
329            Class[] exceptions = {
330                    InvalidKeySpecException.class,
331                    NullPointerException.class,
332                    InvalidKeySpecException.class,
333                    NullPointerException.class
334            };
335
336            for (int i = 0; i < keys.length; i++) {
337                Key key = keys[i];
338                Class keySpec = keySpecs[i];
339                exceptionThrown = false;
340                String message = "getKeySpec(" +
341                    (key == null ? "null" : key.toString()) +
342                    ", " +
343                    (keySpec == null ? "null" : keySpec.toString()) + ")";
344                try {
345                    factory.getKeySpec(key, keySpec);
346                } catch (Exception e) {
347                    checkException(message, e, exceptions[i]);
348                } finally {
349                    checkException(message, null, exceptions[i]);
350                }
351
352            }
353        }
354    }
355
356    @SuppressWarnings("unchecked")
357    public void testTranslateKey() {
358        KeyFactory factory = null;
359        try {
360            factory = KeyFactory.getInstance(TEST_KEYFACTORY_NAME);
361        } catch (NoSuchAlgorithmException e) {
362            fail("unexpected exception: " + e);
363        }
364
365        assertNotNull(factory);
366
367        {
368            Key[] keys = {
369                    new TestPrivateKey(),
370                    new TestPublicKey()
371            };
372
373            Class[] translated = {
374                    TestPublicKey.class,
375                    TestPrivateKey.class
376            };
377
378            for (int i = 0; i < keys.length; i++) {
379                Key key = keys[i];
380                Class translate = translated[i];
381                try {
382                    Key translateKey = factory.translateKey(key);
383                    assertNotNull(translateKey);
384                    assertEquals(translate, translateKey.getClass());
385                } catch (InvalidKeyException e) {
386                    fail("unexpected exception: " + e);
387                }
388            }
389        }
390
391        {
392            Key[] keys = {
393                    new AnotherKey(),
394                    null
395            };
396
397            Class[] exceptions = {
398                    InvalidKeyException.class,
399                    NullPointerException.class
400            };
401
402            for (int i = 0; i < keys.length; i++) {
403                Key key = keys[i];
404                String message = "translateKey(" +
405                    (key == null ? "null" : key.toString()) + ")";
406                exceptionThrown = false;
407                try {
408                    factory.translateKey(key);
409                } catch (Exception e) {
410                    checkException(message, e, exceptions[i]);
411                } finally {
412                    checkException(message, null, exceptions[i]);
413                }
414            }
415        }
416    }
417
418    private static final String TEST_PROVIDER_NAME = "TestKeyFactoryProvider";
419    private static final String TEST_KEYFACTORY_NAME = "TestKeyFactory";
420
421    static class TestKeyFactoryProvider extends Provider {
422
423        protected TestKeyFactoryProvider() {
424            super(TEST_PROVIDER_NAME, 1.1, "Test KeyFactory Provider");
425            put("KeyFactory." + TEST_KEYFACTORY_NAME, TestKeyFactorySpi.class.getName());
426        }
427    }
428
429    public static class TestKeyFactorySpi extends KeyFactorySpi {
430
431        @Override
432        protected PrivateKey engineGeneratePrivate(KeySpec keySpec)
433                throws InvalidKeySpecException {
434            if (TestPrivateKeySpec.class == keySpec.getClass()) {
435                return new TestPrivateKey(((TestPrivateKeySpec)keySpec).encoded);
436            }
437
438            throw new InvalidKeySpecException();
439        }
440
441        @Override
442        protected PublicKey engineGeneratePublic(KeySpec keySpec)
443                throws InvalidKeySpecException {
444            if (TestPublicKeySpec.class == keySpec.getClass()) {
445                return new TestPublicKey(((TestPublicKeySpec)keySpec).encoded);
446            }
447            throw new InvalidKeySpecException();
448        }
449
450        @Override
451        protected <T extends KeySpec> T engineGetKeySpec(Key key,
452                Class<T> keySpec) throws InvalidKeySpecException {
453
454            if (key == null) {
455                throw new NullPointerException();
456            }
457
458            Constructor<T> constructor = null;
459            if (TestPrivateKeySpec.class == keySpec) {
460                try {
461                    constructor = keySpec.getConstructor(TestPrivateKey.class);
462                } catch (SecurityException e) {
463                    throw new InvalidKeySpecException(e);
464                } catch (NoSuchMethodException e) {
465                    throw new InvalidKeySpecException(e);
466                }
467            } else if (TestPublicKeySpec.class == keySpec) {
468                try {
469                    constructor = keySpec.getConstructor(TestPublicKey.class);
470                } catch (SecurityException e) {
471                    throw new InvalidKeySpecException(e);
472                } catch (NoSuchMethodException e) {
473                    throw new InvalidKeySpecException(e);
474                }
475            }
476
477            if (constructor == null) {
478                throw new InvalidKeySpecException();
479            }
480
481            try {
482                return constructor.newInstance(key);
483            } catch (IllegalArgumentException e) {
484                throw new InvalidKeySpecException(e);
485            } catch (InstantiationException e) {
486                throw new InvalidKeySpecException(e);
487            } catch (IllegalAccessException e) {
488                throw new InvalidKeySpecException(e);
489            } catch (InvocationTargetException e) {
490                throw new InvalidKeySpecException(e);
491            }
492        }
493
494        @Override
495        protected Key engineTranslateKey(Key key) throws InvalidKeyException {
496            if (TestPrivateKey.class == key.getClass()) {
497                return new TestPublicKey();
498            } else if (TestPublicKey.class == key.getClass()) {
499                return new TestPrivateKey();
500            }
501            throw new InvalidKeyException();
502        }
503
504    }
505
506    static class TestPrivateKeySpec implements KeySpec {
507        @SuppressWarnings("unused")
508        private final byte[] encoded;
509
510        public TestPrivateKeySpec(TestPrivateKey key) {
511            this.encoded = key.getEncoded();
512        }
513    }
514
515    static class TestPublicKeySpec implements KeySpec {
516        @SuppressWarnings("unused")
517        private final byte[] encoded;
518
519        public TestPublicKeySpec(TestPublicKey key) {
520            this.encoded = key.getEncoded();
521        }
522    }
523
524    static class TestPrivateKey implements PrivateKey {
525
526        private final byte[] encoded;
527
528        public TestPrivateKey() {
529            encoded = new byte[] {3, 4, 5};
530        }
531
532        public TestPrivateKey(byte[] encoded) {
533            this.encoded = encoded;
534        }
535
536        public String getAlgorithm() {
537            return "TestPrivateKey";
538        }
539
540        public byte[] getEncoded() {
541            return encoded;
542        }
543
544        public String getFormat() {
545            return "TestFormat";
546        }
547    }
548
549    static class TestPublicKey implements PublicKey {
550
551        private final byte[] encoded;
552
553        public TestPublicKey() {
554            encoded = new byte[] {3, 4, 5};
555        }
556
557        public TestPublicKey(byte[] encoded) {
558            this.encoded = encoded;
559        }
560
561        public String getAlgorithm() {
562            return "TestPublicKey";
563        }
564
565        public byte[] getEncoded() {
566            return encoded;
567        }
568
569        public String getFormat() {
570            return "TestFormat";
571        }
572    }
573
574    static class AnotherKey implements Key {
575
576        public String getAlgorithm() {
577            return "AnotherKey";
578        }
579
580        public byte[] getEncoded() {
581            return null;
582        }
583
584        public String getFormat() {
585            return "AnotherFormat";
586        }
587
588    }
589
590    private void checkException(String message, Exception thrown, Class<? extends Exception> expected) {
591        if (thrown == null) {
592            if (!exceptionThrown) {
593                fail(message + ", expected " + expected.getName());
594            }
595        } else if (expected == thrown.getClass()) {
596            exceptionThrown = true;
597            // ok
598        } else {
599            exceptionThrown = true;
600            fail(message + ", unexpected exception: " + thrown + ", expected: " + expected.getName());
601        }
602    }
603
604}
605