blob: fa0d462449a002de7e060596204b5791998740fa [file] [log] [blame]
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);
}
}
}
}
}