Showing the changes to java/pkg/sun/security/provider/certpath/IndexedCollectionCertStore.java (1 of 18352 files). Show all
Unified · Split
| @@ -0,0 +1,411 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2002, 2006, 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.provider.certpath; | ||
| 27 | |||
| 28 | import java.util.*; | ||
| 29 | |||
| 30 | import java.security.InvalidAlgorithmParameterException; | ||
| 31 | import java.security.cert.*; | ||
| 32 | |||
| 33 | import javax.security.auth.x500.X500Principal; | ||
| 34 | |||
| 35 | /** | ||
| 36 | * A <code>CertStore</code> that retrieves <code>Certificates</code> and | ||
| 37 | * <code>CRL</code>s from a <code>Collection</code>. | ||
| 38 | * <p> | ||
| 39 | * This implementation is functionally equivalent to CollectionCertStore | ||
| 40 | * with two differences: | ||
| 41 | * <ol> | ||
| 42 | * <li>Upon construction, the elements in the specified Collection are | ||
| 43 | * partially indexed. X509Certificates are indexed by subject, X509CRLs | ||
| 44 | * by issuer, non-X509 Certificates and CRLs are copied without indexing, | ||
| 45 | * other objects are ignored. This increases CertStore construction time | ||
| 46 | * but allows significant speedups for searches which specify the indexed | ||
| 47 | * attributes, in particular for large Collections (reduction from linear | ||
| 48 | * time to effectively constant time). Searches for non-indexed queries | ||
| 49 | * are as fast (or marginally faster) than for the standard | ||
| 50 | * CollectionCertStore. Certificate subjects and CRL issuers | ||
| 51 | * were found to be specified in most searches used internally by the | ||
| 52 | * CertPath provider. Additional attributes could indexed if there are | ||
| 53 | * queries that justify the effort. | ||
| 54 | * | ||
| 55 | * <li>Changes to the specified Collection after construction time are | ||
| 56 | * not detected and ignored. This is because there is no way to efficiently | ||
| 57 | * detect if a Collection has been modified, a full traversal would be | ||
| 58 | * required. That would degrade lookup performance to linear time and | ||
| 59 | * eliminated the benefit of indexing. We may fix this via the introduction | ||
| 60 | * of new public APIs in the future. | ||
| 61 | * </ol> | ||
| 62 | * <p> | ||
| 63 | * Before calling the {@link #engineGetCertificates engineGetCertificates} or | ||
| 64 | * {@link #engineGetCRLs engineGetCRLs} methods, the | ||
| 65 | * {@link #CollectionCertStore(CertStoreParameters) | ||
| 66 | * CollectionCertStore(CertStoreParameters)} constructor is called to | ||
| 67 | * create the <code>CertStore</code> and establish the | ||
| 68 | * <code>Collection</code> from which <code>Certificate</code>s and | ||
| 69 | * <code>CRL</code>s will be retrieved. If the specified | ||
| 70 | * <code>Collection</code> contains an object that is not a | ||
| 71 | * <code>Certificate</code> or <code>CRL</code>, that object will be | ||
| 72 | * ignored. | ||
| 73 | * <p> | ||
| 74 | * <b>Concurrent Access</b> | ||
| 75 | * <p> | ||
| 76 | * As described in the javadoc for <code>CertStoreSpi</code>, the | ||
| 77 | * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods | ||
| 78 | * must be thread-safe. That is, multiple threads may concurrently | ||
| 79 | * invoke these methods on a single <code>CollectionCertStore</code> | ||
| 80 | * object (or more than one) with no ill effects. | ||
| 81 | * <p> | ||
| 82 | * This is achieved by requiring that the <code>Collection</code> passed to | ||
| 83 | * the {@link #CollectionCertStore(CertStoreParameters) | ||
| 84 | * CollectionCertStore(CertStoreParameters)} constructor (via the | ||
| 85 | * <code>CollectionCertStoreParameters</code> object) must have fail-fast | ||
| 86 | * iterators. Simultaneous modifications to the <code>Collection</code> can thus be | ||
| 87 | * detected and certificate or CRL retrieval can be retried. The fact that | ||
| 88 | * <code>Certificate</code>s and <code>CRL</code>s must be thread-safe is also | ||
| 89 | * essential. | ||
| 90 | * | ||
| 91 | * @see java.security.cert.CertStore | ||
| 92 | * @see CollectionCertStore | ||
| 93 | * | ||
| 94 | * @author Andreas Sterbenz | ||
| 95 | */ | ||
| 96 | public class IndexedCollectionCertStore extends CertStoreSpi { | ||
| 97 | |||
| 98 | /** | ||
| 99 | * Map X500Principal(subject) -> X509Certificate | List of X509Certificate | ||
| 100 | */ | ||
| 101 | private Map<X500Principal, Object> certSubjects; | ||
| 102 | /** | ||
| 103 | * Map X500Principal(issuer) -> X509CRL | List of X509CRL | ||
| 104 | */ | ||
| 105 | private Map<X500Principal, Object> crlIssuers; | ||
| 106 | /** | ||
| 107 | * Sets of non-X509 certificates and CRLs | ||
| 108 | */ | ||
| 109 | private Set<Certificate> otherCertificates; | ||
| 110 | private Set<CRL> otherCRLs; | ||
| 111 | |||
| 112 | /** | ||
| 113 | * Creates a <code>CertStore</code> with the specified parameters. | ||
| 114 | * For this class, the parameters object must be an instance of | ||
| 115 | * <code>CollectionCertStoreParameters</code>. | ||
| 116 | * | ||
| 117 | * @param params the algorithm parameters | ||
| 118 | * @exception InvalidAlgorithmParameterException if params is not an | ||
| 119 | * instance of <code>CollectionCertStoreParameters</code> | ||
| 120 | */ | ||
| 121 | public IndexedCollectionCertStore(CertStoreParameters params) | ||
| 122 | throws InvalidAlgorithmParameterException { | ||
| 123 | super(params); | ||
| 124 | if (!(params instanceof CollectionCertStoreParameters)) { | ||
| 125 | throw new InvalidAlgorithmParameterException( | ||
| 126 | "parameters must be CollectionCertStoreParameters"); | ||
| 127 | } | ||
| 128 | Collection<?> coll = ((CollectionCertStoreParameters)params).getCollection(); | ||
| 129 | if (coll == null) { | ||
| 130 | throw new InvalidAlgorithmParameterException | ||
| 131 | ("Collection must not be null"); | ||
| 132 | } | ||
| 133 | buildIndex(coll); | ||
| 134 | } | ||
| 135 | |||
| 136 | /** | ||
| 137 | * Index the specified Collection copying all references to Certificates | ||
| 138 | * and CRLs. | ||
| 139 | */ | ||
| 140 | private void buildIndex(Collection<?> coll) { | ||
| 141 | certSubjects = new HashMap<X500Principal, Object>(); | ||
| 142 | crlIssuers = new HashMap<X500Principal, Object>(); | ||
| 143 | otherCertificates = null; | ||
| 144 | otherCRLs = null; | ||
| 145 | for (Object obj : coll) { | ||
| 146 | if (obj instanceof X509Certificate) { | ||
| 147 | indexCertificate((X509Certificate)obj); | ||
| 148 | } else if (obj instanceof X509CRL) { | ||
| 149 | indexCRL((X509CRL)obj); | ||
| 150 | } else if (obj instanceof Certificate) { | ||
| 151 | if (otherCertificates == null) { | ||
| 152 | otherCertificates = new HashSet<Certificate>(); | ||
| 153 | } | ||
| 154 | otherCertificates.add((Certificate)obj); | ||
| 155 | } else if (obj instanceof CRL) { | ||
| 156 | if (otherCRLs == null) { | ||
| 157 | otherCRLs = new HashSet<CRL>(); | ||
| 158 | } | ||
| 159 | otherCRLs.add((CRL)obj); | ||
| 160 | } else { | ||
| 161 | // ignore | ||
| 162 | } | ||
| 163 | } | ||
| 164 | if (otherCertificates == null) { | ||
| 165 | otherCertificates = Collections.<Certificate>emptySet(); | ||
| 166 | } | ||
| 167 | if (otherCRLs == null) { | ||
| 168 | otherCRLs = Collections.<CRL>emptySet(); | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | /** | ||
| 173 | * Add an X509Certificate to the index. | ||
| 174 | */ | ||
| 175 | private void indexCertificate(X509Certificate cert) { | ||
| 176 | X500Principal subject = cert.getSubjectX500Principal(); | ||
| 177 | Object oldEntry = certSubjects.put(subject, cert); | ||
| 178 | if (oldEntry != null) { // assume this is unlikely | ||
| 179 | if (oldEntry instanceof X509Certificate) { | ||
| 180 | if (cert.equals(oldEntry)) { | ||
| 181 | return; | ||
| 182 | } | ||
| 183 | List<X509Certificate> list = new ArrayList<X509Certificate>(2); | ||
| 184 | list.add(cert); | ||
| 185 | list.add((X509Certificate)oldEntry); | ||
| 186 | certSubjects.put(subject, list); | ||
| 187 | } else { | ||
| 188 | List<X509Certificate> list = (List<X509Certificate>)oldEntry; | ||
| 189 | if (list.contains(cert) == false) { | ||
| 190 | list.add(cert); | ||
| 191 | } | ||
| 192 | certSubjects.put(subject, list); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | /** | ||
| 198 | * Add an X509CRL to the index. | ||
| 199 | */ | ||
| 200 | private void indexCRL(X509CRL crl) { | ||
| 201 | X500Principal issuer = crl.getIssuerX500Principal(); | ||
| 202 | Object oldEntry = crlIssuers.put(issuer, crl); | ||
| 203 | if (oldEntry != null) { // assume this is unlikely | ||
| 204 | if (oldEntry instanceof X509CRL) { | ||
| 205 | if (crl.equals(oldEntry)) { | ||
| 206 | return; | ||
| 207 | } | ||
| 208 | List<X509CRL> list = new ArrayList<X509CRL>(2); | ||
| 209 | list.add(crl); | ||
| 210 | list.add((X509CRL)oldEntry); | ||
| 211 | crlIssuers.put(issuer, list); | ||
| 212 | } else { | ||
| 213 | List<X509CRL> list = (List<X509CRL>)oldEntry; | ||
| 214 | if (list.contains(crl) == false) { | ||
| 215 | list.add(crl); | ||
| 216 | } | ||
| 217 | crlIssuers.put(issuer, list); | ||
| 218 | } | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 222 | /** | ||
| 223 | * Returns a <code>Collection</code> of <code>Certificate</code>s that | ||
| 224 | * match the specified selector. If no <code>Certificate</code>s | ||
| 225 | * match the selector, an empty <code>Collection</code> will be returned. | ||
| 226 | * | ||
| 227 | * @param selector a <code>CertSelector</code> used to select which | ||
| 228 | * <code>Certificate</code>s should be returned. Specify <code>null</code> | ||
| 229 | * to return all <code>Certificate</code>s. | ||
| 230 | * @return a <code>Collection</code> of <code>Certificate</code>s that | ||
| 231 | * match the specified selector | ||
| 232 | * @throws CertStoreException if an exception occurs | ||
| 233 | */ | ||
| 234 | public Collection<? extends Certificate> engineGetCertificates(CertSelector selector) | ||
| 235 | throws CertStoreException { | ||
| 236 | |||
| 237 | // no selector means match all | ||
| 238 | if (selector == null) { | ||
| 239 | Set<Certificate> matches = new HashSet<Certificate>(); | ||
| 240 | matchX509Certs(new X509CertSelector(), matches); | ||
| 241 | matches.addAll(otherCertificates); | ||
| 242 | return matches; | ||
| 243 | } | ||
| 244 | |||
| 245 | if (selector instanceof X509CertSelector == false) { | ||
| 246 | Set<Certificate> matches = new HashSet<Certificate>(); | ||
| 247 | matchX509Certs(selector, matches); | ||
| 248 | for (Certificate cert : otherCertificates) { | ||
| 249 | if (selector.match(cert)) { | ||
| 250 | matches.add(cert); | ||
| 251 | } | ||
| 252 | } | ||
| 253 | return matches; | ||
| 254 | } | ||
| 255 | |||
| 256 | if (certSubjects.isEmpty()) { | ||
| 257 | return Collections.<X509Certificate>emptySet(); | ||
| 258 | } | ||
| 259 | X509CertSelector x509Selector = (X509CertSelector)selector; | ||
| 260 | // see if the subject is specified | ||
| 261 | X500Principal subject; | ||
| 262 | X509Certificate matchCert = x509Selector.getCertificate(); | ||
| 263 | if (matchCert != null) { | ||
| 264 | subject = matchCert.getSubjectX500Principal(); | ||
| 265 | } else { | ||
| 266 | subject = x509Selector.getSubject(); | ||
| 267 | } | ||
| 268 | if (subject != null) { | ||
| 269 | // yes, narrow down candidates to indexed possibilities | ||
| 270 | Object entry = certSubjects.get(subject); | ||
| 271 | if (entry == null) { | ||
| 272 | return Collections.<X509Certificate>emptySet(); | ||
| 273 | } | ||
| 274 | if (entry instanceof X509Certificate) { | ||
| 275 | X509Certificate x509Entry = (X509Certificate)entry; | ||
| 276 | if (x509Selector.match(x509Entry)) { | ||
| 277 | return Collections.singleton(x509Entry); | ||
| 278 | } else { | ||
| 279 | return Collections.<X509Certificate>emptySet(); | ||
| 280 | } | ||
| 281 | } else { | ||
| 282 | List<X509Certificate> list = (List<X509Certificate>)entry; | ||
| 283 | Set<X509Certificate> matches = new HashSet<X509Certificate>(16); | ||
| 284 | for (X509Certificate cert : list) { | ||
| 285 | if (x509Selector.match(cert)) { | ||
| 286 | matches.add(cert); | ||
| 287 | } | ||
| 288 | } | ||
| 289 | return matches; | ||
| 290 | } | ||
| 291 | } | ||
| 292 | // cannot use index, iterate all | ||
| 293 | Set<Certificate> matches = new HashSet<Certificate>(16); | ||
| 294 | matchX509Certs(x509Selector, matches); | ||
| 295 | return matches; | ||
| 296 | } | ||
| 297 | |||
| 298 | /** | ||
| 299 | * Iterate through all the X509Certificates and add matches to the | ||
| 300 | * collection. | ||
| 301 | */ | ||
| 302 | private void matchX509Certs(CertSelector selector, | ||
| 303 | Collection<Certificate> matches) { | ||
| 304 | |||
| 305 | for (Object obj : certSubjects.values()) { | ||
| 306 | if (obj instanceof X509Certificate) { | ||
| 307 | X509Certificate cert = (X509Certificate)obj; | ||
| 308 | if (selector.match(cert)) { | ||
| 309 | matches.add(cert); | ||
| 310 | } | ||
| 311 | } else { | ||
| 312 | List<X509Certificate> list = (List<X509Certificate>)obj; | ||
| 313 | for (X509Certificate cert : list) { | ||
| 314 | if (selector.match(cert)) { | ||
| 315 | matches.add(cert); | ||
| 316 | } | ||
| 317 | } | ||
| 318 | } | ||
| 319 | } | ||
| 320 | } | ||
| 321 | |||
| 322 | /** | ||
| 323 | * Returns a <code>Collection</code> of <code>CRL</code>s that | ||
| 324 | * match the specified selector. If no <code>CRL</code>s | ||
| 325 | * match the selector, an empty <code>Collection</code> will be returned. | ||
| 326 | * | ||
| 327 | * @param selector a <code>CRLSelector</code> used to select which | ||
| 328 | * <code>CRL</code>s should be returned. Specify <code>null</code> | ||
| 329 | * to return all <code>CRL</code>s. | ||
| 330 | * @return a <code>Collection</code> of <code>CRL</code>s that | ||
| 331 | * match the specified selector | ||
| 332 | * @throws CertStoreException if an exception occurs | ||
| 333 | */ | ||
| 334 | public Collection<CRL> engineGetCRLs(CRLSelector selector) | ||
| 335 | throws CertStoreException { | ||
| 336 | |||
| 337 | if (selector == null) { | ||
| 338 | Set<CRL> matches = new HashSet<CRL>(); | ||
| 339 | matchX509CRLs(new X509CRLSelector(), matches); | ||
| 340 | matches.addAll(otherCRLs); | ||
| 341 | return matches; | ||
| 342 | } | ||
| 343 | |||
| 344 | if (selector instanceof X509CRLSelector == false) { | ||
| 345 | Set<CRL> matches = new HashSet<CRL>(); | ||
| 346 | matchX509CRLs(selector, matches); | ||
| 347 | for (CRL crl : otherCRLs) { | ||
| 348 | if (selector.match(crl)) { | ||
| 349 | matches.add(crl); | ||
| 350 | } | ||
| 351 | } | ||
| 352 | return matches; | ||
| 353 | } | ||
| 354 | |||
| 355 | if (crlIssuers.isEmpty()) { | ||
| 356 | return Collections.<CRL>emptySet(); | ||
| 357 | } | ||
| 358 | X509CRLSelector x509Selector = (X509CRLSelector)selector; | ||
| 359 | // see if the issuer is specified | ||
| 360 | Collection<X500Principal> issuers = x509Selector.getIssuers(); | ||
| 361 | if (issuers != null) { | ||
| 362 | HashSet<CRL> matches = new HashSet<CRL>(16); | ||
| 363 | for (X500Principal issuer : issuers) { | ||
| 364 | Object entry = crlIssuers.get(issuer); | ||
| 365 | if (entry == null) { | ||
| 366 | // empty | ||
| 367 | } else if (entry instanceof X509CRL) { | ||
| 368 | X509CRL crl = (X509CRL)entry; | ||
| 369 | if (x509Selector.match(crl)) { | ||
| 370 | matches.add(crl); | ||
| 371 | } | ||
| 372 | } else { // List | ||
| 373 | List<X509CRL> list = (List<X509CRL>)entry; | ||
| 374 | for (X509CRL crl : list) { | ||
| 375 | if (x509Selector.match(crl)) { | ||
| 376 | matches.add(crl); | ||
| 377 | } | ||
| 378 | } | ||
| 379 | } | ||
| 380 | } | ||
| 381 | return matches; | ||
| 382 | } | ||
| 383 | // cannot use index, iterate all | ||
| 384 | Set<CRL> matches = new HashSet<CRL>(16); | ||
| 385 | matchX509CRLs(x509Selector, matches); | ||
| 386 | return matches; | ||
| 387 | } | ||
| 388 | |||
| 389 | /** | ||
| 390 | * Iterate through all the X509CRLs and add matches to the | ||
| 391 | * collection. | ||
| 392 | */ | ||
| 393 | private void matchX509CRLs(CRLSelector selector, Collection<CRL> matches) { | ||
| 394 | for (Object obj : crlIssuers.values()) { | ||
| 395 | if (obj instanceof X509CRL) { | ||
| 396 | X509CRL crl = (X509CRL)obj; | ||
| 397 | if (selector.match(crl)) { | ||
| 398 | matches.add(crl); | ||
| 399 | } | ||
| 400 | } else { | ||
| 401 | List<X509CRL> list = (List<X509CRL>)obj; | ||
| 402 | for (X509CRL crl : list) { | ||
| 403 | if (selector.match(crl)) { | ||
| 404 | matches.add(crl); | ||
| 405 | } | ||
| 406 | } | ||
| 407 | } | ||
| 408 | } | ||
| 409 | } | ||
| 410 | |||
| 411 | } | ||