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