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