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