1 /*
2  * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 import java.io.File;
26 import static java.lang.System.err;
27 import java.security.*;
28 import java.security.cert.Certificate;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.Random;
32 import javax.crypto.spec.PBEParameterSpec;
33 import jdk.test.lib.RandomFactory;
34 import static java.lang.System.out;
35 import java.util.Arrays;
36 
37 /**
38  * @test
39  * @bug 8048830
40  * @summary Test for feature 'support stronger entry protection'. An entry is
41  * stored to keystore with different PasswordProtection objects which are
42  * specified by different PBE algorithms (use -Dseed=X to set PRNG seed)
43  * @library /test/lib ../
44  * @key randomness
45  * @build jdk.test.lib.RandomFactory
46  * @run main EntryProtectionTest
47  */
48 public class EntryProtectionTest {
49     private static final char[] PASSWORD = "passwd".toCharArray();
50     private static final String ALIAS = "testkey";
51     private static final byte[] SALT = new byte[8];
52     private static final int ITERATION_COUNT = 1024;
53     private static final List<KeyStore.PasswordProtection> PASSWORD_PROTECTION
54             = new ArrayList<>();
55     private static final String KEYSTORE_PATH = System.getProperty(
56             "test.classes" + File.separator + "ks.pkcs12",
57             "." + File.separator + "ks.pkcs12");
58 
runTest()59     private void runTest() throws Exception {
60             KeyStore ksIn = Utils.loadKeyStore(KEYSTORE_PATH,
61                     Utils.KeyStoreType.pkcs12, PASSWORD);
62             KeyStore ksTest = KeyStore
63                     .getInstance(Utils.KeyStoreType.pkcs12.name());
64             ksTest.load(null);
65             Certificate cert = ksIn.getCertificate(ALIAS);
66             Key key = ksIn.getKey(ALIAS, PASSWORD);
67             KeyStore.Entry keyStoreEntry = new KeyStore.PrivateKeyEntry(
68                     (PrivateKey) key, new Certificate[]{cert});
69             for (KeyStore.PasswordProtection passwordAlgorithm :
70                     PASSWORD_PROTECTION) {
71                 out.println("Try to use: " +
72                         passwordAlgorithm.getProtectionAlgorithm());
73                 ksTest.setEntry(ALIAS, keyStoreEntry, passwordAlgorithm);
74                 KeyStore.Entry entryRead = ksTest.getEntry(ALIAS,
75                         new KeyStore.PasswordProtection(PASSWORD));
76                 if (!isPrivateKeyEntriesEqual((KeyStore.PrivateKeyEntry)
77                         keyStoreEntry, (KeyStore.PrivateKeyEntry)entryRead)) {
78                     err.println("Original entry in KeyStore: " + keyStoreEntry);
79                     err.println("Enc/Dec entry : " + entryRead);
80                     throw new RuntimeException(
81                             String.format(
82                                     "Decrypted & original enities do "
83                                     + "not match. Algo: %s, Actual: %s, "
84                                     + "Expected: %s",
85                                     passwordAlgorithm.getProtectionAlgorithm(),
86                                     entryRead, keyStoreEntry));
87                 }
88                 ksTest.deleteEntry(ALIAS);
89             }
90             out.println("Test Passed");
91     }
92 
main(String args[])93     public static void main(String args[]) throws Exception {
94         EntryProtectionTest entryProtectionTest = new EntryProtectionTest();
95         entryProtectionTest.setUp();
96         entryProtectionTest.runTest();
97     }
98 
setUp()99     private void setUp() {
100         out.println("Using KEYSTORE_PATH:"+KEYSTORE_PATH);
101         Utils.createKeyStore(Utils.KeyStoreType.pkcs12, KEYSTORE_PATH, ALIAS);
102         Random rand = RandomFactory.getRandom();
103         rand.nextBytes(SALT);
104         out.print("Salt: ");
105         for (byte b : SALT) {
106             out.format("%02X ", b);
107         }
108         out.println("");
109         PASSWORD_PROTECTION
110                 .add(new KeyStore.PasswordProtection(PASSWORD,
111                                 "PBEWithMD5AndDES", new PBEParameterSpec(SALT,
112                                         ITERATION_COUNT)));
113         PASSWORD_PROTECTION.add(new KeyStore.PasswordProtection(PASSWORD,
114                 "PBEWithSHA1AndDESede", null));
115         PASSWORD_PROTECTION.add(new KeyStore.PasswordProtection(PASSWORD,
116                 "PBEWithSHA1AndRC2_40", null));
117         PASSWORD_PROTECTION.add(new KeyStore.PasswordProtection(PASSWORD,
118                 "PBEWithSHA1AndRC2_128", null));
119         PASSWORD_PROTECTION.add(new KeyStore.PasswordProtection(PASSWORD,
120                 "PBEWithSHA1AndRC4_40", null));
121         PASSWORD_PROTECTION.add(new KeyStore.PasswordProtection(PASSWORD,
122                 "PBEWithSHA1AndRC4_128", null));
123     }
124 
125     /**
126      * Checks whether given two KeyStore.PrivateKeyEntry parameters are equal
127      * The KeyStore.PrivateKeyEntry fields like {privateKey, certificateChain[]}
128      * are checked for equality and another field Set<attributes> is not checked
129      * as default implementation adds few PKCS12 attributes during read
130      * operation
131      * @param  first
132      *         parameter is of type KeyStore.PrivateKeyEntry
133      * @param  second
134      *         parameter is of type KeyStore.PrivateKeyEntry
135      * @return boolean
136      *         true when both the KeyStore.PrivateKeyEntry fields are equal
137     */
isPrivateKeyEntriesEqual(KeyStore.PrivateKeyEntry first, KeyStore.PrivateKeyEntry second)138     boolean isPrivateKeyEntriesEqual(KeyStore.PrivateKeyEntry first,
139             KeyStore.PrivateKeyEntry second) {
140         //compare privateKey
141         if (!Arrays.equals(first.getPrivateKey().getEncoded(),
142                 second.getPrivateKey().getEncoded())) {
143             err.println("Mismatch found in privateKey!");
144             return false;
145         }
146         //compare certificateChain[]
147         if (!Arrays.equals(first.getCertificateChain(),
148                 second.getCertificateChain())) {
149             err.println("Mismatch found in certificate chain!");
150             return false;
151         }
152         return true;
153     }
154 }
155