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