Home | History | Annotate | Download | only in x509
      1 package org.bouncycastle.asn1.x509;
      2 
      3 import java.util.Collection;
      4 import java.util.Collections;
      5 import java.util.HashMap;
      6 import java.util.HashSet;
      7 import java.util.Iterator;
      8 import java.util.Map;
      9 import java.util.Set;
     10 
     11 import org.bouncycastle.asn1.ASN1OctetString;
     12 import org.bouncycastle.asn1.ASN1Sequence;
     13 import org.bouncycastle.asn1.DERIA5String;
     14 import org.bouncycastle.asn1.x500.X500Name;
     15 import org.bouncycastle.util.Arrays;
     16 import org.bouncycastle.util.Integers;
     17 import org.bouncycastle.util.Strings;
     18 
     19 public class PKIXNameConstraintValidator
     20     implements NameConstraintValidator
     21 {
     22     private Set excludedSubtreesDN = new HashSet();
     23 
     24     private Set excludedSubtreesDNS = new HashSet();
     25 
     26     private Set excludedSubtreesEmail = new HashSet();
     27 
     28     private Set excludedSubtreesURI = new HashSet();
     29 
     30     private Set excludedSubtreesIP = new HashSet();
     31 
     32     private Set permittedSubtreesDN;
     33 
     34     private Set permittedSubtreesDNS;
     35 
     36     private Set permittedSubtreesEmail;
     37 
     38     private Set permittedSubtreesURI;
     39 
     40     private Set permittedSubtreesIP;
     41 
     42     public PKIXNameConstraintValidator()
     43     {
     44     }
     45 
     46     /**
     47      * Checks if the given GeneralName is in the permitted set.
     48      *
     49      * @param name The GeneralName
     50      * @throws NameConstraintValidatorException If the <code>name</code>
     51      */
     52     public void checkPermitted(GeneralName name)
     53         throws NameConstraintValidatorException
     54     {
     55         switch (name.getTagNo())
     56         {
     57         case GeneralName.rfc822Name:
     58             checkPermittedEmail(permittedSubtreesEmail,
     59                 extractNameAsString(name));
     60             break;
     61         case GeneralName.dNSName:
     62             checkPermittedDNS(permittedSubtreesDNS, DERIA5String.getInstance(
     63                 name.getName()).getString());
     64             break;
     65         case GeneralName.directoryName:
     66             checkPermittedDN(X500Name.getInstance(name.getName()));
     67             break;
     68         case GeneralName.uniformResourceIdentifier:
     69             checkPermittedURI(permittedSubtreesURI, DERIA5String.getInstance(
     70                 name.getName()).getString());
     71             break;
     72         case GeneralName.iPAddress:
     73             byte[] ip = ASN1OctetString.getInstance(name.getName()).getOctets();
     74 
     75             checkPermittedIP(permittedSubtreesIP, ip);
     76         }
     77     }
     78 
     79     /**
     80      * Check if the given GeneralName is contained in the excluded set.
     81      *
     82      * @param name The GeneralName.
     83      * @throws NameConstraintValidatorException If the <code>name</code> is
     84      * excluded.
     85      */
     86     public void checkExcluded(GeneralName name)
     87         throws NameConstraintValidatorException
     88     {
     89         switch (name.getTagNo())
     90         {
     91         case GeneralName.rfc822Name:
     92             checkExcludedEmail(excludedSubtreesEmail, extractNameAsString(name));
     93             break;
     94         case GeneralName.dNSName:
     95             checkExcludedDNS(excludedSubtreesDNS, DERIA5String.getInstance(
     96                 name.getName()).getString());
     97             break;
     98         case GeneralName.directoryName:
     99             checkExcludedDN(X500Name.getInstance(name.getName()));
    100             break;
    101         case GeneralName.uniformResourceIdentifier:
    102             checkExcludedURI(excludedSubtreesURI, DERIA5String.getInstance(
    103                 name.getName()).getString());
    104             break;
    105         case GeneralName.iPAddress:
    106             byte[] ip = ASN1OctetString.getInstance(name.getName()).getOctets();
    107 
    108             checkExcludedIP(excludedSubtreesIP, ip);
    109         }
    110     }
    111 
    112     public void intersectPermittedSubtree(GeneralSubtree permitted)
    113     {
    114         intersectPermittedSubtree(new GeneralSubtree[]{permitted});
    115     }
    116 
    117     /**
    118      * Updates the permitted set of these name constraints with the intersection
    119      * with the given subtree.
    120      *
    121      * @param permitted The permitted subtrees
    122      */
    123     public void intersectPermittedSubtree(GeneralSubtree[] permitted)
    124     {
    125         Map subtreesMap = new HashMap();
    126 
    127         // group in sets in a map ordered by tag no.
    128         for (int i = 0; i != permitted.length; i++)
    129         {
    130             GeneralSubtree subtree = permitted[i];
    131             Integer tagNo = Integers.valueOf(subtree.getBase().getTagNo());
    132             if (subtreesMap.get(tagNo) == null)
    133             {
    134                 subtreesMap.put(tagNo, new HashSet());
    135             }
    136             ((Set)subtreesMap.get(tagNo)).add(subtree);
    137         }
    138 
    139         for (Iterator it = subtreesMap.entrySet().iterator(); it.hasNext(); )
    140         {
    141             Map.Entry entry = (Map.Entry)it.next();
    142 
    143             // go through all subtree groups
    144             switch (((Integer)entry.getKey()).intValue())
    145             {
    146             case GeneralName.rfc822Name:
    147                 permittedSubtreesEmail = intersectEmail(permittedSubtreesEmail,
    148                     (Set)entry.getValue());
    149                 break;
    150             case GeneralName.dNSName:
    151                 permittedSubtreesDNS = intersectDNS(permittedSubtreesDNS,
    152                     (Set)entry.getValue());
    153                 break;
    154             case GeneralName.directoryName:
    155                 permittedSubtreesDN = intersectDN(permittedSubtreesDN,
    156                     (Set)entry.getValue());
    157                 break;
    158             case GeneralName.uniformResourceIdentifier:
    159                 permittedSubtreesURI = intersectURI(permittedSubtreesURI,
    160                     (Set)entry.getValue());
    161                 break;
    162             case GeneralName.iPAddress:
    163                 permittedSubtreesIP = intersectIP(permittedSubtreesIP,
    164                     (Set)entry.getValue());
    165             }
    166         }
    167     }
    168 
    169     public void intersectEmptyPermittedSubtree(int nameType)
    170     {
    171         switch (nameType)
    172         {
    173         case GeneralName.rfc822Name:
    174             permittedSubtreesEmail = new HashSet();
    175             break;
    176         case GeneralName.dNSName:
    177             permittedSubtreesDNS = new HashSet();
    178             break;
    179         case GeneralName.directoryName:
    180             permittedSubtreesDN = new HashSet();
    181             break;
    182         case GeneralName.uniformResourceIdentifier:
    183             permittedSubtreesURI = new HashSet();
    184             break;
    185         case GeneralName.iPAddress:
    186             permittedSubtreesIP = new HashSet();
    187         }
    188     }
    189 
    190     /**
    191      * Adds a subtree to the excluded set of these name constraints.
    192      *
    193      * @param subtree A subtree with an excluded GeneralName.
    194      */
    195     public void addExcludedSubtree(GeneralSubtree subtree)
    196     {
    197         GeneralName base = subtree.getBase();
    198 
    199         switch (base.getTagNo())
    200         {
    201         case GeneralName.rfc822Name:
    202             excludedSubtreesEmail = unionEmail(excludedSubtreesEmail,
    203                 extractNameAsString(base));
    204             break;
    205         case GeneralName.dNSName:
    206             excludedSubtreesDNS = unionDNS(excludedSubtreesDNS,
    207                 extractNameAsString(base));
    208             break;
    209         case GeneralName.directoryName:
    210             excludedSubtreesDN = unionDN(excludedSubtreesDN,
    211                 (ASN1Sequence)base.getName().toASN1Primitive());
    212             break;
    213         case GeneralName.uniformResourceIdentifier:
    214             excludedSubtreesURI = unionURI(excludedSubtreesURI,
    215                 extractNameAsString(base));
    216             break;
    217         case GeneralName.iPAddress:
    218             excludedSubtreesIP = unionIP(excludedSubtreesIP, ASN1OctetString
    219                 .getInstance(base.getName()).getOctets());
    220             break;
    221         }
    222     }
    223 
    224     public int hashCode()
    225     {
    226         return hashCollection(excludedSubtreesDN)
    227             + hashCollection(excludedSubtreesDNS)
    228             + hashCollection(excludedSubtreesEmail)
    229             + hashCollection(excludedSubtreesIP)
    230             + hashCollection(excludedSubtreesURI)
    231             + hashCollection(permittedSubtreesDN)
    232             + hashCollection(permittedSubtreesDNS)
    233             + hashCollection(permittedSubtreesEmail)
    234             + hashCollection(permittedSubtreesIP)
    235             + hashCollection(permittedSubtreesURI);
    236     }
    237 
    238     public boolean equals(Object o)
    239     {
    240         if (!(o instanceof PKIXNameConstraintValidator))
    241         {
    242             return false;
    243         }
    244         PKIXNameConstraintValidator constraintValidator = (PKIXNameConstraintValidator)o;
    245         return collectionsAreEqual(constraintValidator.excludedSubtreesDN, excludedSubtreesDN)
    246             && collectionsAreEqual(constraintValidator.excludedSubtreesDNS, excludedSubtreesDNS)
    247             && collectionsAreEqual(constraintValidator.excludedSubtreesEmail, excludedSubtreesEmail)
    248             && collectionsAreEqual(constraintValidator.excludedSubtreesIP, excludedSubtreesIP)
    249             && collectionsAreEqual(constraintValidator.excludedSubtreesURI, excludedSubtreesURI)
    250             && collectionsAreEqual(constraintValidator.permittedSubtreesDN, permittedSubtreesDN)
    251             && collectionsAreEqual(constraintValidator.permittedSubtreesDNS, permittedSubtreesDNS)
    252             && collectionsAreEqual(constraintValidator.permittedSubtreesEmail, permittedSubtreesEmail)
    253             && collectionsAreEqual(constraintValidator.permittedSubtreesIP, permittedSubtreesIP)
    254             && collectionsAreEqual(constraintValidator.permittedSubtreesURI, permittedSubtreesURI);
    255     }
    256 
    257     public String toString()
    258     {
    259         String temp = "";
    260         temp += "permitted:\n";
    261         if (permittedSubtreesDN != null)
    262         {
    263             temp += "DN:\n";
    264             temp += permittedSubtreesDN.toString() + "\n";
    265         }
    266         if (permittedSubtreesDNS != null)
    267         {
    268             temp += "DNS:\n";
    269             temp += permittedSubtreesDNS.toString() + "\n";
    270         }
    271         if (permittedSubtreesEmail != null)
    272         {
    273             temp += "Email:\n";
    274             temp += permittedSubtreesEmail.toString() + "\n";
    275         }
    276         if (permittedSubtreesURI != null)
    277         {
    278             temp += "URI:\n";
    279             temp += permittedSubtreesURI.toString() + "\n";
    280         }
    281         if (permittedSubtreesIP != null)
    282         {
    283             temp += "IP:\n";
    284             temp += stringifyIPCollection(permittedSubtreesIP) + "\n";
    285         }
    286         temp += "excluded:\n";
    287         if (!excludedSubtreesDN.isEmpty())
    288         {
    289             temp += "DN:\n";
    290             temp += excludedSubtreesDN.toString() + "\n";
    291         }
    292         if (!excludedSubtreesDNS.isEmpty())
    293         {
    294             temp += "DNS:\n";
    295             temp += excludedSubtreesDNS.toString() + "\n";
    296         }
    297         if (!excludedSubtreesEmail.isEmpty())
    298         {
    299             temp += "Email:\n";
    300             temp += excludedSubtreesEmail.toString() + "\n";
    301         }
    302         if (!excludedSubtreesURI.isEmpty())
    303         {
    304             temp += "URI:\n";
    305             temp += excludedSubtreesURI.toString() + "\n";
    306         }
    307         if (!excludedSubtreesIP.isEmpty())
    308         {
    309             temp += "IP:\n";
    310             temp += stringifyIPCollection(excludedSubtreesIP) + "\n";
    311         }
    312         return temp;
    313     }
    314 
    315     private void checkPermittedDN(X500Name dns)
    316         throws NameConstraintValidatorException
    317     {
    318         checkPermittedDN(permittedSubtreesDN, ASN1Sequence.getInstance(dns.toASN1Primitive()));
    319     }
    320 
    321     private void checkExcludedDN(X500Name dns)
    322         throws NameConstraintValidatorException
    323     {
    324         checkExcludedDN(excludedSubtreesDN, ASN1Sequence.getInstance(dns));
    325     }
    326 
    327     private static boolean withinDNSubtree(
    328         ASN1Sequence dns,
    329         ASN1Sequence subtree)
    330     {
    331         if (subtree.size() < 1)
    332         {
    333             return false;
    334         }
    335 
    336         if (subtree.size() > dns.size())
    337         {
    338             return false;
    339         }
    340 
    341         for (int j = subtree.size() - 1; j >= 0; j--)
    342         {
    343             if (!subtree.getObjectAt(j).equals(dns.getObjectAt(j)))
    344             {
    345                 return false;
    346             }
    347         }
    348 
    349         return true;
    350     }
    351 
    352     private void checkPermittedDN(Set permitted, ASN1Sequence dns)
    353         throws NameConstraintValidatorException
    354     {
    355         if (permitted == null)
    356         {
    357             return;
    358         }
    359 
    360         if (permitted.isEmpty() && dns.size() == 0)
    361         {
    362             return;
    363         }
    364         Iterator it = permitted.iterator();
    365 
    366         while (it.hasNext())
    367         {
    368             ASN1Sequence subtree = (ASN1Sequence)it.next();
    369 
    370             if (withinDNSubtree(dns, subtree))
    371             {
    372                 return;
    373             }
    374         }
    375 
    376         throw new NameConstraintValidatorException(
    377             "Subject distinguished name is not from a permitted subtree");
    378     }
    379 
    380     private void checkExcludedDN(Set excluded, ASN1Sequence dns)
    381         throws NameConstraintValidatorException
    382     {
    383         if (excluded.isEmpty())
    384         {
    385             return;
    386         }
    387 
    388         Iterator it = excluded.iterator();
    389 
    390         while (it.hasNext())
    391         {
    392             ASN1Sequence subtree = (ASN1Sequence)it.next();
    393 
    394             if (withinDNSubtree(dns, subtree))
    395             {
    396                 throw new NameConstraintValidatorException(
    397                     "Subject distinguished name is from an excluded subtree");
    398             }
    399         }
    400     }
    401 
    402     private Set intersectDN(Set permitted, Set dns)
    403     {
    404         Set intersect = new HashSet();
    405         for (Iterator it = dns.iterator(); it.hasNext(); )
    406         {
    407             ASN1Sequence dn = ASN1Sequence.getInstance(((GeneralSubtree)it
    408                 .next()).getBase().getName().toASN1Primitive());
    409             if (permitted == null)
    410             {
    411                 if (dn != null)
    412                 {
    413                     intersect.add(dn);
    414                 }
    415             }
    416             else
    417             {
    418                 Iterator _iter = permitted.iterator();
    419                 while (_iter.hasNext())
    420                 {
    421                     ASN1Sequence subtree = (ASN1Sequence)_iter.next();
    422 
    423                     if (withinDNSubtree(dn, subtree))
    424                     {
    425                         intersect.add(dn);
    426                     }
    427                     else if (withinDNSubtree(subtree, dn))
    428                     {
    429                         intersect.add(subtree);
    430                     }
    431                 }
    432             }
    433         }
    434         return intersect;
    435     }
    436 
    437     private Set unionDN(Set excluded, ASN1Sequence dn)
    438     {
    439         if (excluded.isEmpty())
    440         {
    441             if (dn == null)
    442             {
    443                 return excluded;
    444             }
    445             excluded.add(dn);
    446 
    447             return excluded;
    448         }
    449         else
    450         {
    451             Set intersect = new HashSet();
    452 
    453             Iterator it = excluded.iterator();
    454             while (it.hasNext())
    455             {
    456                 ASN1Sequence subtree = (ASN1Sequence)it.next();
    457 
    458                 if (withinDNSubtree(dn, subtree))
    459                 {
    460                     intersect.add(subtree);
    461                 }
    462                 else if (withinDNSubtree(subtree, dn))
    463                 {
    464                     intersect.add(dn);
    465                 }
    466                 else
    467                 {
    468                     intersect.add(subtree);
    469                     intersect.add(dn);
    470                 }
    471             }
    472 
    473             return intersect;
    474         }
    475     }
    476 
    477     private Set intersectEmail(Set permitted, Set emails)
    478     {
    479         Set intersect = new HashSet();
    480         for (Iterator it = emails.iterator(); it.hasNext(); )
    481         {
    482             String email = extractNameAsString(((GeneralSubtree)it.next())
    483                 .getBase());
    484 
    485             if (permitted == null)
    486             {
    487                 if (email != null)
    488                 {
    489                     intersect.add(email);
    490                 }
    491             }
    492             else
    493             {
    494                 Iterator it2 = permitted.iterator();
    495                 while (it2.hasNext())
    496                 {
    497                     String _permitted = (String)it2.next();
    498 
    499                     intersectEmail(email, _permitted, intersect);
    500                 }
    501             }
    502         }
    503         return intersect;
    504     }
    505 
    506     private Set unionEmail(Set excluded, String email)
    507     {
    508         if (excluded.isEmpty())
    509         {
    510             if (email == null)
    511             {
    512                 return excluded;
    513             }
    514             excluded.add(email);
    515             return excluded;
    516         }
    517         else
    518         {
    519             Set union = new HashSet();
    520 
    521             Iterator it = excluded.iterator();
    522             while (it.hasNext())
    523             {
    524                 String _excluded = (String)it.next();
    525 
    526                 unionEmail(_excluded, email, union);
    527             }
    528 
    529             return union;
    530         }
    531     }
    532 
    533     /**
    534      * Returns the intersection of the permitted IP ranges in
    535      * <code>permitted</code> with <code>ip</code>.
    536      *
    537      * @param permitted A <code>Set</code> of permitted IP addresses with
    538      *                  their subnet mask as byte arrays.
    539      * @param ips       The IP address with its subnet mask.
    540      * @return The <code>Set</code> of permitted IP ranges intersected with
    541      * <code>ip</code>.
    542      */
    543     private Set intersectIP(Set permitted, Set ips)
    544     {
    545         Set intersect = new HashSet();
    546         for (Iterator it = ips.iterator(); it.hasNext(); )
    547         {
    548             byte[] ip = ASN1OctetString.getInstance(
    549                 ((GeneralSubtree)it.next()).getBase().getName()).getOctets();
    550             if (permitted == null)
    551             {
    552                 if (ip != null)
    553                 {
    554                     intersect.add(ip);
    555                 }
    556             }
    557             else
    558             {
    559                 Iterator it2 = permitted.iterator();
    560                 while (it2.hasNext())
    561                 {
    562                     byte[] _permitted = (byte[])it2.next();
    563                     intersect.addAll(intersectIPRange(_permitted, ip));
    564                 }
    565             }
    566         }
    567         return intersect;
    568     }
    569 
    570     /**
    571      * Returns the union of the excluded IP ranges in <code>excluded</code>
    572      * with <code>ip</code>.
    573      *
    574      * @param excluded A <code>Set</code> of excluded IP addresses with their
    575      *                 subnet mask as byte arrays.
    576      * @param ip       The IP address with its subnet mask.
    577      * @return The <code>Set</code> of excluded IP ranges unified with
    578      * <code>ip</code> as byte arrays.
    579      */
    580     private Set unionIP(Set excluded, byte[] ip)
    581     {
    582         if (excluded.isEmpty())
    583         {
    584             if (ip == null)
    585             {
    586                 return excluded;
    587             }
    588             excluded.add(ip);
    589 
    590             return excluded;
    591         }
    592         else
    593         {
    594             Set union = new HashSet();
    595 
    596             Iterator it = excluded.iterator();
    597             while (it.hasNext())
    598             {
    599                 byte[] _excluded = (byte[])it.next();
    600                 union.addAll(unionIPRange(_excluded, ip));
    601             }
    602 
    603             return union;
    604         }
    605     }
    606 
    607     /**
    608      * Calculates the union if two IP ranges.
    609      *
    610      * @param ipWithSubmask1 The first IP address with its subnet mask.
    611      * @param ipWithSubmask2 The second IP address with its subnet mask.
    612      * @return A <code>Set</code> with the union of both addresses.
    613      */
    614     private Set unionIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2)
    615     {
    616         Set set = new HashSet();
    617 
    618         // difficult, adding always all IPs is not wrong
    619         if (Arrays.areEqual(ipWithSubmask1, ipWithSubmask2))
    620         {
    621             set.add(ipWithSubmask1);
    622         }
    623         else
    624         {
    625             set.add(ipWithSubmask1);
    626             set.add(ipWithSubmask2);
    627         }
    628         return set;
    629     }
    630 
    631     /**
    632      * Calculates the interesction if two IP ranges.
    633      *
    634      * @param ipWithSubmask1 The first IP address with its subnet mask.
    635      * @param ipWithSubmask2 The second IP address with its subnet mask.
    636      * @return A <code>Set</code> with the single IP address with its subnet
    637      * mask as a byte array or an empty <code>Set</code>.
    638      */
    639     private Set intersectIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2)
    640     {
    641         if (ipWithSubmask1.length != ipWithSubmask2.length)
    642         {
    643             return Collections.EMPTY_SET;
    644         }
    645         byte[][] temp = extractIPsAndSubnetMasks(ipWithSubmask1, ipWithSubmask2);
    646         byte ip1[] = temp[0];
    647         byte subnetmask1[] = temp[1];
    648         byte ip2[] = temp[2];
    649         byte subnetmask2[] = temp[3];
    650 
    651         byte minMax[][] = minMaxIPs(ip1, subnetmask1, ip2, subnetmask2);
    652         byte[] min;
    653         byte[] max;
    654         max = min(minMax[1], minMax[3]);
    655         min = max(minMax[0], minMax[2]);
    656 
    657         // minimum IP address must be bigger than max
    658         if (compareTo(min, max) == 1)
    659         {
    660             return Collections.EMPTY_SET;
    661         }
    662         // OR keeps all significant bits
    663         byte[] ip = or(minMax[0], minMax[2]);
    664         byte[] subnetmask = or(subnetmask1, subnetmask2);
    665         return Collections.singleton(ipWithSubnetMask(ip, subnetmask));
    666     }
    667 
    668     /**
    669      * Concatenates the IP address with its subnet mask.
    670      *
    671      * @param ip         The IP address.
    672      * @param subnetMask Its subnet mask.
    673      * @return The concatenated IP address with its subnet mask.
    674      */
    675     private byte[] ipWithSubnetMask(byte[] ip, byte[] subnetMask)
    676     {
    677         int ipLength = ip.length;
    678         byte[] temp = new byte[ipLength * 2];
    679         System.arraycopy(ip, 0, temp, 0, ipLength);
    680         System.arraycopy(subnetMask, 0, temp, ipLength, ipLength);
    681         return temp;
    682     }
    683 
    684     /**
    685      * Splits the IP addresses and their subnet mask.
    686      *
    687      * @param ipWithSubmask1 The first IP address with the subnet mask.
    688      * @param ipWithSubmask2 The second IP address with the subnet mask.
    689      * @return An array with two elements. Each element contains the IP address
    690      * and the subnet mask in this order.
    691      */
    692     private byte[][] extractIPsAndSubnetMasks(
    693         byte[] ipWithSubmask1,
    694         byte[] ipWithSubmask2)
    695     {
    696         int ipLength = ipWithSubmask1.length / 2;
    697         byte ip1[] = new byte[ipLength];
    698         byte subnetmask1[] = new byte[ipLength];
    699         System.arraycopy(ipWithSubmask1, 0, ip1, 0, ipLength);
    700         System.arraycopy(ipWithSubmask1, ipLength, subnetmask1, 0, ipLength);
    701 
    702         byte ip2[] = new byte[ipLength];
    703         byte subnetmask2[] = new byte[ipLength];
    704         System.arraycopy(ipWithSubmask2, 0, ip2, 0, ipLength);
    705         System.arraycopy(ipWithSubmask2, ipLength, subnetmask2, 0, ipLength);
    706         return new byte[][]
    707             {ip1, subnetmask1, ip2, subnetmask2};
    708     }
    709 
    710     /**
    711      * Based on the two IP addresses and their subnet masks the IP range is
    712      * computed for each IP address - subnet mask pair and returned as the
    713      * minimum IP address and the maximum address of the range.
    714      *
    715      * @param ip1         The first IP address.
    716      * @param subnetmask1 The subnet mask of the first IP address.
    717      * @param ip2         The second IP address.
    718      * @param subnetmask2 The subnet mask of the second IP address.
    719      * @return A array with two elements. The first/second element contains the
    720      * min and max IP address of the first/second IP address and its
    721      * subnet mask.
    722      */
    723     private byte[][] minMaxIPs(
    724         byte[] ip1,
    725         byte[] subnetmask1,
    726         byte[] ip2,
    727         byte[] subnetmask2)
    728     {
    729         int ipLength = ip1.length;
    730         byte[] min1 = new byte[ipLength];
    731         byte[] max1 = new byte[ipLength];
    732 
    733         byte[] min2 = new byte[ipLength];
    734         byte[] max2 = new byte[ipLength];
    735 
    736         for (int i = 0; i < ipLength; i++)
    737         {
    738             min1[i] = (byte)(ip1[i] & subnetmask1[i]);
    739             max1[i] = (byte)(ip1[i] & subnetmask1[i] | ~subnetmask1[i]);
    740 
    741             min2[i] = (byte)(ip2[i] & subnetmask2[i]);
    742             max2[i] = (byte)(ip2[i] & subnetmask2[i] | ~subnetmask2[i]);
    743         }
    744 
    745         return new byte[][]{min1, max1, min2, max2};
    746     }
    747 
    748     private void checkPermittedEmail(Set permitted, String email)
    749         throws NameConstraintValidatorException
    750     {
    751         if (permitted == null)
    752         {
    753             return;
    754         }
    755 
    756         Iterator it = permitted.iterator();
    757 
    758         while (it.hasNext())
    759         {
    760             String str = ((String)it.next());
    761 
    762             if (emailIsConstrained(email, str))
    763             {
    764                 return;
    765             }
    766         }
    767 
    768         if (email.length() == 0 && permitted.size() == 0)
    769         {
    770             return;
    771         }
    772 
    773         throw new NameConstraintValidatorException(
    774             "Subject email address is not from a permitted subtree.");
    775     }
    776 
    777     private void checkExcludedEmail(Set excluded, String email)
    778         throws NameConstraintValidatorException
    779     {
    780         if (excluded.isEmpty())
    781         {
    782             return;
    783         }
    784 
    785         Iterator it = excluded.iterator();
    786 
    787         while (it.hasNext())
    788         {
    789             String str = (String)it.next();
    790 
    791             if (emailIsConstrained(email, str))
    792             {
    793                 throw new NameConstraintValidatorException(
    794                     "Email address is from an excluded subtree.");
    795             }
    796         }
    797     }
    798 
    799     /**
    800      * Checks if the IP <code>ip</code> is included in the permitted set
    801      * <code>permitted</code>.
    802      *
    803      * @param permitted A <code>Set</code> of permitted IP addresses with
    804      *                  their subnet mask as byte arrays.
    805      * @param ip        The IP address.
    806      * @throws NameConstraintValidatorException if the IP is not permitted.
    807      */
    808     private void checkPermittedIP(Set permitted, byte[] ip)
    809         throws NameConstraintValidatorException
    810     {
    811         if (permitted == null)
    812         {
    813             return;
    814         }
    815 
    816         Iterator it = permitted.iterator();
    817 
    818         while (it.hasNext())
    819         {
    820             byte[] ipWithSubnet = (byte[])it.next();
    821 
    822             if (isIPConstrained(ip, ipWithSubnet))
    823             {
    824                 return;
    825             }
    826         }
    827         if (ip.length == 0 && permitted.size() == 0)
    828         {
    829             return;
    830         }
    831         throw new NameConstraintValidatorException(
    832             "IP is not from a permitted subtree.");
    833     }
    834 
    835     /**
    836      * Checks if the IP <code>ip</code> is included in the excluded set
    837      * <code>excluded</code>.
    838      *
    839      * @param excluded A <code>Set</code> of excluded IP addresses with their
    840      *                 subnet mask as byte arrays.
    841      * @param ip       The IP address.
    842      * @throws NameConstraintValidatorException if the IP is excluded.
    843      */
    844     private void checkExcludedIP(Set excluded, byte[] ip)
    845         throws NameConstraintValidatorException
    846     {
    847         if (excluded.isEmpty())
    848         {
    849             return;
    850         }
    851 
    852         Iterator it = excluded.iterator();
    853 
    854         while (it.hasNext())
    855         {
    856             byte[] ipWithSubnet = (byte[])it.next();
    857 
    858             if (isIPConstrained(ip, ipWithSubnet))
    859             {
    860                 throw new NameConstraintValidatorException(
    861                     "IP is from an excluded subtree.");
    862             }
    863         }
    864     }
    865 
    866     /**
    867      * Checks if the IP address <code>ip</code> is constrained by
    868      * <code>constraint</code>.
    869      *
    870      * @param ip         The IP address.
    871      * @param constraint The constraint. This is an IP address concatenated with
    872      *                   its subnetmask.
    873      * @return <code>true</code> if constrained, <code>false</code>
    874      * otherwise.
    875      */
    876     private boolean isIPConstrained(byte ip[], byte[] constraint)
    877     {
    878         int ipLength = ip.length;
    879 
    880         if (ipLength != (constraint.length / 2))
    881         {
    882             return false;
    883         }
    884 
    885         byte[] subnetMask = new byte[ipLength];
    886         System.arraycopy(constraint, ipLength, subnetMask, 0, ipLength);
    887 
    888         byte[] permittedSubnetAddress = new byte[ipLength];
    889 
    890         byte[] ipSubnetAddress = new byte[ipLength];
    891 
    892         // the resulting IP address by applying the subnet mask
    893         for (int i = 0; i < ipLength; i++)
    894         {
    895             permittedSubnetAddress[i] = (byte)(constraint[i] & subnetMask[i]);
    896             ipSubnetAddress[i] = (byte)(ip[i] & subnetMask[i]);
    897         }
    898 
    899         return Arrays.areEqual(permittedSubnetAddress, ipSubnetAddress);
    900     }
    901 
    902     private boolean emailIsConstrained(String email, String constraint)
    903     {
    904         String sub = email.substring(email.indexOf('@') + 1);
    905         // a particular mailbox
    906         if (constraint.indexOf('@') != -1)
    907         {
    908             if (email.equalsIgnoreCase(constraint))
    909             {
    910                 return true;
    911             }
    912         }
    913         // on particular host
    914         else if (!(constraint.charAt(0) == '.'))
    915         {
    916             if (sub.equalsIgnoreCase(constraint))
    917             {
    918                 return true;
    919             }
    920         }
    921         // address in sub domain
    922         else if (withinDomain(sub, constraint))
    923         {
    924             return true;
    925         }
    926         return false;
    927     }
    928 
    929     private boolean withinDomain(String testDomain, String domain)
    930     {
    931         String tempDomain = domain;
    932         if (tempDomain.startsWith("."))
    933         {
    934             tempDomain = tempDomain.substring(1);
    935         }
    936         String[] domainParts = Strings.split(tempDomain, '.');
    937         String[] testDomainParts = Strings.split(testDomain, '.');
    938         // must have at least one subdomain
    939         if (testDomainParts.length <= domainParts.length)
    940         {
    941             return false;
    942         }
    943         int d = testDomainParts.length - domainParts.length;
    944         for (int i = -1; i < domainParts.length; i++)
    945         {
    946             if (i == -1)
    947             {
    948                 if (testDomainParts[i + d].equals(""))
    949                 {
    950                     return false;
    951                 }
    952             }
    953             else if (!domainParts[i].equalsIgnoreCase(testDomainParts[i + d]))
    954             {
    955                 return false;
    956             }
    957         }
    958         return true;
    959     }
    960 
    961     private void checkPermittedDNS(Set permitted, String dns)
    962         throws NameConstraintValidatorException
    963     {
    964         if (permitted == null)
    965         {
    966             return;
    967         }
    968 
    969         Iterator it = permitted.iterator();
    970 
    971         while (it.hasNext())
    972         {
    973             String str = ((String)it.next());
    974 
    975             // is sub domain
    976             if (withinDomain(dns, str) || dns.equalsIgnoreCase(str))
    977             {
    978                 return;
    979             }
    980         }
    981         if (dns.length() == 0 && permitted.size() == 0)
    982         {
    983             return;
    984         }
    985         throw new NameConstraintValidatorException(
    986             "DNS is not from a permitted subtree.");
    987     }
    988 
    989     private void checkExcludedDNS(Set excluded, String dns)
    990         throws NameConstraintValidatorException
    991     {
    992         if (excluded.isEmpty())
    993         {
    994             return;
    995         }
    996 
    997         Iterator it = excluded.iterator();
    998 
    999         while (it.hasNext())
   1000         {
   1001             String str = ((String)it.next());
   1002 
   1003             // is sub domain or the same
   1004             if (withinDomain(dns, str) || dns.equalsIgnoreCase(str))
   1005             {
   1006                 throw new NameConstraintValidatorException(
   1007                     "DNS is from an excluded subtree.");
   1008             }
   1009         }
   1010     }
   1011 
   1012     /**
   1013      * The common part of <code>email1</code> and <code>email2</code> is
   1014      * added to the union <code>union</code>. If <code>email1</code> and
   1015      * <code>email2</code> have nothing in common they are added both.
   1016      *
   1017      * @param email1 Email address constraint 1.
   1018      * @param email2 Email address constraint 2.
   1019      * @param union  The union.
   1020      */
   1021     private void unionEmail(String email1, String email2, Set union)
   1022     {
   1023         // email1 is a particular address
   1024         if (email1.indexOf('@') != -1)
   1025         {
   1026             String _sub = email1.substring(email1.indexOf('@') + 1);
   1027             // both are a particular mailbox
   1028             if (email2.indexOf('@') != -1)
   1029             {
   1030                 if (email1.equalsIgnoreCase(email2))
   1031                 {
   1032                     union.add(email1);
   1033                 }
   1034                 else
   1035                 {
   1036                     union.add(email1);
   1037                     union.add(email2);
   1038                 }
   1039             }
   1040             // email2 specifies a domain
   1041             else if (email2.startsWith("."))
   1042             {
   1043                 if (withinDomain(_sub, email2))
   1044                 {
   1045                     union.add(email2);
   1046                 }
   1047                 else
   1048                 {
   1049                     union.add(email1);
   1050                     union.add(email2);
   1051                 }
   1052             }
   1053             // email2 specifies a particular host
   1054             else
   1055             {
   1056                 if (_sub.equalsIgnoreCase(email2))
   1057                 {
   1058                     union.add(email2);
   1059                 }
   1060                 else
   1061                 {
   1062                     union.add(email1);
   1063                     union.add(email2);
   1064                 }
   1065             }
   1066         }
   1067         // email1 specifies a domain
   1068         else if (email1.startsWith("."))
   1069         {
   1070             if (email2.indexOf('@') != -1)
   1071             {
   1072                 String _sub = email2.substring(email1.indexOf('@') + 1);
   1073                 if (withinDomain(_sub, email1))
   1074                 {
   1075                     union.add(email1);
   1076                 }
   1077                 else
   1078                 {
   1079                     union.add(email1);
   1080                     union.add(email2);
   1081                 }
   1082             }
   1083             // email2 specifies a domain
   1084             else if (email2.startsWith("."))
   1085             {
   1086                 if (withinDomain(email1, email2)
   1087                     || email1.equalsIgnoreCase(email2))
   1088                 {
   1089                     union.add(email2);
   1090                 }
   1091                 else if (withinDomain(email2, email1))
   1092                 {
   1093                     union.add(email1);
   1094                 }
   1095                 else
   1096                 {
   1097                     union.add(email1);
   1098                     union.add(email2);
   1099                 }
   1100             }
   1101             else
   1102             {
   1103                 if (withinDomain(email2, email1))
   1104                 {
   1105                     union.add(email1);
   1106                 }
   1107                 else
   1108                 {
   1109                     union.add(email1);
   1110                     union.add(email2);
   1111                 }
   1112             }
   1113         }
   1114         // email specifies a host
   1115         else
   1116         {
   1117             if (email2.indexOf('@') != -1)
   1118             {
   1119                 String _sub = email2.substring(email1.indexOf('@') + 1);
   1120                 if (_sub.equalsIgnoreCase(email1))
   1121                 {
   1122                     union.add(email1);
   1123                 }
   1124                 else
   1125                 {
   1126                     union.add(email1);
   1127                     union.add(email2);
   1128                 }
   1129             }
   1130             // email2 specifies a domain
   1131             else if (email2.startsWith("."))
   1132             {
   1133                 if (withinDomain(email1, email2))
   1134                 {
   1135                     union.add(email2);
   1136                 }
   1137                 else
   1138                 {
   1139                     union.add(email1);
   1140                     union.add(email2);
   1141                 }
   1142             }
   1143             // email2 specifies a particular host
   1144             else
   1145             {
   1146                 if (email1.equalsIgnoreCase(email2))
   1147                 {
   1148                     union.add(email1);
   1149                 }
   1150                 else
   1151                 {
   1152                     union.add(email1);
   1153                     union.add(email2);
   1154                 }
   1155             }
   1156         }
   1157     }
   1158 
   1159     private void unionURI(String email1, String email2, Set union)
   1160     {
   1161         // email1 is a particular address
   1162         if (email1.indexOf('@') != -1)
   1163         {
   1164             String _sub = email1.substring(email1.indexOf('@') + 1);
   1165             // both are a particular mailbox
   1166             if (email2.indexOf('@') != -1)
   1167             {
   1168                 if (email1.equalsIgnoreCase(email2))
   1169                 {
   1170                     union.add(email1);
   1171                 }
   1172                 else
   1173                 {
   1174                     union.add(email1);
   1175                     union.add(email2);
   1176                 }
   1177             }
   1178             // email2 specifies a domain
   1179             else if (email2.startsWith("."))
   1180             {
   1181                 if (withinDomain(_sub, email2))
   1182                 {
   1183                     union.add(email2);
   1184                 }
   1185                 else
   1186                 {
   1187                     union.add(email1);
   1188                     union.add(email2);
   1189                 }
   1190             }
   1191             // email2 specifies a particular host
   1192             else
   1193             {
   1194                 if (_sub.equalsIgnoreCase(email2))
   1195                 {
   1196                     union.add(email2);
   1197                 }
   1198                 else
   1199                 {
   1200                     union.add(email1);
   1201                     union.add(email2);
   1202                 }
   1203             }
   1204         }
   1205         // email1 specifies a domain
   1206         else if (email1.startsWith("."))
   1207         {
   1208             if (email2.indexOf('@') != -1)
   1209             {
   1210                 String _sub = email2.substring(email1.indexOf('@') + 1);
   1211                 if (withinDomain(_sub, email1))
   1212                 {
   1213                     union.add(email1);
   1214                 }
   1215                 else
   1216                 {
   1217                     union.add(email1);
   1218                     union.add(email2);
   1219                 }
   1220             }
   1221             // email2 specifies a domain
   1222             else if (email2.startsWith("."))
   1223             {
   1224                 if (withinDomain(email1, email2)
   1225                     || email1.equalsIgnoreCase(email2))
   1226                 {
   1227                     union.add(email2);
   1228                 }
   1229                 else if (withinDomain(email2, email1))
   1230                 {
   1231                     union.add(email1);
   1232                 }
   1233                 else
   1234                 {
   1235                     union.add(email1);
   1236                     union.add(email2);
   1237                 }
   1238             }
   1239             else
   1240             {
   1241                 if (withinDomain(email2, email1))
   1242                 {
   1243                     union.add(email1);
   1244                 }
   1245                 else
   1246                 {
   1247                     union.add(email1);
   1248                     union.add(email2);
   1249                 }
   1250             }
   1251         }
   1252         // email specifies a host
   1253         else
   1254         {
   1255             if (email2.indexOf('@') != -1)
   1256             {
   1257                 String _sub = email2.substring(email1.indexOf('@') + 1);
   1258                 if (_sub.equalsIgnoreCase(email1))
   1259                 {
   1260                     union.add(email1);
   1261                 }
   1262                 else
   1263                 {
   1264                     union.add(email1);
   1265                     union.add(email2);
   1266                 }
   1267             }
   1268             // email2 specifies a domain
   1269             else if (email2.startsWith("."))
   1270             {
   1271                 if (withinDomain(email1, email2))
   1272                 {
   1273                     union.add(email2);
   1274                 }
   1275                 else
   1276                 {
   1277                     union.add(email1);
   1278                     union.add(email2);
   1279                 }
   1280             }
   1281             // email2 specifies a particular host
   1282             else
   1283             {
   1284                 if (email1.equalsIgnoreCase(email2))
   1285                 {
   1286                     union.add(email1);
   1287                 }
   1288                 else
   1289                 {
   1290                     union.add(email1);
   1291                     union.add(email2);
   1292                 }
   1293             }
   1294         }
   1295     }
   1296 
   1297     private Set intersectDNS(Set permitted, Set dnss)
   1298     {
   1299         Set intersect = new HashSet();
   1300         for (Iterator it = dnss.iterator(); it.hasNext(); )
   1301         {
   1302             String dns = extractNameAsString(((GeneralSubtree)it.next())
   1303                 .getBase());
   1304             if (permitted == null)
   1305             {
   1306                 if (dns != null)
   1307                 {
   1308                     intersect.add(dns);
   1309                 }
   1310             }
   1311             else
   1312             {
   1313                 Iterator _iter = permitted.iterator();
   1314                 while (_iter.hasNext())
   1315                 {
   1316                     String _permitted = (String)_iter.next();
   1317 
   1318                     if (withinDomain(_permitted, dns))
   1319                     {
   1320                         intersect.add(_permitted);
   1321                     }
   1322                     else if (withinDomain(dns, _permitted))
   1323                     {
   1324                         intersect.add(dns);
   1325                     }
   1326                 }
   1327             }
   1328         }
   1329 
   1330         return intersect;
   1331     }
   1332 
   1333     private Set unionDNS(Set excluded, String dns)
   1334     {
   1335         if (excluded.isEmpty())
   1336         {
   1337             if (dns == null)
   1338             {
   1339                 return excluded;
   1340             }
   1341             excluded.add(dns);
   1342 
   1343             return excluded;
   1344         }
   1345         else
   1346         {
   1347             Set union = new HashSet();
   1348 
   1349             Iterator _iter = excluded.iterator();
   1350             while (_iter.hasNext())
   1351             {
   1352                 String _permitted = (String)_iter.next();
   1353 
   1354                 if (withinDomain(_permitted, dns))
   1355                 {
   1356                     union.add(dns);
   1357                 }
   1358                 else if (withinDomain(dns, _permitted))
   1359                 {
   1360                     union.add(_permitted);
   1361                 }
   1362                 else
   1363                 {
   1364                     union.add(_permitted);
   1365                     union.add(dns);
   1366                 }
   1367             }
   1368 
   1369             return union;
   1370         }
   1371     }
   1372 
   1373     /**
   1374      * The most restricting part from <code>email1</code> and
   1375      * <code>email2</code> is added to the intersection <code>intersect</code>.
   1376      *
   1377      * @param email1    Email address constraint 1.
   1378      * @param email2    Email address constraint 2.
   1379      * @param intersect The intersection.
   1380      */
   1381     private void intersectEmail(String email1, String email2, Set intersect)
   1382     {
   1383         // email1 is a particular address
   1384         if (email1.indexOf('@') != -1)
   1385         {
   1386             String _sub = email1.substring(email1.indexOf('@') + 1);
   1387             // both are a particular mailbox
   1388             if (email2.indexOf('@') != -1)
   1389             {
   1390                 if (email1.equalsIgnoreCase(email2))
   1391                 {
   1392                     intersect.add(email1);
   1393                 }
   1394             }
   1395             // email2 specifies a domain
   1396             else if (email2.startsWith("."))
   1397             {
   1398                 if (withinDomain(_sub, email2))
   1399                 {
   1400                     intersect.add(email1);
   1401                 }
   1402             }
   1403             // email2 specifies a particular host
   1404             else
   1405             {
   1406                 if (_sub.equalsIgnoreCase(email2))
   1407                 {
   1408                     intersect.add(email1);
   1409                 }
   1410             }
   1411         }
   1412         // email specifies a domain
   1413         else if (email1.startsWith("."))
   1414         {
   1415             if (email2.indexOf('@') != -1)
   1416             {
   1417                 String _sub = email2.substring(email1.indexOf('@') + 1);
   1418                 if (withinDomain(_sub, email1))
   1419                 {
   1420                     intersect.add(email2);
   1421                 }
   1422             }
   1423             // email2 specifies a domain
   1424             else if (email2.startsWith("."))
   1425             {
   1426                 if (withinDomain(email1, email2)
   1427                     || email1.equalsIgnoreCase(email2))
   1428                 {
   1429                     intersect.add(email1);
   1430                 }
   1431                 else if (withinDomain(email2, email1))
   1432                 {
   1433                     intersect.add(email2);
   1434                 }
   1435             }
   1436             else
   1437             {
   1438                 if (withinDomain(email2, email1))
   1439                 {
   1440                     intersect.add(email2);
   1441                 }
   1442             }
   1443         }
   1444         // email1 specifies a host
   1445         else
   1446         {
   1447             if (email2.indexOf('@') != -1)
   1448             {
   1449                 String _sub = email2.substring(email2.indexOf('@') + 1);
   1450                 if (_sub.equalsIgnoreCase(email1))
   1451                 {
   1452                     intersect.add(email2);
   1453                 }
   1454             }
   1455             // email2 specifies a domain
   1456             else if (email2.startsWith("."))
   1457             {
   1458                 if (withinDomain(email1, email2))
   1459                 {
   1460                     intersect.add(email1);
   1461                 }
   1462             }
   1463             // email2 specifies a particular host
   1464             else
   1465             {
   1466                 if (email1.equalsIgnoreCase(email2))
   1467                 {
   1468                     intersect.add(email1);
   1469                 }
   1470             }
   1471         }
   1472     }
   1473 
   1474     private void checkExcludedURI(Set excluded, String uri)
   1475         throws NameConstraintValidatorException
   1476     {
   1477         if (excluded.isEmpty())
   1478         {
   1479             return;
   1480         }
   1481 
   1482         Iterator it = excluded.iterator();
   1483 
   1484         while (it.hasNext())
   1485         {
   1486             String str = ((String)it.next());
   1487 
   1488             if (isUriConstrained(uri, str))
   1489             {
   1490                 throw new NameConstraintValidatorException(
   1491                     "URI is from an excluded subtree.");
   1492             }
   1493         }
   1494     }
   1495 
   1496     private Set intersectURI(Set permitted, Set uris)
   1497     {
   1498         Set intersect = new HashSet();
   1499         for (Iterator it = uris.iterator(); it.hasNext(); )
   1500         {
   1501             String uri = extractNameAsString(((GeneralSubtree)it.next())
   1502                 .getBase());
   1503             if (permitted == null)
   1504             {
   1505                 if (uri != null)
   1506                 {
   1507                     intersect.add(uri);
   1508                 }
   1509             }
   1510             else
   1511             {
   1512                 Iterator _iter = permitted.iterator();
   1513                 while (_iter.hasNext())
   1514                 {
   1515                     String _permitted = (String)_iter.next();
   1516                     intersectURI(_permitted, uri, intersect);
   1517                 }
   1518             }
   1519         }
   1520         return intersect;
   1521     }
   1522 
   1523     private Set unionURI(Set excluded, String uri)
   1524     {
   1525         if (excluded.isEmpty())
   1526         {
   1527             if (uri == null)
   1528             {
   1529                 return excluded;
   1530             }
   1531             excluded.add(uri);
   1532 
   1533             return excluded;
   1534         }
   1535         else
   1536         {
   1537             Set union = new HashSet();
   1538 
   1539             Iterator _iter = excluded.iterator();
   1540             while (_iter.hasNext())
   1541             {
   1542                 String _excluded = (String)_iter.next();
   1543 
   1544                 unionURI(_excluded, uri, union);
   1545             }
   1546 
   1547             return union;
   1548         }
   1549     }
   1550 
   1551     private void intersectURI(String email1, String email2, Set intersect)
   1552     {
   1553         // email1 is a particular address
   1554         if (email1.indexOf('@') != -1)
   1555         {
   1556             String _sub = email1.substring(email1.indexOf('@') + 1);
   1557             // both are a particular mailbox
   1558             if (email2.indexOf('@') != -1)
   1559             {
   1560                 if (email1.equalsIgnoreCase(email2))
   1561                 {
   1562                     intersect.add(email1);
   1563                 }
   1564             }
   1565             // email2 specifies a domain
   1566             else if (email2.startsWith("."))
   1567             {
   1568                 if (withinDomain(_sub, email2))
   1569                 {
   1570                     intersect.add(email1);
   1571                 }
   1572             }
   1573             // email2 specifies a particular host
   1574             else
   1575             {
   1576                 if (_sub.equalsIgnoreCase(email2))
   1577                 {
   1578                     intersect.add(email1);
   1579                 }
   1580             }
   1581         }
   1582         // email specifies a domain
   1583         else if (email1.startsWith("."))
   1584         {
   1585             if (email2.indexOf('@') != -1)
   1586             {
   1587                 String _sub = email2.substring(email1.indexOf('@') + 1);
   1588                 if (withinDomain(_sub, email1))
   1589                 {
   1590                     intersect.add(email2);
   1591                 }
   1592             }
   1593             // email2 specifies a domain
   1594             else if (email2.startsWith("."))
   1595             {
   1596                 if (withinDomain(email1, email2)
   1597                     || email1.equalsIgnoreCase(email2))
   1598                 {
   1599                     intersect.add(email1);
   1600                 }
   1601                 else if (withinDomain(email2, email1))
   1602                 {
   1603                     intersect.add(email2);
   1604                 }
   1605             }
   1606             else
   1607             {
   1608                 if (withinDomain(email2, email1))
   1609                 {
   1610                     intersect.add(email2);
   1611                 }
   1612             }
   1613         }
   1614         // email1 specifies a host
   1615         else
   1616         {
   1617             if (email2.indexOf('@') != -1)
   1618             {
   1619                 String _sub = email2.substring(email2.indexOf('@') + 1);
   1620                 if (_sub.equalsIgnoreCase(email1))
   1621                 {
   1622                     intersect.add(email2);
   1623                 }
   1624             }
   1625             // email2 specifies a domain
   1626             else if (email2.startsWith("."))
   1627             {
   1628                 if (withinDomain(email1, email2))
   1629                 {
   1630                     intersect.add(email1);
   1631                 }
   1632             }
   1633             // email2 specifies a particular host
   1634             else
   1635             {
   1636                 if (email1.equalsIgnoreCase(email2))
   1637                 {
   1638                     intersect.add(email1);
   1639                 }
   1640             }
   1641         }
   1642     }
   1643 
   1644     private void checkPermittedURI(Set permitted, String uri)
   1645         throws NameConstraintValidatorException
   1646     {
   1647         if (permitted == null)
   1648         {
   1649             return;
   1650         }
   1651 
   1652         Iterator it = permitted.iterator();
   1653 
   1654         while (it.hasNext())
   1655         {
   1656             String str = ((String)it.next());
   1657 
   1658             if (isUriConstrained(uri, str))
   1659             {
   1660                 return;
   1661             }
   1662         }
   1663         if (uri.length() == 0 && permitted.size() == 0)
   1664         {
   1665             return;
   1666         }
   1667         throw new NameConstraintValidatorException(
   1668             "URI is not from a permitted subtree.");
   1669     }
   1670 
   1671     private boolean isUriConstrained(String uri, String constraint)
   1672     {
   1673         String host = extractHostFromURL(uri);
   1674         // a host
   1675         if (!constraint.startsWith("."))
   1676         {
   1677             if (host.equalsIgnoreCase(constraint))
   1678             {
   1679                 return true;
   1680             }
   1681         }
   1682 
   1683         // in sub domain or domain
   1684         else if (withinDomain(host, constraint))
   1685         {
   1686             return true;
   1687         }
   1688 
   1689         return false;
   1690     }
   1691 
   1692     private static String extractHostFromURL(String url)
   1693     {
   1694         // see RFC 1738
   1695         // remove ':' after protocol, e.g. http:
   1696         String sub = url.substring(url.indexOf(':') + 1);
   1697         // extract host from Common Internet Scheme Syntax, e.g. http://
   1698         if (sub.indexOf("//") != -1)
   1699         {
   1700             sub = sub.substring(sub.indexOf("//") + 2);
   1701         }
   1702         // first remove port, e.g. http://test.com:21
   1703         if (sub.lastIndexOf(':') != -1)
   1704         {
   1705             sub = sub.substring(0, sub.lastIndexOf(':'));
   1706         }
   1707         // remove user and password, e.g. http://john:password@test.com
   1708         sub = sub.substring(sub.indexOf(':') + 1);
   1709         sub = sub.substring(sub.indexOf('@') + 1);
   1710         // remove local parts, e.g. http://test.com/bla
   1711         if (sub.indexOf('/') != -1)
   1712         {
   1713             sub = sub.substring(0, sub.indexOf('/'));
   1714         }
   1715         return sub;
   1716     }
   1717 
   1718     private String extractNameAsString(GeneralName name)
   1719     {
   1720         return DERIA5String.getInstance(name.getName()).getString();
   1721     }
   1722 
   1723     /**
   1724      * Returns the maximum IP address.
   1725      *
   1726      * @param ip1 The first IP address.
   1727      * @param ip2 The second IP address.
   1728      * @return The maximum IP address.
   1729      */
   1730     private static byte[] max(byte[] ip1, byte[] ip2)
   1731     {
   1732         for (int i = 0; i < ip1.length; i++)
   1733         {
   1734             if ((ip1[i] & 0xFFFF) > (ip2[i] & 0xFFFF))
   1735             {
   1736                 return ip1;
   1737             }
   1738         }
   1739         return ip2;
   1740     }
   1741 
   1742     /**
   1743      * Returns the minimum IP address.
   1744      *
   1745      * @param ip1 The first IP address.
   1746      * @param ip2 The second IP address.
   1747      * @return The minimum IP address.
   1748      */
   1749     private static byte[] min(byte[] ip1, byte[] ip2)
   1750     {
   1751         for (int i = 0; i < ip1.length; i++)
   1752         {
   1753             if ((ip1[i] & 0xFFFF) < (ip2[i] & 0xFFFF))
   1754             {
   1755                 return ip1;
   1756             }
   1757         }
   1758         return ip2;
   1759     }
   1760 
   1761     /**
   1762      * Compares IP address <code>ip1</code> with <code>ip2</code>. If ip1
   1763      * is equal to ip2 0 is returned. If ip1 is bigger 1 is returned, -1
   1764      * otherwise.
   1765      *
   1766      * @param ip1 The first IP address.
   1767      * @param ip2 The second IP address.
   1768      * @return 0 if ip1 is equal to ip2, 1 if ip1 is bigger, -1 otherwise.
   1769      */
   1770     private static int compareTo(byte[] ip1, byte[] ip2)
   1771     {
   1772         if (Arrays.areEqual(ip1, ip2))
   1773         {
   1774             return 0;
   1775         }
   1776         if (Arrays.areEqual(max(ip1, ip2), ip1))
   1777         {
   1778             return 1;
   1779         }
   1780         return -1;
   1781     }
   1782 
   1783     /**
   1784      * Returns the logical OR of the IP addresses <code>ip1</code> and
   1785      * <code>ip2</code>.
   1786      *
   1787      * @param ip1 The first IP address.
   1788      * @param ip2 The second IP address.
   1789      * @return The OR of <code>ip1</code> and <code>ip2</code>.
   1790      */
   1791     private static byte[] or(byte[] ip1, byte[] ip2)
   1792     {
   1793         byte[] temp = new byte[ip1.length];
   1794         for (int i = 0; i < ip1.length; i++)
   1795         {
   1796             temp[i] = (byte)(ip1[i] | ip2[i]);
   1797         }
   1798         return temp;
   1799     }
   1800 
   1801     private int hashCollection(Collection coll)
   1802     {
   1803         if (coll == null)
   1804         {
   1805             return 0;
   1806         }
   1807         int hash = 0;
   1808         Iterator it1 = coll.iterator();
   1809         while (it1.hasNext())
   1810         {
   1811             Object o = it1.next();
   1812             if (o instanceof byte[])
   1813             {
   1814                 hash += Arrays.hashCode((byte[])o);
   1815             }
   1816             else
   1817             {
   1818                 hash += o.hashCode();
   1819             }
   1820         }
   1821         return hash;
   1822     }
   1823 
   1824     private boolean collectionsAreEqual(Collection coll1, Collection coll2)
   1825     {
   1826         if (coll1 == coll2)
   1827         {
   1828             return true;
   1829         }
   1830         if (coll1 == null || coll2 == null)
   1831         {
   1832             return false;
   1833         }
   1834         if (coll1.size() != coll2.size())
   1835         {
   1836             return false;
   1837         }
   1838         Iterator it1 = coll1.iterator();
   1839 
   1840         while (it1.hasNext())
   1841         {
   1842             Object a = it1.next();
   1843             Iterator it2 = coll2.iterator();
   1844             boolean found = false;
   1845             while (it2.hasNext())
   1846             {
   1847                 Object b = it2.next();
   1848                 if (equals(a, b))
   1849                 {
   1850                     found = true;
   1851                     break;
   1852                 }
   1853             }
   1854             if (!found)
   1855             {
   1856                 return false;
   1857             }
   1858         }
   1859         return true;
   1860     }
   1861 
   1862     private boolean equals(Object o1, Object o2)
   1863     {
   1864         if (o1 == o2)
   1865         {
   1866             return true;
   1867         }
   1868         if (o1 == null || o2 == null)
   1869         {
   1870             return false;
   1871         }
   1872         if (o1 instanceof byte[] && o2 instanceof byte[])
   1873         {
   1874             return Arrays.areEqual((byte[])o1, (byte[])o2);
   1875         }
   1876         else
   1877         {
   1878             return o1.equals(o2);
   1879         }
   1880     }
   1881 
   1882     /**
   1883      * Stringifies an IPv4 or v6 address with subnet mask.
   1884      *
   1885      * @param ip The IP with subnet mask.
   1886      * @return The stringified IP address.
   1887      */
   1888     private String stringifyIP(byte[] ip)
   1889     {
   1890         String temp = "";
   1891         for (int i = 0; i < ip.length / 2; i++)
   1892         {
   1893             temp += Integer.toString(ip[i] & 0x00FF) + ".";
   1894         }
   1895         temp = temp.substring(0, temp.length() - 1);
   1896         temp += "/";
   1897         for (int i = ip.length / 2; i < ip.length; i++)
   1898         {
   1899             temp += Integer.toString(ip[i] & 0x00FF) + ".";
   1900         }
   1901         temp = temp.substring(0, temp.length() - 1);
   1902         return temp;
   1903     }
   1904 
   1905     private String stringifyIPCollection(Set ips)
   1906     {
   1907         String temp = "";
   1908         temp += "[";
   1909         for (Iterator it = ips.iterator(); it.hasNext(); )
   1910         {
   1911             temp += stringifyIP((byte[])it.next()) + ",";
   1912         }
   1913         if (temp.length() > 1)
   1914         {
   1915             temp = temp.substring(0, temp.length() - 1);
   1916         }
   1917         temp += "]";
   1918         return temp;
   1919     }
   1920 }
   1921