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