1/* 2 * Copyright (c) 2015, 2017, 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 26package sun.security.provider.certpath.ldap; 27 28import java.io.ByteArrayInputStream; 29import java.io.IOException; 30import java.util.*; 31import javax.naming.Context; 32import javax.naming.NamingEnumeration; 33import javax.naming.NamingException; 34import javax.naming.NameNotFoundException; 35import javax.naming.directory.Attribute; 36import javax.naming.directory.Attributes; 37import javax.naming.directory.BasicAttributes; 38 39import java.security.*; 40import java.security.cert.Certificate; 41import java.security.cert.*; 42import javax.naming.CommunicationException; 43import javax.naming.ldap.InitialLdapContext; 44import javax.naming.ldap.LdapContext; 45import javax.security.auth.x500.X500Principal; 46 47import sun.security.util.HexDumpEncoder; 48import sun.security.provider.certpath.X509CertificatePair; 49import sun.security.util.Cache; 50import sun.security.util.Debug; 51 52/** 53 * Core implementation of a LDAP Cert Store. 54 * @see java.security.cert.CertStore 55 * 56 * @since 9 57 */ 58final class LDAPCertStoreImpl { 59 60 private static final Debug debug = Debug.getInstance("certpath"); 61 62 private final static boolean DEBUG = false; 63 64 /** 65 * LDAP attribute identifiers. 66 */ 67 private static final String USER_CERT = "userCertificate;binary"; 68 private static final String CA_CERT = "cACertificate;binary"; 69 private static final String CROSS_CERT = "crossCertificatePair;binary"; 70 private static final String CRL = "certificateRevocationList;binary"; 71 private static final String ARL = "authorityRevocationList;binary"; 72 private static final String DELTA_CRL = "deltaRevocationList;binary"; 73 74 // Constants for various empty values 75 private final static String[] STRING0 = new String[0]; 76 77 private final static byte[][] BB0 = new byte[0][]; 78 79 private final static Attributes EMPTY_ATTRIBUTES = new BasicAttributes(); 80 81 // cache related constants 82 private final static int DEFAULT_CACHE_SIZE = 750; 83 private final static int DEFAULT_CACHE_LIFETIME = 30; 84 85 private final static int LIFETIME; 86 87 private final static String PROP_LIFETIME = 88 "sun.security.certpath.ldap.cache.lifetime"; 89 90 /* 91 * Internal system property, that when set to "true", disables the 92 * JNDI application resource files lookup to prevent recursion issues 93 * when validating signed JARs with LDAP URLs in certificates. 94 */ 95 private final static String PROP_DISABLE_APP_RESOURCE_FILES = 96 "sun.security.certpath.ldap.disable.app.resource.files"; 97 98 static { 99 String s = AccessController.doPrivileged( 100 (PrivilegedAction<String>) () -> System.getProperty(PROP_LIFETIME)); 101 if (s != null) { 102 LIFETIME = Integer.parseInt(s); // throws NumberFormatException 103 } else { 104 LIFETIME = DEFAULT_CACHE_LIFETIME; 105 } 106 } 107 108 /** 109 * The CertificateFactory used to decode certificates from 110 * their binary stored form. 111 */ 112 private CertificateFactory cf; 113 /** 114 * The JNDI directory context. 115 */ 116 private LdapContext ctx; 117 118 /** 119 * Flag indicating that communication error occurred. 120 */ 121 private boolean communicationError = false; 122 123 /** 124 * Flag indicating whether we should prefetch CRLs. 125 */ 126 private boolean prefetchCRLs = false; 127 128 private final Cache<String, byte[][]> valueCache; 129 130 private int cacheHits = 0; 131 private int cacheMisses = 0; 132 private int requests = 0; 133 134 /** 135 * Creates a <code>CertStore</code> with the specified parameters. 136 */ 137 LDAPCertStoreImpl(String serverName, int port) 138 throws InvalidAlgorithmParameterException { 139 createInitialDirContext(serverName, port); 140 // Create CertificateFactory for use later on 141 try { 142 cf = CertificateFactory.getInstance("X.509"); 143 } catch (CertificateException e) { 144 throw new InvalidAlgorithmParameterException( 145 "unable to create CertificateFactory for X.509"); 146 } 147 if (LIFETIME == 0) { 148 valueCache = Cache.newNullCache(); 149 } else if (LIFETIME < 0) { 150 valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE); 151 } else { 152 valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE, LIFETIME); 153 } 154 } 155 156 /** 157 * Create InitialDirContext. 158 * 159 * @param server Server DNS name hosting LDAP service 160 * @param port Port at which server listens for requests 161 * @throws InvalidAlgorithmParameterException if creation fails 162 */ 163 private void createInitialDirContext(String server, int port) 164 throws InvalidAlgorithmParameterException { 165 String url = "ldap://" + server + ":" + port; 166 Hashtable<String,Object> env = new Hashtable<>(); 167 env.put(Context.INITIAL_CONTEXT_FACTORY, 168 "com.sun.jndi.ldap.LdapCtxFactory"); 169 env.put(Context.PROVIDER_URL, url); 170 171 // If property is set to true, disable application resource file lookup. 172 boolean disableAppResourceFiles = AccessController.doPrivileged( 173 (PrivilegedAction<Boolean>) () -> Boolean.getBoolean(PROP_DISABLE_APP_RESOURCE_FILES)); 174 if (disableAppResourceFiles) { 175 if (debug != null) { 176 debug.println("LDAPCertStore disabling app resource files"); 177 } 178 env.put("com.sun.naming.disable.app.resource.files", "true"); 179 } 180 181 try { 182 ctx = new InitialLdapContext(env, null); 183 /* 184 * By default, follow referrals unless application has 185 * overridden property in an application resource file. 186 */ 187 Hashtable<?,?> currentEnv = ctx.getEnvironment(); 188 if (currentEnv.get(Context.REFERRAL) == null) { 189 ctx.addToEnvironment(Context.REFERRAL, "follow-scheme"); 190 } 191 } catch (NamingException e) { 192 if (debug != null) { 193 debug.println("LDAPCertStore.engineInit about to throw " 194 + "InvalidAlgorithmParameterException"); 195 e.printStackTrace(); 196 } 197 Exception ee = new InvalidAlgorithmParameterException 198 ("unable to create InitialDirContext using supplied parameters"); 199 ee.initCause(e); 200 throw (InvalidAlgorithmParameterException)ee; 201 } 202 } 203 204 /** 205 * Private class encapsulating the actual LDAP operations and cache 206 * handling. Use: 207 * 208 * LDAPRequest request = new LDAPRequest(dn); 209 * request.addRequestedAttribute(CROSS_CERT); 210 * request.addRequestedAttribute(CA_CERT); 211 * byte[][] crossValues = request.getValues(CROSS_CERT); 212 * byte[][] caValues = request.getValues(CA_CERT); 213 * 214 * At most one LDAP request is sent for each instance created. If all 215 * getValues() calls can be satisfied from the cache, no request 216 * is sent at all. If a request is sent, all requested attributes 217 * are always added to the cache irrespective of whether the getValues() 218 * method is called. 219 */ 220 private class LDAPRequest { 221 222 private final String name; 223 private Map<String, byte[][]> valueMap; 224 private final List<String> requestedAttributes; 225 226 LDAPRequest(String name) { 227 this.name = name; 228 requestedAttributes = new ArrayList<>(5); 229 } 230 231 String getName() { 232 return name; 233 } 234 235 void addRequestedAttribute(String attrId) { 236 if (valueMap != null) { 237 throw new IllegalStateException("Request already sent"); 238 } 239 requestedAttributes.add(attrId); 240 } 241 242 /** 243 * Gets one or more binary values from an attribute. 244 * 245 * @param name the location holding the attribute 246 * @param attrId the attribute identifier 247 * @return an array of binary values (byte arrays) 248 * @throws NamingException if a naming exception occurs 249 */ 250 byte[][] getValues(String attrId) throws NamingException { 251 if (DEBUG && ((cacheHits + cacheMisses) % 50 == 0)) { 252 System.out.println("Cache hits: " + cacheHits + "; misses: " 253 + cacheMisses); 254 } 255 String cacheKey = name + "|" + attrId; 256 byte[][] values = valueCache.get(cacheKey); 257 if (values != null) { 258 cacheHits++; 259 return values; 260 } 261 cacheMisses++; 262 Map<String, byte[][]> attrs = getValueMap(); 263 values = attrs.get(attrId); 264 return values; 265 } 266 267 /** 268 * Get a map containing the values for this request. The first time 269 * this method is called on an object, the LDAP request is sent, 270 * the results parsed and added to a private map and also to the 271 * cache of this LDAPCertStore. Subsequent calls return the private 272 * map immediately. 273 * 274 * The map contains an entry for each requested attribute. The 275 * attribute name is the key, values are byte[][]. If there are no 276 * values for that attribute, values are byte[0][]. 277 * 278 * @return the value Map 279 * @throws NamingException if a naming exception occurs 280 */ 281 private Map<String, byte[][]> getValueMap() throws NamingException { 282 if (valueMap != null) { 283 return valueMap; 284 } 285 if (DEBUG) { 286 System.out.println("Request: " + name + ":" + requestedAttributes); 287 requests++; 288 if (requests % 5 == 0) { 289 System.out.println("LDAP requests: " + requests); 290 } 291 } 292 valueMap = new HashMap<>(8); 293 String[] attrIds = requestedAttributes.toArray(STRING0); 294 Attributes attrs; 295 296 if (communicationError) { 297 ctx.reconnect(null); 298 communicationError = false; 299 } 300 301 try { 302 attrs = ctx.getAttributes(name, attrIds); 303 } catch (CommunicationException ce) { 304 communicationError = true; 305 throw ce; 306 } catch (NameNotFoundException e) { 307 // name does not exist on this LDAP server 308 // treat same as not attributes found 309 attrs = EMPTY_ATTRIBUTES; 310 } 311 for (String attrId : requestedAttributes) { 312 Attribute attr = attrs.get(attrId); 313 byte[][] values = getAttributeValues(attr); 314 cacheAttribute(attrId, values); 315 valueMap.put(attrId, values); 316 } 317 return valueMap; 318 } 319 320 /** 321 * Add the values to the cache. 322 */ 323 private void cacheAttribute(String attrId, byte[][] values) { 324 String cacheKey = name + "|" + attrId; 325 valueCache.put(cacheKey, values); 326 } 327 328 /** 329 * Get the values for the given attribute. If the attribute is null 330 * or does not contain any values, a zero length byte array is 331 * returned. NOTE that it is assumed that all values are byte arrays. 332 */ 333 private byte[][] getAttributeValues(Attribute attr) 334 throws NamingException { 335 byte[][] values; 336 if (attr == null) { 337 values = BB0; 338 } else { 339 values = new byte[attr.size()][]; 340 int i = 0; 341 NamingEnumeration<?> enum_ = attr.getAll(); 342 while (enum_.hasMore()) { 343 Object obj = enum_.next(); 344 if (debug != null) { 345 if (obj instanceof String) { 346 debug.println("LDAPCertStore.getAttrValues() " 347 + "enum.next is a string!: " + obj); 348 } 349 } 350 byte[] value = (byte[])obj; 351 values[i++] = value; 352 } 353 } 354 return values; 355 } 356 357 } 358 359 /* 360 * Gets certificates from an attribute id and location in the LDAP 361 * directory. Returns a Collection containing only the Certificates that 362 * match the specified CertSelector. 363 * 364 * @param name the location holding the attribute 365 * @param id the attribute identifier 366 * @param sel a CertSelector that the Certificates must match 367 * @return a Collection of Certificates found 368 * @throws CertStoreException if an exception occurs 369 */ 370 private Collection<X509Certificate> getCertificates(LDAPRequest request, 371 String id, X509CertSelector sel) throws CertStoreException { 372 373 /* fetch encoded certs from storage */ 374 byte[][] encodedCert; 375 try { 376 encodedCert = request.getValues(id); 377 } catch (NamingException namingEx) { 378 throw new CertStoreException(namingEx); 379 } 380 381 int n = encodedCert.length; 382 if (n == 0) { 383 return Collections.emptySet(); 384 } 385 386 List<X509Certificate> certs = new ArrayList<>(n); 387 /* decode certs and check if they satisfy selector */ 388 for (int i = 0; i < n; i++) { 389 ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert[i]); 390 try { 391 Certificate cert = cf.generateCertificate(bais); 392 if (sel.match(cert)) { 393 certs.add((X509Certificate)cert); 394 } 395 } catch (CertificateException e) { 396 if (debug != null) { 397 debug.println("LDAPCertStore.getCertificates() encountered " 398 + "exception while parsing cert, skipping the bad data: "); 399 HexDumpEncoder encoder = new HexDumpEncoder(); 400 debug.println( 401 "[ " + encoder.encodeBuffer(encodedCert[i]) + " ]"); 402 } 403 } 404 } 405 406 return certs; 407 } 408 409 /* 410 * Gets certificate pairs from an attribute id and location in the LDAP 411 * directory. 412 * 413 * @param name the location holding the attribute 414 * @param id the attribute identifier 415 * @return a Collection of X509CertificatePairs found 416 * @throws CertStoreException if an exception occurs 417 */ 418 private Collection<X509CertificatePair> getCertPairs( 419 LDAPRequest request, String id) throws CertStoreException { 420 421 /* fetch the encoded cert pairs from storage */ 422 byte[][] encodedCertPair; 423 try { 424 encodedCertPair = request.getValues(id); 425 } catch (NamingException namingEx) { 426 throw new CertStoreException(namingEx); 427 } 428 429 int n = encodedCertPair.length; 430 if (n == 0) { 431 return Collections.emptySet(); 432 } 433 434 List<X509CertificatePair> certPairs = new ArrayList<>(n); 435 /* decode each cert pair and add it to the Collection */ 436 for (int i = 0; i < n; i++) { 437 try { 438 X509CertificatePair certPair = 439 X509CertificatePair.generateCertificatePair(encodedCertPair[i]); 440 certPairs.add(certPair); 441 } catch (CertificateException e) { 442 if (debug != null) { 443 debug.println( 444 "LDAPCertStore.getCertPairs() encountered exception " 445 + "while parsing cert, skipping the bad data: "); 446 HexDumpEncoder encoder = new HexDumpEncoder(); 447 debug.println( 448 "[ " + encoder.encodeBuffer(encodedCertPair[i]) + " ]"); 449 } 450 } 451 } 452 453 return certPairs; 454 } 455 456 /* 457 * Looks at certificate pairs stored in the crossCertificatePair attribute 458 * at the specified location in the LDAP directory. Returns a Collection 459 * containing all X509Certificates stored in the forward component that match 460 * the forward X509CertSelector and all Certificates stored in the reverse 461 * component that match the reverse X509CertSelector. 462 * <p> 463 * If either forward or reverse is null, all certificates from the 464 * corresponding component will be rejected. 465 * 466 * @param name the location to look in 467 * @param forward the forward X509CertSelector (or null) 468 * @param reverse the reverse X509CertSelector (or null) 469 * @return a Collection of X509Certificates found 470 * @throws CertStoreException if an exception occurs 471 */ 472 private Collection<X509Certificate> getMatchingCrossCerts( 473 LDAPRequest request, X509CertSelector forward, 474 X509CertSelector reverse) 475 throws CertStoreException { 476 // Get the cert pairs 477 Collection<X509CertificatePair> certPairs = 478 getCertPairs(request, CROSS_CERT); 479 480 // Find Certificates that match and put them in a list 481 ArrayList<X509Certificate> matchingCerts = new ArrayList<>(); 482 for (X509CertificatePair certPair : certPairs) { 483 X509Certificate cert; 484 if (forward != null) { 485 cert = certPair.getForward(); 486 if ((cert != null) && forward.match(cert)) { 487 matchingCerts.add(cert); 488 } 489 } 490 if (reverse != null) { 491 cert = certPair.getReverse(); 492 if ((cert != null) && reverse.match(cert)) { 493 matchingCerts.add(cert); 494 } 495 } 496 } 497 return matchingCerts; 498 } 499 500 /** 501 * Returns a <code>Collection</code> of <code>X509Certificate</code>s that 502 * match the specified selector. If no <code>X509Certificate</code>s 503 * match the selector, an empty <code>Collection</code> will be returned. 504 * <p> 505 * It is not practical to search every entry in the LDAP database for 506 * matching <code>X509Certificate</code>s. Instead, the 507 * <code>X509CertSelector</code> is examined in order to determine where 508 * matching <code>Certificate</code>s are likely to be found (according 509 * to the PKIX LDAPv2 schema, RFC 2587). 510 * If the subject is specified, its directory entry is searched. If the 511 * issuer is specified, its directory entry is searched. If neither the 512 * subject nor the issuer are specified (or the selector is not an 513 * <code>X509CertSelector</code>), a <code>CertStoreException</code> is 514 * thrown. 515 * 516 * @param selector a <code>X509CertSelector</code> used to select which 517 * <code>Certificate</code>s should be returned. 518 * @return a <code>Collection</code> of <code>X509Certificate</code>s that 519 * match the specified selector 520 * @throws CertStoreException if an exception occurs 521 */ 522 synchronized Collection<X509Certificate> getCertificates 523 (X509CertSelector xsel, String ldapDN) throws CertStoreException { 524 525 if (ldapDN == null) { 526 ldapDN = xsel.getSubjectAsString(); 527 } 528 int basicConstraints = xsel.getBasicConstraints(); 529 String issuer = xsel.getIssuerAsString(); 530 HashSet<X509Certificate> certs = new HashSet<>(); 531 if (debug != null) { 532 debug.println("LDAPCertStore.engineGetCertificates() basicConstraints: " 533 + basicConstraints); 534 } 535 536 // basicConstraints: 537 // -2: only EE certs accepted 538 // -1: no check is done 539 // 0: any CA certificate accepted 540 // >1: certificate's basicConstraints extension pathlen must match 541 if (ldapDN != null) { 542 if (debug != null) { 543 debug.println("LDAPCertStore.engineGetCertificates() " 544 + " subject is not null"); 545 } 546 LDAPRequest request = new LDAPRequest(ldapDN); 547 if (basicConstraints > -2) { 548 request.addRequestedAttribute(CROSS_CERT); 549 request.addRequestedAttribute(CA_CERT); 550 request.addRequestedAttribute(ARL); 551 if (prefetchCRLs) { 552 request.addRequestedAttribute(CRL); 553 } 554 } 555 if (basicConstraints < 0) { 556 request.addRequestedAttribute(USER_CERT); 557 } 558 559 if (basicConstraints > -2) { 560 certs.addAll(getMatchingCrossCerts(request, xsel, null)); 561 if (debug != null) { 562 debug.println("LDAPCertStore.engineGetCertificates() after " 563 + "getMatchingCrossCerts(subject,xsel,null),certs.size(): " 564 + certs.size()); 565 } 566 certs.addAll(getCertificates(request, CA_CERT, xsel)); 567 if (debug != null) { 568 debug.println("LDAPCertStore.engineGetCertificates() after " 569 + "getCertificates(subject,CA_CERT,xsel),certs.size(): " 570 + certs.size()); 571 } 572 } 573 if (basicConstraints < 0) { 574 certs.addAll(getCertificates(request, USER_CERT, xsel)); 575 if (debug != null) { 576 debug.println("LDAPCertStore.engineGetCertificates() after " 577 + "getCertificates(subject,USER_CERT, xsel),certs.size(): " 578 + certs.size()); 579 } 580 } 581 } else { 582 if (debug != null) { 583 debug.println 584 ("LDAPCertStore.engineGetCertificates() subject is null"); 585 } 586 if (basicConstraints == -2) { 587 throw new CertStoreException("need subject to find EE certs"); 588 } 589 if (issuer == null) { 590 throw new CertStoreException("need subject or issuer to find certs"); 591 } 592 } 593 if (debug != null) { 594 debug.println("LDAPCertStore.engineGetCertificates() about to " 595 + "getMatchingCrossCerts..."); 596 } 597 if ((issuer != null) && (basicConstraints > -2)) { 598 LDAPRequest request = new LDAPRequest(issuer); 599 request.addRequestedAttribute(CROSS_CERT); 600 request.addRequestedAttribute(CA_CERT); 601 request.addRequestedAttribute(ARL); 602 if (prefetchCRLs) { 603 request.addRequestedAttribute(CRL); 604 } 605 606 certs.addAll(getMatchingCrossCerts(request, null, xsel)); 607 if (debug != null) { 608 debug.println("LDAPCertStore.engineGetCertificates() after " 609 + "getMatchingCrossCerts(issuer,null,xsel),certs.size(): " 610 + certs.size()); 611 } 612 certs.addAll(getCertificates(request, CA_CERT, xsel)); 613 if (debug != null) { 614 debug.println("LDAPCertStore.engineGetCertificates() after " 615 + "getCertificates(issuer,CA_CERT,xsel),certs.size(): " 616 + certs.size()); 617 } 618 } 619 if (debug != null) { 620 debug.println("LDAPCertStore.engineGetCertificates() returning certs"); 621 } 622 return certs; 623 } 624 625 /* 626 * Gets CRLs from an attribute id and location in the LDAP directory. 627 * Returns a Collection containing only the CRLs that match the 628 * specified X509CRLSelector. 629 * 630 * @param name the location holding the attribute 631 * @param id the attribute identifier 632 * @param sel a X509CRLSelector that the CRLs must match 633 * @return a Collection of CRLs found 634 * @throws CertStoreException if an exception occurs 635 */ 636 private Collection<X509CRL> getCRLs(LDAPRequest request, String id, 637 X509CRLSelector sel) throws CertStoreException { 638 639 /* fetch the encoded crls from storage */ 640 byte[][] encodedCRL; 641 try { 642 encodedCRL = request.getValues(id); 643 } catch (NamingException namingEx) { 644 throw new CertStoreException(namingEx); 645 } 646 647 int n = encodedCRL.length; 648 if (n == 0) { 649 return Collections.emptySet(); 650 } 651 652 List<X509CRL> crls = new ArrayList<>(n); 653 /* decode each crl and check if it matches selector */ 654 for (int i = 0; i < n; i++) { 655 try { 656 CRL crl = cf.generateCRL(new ByteArrayInputStream(encodedCRL[i])); 657 if (sel.match(crl)) { 658 crls.add((X509CRL)crl); 659 } 660 } catch (CRLException e) { 661 if (debug != null) { 662 debug.println("LDAPCertStore.getCRLs() encountered exception" 663 + " while parsing CRL, skipping the bad data: "); 664 HexDumpEncoder encoder = new HexDumpEncoder(); 665 debug.println("[ " + encoder.encodeBuffer(encodedCRL[i]) + " ]"); 666 } 667 } 668 } 669 670 return crls; 671 } 672 673 /** 674 * Returns a <code>Collection</code> of <code>X509CRL</code>s that 675 * match the specified selector. If no <code>X509CRL</code>s 676 * match the selector, an empty <code>Collection</code> will be returned. 677 * <p> 678 * It is not practical to search every entry in the LDAP database for 679 * matching <code>X509CRL</code>s. Instead, the <code>X509CRLSelector</code> 680 * is examined in order to determine where matching <code>X509CRL</code>s 681 * are likely to be found (according to the PKIX LDAPv2 schema, RFC 2587). 682 * If issuerNames or certChecking are specified, the issuer's directory 683 * entry is searched. If neither issuerNames or certChecking are specified 684 * (or the selector is not an <code>X509CRLSelector</code>), a 685 * <code>CertStoreException</code> is thrown. 686 * 687 * @param selector A <code>X509CRLSelector</code> used to select which 688 * <code>CRL</code>s should be returned. Specify <code>null</code> 689 * to return all <code>CRL</code>s. 690 * @return A <code>Collection</code> of <code>X509CRL</code>s that 691 * match the specified selector 692 * @throws CertStoreException if an exception occurs 693 */ 694 synchronized Collection<X509CRL> getCRLs(X509CRLSelector xsel, 695 String ldapDN) throws CertStoreException { 696 697 HashSet<X509CRL> crls = new HashSet<>(); 698 699 // Look in directory entry for issuer of cert we're checking. 700 Collection<Object> issuerNames; 701 X509Certificate certChecking = xsel.getCertificateChecking(); 702 if (certChecking != null) { 703 issuerNames = new HashSet<>(); 704 X500Principal issuer = certChecking.getIssuerX500Principal(); 705 issuerNames.add(issuer.getName(X500Principal.RFC2253)); 706 } else { 707 // But if we don't know which cert we're checking, try the directory 708 // entries of all acceptable CRL issuers 709 if (ldapDN != null) { 710 issuerNames = new HashSet<>(); 711 issuerNames.add(ldapDN); 712 } else { 713 issuerNames = xsel.getIssuerNames(); 714 if (issuerNames == null) { 715 throw new CertStoreException("need issuerNames or" 716 + " certChecking to find CRLs"); 717 } 718 } 719 } 720 for (Object nameObject : issuerNames) { 721 String issuerName; 722 if (nameObject instanceof byte[]) { 723 try { 724 X500Principal issuer = new X500Principal((byte[])nameObject); 725 issuerName = issuer.getName(X500Principal.RFC2253); 726 } catch (IllegalArgumentException e) { 727 continue; 728 } 729 } else { 730 issuerName = (String)nameObject; 731 } 732 // If all we want is CA certs, try to get the (probably shorter) ARL 733 Collection<X509CRL> entryCRLs = Collections.emptySet(); 734 if (certChecking == null || certChecking.getBasicConstraints() != -1) { 735 LDAPRequest request = new LDAPRequest(issuerName); 736 request.addRequestedAttribute(CROSS_CERT); 737 request.addRequestedAttribute(CA_CERT); 738 request.addRequestedAttribute(ARL); 739 if (prefetchCRLs) { 740 request.addRequestedAttribute(CRL); 741 } 742 try { 743 entryCRLs = getCRLs(request, ARL, xsel); 744 if (entryCRLs.isEmpty()) { 745 // no ARLs found. We assume that means that there are 746 // no ARLs on this server at all and prefetch the CRLs. 747 prefetchCRLs = true; 748 } else { 749 crls.addAll(entryCRLs); 750 } 751 } catch (CertStoreException e) { 752 if (debug != null) { 753 debug.println("LDAPCertStore.engineGetCRLs non-fatal error " 754 + "retrieving ARLs:" + e); 755 e.printStackTrace(); 756 } 757 } 758 } 759 // Otherwise, get the CRL 760 // if certChecking is null, we don't know if we should look in ARL or CRL 761 // attribute, so check both for matching CRLs. 762 if (entryCRLs.isEmpty() || certChecking == null) { 763 LDAPRequest request = new LDAPRequest(issuerName); 764 request.addRequestedAttribute(CRL); 765 entryCRLs = getCRLs(request, CRL, xsel); 766 crls.addAll(entryCRLs); 767 } 768 } 769 return crls; 770 } 771} 772