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