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