1 /*
   2  * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.jca;
  27 
  28 import java.util.*;
  29 
  30 import java.security.AccessController;
  31 import java.security.PrivilegedAction;
  32 import java.security.Provider;
  33 import java.security.Provider.Service;
  34 import java.security.Security;
  35 
  36 /**
  37  * List of Providers. Used to represent the provider preferences.
  38  *
  39  * The system starts out with a ProviderList that only has the names
  40  * of the Providers.
  41  * When using ServiceLoader to load the providers, Providers are created
  42  * semi-eagerly as we iterate through them looking for a match.
  43  *
  44  * For compatibility reasons, Providers that could not be loaded are ignored
  45  * and internally presented as the instance EMPTY_PROVIDER. However, those
  46  * objects cannot be presented to applications. Call the convert() method
  47  * to force all Providers to be loaded and to obtain a ProviderList with
  48  * invalid entries removed. All this is handled by the Security class.
  49  *
  50  * Note that all indices used by this class are 0-based per general Java
  51  * convention. These must be converted to the 1-based indices used by the
  52  * Security class externally when needed.
  53  *
  54  * Instances of this class are immutable. This eliminates the need for
  55  * cloning and synchronization in consumers. The add() and remove() style
  56  * methods are static in order to avoid confusion about the immutability.
  57  *
  58  * @author  Andreas Sterbenz
  59  * @since   1.5
  60  */
  61 public final class ProviderList {
  62 
  63     static final sun.security.util.Debug debug =
  64         sun.security.util.Debug.getInstance("jca", "ProviderList");
  65 
  66     private static final ProviderConfig[] PC0 = new ProviderConfig[0];
  67 
  68     private static final Provider[] P0 = new Provider[0];
  69 
  70     // constant for an ProviderList with no elements
  71     static final ProviderList EMPTY = new ProviderList(PC0, true);
  72 
  73     // list of all jdk.security.provider.preferred entries
  74     static private PreferredList preferredPropList = null;
  75 
  76     // dummy provider object to use during initialization
  77     // used to avoid explicit null checks in various places
  78     private static final Provider EMPTY_PROVIDER =
  79         new Provider("##Empty##", "1.0", "initialization in progress") {
  80             private static final long serialVersionUID = 1151354171352296389L;
  81             // override getService() to return null slightly faster
  82             public Service getService(String type, String algorithm) {
  83                 return null;
  84             }
  85         };
  86 
  87     // construct a ProviderList from the security properties
  88     // (static provider configuration in the java.security file)
  89     static ProviderList fromSecurityProperties() {
  90         // doPrivileged() because of Security.getProperty()
  91         return AccessController.doPrivileged(
  92                         new PrivilegedAction<ProviderList>() {
  93             public ProviderList run() {
  94                 return new ProviderList();
  95             }
  96         });
  97     }
  98 
  99     public static ProviderList add(ProviderList providerList, Provider p) {
 100         return insertAt(providerList, p, -1);
 101     }
 102 
 103     public static ProviderList insertAt(ProviderList providerList, Provider p,
 104             int position) {
 105         if (providerList.getProvider(p.getName()) != null) {
 106             return providerList;
 107         }
 108         List<ProviderConfig> list = new ArrayList<>
 109                                     (Arrays.asList(providerList.configs));
 110         int n = list.size();
 111         if ((position < 0) || (position > n)) {
 112             position = n;
 113         }
 114         list.add(position, new ProviderConfig(p));
 115         return new ProviderList(list.toArray(PC0), true);
 116     }
 117 
 118     public static ProviderList remove(ProviderList providerList, String name) {
 119         // make sure provider exists
 120         if (providerList.getProvider(name) == null) {
 121             return providerList;
 122         }
 123         // copy all except matching to new list
 124         ProviderConfig[] configs = new ProviderConfig[providerList.size() - 1];
 125         int j = 0;
 126         for (ProviderConfig config : providerList.configs) {
 127             if (config.getProvider().getName().equals(name) == false) {
 128                 configs[j++] = config;
 129             }
 130         }
 131         return new ProviderList(configs, true);
 132     }
 133 
 134     // Create a new ProviderList from the specified Providers.
 135     // This method is for use by SunJSSE.
 136     public static ProviderList newList(Provider ... providers) {
 137         ProviderConfig[] configs = new ProviderConfig[providers.length];
 138         for (int i = 0; i < providers.length; i++) {
 139             configs[i] = new ProviderConfig(providers[i]);
 140         }
 141         return new ProviderList(configs, true);
 142     }
 143 
 144     // configuration of the providers
 145     private final ProviderConfig[] configs;
 146 
 147     // flag indicating whether all configs have been loaded successfully
 148     private volatile boolean allLoaded;
 149 
 150     // List returned by providers()
 151     private final List<Provider> userList = new AbstractList<Provider>() {
 152         public int size() {
 153             return configs.length;
 154         }
 155         public Provider get(int index) {
 156             return getProvider(index);
 157         }
 158     };
 159 
 160     /**
 161      * Create a new ProviderList from an array of configs
 162      */
 163     private ProviderList(ProviderConfig[] configs, boolean allLoaded) {
 164         this.configs = configs;
 165         this.allLoaded = allLoaded;
 166     }
 167 
 168     /**
 169      * Return a new ProviderList parsed from the java.security Properties.
 170      */
 171     private ProviderList() {
 172         List<ProviderConfig> configList = new ArrayList<>();
 173         String entry;
 174         int i = 1;
 175 
 176         while ((entry = Security.getProperty("security.provider." + i)) != null) {
 177             entry = entry.trim();
 178             if (entry.length() == 0) {
 179                 System.err.println("invalid entry for " +
 180                                    "security.provider." + i);
 181                 break;
 182             }
 183             int k = entry.indexOf(' ');
 184             ProviderConfig config;
 185             if (k == -1) {
 186                 config = new ProviderConfig(entry);
 187             } else {
 188                 String provName = entry.substring(0, k);
 189                 String argument = entry.substring(k + 1).trim();
 190                 config = new ProviderConfig(provName, argument);
 191             }
 192 
 193             // Get rid of duplicate providers.
 194             if (configList.contains(config) == false) {
 195                 configList.add(config);
 196             }
 197             i++;
 198         }
 199         configs = configList.toArray(PC0);
 200 
 201         // Load config entries for use when getInstance is called
 202         entry = Security.getProperty("jdk.security.provider.preferred");
 203         if (entry != null && (entry = entry.trim()).length() > 0) {
 204             String[] entries = entry.split(",");
 205             if (ProviderList.preferredPropList == null) {
 206                 ProviderList.preferredPropList = new PreferredList();
 207             }
 208 
 209             for (String e : entries) {
 210                 i = e.indexOf(':');
 211                 if (i < 0) {
 212                     if (debug != null) {
 213                         debug.println("invalid preferred entry skipped.  " +
 214                                 "Missing colon delimiter \"" + e + "\"");
 215                     }
 216                     continue;
 217                 }
 218                 ProviderList.preferredPropList.add(new PreferredEntry(
 219                         e.substring(0, i).trim(), e.substring(i + 1).trim()));
 220             }
 221         }
 222 
 223         if (debug != null) {
 224             debug.println("provider configuration: " + configList);
 225             debug.println("config configuration: " +
 226                     ProviderList.preferredPropList);
 227         }
 228     }
 229 
 230     /**
 231      * Construct a special ProviderList for JAR verification. It consists
 232      * of the providers specified via jarClassNames, which must be on the
 233      * bootclasspath and cannot be in signed JAR files. This is to avoid
 234      * possible recursion and deadlock during verification.
 235      */
 236     ProviderList getJarList(String[] jarProvNames) {
 237         List<ProviderConfig> newConfigs = new ArrayList<>();
 238         for (String provName : jarProvNames) {
 239             ProviderConfig newConfig = new ProviderConfig(provName);
 240             for (ProviderConfig config : configs) {
 241                 // if the equivalent object is present in this provider list,
 242                 // use the old object rather than the new object.
 243                 // this ensures that when the provider is loaded in the
 244                 // new thread local list, it will also become available
 245                 // in this provider list
 246                 if (config.equals(newConfig)) {
 247                     newConfig = config;
 248                     break;
 249                 }
 250             }
 251             newConfigs.add(newConfig);
 252         }
 253         ProviderConfig[] configArray = newConfigs.toArray(PC0);
 254         return new ProviderList(configArray, false);
 255     }
 256 
 257     public int size() {
 258         return configs.length;
 259     }
 260 
 261     /**
 262      * Return the Provider at the specified index. Returns EMPTY_PROVIDER
 263      * if the provider could not be loaded at this time.
 264      */
 265     Provider getProvider(int index) {
 266         Provider p = configs[index].getProvider();
 267         return (p != null) ? p : EMPTY_PROVIDER;
 268     }
 269 
 270     /**
 271      * Return an unmodifiable List of all Providers in this List. The
 272      * individual Providers are loaded on demand. Elements that could not
 273      * be initialized are replaced with EMPTY_PROVIDER.
 274      */
 275     public List<Provider> providers() {
 276         return userList;
 277     }
 278 
 279     private ProviderConfig getProviderConfig(String name) {
 280         int index = getIndex(name);
 281         return (index != -1) ? configs[index] : null;
 282     }
 283 
 284     // return the Provider with the specified name or null
 285     public Provider getProvider(String name) {
 286         ProviderConfig config = getProviderConfig(name);
 287         return (config == null) ? null : config.getProvider();
 288     }
 289 
 290     /**
 291      * Return the index at which the provider with the specified name is
 292      * installed or -1 if it is not present in this ProviderList.
 293      */
 294     public int getIndex(String name) {
 295         for (int i = 0; i < configs.length; i++) {
 296             Provider p = getProvider(i);
 297             if (p.getName().equals(name)) {
 298                 return i;
 299             }
 300         }
 301         return -1;
 302     }
 303 
 304     // attempt to load all Providers not already loaded
 305     private int loadAll() {
 306         if (allLoaded) {
 307             return configs.length;
 308         }
 309         if (debug != null) {
 310             debug.println("Loading all providers");
 311             new Exception("Debug Info. Call trace:").printStackTrace();
 312         }
 313         int n = 0;
 314         for (int i = 0; i < configs.length; i++) {
 315             Provider p = configs[i].getProvider();
 316             if (p != null) {
 317                 n++;
 318             }
 319         }
 320         if (n == configs.length) {
 321             allLoaded = true;
 322         }
 323         return n;
 324     }
 325 
 326     /**
 327      * Try to load all Providers and return the ProviderList. If one or
 328      * more Providers could not be loaded, a new ProviderList with those
 329      * entries removed is returned. Otherwise, the method returns this.
 330      */
 331     ProviderList removeInvalid() {
 332         int n = loadAll();
 333         if (n == configs.length) {
 334             return this;
 335         }
 336         ProviderConfig[] newConfigs = new ProviderConfig[n];
 337         for (int i = 0, j = 0; i < configs.length; i++) {
 338             ProviderConfig config = configs[i];
 339             if (config.isLoaded()) {
 340                 newConfigs[j++] = config;
 341             }
 342         }
 343         return new ProviderList(newConfigs, true);
 344     }
 345 
 346     // return the providers as an array
 347     public Provider[] toArray() {
 348         return providers().toArray(P0);
 349     }
 350 
 351     // return a String representation of this ProviderList
 352     public String toString() {
 353         return Arrays.asList(configs).toString();
 354     }
 355 
 356     /**
 357      * Return a Service describing an implementation of the specified
 358      * algorithm from the Provider with the highest precedence that
 359      * supports that algorithm. Return null if no Provider supports this
 360      * algorithm.
 361      */
 362     public Service getService(String type, String name) {
 363         ArrayList<PreferredEntry> pList = null;
 364         int i;
 365 
 366         // Preferred provider list
 367         if (preferredPropList != null &&
 368                 (pList = preferredPropList.getAll(type, name)) != null) {
 369             for (i = 0; i < pList.size(); i++) {
 370                 Provider p = getProvider(pList.get(i).provider);
 371                 Service s = p.getService(type, name);
 372                 if (s != null) {
 373                     return s;
 374                 }
 375             }
 376         }
 377 
 378         for (i = 0; i < configs.length; i++) {
 379             Provider p = getProvider(i);
 380             Service s = p.getService(type, name);
 381             if (s != null) {
 382                 return s;
 383             }
 384         }
 385         return null;
 386     }
 387 
 388     /**
 389      * Return a List containing all the Services describing implementations
 390      * of the specified algorithms in precedence order. If no implementation
 391      * exists, this method returns an empty List.
 392      *
 393      * The elements of this list are determined lazily on demand.
 394      *
 395      * The List returned is NOT thread safe.
 396      */
 397     public List<Service> getServices(String type, String algorithm) {
 398         return new ServiceList(type, algorithm);
 399     }
 400 
 401     /**
 402      * This method exists for compatibility with JCE only. It will be removed
 403      * once JCE has been changed to use the replacement method.
 404      * @deprecated use {@code getServices(List<ServiceId>)} instead
 405      */
 406     @Deprecated
 407     public List<Service> getServices(String type, List<String> algorithms) {
 408         List<ServiceId> ids = new ArrayList<>();
 409         for (String alg : algorithms) {
 410             ids.add(new ServiceId(type, alg));
 411         }
 412         return getServices(ids);
 413     }
 414 
 415     public List<Service> getServices(List<ServiceId> ids) {
 416         return new ServiceList(ids);
 417     }
 418 
 419     /**
 420      * Inner class for a List of Services. Custom List implementation in
 421      * order to delay Provider initialization and lookup.
 422      * Not thread safe.
 423      */
 424     private final class ServiceList extends AbstractList<Service> {
 425 
 426         // type and algorithm for simple lookup
 427         // avoid allocating/traversing the ServiceId list for these lookups
 428         private final String type;
 429         private final String algorithm;
 430 
 431         // list of ids for parallel lookup
 432         // if ids is non-null, type and algorithm are null
 433         private final List<ServiceId> ids;
 434 
 435         // first service we have found
 436         // it is stored in a separate variable so that we can avoid
 437         // allocating the services list if we do not need the second service.
 438         // this is the case if we don't failover (failovers are typically rare)
 439         private Service firstService;
 440 
 441         // list of the services we have found so far
 442         private List<Service> services;
 443 
 444         // index into config[] of the next provider we need to query
 445         private int providerIndex = 0;
 446 
 447         // Matching preferred provider list for this ServiceList
 448         ArrayList<PreferredEntry> preferredList = null;
 449         private int preferredIndex = 0;
 450 
 451         ServiceList(String type, String algorithm) {
 452             this.type = type;
 453             this.algorithm = algorithm;
 454             this.ids = null;
 455         }
 456 
 457         ServiceList(List<ServiceId> ids) {
 458             this.type = null;
 459             this.algorithm = null;
 460             this.ids = ids;
 461         }
 462 
 463         private void addService(Service s) {
 464             if (firstService == null) {
 465                 firstService = s;
 466             } else {
 467                 if (services == null) {
 468                     services = new ArrayList<Service>(4);
 469                     services.add(firstService);
 470                 }
 471                 services.add(s);
 472             }
 473         }
 474 
 475         private Service tryGet(int index) {
 476             Provider p;
 477 
 478             // If preferred providers are configured, check for matches with
 479             // the requested service.
 480             if (preferredPropList != null && preferredList == null) {
 481                 preferredList = preferredPropList.getAll(this);
 482             }
 483 
 484             while (true) {
 485                 if ((index == 0) && (firstService != null)) {
 486                     return firstService;
 487                 } else if ((services != null) && (services.size() > index)) {
 488                     return services.get(index);
 489                 }
 490                 if (providerIndex >= configs.length) {
 491                     return null;
 492                 }
 493 
 494                 // If there were matches with a preferred provider, iterate
 495                 // through the list first before going through the
 496                 // ordered list (java.security.provider.#)
 497                 if (preferredList != null &&
 498                         preferredIndex < preferredList.size()) {
 499                     PreferredEntry entry = preferredList.get(preferredIndex++);
 500                     // Look for the provider name in the PreferredEntry
 501                     p = getProvider(entry.provider);
 502                     if (p == null) {
 503                         if (debug != null) {
 504                             debug.println("No provider found with name: " +
 505                                     entry.provider);
 506                         }
 507                         continue;
 508                     }
 509                 } else {
 510                     // check all algorithms in this provider before moving on
 511                     p = getProvider(providerIndex++);
 512                 }
 513 
 514                 if (type != null) {
 515                     // simple lookup
 516                     Service s = p.getService(type, algorithm);
 517                     if (s != null) {
 518                         addService(s);
 519                     }
 520                 } else {
 521                     // parallel lookup
 522                     for (ServiceId id : ids) {
 523                         Service s = p.getService(id.type, id.algorithm);
 524                         if (s != null) {
 525                             addService(s);
 526                         }
 527                     }
 528                 }
 529             }
 530         }
 531 
 532         public Service get(int index) {
 533             Service s = tryGet(index);
 534             if (s == null) {
 535                 throw new IndexOutOfBoundsException();
 536             }
 537             return s;
 538         }
 539 
 540         public int size() {
 541             int n;
 542             if (services != null) {
 543                 n = services.size();
 544             } else {
 545                 n = (firstService != null) ? 1 : 0;
 546             }
 547             while (tryGet(n) != null) {
 548                 n++;
 549             }
 550             return n;
 551         }
 552 
 553         // override isEmpty() and iterator() to not call size()
 554         // this avoids loading + checking all Providers
 555 
 556         public boolean isEmpty() {
 557             return (tryGet(0) == null);
 558         }
 559 
 560         public Iterator<Service> iterator() {
 561             return new Iterator<Service>() {
 562                 int index;
 563 
 564                 public boolean hasNext() {
 565                     return tryGet(index) != null;
 566                 }
 567 
 568                 public Service next() {
 569                     Service s = tryGet(index);
 570                     if (s == null) {
 571                         throw new NoSuchElementException();
 572                     }
 573                     index++;
 574                     return s;
 575                 }
 576 
 577                 public void remove() {
 578                     throw new UnsupportedOperationException();
 579                 }
 580             };
 581         }
 582     }
 583 
 584     // Provider list defined by jdk.security.provider.preferred entry
 585     static final class PreferredList {
 586         ArrayList<PreferredEntry> list = new ArrayList<PreferredEntry>();
 587 
 588         /*
 589          * Return a list of all preferred entries that match the passed
 590          * ServiceList.
 591          */
 592         ArrayList<PreferredEntry> getAll(ServiceList s) {
 593             if (s.ids == null) {
 594                 return getAll(s.type, s.algorithm);
 595 
 596             }
 597 
 598             ArrayList<PreferredEntry> l = new ArrayList<PreferredEntry>();
 599             for (ServiceId id : s.ids) {
 600                 implGetAll(l, id.type, id.algorithm);
 601             }
 602 
 603             return l;
 604         }
 605 
 606         /*
 607          * Return a list of all preferred entries that match the passed
 608          * type and algorithm.
 609          */
 610         ArrayList<PreferredEntry> getAll(String type, String algorithm) {
 611             ArrayList<PreferredEntry> l = new ArrayList<PreferredEntry>();
 612             implGetAll(l, type, algorithm);
 613             return l;
 614         }
 615 
 616         /*
 617          * Compare each preferred entry against the passed type and
 618          * algorithm, putting any matches in the passed ArrayList.
 619          */
 620         private void implGetAll(ArrayList<PreferredEntry> l, String type,
 621                 String algorithm) {
 622             PreferredEntry e;
 623 
 624             for (int i = 0; i < size(); i++) {
 625                 e = list.get(i);
 626                 if (e.match(type, algorithm)) {
 627                     l.add(e);
 628                 }
 629             }
 630         }
 631 
 632         public PreferredEntry get(int i) {
 633             return list.get(i);
 634         }
 635 
 636         public int size() {
 637             return list.size();
 638         }
 639 
 640         public boolean add(PreferredEntry e) {
 641             return list.add(e);
 642         }
 643 
 644         public String toString() {
 645             String s = "";
 646             for (PreferredEntry e: list) {
 647                 s += e.toString();
 648             }
 649             return s;
 650         }
 651     }
 652 
 653     /* Defined Groups for jdk.security.provider.preferred */
 654     private static final String SHA2Group[] = { "SHA-224", "SHA-256",
 655             "SHA-384", "SHA-512", "SHA-512/224", "SHA-512/256" };
 656     private static final String HmacSHA2Group[] = { "HmacSHA224",
 657             "HmacSHA256", "HmacSHA384", "HmacSHA512"};
 658     private static final String SHA2RSAGroup[] = { "SHA224withRSA",
 659             "SHA256withRSA", "SHA384withRSA", "SHA512withRSA"};
 660     private static final String SHA2DSAGroup[] = { "SHA224withDSA",
 661             "SHA256withDSA", "SHA384withDSA", "SHA512withDSA"};
 662     private static final String SHA2ECDSAGroup[] = { "SHA224withECDSA",
 663             "SHA256withECDSA", "SHA384withECDSA", "SHA512withECDSA"};
 664     private static final String SHA3Group[] = { "SHA3-224", "SHA3-256",
 665             "SHA3-384", "SHA3-512" };
 666     private static final String HmacSHA3Group[] = { "HmacSHA3-224",
 667             "HmacSHA3-256", "HmacSHA3-384", "HmacSHA3-512"};
 668 
 669     // Individual preferred property entry from jdk.security.provider.preferred
 670     private static class PreferredEntry {
 671         private String type = null;
 672         private String algorithm;
 673         private String provider;
 674         private String alternateNames[] = null;
 675         private boolean group = false;
 676 
 677         PreferredEntry(String t, String p) {
 678             int i = t.indexOf('.');
 679             if (i > 0) {
 680                 type = t.substring(0, i);
 681                 algorithm = t.substring(i + 1);
 682             } else {
 683                 algorithm = t;
 684             }
 685 
 686             provider = p;
 687             // Group definitions
 688             if (type != null && type.compareToIgnoreCase("Group") == 0) {
 689                 // Currently intrinsic algorithm groups
 690                 if (algorithm.compareToIgnoreCase("SHA2") == 0) {
 691                     alternateNames = SHA2Group;
 692                 } else if (algorithm.compareToIgnoreCase("HmacSHA2") == 0) {
 693                     alternateNames = HmacSHA2Group;
 694                 } else if (algorithm.compareToIgnoreCase("SHA2RSA") == 0) {
 695                     alternateNames = SHA2RSAGroup;
 696                 } else if (algorithm.compareToIgnoreCase("SHA2DSA") == 0) {
 697                     alternateNames = SHA2DSAGroup;
 698                 } else if (algorithm.compareToIgnoreCase("SHA2ECDSA") == 0) {
 699                     alternateNames = SHA2ECDSAGroup;
 700                 } else if (algorithm.compareToIgnoreCase("SHA3") == 0) {
 701                     alternateNames = SHA3Group;
 702                 } else if (algorithm.compareToIgnoreCase("HmacSHA3") == 0) {
 703                     alternateNames = HmacSHA3Group;
 704                 }
 705                 if (alternateNames != null) {
 706                     group = true;
 707                 }
 708 
 709             // If the algorithm name given is SHA1
 710             } else if (algorithm.compareToIgnoreCase("SHA1") == 0) {
 711                 alternateNames = new String[] { "SHA-1" };
 712             } else if (algorithm.compareToIgnoreCase("SHA-1") == 0) {
 713                 alternateNames = new String[] { "SHA1" };
 714             }
 715         }
 716 
 717         boolean match(String t, String a) {
 718             if (debug != null) {
 719                 debug.println("Config check:  " + toString() + " == " +
 720                         print(t, a, null));
 721             }
 722 
 723             // Compare service type if configured
 724             if (type != null && !group && type.compareToIgnoreCase(t) != 0) {
 725                 return false;
 726             }
 727 
 728             // Compare the algorithm string.
 729             if (!group && a.compareToIgnoreCase(algorithm) == 0) {
 730                 if (debug != null) {
 731                     debug.println("Config entry matched:  " + toString());
 732                 }
 733                 return true;
 734             }
 735 
 736             if (alternateNames != null) {
 737                 for (String alt : alternateNames) {
 738                     if (debug != null) {
 739                         debug.println("AltName check:  " + print(type, alt,
 740                                 provider));
 741                     }
 742                     if (a.compareToIgnoreCase(alt) == 0) {
 743                         if (debug != null) {
 744                             debug.println("AltName entry matched:  " +
 745                                     provider);
 746                         }
 747                         return true;
 748                     }
 749                 }
 750             }
 751 
 752             // No match
 753             return false;
 754         }
 755 
 756         // Print debugging output of PreferredEntry
 757         private String print(String t, String a, String p) {
 758             return "[" + ((t != null) ? t : "" ) + ", " + a +
 759                     ((p != null) ? " : " + p : "" ) + "] ";
 760         }
 761 
 762         public String toString() {
 763             return print(type, algorithm, provider);
 764         }
 765     }
 766 
 767 }