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 // This is an arbitrary X.509 certificate 42 private static final String CERT_FILE = "trusted.pem"; 43 44 public static final void main(String[] args) throws Exception { 45 46 // Testing empty keystores 47 48 init("empty.jks", "JKS"); 49 init("empty.jceks", "JCEKS"); 50 init("empty.p12", "PKCS12"); 51 52 load("empty.jks", "JKS"); 53 load("empty.jceks", "JCEKS"); 54 load("empty.p12", "PKCS12"); 55 load("empty.p12", "JKS"); // test compatibility mode 56 load("empty.jks", "PKCS12", true); // test without compatibility mode 57 load("empty.jks", "JKS", false); // test without compatibility mode 58 load("empty.p12", "JKS", true); // test without compatibility mode 59 load("empty.p12", "PKCS12", false); // test without compatibility mode 60 61 build("empty.jks", "JKS", true); 62 build("empty.jks", "JKS", false); 63 build("empty.jceks", "JCEKS", true); 64 build("empty.jceks", "JCEKS", false); 65 build("empty.p12", "PKCS12", true); 66 build("empty.p12", "PKCS12", false); 67 68 // Testing keystores containing an X.509 certificate 69 70 X509Certificate cert = loadCertificate(CERT_FILE); 71 init("onecert.jks", "JKS", cert); 72 init("onecert.jceks", "JCEKS", cert); 73 init("onecert.p12", "PKCS12", cert); 74 75 load("onecert.jks", "JKS"); 76 load("onecert.jceks", "JCEKS"); 77 load("onecert.p12", "PKCS12"); 78 load("onecert.p12", "JKS"); // test compatibility mode 79 load("onecert.jks", "PKCS12", true); // test without compatibility mode 80 load("onecert.jks", "JKS", false); // test without compatibility mode 81 load("onecert.p12", "JKS", true); // test without compatibility mode 82 load("onecert.p12", "PKCS12", false); // test without compatibility mode 83 84 build("onecert.jks", "JKS", true); 85 build("onecert.jks", "JKS", false); 86 build("onecert.jceks", "JCEKS", true); 87 build("onecert.jceks", "JCEKS", false); 88 build("onecert.p12", "PKCS12", true); 89 build("onecert.p12", "PKCS12", false); 90 91 // Testing keystores containing a secret key 92 93 SecretKey key = generateSecretKey("AES", 128); 94 init("onekey.jceks", "JCEKS", key); 95 init("onekey.p12", "PKCS12", key); 96 97 load("onekey.jceks", "JCEKS"); 98 load("onekey.p12", "PKCS12"); 99 load("onekey.p12", "JKS"); // test compatibility mode 100 load("onekey.p12", "JKS", true); // test without compatibility mode 101 load("onekey.p12", "PKCS12", false); // test without compatibility mode 102 103 build("onekey.jceks", "JCEKS", true); 104 build("onekey.jceks", "JCEKS", false); 105 build("onekey.p12", "PKCS12", true); 106 build("onekey.p12", "PKCS12", false); 107 108 System.out.println("OK."); 109 } 110 111 // Instantiate an empty keystore using the supplied keystore type 112 private static void init(String file, String type) throws Exception { 113 KeyStore ks = KeyStore.getInstance(type); 114 ks.load(null, null); 115 try (OutputStream stream = new FileOutputStream(file)) { 116 ks.store(stream, PASSWORD); 117 } 118 System.out.println("Created a " + type + " keystore named '" + file + "'"); 119 } 120 121 // Instantiate a keystore using the supplied keystore type & create an entry 122 private static void init(String file, String type, X509Certificate cert) 123 throws Exception { 124 KeyStore ks = KeyStore.getInstance(type); 125 ks.load(null, null); 126 ks.setEntry("mycert", new KeyStore.TrustedCertificateEntry(cert), null); 127 try (OutputStream stream = new FileOutputStream(file)) { 128 ks.store(stream, PASSWORD); 129 } 130 System.out.println("Created a " + type + " keystore named '" + file + "'"); 131 } 132 133 // Instantiate a keystore using the supplied keystore type & create an entry 134 private static void init(String file, String type, SecretKey key) 135 throws Exception { 136 KeyStore ks = KeyStore.getInstance(type); 137 ks.load(null, null); 138 ks.setEntry("mykey", new KeyStore.SecretKeyEntry(key), 139 new PasswordProtection(PASSWORD)); 140 try (OutputStream stream = new FileOutputStream(file)) { 141 ks.store(stream, PASSWORD); 142 } 143 System.out.println("Created a " + type + " keystore named '" + file + "'"); 144 } 145 146 // Instantiate a keystore by probing the supplied file for the keystore type 147 private static void build(String file, String type, boolean usePassword) 148 throws Exception { 149 150 Builder builder; 151 if (usePassword) { 152 builder = Builder.newInstance(type, null, new File(file), 153 new PasswordProtection(PASSWORD)); 154 } else { 155 builder = Builder.newInstance(type, null, new File(file), 156 new CallbackHandlerProtection(new DummyHandler())); 157 } 158 KeyStore ks = builder.getKeyStore(); 159 if (!type.equalsIgnoreCase(ks.getType())) { 160 throw new Exception("ERROR: expected a " + type + " keystore, " + 161 "got a " + ks.getType() + " keystore instead"); 162 } else { 163 System.out.println("Built a " + type + " keystore named '" + file + "'"); 164 } 165 } 166 167 // Load the keystore entries 168 private static void load(String file, String type) throws Exception { 169 KeyStore ks = KeyStore.getInstance(type); 170 try (InputStream stream = new FileInputStream(file)) { 171 ks.load(stream, PASSWORD); 172 } 173 if (!type.equalsIgnoreCase(ks.getType())) { 174 throw new Exception("ERROR: expected a " + type + " keystore, " + 175 "got a " + ks.getType() + " keystore instead"); 176 } else { 177 System.out.println("Loaded a " + type + " keystore named '" + file + "'"); 178 } 179 } 180 181 // Load the keystore entries (with compatibility mode disabled) 182 private static void load(String file, String type, boolean expectFailure) 183 throws Exception { 184 Security.setProperty("keystore.type.compat", "false"); 185 try { 186 load(file, type); 187 if (expectFailure) { 188 throw new Exception("ERROR: expected load to fail but it didn't"); 189 } 190 } catch (IOException e) { 191 if (expectFailure) { 192 System.out.println("Failed to load a " + type + " keystore named '" + file + "' (as expected)"); 193 } else { 194 throw e; 195 } 196 } finally { 197 Security.setProperty("keystore.type.compat", "true"); 198 } 199 } 200 201 // Read an X.509 certificate from the supplied file 202 private static X509Certificate loadCertificate(String certFile) 203 throws Exception { 204 X509Certificate cert = null; 205 try (FileInputStream certStream = 206 new FileInputStream(DIR + "/" + certFile)) { 207 CertificateFactory factory = 208 CertificateFactory.getInstance("X.509"); 209 return (X509Certificate) factory.generateCertificate(certStream); 210 } 211 } 212 213 // Generate a secret key using the supplied algorithm name and key size 214 private static SecretKey generateSecretKey(String algorithm, int size) 215 throws NoSuchAlgorithmException { 216 KeyGenerator generator = KeyGenerator.getInstance(algorithm); 217 generator.init(size); 218 return generator.generateKey(); 219 } 220 221 private static class DummyHandler implements CallbackHandler { 222 public void handle(Callback[] callbacks) 223 throws IOException, UnsupportedCallbackException { 224 System.out.println("** Callbackhandler invoked"); 225 for (int i = 0; i < callbacks.length; i++) { 226 Callback cb = callbacks[i]; 227 if (cb instanceof PasswordCallback) { 228 PasswordCallback pcb = (PasswordCallback)cb; 229 pcb.setPassword(PASSWORD); 230 break; 231 } 232 } 233 } 234 } 235 }