1 package org.bouncycastle.jce.provider; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.lang.ref.WeakReference; 7 import java.net.HttpURLConnection; 8 import java.net.URI; 9 import java.security.cert.CRL; 10 import java.security.cert.CRLException; 11 import java.security.cert.CertificateFactory; 12 import java.security.cert.X509CRL; 13 import java.util.ArrayList; 14 import java.util.Collection; 15 import java.util.Collections; 16 import java.util.Date; 17 import java.util.Hashtable; 18 import java.util.Iterator; 19 import java.util.List; 20 import java.util.Map; 21 import java.util.WeakHashMap; 22 23 import javax.naming.Context; 24 import javax.naming.NamingException; 25 import javax.naming.directory.Attribute; 26 import javax.naming.directory.Attributes; 27 import javax.naming.directory.DirContext; 28 import javax.naming.directory.InitialDirContext; 29 30 import org.bouncycastle.jcajce.PKIXCRLStore; 31 import org.bouncycastle.util.CollectionStore; 32 import org.bouncycastle.util.Iterable; 33 import org.bouncycastle.util.Selector; 34 import org.bouncycastle.util.Store; 35 36 class CrlCache 37 { 38 private static final int DEFAULT_TIMEOUT = 15000; 39 40 private static Map cache = 41 Collections.synchronizedMap(new WeakHashMap()); 42 getCrl(CertificateFactory certFact, Date validDate, URI distributionPoint)43 static synchronized PKIXCRLStore getCrl(CertificateFactory certFact, Date validDate, URI distributionPoint) 44 throws IOException, CRLException 45 { 46 PKIXCRLStore crlStore = null; 47 48 WeakReference markerRef = (WeakReference)cache.get(distributionPoint); 49 if (markerRef != null) 50 { 51 crlStore = (PKIXCRLStore)markerRef.get(); 52 } 53 54 if (crlStore != null) 55 { 56 boolean isExpired = false; 57 for (Iterator it = crlStore.getMatches(null).iterator(); it.hasNext();) 58 { 59 X509CRL crl = (X509CRL)it.next(); 60 61 Date nextUpdate = crl.getNextUpdate(); 62 if (nextUpdate != null && nextUpdate.before(validDate)) 63 { 64 isExpired = true; 65 break; 66 } 67 } 68 69 if (!isExpired) 70 { 71 return crlStore; 72 } 73 } 74 75 Collection crls; 76 77 if (distributionPoint.getScheme().equals("ldap")) 78 { 79 crls = getCrlsFromLDAP(certFact, distributionPoint); 80 } 81 else 82 { 83 // http, https, ftp 84 crls = getCrls(certFact, distributionPoint); 85 } 86 87 LocalCRLStore localCRLStore = new LocalCRLStore(new CollectionStore<CRL>(crls)); 88 89 cache.put(distributionPoint, new WeakReference<PKIXCRLStore>(localCRLStore)); 90 91 return localCRLStore; 92 } 93 getCrlsFromLDAP(CertificateFactory certFact, URI distributionPoint)94 private static Collection getCrlsFromLDAP(CertificateFactory certFact, URI distributionPoint) 95 throws IOException, CRLException 96 { 97 Map<String, String> env = new Hashtable<String, String>(); 98 99 env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 100 env.put(Context.PROVIDER_URL, distributionPoint.toString()); 101 102 byte[] val = null; 103 try 104 { 105 DirContext ctx = new InitialDirContext((Hashtable)env); 106 Attributes avals = ctx.getAttributes(""); 107 Attribute aval = avals.get("certificateRevocationList;binary"); 108 val = (byte[])aval.get(); 109 } 110 catch (NamingException e) 111 { 112 throw new CRLException("issue connecting to: " + distributionPoint.toString()); 113 } 114 115 if ((val == null) || (val.length == 0)) 116 { 117 throw new CRLException("no CRL returned from: " + distributionPoint); 118 } 119 else 120 { 121 return certFact.generateCRLs(new ByteArrayInputStream(val)); 122 } 123 } 124 getCrls(CertificateFactory certFact, URI distributionPoint)125 private static Collection getCrls(CertificateFactory certFact, URI distributionPoint) 126 throws IOException, CRLException 127 { 128 HttpURLConnection crlCon = (HttpURLConnection)distributionPoint.toURL().openConnection(); 129 // crlCon.setConnectTimeout(DEFAULT_TIMEOUT); 130 // crlCon.setReadTimeout(DEFAULT_TIMEOUT); 131 132 InputStream crlIn = crlCon.getInputStream(); 133 134 Collection crls = certFact.generateCRLs(crlIn); 135 136 crlIn.close(); 137 138 return crls; 139 } 140 141 private static class LocalCRLStore<T extends CRL> 142 implements PKIXCRLStore, Iterable<CRL> 143 { 144 private Collection<CRL> _local; 145 146 /** 147 * Basic constructor. 148 * 149 * @param collection - initial contents for the store, this is copied. 150 */ LocalCRLStore( Store<CRL> collection)151 public LocalCRLStore( 152 Store<CRL> collection) 153 { 154 _local = new ArrayList<CRL>(collection.getMatches(null)); 155 } 156 157 /** 158 * Return the matches in the collection for the passed in selector. 159 * 160 * @param selector the selector to match against. 161 * @return a possibly empty collection of matching objects. 162 */ getMatches(Selector selector)163 public Collection getMatches(Selector selector) 164 { 165 if (selector == null) 166 { 167 return new ArrayList<CRL>(_local); 168 } 169 else 170 { 171 List<CRL> col = new ArrayList<CRL>(); 172 Iterator<CRL> iter = _local.iterator(); 173 174 while (iter.hasNext()) 175 { 176 CRL obj = (CRL)iter.next(); 177 178 if (selector.match(obj)) 179 { 180 col.add(obj); 181 } 182 } 183 184 return col; 185 } 186 } 187 iterator()188 public Iterator<CRL> iterator() 189 { 190 return getMatches(null).iterator(); 191 } 192 } 193 } 194