| package org.bouncycastle.cert.dane.fetcher; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import javax.naming.Binding; |
| import javax.naming.Context; |
| import javax.naming.NamingEnumeration; |
| import javax.naming.NamingException; |
| import javax.naming.directory.Attribute; |
| import javax.naming.directory.Attributes; |
| import javax.naming.directory.DirContext; |
| import javax.naming.directory.InitialDirContext; |
| |
| import org.bouncycastle.cert.dane.DANEEntry; |
| import org.bouncycastle.cert.dane.DANEEntryFetcher; |
| import org.bouncycastle.cert.dane.DANEEntryFetcherFactory; |
| import org.bouncycastle.cert.dane.DANEException; |
| |
| /** |
| * A DANE entry fetcher implemented using JNDI. |
| */ |
| public class JndiDANEFetcherFactory |
| implements DANEEntryFetcherFactory |
| { |
| private static final String DANE_TYPE = "53"; |
| |
| private List dnsServerList = new ArrayList(); |
| private boolean isAuthoritative; |
| |
| /** |
| * Specify the dnsServer to use. |
| * |
| * @param dnsServer IP address/name of the dns server |
| * @return the current factory. |
| */ |
| public JndiDANEFetcherFactory usingDNSServer(String dnsServer) |
| { |
| this.dnsServerList.add(dnsServer); |
| |
| return this; |
| } |
| |
| /** |
| * Specify requests must be authoritative, or not (default false). |
| * |
| * @param isAuthoritative true if requests must be authoritative, false otherwise. |
| * @return the current factory.. |
| */ |
| public JndiDANEFetcherFactory setAuthoritative(boolean isAuthoritative) |
| { |
| this.isAuthoritative = isAuthoritative; |
| |
| return this; |
| } |
| |
| /** |
| * Build an entry fetcher for the specified domain name. |
| * |
| * @param domainName the domain name of interest. |
| * @return a resolver for fetching entry's associated with domainName. |
| */ |
| public DANEEntryFetcher build(final String domainName) |
| { |
| final Hashtable env = new Hashtable(); |
| |
| env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.dns.DnsContextFactory"); |
| env.put(Context.AUTHORITATIVE, isAuthoritative ? "true" : "false"); // JDK compatibility |
| |
| if (dnsServerList.size() > 0) |
| { |
| StringBuffer dnsServers = new StringBuffer(); |
| |
| for (Iterator it = dnsServerList.iterator(); it.hasNext(); ) |
| { |
| if (dnsServers.length() > 0) |
| { |
| dnsServers.append(" "); |
| } |
| dnsServers.append("dns://" + it.next()); |
| } |
| |
| env.put(Context.PROVIDER_URL, dnsServers.toString()); |
| } |
| |
| return new DANEEntryFetcher() |
| { |
| public List getEntries() |
| throws DANEException |
| { |
| List entries = new ArrayList(); |
| |
| try |
| { |
| DirContext ctx = new InitialDirContext(env); |
| |
| NamingEnumeration bindings; |
| if (domainName.indexOf("_smimecert.") > 0) |
| { |
| // need to use fully qualified domain name if using named DNS server. |
| Attributes attrs = ctx.getAttributes(domainName, new String[]{DANE_TYPE}); |
| Attribute smimeAttr = attrs.get(DANE_TYPE); |
| |
| if (smimeAttr != null) |
| { |
| addEntries(entries, domainName, smimeAttr); |
| } |
| } |
| else |
| { |
| bindings = ctx.listBindings("_smimecert." + domainName); |
| |
| while (bindings.hasMore()) |
| { |
| Binding b = (Binding)bindings.next(); |
| |
| DirContext sc = (DirContext)b.getObject(); |
| |
| String name = sc.getNameInNamespace().substring(1, sc.getNameInNamespace().length() - 1); |
| |
| // need to use fully qualified domain name if using named DNS server. |
| Attributes attrs = ctx.getAttributes(name, new String[]{DANE_TYPE}); |
| Attribute smimeAttr = attrs.get(DANE_TYPE); |
| |
| if (smimeAttr != null) |
| { |
| String fullName = sc.getNameInNamespace(); |
| String domainName = fullName.substring(1, fullName.length() - 1); |
| |
| addEntries(entries, domainName, smimeAttr); |
| } |
| } |
| } |
| |
| return entries; |
| } |
| catch (NamingException e) |
| { |
| throw new DANEException("Exception dealing with DNS: " + e.getMessage(), e); |
| } |
| } |
| }; |
| } |
| |
| private void addEntries(List entries, String domainName, Attribute smimeAttr) |
| throws NamingException, DANEException |
| { |
| for (int index = 0; index != smimeAttr.size(); index++) |
| { |
| byte[] data = (byte[])smimeAttr.get(index); |
| |
| if (DANEEntry.isValidCertificate(data)) |
| { |
| try |
| { |
| entries.add(new DANEEntry(domainName, data)); |
| } |
| catch (IOException e) |
| { |
| throw new DANEException("Exception parsing entry: " + e.getMessage(), e); |
| } |
| } |
| } |
| } |
| } |