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
18/**
19 * @author Vera Y. Petrashkova
20 */
21
22package org.apache.harmony.security.tests.java.security;
23
24import java.io.File;
25import java.io.FileOutputStream;
26import java.io.IOException;
27import java.security.InvalidKeyException;
28import java.security.KeyStore;
29import java.security.KeyStoreException;
30import java.security.NoSuchAlgorithmException;
31import java.security.NoSuchProviderException;
32import java.security.PrivateKey;
33import java.security.Provider;
34import java.security.PublicKey;
35import java.security.SignatureException;
36import java.security.cert.Certificate;
37import java.security.cert.CertificateEncodingException;
38import java.security.cert.CertificateException;
39import java.security.spec.InvalidKeySpecException;
40import java.util.Enumeration;
41
42import junit.framework.TestCase;
43
44import org.apache.harmony.security.tests.support.KeyStoreTestSupport;
45import org.apache.harmony.security.tests.support.SpiEngUtils;
46import org.apache.harmony.security.tests.support.TestKeyPair;
47import org.apache.harmony.security.tests.support.tmpCallbackHandler;
48
49/**
50 * Tests for <code>KeyStore.Builder</code> class
51 */
52public class KSBuilder_ImplTest extends TestCase {
53
54    private static char[] pass = { 's', 't', 'o', 'r', 'e', 'p', 'w', 'd' };
55
56    private KeyStore.PasswordProtection protPass = new KeyStore.PasswordProtection(pass);
57    private tmpCallbackHandler tmpCall = new tmpCallbackHandler();
58    private KeyStore.CallbackHandlerProtection callbackHand = new KeyStore.CallbackHandlerProtection(tmpCall);
59    private myProtectionParameter myProtParam = new myProtectionParameter(new byte[5]);
60    public static String[] validValues = KeyStoreTestSupport.validValues;
61
62    private static String defaultType = KeyStoreTestSupport.defaultType;
63
64    private static boolean JKSSupported = false;
65
66    private static Provider defaultProvider = null;
67
68    static {
69        defaultProvider = SpiEngUtils.isSupport(
70                KeyStoreTestSupport.defaultType, KeyStoreTestSupport.srvKeyStore);
71        JKSSupported = (defaultProvider != null);
72    }
73
74    // Creates empty KeyStore and loads it to file
75    private File createKS() throws Exception {
76        FileOutputStream fos = null;
77        File ff = File.createTempFile("KSBuilder_ImplTest", "keystore");
78        ff.deleteOnExit();
79        try {
80
81            KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
82            fos = new FileOutputStream(ff);
83            ks.load(null, null);
84            ks.store(fos, pass);
85        } finally {
86            if (fos != null) {
87                try {
88                    fos.close();
89                } catch (IOException e) {
90                }
91            }
92        }
93        return ff;
94    }
95
96    /*
97     * Test for method:
98     * <code>newInstance(KeyStore keyStore, ProtectionParameter protectionParameter)</code>
99     * <code>getKeyStore()</code>
100     * <code>getProtectionParameter(String alias)</code>
101     * Assertions:
102     * throws NullPointerException if keyStore or protectionParameter is null
103     * throws IllegalArgumentException if keyStore was not initialized
104     * returns new object.
105     *
106     * getKeyStore() returns specified keystore;
107     * getProtectionParameter(String alias)
108     * throws NullPointerException when alias is null;
109     * throws KeyStoreException when alias is not available;
110     * returns ProtectionParameter which is used in newInstance(...)
111     *
112     */
113    public void testNewInstanceKeyStoreProtectionParameter()
114            throws KeyStoreException, NoSuchAlgorithmException, IOException,
115            CertificateException, InvalidKeyException, InvalidKeySpecException {
116        // exceptions verification
117        try {
118            KeyStore.Builder.newInstance(null, protPass);
119            fail("NullPointerException must be thrown when KeyStore is null");
120        } catch (NullPointerException e) {
121        }
122        if (!JKSSupported) {
123            fail(defaultType + " type is not supported");
124            return;
125        }
126        KeyStore.Builder ksB;
127        KeyStore ks = KeyStore.getInstance(defaultType);
128        try {
129            KeyStore.Builder.newInstance(ks, null);
130            fail("NullPointerException must be thrown when ProtectionParameter is null");
131        } catch (NullPointerException e) {
132        }
133
134        KeyStore.PasswordProtection protPass1 = new KeyStore.PasswordProtection(
135                pass);
136        KeyStore.ProtectionParameter[] pp = { protPass, protPass1,
137                callbackHand, myProtParam };
138        TestKeyPair tkp = new TestKeyPair("DSA");
139        Certificate certs[] = {
140                new MCertificate("DSA", tkp.getPrivate()
141                        .getEncoded()),
142                new MCertificate("DSA", tkp.getPrivate()
143                        .getEncoded()) };
144        PrivateKey privKey = tkp.getPrivate();
145
146        KeyStore.PrivateKeyEntry pKey = new KeyStore.PrivateKeyEntry(privKey,
147                certs);
148        for (int i = 0; i < pp.length; i++) {
149            ks = KeyStore.getInstance(defaultType);
150            try {
151                KeyStore.Builder.newInstance(ks, pp[i]);
152                fail("IllegalArgumentException must be thrown because KeyStore was not initialized");
153            } catch (IllegalArgumentException e) {
154            }
155            ks.load(null, pass);
156            ksB = KeyStore.Builder.newInstance(ks, pp[i]);
157
158            assertEquals("Incorrect KeyStore", ksB.getKeyStore().size(), 0);
159
160            ks.setEntry("aaa", pKey, pp[0]);
161            ksB = KeyStore.Builder.newInstance(ks, pp[i]);
162
163            // verification getKeyStore() and getProtectionParameter(String
164            // alias)
165            assertEquals("Incorrect KeyStore", ks, ksB.getKeyStore());
166
167            try {
168                ksB.getProtectionParameter(null);
169                fail("NullPointerException must be thrown");
170            } catch (NullPointerException e) {
171            }
172            try {
173                assertEquals(ksB.getProtectionParameter("aaa"), pp[i]);
174            } catch (KeyStoreException e) {
175                fail("Unexpected: " + e.toString() + " was thrown");
176            }
177
178            try {
179                assertEquals(ksB.getProtectionParameter("Bad alias"), pp[i]);
180            } catch (KeyStoreException e) {
181                // KeyStoreException might be thrown because there is no entry with such alias
182            }
183
184            try {
185                assertEquals(ksB.getProtectionParameter(""), pp[i]);
186            } catch (KeyStoreException e) {
187                // KeyStoreException might be thrown because there is no entry with such alias
188            }
189
190            KeyStore.ProtectionParameter pPar = ksB
191                    .getProtectionParameter("aaa");
192
193            switch (i) {
194                case 0:
195                    assertTrue(pPar instanceof KeyStore.PasswordProtection);
196                    break;
197                case 1:
198                    assertTrue(pPar instanceof KeyStore.PasswordProtection);
199                    break;
200                case 2:
201                    assertTrue(pPar instanceof KeyStore.CallbackHandlerProtection);
202                    break;
203                case 3:
204                    assertTrue(pPar instanceof myProtectionParameter);
205                    break;
206                default:
207                    fail("Incorrect protection parameter");
208            }
209            assertEquals(pPar, pp[i]);
210        }
211    }
212
213    /*
214    * Test for methods:
215    * <code>newInstance(String type, Provider provider, File file,
216    * ProtectionParameter protectionParameter)</code>
217    * <code>getKeyStore()</code>
218    * <code>getProtectionParameter(String alias)</code>
219    * Assertions:
220    * throws NullPointerException if type, file or protectionParameter is null;
221    * throws IllegalArgumentException if file does not exist or is not file;
222    * throws IllegalArgumentException if ProtectionParameter is not
223    * PasswordProtection or CallbackHandlerProtection;
224    * returns new object
225    *
226    * getKeyStore() returns specified keystore;
227    * getProtectionParameter(String alias)
228    * throws NullPointerException when alias is null;
229    * throws KeyStoreException when alias is not available;
230    * returns ProtectionParameter which is used in newInstance(...)
231    *
232    */
233    public void testNewInstanceStringProviderFileProtectionParameter()
234            throws Exception {
235        if (!JKSSupported) {
236            fail(defaultType + " type is not supported");
237            return;
238        }
239        File fl = File.createTempFile("KSBuilder_ImplTest", "keystore");
240        fl.deleteOnExit();
241        KeyStore.Builder ksB;
242        KeyStore.Builder ksB1;
243        KeyStore ks = null;
244        KeyStore ks1 = null;
245
246        myProtectionParameter myPP = new myProtectionParameter(new byte[5]);
247        // check exceptions
248        try {
249
250            KeyStore.Builder.newInstance(null, defaultProvider, fl, protPass);
251            fail("NullPointerException must be thrown when type is null");
252        } catch (NullPointerException e) {
253        }
254        try {
255            KeyStore.Builder.newInstance(defaultType, defaultProvider, null,
256                    protPass);
257            fail("NullPointerException must be thrown when file is null");
258        } catch (NullPointerException e) {
259        }
260        try {
261            KeyStore.Builder
262                    .newInstance(defaultType, defaultProvider, fl, null);
263            fail("NullPointerException must be thrown when ProtectionParameter is null");
264        } catch (NullPointerException e) {
265        }
266        try {
267            KeyStore.Builder
268                    .newInstance(defaultType, defaultProvider, fl, myPP);
269            fail("IllegalArgumentException must be thrown when ProtectionParameter is not correct");
270        } catch (IllegalArgumentException e) {
271        }
272        try {
273            KeyStore.Builder.newInstance(defaultType, defaultProvider,
274                    new File(fl.getAbsolutePath().concat("should_absent")),
275                    protPass);
276            fail("IllegalArgumentException must be thrown when file does not exist");
277        } catch (IllegalArgumentException e) {
278        }
279        try {
280            // 'file' param points to directory
281            KeyStore.Builder.newInstance(defaultType, defaultProvider,
282                    fl.getParentFile(), protPass);
283            fail("IllegalArgumentException must be thrown when file does not exist");
284        } catch (IllegalArgumentException e) {
285        }
286        ksB = KeyStore.Builder.newInstance(defaultType, defaultProvider, fl,
287                protPass);
288        try {
289            ksB.getKeyStore();
290            fail("KeyStoreException must be throw because file is empty");
291        } catch (KeyStoreException e) {
292        }
293
294        fl = createKS();
295        KeyStore.ProtectionParameter[] pp = { myPP, protPass, callbackHand };
296        for (int i = 0; i < pp.length; i++) {
297            if (i == 0) {
298                try {
299                    KeyStore.Builder.newInstance(defaultType, null, fl, pp[i]);
300                    fail("IllegalArgumentException must be thrown for incorrect ProtectionParameter");
301                } catch (IllegalArgumentException e) {
302                }
303                try {
304                    KeyStore.Builder.newInstance(defaultType, defaultProvider,
305                            fl, pp[i]);
306                    fail("IllegalArgumentException must be thrown for incorrect ProtectionParameter");
307                } catch (IllegalArgumentException e) {
308                }
309                continue;
310            }
311            ksB = KeyStore.Builder.newInstance(defaultType, null, fl, pp[i]);
312            ksB1 = KeyStore.Builder.newInstance(defaultType, defaultProvider,
313                    fl, pp[i]);
314            try {
315                ks = ksB.getKeyStore();
316                if (i == 2) {
317                    fail("KeyStoreException must be thrown for incorrect ProtectionParameter");
318                } else {
319                    assertEquals("Incorrect KeyStore size", ks.size(), 0);
320                }
321            } catch (KeyStoreException e) {
322                if (i == 2) {
323                    continue;
324                }
325                fail("Unexpected KeyException was thrown");
326            }
327            try {
328                ks1 = ksB1.getKeyStore();
329                if (i == 2) {
330                    fail("KeyStoreException must be thrown for incorrect ProtectionParameter");
331                }
332            } catch (KeyStoreException e) {
333                if (i == 2) {
334                    continue;
335                }
336                fail("Unexpected KeyException was thrown");
337            }
338            assertEquals("Incorrect KeyStore size", ks.size(), ks1.size());
339            Enumeration iter = ks.aliases();
340            String aName;
341
342            while (iter.hasMoreElements()) {
343                aName = (String) iter.nextElement();
344                assertEquals("Incorrect ProtectionParameter", ksB
345                        .getProtectionParameter(aName), pp[i]);
346            }
347
348            try {
349                assertEquals(ksB.getProtectionParameter("Bad alias"), pp[i]);
350            } catch (KeyStoreException e) {
351                // KeyStoreException might be thrown because there is no entry with such alias
352            }
353
354            iter = ks1.aliases();
355            while (iter.hasMoreElements()) {
356                aName = (String) iter.nextElement();
357                assertEquals("Incorrect ProtectionParameter", ksB1
358                        .getProtectionParameter(aName), pp[i]);
359            }
360
361            try {
362                assertEquals(ksB1.getProtectionParameter("Bad alias"), pp[i]);
363            } catch (KeyStoreException e) {
364                // KeyStoreException might be thrown because there is no entry with such alias
365            }
366        }
367    }
368
369    /*
370    * Test for method:
371    * <code>newInstance(String type, Provider provider,
372    * ProtectionParameter protectionParameter)</code>
373    * <code>getKeyStore()</code>
374    * <code>getProtectionParameter(String alias)</code>
375    * Assertions:
376    * throws NullPointerException if type, or protectionParameter is null;
377    * returns new object
378    *
379    * getKeyStore() returns empty keystore
380    * getProtectionParameter(String alias)
381    * throws NullPointerException when alias is null;
382    * throws KeyStoreException when alias is not available
383    *
384    */
385    public void testNewInstanceStringProviderProtectionParameter()
386            throws KeyStoreException {
387        if (!JKSSupported) {
388            fail(defaultType + " type is not supported");
389            return;
390        }
391        try {
392            KeyStore.Builder.newInstance(null,
393                    defaultProvider, protPass);
394            fail("NullPointerException must be thrown when type is null");
395        } catch (NullPointerException e) {
396        }
397        try {
398            KeyStore.Builder.newInstance(defaultType,
399                    defaultProvider, null);
400            fail("NullPointerException must be thrown when ProtectionParameter is null");
401        } catch (NullPointerException e) {
402        }
403        myProtectionParameter myPP = new myProtectionParameter(new byte[5]);
404        KeyStore.ProtectionParameter[] pp = { protPass, myPP, callbackHand };
405        KeyStore.Builder ksB, ksB1;
406        KeyStore ks = null;
407        for (int i = 0; i < pp.length; i++) {
408            ksB = KeyStore.Builder.newInstance(defaultType, defaultProvider,
409                    pp[i]);
410            ksB1 = KeyStore.Builder.newInstance(defaultType, null, pp[i]);
411            switch (i) {
412                case 0:
413                    try {
414                        ks = ksB.getKeyStore();
415                        assertNotNull("KeyStore is null", ks);
416                        try {
417                            assertEquals(ksB.getProtectionParameter("Bad alias"),
418                                    pp[i]);
419                        } catch (KeyStoreException e) {
420                            // KeyStoreException might be thrown because there is no entry with such alias
421                        }
422
423                        ks = ksB1.getKeyStore();
424                        assertNotNull("KeyStore is null", ks);
425
426                        try {
427                            assertEquals(ksB1.getProtectionParameter("Bad alias"),
428                                    pp[i]);
429                        } catch (KeyStoreException e) {
430                            // KeyStoreException might be thrown because there is no entry with such alias
431                        }
432                    } catch (KeyStoreException e) {
433                        try {
434                            ks = ksB.getKeyStore();
435                        } catch (KeyStoreException e1) {
436                            assertEquals("Incorrect exception", e.getMessage(), e1
437                                    .getMessage());
438                        }
439                    }
440                    break;
441                case 1:
442                case 2:
443                    Exception ex1 = null;
444                    Exception ex2 = null;
445                    try {
446                        ks = ksB.getKeyStore();
447                    } catch (KeyStoreException e) {
448                        ex1 = e;
449                    }
450                    try {
451                        ks = ksB.getKeyStore();
452                    } catch (KeyStoreException e) {
453                        ex2 = e;
454                    }
455                    assertEquals("Incorrect exception", ex1.getMessage(), ex2
456                            .getMessage());
457
458
459                    try {
460                        ksB.getProtectionParameter("aaa");
461                        fail("IllegalStateException must be thrown because getKeyStore() was not invoked");
462                    } catch (IllegalStateException e) {
463                    }
464
465                    try {
466                        ks = ksB1.getKeyStore();
467                    } catch (KeyStoreException e) {
468                        ex1 = e;
469                    }
470                    try {
471                        ks = ksB1.getKeyStore();
472                    } catch (KeyStoreException e) {
473                        ex2 = e;
474                    }
475                    assertEquals("Incorrect exception", ex1.getMessage(), ex2
476                            .getMessage());
477
478
479                    try {
480                        ksB1.getProtectionParameter("aaa");
481                        fail("IllegalStateException must be thrown because getKeyStore() was not invoked");
482                    } catch (IllegalStateException e) {
483                    }
484                    break;
485
486            }
487        }
488    }
489
490    /**
491     * Additional class for creation Certificate object
492     */
493    public class MCertificate extends Certificate {
494        private final byte[] encoding;
495
496        private final String type;
497
498        public MCertificate(String type, byte[] encoding) {
499            super(type);
500            this.encoding = encoding;
501            this.type = type;
502        }
503
504        public byte[] getEncoded() throws CertificateEncodingException {
505            return encoding.clone();
506        }
507
508        public void verify(PublicKey key) throws CertificateException,
509                NoSuchAlgorithmException, InvalidKeyException,
510                NoSuchProviderException, SignatureException {
511        }
512
513        public void verify(PublicKey key, String sigProvider)
514                throws CertificateException, NoSuchAlgorithmException,
515                InvalidKeyException, NoSuchProviderException, SignatureException {
516        }
517
518        public String toString() {
519            return "[MCertificate, type: " + getType() + "]";
520        }
521
522        public PublicKey getPublicKey() {
523            return new PublicKey() {
524                public String getAlgorithm() {
525                    return type;
526                }
527
528                public byte[] getEncoded() {
529                    return encoding;
530                }
531
532                public String getFormat() {
533                    return "test";
534                }
535            };
536        }
537    }
538}
539
540/**
541 * Additional class for creating KeyStoreBuilder
542 */
543class myProtectionParameter implements KeyStore.ProtectionParameter {
544    public myProtectionParameter(byte[] param) {
545        if (param == null) {
546            throw new NullPointerException("param is null");
547        }
548    }
549}
550