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 20import java.io.BufferedInputStream; 21import java.io.File; 22import java.io.FileInputStream; 23import java.io.IOException; 24import java.io.InputStream; 25// BEGIN android-added 26import java.util.logging.Level; 27import java.util.logging.Logger; 28// END android-added 29import java.util.Enumeration; 30import java.net.URL; 31import java.util.HashMap; 32import java.util.HashSet; 33import java.util.Iterator; 34import java.util.Map; 35import java.util.Properties; 36import java.util.Set; 37import java.util.Map.Entry; 38 39import org.apache.harmony.security.Util; 40import org.apache.harmony.security.fortress.Engine; 41import org.apache.harmony.security.fortress.PolicyUtils; 42import org.apache.harmony.security.fortress.SecurityAccess; 43import org.apache.harmony.security.fortress.Services; 44import org.apache.harmony.security.internal.nls.Messages; 45 46/** 47 * {@code Security} is the central class in the Java Security API. It manages 48 * the list of security {@code Provider} that have been installed into this 49 * runtime environment. 50 */ 51public final class Security { 52 53 // Security properties 54 private static Properties secprops = new Properties(); 55 56 // static initialization 57 // - load security properties files 58 // - load statically registered providers 59 // - if no provider description file found then load default providers 60 static { 61 AccessController.doPrivileged(new java.security.PrivilegedAction<Void>() { 62 public Void run() { 63 boolean loaded = false; 64 65 // BEGIN android-added 66 /* 67 * Android only uses a local "security.properties" resource 68 * for configuration. TODO: Reevaluate this decision. 69 */ 70 try { 71 InputStream configStream = 72 getClass().getResourceAsStream("security.properties"); //$NON-NLS-1$ 73 InputStream input = 74 new BufferedInputStream(configStream, 8192); 75 secprops.load(input); 76 loaded = true; 77 configStream.close(); 78 } catch (Exception ex) { 79 Logger.global.log(Level.SEVERE, 80 "Could not load Security properties.", ex); 81 } 82 // END android-added 83 84 // BEGIN android-removed 85// if (Util.equalsIgnoreCase("true", secprops.getProperty("security.allowCustomPropertiesFile", "true"))) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 86// String securityFile = System.getProperty("java.security.properties"); //$NON-NLS-1$ 87// if (securityFile != null) { 88// if (securityFile.startsWith("=")) { // overwrite //$NON-NLS-1$ 89// secprops = new Properties(); 90// loaded = false; 91// securityFile = securityFile.substring(1); 92// } 93// try { 94// securityFile = PolicyUtils.expand(securityFile, System.getProperties()); 95// } catch (PolicyUtils.ExpansionFailedException e) { 96//// System.err.println("Could not load custom Security properties file " 97//// + securityFile +": " + e); 98// } 99// f = new File(securityFile); 100// InputStream is; 101// try { 102// if (f.exists()) { 103// FileInputStream fis = new FileInputStream(f); 104// is = new BufferedInputStream(fis); 105// } else { 106// URL url = new URL(securityFile); 107// is = new BufferedInputStream(url.openStream()); 108// } 109// secprops.load(is); 110// loaded = true; 111// is.close(); 112// } catch (IOException e) { 113// // System.err.println("Could not load custom Security properties file " 114// // + securityFile +": " + e); 115// } 116// } 117// } 118 // END android-removed 119 if (!loaded) { 120 registerDefaultProviders(); 121 } 122 Engine.door = new SecurityDoor(); 123 return null; 124 } 125 }); 126 } 127 128 /** 129 * This class can't be instantiated. 130 */ 131 private Security() { 132 } 133 134 // Register default providers 135 private static void registerDefaultProviders() { 136 secprops.put("security.provider.1", "org.apache.harmony.security.provider.cert.DRLCertFactory"); //$NON-NLS-1$ //$NON-NLS-2$ 137 secprops.put("security.provider.2", "org.apache.harmony.security.provider.crypto.CryptoProvider"); //$NON-NLS-1$ //$NON-NLS-2$ 138 secprops.put("security.provider.3", "org.apache.harmony.xnet.provider.jsse.JSSEProvider"); //$NON-NLS-1$ //$NON-NLS-2$ 139 secprops.put("security.provider.4", "org.bouncycastle.jce.provider.BouncyCastleProvider"); //$NON-NLS-1$ //$NON-NLS-2$ 140 } 141 142 /** 143 * Returns value for the specified algorithm with the specified name. 144 * 145 * @param algName 146 * the name of the algorithm. 147 * @param propName 148 * the name of the property. 149 * @return value of the property. 150 * @deprecated Use {@link AlgorithmParameters} and {@link KeyFactory} 151 * instead. 152 */ 153 @Deprecated 154 public static String getAlgorithmProperty(String algName, String propName) { 155 if (algName == null || propName == null) { 156 return null; 157 } 158 // BEGIN android-changed 159 String prop = "Alg." + propName + "." + algName; //$NON-NLS-1$ 160 // END android-changed 161 Provider[] providers = getProviders(); 162 for (int i = 0; i < providers.length; i++) { 163 for (Enumeration e = providers[i].propertyNames(); e 164 .hasMoreElements();) { 165 String pname = (String) e.nextElement(); 166 if (Util.equalsIgnoreCase(prop, pname)) { 167 return providers[i].getProperty(pname); 168 } 169 } 170 } 171 return null; 172 } 173 174 /** 175 * Insert the given {@code Provider} at the specified {@code position}. The 176 * positions define the preference order in which providers are searched for 177 * requested algorithms. 178 * <p> 179 * If a {@code SecurityManager} is installed, code calling this method needs 180 * the {@code SecurityPermission} {@code insertProvider.NAME} (where NAME is 181 * the provider name) to be granted, otherwise a {@code SecurityException} 182 * will be thrown. 183 * 184 * @param provider 185 * the provider to insert. 186 * @param position 187 * the position (starting from 1). 188 * @return the actual position or {@code -1} if the given {@code provider} 189 * was already in the list. The actual position may be different 190 * from the desired position. 191 * @throws SecurityException 192 * if a {@code SecurityManager} is installed and the caller does 193 * not have permission to invoke this method. 194 */ 195 public static synchronized int insertProviderAt(Provider provider, 196 int position) { 197 // check security access; check that provider is not already 198 // installed, else return -1; if (position <1) or (position > max 199 // position) position = max position + 1; insert provider, shift up 200 // one position for next providers; Note: The position is 1-based 201 SecurityManager sm = System.getSecurityManager(); 202 if (sm != null) { 203 sm.checkSecurityAccess("insertProvider." + provider.getName()); //$NON-NLS-1$ 204 } 205 if (getProvider(provider.getName()) != null) { 206 return -1; 207 } 208 int result = Services.insertProviderAt(provider, position); 209 renumProviders(); 210 return result; 211 } 212 213 /** 214 * Adds the given {@code provider} to the collection of providers at the 215 * next available position. 216 * <p> 217 * If a {@code SecurityManager} is installed, code calling this method needs 218 * the {@code SecurityPermission} {@code insertProvider.NAME} (where NAME is 219 * the provider name) to be granted, otherwise a {@code SecurityException} 220 * will be thrown. 221 * 222 * @param provider 223 * the provider to be added. 224 * @return the actual position or {@code -1} if the given {@code provider} 225 * was already in the list. 226 * @throws SecurityException 227 * if a {@code SecurityManager} is installed and the caller does 228 * not have permission to invoke this method. 229 */ 230 public static int addProvider(Provider provider) { 231 return insertProviderAt(provider, 0); 232 } 233 234 /** 235 * Removes the {@code Provider} with the specified name form the collection 236 * of providers. If the the {@code Provider} with the specified name is 237 * removed, all provider at a greater position are shifted down one 238 * position. 239 * <p> 240 * Returns silently if {@code name} is {@code null} or no provider with the 241 * specified name is installed. 242 * <p> 243 * If a {@code SecurityManager} is installed, code calling this method needs 244 * the {@code SecurityPermission} {@code removeProvider.NAME} (where NAME is 245 * the provider name) to be granted, otherwise a {@code SecurityException} 246 * will be thrown. 247 * 248 * @param name 249 * the name of the provider to remove. 250 * @throws SecurityException 251 * if a {@code SecurityManager} is installed and the caller does 252 * not have permission to invoke this method. 253 */ 254 public static synchronized void removeProvider(String name) { 255 // It is not clear from spec.: 256 // 1. if name is null, should we checkSecurityAccess or not? 257 // throw SecurityException or not? 258 // 2. as 1 but provider is not installed 259 // 3. behavior if name is empty string? 260 261 Provider p; 262 if ((name == null) || (name.length() == 0)) { 263 return; 264 } 265 p = getProvider(name); 266 if (p == null) { 267 return; 268 } 269 SecurityManager sm = System.getSecurityManager(); 270 if (sm != null) { 271 sm.checkSecurityAccess("removeProvider." + name); //$NON-NLS-1$ 272 } 273 Services.removeProvider(p.getProviderNumber()); 274 renumProviders(); 275 p.setProviderNumber(-1); 276 } 277 278 /** 279 * Returns an array containing all installed providers. The providers are 280 * ordered according their preference order. 281 * 282 * @return an array containing all installed providers. 283 */ 284 public static synchronized Provider[] getProviders() { 285 return Services.getProviders(); 286 } 287 288 /** 289 * Returns the {@code Provider} with the specified name. Returns {@code 290 * null} if name is {@code null} or no provider with the specified name is 291 * installed. 292 * 293 * @param name 294 * the name of the requested provider. 295 * @return the provider with the specified name, maybe {@code null}. 296 */ 297 public static synchronized Provider getProvider(String name) { 298 return Services.getProvider(name); 299 } 300 301 /** 302 * Returns the array of providers which meet the user supplied string 303 * filter. The specified filter must be supplied in one of two formats: 304 * <nl> 305 * <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE 306 * <p> 307 * (for example: "MessageDigest.SHA") 308 * <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE 309 * ATTR_NAME:ATTR_VALUE 310 * <p> 311 * (for example: "Signature.MD2withRSA KeySize:512") 312 * </nl> 313 * 314 * @param filter 315 * case-insensitive filter. 316 * @return the providers which meet the user supplied string filter {@code 317 * filter}. A {@code null} value signifies that none of the 318 * installed providers meets the filter specification. 319 * @throws InvalidParameterException 320 * if an unusable filter is supplied. 321 * @throws NullPointerException 322 * if {@code filter} is {@code null}. 323 */ 324 public static Provider[] getProviders(String filter) { 325 if (filter == null) { 326 throw new NullPointerException(Messages.getString("security.2A")); //$NON-NLS-1$ 327 } 328 if (filter.length() == 0) { 329 throw new InvalidParameterException( 330 Messages.getString("security.2B")); //$NON-NLS-1$ 331 } 332 HashMap<String, String> hm = new HashMap<String, String>(); 333 int i = filter.indexOf(':'); 334 if ((i == filter.length() - 1) || (i == 0)) { 335 throw new InvalidParameterException( 336 Messages.getString("security.2B")); //$NON-NLS-1$ 337 } 338 if (i < 1) { 339 hm.put(filter, ""); //$NON-NLS-1$ 340 } else { 341 hm.put(filter.substring(0, i), filter.substring(i + 1)); 342 } 343 return getProviders(hm); 344 } 345 346 /** 347 * Returns the array of providers which meet the user supplied set of 348 * filters. The filter must be supplied in one of two formats: 349 * <nl> 350 * <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE 351 * <p> 352 * for example: "MessageDigest.SHA" The value associated with the key must 353 * be an empty string. <li> CRYPTO_SERVICE_NAME.ALGORITHM_OR_TYPE 354 * ATTR_NAME:ATTR_VALUE 355 * <p> 356 * for example: "Signature.MD2withRSA KeySize:512" where "KeySize:512" is 357 * the value of the filter map entry. 358 * </nl> 359 * 360 * @param filter 361 * case-insensitive filter. 362 * @return the providers which meet the user supplied string filter {@code 363 * filter}. A {@code null} value signifies that none of the 364 * installed providers meets the filter specification. 365 * @throws InvalidParameterException 366 * if an unusable filter is supplied. 367 * @throws NullPointerException 368 * if {@code filter} is {@code null}. 369 */ 370 public static synchronized Provider[] getProviders(Map<String,String> filter) { 371 if (filter == null) { 372 throw new NullPointerException(Messages.getString("security.2A")); //$NON-NLS-1$ 373 } 374 if (filter.isEmpty()) { 375 return null; 376 } 377 java.util.List<Provider> result = Services.getProvidersList(); 378 Set<Entry<String, String>> keys = filter.entrySet(); 379 Map.Entry<String, String> entry; 380 for (Iterator<Entry<String, String>> it = keys.iterator(); it.hasNext();) { 381 entry = it.next(); 382 String key = entry.getKey(); 383 String val = entry.getValue(); 384 String attribute = null; 385 int i = key.indexOf(' '); 386 int j = key.indexOf('.'); 387 if (j == -1) { 388 throw new InvalidParameterException( 389 Messages.getString("security.2B")); //$NON-NLS-1$ 390 } 391 if (i == -1) { // <crypto_service>.<algorithm_or_type> 392 if (val.length() != 0) { 393 throw new InvalidParameterException( 394 Messages.getString("security.2B")); //$NON-NLS-1$ 395 } 396 } else { // <crypto_service>.<algorithm_or_type> <attribute_name> 397 if (val.length() == 0) { 398 throw new InvalidParameterException( 399 Messages.getString("security.2B")); //$NON-NLS-1$ 400 } 401 attribute = key.substring(i + 1); 402 if (attribute.trim().length() == 0) { 403 throw new InvalidParameterException( 404 Messages.getString("security.2B")); //$NON-NLS-1$ 405 } 406 key = key.substring(0, i); 407 } 408 String serv = key.substring(0, j); 409 String alg = key.substring(j + 1); 410 if (serv.length() == 0 || alg.length() == 0) { 411 throw new InvalidParameterException( 412 Messages.getString("security.2B")); //$NON-NLS-1$ 413 } 414 Provider p; 415 for (int k = 0; k < result.size(); k++) { 416 try { 417 p = result.get(k); 418 } catch (IndexOutOfBoundsException e) { 419 break; 420 } 421 if (!p.implementsAlg(serv, alg, attribute, val)) { 422 result.remove(p); 423 k--; 424 } 425 } 426 } 427 if (result.size() > 0) { 428 return result.toArray(new Provider[result.size()]); 429 } 430 return null; 431 } 432 433 /** 434 * Returns the value of the security property named by the argument. 435 * <p> 436 * If a {@code SecurityManager} is installed, code calling this method needs 437 * the {@code SecurityPermission} {@code getProperty.KEY} (where KEY is the 438 * specified {@code key}) to be granted, otherwise a {@code 439 * SecurityException} will be thrown. 440 * 441 * @param key 442 * the name of the requested security property. 443 * @return the value of the security property. 444 * @throws SecurityException 445 * if a {@code SecurityManager} is installed and the caller does 446 * not have permission to invoke this method. 447 */ 448 public static String getProperty(String key) { 449 if (key == null) { 450 throw new NullPointerException(Messages.getString("security.2C")); //$NON-NLS-1$ 451 } 452 SecurityManager sm = System.getSecurityManager(); 453 if (sm != null) { 454 sm.checkSecurityAccess("getProperty." + key); //$NON-NLS-1$ 455 } 456 String property = secprops.getProperty(key); 457 if (property != null) { 458 property = property.trim(); 459 } 460 return property; 461 } 462 463 /** 464 * Sets the value of the specified security property. 465 * <p> 466 * If a {@code SecurityManager} is installed, code calling this method needs 467 * the {@code SecurityPermission} {@code setProperty.KEY} (where KEY is the 468 * specified {@code key}) to be granted, otherwise a {@code 469 * SecurityException} will be thrown. 470 * 471 * @param key 472 * the name of the security property. 473 * @param datnum 474 * the value of the security property. 475 * @throws SecurityException 476 * if a {@code SecurityManager} is installed and the caller does 477 * not have permission to invoke this method. 478 */ 479 public static void setProperty(String key, String datnum) { 480 SecurityManager sm = System.getSecurityManager(); 481 if (sm != null) { 482 sm.checkSecurityAccess("setProperty." + key); //$NON-NLS-1$ 483 } 484 secprops.put(key, datnum); 485 } 486 487 /** 488 * Returns a {@code Set} of all registered algorithms for the specified 489 * cryptographic service. {@code "Signature"}, {@code "Cipher"} and {@code 490 * "KeyStore"} are examples for such kind of services. 491 * 492 * @param serviceName 493 * the case-insensitive name of the service. 494 * @return a {@code Set} of all registered algorithms for the specified 495 * cryptographic service, or an empty {@code Set} if {@code 496 * serviceName} is {@code null} or if no registered provider 497 * provides the requested service. 498 */ 499 public static Set<String> getAlgorithms(String serviceName) { 500 Set<String> result = new HashSet<String>(); 501 // BEGIN android-added 502 // compatibility with RI 503 if (serviceName == null) { 504 return result; 505 } 506 // END android-added 507 Provider[] p = getProviders(); 508 for (int i = 0; i < p.length; i++) { 509 for (Iterator it = p[i].getServices().iterator(); it.hasNext();) { 510 Provider.Service s = (Provider.Service) it.next(); 511 if (Util.equalsIgnoreCase(s.getType(),serviceName)) { 512 result.add(s.getAlgorithm()); 513 } 514 } 515 } 516 return result; 517 } 518 519 /** 520 * 521 * Update sequence numbers of all providers. 522 * 523 */ 524 private static void renumProviders() { 525 Provider[] p = Services.getProviders(); 526 for (int i = 0; i < p.length; i++) { 527 p[i].setProviderNumber(i + 1); 528 } 529 } 530 531 private static class SecurityDoor implements SecurityAccess { 532 // Access to Security.renumProviders() 533 public void renumProviders() { 534 Security.renumProviders(); 535 } 536 537 // Access to Security.getAliases() 538 public Iterator<String> getAliases(Provider.Service s) { 539 return s.getAliases(); 540 } 541 542 // Access to Provider.getService() 543 public Provider.Service getService(Provider p, String type) { 544 return p.getService(type); 545 } 546 } 547} 548