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