1 /* 2 * Copyright (c) 1996, 2018, 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.JdkSecurityPropertyModificationEvent; 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 overridden), 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 if (isJdkSecurityProperty(key)) { 802 JdkSecurityPropertyModificationEvent spe = new JdkSecurityPropertyModificationEvent(); 803 // following is a no-op if event is disabled 804 spe.key = key; 805 spe.value = datum; 806 spe.commit(); 807 808 if (EventHelper.isLoggingSecurity()) { 809 EventHelper.logJdkSecurityPropertyEvent(key, datum); 810 } 811 } 812 } 813 814 /* 815 * Helper method to identify security properties 816 * that should be specific to JDK usage. 817 */ 818 private static boolean isJdkSecurityProperty(String key) { 819 return key.startsWith("com.sun.") || 820 key.startsWith("crypto.policy") || 821 key.startsWith("jceks.key.serialFilter") || 822 key.startsWith("jdk.") || 823 key.startsWith("keystore.type") || 824 key.startsWith("krb5.kdc.bad.policy") || 825 key.startsWith("login.config") || 826 key.startsWith("networkaddress.cache.") || 827 key.startsWith("ocsp.") || 828 key.startsWith("package.") || 829 key.startsWith("policy.") || 830 key.startsWith("securerandom.") || 831 key.startsWith("security.") || 832 key.startsWith("ssl.") || 833 key.startsWith("sun.rmi."); 834 } 835 836 /* 837 * Implementation detail: If the property we just set in 838 * setProperty() was either "package.access" or 839 * "package.definition", we need to signal to the SecurityManager 840 * class that the value has just changed, and that it should 841 * invalidate it's local cache values. 842 */ 843 private static void invalidateSMCache(String key) { 844 845 final boolean pa = key.equals("package.access"); 846 final boolean pd = key.equals("package.definition"); 847 848 if (pa || pd) { 849 SharedSecrets.getJavaLangAccess().invalidatePackageAccessCache(); 850 } 851 } 852 853 private static void check(String directive) { 854 SecurityManager security = System.getSecurityManager(); 855 if (security != null) { 856 security.checkSecurityAccess(directive); 857 } 858 } 859 860 private static void checkInsertProvider(String name) { 861 SecurityManager security = System.getSecurityManager(); 862 if (security != null) { 863 try { 864 security.checkSecurityAccess("insertProvider"); 865 } catch (SecurityException se1) { 866 try { 867 security.checkSecurityAccess("insertProvider." + name); 868 } catch (SecurityException se2) { 869 // throw first exception, but add second to suppressed 870 se1.addSuppressed(se2); 871 throw se1; 872 } 873 } 874 } 875 } 876 877 /* 878 * Returns all providers who satisfy the specified 879 * criterion. 880 */ 881 private static LinkedHashSet<Provider> getAllQualifyingCandidates( 882 String filterKey, 883 String filterValue, 884 Provider[] allProviders) { 885 String[] filterComponents = getFilterComponents(filterKey, 886 filterValue); 887 888 // The first component is the service name. 889 // The second is the algorithm name. 890 // If the third isn't null, that is the attrinute name. 891 String serviceName = filterComponents[0]; 892 String algName = filterComponents[1]; 893 String attrName = filterComponents[2]; 894 895 return getProvidersNotUsingCache(serviceName, algName, attrName, 896 filterValue, allProviders); 897 } 898 899 private static LinkedHashSet<Provider> getProvidersNotUsingCache( 900 String serviceName, 901 String algName, 902 String attrName, 903 String filterValue, 904 Provider[] allProviders) { 905 LinkedHashSet<Provider> candidates = new LinkedHashSet<>(5); 906 for (int i = 0; i < allProviders.length; i++) { 907 if (isCriterionSatisfied(allProviders[i], serviceName, 908 algName, 909 attrName, filterValue)) { 910 candidates.add(allProviders[i]); 911 } 912 } 913 return candidates; 914 } 915 916 /* 917 * Returns true if the given provider satisfies 918 * the selection criterion key:value. 919 */ 920 private static boolean isCriterionSatisfied(Provider prov, 921 String serviceName, 922 String algName, 923 String attrName, 924 String filterValue) { 925 String key = serviceName + '.' + algName; 926 927 if (attrName != null) { 928 key += ' ' + attrName; 929 } 930 // Check whether the provider has a property 931 // whose key is the same as the given key. 932 String propValue = getProviderProperty(key, prov); 933 934 if (propValue == null) { 935 // Check whether we have an alias instead 936 // of a standard name in the key. 937 String standardName = getProviderProperty("Alg.Alias." + 938 serviceName + "." + 939 algName, 940 prov); 941 if (standardName != null) { 942 key = serviceName + "." + standardName; 943 944 if (attrName != null) { 945 key += ' ' + attrName; 946 } 947 948 propValue = getProviderProperty(key, prov); 949 } 950 951 if (propValue == null) { 952 // The provider doesn't have the given 953 // key in its property list. 954 return false; 955 } 956 } 957 958 // If the key is in the format of: 959 // <crypto_service>.<algorithm_or_type>, 960 // there is no need to check the value. 961 962 if (attrName == null) { 963 return true; 964 } 965 966 // If we get here, the key must be in the 967 // format of <crypto_service>.<algorithm_or_provider> <attribute_name>. 968 if (isStandardAttr(attrName)) { 969 return isConstraintSatisfied(attrName, filterValue, propValue); 970 } else { 971 return filterValue.equalsIgnoreCase(propValue); 972 } 973 } 974 975 /* 976 * Returns true if the attribute is a standard attribute; 977 * otherwise, returns false. 978 */ 979 private static boolean isStandardAttr(String attribute) { 980 // For now, we just have two standard attributes: 981 // KeySize and ImplementedIn. 982 if (attribute.equalsIgnoreCase("KeySize")) 983 return true; 984 985 if (attribute.equalsIgnoreCase("ImplementedIn")) 986 return true; 987 988 return false; 989 } 990 991 /* 992 * Returns true if the requested attribute value is supported; 993 * otherwise, returns false. 994 */ 995 private static boolean isConstraintSatisfied(String attribute, 996 String value, 997 String prop) { 998 // For KeySize, prop is the max key size the 999 // provider supports for a specific <crypto_service>.<algorithm>. 1000 if (attribute.equalsIgnoreCase("KeySize")) { 1001 int requestedSize = Integer.parseInt(value); 1002 int maxSize = Integer.parseInt(prop); 1003 if (requestedSize <= maxSize) { 1004 return true; 1005 } else { 1006 return false; 1007 } 1008 } 1009 1010 // For Type, prop is the type of the implementation 1011 // for a specific <crypto service>.<algorithm>. 1012 if (attribute.equalsIgnoreCase("ImplementedIn")) { 1013 return value.equalsIgnoreCase(prop); 1014 } 1015 1016 return false; 1017 } 1018 1019 static String[] getFilterComponents(String filterKey, String filterValue) { 1020 int algIndex = filterKey.indexOf('.'); 1021 1022 if (algIndex < 0) { 1023 // There must be a dot in the filter, and the dot 1024 // shouldn't be at the beginning of this string. 1025 throw new InvalidParameterException("Invalid filter"); 1026 } 1027 1028 String serviceName = filterKey.substring(0, algIndex); 1029 String algName = null; 1030 String attrName = null; 1031 1032 if (filterValue.length() == 0) { 1033 // The filterValue is an empty string. So the filterKey 1034 // should be in the format of <crypto_service>.<algorithm_or_type>. 1035 algName = filterKey.substring(algIndex + 1).trim(); 1036 if (algName.length() == 0) { 1037 // There must be a algorithm or type name. 1038 throw new InvalidParameterException("Invalid filter"); 1039 } 1040 } else { 1041 // The filterValue is a non-empty string. So the filterKey must be 1042 // in the format of 1043 // <crypto_service>.<algorithm_or_type> <attribute_name> 1044 int attrIndex = filterKey.indexOf(' '); 1045 1046 if (attrIndex == -1) { 1047 // There is no attribute name in the filter. 1048 throw new InvalidParameterException("Invalid filter"); 1049 } else { 1050 attrName = filterKey.substring(attrIndex + 1).trim(); 1051 if (attrName.length() == 0) { 1052 // There is no attribute name in the filter. 1053 throw new InvalidParameterException("Invalid filter"); 1054 } 1055 } 1056 1057 // There must be an algorithm name in the filter. 1058 if ((attrIndex < algIndex) || 1059 (algIndex == attrIndex - 1)) { 1060 throw new InvalidParameterException("Invalid filter"); 1061 } else { 1062 algName = filterKey.substring(algIndex + 1, attrIndex); 1063 } 1064 } 1065 1066 String[] result = new String[3]; 1067 result[0] = serviceName; 1068 result[1] = algName; 1069 result[2] = attrName; 1070 1071 return result; 1072 } 1073 1074 /** 1075 * Returns a Set of Strings containing the names of all available 1076 * algorithms or types for the specified Java cryptographic service 1077 * (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore). Returns 1078 * an empty Set if there is no provider that supports the 1079 * specified service or if serviceName is null. For a complete list 1080 * of Java cryptographic services, please see the 1081 * {@extLink security_guide_jca 1082 * Java Cryptography Architecture (JCA) Reference Guide}. 1083 * Note: the returned set is immutable. 1084 * 1085 * @param serviceName the name of the Java cryptographic 1086 * service (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore). 1087 * Note: this parameter is case-insensitive. 1088 * 1089 * @return a Set of Strings containing the names of all available 1090 * algorithms or types for the specified Java cryptographic service 1091 * or an empty set if no provider supports the specified service. 1092 * 1093 * @since 1.4 1094 **/ 1095 public static Set<String> getAlgorithms(String serviceName) { 1096 1097 if ((serviceName == null) || (serviceName.length() == 0) || 1098 (serviceName.endsWith("."))) { 1099 return Collections.emptySet(); 1100 } 1101 1102 HashSet<String> result = new HashSet<>(); 1103 Provider[] providers = Security.getProviders(); 1104 1105 for (int i = 0; i < providers.length; i++) { 1106 // Check the keys for each provider. 1107 for (Enumeration<Object> e = providers[i].keys(); 1108 e.hasMoreElements(); ) { 1109 String currentKey = 1110 ((String)e.nextElement()).toUpperCase(Locale.ENGLISH); 1111 if (currentKey.startsWith( 1112 serviceName.toUpperCase(Locale.ENGLISH))) { 1113 // We should skip the currentKey if it contains a 1114 // whitespace. The reason is: such an entry in the 1115 // provider property contains attributes for the 1116 // implementation of an algorithm. We are only interested 1117 // in entries which lead to the implementation 1118 // classes. 1119 if (currentKey.indexOf(' ') < 0) { 1120 result.add(currentKey.substring( 1121 serviceName.length() + 1)); 1122 } 1123 } 1124 } 1125 } 1126 return Collections.unmodifiableSet(result); 1127 } 1128 }