diff options
Diffstat (limited to 'prov/src/main/java/org/spongycastle/jce/provider/X509LDAPCertStoreSpi.java')
-rw-r--r-- | prov/src/main/java/org/spongycastle/jce/provider/X509LDAPCertStoreSpi.java | 477 |
1 files changed, 477 insertions, 0 deletions
diff --git a/prov/src/main/java/org/spongycastle/jce/provider/X509LDAPCertStoreSpi.java b/prov/src/main/java/org/spongycastle/jce/provider/X509LDAPCertStoreSpi.java new file mode 100644 index 00000000..3f629eca --- /dev/null +++ b/prov/src/main/java/org/spongycastle/jce/provider/X509LDAPCertStoreSpi.java @@ -0,0 +1,477 @@ +package org.spongycastle.jce.provider; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.cert.CRL; +import java.security.cert.CRLSelector; +import java.security.cert.CertSelector; +import java.security.cert.CertStoreException; +import java.security.cert.CertStoreParameters; +import java.security.cert.CertStoreSpi; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509CRLSelector; +import java.security.cert.X509CertSelector; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; +import java.util.Set; + +import javax.naming.Context; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; +import javax.naming.directory.SearchControls; +import javax.naming.directory.SearchResult; +import javax.security.auth.x500.X500Principal; + +import org.spongycastle.asn1.ASN1InputStream; +import org.spongycastle.asn1.x509.CertificatePair; +import org.spongycastle.jce.X509LDAPCertStoreParameters; + +/** + * + * This is a general purpose implementation to get X.509 certificates and CRLs + * from a LDAP location. + * <p> + * At first a search is performed in the ldap*AttributeNames of the + * {@link org.spongycastle.jce.X509LDAPCertStoreParameters} with the given + * information of the subject (for all kind of certificates) or issuer (for + * CRLs), respectively, if a X509CertSelector is given with that details. For + * CRLs, CA certificates and cross certificates a coarse search is made only for + * entries with that content to get more possibly matchign results. + */ +public class X509LDAPCertStoreSpi + extends CertStoreSpi +{ + private X509LDAPCertStoreParameters params; + + public X509LDAPCertStoreSpi(CertStoreParameters params) + throws InvalidAlgorithmParameterException + { + super(params); + + if (!(params instanceof X509LDAPCertStoreParameters)) + { + throw new InvalidAlgorithmParameterException( + X509LDAPCertStoreSpi.class.getName() + ": parameter must be a " + X509LDAPCertStoreParameters.class.getName() + " object\n" + + params.toString()); + } + + this.params = (X509LDAPCertStoreParameters)params; + } + + /** + * Initial Context Factory. + */ + private static String LDAP_PROVIDER = "com.sun.jndi.ldap.LdapCtxFactory"; + + /** + * Processing referrals.. + */ + private static String REFERRALS_IGNORE = "ignore"; + + /** + * Security level to be used for LDAP connections. + */ + private static final String SEARCH_SECURITY_LEVEL = "none"; + + /** + * Package Prefix for loading URL context factories. + */ + private static final String URL_CONTEXT_PREFIX = "com.sun.jndi.url"; + + private DirContext connectLDAP() throws NamingException + { + Properties props = new Properties(); + props.setProperty(Context.INITIAL_CONTEXT_FACTORY, LDAP_PROVIDER); + props.setProperty(Context.BATCHSIZE, "0"); + + props.setProperty(Context.PROVIDER_URL, params.getLdapURL()); + props.setProperty(Context.URL_PKG_PREFIXES, URL_CONTEXT_PREFIX); + props.setProperty(Context.REFERRAL, REFERRALS_IGNORE); + props.setProperty(Context.SECURITY_AUTHENTICATION, + SEARCH_SECURITY_LEVEL); + + DirContext ctx = new InitialDirContext(props); + return ctx; + } + + private String parseDN(String subject, String subjectAttributeName) + { + String temp = subject; + int begin = temp.toLowerCase().indexOf( + subjectAttributeName.toLowerCase()); + temp = temp.substring(begin + subjectAttributeName.length()); + int end = temp.indexOf(','); + if (end == -1) + { + end = temp.length(); + } + while (temp.charAt(end - 1) == '\\') + { + end = temp.indexOf(',', end + 1); + if (end == -1) + { + end = temp.length(); + } + } + temp = temp.substring(0, end); + begin = temp.indexOf('='); + temp = temp.substring(begin + 1); + if (temp.charAt(0) == ' ') + { + temp = temp.substring(1); + } + if (temp.startsWith("\"")) + { + temp = temp.substring(1); + } + if (temp.endsWith("\"")) + { + temp = temp.substring(0, temp.length() - 1); + } + return temp; + } + + public Collection engineGetCertificates(CertSelector selector) + throws CertStoreException + { + if (!(selector instanceof X509CertSelector)) + { + throw new CertStoreException("selector is not a X509CertSelector"); + } + X509CertSelector xselector = (X509CertSelector)selector; + + Set certSet = new HashSet(); + + Set set = getEndCertificates(xselector); + set.addAll(getCACertificates(xselector)); + set.addAll(getCrossCertificates(xselector)); + + Iterator it = set.iterator(); + + try + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", + BouncyCastleProvider.PROVIDER_NAME); + while (it.hasNext()) + { + byte[] bytes = (byte[])it.next(); + if (bytes == null || bytes.length == 0) + { + continue; + } + + List bytesList = new ArrayList(); + bytesList.add(bytes); + + try + { + CertificatePair pair = CertificatePair + .getInstance(new ASN1InputStream(bytes) + .readObject()); + bytesList.clear(); + if (pair.getForward() != null) + { + bytesList.add(pair.getForward().getEncoded()); + } + if (pair.getReverse() != null) + { + bytesList.add(pair.getReverse().getEncoded()); + } + } + catch (IOException e) + { + + } + catch (IllegalArgumentException e) + { + + } + for (Iterator it2 = bytesList.iterator(); it2.hasNext();) + { + ByteArrayInputStream bIn = new ByteArrayInputStream( + (byte[])it2.next()); + try + { + Certificate cert = cf.generateCertificate(bIn); + // System.out.println(((X509Certificate) + // cert).getSubjectX500Principal()); + if (xselector.match(cert)) + { + certSet.add(cert); + } + } + catch (Exception e) + { + + } + } + } + } + catch (Exception e) + { + throw new CertStoreException( + "certificate cannot be constructed from LDAP result: " + e); + } + + return certSet; + } + + private Set certSubjectSerialSearch(X509CertSelector xselector, + String[] attrs, String attrName, String subjectAttributeName) + throws CertStoreException + { + Set set = new HashSet(); + try + { + if (xselector.getSubjectAsBytes() != null + || xselector.getSubjectAsString() != null + || xselector.getCertificate() != null) + { + String subject = null; + String serial = null; + if (xselector.getCertificate() != null) + { + subject = xselector.getCertificate() + .getSubjectX500Principal().getName("RFC1779"); + serial = xselector.getCertificate().getSerialNumber() + .toString(); + } + else + { + if (xselector.getSubjectAsBytes() != null) + { + subject = new X500Principal(xselector + .getSubjectAsBytes()).getName("RFC1779"); + } + else + { + subject = xselector.getSubjectAsString(); + } + } + String attrValue = parseDN(subject, subjectAttributeName); + set.addAll(search(attrName, "*" + attrValue + "*", attrs)); + if (serial != null + && params.getSearchForSerialNumberIn() != null) + { + attrValue = serial; + attrName = params.getSearchForSerialNumberIn(); + set.addAll(search(attrName, "*" + attrValue + "*", attrs)); + } + } + else + { + set.addAll(search(attrName, "*", attrs)); + } + } + catch (IOException e) + { + throw new CertStoreException("exception processing selector: " + e); + } + + return set; + } + + private Set getEndCertificates(X509CertSelector xselector) + throws CertStoreException + { + String[] attrs = {params.getUserCertificateAttribute()}; + String attrName = params.getLdapUserCertificateAttributeName(); + String subjectAttributeName = params.getUserCertificateSubjectAttributeName(); + + Set set = certSubjectSerialSearch(xselector, attrs, attrName, + subjectAttributeName); + return set; + } + + private Set getCACertificates(X509CertSelector xselector) + throws CertStoreException + { + String[] attrs = {params.getCACertificateAttribute()}; + String attrName = params.getLdapCACertificateAttributeName(); + String subjectAttributeName = params + .getCACertificateSubjectAttributeName(); + Set set = certSubjectSerialSearch(xselector, attrs, attrName, + subjectAttributeName); + + if (set.isEmpty()) + { + set.addAll(search(null, "*", attrs)); + } + + return set; + } + + private Set getCrossCertificates(X509CertSelector xselector) + throws CertStoreException + { + String[] attrs = {params.getCrossCertificateAttribute()}; + String attrName = params.getLdapCrossCertificateAttributeName(); + String subjectAttributeName = params + .getCrossCertificateSubjectAttributeName(); + Set set = certSubjectSerialSearch(xselector, attrs, attrName, + subjectAttributeName); + + if (set.isEmpty()) + { + set.addAll(search(null, "*", attrs)); + } + + return set; + } + + public Collection engineGetCRLs(CRLSelector selector) + throws CertStoreException + { + String[] attrs = {params.getCertificateRevocationListAttribute()}; + if (!(selector instanceof X509CRLSelector)) + { + throw new CertStoreException("selector is not a X509CRLSelector"); + } + X509CRLSelector xselector = (X509CRLSelector)selector; + + Set crlSet = new HashSet(); + + String attrName = params.getLdapCertificateRevocationListAttributeName(); + Set set = new HashSet(); + + if (xselector.getIssuerNames() != null) + { + for (Iterator it = xselector.getIssuerNames().iterator(); it + .hasNext();) + { + Object o = it.next(); + String attrValue = null; + if (o instanceof String) + { + String issuerAttributeName = params + .getCertificateRevocationListIssuerAttributeName(); + attrValue = parseDN((String)o, issuerAttributeName); + } + else + { + String issuerAttributeName = params + .getCertificateRevocationListIssuerAttributeName(); + attrValue = parseDN(new X500Principal((byte[])o) + .getName("RFC1779"), issuerAttributeName); + } + set.addAll(search(attrName, "*" + attrValue + "*", attrs)); + } + } + else + { + set.addAll(search(attrName, "*", attrs)); + } + set.addAll(search(null, "*", attrs)); + Iterator it = set.iterator(); + + try + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", + BouncyCastleProvider.PROVIDER_NAME); + while (it.hasNext()) + { + CRL crl = cf.generateCRL(new ByteArrayInputStream((byte[])it + .next())); + if (xselector.match(crl)) + { + crlSet.add(crl); + } + } + } + catch (Exception e) + { + throw new CertStoreException( + "CRL cannot be constructed from LDAP result " + e); + } + + return crlSet; + } + + /** + * Returns a Set of byte arrays with the certificate or CRL encodings. + * + * @param attributeName The attribute name to look for in the LDAP. + * @param attributeValue The value the attribute name must have. + * @param attrs The attributes in the LDAP which hold the certificate, + * certificate pair or CRL in a found entry. + * @return Set of byte arrays with the certificate encodings. + */ + private Set search(String attributeName, String attributeValue, + String[] attrs) throws CertStoreException + { + String filter = attributeName + "=" + attributeValue; + if (attributeName == null) + { + filter = null; + } + DirContext ctx = null; + Set set = new HashSet(); + try + { + + ctx = connectLDAP(); + + SearchControls constraints = new SearchControls(); + constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); + constraints.setCountLimit(0); + for (int i = 0; i < attrs.length; i++) + { + String temp[] = new String[1]; + temp[0] = attrs[i]; + constraints.setReturningAttributes(temp); + + String filter2 = "(&(" + filter + ")(" + temp[0] + "=*))"; + if (filter == null) + { + filter2 = "(" + temp[0] + "=*)"; + } + NamingEnumeration results = ctx.search(params.getBaseDN(), + filter2, constraints); + while (results.hasMoreElements()) + { + SearchResult sr = (SearchResult)results.next(); + // should only be one attribute in the attribute set with + // one + // attribute value as byte array + NamingEnumeration enumeration = ((Attribute)(sr + .getAttributes().getAll().next())).getAll(); + while (enumeration.hasMore()) + { + Object o = enumeration.next(); + set.add(o); + } + } + } + } + catch (Exception e) + { + throw new CertStoreException( + "Error getting results from LDAP directory " + e); + + } + finally + { + try + { + if (null != ctx) + { + ctx.close(); + } + } + catch (Exception e) + { + } + } + return set; + } + +} |