1 /* 2 * Copyright (c) 2012, 2017, 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 /lib/testlibrary ../ 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 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 93 public static void main(String args[]) throws Exception { 94 EntryProtectionTest entryProtectionTest = new EntryProtectionTest(); 95 entryProtectionTest.setUp(); 96 entryProtectionTest.runTest(); 97 } 98 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 */ 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 }