1 package org.bouncycastle.jce.provider; 2 3 import org.bouncycastle.asn1.ASN1OctetString; 4 import org.bouncycastle.asn1.ASN1Sequence; 5 import org.bouncycastle.asn1.DERIA5String; 6 import org.bouncycastle.asn1.x509.GeneralName; 7 import org.bouncycastle.asn1.x509.GeneralSubtree; 8 import org.bouncycastle.util.Arrays; 9 import org.bouncycastle.util.Strings; 10 11 import java.util.Collection; 12 import java.util.Collections; 13 import java.util.Enumeration; 14 import java.util.HashMap; 15 import java.util.HashSet; 16 import java.util.Iterator; 17 import java.util.Map; 18 import java.util.Set; 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().getDERObject()); 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 .getDERObject())); 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 .getDERObject())); 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 /** 1522 * Updates the permitted set of these name constraints with the intersection 1523 * with the given subtree. 1524 * 1525 * @param permitted The permitted subtrees 1526 */ 1527 1528 public void intersectPermittedSubtree(ASN1Sequence permitted) 1529 { 1530 Map subtreesMap = new HashMap(); 1531 1532 // group in sets in a map ordered by tag no. 1533 for (Enumeration e = permitted.getObjects(); e.hasMoreElements();) 1534 { 1535 GeneralSubtree subtree = GeneralSubtree.getInstance(e.nextElement()); 1536 // BEGIN android-changed 1537 Integer tagNo = Integer.valueOf(subtree.getBase().getTagNo()); 1538 // END android-changed 1539 if (subtreesMap.get(tagNo) == null) 1540 { 1541 subtreesMap.put(tagNo, new HashSet()); 1542 } 1543 ((Set)subtreesMap.get(tagNo)).add(subtree); 1544 } 1545 1546 for (Iterator it = subtreesMap.entrySet().iterator(); it.hasNext();) 1547 { 1548 Map.Entry entry = (Map.Entry)it.next(); 1549 1550 // go through all subtree groups 1551 switch (((Integer)entry.getKey()).intValue()) 1552 { 1553 case 1: 1554 permittedSubtreesEmail = intersectEmail(permittedSubtreesEmail, 1555 (Set)entry.getValue()); 1556 break; 1557 case 2: 1558 permittedSubtreesDNS = intersectDNS(permittedSubtreesDNS, 1559 (Set)entry.getValue()); 1560 break; 1561 case 4: 1562 permittedSubtreesDN = intersectDN(permittedSubtreesDN, 1563 (Set)entry.getValue()); 1564 break; 1565 case 6: 1566 permittedSubtreesURI = intersectURI(permittedSubtreesURI, 1567 (Set)entry.getValue()); 1568 break; 1569 case 7: 1570 permittedSubtreesIP = intersectIP(permittedSubtreesIP, 1571 (Set)entry.getValue()); 1572 } 1573 } 1574 } 1575 1576 private String extractNameAsString(GeneralName name) 1577 { 1578 return DERIA5String.getInstance(name.getName()).getString(); 1579 } 1580 1581 public void intersectEmptyPermittedSubtree(int nameType) 1582 { 1583 switch (nameType) 1584 { 1585 case 1: 1586 permittedSubtreesEmail = new HashSet(); 1587 break; 1588 case 2: 1589 permittedSubtreesDNS = new HashSet(); 1590 break; 1591 case 4: 1592 permittedSubtreesDN = new HashSet(); 1593 break; 1594 case 6: 1595 permittedSubtreesURI = new HashSet(); 1596 break; 1597 case 7: 1598 permittedSubtreesIP = new HashSet(); 1599 } 1600 } 1601 1602 /** 1603 * Adds a subtree to the excluded set of these name constraints. 1604 * 1605 * @param subtree A subtree with an excluded GeneralName. 1606 */ 1607 public void addExcludedSubtree(GeneralSubtree subtree) 1608 { 1609 GeneralName base = subtree.getBase(); 1610 1611 switch (base.getTagNo()) 1612 { 1613 case 1: 1614 excludedSubtreesEmail = unionEmail(excludedSubtreesEmail, 1615 extractNameAsString(base)); 1616 break; 1617 case 2: 1618 excludedSubtreesDNS = unionDNS(excludedSubtreesDNS, 1619 extractNameAsString(base)); 1620 break; 1621 case 4: 1622 excludedSubtreesDN = unionDN(excludedSubtreesDN, 1623 (ASN1Sequence)base.getName().getDERObject()); 1624 break; 1625 case 6: 1626 excludedSubtreesURI = unionURI(excludedSubtreesURI, 1627 extractNameAsString(base)); 1628 break; 1629 case 7: 1630 excludedSubtreesIP = unionIP(excludedSubtreesIP, ASN1OctetString 1631 .getInstance(base.getName()).getOctets()); 1632 break; 1633 } 1634 } 1635 1636 /** 1637 * Returns the maximum IP address. 1638 * 1639 * @param ip1 The first IP address. 1640 * @param ip2 The second IP address. 1641 * @return The maximum IP address. 1642 */ 1643 private static byte[] max(byte[] ip1, byte[] ip2) 1644 { 1645 for (int i = 0; i < ip1.length; i++) 1646 { 1647 if ((ip1[i] & 0xFFFF) > (ip2[i] & 0xFFFF)) 1648 { 1649 return ip1; 1650 } 1651 } 1652 return ip2; 1653 } 1654 1655 /** 1656 * Returns the minimum IP address. 1657 * 1658 * @param ip1 The first IP address. 1659 * @param ip2 The second IP address. 1660 * @return The minimum IP address. 1661 */ 1662 private static byte[] min(byte[] ip1, byte[] ip2) 1663 { 1664 for (int i = 0; i < ip1.length; i++) 1665 { 1666 if ((ip1[i] & 0xFFFF) < (ip2[i] & 0xFFFF)) 1667 { 1668 return ip1; 1669 } 1670 } 1671 return ip2; 1672 } 1673 1674 /** 1675 * Compares IP address <code>ip1</code> with <code>ip2</code>. If ip1 1676 * is equal to ip2 0 is returned. If ip1 is bigger 1 is returned, -1 1677 * otherwise. 1678 * 1679 * @param ip1 The first IP address. 1680 * @param ip2 The second IP address. 1681 * @return 0 if ip1 is equal to ip2, 1 if ip1 is bigger, -1 otherwise. 1682 */ 1683 private static int compareTo(byte[] ip1, byte[] ip2) 1684 { 1685 if (Arrays.areEqual(ip1, ip2)) 1686 { 1687 return 0; 1688 } 1689 if (Arrays.areEqual(max(ip1, ip2), ip1)) 1690 { 1691 return 1; 1692 } 1693 return -1; 1694 } 1695 1696 /** 1697 * Returns the logical OR of the IP addresses <code>ip1</code> and 1698 * <code>ip2</code>. 1699 * 1700 * @param ip1 The first IP address. 1701 * @param ip2 The second IP address. 1702 * @return The OR of <code>ip1</code> and <code>ip2</code>. 1703 */ 1704 private static byte[] or(byte[] ip1, byte[] ip2) 1705 { 1706 byte[] temp = new byte[ip1.length]; 1707 for (int i = 0; i < ip1.length; i++) 1708 { 1709 temp[i] = (byte)(ip1[i] | ip2[i]); 1710 } 1711 return temp; 1712 } 1713 1714 public int hashCode() 1715 { 1716 return hashCollection(excludedSubtreesDN) 1717 + hashCollection(excludedSubtreesDNS) 1718 + hashCollection(excludedSubtreesEmail) 1719 + hashCollection(excludedSubtreesIP) 1720 + hashCollection(excludedSubtreesURI) 1721 + hashCollection(permittedSubtreesDN) 1722 + hashCollection(permittedSubtreesDNS) 1723 + hashCollection(permittedSubtreesEmail) 1724 + hashCollection(permittedSubtreesIP) 1725 + hashCollection(permittedSubtreesURI); 1726 } 1727 1728 private int hashCollection(Collection coll) 1729 { 1730 if (coll == null) 1731 { 1732 return 0; 1733 } 1734 int hash = 0; 1735 Iterator it1 = coll.iterator(); 1736 while (it1.hasNext()) 1737 { 1738 Object o = it1.next(); 1739 if (o instanceof byte[]) 1740 { 1741 hash += Arrays.hashCode((byte[])o); 1742 } 1743 else 1744 { 1745 hash += o.hashCode(); 1746 } 1747 } 1748 return hash; 1749 } 1750 1751 public boolean equals(Object o) 1752 { 1753 if (!(o instanceof PKIXNameConstraintValidator)) 1754 { 1755 return false; 1756 } 1757 PKIXNameConstraintValidator constraintValidator = (PKIXNameConstraintValidator)o; 1758 return collectionsAreEqual(constraintValidator.excludedSubtreesDN, excludedSubtreesDN) 1759 && collectionsAreEqual(constraintValidator.excludedSubtreesDNS, excludedSubtreesDNS) 1760 && collectionsAreEqual(constraintValidator.excludedSubtreesEmail, excludedSubtreesEmail) 1761 && collectionsAreEqual(constraintValidator.excludedSubtreesIP, excludedSubtreesIP) 1762 && collectionsAreEqual(constraintValidator.excludedSubtreesURI, excludedSubtreesURI) 1763 && collectionsAreEqual(constraintValidator.permittedSubtreesDN, permittedSubtreesDN) 1764 && collectionsAreEqual(constraintValidator.permittedSubtreesDNS, permittedSubtreesDNS) 1765 && collectionsAreEqual(constraintValidator.permittedSubtreesEmail, permittedSubtreesEmail) 1766 && collectionsAreEqual(constraintValidator.permittedSubtreesIP, permittedSubtreesIP) 1767 && collectionsAreEqual(constraintValidator.permittedSubtreesURI, permittedSubtreesURI); 1768 } 1769 1770 private boolean collectionsAreEqual(Collection coll1, Collection coll2) 1771 { 1772 if (coll1 == coll2) 1773 { 1774 return true; 1775 } 1776 if (coll1 == null || coll2 == null) 1777 { 1778 return false; 1779 } 1780 if (coll1.size() != coll2.size()) 1781 { 1782 return false; 1783 } 1784 Iterator it1 = coll1.iterator(); 1785 1786 while (it1.hasNext()) 1787 { 1788 Object a = it1.next(); 1789 Iterator it2 = coll2.iterator(); 1790 boolean found = false; 1791 while (it2.hasNext()) 1792 { 1793 Object b = it2.next(); 1794 if (equals(a, b)) 1795 { 1796 found = true; 1797 break; 1798 } 1799 } 1800 if (!found) 1801 { 1802 return false; 1803 } 1804 } 1805 return true; 1806 } 1807 1808 private boolean equals(Object o1, Object o2) 1809 { 1810 if (o1 == o2) 1811 { 1812 return true; 1813 } 1814 if (o1 == null || o2 == null) 1815 { 1816 return false; 1817 } 1818 if (o1 instanceof byte[] && o2 instanceof byte[]) 1819 { 1820 return Arrays.areEqual((byte[])o1, (byte[])o2); 1821 } 1822 else 1823 { 1824 return o1.equals(o2); 1825 } 1826 } 1827 1828 /** 1829 * Stringifies an IPv4 or v6 address with subnet mask. 1830 * 1831 * @param ip The IP with subnet mask. 1832 * @return The stringified IP address. 1833 */ 1834 private String stringifyIP(byte[] ip) 1835 { 1836 String temp = ""; 1837 for (int i = 0; i < ip.length / 2; i++) 1838 { 1839 temp += Integer.toString(ip[i] & 0x00FF) + "."; 1840 } 1841 temp = temp.substring(0, temp.length() - 1); 1842 temp += "/"; 1843 for (int i = ip.length / 2; i < ip.length; i++) 1844 { 1845 temp += Integer.toString(ip[i] & 0x00FF) + "."; 1846 } 1847 temp = temp.substring(0, temp.length() - 1); 1848 return temp; 1849 } 1850 1851 private String stringifyIPCollection(Set ips) 1852 { 1853 String temp = ""; 1854 temp += "["; 1855 for (Iterator it = ips.iterator(); it.hasNext();) 1856 { 1857 temp += stringifyIP((byte[])it.next()) + ","; 1858 } 1859 if (temp.length() > 1) 1860 { 1861 temp = temp.substring(0, temp.length() - 1); 1862 } 1863 temp += "]"; 1864 return temp; 1865 } 1866 1867 public String toString() 1868 { 1869 String temp = ""; 1870 temp += "permitted:\n"; 1871 if (permittedSubtreesDN != null) 1872 { 1873 temp += "DN:\n"; 1874 temp += permittedSubtreesDN.toString() + "\n"; 1875 } 1876 if (permittedSubtreesDNS != null) 1877 { 1878 temp += "DNS:\n"; 1879 temp += permittedSubtreesDNS.toString() + "\n"; 1880 } 1881 if (permittedSubtreesEmail != null) 1882 { 1883 temp += "Email:\n"; 1884 temp += permittedSubtreesEmail.toString() + "\n"; 1885 } 1886 if (permittedSubtreesURI != null) 1887 { 1888 temp += "URI:\n"; 1889 temp += permittedSubtreesURI.toString() + "\n"; 1890 } 1891 if (permittedSubtreesIP != null) 1892 { 1893 temp += "IP:\n"; 1894 temp += stringifyIPCollection(permittedSubtreesIP) + "\n"; 1895 } 1896 temp += "excluded:\n"; 1897 if (!excludedSubtreesDN.isEmpty()) 1898 { 1899 temp += "DN:\n"; 1900 temp += excludedSubtreesDN.toString() + "\n"; 1901 } 1902 if (!excludedSubtreesDNS.isEmpty()) 1903 { 1904 temp += "DNS:\n"; 1905 temp += excludedSubtreesDNS.toString() + "\n"; 1906 } 1907 if (!excludedSubtreesEmail.isEmpty()) 1908 { 1909 temp += "Email:\n"; 1910 temp += excludedSubtreesEmail.toString() + "\n"; 1911 } 1912 if (!excludedSubtreesURI.isEmpty()) 1913 { 1914 temp += "URI:\n"; 1915 temp += excludedSubtreesURI.toString() + "\n"; 1916 } 1917 if (!excludedSubtreesIP.isEmpty()) 1918 { 1919 temp += "IP:\n"; 1920 temp += stringifyIPCollection(excludedSubtreesIP) + "\n"; 1921 } 1922 return temp; 1923 } 1924 } 1925