VYPR
Medium severityGHSA Advisory· Published Apr 15, 2026· Updated Apr 17, 2026

CVE-2026-0636

CVE-2026-0636

Description

Improper neutralization of special elements used in an LDAP query ('LDAP injection') vulnerability in Legion of the Bouncy Castle Inc. BC-JAVA bcprov on all (prov modules). This vulnerability is associated with program files LDAPStoreHelper.

This issue affects BC-JAVA: from 1.74 before 1.84.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.bouncycastle:bcprov-jdk14Maven
>= 1.74, < 1.841.84
org.bouncycastle:bcprov-jdk15to18Maven
>= 1.74, < 1.841.84
org.bouncycastle:bcprov-jdk18onMaven
>= 1.74, < 1.841.84

Affected products

1

Patches

1
d20cdb8430e0

refactored out common code from LDAP classes

https://github.com/bcgit/bc-javaDavid HookJan 1, 2026via ghsa
3 files changed · +154 158
  • prov/src/main/java/org/bouncycastle/jce/provider/X509LDAPCertStoreSpi.java+5 96 modified
    @@ -34,6 +34,7 @@
     import org.bouncycastle.asn1.ASN1InputStream;
     import org.bouncycastle.asn1.x509.CertificatePair;
     import org.bouncycastle.jce.X509LDAPCertStoreParameters;
    +import org.bouncycastle.ldap.LDAPUtils;
     import org.bouncycastle.util.Strings;
     
     /**
    @@ -50,26 +51,6 @@
     public class X509LDAPCertStoreSpi
         extends CertStoreSpi
     {
    -    private static String[] FILTER_ESCAPE_TABLE = new String['\\' + 1];
    -
    -    static
    -    {
    -        // Filter encoding table -------------------------------------
    -
    -        // fill with char itself
    -        for (char c = 0; c < FILTER_ESCAPE_TABLE.length; c++)
    -        {
    -            FILTER_ESCAPE_TABLE[c] = String.valueOf(c);
    -        }
    -
    -        // escapes (RFC2254)
    -        FILTER_ESCAPE_TABLE['*'] = "\\2a";
    -        FILTER_ESCAPE_TABLE['('] = "\\28";
    -        FILTER_ESCAPE_TABLE[')'] = "\\29";
    -        FILTER_ESCAPE_TABLE['\\'] = "\\5c";
    -        FILTER_ESCAPE_TABLE[0] = "\\00";
    -    }
    -
         /**
          * Initial Context Factory.
          */
    @@ -124,42 +105,6 @@ private DirContext connectLDAP()
             return ctx;
         }
     
    -    private String parseDN(String subject, String subjectAttributeName)
    -    {
    -        String temp = subject;
    -        int begin = Strings.toLowerCase(temp).indexOf(Strings.toLowerCase(subjectAttributeName));
    -        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 filterEncode(temp);
    -    }
    -
         public Collection engineGetCertificates(CertSelector selector)
             throws CertStoreException
         {
    @@ -277,7 +222,7 @@ private Set certSubjectSerialSearch(X509CertSelector xselector,
                             subject = xselector.getSubjectAsString();
                         }
                     }
    -                String attrValue = parseDN(subject, subjectAttributeName);
    +                String attrValue = LDAPUtils.parseDN(subject, subjectAttributeName);
                     set.addAll(search(attrName, "*" + attrValue + "*", attrs));
                     if (serial != null
                         && params.getSearchForSerialNumberIn() != null)
    @@ -374,13 +319,13 @@ public Collection engineGetCRLs(CRLSelector selector)
                     {
                         String issuerAttributeName = params
                             .getCertificateRevocationListIssuerAttributeName();
    -                    attrValue = parseDN((String)o, issuerAttributeName);
    +                    attrValue = LDAPUtils.parseDN((String)o, issuerAttributeName);
                     }
                     else
                     {
                         String issuerAttributeName = params
                             .getCertificateRevocationListIssuerAttributeName();
    -                    attrValue = parseDN(new X500Principal((byte[])o)
    +                    attrValue = LDAPUtils.parseDN(new X500Principal((byte[])o)
                             .getName("RFC1779"), issuerAttributeName);
                     }
                     set.addAll(search(attrName, "*" + attrValue + "*", attrs));
    @@ -415,43 +360,7 @@ public Collection engineGetCRLs(CRLSelector selector)
     
             return crlSet;
         }
    -
    -    /**
    -     * Escape a value for use in a filter.
    -     *
    -     * @param value the value to escape.
    -     * @return a properly escaped representation of the supplied value.
    -     */
    -    private String filterEncode(String value)
    -    {
    -        if (value == null)
    -        {
    -            return null;
    -        }
    -
    -        // make buffer roomy
    -        StringBuilder encodedValue = new StringBuilder(value.length() * 2);
    -
    -        int length = value.length();
    -
    -        for (int i = 0; i < length; i++)
    -        {
    -            char c = value.charAt(i);
    -
    -            if (c < FILTER_ESCAPE_TABLE.length)
    -            {
    -                encodedValue.append(FILTER_ESCAPE_TABLE[c]);
    -            }
    -            else
    -            {
    -                // default: add the char
    -                encodedValue.append(c);
    -            }
    -        }
    -
    -        return encodedValue.toString();
    -    }
    -
    +    
         /**
          * Returns a Set of byte arrays with the certificate or CRL encodings.
          *
    
  • prov/src/main/java/org/bouncycastle/ldap/LDAPUtils.java+112 0 added
    @@ -0,0 +1,112 @@
    +package org.bouncycastle.ldap;
    +
    +import org.bouncycastle.util.Strings;
    +
    +/**
    + * General utility methods for assisting with preparation of LDAP queries.
    + */
    +public class LDAPUtils
    +{
    +    private static String[] FILTER_ESCAPE_TABLE = new String['\\' + 1];
    +
    +    static
    +    {
    +        // Filter encoding table -------------------------------------
    +
    +        // fill with char itself
    +        for (char c = 0; c < FILTER_ESCAPE_TABLE.length; c++)
    +        {
    +            FILTER_ESCAPE_TABLE[c] = String.valueOf(c);
    +        }
    +
    +        // escapes (RFC2254)
    +        FILTER_ESCAPE_TABLE['*'] = "\\2a";
    +        FILTER_ESCAPE_TABLE['('] = "\\28";
    +        FILTER_ESCAPE_TABLE[')'] = "\\29";
    +        FILTER_ESCAPE_TABLE['\\'] = "\\5c";
    +        FILTER_ESCAPE_TABLE[0] = "\\00";
    +    }
    +
    +    /**
    +     * Parse out the contents of a particular subject attribute name from the string form of an X.500 DN.
    +     *
    +     * @param subject string form of an X.500 DN.
    +     * @param subjectAttributeName the RDN attribute name of interest.
    +     * @return an escaped string suitable for use in an LDAP query.
    +     */
    +    public static String parseDN(String subject, String subjectAttributeName)
    +    {
    +        String temp = subject;
    +        int begin = Strings.toLowerCase(temp).indexOf(Strings.toLowerCase(subjectAttributeName));
    +        if (begin == -1)
    +        {
    +            return "";
    +        }
    +        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 filterEncode(temp);
    +    }
    +
    +    /**
    +     * Escape a value for use in a filter.
    +     *
    +     * @param value the value to escape.
    +     * @return a properly escaped representation of the supplied value.
    +     */
    +    private static String filterEncode(String value)
    +    {
    +        if (value == null)
    +        {
    +            return null;
    +        }
    +
    +        // make buffer roomy
    +        StringBuilder encodedValue = new StringBuilder(value.length() * 2);
    +
    +        int length = value.length();
    +
    +        for (int i = 0; i < length; i++)
    +        {
    +            char c = value.charAt(i);
    +
    +            if (c < FILTER_ESCAPE_TABLE.length)
    +            {
    +                encodedValue.append(FILTER_ESCAPE_TABLE[c]);
    +            }
    +            else
    +            {
    +                // default: add the char
    +                encodedValue.append(c);
    +            }
    +        }
    +
    +        return encodedValue.toString();
    +    }
    +}
    
  • prov/src/main/java/org/bouncycastle/x509/util/LDAPStoreHelper.java+37 62 modified
    @@ -35,6 +35,7 @@
     import org.bouncycastle.jce.provider.X509CRLParser;
     import org.bouncycastle.jce.provider.X509CertPairParser;
     import org.bouncycastle.jce.provider.X509CertParser;
    +import org.bouncycastle.ldap.LDAPUtils;
     import org.bouncycastle.util.StoreException;
     import org.bouncycastle.util.Strings;
     import org.bouncycastle.x509.X509AttributeCertStoreSelector;
    @@ -65,7 +66,6 @@
      */
     public class LDAPStoreHelper
     {
    -
         // TODO: cache results
     
         private X509LDAPCertStoreParameters params;
    @@ -95,7 +95,8 @@ public LDAPStoreHelper(X509LDAPCertStoreParameters params)
          */
         private static final String URL_CONTEXT_PREFIX = "com.sun.jndi.url";
     
    -    private DirContext connectLDAP() throws NamingException
    +    private DirContext connectLDAP()
    +        throws NamingException
         {
             Properties props = new Properties();
             props.setProperty(Context.INITIAL_CONTEXT_FACTORY, LDAP_PROVIDER);
    @@ -111,47 +112,6 @@ private DirContext connectLDAP() throws NamingException
             return ctx;
         }
     
    -    private String parseDN(String subject, String dNAttributeName)
    -    {
    -        String temp = subject;
    -        int begin = Strings.toLowerCase(temp).indexOf(
    -            Strings.toLowerCase(dNAttributeName) + "=");
    -        if (begin == -1)
    -        {
    -            return "";
    -        }
    -        temp = temp.substring(begin + dNAttributeName.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;
    -    }
    -
         private Set createCerts(List list, X509CertStoreSelector xselector)
             throws StoreException
         {
    @@ -224,7 +184,7 @@ private List certSubjectSerialSearch(X509CertStoreSelector xselector,
             {
                 for (int i = 0; i < subjectAttributeNames.length; i++)
                 {
    -                attrValue = parseDN(subject, subjectAttributeNames[i]);
    +                attrValue = LDAPUtils.parseDN(subject, subjectAttributeNames[i]);
                     list
                         .addAll(search(attrNames, "*" + attrValue + "*",
                             attrs));
    @@ -235,7 +195,7 @@ private List certSubjectSerialSearch(X509CertStoreSelector xselector,
                 attrValue = serial;
                 list.addAll(search(
                     splitString(params.getSearchForSerialNumberIn()),
    -                                                  attrValue, attrs));
    +                attrValue, attrs));
             }
             if (serial == null && subject == null)
             {
    @@ -246,7 +206,6 @@ private List certSubjectSerialSearch(X509CertStoreSelector xselector,
         }
     
     
    -
         /**
          * Can use the subject of the forward certificate of the set certificate
          * pair or the subject of the forward
    @@ -290,7 +249,7 @@ private List crossCertificatePairSubjectSearch(
             {
                 for (int i = 0; i < subjectAttributeNames.length; i++)
                 {
    -                attrValue = parseDN(subject, subjectAttributeNames[i]);
    +                attrValue = LDAPUtils.parseDN(subject, subjectAttributeNames[i]);
                     list
                         .addAll(search(attrNames, "*" + attrValue + "*",
                             attrs));
    @@ -385,7 +344,7 @@ private List attrCertSubjectSerialSearch(
             {
                 for (int i = 0; i < subjectAttributeNames.length; i++)
                 {
    -                attrValue = parseDN(subject, subjectAttributeNames[i]);
    +                attrValue = LDAPUtils.parseDN(subject, subjectAttributeNames[i]);
                     list
                         .addAll(search(attrNames, "*" + attrValue + "*",
                             attrs));
    @@ -441,11 +400,11 @@ private List cRLIssuerSearch(X509CRLStoreSelector xselector,
             if (xselector.getAttrCertificateChecking() != null)
             {
                 Principal principals[] = xselector.getAttrCertificateChecking().getIssuer().getPrincipals();
    -            for (int i=0; i<principals.length; i++)
    +            for (int i = 0; i < principals.length; i++)
                 {
                     if (principals[i] instanceof X500Principal)
                     {
    -                    issuers.add(principals[i]);        
    +                    issuers.add(principals[i]);
                     }
                 }
             }
    @@ -457,7 +416,7 @@ private List cRLIssuerSearch(X509CRLStoreSelector xselector,
     
                 for (int i = 0; i < issuerAttributeNames.length; i++)
                 {
    -                attrValue = parseDN(issuer, issuerAttributeNames[i]);
    +                attrValue = LDAPUtils.parseDN(issuer, issuerAttributeNames[i]);
                     list
                         .addAll(search(attrNames, "*" + attrValue + "*",
                             attrs));
    @@ -485,7 +444,8 @@ private List cRLIssuerSearch(X509CRLStoreSelector xselector,
          *                        directory.
          */
         private List search(String attributeNames[], String attributeValue,
    -                        String[] attrs) throws StoreException
    +                        String[] attrs)
    +        throws StoreException
         {
             String filter = null;
             if (attributeNames == null)
    @@ -599,7 +559,8 @@ private Set createCRLs(List list, X509CRLStoreSelector xselector)
         }
     
         private Set createCrossCertificatePairs(List list,
    -                                            X509CertPairStoreSelector xselector) throws StoreException
    +                                            X509CertPairStoreSelector xselector)
    +        throws StoreException
         {
             Set certPairSet = new HashSet();
     
    @@ -626,7 +587,7 @@ private Set createCrossCertificatePairs(List list,
                         pair = new X509CertificatePair(new CertificatePair(
                             Certificate
                                 .getInstance(new ASN1InputStream(
    -                            forward).readObject()),
    +                                forward).readObject()),
                             Certificate
                                 .getInstance(new ASN1InputStream(
                                     reverse).readObject())));
    @@ -652,7 +613,8 @@ private Set createCrossCertificatePairs(List list,
         }
     
         private Set createAttributeCertificates(List list,
    -                                            X509AttributeCertStoreSelector xselector) throws StoreException
    +                                            X509AttributeCertStoreSelector xselector)
    +        throws StoreException
         {
             Set certSet = new HashSet();
     
    @@ -719,12 +681,14 @@ public Collection getAuthorityRevocationLists(X509CRLStoreSelector selector)
          * The attributeCertificateRevocationList holds a list of attribute
          * certificates that have been revoked.
          * </p>
    +     *
          * @param selector The CRL selector to use to find the CRLs.
          * @return A possible empty collection with CRLs.
          * @throws StoreException
          */
         public Collection getAttributeCertificateRevocationLists(
    -        X509CRLStoreSelector selector) throws StoreException
    +        X509CRLStoreSelector selector)
    +        throws StoreException
         {
             String[] attrs = splitString(params
                 .getAttributeCertificateRevocationListAttribute());
    @@ -754,12 +718,14 @@ public Collection getAttributeCertificateRevocationLists(
          * The attributeAuthorityList holds a list of AA certificates that have been
          * revoked.
          * </p>
    +     *
          * @param selector The CRL selector to use to find the CRLs.
          * @return A possible empty collection with CRLs
          * @throws StoreException
          */
         public Collection getAttributeAuthorityRevocationLists(
    -        X509CRLStoreSelector selector) throws StoreException
    +        X509CRLStoreSelector selector)
    +        throws StoreException
         {
             String[] attrs = splitString(params.getAttributeAuthorityRevocationListAttribute());
             String attrNames[] = splitString(params
    @@ -789,7 +755,8 @@ public Collection getAttributeAuthorityRevocationLists(
          * @throws StoreException
          */
         public Collection getCrossCertificatePairs(
    -        X509CertPairStoreSelector selector) throws StoreException
    +        X509CertPairStoreSelector selector)
    +        throws StoreException
         {
             String[] attrs = splitString(params.getCrossCertificateAttribute());
             String attrNames[] = splitString(params.getLdapCrossCertificateAttributeName());
    @@ -850,6 +817,7 @@ public Collection getUserCertificates(X509CertStoreSelector selector)
          * <p>
          * The aAcertificate holds the privileges of an attribute authority.
          * </p>
    +     *
          * @param selector The selector to find the attribute certificates.
          * @return A possible empty collection with attribute certificates.
          * @throws StoreException
    @@ -882,12 +850,14 @@ public Collection getAACertificates(X509AttributeCertStoreSelector selector)
          * authority and holds a description of the privilege and its delegation
          * rules.
          * </p>
    +     *
          * @param selector The selector to find the attribute certificates.
          * @return A possible empty collection with attribute certificates.
          * @throws StoreException
          */
         public Collection getAttributeDescriptorCertificates(
    -        X509AttributeCertStoreSelector selector) throws StoreException
    +        X509AttributeCertStoreSelector selector)
    +        throws StoreException
         {
             String[] attrs = splitString(params.getAttributeDescriptorCertificateAttribute());
             String attrNames[] = splitString(params
    @@ -916,6 +886,7 @@ public Collection getAttributeDescriptorCertificates(
          * store self-issued certificates (if any) and certificates issued to this
          * CA by CAs in the same realm as this CA.
          * </p>
    +     *
          * @param selector The selector to find the certificates.
          * @return A possible empty collection with certificates.
          * @throws StoreException
    @@ -948,7 +919,8 @@ public Collection getCACertificates(X509CertStoreSelector selector)
          * @throws StoreException
          */
         public Collection getDeltaCertificateRevocationLists(
    -        X509CRLStoreSelector selector) throws StoreException
    +        X509CRLStoreSelector selector)
    +        throws StoreException
         {
             String[] attrs = splitString(params.getDeltaRevocationListAttribute());
             String attrNames[] = splitString(params.getLdapDeltaRevocationListAttributeName());
    @@ -973,12 +945,14 @@ public Collection getDeltaCertificateRevocationLists(
          * <p>
          * The attributeCertificateAttribute holds the privileges of a user
          * </p>
    +     *
          * @param selector The selector to find the attribute certificates.
          * @return A possible empty collection with attribute certificates.
          * @throws StoreException
          */
         public Collection getAttributeCertificateAttributes(
    -        X509AttributeCertStoreSelector selector) throws StoreException
    +        X509AttributeCertStoreSelector selector)
    +        throws StoreException
         {
             String[] attrs = splitString(params.getAttributeCertificateAttributeAttribute());
             String attrNames[] = splitString(params
    @@ -1007,7 +981,8 @@ public Collection getAttributeCertificateAttributes(
          * @throws StoreException
          */
         public Collection getCertificateRevocationLists(
    -        X509CRLStoreSelector selector) throws StoreException
    +        X509CRLStoreSelector selector)
    +        throws StoreException
         {
             String[] attrs = splitString(params.getCertificateRevocationListAttribute());
             String attrNames[] = splitString(params
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

3

News mentions

0

No linked articles in our index yet.