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