1 /* 2 * Copyright (c) 2015, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8062552 27 * @run main/othervm TestKeystoreCompat 28 * @summary test compatibility mode for JKS and PKCS12 keystores 29 */ 30 31 import java.io.*; 32 import java.security.*; 33 import java.security.KeyStore.*; 34 import java.security.cert.*; 35 import javax.crypto.*; 36 import javax.security.auth.callback.*; 37 38 public class TestKeystoreCompat { 39 private static final char[] PASSWORD = "changeit".toCharArray(); 40 private static final String DIR = System.getProperty("test.src", "."); 41 private static final String CERT_FILE = "trusted.pem"; 42 43 public static final void main(String[] args) throws Exception { 44 45 // Testing empty keystores 46 47 init("empty.jks", "JKS"); 48 init("empty.jceks", "JCEKS"); 49 init("empty.p12", "PKCS12"); 50 51 load("empty.jks", "JKS"); 52 load("empty.jceks", "JCEKS"); 53 load("empty.p12", "PKCS12"); 54 load("empty.p12", "JKS"); // test compatibility mode 55 load("empty.jks", "PKCS12", true); // test without compatibility mode 56 load("empty.jks", "JKS", false); // test without compatibility mode 57 load("empty.p12", "JKS", true); // test without compatibility mode 58 load("empty.p12", "PKCS12", false); // test without compatibility mode 59 60 build("empty.jks", "JKS", true); 61 build("empty.jks", "JKS", false); 62 build("empty.jceks", "JCEKS", true); 63 build("empty.jceks", "JCEKS", false); 64 build("empty.p12", "PKCS12", true); 65 build("empty.p12", "PKCS12", false); 66 67 // Testing keystores containing an X.509 certificate 68 69 X509Certificate cert = loadCertificate(CERT_FILE); 70 init("onecert.jks", "JKS", cert); 71 init("onecert.jceks", "JCEKS", cert); 72 init("onecert.p12", "PKCS12", cert); 73 74 load("onecert.jks", "JKS"); 75 load("onecert.jceks", "JCEKS"); 76 load("onecert.p12", "PKCS12"); 77 load("onecert.p12", "JKS"); // test compatibility mode 78 load("onecert.jks", "PKCS12", true); // test without compatibility mode 79 load("onecert.jks", "JKS", false); // test without compatibility mode 80 load("onecert.p12", "JKS", true); // test without compatibility mode 81 load("onecert.p12", "PKCS12", false); // test without compatibility mode 82 83 build("onecert.jks", "JKS", true); 84 build("onecert.jks", "JKS", false); 85 build("onecert.jceks", "JCEKS", true); 86 build("onecert.jceks", "JCEKS", false); 87 build("onecert.p12", "PKCS12", true); 88 build("onecert.p12", "PKCS12", false); 89 90 // Testing keystores containing a secret key 91 92 SecretKey key = generateSecretKey("AES", 128); 93 init("onekey.jceks", "JCEKS", key); 94 init("onekey.p12", "PKCS12", key); 95 96 load("onekey.jceks", "JCEKS"); 97 load("onekey.p12", "PKCS12"); 98 load("onekey.p12", "JKS"); // test compatibility mode 99 load("onekey.p12", "JKS", true); // test without compatibility mode 100 load("onekey.p12", "PKCS12", false); // test without compatibility mode 101 102 build("onekey.jceks", "JCEKS", true); 103 build("onekey.jceks", "JCEKS", false); 104 build("onekey.p12", "PKCS12", true); 105 build("onekey.p12", "PKCS12", false); 106 107 System.out.println("OK."); 108 } 109 110 // Instantiate an empty keystore using the supplied keystore type 111 private static void init(String file, String type) throws Exception { 112 KeyStore ks = KeyStore.getInstance(type); 113 ks.load(null, null); 114 try (OutputStream stream = new FileOutputStream(file)) { 115 ks.store(stream, PASSWORD); 116 } 117 System.out.println("Created a " + type + " keystore named '" + file + "'"); 118 } 119 120 // Instantiate a keystore using the supplied keystore type & create an entry 121 private static void init(String file, String type, X509Certificate cert) 122 throws Exception { 123 KeyStore ks = KeyStore.getInstance(type); 124 ks.load(null, null); 125 ks.setEntry("mycert", new KeyStore.TrustedCertificateEntry(cert), null); 126 try (OutputStream stream = new FileOutputStream(file)) { 127 ks.store(stream, PASSWORD); 128 } 129 System.out.println("Created a " + type + " keystore named '" + file + "'"); 130 } 131 132 // Instantiate a keystore using the supplied keystore type & create an entry 133 private static void init(String file, String type, SecretKey key) 134 throws Exception { 135 KeyStore ks = KeyStore.getInstance(type); 136 ks.load(null, null); 137 ks.setEntry("mykey", new KeyStore.SecretKeyEntry(key), 138 new PasswordProtection(PASSWORD)); 139 try (OutputStream stream = new FileOutputStream(file)) { 140 ks.store(stream, PASSWORD); 141 } 142 System.out.println("Created a " + type + " keystore named '" + file + "'"); 143 } 144 145 // Instantiate a keystore by probing the supplied file for the keystore type 146 private static void build(String file, String type, boolean usePassword) 147 throws Exception { 148 149 Builder builder; 150 if (usePassword) { 151 builder = Builder.newInstance(type, null, new File(file), 152 new PasswordProtection(PASSWORD)); 153 } else { 154 builder = Builder.newInstance(type, null, new File(file), 155 new CallbackHandlerProtection(new DummyHandler())); 156 } 157 KeyStore ks = builder.getKeyStore(); 158 if (!type.equalsIgnoreCase(ks.getType())) { 159 throw new Exception("ERROR: expected a " + type + " keystore, " + 160 "got a " + ks.getType() + " keystore instead"); 161 } else { 162 System.out.println("Built a " + type + " keystore named '" + file + "'"); 163 } 164 } 165 166 // Load the keystore entries 167 private static void load(String file, String type) throws Exception { 168 KeyStore ks = KeyStore.getInstance(type); 169 try (InputStream stream = new FileInputStream(file)) { 170 ks.load(stream, PASSWORD); 171 } 172 if (!type.equalsIgnoreCase(ks.getType())) { 173 throw new Exception("ERROR: expected a " + type + " keystore, " + 174 "got a " + ks.getType() + " keystore instead"); 175 } else { 176 System.out.println("Loaded a " + type + " keystore named '" + file + "'"); 177 } 178 } 179 180 // Load the keystore entries (with compatibility mode disabled) 181 private static void load(String file, String type, boolean expectFailure) 182 throws Exception { 183 Security.setProperty("keystore.type.compat", "false"); 184 try { 185 load(file, type); 186 if (expectFailure) { 187 throw new Exception("ERROR: expected load to fail but it didn't"); 188 } 189 } catch (IOException e) { 190 if (expectFailure) { 191 System.out.println("Failed to load a " + type + " keystore named '" + file + "' (as expected)"); 192 } else { 193 throw e; 194 } 195 } finally { 196 Security.setProperty("keystore.type.compat", "true"); 197 } 198 } 199 200 // Read an X.509 certificate from the supplied file 201 private static X509Certificate loadCertificate(String certFile) 202 throws Exception { 203 X509Certificate cert = null; 204 try (FileInputStream certStream = 205 new FileInputStream(DIR + "/" + certFile)) { 206 CertificateFactory factory = 207 CertificateFactory.getInstance("X.509"); 208 return (X509Certificate) factory.generateCertificate(certStream); 209 } 210 } 211 212 // Generate a secret key using the supplied algorithm name and key size 213 private static SecretKey generateSecretKey(String algorithm, int size) 214 throws NoSuchAlgorithmException { 215 KeyGenerator generator = KeyGenerator.getInstance(algorithm); 216 generator.init(size); 217 return generator.generateKey(); 218 } 219 220 private static class DummyHandler implements CallbackHandler { 221 public void handle(Callback[] callbacks) 222 throws IOException, UnsupportedCallbackException { 223 System.out.println("** Callbackhandler invoked"); 224 for (int i = 0; i < callbacks.length; i++) { 225 Callback cb = callbacks[i]; 226 if (cb instanceof PasswordCallback) { 227 PasswordCallback pcb = (PasswordCallback)cb; 228 pcb.setPassword(PASSWORD); 229 break; 230 } 231 } 232 } 233 } 234 }