1 /* 2 * Copyright (c) 1996, 2019, 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.io.*; 29 import java.util.*; 30 import static java.util.Locale.ENGLISH; 31 import java.lang.ref.*; 32 import java.lang.reflect.*; 33 import java.util.function.BiConsumer; 34 import java.util.function.BiFunction; 35 import java.util.function.Function; 36 import java.util.concurrent.ConcurrentHashMap; 37 38 /** 39 * This class represents a "provider" for the 40 * Java Security API, where a provider implements some or all parts of 41 * Java Security. Services that a provider may implement include: 42 * 43 * <ul> 44 * 45 * <li>Algorithms (such as DSA, RSA, or SHA-256). 46 * 47 * <li>Key generation, conversion, and management facilities (such as for 48 * algorithm-specific keys). 49 * 50 * </ul> 51 * 52 * <p>Some provider implementations may encounter unrecoverable internal 53 * errors during their operation, for example a failure to communicate with a 54 * security token. A {@link ProviderException} should be used to indicate 55 * such errors. 56 * 57 * <p>Please note that a provider can be used to implement any security 58 * service in Java that uses a pluggable architecture with a choice 59 * of implementations that fit underneath. 60 * 61 * <p>The service type {@code Provider} is reserved for use by the 62 * security framework. Services of this type cannot be added, removed, 63 * or modified by applications. 64 * The following attributes are automatically placed in each Provider object: 65 * <table class="striped"> 66 * <caption><b>Attributes Automatically Placed in a Provider Object</b></caption> 67 * <thead> 68 * <tr><th scope="col">Name</th><th scope="col">Value</th> 69 * </thead> 70 * <tbody style="text-align:left"> 71 * <tr><th scope="row">{@code Provider.id name}</th> 72 * <td>{@code String.valueOf(provider.getName())}</td> 73 * <tr><th scope="row">{@code Provider.id version}</th> 74 * <td>{@code String.valueOf(provider.getVersionStr())}</td> 75 * <tr><th scope="row">{@code Provider.id info}</th> 76 * <td>{@code String.valueOf(provider.getInfo())}</td> 77 * <tr><th scope="row">{@code Provider.id className}</th> 78 * <td>{@code provider.getClass().getName()}</td> 79 * </tbody> 80 * </table> 81 * 82 * <p>Each provider has a name and a version string. A provider normally 83 * identifies itself with a file named {@code java.security.Provider} 84 * in the resource directory {@code META-INF/services}. 85 * Security providers are looked up via the {@link ServiceLoader} mechanism 86 * using the {@link ClassLoader#getSystemClassLoader application class loader}. 87 * 88 * <p>Providers may be configured such that they are automatically 89 * installed and made available at runtime via the 90 * {@link Security#getProviders() Security.getProviders()} method. 91 * The mechanism for configuring and installing security providers is 92 * implementation-specific. 93 * 94 * @implNote 95 * The JDK implementation supports static registration of the security 96 * providers via the {@code conf/security/java.security} file in the Java 97 * installation directory. These providers are automatically installed by 98 * the JDK runtime, see {@extLink security_guide_jca_provider 99 * The Provider Class} 100 * in the Java Cryptography Architecture (JCA) Reference Guide 101 * for information about how a particular type of provider, the cryptographic 102 * service provider, works and is installed. 103 * 104 * @author Benjamin Renaud 105 * @author Andreas Sterbenz 106 * @since 1.1 107 */ 108 public abstract class Provider extends Properties { 109 110 // Declare serialVersionUID to be compatible with JDK1.1 111 @java.io.Serial 112 private static final long serialVersionUID = -4298000515446427739L; 113 114 private static final sun.security.util.Debug debug = 115 sun.security.util.Debug.getInstance("provider", "Provider"); 116 117 /** 118 * The provider name. 119 * 120 * @serial 121 */ 122 private String name; 123 124 /** 125 * A description of the provider and its services. 126 * 127 * @serial 128 */ 129 private String info; 130 131 /** 132 * The provider version number. 133 * 134 * @serial 135 */ 136 private double version; 137 138 /** 139 * The provider version string. 140 * 141 * @serial 142 */ 143 private String versionStr; 144 145 private transient Set<Map.Entry<Object,Object>> entrySet = null; 146 private transient int entrySetCallCount = 0; 147 148 private transient boolean initialized; 149 150 private static Object newInstanceUtil(final Class<?> clazz, 151 final Class<?> ctrParamClz, final Object ctorParamObj) 152 throws Exception { 153 if (ctrParamClz == null) { 154 Constructor<?> con = clazz.getConstructor(); 155 return con.newInstance(); 156 } else { 157 // Looking for the constructor with a params first and fallback 158 // to one without if not found. This is to support the enhanced 159 // SecureRandom where both styles of constructors are supported. 160 // Before jdk9, there was no params support (only getInstance(alg)) 161 // and an impl only had the params-less constructor. Since jdk9, 162 // there is getInstance(alg,params) and an impl can contain 163 // an Impl(params) constructor. 164 try { 165 Constructor<?> con = clazz.getConstructor(ctrParamClz); 166 return con.newInstance(ctorParamObj); 167 } catch (NoSuchMethodException nsme) { 168 // For pre-jdk9 SecureRandom implementations, they only 169 // have params-less constructors which still works when 170 // the input ctorParamObj is null. 171 // 172 // For other primitives using params, ctorParamObj should not 173 // be null and nsme is thrown, just like before. 174 if (ctorParamObj == null) { 175 try { 176 Constructor<?> con = clazz.getConstructor(); 177 return con.newInstance(); 178 } catch (NoSuchMethodException nsme2) { 179 nsme.addSuppressed(nsme2); 180 throw nsme; 181 } 182 } else { 183 throw nsme; 184 } 185 } 186 } 187 } 188 189 private static double parseVersionStr(String s) { 190 try { 191 int firstDotIdx = s.indexOf('.'); 192 int nextDotIdx = s.indexOf('.', firstDotIdx + 1); 193 if (nextDotIdx != -1) { 194 s = s.substring(0, nextDotIdx); 195 } 196 int endIdx = s.indexOf('-'); 197 if (endIdx > 0) { 198 s = s.substring(0, endIdx); 199 } 200 endIdx = s.indexOf('+'); 201 if (endIdx > 0) { 202 s = s.substring(0, endIdx); 203 } 204 return Double.parseDouble(s); 205 } catch (NullPointerException | NumberFormatException e) { 206 return 0d; 207 } 208 } 209 210 /** 211 * Constructs a provider with the specified name, version number, 212 * and information. Calling this constructor is equivalent to call the 213 * {@link #Provider(String, String, String)} with {@code name} 214 * name, {@code Double.toString(version)}, and {@code info}. 215 * 216 * @param name the provider name. 217 * 218 * @param version the provider version number. 219 * 220 * @param info a description of the provider and its services. 221 * 222 * @deprecated use {@link #Provider(String, String, String)} instead. 223 */ 224 @Deprecated(since="9") 225 protected Provider(String name, double version, String info) { 226 this.name = name; 227 this.version = version; 228 this.versionStr = Double.toString(version); 229 this.info = info; 230 this.serviceMap = new ConcurrentHashMap<>(); 231 putId(); 232 initialized = true; 233 } 234 235 /** 236 * Constructs a provider with the specified name, version string, 237 * and information. 238 * 239 * <p>The version string contains a version number optionally followed 240 * by other information separated by one of the characters of '+', '-'. 241 * 242 * The format for the version number is: 243 * 244 * <blockquote><pre> 245 * ^[0-9]+(\.[0-9]+)* 246 * </pre></blockquote> 247 * 248 * <p>In order to return the version number in a double, when there are 249 * more than two components (separated by '.' as defined above), only 250 * the first two components are retained. The resulting string is then 251 * passed to {@link Double#valueOf(String)} to generate version number, 252 * i.e. {@link #getVersion}. 253 * <p>If the conversion failed, value 0 will be used. 254 * 255 * @param name the provider name. 256 * 257 * @param versionStr the provider version string. 258 * 259 * @param info a description of the provider and its services. 260 * 261 * @since 9 262 */ 263 protected Provider(String name, String versionStr, String info) { 264 this.name = name; 265 this.versionStr = versionStr; 266 this.version = parseVersionStr(versionStr); 267 this.info = info; 268 this.serviceMap = new ConcurrentHashMap<>(); 269 putId(); 270 initialized = true; 271 } 272 273 /** 274 * Apply the supplied configuration argument to this provider instance 275 * and return the configured provider. Note that if this provider cannot 276 * be configured in-place, a new provider will be created and returned. 277 * Therefore, callers should always use the returned provider. 278 * 279 * @implSpec 280 * The default implementation throws {@code UnsupportedOperationException}. 281 * Subclasses should override this method only if a configuration argument 282 * is supported. 283 * 284 * @param configArg the configuration information for configuring this 285 * provider. 286 * 287 * @throws UnsupportedOperationException if a configuration argument is 288 * not supported. 289 * @throws NullPointerException if the supplied configuration argument is 290 null. 291 * @throws InvalidParameterException if the supplied configuration argument 292 * is invalid. 293 * @return a provider configured with the supplied configuration argument. 294 * 295 * @since 9 296 */ 297 public Provider configure(String configArg) { 298 throw new UnsupportedOperationException("configure is not supported"); 299 } 300 301 /** 302 * Check if this provider instance has been configured. 303 * 304 * @implSpec 305 * The default implementation returns true. 306 * Subclasses should override this method if the provider instance requires 307 * an explicit {@code configure} call after being constructed. 308 * 309 * @return true if no further configuration is needed, false otherwise. 310 * 311 * @since 9 312 */ 313 public boolean isConfigured() { 314 return true; 315 } 316 317 318 /** 319 * Returns the name of this provider. 320 * 321 * @return the name of this provider. 322 */ 323 public String getName() { 324 return name; 325 } 326 327 /** 328 * Returns the version number for this provider. 329 * 330 * @return the version number for this provider. 331 * 332 * @deprecated use {@link #getVersionStr} instead. 333 */ 334 @Deprecated(since="9") 335 public double getVersion() { 336 return version; 337 } 338 339 /** 340 * Returns the version string for this provider. 341 * 342 * @return the version string for this provider. 343 * 344 * @since 9 345 */ 346 public String getVersionStr() { 347 return versionStr; 348 } 349 350 /** 351 * Returns a human-readable description of the provider and its 352 * services. This may return an HTML page, with relevant links. 353 * 354 * @return a description of the provider and its services. 355 */ 356 public String getInfo() { 357 return info; 358 } 359 360 /** 361 * Returns a string with the name and the version string 362 * of this provider. 363 * 364 * @return the string with the name and the version string 365 * for this provider. 366 */ 367 public String toString() { 368 return name + " version " + versionStr; 369 } 370 371 /* 372 * override the following methods to ensure that provider 373 * information can only be changed if the caller has the appropriate 374 * permissions. 375 */ 376 377 /** 378 * Clears this provider so that it no longer contains the properties 379 * used to look up facilities implemented by the provider. 380 * 381 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 382 * method is called with the string {@code "clearProviderProperties."+name} 383 * (where {@code name} is the provider name) to see if it's ok to clear 384 * this provider. 385 * 386 * @throws SecurityException 387 * if a security manager exists and its {@link 388 * java.lang.SecurityManager#checkSecurityAccess} method 389 * denies access to clear this provider 390 * 391 * @since 1.2 392 */ 393 @Override 394 public synchronized void clear() { 395 check("clearProviderProperties."+name); 396 if (debug != null) { 397 debug.println("Remove " + name + " provider properties"); 398 } 399 implClear(); 400 } 401 402 /** 403 * Reads a property list (key and element pairs) from the input stream. 404 * 405 * @param inStream the input stream. 406 * @exception IOException if an error occurred when reading from the 407 * input stream. 408 * @see java.util.Properties#load 409 */ 410 @Override 411 public synchronized void load(InputStream inStream) throws IOException { 412 check("putProviderProperty."+name); 413 if (debug != null) { 414 debug.println("Load " + name + " provider properties"); 415 } 416 Properties tempProperties = new Properties(); 417 tempProperties.load(inStream); 418 implPutAll(tempProperties); 419 } 420 421 /** 422 * Copies all of the mappings from the specified Map to this provider. 423 * These mappings will replace any properties that this provider had 424 * for any of the keys currently in the specified Map. 425 * 426 * @since 1.2 427 */ 428 @Override 429 public synchronized void putAll(Map<?,?> t) { 430 check("putProviderProperty."+name); 431 if (debug != null) { 432 debug.println("Put all " + name + " provider properties"); 433 } 434 implPutAll(t); 435 } 436 437 /** 438 * Returns an unmodifiable Set view of the property entries contained 439 * in this Provider. 440 * 441 * @see java.util.Map.Entry 442 * @since 1.2 443 */ 444 @Override 445 public synchronized Set<Map.Entry<Object,Object>> entrySet() { 446 checkInitialized(); 447 if (entrySet == null) { 448 if (entrySetCallCount++ == 0) // Initial call 449 entrySet = Collections.unmodifiableMap(this).entrySet(); 450 else 451 return super.entrySet(); // Recursive call 452 } 453 454 // This exception will be thrown if the implementation of 455 // Collections.unmodifiableMap.entrySet() is changed such that it 456 // no longer calls entrySet() on the backing Map. (Provider's 457 // entrySet implementation depends on this "implementation detail", 458 // which is unlikely to change. 459 if (entrySetCallCount != 2) 460 throw new RuntimeException("Internal error."); 461 462 return entrySet; 463 } 464 465 /** 466 * Returns an unmodifiable Set view of the property keys contained in 467 * this provider. 468 * 469 * @since 1.2 470 */ 471 @Override 472 public Set<Object> keySet() { 473 checkInitialized(); 474 return Collections.unmodifiableSet(super.keySet()); 475 } 476 477 /** 478 * Returns an unmodifiable Collection view of the property values 479 * contained in this provider. 480 * 481 * @since 1.2 482 */ 483 @Override 484 public Collection<Object> values() { 485 checkInitialized(); 486 return Collections.unmodifiableCollection(super.values()); 487 } 488 489 /** 490 * Sets the {@code key} property to have the specified 491 * {@code value}. 492 * 493 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 494 * method is called with the string {@code "putProviderProperty."+name}, 495 * where {@code name} is the provider name, to see if it's ok to set this 496 * provider's property values. 497 * 498 * @throws SecurityException 499 * if a security manager exists and its {@link 500 * java.lang.SecurityManager#checkSecurityAccess} method 501 * denies access to set property values. 502 * 503 * @since 1.2 504 */ 505 @Override 506 public synchronized Object put(Object key, Object value) { 507 check("putProviderProperty."+name); 508 if (debug != null) { 509 debug.println("Set " + name + " provider property [" + 510 key + "/" + value +"]"); 511 } 512 return implPut(key, value); 513 } 514 515 /** 516 * If the specified key is not already associated with a value (or is mapped 517 * to {@code null}) associates it with the given value and returns 518 * {@code null}, else returns the current value. 519 * 520 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 521 * method is called with the string {@code "putProviderProperty."+name}, 522 * where {@code name} is the provider name, to see if it's ok to set this 523 * provider's property values. 524 * 525 * @throws SecurityException 526 * if a security manager exists and its {@link 527 * java.lang.SecurityManager#checkSecurityAccess} method 528 * denies access to set property values. 529 * 530 * @since 1.8 531 */ 532 @Override 533 public synchronized Object putIfAbsent(Object key, Object value) { 534 check("putProviderProperty."+name); 535 if (debug != null) { 536 debug.println("Set " + name + " provider property [" + 537 key + "/" + value +"]"); 538 } 539 return implPutIfAbsent(key, value); 540 } 541 542 /** 543 * Removes the {@code key} property (and its corresponding 544 * {@code value}). 545 * 546 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 547 * method is called with the string {@code "removeProviderProperty."+name}, 548 * where {@code name} is the provider name, to see if it's ok to remove this 549 * provider's properties. 550 * 551 * @throws SecurityException 552 * if a security manager exists and its {@link 553 * java.lang.SecurityManager#checkSecurityAccess} method 554 * denies access to remove this provider's properties. 555 * 556 * @since 1.2 557 */ 558 @Override 559 public synchronized Object remove(Object key) { 560 check("removeProviderProperty."+name); 561 if (debug != null) { 562 debug.println("Remove " + name + " provider property " + key); 563 } 564 return implRemove(key); 565 } 566 567 /** 568 * Removes the entry for the specified key only if it is currently 569 * mapped to the specified value. 570 * 571 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 572 * method is called with the string {@code "removeProviderProperty."+name}, 573 * where {@code name} is the provider name, to see if it's ok to remove this 574 * provider's properties. 575 * 576 * @throws SecurityException 577 * if a security manager exists and its {@link 578 * java.lang.SecurityManager#checkSecurityAccess} method 579 * denies access to remove this provider's properties. 580 * 581 * @since 1.8 582 */ 583 @Override 584 public synchronized boolean remove(Object key, Object value) { 585 check("removeProviderProperty."+name); 586 if (debug != null) { 587 debug.println("Remove " + name + " provider property " + key); 588 } 589 return implRemove(key, value); 590 } 591 592 /** 593 * Replaces the entry for the specified key only if currently 594 * mapped to the specified value. 595 * 596 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 597 * method is called with the string {@code "putProviderProperty."+name}, 598 * where {@code name} is the provider name, to see if it's ok to set this 599 * provider's property values. 600 * 601 * @throws SecurityException 602 * if a security manager exists and its {@link 603 * java.lang.SecurityManager#checkSecurityAccess} method 604 * denies access to set property values. 605 * 606 * @since 1.8 607 */ 608 @Override 609 public synchronized boolean replace(Object key, Object oldValue, 610 Object newValue) { 611 check("putProviderProperty." + name); 612 613 if (debug != null) { 614 debug.println("Replace " + name + " provider property " + key); 615 } 616 return implReplace(key, oldValue, newValue); 617 } 618 619 /** 620 * Replaces the entry for the specified key only if it is 621 * currently mapped to some value. 622 * 623 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 624 * method is called with the string {@code "putProviderProperty."+name}, 625 * where {@code name} is the provider name, to see if it's ok to set this 626 * provider's property values. 627 * 628 * @throws SecurityException 629 * if a security manager exists and its {@link 630 * java.lang.SecurityManager#checkSecurityAccess} method 631 * denies access to set property values. 632 * 633 * @since 1.8 634 */ 635 @Override 636 public synchronized Object replace(Object key, Object value) { 637 check("putProviderProperty." + name); 638 639 if (debug != null) { 640 debug.println("Replace " + name + " provider property " + key); 641 } 642 return implReplace(key, value); 643 } 644 645 /** 646 * Replaces each entry's value with the result of invoking the given 647 * function on that entry, in the order entries are returned by an entry 648 * set iterator, until all entries have been processed or the function 649 * throws an exception. 650 * 651 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 652 * method is called with the string {@code "putProviderProperty."+name}, 653 * where {@code name} is the provider name, to see if it's ok to set this 654 * provider's property values. 655 * 656 * @throws SecurityException 657 * if a security manager exists and its {@link 658 * java.lang.SecurityManager#checkSecurityAccess} method 659 * denies access to set property values. 660 * 661 * @since 1.8 662 */ 663 @Override 664 public synchronized void replaceAll(BiFunction<? super Object, 665 ? super Object, ? extends Object> function) { 666 check("putProviderProperty." + name); 667 668 if (debug != null) { 669 debug.println("ReplaceAll " + name + " provider property "); 670 } 671 implReplaceAll(function); 672 } 673 674 /** 675 * Attempts to compute a mapping for the specified key and its 676 * current mapped value (or {@code null} if there is no current 677 * mapping). 678 * 679 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 680 * method is called with the strings {@code "putProviderProperty."+name} 681 * and {@code "removeProviderProperty."+name}, where {@code name} is the 682 * provider name, to see if it's ok to set this provider's property values 683 * and remove this provider's properties. 684 * 685 * @throws SecurityException 686 * if a security manager exists and its {@link 687 * java.lang.SecurityManager#checkSecurityAccess} method 688 * denies access to set property values or remove properties. 689 * 690 * @since 1.8 691 */ 692 @Override 693 public synchronized Object compute(Object key, BiFunction<? super Object, 694 ? super Object, ? extends Object> remappingFunction) { 695 check("putProviderProperty." + name); 696 check("removeProviderProperty." + name); 697 698 if (debug != null) { 699 debug.println("Compute " + name + " provider property " + key); 700 } 701 return implCompute(key, remappingFunction); 702 } 703 704 /** 705 * If the specified key is not already associated with a value (or 706 * is mapped to {@code null}), attempts to compute its value using 707 * the given mapping function and enters it into this map unless 708 * {@code null}. 709 * 710 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 711 * method is called with the strings {@code "putProviderProperty."+name} 712 * and {@code "removeProviderProperty."+name}, where {@code name} is the 713 * provider name, to see if it's ok to set this provider's property values 714 * and remove this provider's properties. 715 * 716 * @throws SecurityException 717 * if a security manager exists and its {@link 718 * java.lang.SecurityManager#checkSecurityAccess} method 719 * denies access to set property values and remove properties. 720 * 721 * @since 1.8 722 */ 723 @Override 724 public synchronized Object computeIfAbsent(Object key, Function<? super Object, 725 ? extends Object> mappingFunction) { 726 check("putProviderProperty." + name); 727 check("removeProviderProperty." + name); 728 729 if (debug != null) { 730 debug.println("ComputeIfAbsent " + name + " provider property " + 731 key); 732 } 733 return implComputeIfAbsent(key, mappingFunction); 734 } 735 736 /** 737 * If the value for the specified key is present and non-null, attempts to 738 * compute a new mapping given the key and its current mapped value. 739 * 740 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 741 * method is called with the strings {@code "putProviderProperty."+name} 742 * and {@code "removeProviderProperty."+name}, where {@code name} is the 743 * provider name, to see if it's ok to set this provider's property values 744 * and remove this provider's properties. 745 * 746 * @throws SecurityException 747 * if a security manager exists and its {@link 748 * java.lang.SecurityManager#checkSecurityAccess} method 749 * denies access to set property values or remove properties. 750 * 751 * @since 1.8 752 */ 753 @Override 754 public synchronized Object computeIfPresent(Object key, BiFunction<? super Object, 755 ? super Object, ? extends Object> remappingFunction) { 756 check("putProviderProperty." + name); 757 check("removeProviderProperty." + name); 758 759 if (debug != null) { 760 debug.println("ComputeIfPresent " + name + " provider property " + 761 key); 762 } 763 return implComputeIfPresent(key, remappingFunction); 764 } 765 766 /** 767 * If the specified key is not already associated with a value or is 768 * associated with null, associates it with the given value. Otherwise, 769 * replaces the value with the results of the given remapping function, 770 * or removes if the result is null. This method may be of use when 771 * combining multiple mapped values for a key. 772 * 773 * <p>If a security manager is enabled, its {@code checkSecurityAccess} 774 * method is called with the strings {@code "putProviderProperty."+name} 775 * and {@code "removeProviderProperty."+name}, where {@code name} is the 776 * provider name, to see if it's ok to set this provider's property values 777 * and remove this provider's properties. 778 * 779 * @throws SecurityException 780 * if a security manager exists and its {@link 781 * java.lang.SecurityManager#checkSecurityAccess} method 782 * denies access to set property values or remove properties. 783 * 784 * @since 1.8 785 */ 786 @Override 787 public synchronized Object merge(Object key, Object value, BiFunction<? super Object, 788 ? super Object, ? extends Object> remappingFunction) { 789 check("putProviderProperty." + name); 790 check("removeProviderProperty." + name); 791 792 if (debug != null) { 793 debug.println("Merge " + name + " provider property " + key); 794 } 795 return implMerge(key, value, remappingFunction); 796 } 797 798 // let javadoc show doc from superclass 799 @Override 800 public Object get(Object key) { 801 checkInitialized(); 802 return super.get(key); 803 } 804 /** 805 * @since 1.8 806 */ 807 @Override 808 public synchronized Object getOrDefault(Object key, Object defaultValue) { 809 checkInitialized(); 810 return super.getOrDefault(key, defaultValue); 811 } 812 813 /** 814 * @since 1.8 815 */ 816 @Override 817 public synchronized void forEach(BiConsumer<? super Object, ? super Object> action) { 818 checkInitialized(); 819 super.forEach(action); 820 } 821 822 // let javadoc show doc from superclass 823 @Override 824 public Enumeration<Object> keys() { 825 checkInitialized(); 826 return super.keys(); 827 } 828 829 // let javadoc show doc from superclass 830 @Override 831 public Enumeration<Object> elements() { 832 checkInitialized(); 833 return super.elements(); 834 } 835 836 // let javadoc show doc from superclass 837 public String getProperty(String key) { 838 checkInitialized(); 839 return super.getProperty(key); 840 } 841 842 private void checkInitialized() { 843 if (!initialized) { 844 throw new IllegalStateException(); 845 } 846 } 847 848 private void check(String directive) { 849 checkInitialized(); 850 SecurityManager security = System.getSecurityManager(); 851 if (security != null) { 852 security.checkSecurityAccess(directive); 853 } 854 } 855 856 // legacy properties changed since last call to any services method? 857 private transient boolean legacyChanged; 858 // serviceMap changed since last call to getServices() 859 private volatile transient boolean servicesChanged; 860 861 // Map<ServiceKey,Service> 862 // used for services added via putService(), initialized on demand 863 private transient Map<ServiceKey,Service> serviceMap; 864 865 // Map<ServiceKey,Service> 866 // used for services added via legacy methods, init on demand 867 private transient Map<ServiceKey,Service> legacyMap; 868 869 // Set<Service> 870 // Unmodifiable set of all services. Initialized on demand. 871 private transient Set<Service> serviceSet; 872 873 // register the id attributes for this provider 874 // this is to ensure that equals() and hashCode() do not incorrectly 875 // report to different provider objects as the same 876 private void putId() { 877 // note: name and info may be null 878 super.put("Provider.id name", String.valueOf(name)); 879 super.put("Provider.id version", String.valueOf(versionStr)); 880 super.put("Provider.id info", String.valueOf(info)); 881 super.put("Provider.id className", this.getClass().getName()); 882 } 883 884 /** 885 * Reads the {@code ObjectInputStream} for the default serializable fields. 886 * If the serialized field {@code versionStr} is found in the STREAM FIELDS, 887 * its String value will be used to populate both the version string and 888 * version number. If {@code versionStr} is not found, but {@code version} 889 * is, then its double value will be used to populate both fields. 890 * 891 * @param in the {@code ObjectInputStream} to read 892 * @serial 893 */ 894 @java.io.Serial 895 private void readObject(ObjectInputStream in) 896 throws IOException, ClassNotFoundException { 897 Map<Object,Object> copy = new HashMap<>(); 898 for (Map.Entry<Object,Object> entry : super.entrySet()) { 899 copy.put(entry.getKey(), entry.getValue()); 900 } 901 defaults = null; 902 in.defaultReadObject(); 903 if (this.versionStr == null) { 904 // set versionStr based on version when not found in serialized bytes 905 this.versionStr = Double.toString(this.version); 906 } else { 907 // otherwise, set version based on versionStr 908 this.version = parseVersionStr(this.versionStr); 909 } 910 this.serviceMap = new ConcurrentHashMap<>(); 911 implClear(); 912 initialized = true; 913 putAll(copy); 914 } 915 916 private static boolean isProviderInfo(Object key) { 917 String keyString = (String)key; 918 if (keyString.startsWith("Provider.")) { 919 return true; 920 } 921 return false; 922 } 923 924 /** 925 * Copies all of the mappings from the specified Map to this provider. 926 * Internal method to be called AFTER the security check has been 927 * performed. 928 */ 929 private void implPutAll(Map<?,?> t) { 930 for (Map.Entry<?,?> e : t.entrySet()) { 931 implPut(e.getKey(), e.getValue()); 932 } 933 } 934 935 private Object implRemove(Object key) { 936 if (key instanceof String) { 937 if (isProviderInfo(key)) { 938 return null; 939 } 940 legacyChanged = true; 941 } 942 return super.remove(key); 943 } 944 945 private boolean implRemove(Object key, Object value) { 946 if (key instanceof String && value instanceof String) { 947 if (isProviderInfo(key)) { 948 return false; 949 } 950 legacyChanged = true; 951 } 952 return super.remove(key, value); 953 } 954 955 private boolean implReplace(Object key, Object oldValue, Object newValue) { 956 if ((key instanceof String) && (oldValue instanceof String) && 957 (newValue instanceof String)) { 958 if (isProviderInfo(key)) { 959 return false; 960 } 961 legacyChanged = true; 962 } 963 return super.replace(key, oldValue, newValue); 964 } 965 966 private Object implReplace(Object key, Object value) { 967 if ((key instanceof String) && (value instanceof String)) { 968 if (isProviderInfo(key)) { 969 return null; 970 } 971 legacyChanged = true; 972 } 973 return super.replace(key, value); 974 } 975 976 @SuppressWarnings("unchecked") // Function must actually operate over strings 977 private void implReplaceAll(BiFunction<? super Object, ? super Object, 978 ? extends Object> function) { 979 legacyChanged = true; 980 super.replaceAll(function); 981 } 982 983 @SuppressWarnings("unchecked") // Function must actually operate over strings 984 private Object implMerge(Object key, Object value, BiFunction<? super Object, 985 ? super Object, ? extends Object> remappingFunction) { 986 if ((key instanceof String) && (value instanceof String)) { 987 if (isProviderInfo(key)) { 988 return null; 989 } 990 legacyChanged = true; 991 } 992 return super.merge(key, value, remappingFunction); 993 } 994 995 @SuppressWarnings("unchecked") // Function must actually operate over strings 996 private Object implCompute(Object key, BiFunction<? super Object, 997 ? super Object, ? extends Object> remappingFunction) { 998 if (key instanceof String) { 999 if (isProviderInfo(key)) { 1000 return null; 1001 } 1002 legacyChanged = true; 1003 } 1004 return super.compute(key, remappingFunction); 1005 } 1006 1007 @SuppressWarnings("unchecked") // Function must actually operate over strings 1008 private Object implComputeIfAbsent(Object key, Function<? super Object, 1009 ? extends Object> mappingFunction) { 1010 if (key instanceof String) { 1011 if (isProviderInfo(key)) { 1012 return null; 1013 } 1014 legacyChanged = true; 1015 } 1016 return super.computeIfAbsent(key, mappingFunction); 1017 } 1018 1019 @SuppressWarnings("unchecked") // Function must actually operate over strings 1020 private Object implComputeIfPresent(Object key, BiFunction<? super Object, 1021 ? super Object, ? extends Object> remappingFunction) { 1022 if (key instanceof String) { 1023 if (isProviderInfo(key)) { 1024 return null; 1025 } 1026 legacyChanged = true; 1027 } 1028 return super.computeIfPresent(key, remappingFunction); 1029 } 1030 1031 private Object implPut(Object key, Object value) { 1032 if ((key instanceof String) && (value instanceof String)) { 1033 if (isProviderInfo(key)) { 1034 return null; 1035 } 1036 legacyChanged = true; 1037 } 1038 return super.put(key, value); 1039 } 1040 1041 private Object implPutIfAbsent(Object key, Object value) { 1042 if ((key instanceof String) && (value instanceof String)) { 1043 if (isProviderInfo(key)) { 1044 return null; 1045 } 1046 legacyChanged = true; 1047 } 1048 return super.putIfAbsent(key, value); 1049 } 1050 1051 private void implClear() { 1052 if (legacyMap != null) { 1053 legacyMap.clear(); 1054 } 1055 serviceMap.clear(); 1056 legacyChanged = false; 1057 servicesChanged = false; 1058 serviceSet = null; 1059 super.clear(); 1060 putId(); 1061 } 1062 1063 // used as key in the serviceMap and legacyMap HashMaps 1064 private static class ServiceKey { 1065 private final String type; 1066 private final String algorithm; 1067 private final String originalAlgorithm; 1068 private ServiceKey(String type, String algorithm, boolean intern) { 1069 this.type = type; 1070 this.originalAlgorithm = algorithm; 1071 algorithm = algorithm.toUpperCase(ENGLISH); 1072 this.algorithm = intern ? algorithm.intern() : algorithm; 1073 } 1074 public int hashCode() { 1075 return Objects.hash(type, algorithm); 1076 } 1077 public boolean equals(Object obj) { 1078 if (this == obj) { 1079 return true; 1080 } 1081 if (!(obj instanceof ServiceKey)) { 1082 return false; 1083 } 1084 ServiceKey other = (ServiceKey)obj; 1085 return this.type.equals(other.type) 1086 && this.algorithm.equals(other.algorithm); 1087 } 1088 boolean matches(String type, String algorithm) { 1089 return (this.type == type) && (this.originalAlgorithm == algorithm); 1090 } 1091 } 1092 1093 /** 1094 * Ensure all the legacy String properties are fully parsed into 1095 * service objects. 1096 */ 1097 private void ensureLegacyParsed() { 1098 if (legacyChanged == false) { 1099 return; 1100 } 1101 serviceSet = null; 1102 if (legacyMap == null) { 1103 legacyMap = new ConcurrentHashMap<>(); 1104 } else { 1105 legacyMap.clear(); 1106 } 1107 for (Map.Entry<?,?> entry : super.entrySet()) { 1108 parseLegacyPut(entry.getKey(), entry.getValue()); 1109 } 1110 removeInvalidServices(legacyMap); 1111 legacyChanged = false; 1112 } 1113 1114 /** 1115 * Remove all invalid services from the Map. Invalid services can only 1116 * occur if the legacy properties are inconsistent or incomplete. 1117 */ 1118 private void removeInvalidServices(Map<ServiceKey,Service> map) { 1119 for (Iterator<Map.Entry<ServiceKey, Service>> t = 1120 map.entrySet().iterator(); t.hasNext(); ) { 1121 Service s = t.next().getValue(); 1122 if (s.isValid() == false) { 1123 t.remove(); 1124 } 1125 } 1126 } 1127 1128 private String[] getTypeAndAlgorithm(String key) { 1129 int i = key.indexOf('.'); 1130 if (i < 1) { 1131 if (debug != null) { 1132 debug.println("Ignoring invalid entry in provider " 1133 + name + ":" + key); 1134 } 1135 return null; 1136 } 1137 String type = key.substring(0, i); 1138 String alg = key.substring(i + 1); 1139 return new String[] {type, alg}; 1140 } 1141 1142 private static final String ALIAS_PREFIX = "Alg.Alias."; 1143 private static final String ALIAS_PREFIX_LOWER = "alg.alias."; 1144 private static final int ALIAS_LENGTH = ALIAS_PREFIX.length(); 1145 1146 private void parseLegacyPut(Object k, Object v) { 1147 if (!(k instanceof String) || !(v instanceof String)) { 1148 return; 1149 } 1150 String name = (String) k; 1151 String value = (String) v; 1152 if (isProviderInfo(name)) { 1153 return; 1154 } 1155 if (name.toLowerCase(ENGLISH).startsWith(ALIAS_PREFIX_LOWER)) { 1156 // e.g. put("Alg.Alias.MessageDigest.SHA", "SHA-1"); 1157 // aliasKey ~ MessageDigest.SHA 1158 String stdAlg = value; 1159 String aliasKey = name.substring(ALIAS_LENGTH); 1160 String[] typeAndAlg = getTypeAndAlgorithm(aliasKey); 1161 if (typeAndAlg == null) { 1162 return; 1163 } 1164 String type = getEngineName(typeAndAlg[0]); 1165 String aliasAlg = typeAndAlg[1].intern(); 1166 ServiceKey key = new ServiceKey(type, stdAlg, true); 1167 Service s = legacyMap.get(key); 1168 if (s == null) { 1169 s = new Service(this); 1170 s.type = type; 1171 s.algorithm = stdAlg; 1172 legacyMap.put(key, s); 1173 } 1174 legacyMap.put(new ServiceKey(type, aliasAlg, true), s); 1175 s.addAlias(aliasAlg); 1176 } else { 1177 String[] typeAndAlg = getTypeAndAlgorithm(name); 1178 if (typeAndAlg == null) { 1179 return; 1180 } 1181 int i = typeAndAlg[1].indexOf(' '); 1182 if (i == -1) { 1183 // e.g. put("MessageDigest.SHA-1", "sun.security.provider.SHA"); 1184 String type = getEngineName(typeAndAlg[0]); 1185 String stdAlg = typeAndAlg[1].intern(); 1186 String className = value; 1187 ServiceKey key = new ServiceKey(type, stdAlg, true); 1188 Service s = legacyMap.get(key); 1189 if (s == null) { 1190 s = new Service(this); 1191 s.type = type; 1192 s.algorithm = stdAlg; 1193 legacyMap.put(key, s); 1194 } 1195 s.className = className; 1196 } else { // attribute 1197 // e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software"); 1198 String attributeValue = value; 1199 String type = getEngineName(typeAndAlg[0]); 1200 String attributeString = typeAndAlg[1]; 1201 String stdAlg = attributeString.substring(0, i).intern(); 1202 String attributeName = attributeString.substring(i + 1); 1203 // kill additional spaces 1204 while (attributeName.startsWith(" ")) { 1205 attributeName = attributeName.substring(1); 1206 } 1207 attributeName = attributeName.intern(); 1208 ServiceKey key = new ServiceKey(type, stdAlg, true); 1209 Service s = legacyMap.get(key); 1210 if (s == null) { 1211 s = new Service(this); 1212 s.type = type; 1213 s.algorithm = stdAlg; 1214 legacyMap.put(key, s); 1215 } 1216 s.addAttribute(attributeName, attributeValue); 1217 } 1218 } 1219 } 1220 1221 /** 1222 * Get the service describing this Provider's implementation of the 1223 * specified type of this algorithm or alias. If no such 1224 * implementation exists, this method returns null. If there are two 1225 * matching services, one added to this provider using 1226 * {@link #putService putService()} and one added via {@link #put put()}, 1227 * the service added via {@link #putService putService()} is returned. 1228 * 1229 * @param type the type of {@link Service service} requested 1230 * (for example, {@code MessageDigest}) 1231 * @param algorithm the case insensitive algorithm name (or alternate 1232 * alias) of the service requested (for example, {@code SHA-1}) 1233 * 1234 * @return the service describing this Provider's matching service 1235 * or null if no such service exists 1236 * 1237 * @throws NullPointerException if type or algorithm is null 1238 * 1239 * @since 1.5 1240 */ 1241 public Service getService(String type, String algorithm) { 1242 checkInitialized(); 1243 1244 // avoid allocating a new ServiceKey object if possible 1245 ServiceKey key = previousKey; 1246 if (key.matches(type, algorithm) == false) { 1247 key = new ServiceKey(type, algorithm, false); 1248 previousKey = key; 1249 } 1250 if (!serviceMap.isEmpty()) { 1251 Service s = serviceMap.get(key); 1252 if (s != null) { 1253 return s; 1254 } 1255 } 1256 synchronized (this) { 1257 ensureLegacyParsed(); 1258 } 1259 if (legacyMap != null && !legacyMap.isEmpty()) { 1260 return legacyMap.get(key); 1261 } 1262 return null; 1263 } 1264 1265 // ServiceKey from previous getService() call 1266 // by re-using it if possible we avoid allocating a new object 1267 // and the toUpperCase() call. 1268 // re-use will occur e.g. as the framework traverses the provider 1269 // list and queries each provider with the same values until it finds 1270 // a matching service 1271 private static volatile ServiceKey previousKey = 1272 new ServiceKey("", "", false); 1273 1274 /** 1275 * Get an unmodifiable Set of all services supported by 1276 * this Provider. 1277 * 1278 * @return an unmodifiable Set of all services supported by 1279 * this Provider 1280 * 1281 * @since 1.5 1282 */ 1283 public synchronized Set<Service> getServices() { 1284 checkInitialized(); 1285 if (legacyChanged || servicesChanged) { 1286 serviceSet = null; 1287 } 1288 if (serviceSet == null) { 1289 ensureLegacyParsed(); 1290 Set<Service> set = new LinkedHashSet<>(); 1291 if (!serviceMap.isEmpty()) { 1292 set.addAll(serviceMap.values()); 1293 } 1294 if (legacyMap != null && !legacyMap.isEmpty()) { 1295 set.addAll(legacyMap.values()); 1296 } 1297 serviceSet = Collections.unmodifiableSet(set); 1298 servicesChanged = false; 1299 } 1300 return serviceSet; 1301 } 1302 1303 /** 1304 * Add a service. If a service of the same type with the same algorithm 1305 * name exists and it was added using {@link #putService putService()}, 1306 * it is replaced by the new service. 1307 * This method also places information about this service 1308 * in the provider's Hashtable values in the format described in the 1309 * {@extLink security_guide_jca 1310 * Java Cryptography Architecture (JCA) Reference Guide}. 1311 * 1312 * <p>Also, if there is a security manager, its 1313 * {@code checkSecurityAccess} method is called with the string 1314 * {@code "putProviderProperty."+name}, where {@code name} is 1315 * the provider name, to see if it's ok to set this provider's property 1316 * values. If the default implementation of {@code checkSecurityAccess} 1317 * is used (that is, that method is not overridden), then this results in 1318 * a call to the security manager's {@code checkPermission} method with 1319 * a {@code SecurityPermission("putProviderProperty."+name)} 1320 * permission. 1321 * 1322 * @param s the Service to add 1323 * 1324 * @throws SecurityException 1325 * if a security manager exists and its {@link 1326 * java.lang.SecurityManager#checkSecurityAccess} method denies 1327 * access to set property values. 1328 * @throws NullPointerException if s is null 1329 * 1330 * @since 1.5 1331 */ 1332 protected void putService(Service s) { 1333 check("putProviderProperty." + name); 1334 if (debug != null) { 1335 debug.println(name + ".putService(): " + s); 1336 } 1337 if (s == null) { 1338 throw new NullPointerException(); 1339 } 1340 if (s.getProvider() != this) { 1341 throw new IllegalArgumentException 1342 ("service.getProvider() must match this Provider object"); 1343 } 1344 String type = s.getType(); 1345 String algorithm = s.getAlgorithm(); 1346 ServiceKey key = new ServiceKey(type, algorithm, true); 1347 implRemoveService(serviceMap.get(key)); 1348 serviceMap.put(key, s); 1349 for (String alias : s.getAliases()) { 1350 serviceMap.put(new ServiceKey(type, alias, true), s); 1351 } 1352 servicesChanged = true; 1353 synchronized (this) { 1354 putPropertyStrings(s); 1355 } 1356 } 1357 1358 /** 1359 * Put the string properties for this Service in this Provider's 1360 * Hashtable. 1361 */ 1362 private void putPropertyStrings(Service s) { 1363 String type = s.getType(); 1364 String algorithm = s.getAlgorithm(); 1365 // use super() to avoid permission check and other processing 1366 super.put(type + "." + algorithm, s.getClassName()); 1367 for (String alias : s.getAliases()) { 1368 super.put(ALIAS_PREFIX + type + "." + alias, algorithm); 1369 } 1370 for (Map.Entry<UString,String> entry : s.attributes.entrySet()) { 1371 String key = type + "." + algorithm + " " + entry.getKey(); 1372 super.put(key, entry.getValue()); 1373 } 1374 } 1375 1376 /** 1377 * Remove the string properties for this Service from this Provider's 1378 * Hashtable. 1379 */ 1380 private void removePropertyStrings(Service s) { 1381 String type = s.getType(); 1382 String algorithm = s.getAlgorithm(); 1383 // use super() to avoid permission check and other processing 1384 super.remove(type + "." + algorithm); 1385 for (String alias : s.getAliases()) { 1386 super.remove(ALIAS_PREFIX + type + "." + alias); 1387 } 1388 for (Map.Entry<UString,String> entry : s.attributes.entrySet()) { 1389 String key = type + "." + algorithm + " " + entry.getKey(); 1390 super.remove(key); 1391 } 1392 } 1393 1394 /** 1395 * Remove a service previously added using 1396 * {@link #putService putService()}. The specified service is removed from 1397 * this provider. It will no longer be returned by 1398 * {@link #getService getService()} and its information will be removed 1399 * from this provider's Hashtable. 1400 * 1401 * <p>Also, if there is a security manager, its 1402 * {@code checkSecurityAccess} method is called with the string 1403 * {@code "removeProviderProperty."+name}, where {@code name} is 1404 * the provider name, to see if it's ok to remove this provider's 1405 * properties. If the default implementation of 1406 * {@code checkSecurityAccess} is used (that is, that method is not 1407 * overridden), then this results in a call to the security manager's 1408 * {@code checkPermission} method with a 1409 * {@code SecurityPermission("removeProviderProperty."+name)} 1410 * permission. 1411 * 1412 * @param s the Service to be removed 1413 * 1414 * @throws SecurityException 1415 * if a security manager exists and its {@link 1416 * java.lang.SecurityManager#checkSecurityAccess} method denies 1417 * access to remove this provider's properties. 1418 * @throws NullPointerException if s is null 1419 * 1420 * @since 1.5 1421 */ 1422 protected void removeService(Service s) { 1423 check("removeProviderProperty." + name); 1424 if (debug != null) { 1425 debug.println(name + ".removeService(): " + s); 1426 } 1427 if (s == null) { 1428 throw new NullPointerException(); 1429 } 1430 implRemoveService(s); 1431 } 1432 1433 private void implRemoveService(Service s) { 1434 if ((s == null) || serviceMap.isEmpty()) { 1435 return; 1436 } 1437 String type = s.getType(); 1438 String algorithm = s.getAlgorithm(); 1439 ServiceKey key = new ServiceKey(type, algorithm, false); 1440 Service oldService = serviceMap.get(key); 1441 if (s != oldService) { 1442 return; 1443 } 1444 servicesChanged = true; 1445 serviceMap.remove(key); 1446 for (String alias : s.getAliases()) { 1447 serviceMap.remove(new ServiceKey(type, alias, false)); 1448 } 1449 synchronized (this) { 1450 removePropertyStrings(s); 1451 } 1452 } 1453 1454 // Wrapped String that behaves in a case insensitive way for equals/hashCode 1455 private static class UString { 1456 final String string; 1457 final String lowerString; 1458 1459 UString(String s) { 1460 this.string = s; 1461 this.lowerString = s.toLowerCase(ENGLISH); 1462 } 1463 1464 public int hashCode() { 1465 return lowerString.hashCode(); 1466 } 1467 1468 public boolean equals(Object obj) { 1469 if (this == obj) { 1470 return true; 1471 } 1472 if (obj instanceof UString == false) { 1473 return false; 1474 } 1475 UString other = (UString)obj; 1476 return lowerString.equals(other.lowerString); 1477 } 1478 1479 public String toString() { 1480 return string; 1481 } 1482 } 1483 1484 // describe relevant properties of a type of engine 1485 private static class EngineDescription { 1486 final String name; 1487 final boolean supportsParameter; 1488 final String constructorParameterClassName; 1489 private volatile Class<?> constructorParameterClass; 1490 1491 EngineDescription(String name, boolean sp, String paramName) { 1492 this.name = name; 1493 this.supportsParameter = sp; 1494 this.constructorParameterClassName = paramName; 1495 } 1496 Class<?> getConstructorParameterClass() throws ClassNotFoundException { 1497 Class<?> clazz = constructorParameterClass; 1498 if (clazz == null) { 1499 clazz = Class.forName(constructorParameterClassName); 1500 constructorParameterClass = clazz; 1501 } 1502 return clazz; 1503 } 1504 } 1505 1506 // built in knowledge of the engine types shipped as part of the JDK 1507 private static final Map<String,EngineDescription> knownEngines; 1508 1509 private static void addEngine(String name, boolean sp, String paramName) { 1510 EngineDescription ed = new EngineDescription(name, sp, paramName); 1511 // also index by canonical name to avoid toLowerCase() for some lookups 1512 knownEngines.put(name.toLowerCase(ENGLISH), ed); 1513 knownEngines.put(name, ed); 1514 } 1515 1516 static { 1517 knownEngines = new HashMap<>(); 1518 // JCA 1519 addEngine("AlgorithmParameterGenerator", false, null); 1520 addEngine("AlgorithmParameters", false, null); 1521 addEngine("KeyFactory", false, null); 1522 addEngine("KeyPairGenerator", false, null); 1523 addEngine("KeyStore", false, null); 1524 addEngine("MessageDigest", false, null); 1525 addEngine("SecureRandom", false, 1526 "java.security.SecureRandomParameters"); 1527 addEngine("Signature", true, null); 1528 addEngine("CertificateFactory", false, null); 1529 addEngine("CertPathBuilder", false, null); 1530 addEngine("CertPathValidator", false, null); 1531 addEngine("CertStore", false, 1532 "java.security.cert.CertStoreParameters"); 1533 // JCE 1534 addEngine("Cipher", true, null); 1535 addEngine("ExemptionMechanism", false, null); 1536 addEngine("Mac", true, null); 1537 addEngine("KeyAgreement", true, null); 1538 addEngine("KeyGenerator", false, null); 1539 addEngine("SecretKeyFactory", false, null); 1540 // JSSE 1541 addEngine("KeyManagerFactory", false, null); 1542 addEngine("SSLContext", false, null); 1543 addEngine("TrustManagerFactory", false, null); 1544 // JGSS 1545 addEngine("GssApiMechanism", false, null); 1546 // SASL 1547 addEngine("SaslClientFactory", false, null); 1548 addEngine("SaslServerFactory", false, null); 1549 // POLICY 1550 addEngine("Policy", false, 1551 "java.security.Policy$Parameters"); 1552 // CONFIGURATION 1553 addEngine("Configuration", false, 1554 "javax.security.auth.login.Configuration$Parameters"); 1555 // XML DSig 1556 addEngine("XMLSignatureFactory", false, null); 1557 addEngine("KeyInfoFactory", false, null); 1558 addEngine("TransformService", false, null); 1559 // Smart Card I/O 1560 addEngine("TerminalFactory", false, 1561 "java.lang.Object"); 1562 } 1563 1564 // get the "standard" (mixed-case) engine name for arbitary case engine name 1565 // if there is no known engine by that name, return s 1566 private static String getEngineName(String s) { 1567 // try original case first, usually correct 1568 EngineDescription e = knownEngines.get(s); 1569 if (e == null) { 1570 e = knownEngines.get(s.toLowerCase(ENGLISH)); 1571 } 1572 return (e == null) ? s : e.name; 1573 } 1574 1575 /** 1576 * The description of a security service. It encapsulates the properties 1577 * of a service and contains a factory method to obtain new implementation 1578 * instances of this service. 1579 * 1580 * <p>Each service has a provider that offers the service, a type, 1581 * an algorithm name, and the name of the class that implements the 1582 * service. Optionally, it also includes a list of alternate algorithm 1583 * names for this service (aliases) and attributes, which are a map of 1584 * (name, value) String pairs. 1585 * 1586 * <p>This class defines the methods {@link #supportsParameter 1587 * supportsParameter()} and {@link #newInstance newInstance()} 1588 * which are used by the Java security framework when it searches for 1589 * suitable services and instantiates them. The valid arguments to those 1590 * methods depend on the type of service. For the service types defined 1591 * within Java SE, see the 1592 * {@extLink security_guide_jca 1593 * Java Cryptography Architecture (JCA) Reference Guide} 1594 * for the valid values. 1595 * Note that components outside of Java SE can define additional types of 1596 * services and their behavior. 1597 * 1598 * <p>Instances of this class are immutable. 1599 * 1600 * @since 1.5 1601 */ 1602 public static class Service { 1603 1604 private String type, algorithm, className; 1605 private final Provider provider; 1606 private List<String> aliases; 1607 private Map<UString,String> attributes; 1608 1609 // Reference to the cached implementation Class object 1610 private volatile Reference<Class<?>> classRef; 1611 1612 // flag indicating whether this service has its attributes for 1613 // supportedKeyFormats or supportedKeyClasses set 1614 // if null, the values have not been initialized 1615 // if TRUE, at least one of supportedFormats/Classes is non null 1616 private volatile Boolean hasKeyAttributes; 1617 1618 // supported encoding formats 1619 private String[] supportedFormats; 1620 1621 // names of the supported key (super) classes 1622 private Class<?>[] supportedClasses; 1623 1624 // whether this service has been registered with the Provider 1625 private boolean registered; 1626 1627 private static final Class<?>[] CLASS0 = new Class<?>[0]; 1628 1629 // this constructor and these methods are used for parsing 1630 // the legacy string properties. 1631 1632 private Service(Provider provider) { 1633 this.provider = provider; 1634 aliases = Collections.<String>emptyList(); 1635 attributes = Collections.<UString,String>emptyMap(); 1636 } 1637 1638 private boolean isValid() { 1639 return (type != null) && (algorithm != null) && (className != null); 1640 } 1641 1642 private void addAlias(String alias) { 1643 if (aliases.isEmpty()) { 1644 aliases = new ArrayList<>(2); 1645 } 1646 aliases.add(alias); 1647 } 1648 1649 void addAttribute(String type, String value) { 1650 if (attributes.isEmpty()) { 1651 attributes = new HashMap<>(8); 1652 } 1653 attributes.put(new UString(type), value); 1654 } 1655 1656 /** 1657 * Construct a new service. 1658 * 1659 * @param provider the provider that offers this service 1660 * @param type the type of this service 1661 * @param algorithm the algorithm name 1662 * @param className the name of the class implementing this service 1663 * @param aliases List of aliases or null if algorithm has no aliases 1664 * @param attributes Map of attributes or null if this implementation 1665 * has no attributes 1666 * 1667 * @throws NullPointerException if provider, type, algorithm, or 1668 * className is null 1669 */ 1670 public Service(Provider provider, String type, String algorithm, 1671 String className, List<String> aliases, 1672 Map<String,String> attributes) { 1673 if ((provider == null) || (type == null) || 1674 (algorithm == null) || (className == null)) { 1675 throw new NullPointerException(); 1676 } 1677 this.provider = provider; 1678 this.type = getEngineName(type); 1679 this.algorithm = algorithm; 1680 this.className = className; 1681 if (aliases == null) { 1682 this.aliases = Collections.<String>emptyList(); 1683 } else { 1684 this.aliases = new ArrayList<>(aliases); 1685 } 1686 if (attributes == null) { 1687 this.attributes = Collections.<UString,String>emptyMap(); 1688 } else { 1689 this.attributes = new HashMap<>(); 1690 for (Map.Entry<String,String> entry : attributes.entrySet()) { 1691 this.attributes.put(new UString(entry.getKey()), entry.getValue()); 1692 } 1693 } 1694 } 1695 1696 /** 1697 * Get the type of this service. For example, {@code MessageDigest}. 1698 * 1699 * @return the type of this service 1700 */ 1701 public final String getType() { 1702 return type; 1703 } 1704 1705 /** 1706 * Return the name of the algorithm of this service. For example, 1707 * {@code SHA-1}. 1708 * 1709 * @return the algorithm of this service 1710 */ 1711 public final String getAlgorithm() { 1712 return algorithm; 1713 } 1714 1715 /** 1716 * Return the Provider of this service. 1717 * 1718 * @return the Provider of this service 1719 */ 1720 public final Provider getProvider() { 1721 return provider; 1722 } 1723 1724 /** 1725 * Return the name of the class implementing this service. 1726 * 1727 * @return the name of the class implementing this service 1728 */ 1729 public final String getClassName() { 1730 return className; 1731 } 1732 1733 // internal only 1734 private final List<String> getAliases() { 1735 return aliases; 1736 } 1737 1738 /** 1739 * Return the value of the specified attribute or null if this 1740 * attribute is not set for this Service. 1741 * 1742 * @param name the name of the requested attribute 1743 * 1744 * @return the value of the specified attribute or null if the 1745 * attribute is not present 1746 * 1747 * @throws NullPointerException if name is null 1748 */ 1749 public final String getAttribute(String name) { 1750 if (name == null) { 1751 throw new NullPointerException(); 1752 } 1753 return attributes.get(new UString(name)); 1754 } 1755 1756 /** 1757 * Return a new instance of the implementation described by this 1758 * service. The security provider framework uses this method to 1759 * construct implementations. Applications will typically not need 1760 * to call it. 1761 * 1762 * <p>The default implementation uses reflection to invoke the 1763 * standard constructor for this type of service. 1764 * Security providers can override this method to implement 1765 * instantiation in a different way. 1766 * For details and the values of constructorParameter that are 1767 * valid for the various types of services see the 1768 * {@extLink security_guide_jca 1769 * Java Cryptography Architecture (JCA) Reference Guide}. 1770 * 1771 * @param constructorParameter the value to pass to the constructor, 1772 * or null if this type of service does not use a constructorParameter. 1773 * 1774 * @return a new implementation of this service 1775 * 1776 * @throws InvalidParameterException if the value of 1777 * constructorParameter is invalid for this type of service. 1778 * @throws NoSuchAlgorithmException if instantiation failed for 1779 * any other reason. 1780 */ 1781 public Object newInstance(Object constructorParameter) 1782 throws NoSuchAlgorithmException { 1783 if (registered == false) { 1784 if (provider.getService(type, algorithm) != this) { 1785 throw new NoSuchAlgorithmException 1786 ("Service not registered with Provider " 1787 + provider.getName() + ": " + this); 1788 } 1789 registered = true; 1790 } 1791 Class<?> ctrParamClz; 1792 try { 1793 EngineDescription cap = knownEngines.get(type); 1794 if (cap == null) { 1795 // unknown engine type, use generic code 1796 // this is the code path future for non-core 1797 // optional packages 1798 ctrParamClz = constructorParameter == null? 1799 null : constructorParameter.getClass(); 1800 } else { 1801 ctrParamClz = cap.constructorParameterClassName == null? 1802 null : Class.forName(cap.constructorParameterClassName); 1803 if (constructorParameter != null) { 1804 if (ctrParamClz == null) { 1805 throw new InvalidParameterException 1806 ("constructorParameter not used with " + type 1807 + " engines"); 1808 } else { 1809 Class<?> argClass = constructorParameter.getClass(); 1810 if (ctrParamClz.isAssignableFrom(argClass) == false) { 1811 throw new InvalidParameterException 1812 ("constructorParameter must be instanceof " 1813 + cap.constructorParameterClassName.replace('$', '.') 1814 + " for engine type " + type); 1815 } 1816 } 1817 } 1818 } 1819 // constructorParameter can be null if not provided 1820 return newInstanceUtil(getImplClass(), ctrParamClz, constructorParameter); 1821 } catch (NoSuchAlgorithmException e) { 1822 throw e; 1823 } catch (InvocationTargetException e) { 1824 throw new NoSuchAlgorithmException 1825 ("Error constructing implementation (algorithm: " 1826 + algorithm + ", provider: " + provider.getName() 1827 + ", class: " + className + ")", e.getCause()); 1828 } catch (Exception e) { 1829 throw new NoSuchAlgorithmException 1830 ("Error constructing implementation (algorithm: " 1831 + algorithm + ", provider: " + provider.getName() 1832 + ", class: " + className + ")", e); 1833 } 1834 } 1835 1836 // return the implementation Class object for this service 1837 private Class<?> getImplClass() throws NoSuchAlgorithmException { 1838 try { 1839 Reference<Class<?>> ref = classRef; 1840 Class<?> clazz = (ref == null) ? null : ref.get(); 1841 if (clazz == null) { 1842 ClassLoader cl = provider.getClass().getClassLoader(); 1843 if (cl == null) { 1844 clazz = Class.forName(className); 1845 } else { 1846 clazz = cl.loadClass(className); 1847 } 1848 if (!Modifier.isPublic(clazz.getModifiers())) { 1849 throw new NoSuchAlgorithmException 1850 ("class configured for " + type + " (provider: " + 1851 provider.getName() + ") is not public."); 1852 } 1853 classRef = new WeakReference<>(clazz); 1854 } 1855 return clazz; 1856 } catch (ClassNotFoundException e) { 1857 throw new NoSuchAlgorithmException 1858 ("class configured for " + type + " (provider: " + 1859 provider.getName() + ") cannot be found.", e); 1860 } 1861 } 1862 1863 /** 1864 * Test whether this Service can use the specified parameter. 1865 * Returns false if this service cannot use the parameter. Returns 1866 * true if this service can use the parameter, if a fast test is 1867 * infeasible, or if the status is unknown. 1868 * 1869 * <p>The security provider framework uses this method with 1870 * some types of services to quickly exclude non-matching 1871 * implementations for consideration. 1872 * Applications will typically not need to call it. 1873 * 1874 * <p>For details and the values of parameter that are valid for the 1875 * various types of services see the top of this class and the 1876 * {@extLink security_guide_jca 1877 * Java Cryptography Architecture (JCA) Reference Guide}. 1878 * Security providers can override it to implement their own test. 1879 * 1880 * @param parameter the parameter to test 1881 * 1882 * @return false if this service cannot use the specified 1883 * parameter; true if it can possibly use the parameter 1884 * 1885 * @throws InvalidParameterException if the value of parameter is 1886 * invalid for this type of service or if this method cannot be 1887 * used with this type of service 1888 */ 1889 public boolean supportsParameter(Object parameter) { 1890 EngineDescription cap = knownEngines.get(type); 1891 if (cap == null) { 1892 // unknown engine type, return true by default 1893 return true; 1894 } 1895 if (cap.supportsParameter == false) { 1896 throw new InvalidParameterException("supportsParameter() not " 1897 + "used with " + type + " engines"); 1898 } 1899 // allow null for keys without attributes for compatibility 1900 if ((parameter != null) && (parameter instanceof Key == false)) { 1901 throw new InvalidParameterException 1902 ("Parameter must be instanceof Key for engine " + type); 1903 } 1904 if (hasKeyAttributes() == false) { 1905 return true; 1906 } 1907 if (parameter == null) { 1908 return false; 1909 } 1910 Key key = (Key)parameter; 1911 if (supportsKeyFormat(key)) { 1912 return true; 1913 } 1914 if (supportsKeyClass(key)) { 1915 return true; 1916 } 1917 return false; 1918 } 1919 1920 /** 1921 * Return whether this service has its supported properties for 1922 * keys defined. Parses the attributes if not yet initialized. 1923 */ 1924 private boolean hasKeyAttributes() { 1925 Boolean b = hasKeyAttributes; 1926 if (b == null) { 1927 synchronized (this) { 1928 String s; 1929 s = getAttribute("SupportedKeyFormats"); 1930 if (s != null) { 1931 supportedFormats = s.split("\\|"); 1932 } 1933 s = getAttribute("SupportedKeyClasses"); 1934 if (s != null) { 1935 String[] classNames = s.split("\\|"); 1936 List<Class<?>> classList = 1937 new ArrayList<>(classNames.length); 1938 for (String className : classNames) { 1939 Class<?> clazz = getKeyClass(className); 1940 if (clazz != null) { 1941 classList.add(clazz); 1942 } 1943 } 1944 supportedClasses = classList.toArray(CLASS0); 1945 } 1946 boolean bool = (supportedFormats != null) 1947 || (supportedClasses != null); 1948 b = Boolean.valueOf(bool); 1949 hasKeyAttributes = b; 1950 } 1951 } 1952 return b.booleanValue(); 1953 } 1954 1955 // get the key class object of the specified name 1956 private Class<?> getKeyClass(String name) { 1957 try { 1958 return Class.forName(name); 1959 } catch (ClassNotFoundException e) { 1960 // ignore 1961 } 1962 try { 1963 ClassLoader cl = provider.getClass().getClassLoader(); 1964 if (cl != null) { 1965 return cl.loadClass(name); 1966 } 1967 } catch (ClassNotFoundException e) { 1968 // ignore 1969 } 1970 return null; 1971 } 1972 1973 private boolean supportsKeyFormat(Key key) { 1974 if (supportedFormats == null) { 1975 return false; 1976 } 1977 String format = key.getFormat(); 1978 if (format == null) { 1979 return false; 1980 } 1981 for (String supportedFormat : supportedFormats) { 1982 if (supportedFormat.equals(format)) { 1983 return true; 1984 } 1985 } 1986 return false; 1987 } 1988 1989 private boolean supportsKeyClass(Key key) { 1990 if (supportedClasses == null) { 1991 return false; 1992 } 1993 Class<?> keyClass = key.getClass(); 1994 for (Class<?> clazz : supportedClasses) { 1995 if (clazz.isAssignableFrom(keyClass)) { 1996 return true; 1997 } 1998 } 1999 return false; 2000 } 2001 2002 /** 2003 * Return a String representation of this service. 2004 * 2005 * @return a String representation of this service. 2006 */ 2007 public String toString() { 2008 String aString = aliases.isEmpty() 2009 ? "" : "\r\n aliases: " + aliases.toString(); 2010 String attrs = attributes.isEmpty() 2011 ? "" : "\r\n attributes: " + attributes.toString(); 2012 return provider.getName() + ": " + type + "." + algorithm 2013 + " -> " + className + aString + attrs + "\r\n"; 2014 } 2015 } 2016 }