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