1 /* 2 * Copyright (c) 2005, 2012, 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 26 package sun.security.tools; 27 28 29 import java.io.BufferedReader; 30 import java.io.File; 31 import java.io.FileInputStream; 32 import java.io.IOException; 33 import java.io.InputStreamReader; 34 35 import java.io.StreamTokenizer; 36 import java.io.StringReader; 37 import java.net.URL; 38 39 import java.security.KeyStore; 40 41 import java.text.Collator; 42 43 import java.util.ArrayList; 44 import java.util.Arrays; 45 import java.util.List; 46 import java.util.Locale; 47 import java.util.Properties; 48 49 import sun.security.util.PropertyExpander; 50 51 /** 52 * <p> This class provides several utilities to <code>KeyStore</code>. 53 * 54 * @since 1.6.0 55 */ 56 public class KeyStoreUtil { 57 58 private KeyStoreUtil() { 59 // this class is not meant to be instantiated 60 } 61 62 private static final String JKS = "jks"; 63 64 private static final Collator collator = Collator.getInstance(); 65 static { 66 // this is for case insensitive string comparisons 67 collator.setStrength(Collator.PRIMARY); 68 }; 69 70 /** 71 * Returns true if KeyStore has a password. This is true except for 72 * MSCAPI KeyStores 73 */ 74 public static boolean isWindowsKeyStore(String storetype) { 75 return storetype.equalsIgnoreCase("Windows-MY") 76 || storetype.equalsIgnoreCase("Windows-ROOT"); 77 } 78 79 /** 80 * Returns standard-looking names for storetype 81 */ 82 public static String niceStoreTypeName(String storetype) { 83 if (storetype.equalsIgnoreCase("Windows-MY")) { 84 return "Windows-MY"; 85 } else if(storetype.equalsIgnoreCase("Windows-ROOT")) { 86 return "Windows-ROOT"; 87 } else { 88 return storetype.toUpperCase(Locale.ENGLISH); 89 } 90 } 91 92 /** 93 * Returns the keystore with the configured CA certificates. 94 */ 95 public static KeyStore getCacertsKeyStore() 96 throws Exception 97 { 98 String sep = File.separator; 99 File file = new File(System.getProperty("java.home") + sep 100 + "lib" + sep + "security" + sep 101 + "cacerts"); 102 if (!file.exists()) { 103 return null; 104 } 105 KeyStore caks = null; 106 try (FileInputStream fis = new FileInputStream(file)) { 107 caks = KeyStore.getInstance(JKS); 108 caks.load(fis, null); 109 } 110 return caks; 111 } 112 113 public static char[] getPassWithModifier(String modifier, String arg, 114 java.util.ResourceBundle rb) { 115 if (modifier == null) { 116 return arg.toCharArray(); 117 } else if (collator.compare(modifier, "env") == 0) { 118 String value = System.getenv(arg); 119 if (value == null) { 120 System.err.println(rb.getString( 121 "Cannot.find.environment.variable.") + arg); 122 return null; 123 } else { 124 return value.toCharArray(); 125 } 126 } else if (collator.compare(modifier, "file") == 0) { 127 try { 128 URL url = null; 129 try { 130 url = new URL(arg); 131 } catch (java.net.MalformedURLException mue) { 132 File f = new File(arg); 133 if (f.exists()) { 134 url = f.toURI().toURL(); 135 } else { 136 System.err.println(rb.getString( 137 "Cannot.find.file.") + arg); 138 return null; 139 } 140 } 141 142 try (BufferedReader br = 143 new BufferedReader(new InputStreamReader( 144 url.openStream()))) { 145 String value = br.readLine(); 146 147 if (value == null) { 148 return new char[0]; 149 } 150 151 return value.toCharArray(); 152 } 153 } catch (IOException ioe) { 154 System.err.println(ioe); 155 return null; 156 } 157 } else { 158 System.err.println(rb.getString("Unknown.password.type.") + 159 modifier); 160 return null; 161 } 162 } 163 164 /** 165 * Parses a option line likes 166 * -genkaypair -dname "CN=Me" 167 * and add the results into a list 168 * @param list the list to fill into 169 * @param s the line 170 */ 171 private static void parseArgsLine(List<String> list, String s) 172 throws IOException, PropertyExpander.ExpandException { 173 StreamTokenizer st = new StreamTokenizer(new StringReader(s)); 174 175 st.resetSyntax(); 176 st.whitespaceChars(0x00, 0x20); 177 st.wordChars(0x21, 0xFF); 178 // Everything is a word char except for quotation and apostrophe 179 st.quoteChar('"'); 180 st.quoteChar('\''); 181 182 while (true) { 183 if (st.nextToken() == StreamTokenizer.TT_EOF) { 184 break; 185 } 186 list.add(PropertyExpander.expand(st.sval)); 187 } 188 } 189 190 /** 191 * Prepends matched options from a pre-configured options file. 192 * @param tool the name of the tool, can be "keytool" or "jarsigner" 193 * @param file the pre-configured options file 194 * @param c1 the name of the command, must not be null 195 * @param c2 the alternative command name, null if none. For example, 196 * "genkey" is alt name for "genkeypair". A command can only 197 * have one alt name now. 198 * @param args existing arguments 199 * @return arguments combined 200 * @throws IOException if there is a file I/O or format error 201 * @throws PropertyExpander.ExpandException 202 * if there is a property expansion error 203 */ 204 public static String[] expandArgs(String tool, String file, 205 String c1, String c2, String[] args) 206 throws IOException, PropertyExpander.ExpandException { 207 208 List<String> result = new ArrayList<>(); 209 Properties p = new Properties(); 210 p.load(new FileInputStream(file)); 211 212 String s = p.getProperty(tool + ".all"); 213 if (s != null) { 214 parseArgsLine(result, s); 215 } 216 217 // Cannot provide both -genkey and -genkeypair 218 String s1 = p.getProperty(tool + "." + c1.substring(1)); 219 String s2 = null; 220 if (c2 != null) { 221 s2 = p.getProperty(tool + "." + c2.substring(1)); 222 } 223 if (s1 != null && s2 != null) { 224 throw new IOException("Cannot have both " + c1 + " and " + c2); 225 } 226 if (s1 == null) { 227 s1 = s2; 228 } 229 if (s1 != null) { 230 parseArgsLine(result, s1); 231 } 232 233 if (result.isEmpty()) { 234 return args; 235 } else { 236 result.addAll(Arrays.asList(args)); 237 return result.toArray(new String[result.size()]); 238 } 239 } 240 }