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