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