1 /* 2 * Copyright (c) 2014, 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 com.oracle.security.ucrypto; 27 28 import java.io.*; 29 import static java.io.StreamTokenizer.*; 30 import java.math.BigInteger; 31 import java.util.*; 32 33 import java.security.*; 34 35 import sun.security.action.GetPropertyAction; 36 import sun.security.util.PropertyExpander; 37 38 /** 39 * Configuration container and file parsing. 40 * 41 * Currently, there is only one supported entry "disabledServices" 42 * for disabling crypto services. Its syntax is as follows: 43 * 44 * disabledServices = { 45 * <ServiceType>.<Algorithm> 46 * ... 47 * } 48 * 49 * where <Service> can be "MessageDigest", "Cipher", etc. and <Algorithm> 50 * reprepresents the value that's passed into the various getInstance() calls. 51 * 52 * @since 9 53 */ 54 final class Config { 55 56 // Reader and StringTokenizer used during parsing 57 private Reader reader; 58 59 private StreamTokenizer st; 60 61 private Set<String> parsedKeywords; 62 63 // set of disabled crypto services, e.g. MessageDigest.SHA1, or 64 // Cipher.AES/ECB/PKCS5Padding 65 private Set<String> disabledServices; 66 Config(String filename)67 Config(String filename) throws IOException { 68 FileInputStream in = new FileInputStream(expand(filename)); 69 reader = new BufferedReader(new InputStreamReader(in, "ISO-8859-1")); 70 parsedKeywords = new HashSet<String>(); 71 st = new StreamTokenizer(reader); 72 setupTokenizer(); 73 parse(); 74 } 75 getDisabledServices()76 String[] getDisabledServices() { 77 if (disabledServices != null) { 78 return disabledServices.toArray(new String[disabledServices.size()]); 79 } else { 80 return new String[0]; 81 } 82 } 83 expand(final String s)84 private static String expand(final String s) throws IOException { 85 try { 86 return PropertyExpander.expand(s); 87 } catch (Exception e) { 88 throw new RuntimeException(e.getMessage()); 89 } 90 } 91 setupTokenizer()92 private void setupTokenizer() { 93 st.resetSyntax(); 94 st.wordChars('a', 'z'); 95 st.wordChars('A', 'Z'); 96 st.wordChars('0', '9'); 97 st.wordChars(':', ':'); 98 st.wordChars('.', '.'); 99 st.wordChars('_', '_'); 100 st.wordChars('-', '-'); 101 st.wordChars('/', '/'); 102 st.wordChars('\\', '\\'); 103 st.wordChars('$', '$'); 104 st.wordChars('{', '{'); // need {} for property subst 105 st.wordChars('}', '}'); 106 st.wordChars('*', '*'); 107 st.wordChars('+', '+'); 108 st.wordChars('~', '~'); 109 // XXX check ASCII table and add all other characters except special 110 111 // special: #="(), 112 st.whitespaceChars(0, ' '); 113 st.commentChar('#'); 114 st.eolIsSignificant(true); 115 st.quoteChar('\"'); 116 } 117 excToken(String msg)118 private ConfigException excToken(String msg) { 119 return new ConfigException(msg + " " + st); 120 } 121 excLine(String msg)122 private ConfigException excLine(String msg) { 123 return new ConfigException(msg + ", line " + st.lineno()); 124 } 125 parse()126 private void parse() throws IOException { 127 while (true) { 128 int token = nextToken(); 129 if (token == TT_EOF) { 130 break; 131 } 132 if (token == TT_EOL) { 133 continue; 134 } 135 if (token != TT_WORD) { 136 throw excToken("Unexpected token:"); 137 } 138 String word = st.sval; 139 if (word.equals("disabledServices")) { 140 parseDisabledServices(word); 141 } else { 142 throw new ConfigException 143 ("Unknown keyword '" + word + "', line " + st.lineno()); 144 } 145 parsedKeywords.add(word); 146 } 147 reader.close(); 148 reader = null; 149 st = null; 150 parsedKeywords = null; 151 } 152 153 // 154 // Parsing helper methods 155 // nextToken()156 private int nextToken() throws IOException { 157 int token = st.nextToken(); 158 return token; 159 } 160 parseEquals()161 private void parseEquals() throws IOException { 162 int token = nextToken(); 163 if (token != '=') { 164 throw excToken("Expected '=', read"); 165 } 166 } 167 parseOpenBraces()168 private void parseOpenBraces() throws IOException { 169 while (true) { 170 int token = nextToken(); 171 if (token == TT_EOL) { 172 continue; 173 } 174 if ((token == TT_WORD) && st.sval.equals("{")) { 175 return; 176 } 177 throw excToken("Expected '{', read"); 178 } 179 } 180 isCloseBraces(int token)181 private boolean isCloseBraces(int token) { 182 return (token == TT_WORD) && st.sval.equals("}"); 183 } 184 checkDup(String keyword)185 private void checkDup(String keyword) throws IOException { 186 if (parsedKeywords.contains(keyword)) { 187 throw excLine(keyword + " must only be specified once"); 188 } 189 } 190 parseDisabledServices(String keyword)191 private void parseDisabledServices(String keyword) throws IOException { 192 checkDup(keyword); 193 disabledServices = new HashSet<String>(); 194 parseEquals(); 195 parseOpenBraces(); 196 while (true) { 197 int token = nextToken(); 198 if (isCloseBraces(token)) { 199 break; 200 } 201 if (token == TT_EOL) { 202 continue; 203 } 204 if (token != TT_WORD) { 205 throw excToken("Expected mechanism, read"); 206 } 207 disabledServices.add(st.sval); 208 } 209 } 210 } 211 212 class ConfigException extends IOException { 213 private static final long serialVersionUID = 254492758127673194L; ConfigException(String msg)214 ConfigException(String msg) { 215 super(msg); 216 } 217 } 218