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