1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package java.security; 28 29 import java.lang.reflect.*; 30 import java.util.*; 31 import java.util.concurrent.ConcurrentHashMap; 32 import java.util.concurrent.atomic.AtomicInteger; 33 import java.io.*; 34 import sun.security.jca.GetInstance; 35 import sun.security.jca.ProviderList; 36 import sun.security.jca.Providers; 37 38 /** 39 * <p>This class centralizes all security properties and common security 40 * methods. One of its primary uses is to manage providers. 41 * 42 * <p>The default values of security properties are read from an 43 * implementation-specific location, which is typically the properties file 44 * {@code lib/security/java.security} in the Java installation directory. 45 * 46 * @author Benjamin Renaud 47 */ 48 49 public final class Security { 50 51 // Android-added: Track the version to allow callers know when something has changed. 52 private static final AtomicInteger version = new AtomicInteger(); 53 54 // Android-removed: Debug is stubbed and disabled on Android. 55 // /* Are we debugging? -- for developers */ 56 // private static final Debug sdebug = 57 // Debug.getInstance("properties"); 58 59 /* The java.security properties */ 60 // Android-changed: Added final. 61 private static final Properties props; 62 63 // An element in the cache 64 private static class ProviderProperty { 65 String className; 66 Provider provider; 67 } 68 69 static { 70 // BEGIN Android-changed: doPrivileged is stubbed on Android. 71 // Also, because props is final it must be assigned in the static block, not a method. 72 /* 73 // doPrivileged here because there are multiple 74 // things in initialize that might require privs. 75 // (the FileInputStream call and the File.exists call, 76 // the securityPropFile call, etc) 77 AccessController.doPrivileged(new PrivilegedAction<Void>() { 78 public Void run() { 79 initialize(); 80 return null; 81 } 82 }); 83 } 84 85 private static void initialize() { 86 */ 87 // END Android-changed: doPrivileged is stubbed on Android. 88 props = new Properties(); 89 boolean loadedProps = false; 90 // BEGIN Android-changed: Use a resource file, Android logging, and only one file. 91 InputStream is = null; 92 try { 93 /* 94 * Android keeps the property file in a resource file. 95 */ 96 InputStream propStream = Security.class.getResourceAsStream("security.properties"); 97 if (propStream == null) { 98 System.logE("Could not find 'security.properties'."); 99 } else { 100 is = new BufferedInputStream(propStream); 101 props.load(is); 102 loadedProps = true; 103 } 104 } catch (IOException ex) { 105 System.logE("Could not load 'security.properties'", ex); 106 } finally { 107 if (is != null) { 108 try { is.close()109 is.close(); 110 } catch (IOException ignored) {} 111 } 112 } 113 // END Android-changed: Use a resource file, Android logging, and only one file. 114 115 if (!loadedProps) { initializeStatic()116 initializeStatic(); 117 } 118 } 119 120 /* 121 * Initialize to default values, if <java.home>/lib/java.security 122 * is not found. 123 */ initializeStatic()124 private static void initializeStatic() { 125 // Android-changed: Use Conscrypt and BC, not the sun.security providers. 126 /* 127 props.put("security.provider.1", "sun.security.provider.Sun"); 128 props.put("security.provider.2", "sun.security.rsa.SunRsaSign"); 129 props.put("security.provider.3", "com.sun.net.ssl.internal.ssl.Provider"); 130 props.put("security.provider.4", "com.sun.crypto.provider.SunJCE"); 131 props.put("security.provider.5", "sun.security.jgss.SunProvider"); 132 props.put("security.provider.6", "com.sun.security.sasl.Provider"); 133 */ 134 props.put("security.provider.1", "com.android.org.conscrypt.OpenSSLProvider"); 135 props.put("security.provider.2", "sun.security.provider.CertPathProvider"); 136 props.put("security.provider.3", "com.android.org.bouncycastle.jce.provider.BouncyCastleProvider"); 137 props.put("security.provider.4", "com.android.org.conscrypt.JSSEProvider"); 138 } 139 140 /** 141 * Don't let anyone instantiate this. 142 */ Security()143 private Security() { 144 } 145 146 /** 147 * Looks up providers, and returns the property (and its associated 148 * provider) mapping the key, if any. 149 * The order in which the providers are looked up is the 150 * provider-preference order, as specificed in the security 151 * properties file. 152 */ getProviderProperty(String key)153 private static ProviderProperty getProviderProperty(String key) { 154 ProviderProperty entry = null; 155 156 List<Provider> providers = Providers.getProviderList().providers(); 157 for (int i = 0; i < providers.size(); i++) { 158 159 String matchKey = null; 160 Provider prov = providers.get(i); 161 String prop = prov.getProperty(key); 162 163 if (prop == null) { 164 // Is there a match if we do a case-insensitive property name 165 // comparison? Let's try ... 166 for (Enumeration<Object> e = prov.keys(); 167 e.hasMoreElements() && prop == null; ) { 168 matchKey = (String)e.nextElement(); 169 if (key.equalsIgnoreCase(matchKey)) { 170 prop = prov.getProperty(matchKey); 171 break; 172 } 173 } 174 } 175 176 if (prop != null) { 177 ProviderProperty newEntry = new ProviderProperty(); 178 newEntry.className = prop; 179 newEntry.provider = prov; 180 return newEntry; 181 } 182 } 183 184 return entry; 185 } 186 187 /** 188 * Returns the property (if any) mapping the key for the given provider. 189 */ getProviderProperty(String key, Provider provider)190 private static String getProviderProperty(String key, Provider provider) { 191 String prop = provider.getProperty(key); 192 if (prop == null) { 193 // Is there a match if we do a case-insensitive property name 194 // comparison? Let's try ... 195 for (Enumeration<Object> e = provider.keys(); 196 e.hasMoreElements() && prop == null; ) { 197 String matchKey = (String)e.nextElement(); 198 if (key.equalsIgnoreCase(matchKey)) { 199 prop = provider.getProperty(matchKey); 200 break; 201 } 202 } 203 } 204 return prop; 205 } 206 207 /** 208 * Gets a specified property for an algorithm. The algorithm name 209 * should be a standard name. See the <a href= 210 * "{@docRoot}/../technotes/guides/security/StandardNames.html"> 211 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 212 * for information about standard algorithm names. 213 * 214 * One possible use is by specialized algorithm parsers, which may map 215 * classes to algorithms which they understand (much like Key parsers 216 * do). 217 * 218 * @param algName the algorithm name. 219 * 220 * @param propName the name of the property to get. 221 * 222 * @return the value of the specified property. 223 * 224 * @deprecated This method used to return the value of a proprietary 225 * property in the master file of the "SUN" Cryptographic Service 226 * Provider in order to determine how to parse algorithm-specific 227 * parameters. Use the new provider-based and algorithm-independent 228 * {@code AlgorithmParameters} and {@code KeyFactory} engine 229 * classes (introduced in the J2SE version 1.2 platform) instead. 230 */ 231 @Deprecated getAlgorithmProperty(String algName, String propName)232 public static String getAlgorithmProperty(String algName, 233 String propName) { 234 ProviderProperty entry = getProviderProperty("Alg." + propName 235 + "." + algName); 236 if (entry != null) { 237 return entry.className; 238 } else { 239 return null; 240 } 241 } 242 243 /** 244 * Adds a new provider, at a specified position. The position is 245 * the preference order in which providers are searched for 246 * requested algorithms. The position is 1-based, that is, 247 * 1 is most preferred, followed by 2, and so on. 248 * 249 * <p>If the given provider is installed at the requested position, 250 * the provider that used to be at that position, and all providers 251 * with a position greater than {@code position}, are shifted up 252 * one position (towards the end of the list of installed providers). 253 * 254 * <p>A provider cannot be added if it is already installed. 255 * 256 * <p>If there is a security manager, the 257 * {@link java.lang.SecurityManager#checkSecurityAccess} method is called 258 * with the {@code "insertProvider"} permission target name to see if 259 * it's ok to add a new provider. If this permission check is denied, 260 * {@code checkSecurityAccess} is called again with the 261 * {@code "insertProvider."+provider.getName()} permission target name. If 262 * both checks are denied, a {@code SecurityException} is thrown. 263 * 264 * @param provider the provider to be added. 265 * 266 * @param position the preference position that the caller would 267 * like for this provider. 268 * 269 * @return the actual preference position in which the provider was 270 * added, or -1 if the provider was not added because it is 271 * already installed. 272 * 273 * @throws NullPointerException if provider is null 274 * @throws SecurityException 275 * if a security manager exists and its {@link 276 * java.lang.SecurityManager#checkSecurityAccess} method 277 * denies access to add a new provider 278 * 279 * @see #getProvider 280 * @see #removeProvider 281 * @see java.security.SecurityPermission 282 */ insertProviderAt(Provider provider, int position)283 public static synchronized int insertProviderAt(Provider provider, 284 int position) { 285 String providerName = provider.getName(); 286 // Android-removed: Checks using SecurityManager, which is not functional in Android. 287 // checkInsertProvider(providerName); 288 ProviderList list = Providers.getFullProviderList(); 289 ProviderList newList = ProviderList.insertAt(list, provider, position - 1); 290 if (list == newList) { 291 return -1; 292 } 293 // Android-added: Version tracking call. 294 increaseVersion(); 295 Providers.setProviderList(newList); 296 return newList.getIndex(providerName) + 1; 297 } 298 299 /** 300 * Adds a provider to the next position available. 301 * 302 * <p>If there is a security manager, the 303 * {@link java.lang.SecurityManager#checkSecurityAccess} method is called 304 * with the {@code "insertProvider"} permission target name to see if 305 * it's ok to add a new provider. If this permission check is denied, 306 * {@code checkSecurityAccess} is called again with the 307 * {@code "insertProvider."+provider.getName()} permission target name. If 308 * both checks are denied, a {@code SecurityException} is thrown. 309 * 310 * @param provider the provider to be added. 311 * 312 * @return the preference position in which the provider was 313 * added, or -1 if the provider was not added because it is 314 * already installed. 315 * 316 * @throws NullPointerException if provider is null 317 * @throws SecurityException 318 * if a security manager exists and its {@link 319 * java.lang.SecurityManager#checkSecurityAccess} method 320 * denies access to add a new provider 321 * 322 * @see #getProvider 323 * @see #removeProvider 324 * @see java.security.SecurityPermission 325 */ addProvider(Provider provider)326 public static int addProvider(Provider provider) { 327 /* 328 * We can't assign a position here because the statically 329 * registered providers may not have been installed yet. 330 * insertProviderAt() will fix that value after it has 331 * loaded the static providers. 332 */ 333 return insertProviderAt(provider, 0); 334 } 335 336 /** 337 * Removes the provider with the specified name. 338 * 339 * <p>When the specified provider is removed, all providers located 340 * at a position greater than where the specified provider was are shifted 341 * down one position (towards the head of the list of installed 342 * providers). 343 * 344 * <p>This method returns silently if the provider is not installed or 345 * if name is null. 346 * 347 * <p>First, if there is a security manager, its 348 * {@code checkSecurityAccess} 349 * method is called with the string {@code "removeProvider."+name} 350 * to see if it's ok to remove the provider. 351 * If the default implementation of {@code checkSecurityAccess} 352 * is used (i.e., that method is not overriden), then this will result in 353 * a call to the security manager's {@code checkPermission} method 354 * with a {@code SecurityPermission("removeProvider."+name)} 355 * permission. 356 * 357 * @param name the name of the provider to remove. 358 * 359 * @throws SecurityException 360 * if a security manager exists and its {@link 361 * java.lang.SecurityManager#checkSecurityAccess} method 362 * denies 363 * access to remove the provider 364 * 365 * @see #getProvider 366 * @see #addProvider 367 */ removeProvider(String name)368 public static synchronized void removeProvider(String name) { 369 // Android-removed: Checks using SecurityManager, which is not functional in Android. 370 // check("removeProvider." + name); 371 ProviderList list = Providers.getFullProviderList(); 372 ProviderList newList = ProviderList.remove(list, name); 373 Providers.setProviderList(newList); 374 // Android-added: Version tracking call. 375 increaseVersion(); 376 } 377 378 /** 379 * Returns an array containing all the installed providers. The order of 380 * the providers in the array is their preference order. 381 * 382 * @return an array of all the installed providers. 383 */ getProviders()384 public static Provider[] getProviders() { 385 return Providers.getFullProviderList().toArray(); 386 } 387 388 /** 389 * Returns the provider installed with the specified name, if 390 * any. Returns null if no provider with the specified name is 391 * installed or if name is null. 392 * 393 * @param name the name of the provider to get. 394 * 395 * @return the provider of the specified name. 396 * 397 * @see #removeProvider 398 * @see #addProvider 399 */ getProvider(String name)400 public static Provider getProvider(String name) { 401 return Providers.getProviderList().getProvider(name); 402 } 403 404 /** 405 * Returns an array containing all installed providers that satisfy the 406 * specified selection criterion, or null if no such providers have been 407 * installed. The returned providers are ordered 408 * according to their 409 * {@linkplain #insertProviderAt(java.security.Provider, int) preference order}. 410 * 411 * <p> A cryptographic service is always associated with a particular 412 * algorithm or type. For example, a digital signature service is 413 * always associated with a particular algorithm (e.g., DSA), 414 * and a CertificateFactory service is always associated with 415 * a particular certificate type (e.g., X.509). 416 * 417 * <p>The selection criterion must be specified in one of the following two 418 * formats: 419 * <ul> 420 * <li> <i>{@literal <crypto_service>.<algorithm_or_type>}</i> 421 * <p> The cryptographic service name must not contain any dots. 422 * <p> A 423 * provider satisfies the specified selection criterion iff the provider 424 * implements the 425 * specified algorithm or type for the specified cryptographic service. 426 * <p> For example, "CertificateFactory.X.509" 427 * would be satisfied by any provider that supplied 428 * a CertificateFactory implementation for X.509 certificates. 429 * <li> <i>{@literal <crypto_service>.<algorithm_or_type> 430 * <attribute_name>:<attribute_value>}</i> 431 * <p> The cryptographic service name must not contain any dots. There 432 * must be one or more space characters between the 433 * <i>{@literal <algorithm_or_type>}</i> and the 434 * <i>{@literal <attribute_name>}</i>. 435 * <p> A provider satisfies this selection criterion iff the 436 * provider implements the specified algorithm or type for the specified 437 * cryptographic service and its implementation meets the 438 * constraint expressed by the specified attribute name/value pair. 439 * <p> For example, "Signature.SHA1withDSA KeySize:1024" would be 440 * satisfied by any provider that implemented 441 * the SHA1withDSA signature algorithm with a keysize of 1024 (or larger). 442 * 443 * </ul> 444 * 445 * <p> See the <a href= 446 * "{@docRoot}/../technotes/guides/security/StandardNames.html"> 447 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 448 * for information about standard cryptographic service names, standard 449 * algorithm names and standard attribute names. 450 * 451 * @param filter the criterion for selecting 452 * providers. The filter is case-insensitive. 453 * 454 * @return all the installed providers that satisfy the selection 455 * criterion, or null if no such providers have been installed. 456 * 457 * @throws InvalidParameterException 458 * if the filter is not in the required format 459 * @throws NullPointerException if filter is null 460 * 461 * @see #getProviders(java.util.Map) 462 * @since 1.3 463 */ getProviders(String filter)464 public static Provider[] getProviders(String filter) { 465 String key = null; 466 String value = null; 467 int index = filter.indexOf(':'); 468 469 if (index == -1) { 470 key = filter; 471 value = ""; 472 } else { 473 key = filter.substring(0, index); 474 value = filter.substring(index + 1); 475 } 476 477 Hashtable<String, String> hashtableFilter = new Hashtable<>(1); 478 hashtableFilter.put(key, value); 479 480 return (getProviders(hashtableFilter)); 481 } 482 483 /** 484 * Returns an array containing all installed providers that satisfy the 485 * specified* selection criteria, or null if no such providers have been 486 * installed. The returned providers are ordered 487 * according to their 488 * {@linkplain #insertProviderAt(java.security.Provider, int) 489 * preference order}. 490 * 491 * <p>The selection criteria are represented by a map. 492 * Each map entry represents a selection criterion. 493 * A provider is selected iff it satisfies all selection 494 * criteria. The key for any entry in such a map must be in one of the 495 * following two formats: 496 * <ul> 497 * <li> <i>{@literal <crypto_service>.<algorithm_or_type>}</i> 498 * <p> The cryptographic service name must not contain any dots. 499 * <p> The value associated with the key must be an empty string. 500 * <p> A provider 501 * satisfies this selection criterion iff the provider implements the 502 * specified algorithm or type for the specified cryptographic service. 503 * <li> <i>{@literal <crypto_service>}. 504 * {@literal <algorithm_or_type> <attribute_name>}</i> 505 * <p> The cryptographic service name must not contain any dots. There 506 * must be one or more space characters between the 507 * <i>{@literal <algorithm_or_type>}</i> 508 * and the <i>{@literal <attribute_name>}</i>. 509 * <p> The value associated with the key must be a non-empty string. 510 * A provider satisfies this selection criterion iff the 511 * provider implements the specified algorithm or type for the specified 512 * cryptographic service and its implementation meets the 513 * constraint expressed by the specified attribute name/value pair. 514 * </ul> 515 * 516 * <p> See the <a href= 517 * "../../../technotes/guides/security/StandardNames.html"> 518 * Java Cryptography Architecture Standard Algorithm Name Documentation</a> 519 * for information about standard cryptographic service names, standard 520 * algorithm names and standard attribute names. 521 * 522 * @param filter the criteria for selecting 523 * providers. The filter is case-insensitive. 524 * 525 * @return all the installed providers that satisfy the selection 526 * criteria, or null if no such providers have been installed. 527 * 528 * @throws InvalidParameterException 529 * if the filter is not in the required format 530 * @throws NullPointerException if filter is null 531 * 532 * @see #getProviders(java.lang.String) 533 * @since 1.3 534 */ getProviders(Map<String,String> filter)535 public static Provider[] getProviders(Map<String,String> filter) { 536 // Get all installed providers first. 537 // Then only return those providers who satisfy the selection criteria. 538 Provider[] allProviders = Security.getProviders(); 539 Set<String> keySet = filter.keySet(); 540 LinkedHashSet<Provider> candidates = new LinkedHashSet<>(5); 541 542 // Returns all installed providers 543 // if the selection criteria is null. 544 if ((keySet == null) || (allProviders == null)) { 545 return allProviders; 546 } 547 548 boolean firstSearch = true; 549 550 // For each selection criterion, remove providers 551 // which don't satisfy the criterion from the candidate set. 552 for (Iterator<String> ite = keySet.iterator(); ite.hasNext(); ) { 553 String key = ite.next(); 554 String value = filter.get(key); 555 556 LinkedHashSet<Provider> newCandidates = getAllQualifyingCandidates(key, value, 557 allProviders); 558 if (firstSearch) { 559 candidates = newCandidates; 560 firstSearch = false; 561 } 562 563 if ((newCandidates != null) && !newCandidates.isEmpty()) { 564 // For each provider in the candidates set, if it 565 // isn't in the newCandidate set, we should remove 566 // it from the candidate set. 567 for (Iterator<Provider> cansIte = candidates.iterator(); 568 cansIte.hasNext(); ) { 569 Provider prov = cansIte.next(); 570 if (!newCandidates.contains(prov)) { 571 cansIte.remove(); 572 } 573 } 574 } else { 575 candidates = null; 576 break; 577 } 578 } 579 580 if ((candidates == null) || (candidates.isEmpty())) 581 return null; 582 583 Object[] candidatesArray = candidates.toArray(); 584 Provider[] result = new Provider[candidatesArray.length]; 585 586 for (int i = 0; i < result.length; i++) { 587 result[i] = (Provider)candidatesArray[i]; 588 } 589 590 return result; 591 } 592 593 // Map containing cached Spi Class objects of the specified type 594 private static final Map<String, Class<?>> spiMap = 595 new ConcurrentHashMap<>(); 596 597 /** 598 * Return the Class object for the given engine type 599 * (e.g. "MessageDigest"). Works for Spis in the java.security package 600 * only. 601 */ getSpiClass(String type)602 private static Class<?> getSpiClass(String type) { 603 Class<?> clazz = spiMap.get(type); 604 if (clazz != null) { 605 return clazz; 606 } 607 try { 608 clazz = Class.forName("java.security." + type + "Spi"); 609 spiMap.put(type, clazz); 610 return clazz; 611 } catch (ClassNotFoundException e) { 612 throw new AssertionError("Spi class not found", e); 613 } 614 } 615 616 /* 617 * Returns an array of objects: the first object in the array is 618 * an instance of an implementation of the requested algorithm 619 * and type, and the second object in the array identifies the provider 620 * of that implementation. 621 * The {@code provider} argument can be null, in which case all 622 * configured providers will be searched in order of preference. 623 */ getImpl(String algorithm, String type, String provider)624 static Object[] getImpl(String algorithm, String type, String provider) 625 throws NoSuchAlgorithmException, NoSuchProviderException { 626 if (provider == null) { 627 return GetInstance.getInstance 628 (type, getSpiClass(type), algorithm).toArray(); 629 } else { 630 return GetInstance.getInstance 631 (type, getSpiClass(type), algorithm, provider).toArray(); 632 } 633 } 634 getImpl(String algorithm, String type, String provider, Object params)635 static Object[] getImpl(String algorithm, String type, String provider, 636 Object params) throws NoSuchAlgorithmException, 637 NoSuchProviderException, InvalidAlgorithmParameterException { 638 if (provider == null) { 639 return GetInstance.getInstance 640 (type, getSpiClass(type), algorithm, params).toArray(); 641 } else { 642 return GetInstance.getInstance 643 (type, getSpiClass(type), algorithm, params, provider).toArray(); 644 } 645 } 646 647 /* 648 * Returns an array of objects: the first object in the array is 649 * an instance of an implementation of the requested algorithm 650 * and type, and the second object in the array identifies the provider 651 * of that implementation. 652 * The {@code provider} argument cannot be null. 653 */ getImpl(String algorithm, String type, Provider provider)654 static Object[] getImpl(String algorithm, String type, Provider provider) 655 throws NoSuchAlgorithmException { 656 return GetInstance.getInstance 657 (type, getSpiClass(type), algorithm, provider).toArray(); 658 } 659 getImpl(String algorithm, String type, Provider provider, Object params)660 static Object[] getImpl(String algorithm, String type, Provider provider, 661 Object params) throws NoSuchAlgorithmException, 662 InvalidAlgorithmParameterException { 663 return GetInstance.getInstance 664 (type, getSpiClass(type), algorithm, params, provider).toArray(); 665 } 666 667 /** 668 * Gets a security property value. 669 * 670 * <p>First, if there is a security manager, its 671 * {@code checkPermission} method is called with a 672 * {@code java.security.SecurityPermission("getProperty."+key)} 673 * permission to see if it's ok to retrieve the specified 674 * security property value.. 675 * 676 * @param key the key of the property being retrieved. 677 * 678 * @return the value of the security property corresponding to key. 679 * 680 * @throws SecurityException 681 * if a security manager exists and its {@link 682 * java.lang.SecurityManager#checkPermission} method 683 * denies 684 * access to retrieve the specified security property value 685 * @throws NullPointerException is key is null 686 * 687 * @see #setProperty 688 * @see java.security.SecurityPermission 689 */ getProperty(String key)690 public static String getProperty(String key) { 691 SecurityManager sm = System.getSecurityManager(); 692 if (sm != null) { 693 sm.checkPermission(new SecurityPermission("getProperty."+ 694 key)); 695 } 696 String name = props.getProperty(key); 697 if (name != null) 698 name = name.trim(); // could be a class name with trailing ws 699 return name; 700 } 701 702 /** 703 * Sets a security property value. 704 * 705 * <p>First, if there is a security manager, its 706 * {@code checkPermission} method is called with a 707 * {@code java.security.SecurityPermission("setProperty."+key)} 708 * permission to see if it's ok to set the specified 709 * security property value. 710 * 711 * @param key the name of the property to be set. 712 * 713 * @param datum the value of the property to be set. 714 * 715 * @throws SecurityException 716 * if a security manager exists and its {@link 717 * java.lang.SecurityManager#checkPermission} method 718 * denies access to set the specified security property value 719 * @throws NullPointerException if key or datum is null 720 * 721 * @see #getProperty 722 * @see java.security.SecurityPermission 723 */ setProperty(String key, String datum)724 public static void setProperty(String key, String datum) { 725 // Android-removed: Checks using SecurityManager, which is not functional in Android. 726 // check("setProperty."+key); 727 props.put(key, datum); 728 // Android-added: Version tracking call. 729 increaseVersion(); 730 invalidateSMCache(key); /* See below. */ 731 } 732 733 /* 734 * Implementation detail: If the property we just set in 735 * setProperty() was either "package.access" or 736 * "package.definition", we need to signal to the SecurityManager 737 * class that the value has just changed, and that it should 738 * invalidate it's local cache values. 739 * 740 * Rather than create a new API entry for this function, 741 * we use reflection to set a private variable. 742 */ invalidateSMCache(String key)743 private static void invalidateSMCache(String key) { 744 745 final boolean pa = key.equals("package.access"); 746 final boolean pd = key.equals("package.definition"); 747 748 if (pa || pd) { 749 AccessController.doPrivileged(new PrivilegedAction<Void>() { 750 public Void run() { 751 try { 752 /* Get the class via the bootstrap class loader. */ 753 Class<?> cl = Class.forName( 754 "java.lang.SecurityManager", false, null); 755 Field f = null; 756 boolean accessible = false; 757 758 if (pa) { 759 f = cl.getDeclaredField("packageAccessValid"); 760 accessible = f.isAccessible(); 761 f.setAccessible(true); 762 } else { 763 f = cl.getDeclaredField("packageDefinitionValid"); 764 accessible = f.isAccessible(); 765 f.setAccessible(true); 766 } 767 f.setBoolean(f, false); 768 f.setAccessible(accessible); 769 } 770 catch (Exception e1) { 771 /* If we couldn't get the class, it hasn't 772 * been loaded yet. If there is no such 773 * field, we shouldn't try to set it. There 774 * shouldn't be a security execption, as we 775 * are loaded by boot class loader, and we 776 * are inside a doPrivileged() here. 777 * 778 * NOOP: don't do anything... 779 */ 780 } 781 return null; 782 } /* run */ 783 }); /* PrivilegedAction */ 784 } /* if */ 785 } 786 787 // BEGIN Android-removed: SecurityManager is stubbed on Android. 788 /* 789 private static void check(String directive) { 790 SecurityManager security = System.getSecurityManager(); 791 if (security != null) { 792 security.checkSecurityAccess(directive); 793 } 794 } 795 796 private static void checkInsertProvider(String name) { 797 SecurityManager security = System.getSecurityManager(); 798 if (security != null) { 799 try { 800 security.checkSecurityAccess("insertProvider"); 801 } catch (SecurityException se1) { 802 try { 803 security.checkSecurityAccess("insertProvider." + name); 804 } catch (SecurityException se2) { 805 // throw first exception, but add second to suppressed 806 se1.addSuppressed(se2); 807 throw se1; 808 } 809 } 810 } 811 } 812 */ 813 // END Android-removed: SecurityManager is stubbed on Android. 814 815 /* 816 * Returns all providers who satisfy the specified 817 * criterion. 818 */ getAllQualifyingCandidates( String filterKey, String filterValue, Provider[] allProviders)819 private static LinkedHashSet<Provider> getAllQualifyingCandidates( 820 String filterKey, 821 String filterValue, 822 Provider[] allProviders) { 823 String[] filterComponents = getFilterComponents(filterKey, 824 filterValue); 825 826 // The first component is the service name. 827 // The second is the algorithm name. 828 // If the third isn't null, that is the attrinute name. 829 String serviceName = filterComponents[0]; 830 String algName = filterComponents[1]; 831 String attrName = filterComponents[2]; 832 833 return getProvidersNotUsingCache(serviceName, algName, attrName, 834 filterValue, allProviders); 835 } 836 getProvidersNotUsingCache( String serviceName, String algName, String attrName, String filterValue, Provider[] allProviders)837 private static LinkedHashSet<Provider> getProvidersNotUsingCache( 838 String serviceName, 839 String algName, 840 String attrName, 841 String filterValue, 842 Provider[] allProviders) { 843 LinkedHashSet<Provider> candidates = new LinkedHashSet<>(5); 844 for (int i = 0; i < allProviders.length; i++) { 845 if (isCriterionSatisfied(allProviders[i], serviceName, 846 algName, 847 attrName, filterValue)) { 848 candidates.add(allProviders[i]); 849 } 850 } 851 return candidates; 852 } 853 854 /* 855 * Returns true if the given provider satisfies 856 * the selection criterion key:value. 857 */ isCriterionSatisfied(Provider prov, String serviceName, String algName, String attrName, String filterValue)858 private static boolean isCriterionSatisfied(Provider prov, 859 String serviceName, 860 String algName, 861 String attrName, 862 String filterValue) { 863 String key = serviceName + '.' + algName; 864 865 if (attrName != null) { 866 key += ' ' + attrName; 867 } 868 // Check whether the provider has a property 869 // whose key is the same as the given key. 870 String propValue = getProviderProperty(key, prov); 871 872 if (propValue == null) { 873 // Check whether we have an alias instead 874 // of a standard name in the key. 875 String standardName = getProviderProperty("Alg.Alias." + 876 serviceName + "." + 877 algName, 878 prov); 879 if (standardName != null) { 880 key = serviceName + "." + standardName; 881 882 if (attrName != null) { 883 key += ' ' + attrName; 884 } 885 886 propValue = getProviderProperty(key, prov); 887 } 888 889 if (propValue == null) { 890 // The provider doesn't have the given 891 // key in its property list. 892 return false; 893 } 894 } 895 896 // If the key is in the format of: 897 // <crypto_service>.<algorithm_or_type>, 898 // there is no need to check the value. 899 900 if (attrName == null) { 901 return true; 902 } 903 904 // If we get here, the key must be in the 905 // format of <crypto_service>.<algorithm_or_provider> <attribute_name>. 906 if (isStandardAttr(attrName)) { 907 return isConstraintSatisfied(attrName, filterValue, propValue); 908 } else { 909 return filterValue.equalsIgnoreCase(propValue); 910 } 911 } 912 913 /* 914 * Returns true if the attribute is a standard attribute; 915 * otherwise, returns false. 916 */ isStandardAttr(String attribute)917 private static boolean isStandardAttr(String attribute) { 918 // For now, we just have two standard attributes: 919 // KeySize and ImplementedIn. 920 if (attribute.equalsIgnoreCase("KeySize")) 921 return true; 922 923 if (attribute.equalsIgnoreCase("ImplementedIn")) 924 return true; 925 926 return false; 927 } 928 929 /* 930 * Returns true if the requested attribute value is supported; 931 * otherwise, returns false. 932 */ isConstraintSatisfied(String attribute, String value, String prop)933 private static boolean isConstraintSatisfied(String attribute, 934 String value, 935 String prop) { 936 // For KeySize, prop is the max key size the 937 // provider supports for a specific <crypto_service>.<algorithm>. 938 if (attribute.equalsIgnoreCase("KeySize")) { 939 int requestedSize = Integer.parseInt(value); 940 int maxSize = Integer.parseInt(prop); 941 if (requestedSize <= maxSize) { 942 return true; 943 } else { 944 return false; 945 } 946 } 947 948 // For Type, prop is the type of the implementation 949 // for a specific <crypto service>.<algorithm>. 950 if (attribute.equalsIgnoreCase("ImplementedIn")) { 951 return value.equalsIgnoreCase(prop); 952 } 953 954 return false; 955 } 956 getFilterComponents(String filterKey, String filterValue)957 static String[] getFilterComponents(String filterKey, String filterValue) { 958 int algIndex = filterKey.indexOf('.'); 959 960 if (algIndex < 0) { 961 // There must be a dot in the filter, and the dot 962 // shouldn't be at the beginning of this string. 963 throw new InvalidParameterException("Invalid filter"); 964 } 965 966 String serviceName = filterKey.substring(0, algIndex); 967 String algName = null; 968 String attrName = null; 969 970 if (filterValue.length() == 0) { 971 // The filterValue is an empty string. So the filterKey 972 // should be in the format of <crypto_service>.<algorithm_or_type>. 973 algName = filterKey.substring(algIndex + 1).trim(); 974 if (algName.length() == 0) { 975 // There must be a algorithm or type name. 976 throw new InvalidParameterException("Invalid filter"); 977 } 978 } else { 979 // The filterValue is a non-empty string. So the filterKey must be 980 // in the format of 981 // <crypto_service>.<algorithm_or_type> <attribute_name> 982 int attrIndex = filterKey.indexOf(' '); 983 984 if (attrIndex == -1) { 985 // There is no attribute name in the filter. 986 throw new InvalidParameterException("Invalid filter"); 987 } else { 988 attrName = filterKey.substring(attrIndex + 1).trim(); 989 if (attrName.length() == 0) { 990 // There is no attribute name in the filter. 991 throw new InvalidParameterException("Invalid filter"); 992 } 993 } 994 995 // There must be an algorithm name in the filter. 996 if ((attrIndex < algIndex) || 997 (algIndex == attrIndex - 1)) { 998 throw new InvalidParameterException("Invalid filter"); 999 } else { 1000 algName = filterKey.substring(algIndex + 1, attrIndex); 1001 } 1002 } 1003 1004 String[] result = new String[3]; 1005 result[0] = serviceName; 1006 result[1] = algName; 1007 result[2] = attrName; 1008 1009 return result; 1010 } 1011 1012 /** 1013 * Returns a Set of Strings containing the names of all available 1014 * algorithms or types for the specified Java cryptographic service 1015 * (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore). Returns 1016 * an empty Set if there is no provider that supports the 1017 * specified service or if serviceName is null. For a complete list 1018 * of Java cryptographic services, please see the 1019 * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">Java 1020 * Cryptography Architecture API Specification & Reference</a>. 1021 * Note: the returned set is immutable. 1022 * 1023 * @param serviceName the name of the Java cryptographic 1024 * service (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore). 1025 * Note: this parameter is case-insensitive. 1026 * 1027 * @return a Set of Strings containing the names of all available 1028 * algorithms or types for the specified Java cryptographic service 1029 * or an empty set if no provider supports the specified service. 1030 * 1031 * @since 1.4 1032 **/ getAlgorithms(String serviceName)1033 public static Set<String> getAlgorithms(String serviceName) { 1034 1035 if ((serviceName == null) || (serviceName.length() == 0) || 1036 (serviceName.endsWith("."))) { 1037 return Collections.emptySet(); 1038 } 1039 1040 HashSet<String> result = new HashSet<>(); 1041 Provider[] providers = Security.getProviders(); 1042 1043 for (int i = 0; i < providers.length; i++) { 1044 // Check the keys for each provider. 1045 for (Enumeration<Object> e = providers[i].keys(); 1046 e.hasMoreElements(); ) { 1047 String currentKey = 1048 ((String)e.nextElement()).toUpperCase(Locale.ENGLISH); 1049 if (currentKey.startsWith( 1050 serviceName.toUpperCase(Locale.ENGLISH))) { 1051 // We should skip the currentKey if it contains a 1052 // whitespace. The reason is: such an entry in the 1053 // provider property contains attributes for the 1054 // implementation of an algorithm. We are only interested 1055 // in entries which lead to the implementation 1056 // classes. 1057 if (currentKey.indexOf(" ") < 0) { 1058 result.add(currentKey.substring( 1059 serviceName.length() + 1)); 1060 } 1061 } 1062 } 1063 } 1064 return Collections.unmodifiableSet(result); 1065 } 1066 1067 // BEGIN Android-added: Methods for version handling. 1068 /** 1069 * @hide 1070 */ increaseVersion()1071 public static void increaseVersion() { 1072 version.incrementAndGet(); 1073 } 1074 /** 1075 * @hide 1076 */ getVersion()1077 public static int getVersion() { 1078 return version.get(); 1079 } 1080 // END Android-added: Methods for version handling. 1081 } 1082