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