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 18 package java.security; 19 20 import java.io.BufferedInputStream; 21 import java.io.InputStream; 22 import java.util.ArrayList; 23 import java.util.Enumeration; 24 import java.util.HashMap; 25 import java.util.HashSet; 26 import java.util.Iterator; 27 import java.util.List; 28 import java.util.Map; 29 import java.util.Map.Entry; 30 import java.util.Properties; 31 import java.util.Set; 32 import org.apache.harmony.security.fortress.Engine; 33 import org.apache.harmony.security.fortress.SecurityAccess; 34 import 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 */ 41 public 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; configStream.close()57 configStream.close(); 58 } catch (Exception ex) { 59 System.logE("Could not load 'security.properties'", ex); 60 } 61 if (!loaded) { registerDefaultProviders()62 registerDefaultProviders(); 63 } 64 Engine.door = new SecurityDoor(); 65 } 66 67 /** 68 * This class can't be instantiated. 69 */ Security()70 private Security() { 71 } 72 73 // Register default providers registerDefaultProviders()74 private static void registerDefaultProviders() { 75 secprops.put("security.provider.1", "com.android.org.conscrypt.OpenSSLProvider"); 76 secprops.put("security.provider.2", "com.android.org.bouncycastle.jce.provider.BouncyCastleProvider"); 77 secprops.put("security.provider.3", "org.apache.harmony.security.provider.crypto.CryptoProvider"); 78 secprops.put("security.provider.4", "com.android.org.conscrypt.JSSEProvider"); 79 } 80 81 /** 82 * Returns value for the specified algorithm with the specified name. 83 * 84 * @param algName 85 * the name of the algorithm. 86 * @param propName 87 * the name of the property. 88 * @return value of the property. 89 * @deprecated Use {@link AlgorithmParameters} and {@link KeyFactory} instead. 90 */ 91 @Deprecated getAlgorithmProperty(String algName, String propName)92 public static String getAlgorithmProperty(String algName, String propName) { 93 if (algName == null || propName == null) { 94 return null; 95 } 96 String prop = "Alg." + propName + "." + algName; 97 Provider[] providers = getProviders(); 98 for (Provider provider : providers) { 99 for (Enumeration<?> e = provider.propertyNames(); e.hasMoreElements();) { 100 String propertyName = (String) e.nextElement(); 101 if (propertyName.equalsIgnoreCase(prop)) { 102 return provider.getProperty(propertyName); 103 } 104 } 105 } 106 return null; 107 } 108 109 /** 110 * Insert the given {@code Provider} at the specified {@code position}. The 111 * positions define the preference order in which providers are searched for 112 * requested algorithms. 113 * 114 * @param provider 115 * the provider to insert. 116 * @param position 117 * the position (starting from 1). 118 * @return the actual position or {@code -1} if the given {@code provider} 119 * was already in the list. The actual position may be different 120 * from the desired position. 121 */ insertProviderAt(Provider provider, int position)122 public static synchronized int insertProviderAt(Provider provider, int position) { 123 // check that provider is not already 124 // installed, else return -1; if (position <1) or (position > max 125 // position) position = max position + 1; insert provider, shift up 126 // one position for next providers; Note: The position is 1-based 127 if (getProvider(provider.getName()) != null) { 128 return -1; 129 } 130 int result = Services.insertProviderAt(provider, position); 131 renumProviders(); 132 return result; 133 } 134 135 /** 136 * Adds the given {@code provider} to the collection of providers at the 137 * next available position. 138 * 139 * @param provider 140 * the provider to be added. 141 * @return the actual position or {@code -1} if the given {@code provider} 142 * was already in the list. 143 */ addProvider(Provider provider)144 public static int addProvider(Provider provider) { 145 return insertProviderAt(provider, 0); 146 } 147 148 /** 149 * Removes the {@code Provider} with the specified name form the collection 150 * of providers. If the the {@code Provider} with the specified name is 151 * removed, all provider at a greater position are shifted down one 152 * position. 153 * 154 * <p>Returns silently if {@code name} is {@code null} or no provider with the 155 * specified name is installed. 156 * 157 * @param name 158 * the name of the provider to remove. 159 */ removeProvider(String name)160 public static synchronized void removeProvider(String name) { 161 // It is not clear from spec.: 162 // 1. if name is null, should we checkSecurityAccess or not? 163 // throw SecurityException or not? 164 // 2. as 1 but provider is not installed 165 // 3. behavior if name is empty string? 166 167 Provider p; 168 if ((name == null) || (name.length() == 0)) { 169 return; 170 } 171 p = getProvider(name); 172 if (p == null) { 173 return; 174 } 175 Services.removeProvider(p.getProviderNumber()); 176 renumProviders(); 177 p.setProviderNumber(-1); 178 } 179 180 /** 181 * Returns an array containing all installed providers. The providers are 182 * ordered according their preference order. 183 * 184 * @return an array containing all installed providers. 185 */ getProviders()186 public static synchronized Provider[] getProviders() { 187 ArrayList<Provider> providers = Services.getProviders(); 188 return providers.toArray(new Provider[providers.size()]); 189 } 190 191 /** 192 * Returns the {@code Provider} with the specified name. Returns {@code 193 * null} if name is {@code null} or no provider with the specified name is 194 * installed. 195 * 196 * @param name 197 * the name of the requested provider. 198 * @return the provider with the specified name, maybe {@code null}. 199 */ getProvider(String name)200 public static synchronized Provider getProvider(String name) { 201 return Services.getProvider(name); 202 } 203 204 /** 205 * Returns the array of providers which meet the user supplied string 206 * filter. The specified filter must be supplied in one of two formats: 207 * <nl> 208 * <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE 209 * <p> 210 * (for example: "MessageDigest.SHA") 211 * <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE 212 * ATTR_NAME:ATTR_VALUE 213 * <p> 214 * (for example: "Signature.MD2withRSA KeySize:512") 215 * </nl> 216 * 217 * @param filter 218 * case-insensitive filter. 219 * @return the providers which meet the user supplied string filter {@code 220 * filter}. A {@code null} value signifies that none of the 221 * installed providers meets the filter specification. 222 * @throws InvalidParameterException 223 * if an unusable filter is supplied. 224 * @throws NullPointerException 225 * if {@code filter} is {@code null}. 226 */ getProviders(String filter)227 public static Provider[] getProviders(String filter) { 228 if (filter == null) { 229 throw new NullPointerException("filter == null"); 230 } 231 if (filter.length() == 0) { 232 throw new InvalidParameterException(); 233 } 234 HashMap<String, String> hm = new HashMap<String, String>(); 235 int i = filter.indexOf(':'); 236 if ((i == filter.length() - 1) || (i == 0)) { 237 throw new InvalidParameterException(); 238 } 239 if (i < 1) { 240 hm.put(filter, ""); 241 } else { 242 hm.put(filter.substring(0, i), filter.substring(i + 1)); 243 } 244 return getProviders(hm); 245 } 246 247 /** 248 * Returns the array of providers which meet the user supplied set of 249 * filters. The filter must be supplied in one of two formats: 250 * <nl> 251 * <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE 252 * <p> 253 * for example: "MessageDigest.SHA" The value associated with the key must 254 * be an empty string. <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE 255 * ATTR_NAME:ATTR_VALUE 256 * <p> 257 * for example: "Signature.MD2withRSA KeySize:512" where "KeySize:512" is 258 * the value of the filter map entry. 259 * </nl> 260 * 261 * @param filter 262 * case-insensitive filter. 263 * @return the providers which meet the user supplied string filter {@code 264 * filter}. A {@code null} value signifies that none of the 265 * installed providers meets the filter specification. 266 * @throws InvalidParameterException 267 * if an unusable filter is supplied. 268 * @throws NullPointerException 269 * if {@code filter} is {@code null}. 270 */ getProviders(Map<String,String> filter)271 public static synchronized Provider[] getProviders(Map<String,String> filter) { 272 if (filter == null) { 273 throw new NullPointerException("filter == null"); 274 } 275 if (filter.isEmpty()) { 276 return null; 277 } 278 ArrayList<Provider> result = new ArrayList<Provider>(Services.getProviders()); 279 Set<Entry<String, String>> keys = filter.entrySet(); 280 Map.Entry<String, String> entry; 281 for (Iterator<Entry<String, String>> it = keys.iterator(); it.hasNext();) { 282 entry = it.next(); 283 String key = entry.getKey(); 284 String val = entry.getValue(); 285 String attribute = null; 286 int i = key.indexOf(' '); 287 int j = key.indexOf('.'); 288 if (j == -1) { 289 throw new InvalidParameterException(); 290 } 291 if (i == -1) { // <crypto_service>.<algorithm_or_type> 292 if (val.length() != 0) { 293 throw new InvalidParameterException(); 294 } 295 } else { // <crypto_service>.<algorithm_or_type> <attribute_name> 296 if (val.length() == 0) { 297 throw new InvalidParameterException(); 298 } 299 attribute = key.substring(i + 1); 300 if (attribute.trim().length() == 0) { 301 throw new InvalidParameterException(); 302 } 303 key = key.substring(0, i); 304 } 305 String serv = key.substring(0, j); 306 String alg = key.substring(j + 1); 307 if (serv.length() == 0 || alg.length() == 0) { 308 throw new InvalidParameterException(); 309 } 310 filterProviders(result, serv, alg, attribute, val); 311 } 312 if (result.size() > 0) { 313 return result.toArray(new Provider[result.size()]); 314 } 315 return null; 316 } 317 filterProviders(ArrayList<Provider> providers, String service, String algorithm, String attribute, String attrValue)318 private static void filterProviders(ArrayList<Provider> providers, String service, 319 String algorithm, String attribute, String attrValue) { 320 Iterator<Provider> it = providers.iterator(); 321 while (it.hasNext()) { 322 Provider p = it.next(); 323 if (!p.implementsAlg(service, algorithm, attribute, attrValue)) { 324 it.remove(); 325 } 326 } 327 } 328 329 /** 330 * Returns the value of the security property named by the argument. 331 * 332 * @param key 333 * the name of the requested security property. 334 * @return the value of the security property. 335 */ getProperty(String key)336 public static String getProperty(String key) { 337 if (key == null) { 338 throw new NullPointerException("key == null"); 339 } 340 String property = secprops.getProperty(key); 341 if (property != null) { 342 property = property.trim(); 343 } 344 return property; 345 } 346 347 /** 348 * Sets the value of the specified security property. 349 */ setProperty(String key, String value)350 public static void setProperty(String key, String value) { 351 Services.setNeedRefresh(); 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 */ getAlgorithms(String serviceName)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 */ renumProviders()388 private static void renumProviders() { 389 ArrayList<Provider> providers = Services.getProviders(); 390 for (int i = 0; i < providers.size(); i++) { 391 providers.get(i).setProviderNumber(i + 1); 392 } 393 } 394 395 private static class SecurityDoor implements SecurityAccess { 396 // Access to Security.renumProviders() renumProviders()397 public void renumProviders() { 398 Security.renumProviders(); 399 } 400 401 // Access to Security.getAliases() getAliases(Provider.Service s)402 public List<String> getAliases(Provider.Service s) { 403 return s.getAliases(); 404 } 405 406 // Access to Provider.getService() getService(Provider p, String type)407 public Provider.Service getService(Provider p, String type) { 408 return p.getService(type); 409 } 410 } 411 } 412