1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.security; 19 20 21import java.io.BufferedInputStream; 22import java.io.InputStream; 23import java.util.Enumeration; 24import java.util.HashMap; 25import java.util.HashSet; 26import java.util.Iterator; 27import java.util.List; 28import java.util.Map; 29import java.util.Map.Entry; 30import java.util.Properties; 31import java.util.Set; 32import org.apache.harmony.security.fortress.Engine; 33import org.apache.harmony.security.fortress.SecurityAccess; 34import org.apache.harmony.security.fortress.Services; 35 36/** 37 * {@code Security} is the central class in the Java Security API. It manages 38 * the list of security {@code Provider} that have been installed into this 39 * runtime environment. 40 */ 41public final class Security { 42 43 // Security properties 44 private static final Properties secprops = new Properties(); 45 46 // static initialization 47 // - load security properties files 48 // - load statically registered providers 49 // - if no provider description file found then load default providers 50 static { 51 boolean loaded = false; 52 try { 53 InputStream configStream = Security.class.getResourceAsStream("security.properties"); 54 InputStream input = new BufferedInputStream(configStream); 55 secprops.load(input); 56 loaded = true; 57 configStream.close(); 58 } catch (Exception ex) { 59 System.logE("Could not load 'security.properties'", ex); 60 } 61 if (!loaded) { 62 registerDefaultProviders(); 63 } 64 Engine.door = new SecurityDoor(); 65 } 66 67 /** 68 * This class can't be instantiated. 69 */ 70 private Security() { 71 } 72 73 // Register default providers 74 private static void registerDefaultProviders() { 75 secprops.put("security.provider.1", "org.apache.harmony.xnet.provider.jsse.OpenSSLProvider"); 76 secprops.put("security.provider.2", "org.apache.harmony.security.provider.cert.DRLCertFactory"); 77 secprops.put("security.provider.3", "org.bouncycastle.jce.provider.BouncyCastleProvider"); 78 secprops.put("security.provider.4", "org.apache.harmony.security.provider.crypto.CryptoProvider"); 79 secprops.put("security.provider.5", "org.apache.harmony.xnet.provider.jsse.JSSEProvider"); 80 } 81 82 /** 83 * Returns value for the specified algorithm with the specified name. 84 * 85 * @param algName 86 * the name of the algorithm. 87 * @param propName 88 * the name of the property. 89 * @return value of the property. 90 * @deprecated Use {@link AlgorithmParameters} and {@link KeyFactory} 91 * instead. 92 */ 93 @Deprecated 94 public static String getAlgorithmProperty(String algName, String propName) { 95 if (algName == null || propName == null) { 96 return null; 97 } 98 String prop = "Alg." + propName + "." + algName; 99 Provider[] providers = getProviders(); 100 for (Provider provider : providers) { 101 for (Enumeration e = provider.propertyNames(); e.hasMoreElements(); ) { 102 String propertyName = (String) e.nextElement(); 103 if (propertyName.equalsIgnoreCase(prop)) { 104 return provider.getProperty(propertyName); 105 } 106 } 107 } 108 return null; 109 } 110 111 /** 112 * Insert the given {@code Provider} at the specified {@code position}. The 113 * positions define the preference order in which providers are searched for 114 * requested algorithms. 115 * 116 * @param provider 117 * the provider to insert. 118 * @param position 119 * the position (starting from 1). 120 * @return the actual position or {@code -1} if the given {@code provider} 121 * was already in the list. The actual position may be different 122 * from the desired position. 123 */ 124 public static synchronized int insertProviderAt(Provider provider, int position) { 125 // check that provider is not already 126 // installed, else return -1; if (position <1) or (position > max 127 // position) position = max position + 1; insert provider, shift up 128 // one position for next providers; Note: The position is 1-based 129 if (getProvider(provider.getName()) != null) { 130 return -1; 131 } 132 int result = Services.insertProviderAt(provider, position); 133 renumProviders(); 134 return result; 135 } 136 137 /** 138 * Adds the given {@code provider} to the collection of providers at the 139 * next available position. 140 * 141 * @param provider 142 * the provider to be added. 143 * @return the actual position or {@code -1} if the given {@code provider} 144 * was already in the list. 145 */ 146 public static int addProvider(Provider provider) { 147 return insertProviderAt(provider, 0); 148 } 149 150 /** 151 * Removes the {@code Provider} with the specified name form the collection 152 * of providers. If the the {@code Provider} with the specified name is 153 * removed, all provider at a greater position are shifted down one 154 * position. 155 * 156 * <p>Returns silently if {@code name} is {@code null} or no provider with the 157 * specified name is installed. 158 * 159 * @param name 160 * the name of the provider to remove. 161 */ 162 public static synchronized void removeProvider(String name) { 163 // It is not clear from spec.: 164 // 1. if name is null, should we checkSecurityAccess or not? 165 // throw SecurityException or not? 166 // 2. as 1 but provider is not installed 167 // 3. behavior if name is empty string? 168 169 Provider p; 170 if ((name == null) || (name.length() == 0)) { 171 return; 172 } 173 p = getProvider(name); 174 if (p == null) { 175 return; 176 } 177 Services.removeProvider(p.getProviderNumber()); 178 renumProviders(); 179 p.setProviderNumber(-1); 180 } 181 182 /** 183 * Returns an array containing all installed providers. The providers are 184 * ordered according their preference order. 185 * 186 * @return an array containing all installed providers. 187 */ 188 public static synchronized Provider[] getProviders() { 189 return Services.getProviders(); 190 } 191 192 /** 193 * Returns the {@code Provider} with the specified name. Returns {@code 194 * null} if name is {@code null} or no provider with the specified name is 195 * installed. 196 * 197 * @param name 198 * the name of the requested provider. 199 * @return the provider with the specified name, maybe {@code null}. 200 */ 201 public static synchronized Provider getProvider(String name) { 202 return Services.getProvider(name); 203 } 204 205 /** 206 * Returns the array of providers which meet the user supplied string 207 * filter. The specified filter must be supplied in one of two formats: 208 * <nl> 209 * <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE 210 * <p> 211 * (for example: "MessageDigest.SHA") 212 * <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE 213 * ATTR_NAME:ATTR_VALUE 214 * <p> 215 * (for example: "Signature.MD2withRSA KeySize:512") 216 * </nl> 217 * 218 * @param filter 219 * case-insensitive filter. 220 * @return the providers which meet the user supplied string filter {@code 221 * filter}. A {@code null} value signifies that none of the 222 * installed providers meets the filter specification. 223 * @throws InvalidParameterException 224 * if an unusable filter is supplied. 225 * @throws NullPointerException 226 * if {@code filter} is {@code null}. 227 */ 228 public static Provider[] getProviders(String filter) { 229 if (filter == null) { 230 throw new NullPointerException(); 231 } 232 if (filter.length() == 0) { 233 throw new InvalidParameterException(); 234 } 235 HashMap<String, String> hm = new HashMap<String, String>(); 236 int i = filter.indexOf(':'); 237 if ((i == filter.length() - 1) || (i == 0)) { 238 throw new InvalidParameterException(); 239 } 240 if (i < 1) { 241 hm.put(filter, ""); 242 } else { 243 hm.put(filter.substring(0, i), filter.substring(i + 1)); 244 } 245 return getProviders(hm); 246 } 247 248 /** 249 * Returns the array of providers which meet the user supplied set of 250 * filters. The filter must be supplied in one of two formats: 251 * <nl> 252 * <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE 253 * <p> 254 * for example: "MessageDigest.SHA" The value associated with the key must 255 * be an empty string. <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE 256 * ATTR_NAME:ATTR_VALUE 257 * <p> 258 * for example: "Signature.MD2withRSA KeySize:512" where "KeySize:512" is 259 * the value of the filter map entry. 260 * </nl> 261 * 262 * @param filter 263 * case-insensitive filter. 264 * @return the providers which meet the user supplied string filter {@code 265 * filter}. A {@code null} value signifies that none of the 266 * installed providers meets the filter specification. 267 * @throws InvalidParameterException 268 * if an unusable filter is supplied. 269 * @throws NullPointerException 270 * if {@code filter} is {@code null}. 271 */ 272 public static synchronized Provider[] getProviders(Map<String,String> filter) { 273 if (filter == null) { 274 throw new NullPointerException(); 275 } 276 if (filter.isEmpty()) { 277 return null; 278 } 279 java.util.List<Provider> result = Services.getProvidersList(); 280 Set<Entry<String, String>> keys = filter.entrySet(); 281 Map.Entry<String, String> entry; 282 for (Iterator<Entry<String, String>> it = keys.iterator(); it.hasNext();) { 283 entry = it.next(); 284 String key = entry.getKey(); 285 String val = entry.getValue(); 286 String attribute = null; 287 int i = key.indexOf(' '); 288 int j = key.indexOf('.'); 289 if (j == -1) { 290 throw new InvalidParameterException(); 291 } 292 if (i == -1) { // <crypto_service>.<algorithm_or_type> 293 if (val.length() != 0) { 294 throw new InvalidParameterException(); 295 } 296 } else { // <crypto_service>.<algorithm_or_type> <attribute_name> 297 if (val.length() == 0) { 298 throw new InvalidParameterException(); 299 } 300 attribute = key.substring(i + 1); 301 if (attribute.trim().length() == 0) { 302 throw new InvalidParameterException(); 303 } 304 key = key.substring(0, i); 305 } 306 String serv = key.substring(0, j); 307 String alg = key.substring(j + 1); 308 if (serv.length() == 0 || alg.length() == 0) { 309 throw new InvalidParameterException(); 310 } 311 Provider p; 312 for (int k = 0; k < result.size(); k++) { 313 try { 314 p = result.get(k); 315 } catch (IndexOutOfBoundsException e) { 316 break; 317 } 318 if (!p.implementsAlg(serv, alg, attribute, val)) { 319 result.remove(p); 320 k--; 321 } 322 } 323 } 324 if (result.size() > 0) { 325 return result.toArray(new Provider[result.size()]); 326 } 327 return null; 328 } 329 330 /** 331 * Returns the value of the security property named by the argument. 332 * 333 * @param key 334 * the name of the requested security property. 335 * @return the value of the security property. 336 */ 337 public static String getProperty(String key) { 338 if (key == null) { 339 throw new NullPointerException("key == null"); 340 } 341 String property = secprops.getProperty(key); 342 if (property != null) { 343 property = property.trim(); 344 } 345 return property; 346 } 347 348 /** 349 * Sets the value of the specified security property. 350 */ 351 public static void setProperty(String key, String value) { 352 secprops.put(key, value); 353 } 354 355 /** 356 * Returns a {@code Set} of all registered algorithms for the specified 357 * cryptographic service. {@code "Signature"}, {@code "Cipher"} and {@code 358 * "KeyStore"} are examples for such kind of services. 359 * 360 * @param serviceName 361 * the case-insensitive name of the service. 362 * @return a {@code Set} of all registered algorithms for the specified 363 * cryptographic service, or an empty {@code Set} if {@code 364 * serviceName} is {@code null} or if no registered provider 365 * provides the requested service. 366 */ 367 public static Set<String> getAlgorithms(String serviceName) { 368 Set<String> result = new HashSet<String>(); 369 // compatibility with RI 370 if (serviceName == null) { 371 return result; 372 } 373 for (Provider provider : getProviders()) { 374 for (Provider.Service service: provider.getServices()) { 375 if (service.getType().equalsIgnoreCase(serviceName)) { 376 result.add(service.getAlgorithm()); 377 } 378 } 379 } 380 return result; 381 } 382 383 /** 384 * 385 * Update sequence numbers of all providers. 386 * 387 */ 388 private static void renumProviders() { 389 Provider[] p = Services.getProviders(); 390 for (int i = 0; i < p.length; i++) { 391 p[i].setProviderNumber(i + 1); 392 } 393 } 394 395 private static class SecurityDoor implements SecurityAccess { 396 // Access to Security.renumProviders() 397 public void renumProviders() { 398 Security.renumProviders(); 399 } 400 401 // Access to Security.getAliases() 402 public List<String> getAliases(Provider.Service s) { 403 return s.getAliases(); 404 } 405 406 // Access to Provider.getService() 407 public Provider.Service getService(Provider p, String type) { 408 return p.getService(type); 409 } 410 } 411} 412