1package org.bouncycastle.jce.provider; 2 3import java.util.Collection; 4import java.util.Collections; 5import java.util.HashMap; 6import java.util.HashSet; 7import java.util.Iterator; 8import java.util.Map; 9import java.util.Set; 10 11import org.bouncycastle.asn1.ASN1OctetString; 12import org.bouncycastle.asn1.ASN1Sequence; 13import org.bouncycastle.asn1.DERIA5String; 14import org.bouncycastle.asn1.x509.GeneralName; 15import org.bouncycastle.asn1.x509.GeneralSubtree; 16import org.bouncycastle.util.Arrays; 17import org.bouncycastle.util.Integers; 18import org.bouncycastle.util.Strings; 19 20public 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 or @domain 639 if (constraint.indexOf('@') != -1) 640 { 641 if (email.equalsIgnoreCase(constraint)) 642 { 643 return true; 644 } 645 if (sub.equalsIgnoreCase(constraint.substring(1))) 646 { 647 return true; 648 } 649 } 650 // on particular host 651 else if (!(constraint.charAt(0) == '.')) 652 { 653 if (sub.equalsIgnoreCase(constraint)) 654 { 655 return true; 656 } 657 } 658 // address in sub domain 659 else if (withinDomain(sub, constraint)) 660 { 661 return true; 662 } 663 return false; 664 } 665 666 private boolean withinDomain(String testDomain, String domain) 667 { 668 String tempDomain = domain; 669 if (tempDomain.startsWith(".")) 670 { 671 tempDomain = tempDomain.substring(1); 672 } 673 String[] domainParts = Strings.split(tempDomain, '.'); 674 String[] testDomainParts = Strings.split(testDomain, '.'); 675 // must have at least one subdomain 676 if (testDomainParts.length <= domainParts.length) 677 { 678 return false; 679 } 680 int d = testDomainParts.length - domainParts.length; 681 for (int i = -1; i < domainParts.length; i++) 682 { 683 if (i == -1) 684 { 685 if (testDomainParts[i + d].equals("")) 686 { 687 return false; 688 } 689 } 690 else if (!domainParts[i].equalsIgnoreCase(testDomainParts[i + d])) 691 { 692 return false; 693 } 694 } 695 return true; 696 } 697 698 private void checkPermittedDNS(Set permitted, String dns) 699 throws PKIXNameConstraintValidatorException 700 { 701 if (permitted == null) 702 { 703 return; 704 } 705 706 Iterator it = permitted.iterator(); 707 708 while (it.hasNext()) 709 { 710 String str = ((String)it.next()); 711 712 // is sub domain 713 if (withinDomain(dns, str) || dns.equalsIgnoreCase(str)) 714 { 715 return; 716 } 717 } 718 if (dns.length() == 0 && permitted.size() == 0) 719 { 720 return; 721 } 722 throw new PKIXNameConstraintValidatorException( 723 "DNS is not from a permitted subtree."); 724 } 725 726 private void checkExcludedDNS(Set excluded, String dns) 727 throws PKIXNameConstraintValidatorException 728 { 729 if (excluded.isEmpty()) 730 { 731 return; 732 } 733 734 Iterator it = excluded.iterator(); 735 736 while (it.hasNext()) 737 { 738 String str = ((String)it.next()); 739 740 // is sub domain or the same 741 if (withinDomain(dns, str) || dns.equalsIgnoreCase(str)) 742 { 743 throw new PKIXNameConstraintValidatorException( 744 "DNS is from an excluded subtree."); 745 } 746 } 747 } 748 749 /** 750 * The common part of <code>email1</code> and <code>email2</code> is 751 * added to the union <code>union</code>. If <code>email1</code> and 752 * <code>email2</code> have nothing in common they are added both. 753 * 754 * @param email1 Email address constraint 1. 755 * @param email2 Email address constraint 2. 756 * @param union The union. 757 */ 758 private void unionEmail(String email1, String email2, Set union) 759 { 760 // email1 is a particular address 761 if (email1.indexOf('@') != -1) 762 { 763 String _sub = email1.substring(email1.indexOf('@') + 1); 764 // both are a particular mailbox 765 if (email2.indexOf('@') != -1) 766 { 767 if (email1.equalsIgnoreCase(email2)) 768 { 769 union.add(email1); 770 } 771 else 772 { 773 union.add(email1); 774 union.add(email2); 775 } 776 } 777 // email2 specifies a domain 778 else if (email2.startsWith(".")) 779 { 780 if (withinDomain(_sub, email2)) 781 { 782 union.add(email2); 783 } 784 else 785 { 786 union.add(email1); 787 union.add(email2); 788 } 789 } 790 // email2 specifies a particular host 791 else 792 { 793 if (_sub.equalsIgnoreCase(email2)) 794 { 795 union.add(email2); 796 } 797 else 798 { 799 union.add(email1); 800 union.add(email2); 801 } 802 } 803 } 804 // email1 specifies a domain 805 else if (email1.startsWith(".")) 806 { 807 if (email2.indexOf('@') != -1) 808 { 809 String _sub = email2.substring(email1.indexOf('@') + 1); 810 if (withinDomain(_sub, email1)) 811 { 812 union.add(email1); 813 } 814 else 815 { 816 union.add(email1); 817 union.add(email2); 818 } 819 } 820 // email2 specifies a domain 821 else if (email2.startsWith(".")) 822 { 823 if (withinDomain(email1, email2) 824 || email1.equalsIgnoreCase(email2)) 825 { 826 union.add(email2); 827 } 828 else if (withinDomain(email2, email1)) 829 { 830 union.add(email1); 831 } 832 else 833 { 834 union.add(email1); 835 union.add(email2); 836 } 837 } 838 else 839 { 840 if (withinDomain(email2, email1)) 841 { 842 union.add(email1); 843 } 844 else 845 { 846 union.add(email1); 847 union.add(email2); 848 } 849 } 850 } 851 // email specifies a host 852 else 853 { 854 if (email2.indexOf('@') != -1) 855 { 856 String _sub = email2.substring(email1.indexOf('@') + 1); 857 if (_sub.equalsIgnoreCase(email1)) 858 { 859 union.add(email1); 860 } 861 else 862 { 863 union.add(email1); 864 union.add(email2); 865 } 866 } 867 // email2 specifies a domain 868 else if (email2.startsWith(".")) 869 { 870 if (withinDomain(email1, email2)) 871 { 872 union.add(email2); 873 } 874 else 875 { 876 union.add(email1); 877 union.add(email2); 878 } 879 } 880 // email2 specifies a particular host 881 else 882 { 883 if (email1.equalsIgnoreCase(email2)) 884 { 885 union.add(email1); 886 } 887 else 888 { 889 union.add(email1); 890 union.add(email2); 891 } 892 } 893 } 894 } 895 896 private void unionURI(String email1, String email2, Set union) 897 { 898 // email1 is a particular address 899 if (email1.indexOf('@') != -1) 900 { 901 String _sub = email1.substring(email1.indexOf('@') + 1); 902 // both are a particular mailbox 903 if (email2.indexOf('@') != -1) 904 { 905 if (email1.equalsIgnoreCase(email2)) 906 { 907 union.add(email1); 908 } 909 else 910 { 911 union.add(email1); 912 union.add(email2); 913 } 914 } 915 // email2 specifies a domain 916 else if (email2.startsWith(".")) 917 { 918 if (withinDomain(_sub, email2)) 919 { 920 union.add(email2); 921 } 922 else 923 { 924 union.add(email1); 925 union.add(email2); 926 } 927 } 928 // email2 specifies a particular host 929 else 930 { 931 if (_sub.equalsIgnoreCase(email2)) 932 { 933 union.add(email2); 934 } 935 else 936 { 937 union.add(email1); 938 union.add(email2); 939 } 940 } 941 } 942 // email1 specifies a domain 943 else if (email1.startsWith(".")) 944 { 945 if (email2.indexOf('@') != -1) 946 { 947 String _sub = email2.substring(email1.indexOf('@') + 1); 948 if (withinDomain(_sub, email1)) 949 { 950 union.add(email1); 951 } 952 else 953 { 954 union.add(email1); 955 union.add(email2); 956 } 957 } 958 // email2 specifies a domain 959 else if (email2.startsWith(".")) 960 { 961 if (withinDomain(email1, email2) 962 || email1.equalsIgnoreCase(email2)) 963 { 964 union.add(email2); 965 } 966 else if (withinDomain(email2, email1)) 967 { 968 union.add(email1); 969 } 970 else 971 { 972 union.add(email1); 973 union.add(email2); 974 } 975 } 976 else 977 { 978 if (withinDomain(email2, email1)) 979 { 980 union.add(email1); 981 } 982 else 983 { 984 union.add(email1); 985 union.add(email2); 986 } 987 } 988 } 989 // email specifies a host 990 else 991 { 992 if (email2.indexOf('@') != -1) 993 { 994 String _sub = email2.substring(email1.indexOf('@') + 1); 995 if (_sub.equalsIgnoreCase(email1)) 996 { 997 union.add(email1); 998 } 999 else 1000 { 1001 union.add(email1); 1002 union.add(email2); 1003 } 1004 } 1005 // email2 specifies a domain 1006 else if (email2.startsWith(".")) 1007 { 1008 if (withinDomain(email1, email2)) 1009 { 1010 union.add(email2); 1011 } 1012 else 1013 { 1014 union.add(email1); 1015 union.add(email2); 1016 } 1017 } 1018 // email2 specifies a particular host 1019 else 1020 { 1021 if (email1.equalsIgnoreCase(email2)) 1022 { 1023 union.add(email1); 1024 } 1025 else 1026 { 1027 union.add(email1); 1028 union.add(email2); 1029 } 1030 } 1031 } 1032 } 1033 1034 private Set intersectDNS(Set permitted, Set dnss) 1035 { 1036 Set intersect = new HashSet(); 1037 for (Iterator it = dnss.iterator(); it.hasNext();) 1038 { 1039 String dns = extractNameAsString(((GeneralSubtree)it.next()) 1040 .getBase()); 1041 if (permitted == null) 1042 { 1043 if (dns != null) 1044 { 1045 intersect.add(dns); 1046 } 1047 } 1048 else 1049 { 1050 Iterator _iter = permitted.iterator(); 1051 while (_iter.hasNext()) 1052 { 1053 String _permitted = (String)_iter.next(); 1054 1055 if (withinDomain(_permitted, dns)) 1056 { 1057 intersect.add(_permitted); 1058 } 1059 else if (withinDomain(dns, _permitted)) 1060 { 1061 intersect.add(dns); 1062 } 1063 } 1064 } 1065 } 1066 1067 return intersect; 1068 } 1069 1070 protected Set unionDNS(Set excluded, String dns) 1071 { 1072 if (excluded.isEmpty()) 1073 { 1074 if (dns == null) 1075 { 1076 return excluded; 1077 } 1078 excluded.add(dns); 1079 1080 return excluded; 1081 } 1082 else 1083 { 1084 Set union = new HashSet(); 1085 1086 Iterator _iter = excluded.iterator(); 1087 while (_iter.hasNext()) 1088 { 1089 String _permitted = (String)_iter.next(); 1090 1091 if (withinDomain(_permitted, dns)) 1092 { 1093 union.add(dns); 1094 } 1095 else if (withinDomain(dns, _permitted)) 1096 { 1097 union.add(_permitted); 1098 } 1099 else 1100 { 1101 union.add(_permitted); 1102 union.add(dns); 1103 } 1104 } 1105 1106 return union; 1107 } 1108 } 1109 1110 /** 1111 * The most restricting part from <code>email1</code> and 1112 * <code>email2</code> is added to the intersection <code>intersect</code>. 1113 * 1114 * @param email1 Email address constraint 1. 1115 * @param email2 Email address constraint 2. 1116 * @param intersect The intersection. 1117 */ 1118 private void intersectEmail(String email1, String email2, Set intersect) 1119 { 1120 // email1 is a particular address 1121 if (email1.indexOf('@') != -1) 1122 { 1123 String _sub = email1.substring(email1.indexOf('@') + 1); 1124 // both are a particular mailbox 1125 if (email2.indexOf('@') != -1) 1126 { 1127 if (email1.equalsIgnoreCase(email2)) 1128 { 1129 intersect.add(email1); 1130 } 1131 } 1132 // email2 specifies a domain 1133 else if (email2.startsWith(".")) 1134 { 1135 if (withinDomain(_sub, email2)) 1136 { 1137 intersect.add(email1); 1138 } 1139 } 1140 // email2 specifies a particular host 1141 else 1142 { 1143 if (_sub.equalsIgnoreCase(email2)) 1144 { 1145 intersect.add(email1); 1146 } 1147 } 1148 } 1149 // email specifies a domain 1150 else if (email1.startsWith(".")) 1151 { 1152 if (email2.indexOf('@') != -1) 1153 { 1154 String _sub = email2.substring(email1.indexOf('@') + 1); 1155 if (withinDomain(_sub, email1)) 1156 { 1157 intersect.add(email2); 1158 } 1159 } 1160 // email2 specifies a domain 1161 else if (email2.startsWith(".")) 1162 { 1163 if (withinDomain(email1, email2) 1164 || email1.equalsIgnoreCase(email2)) 1165 { 1166 intersect.add(email1); 1167 } 1168 else if (withinDomain(email2, email1)) 1169 { 1170 intersect.add(email2); 1171 } 1172 } 1173 else 1174 { 1175 if (withinDomain(email2, email1)) 1176 { 1177 intersect.add(email2); 1178 } 1179 } 1180 } 1181 // email1 specifies a host 1182 else 1183 { 1184 if (email2.indexOf('@') != -1) 1185 { 1186 String _sub = email2.substring(email2.indexOf('@') + 1); 1187 if (_sub.equalsIgnoreCase(email1)) 1188 { 1189 intersect.add(email2); 1190 } 1191 } 1192 // email2 specifies a domain 1193 else if (email2.startsWith(".")) 1194 { 1195 if (withinDomain(email1, email2)) 1196 { 1197 intersect.add(email1); 1198 } 1199 } 1200 // email2 specifies a particular host 1201 else 1202 { 1203 if (email1.equalsIgnoreCase(email2)) 1204 { 1205 intersect.add(email1); 1206 } 1207 } 1208 } 1209 } 1210 1211 private void checkExcludedURI(Set excluded, String uri) 1212 throws PKIXNameConstraintValidatorException 1213 { 1214 if (excluded.isEmpty()) 1215 { 1216 return; 1217 } 1218 1219 Iterator it = excluded.iterator(); 1220 1221 while (it.hasNext()) 1222 { 1223 String str = ((String)it.next()); 1224 1225 if (isUriConstrained(uri, str)) 1226 { 1227 throw new PKIXNameConstraintValidatorException( 1228 "URI is from an excluded subtree."); 1229 } 1230 } 1231 } 1232 1233 private Set intersectURI(Set permitted, Set uris) 1234 { 1235 Set intersect = new HashSet(); 1236 for (Iterator it = uris.iterator(); it.hasNext();) 1237 { 1238 String uri = extractNameAsString(((GeneralSubtree)it.next()) 1239 .getBase()); 1240 if (permitted == null) 1241 { 1242 if (uri != null) 1243 { 1244 intersect.add(uri); 1245 } 1246 } 1247 else 1248 { 1249 Iterator _iter = permitted.iterator(); 1250 while (_iter.hasNext()) 1251 { 1252 String _permitted = (String)_iter.next(); 1253 intersectURI(_permitted, uri, intersect); 1254 } 1255 } 1256 } 1257 return intersect; 1258 } 1259 1260 private Set unionURI(Set excluded, String uri) 1261 { 1262 if (excluded.isEmpty()) 1263 { 1264 if (uri == null) 1265 { 1266 return excluded; 1267 } 1268 excluded.add(uri); 1269 1270 return excluded; 1271 } 1272 else 1273 { 1274 Set union = new HashSet(); 1275 1276 Iterator _iter = excluded.iterator(); 1277 while (_iter.hasNext()) 1278 { 1279 String _excluded = (String)_iter.next(); 1280 1281 unionURI(_excluded, uri, union); 1282 } 1283 1284 return union; 1285 } 1286 } 1287 1288 private void intersectURI(String email1, String email2, Set intersect) 1289 { 1290 // email1 is a particular address 1291 if (email1.indexOf('@') != -1) 1292 { 1293 String _sub = email1.substring(email1.indexOf('@') + 1); 1294 // both are a particular mailbox 1295 if (email2.indexOf('@') != -1) 1296 { 1297 if (email1.equalsIgnoreCase(email2)) 1298 { 1299 intersect.add(email1); 1300 } 1301 } 1302 // email2 specifies a domain 1303 else if (email2.startsWith(".")) 1304 { 1305 if (withinDomain(_sub, email2)) 1306 { 1307 intersect.add(email1); 1308 } 1309 } 1310 // email2 specifies a particular host 1311 else 1312 { 1313 if (_sub.equalsIgnoreCase(email2)) 1314 { 1315 intersect.add(email1); 1316 } 1317 } 1318 } 1319 // email specifies a domain 1320 else if (email1.startsWith(".")) 1321 { 1322 if (email2.indexOf('@') != -1) 1323 { 1324 String _sub = email2.substring(email1.indexOf('@') + 1); 1325 if (withinDomain(_sub, email1)) 1326 { 1327 intersect.add(email2); 1328 } 1329 } 1330 // email2 specifies a domain 1331 else if (email2.startsWith(".")) 1332 { 1333 if (withinDomain(email1, email2) 1334 || email1.equalsIgnoreCase(email2)) 1335 { 1336 intersect.add(email1); 1337 } 1338 else if (withinDomain(email2, email1)) 1339 { 1340 intersect.add(email2); 1341 } 1342 } 1343 else 1344 { 1345 if (withinDomain(email2, email1)) 1346 { 1347 intersect.add(email2); 1348 } 1349 } 1350 } 1351 // email1 specifies a host 1352 else 1353 { 1354 if (email2.indexOf('@') != -1) 1355 { 1356 String _sub = email2.substring(email2.indexOf('@') + 1); 1357 if (_sub.equalsIgnoreCase(email1)) 1358 { 1359 intersect.add(email2); 1360 } 1361 } 1362 // email2 specifies a domain 1363 else if (email2.startsWith(".")) 1364 { 1365 if (withinDomain(email1, email2)) 1366 { 1367 intersect.add(email1); 1368 } 1369 } 1370 // email2 specifies a particular host 1371 else 1372 { 1373 if (email1.equalsIgnoreCase(email2)) 1374 { 1375 intersect.add(email1); 1376 } 1377 } 1378 } 1379 } 1380 1381 private void checkPermittedURI(Set permitted, String uri) 1382 throws PKIXNameConstraintValidatorException 1383 { 1384 if (permitted == null) 1385 { 1386 return; 1387 } 1388 1389 Iterator it = permitted.iterator(); 1390 1391 while (it.hasNext()) 1392 { 1393 String str = ((String)it.next()); 1394 1395 if (isUriConstrained(uri, str)) 1396 { 1397 return; 1398 } 1399 } 1400 if (uri.length() == 0 && permitted.size() == 0) 1401 { 1402 return; 1403 } 1404 throw new PKIXNameConstraintValidatorException( 1405 "URI is not from a permitted subtree."); 1406 } 1407 1408 private boolean isUriConstrained(String uri, String constraint) 1409 { 1410 String host = extractHostFromURL(uri); 1411 // a host 1412 if (!constraint.startsWith(".")) 1413 { 1414 if (host.equalsIgnoreCase(constraint)) 1415 { 1416 return true; 1417 } 1418 } 1419 1420 // in sub domain or domain 1421 else if (withinDomain(host, constraint)) 1422 { 1423 return true; 1424 } 1425 1426 return false; 1427 } 1428 1429 private static String extractHostFromURL(String url) 1430 { 1431 // see RFC 1738 1432 // remove ':' after protocol, e.g. http: 1433 String sub = url.substring(url.indexOf(':') + 1); 1434 // extract host from Common Internet Scheme Syntax, e.g. http:// 1435 if (sub.indexOf("//") != -1) 1436 { 1437 sub = sub.substring(sub.indexOf("//") + 2); 1438 } 1439 // first remove port, e.g. http://test.com:21 1440 if (sub.lastIndexOf(':') != -1) 1441 { 1442 sub = sub.substring(0, sub.lastIndexOf(':')); 1443 } 1444 // remove user and password, e.g. http://john:password@test.com 1445 sub = sub.substring(sub.indexOf(':') + 1); 1446 sub = sub.substring(sub.indexOf('@') + 1); 1447 // remove local parts, e.g. http://test.com/bla 1448 if (sub.indexOf('/') != -1) 1449 { 1450 sub = sub.substring(0, sub.indexOf('/')); 1451 } 1452 return sub; 1453 } 1454 1455 /** 1456 * Checks if the given GeneralName is in the permitted set. 1457 * 1458 * @param name The GeneralName 1459 * @throws PKIXNameConstraintValidatorException 1460 * If the <code>name</code> 1461 */ 1462 public void checkPermitted(GeneralName name) 1463 throws PKIXNameConstraintValidatorException 1464 { 1465 switch (name.getTagNo()) 1466 { 1467 case 1: 1468 checkPermittedEmail(permittedSubtreesEmail, 1469 extractNameAsString(name)); 1470 break; 1471 case 2: 1472 checkPermittedDNS(permittedSubtreesDNS, DERIA5String.getInstance( 1473 name.getName()).getString()); 1474 break; 1475 case 4: 1476 checkPermittedDN(ASN1Sequence.getInstance(name.getName() 1477 .toASN1Primitive())); 1478 break; 1479 case 6: 1480 checkPermittedURI(permittedSubtreesURI, DERIA5String.getInstance( 1481 name.getName()).getString()); 1482 break; 1483 case 7: 1484 byte[] ip = ASN1OctetString.getInstance(name.getName()).getOctets(); 1485 1486 checkPermittedIP(permittedSubtreesIP, ip); 1487 } 1488 } 1489 1490 /** 1491 * Check if the given GeneralName is contained in the excluded set. 1492 * 1493 * @param name The GeneralName. 1494 * @throws PKIXNameConstraintValidatorException 1495 * If the <code>name</code> is 1496 * excluded. 1497 */ 1498 public void checkExcluded(GeneralName name) 1499 throws PKIXNameConstraintValidatorException 1500 { 1501 switch (name.getTagNo()) 1502 { 1503 case 1: 1504 checkExcludedEmail(excludedSubtreesEmail, extractNameAsString(name)); 1505 break; 1506 case 2: 1507 checkExcludedDNS(excludedSubtreesDNS, DERIA5String.getInstance( 1508 name.getName()).getString()); 1509 break; 1510 case 4: 1511 checkExcludedDN(ASN1Sequence.getInstance(name.getName() 1512 .toASN1Primitive())); 1513 break; 1514 case 6: 1515 checkExcludedURI(excludedSubtreesURI, DERIA5String.getInstance( 1516 name.getName()).getString()); 1517 break; 1518 case 7: 1519 byte[] ip = ASN1OctetString.getInstance(name.getName()).getOctets(); 1520 1521 checkExcludedIP(excludedSubtreesIP, ip); 1522 } 1523 } 1524 1525 public void intersectPermittedSubtree(GeneralSubtree permitted) 1526 { 1527 intersectPermittedSubtree(new GeneralSubtree[] { permitted }); 1528 } 1529 1530 /** 1531 * Updates the permitted set of these name constraints with the intersection 1532 * with the given subtree. 1533 * 1534 * @param permitted The permitted subtrees 1535 */ 1536 1537 public void intersectPermittedSubtree(GeneralSubtree[] permitted) 1538 { 1539 Map subtreesMap = new HashMap(); 1540 1541 // group in sets in a map ordered by tag no. 1542 for (int i = 0; i != permitted.length; i++) 1543 { 1544 GeneralSubtree subtree = permitted[i]; 1545 Integer tagNo = Integers.valueOf(subtree.getBase().getTagNo()); 1546 if (subtreesMap.get(tagNo) == null) 1547 { 1548 subtreesMap.put(tagNo, new HashSet()); 1549 } 1550 ((Set)subtreesMap.get(tagNo)).add(subtree); 1551 } 1552 1553 for (Iterator it = subtreesMap.entrySet().iterator(); it.hasNext();) 1554 { 1555 Map.Entry entry = (Map.Entry)it.next(); 1556 1557 // go through all subtree groups 1558 switch (((Integer)entry.getKey()).intValue()) 1559 { 1560 case 1: 1561 permittedSubtreesEmail = intersectEmail(permittedSubtreesEmail, 1562 (Set)entry.getValue()); 1563 break; 1564 case 2: 1565 permittedSubtreesDNS = intersectDNS(permittedSubtreesDNS, 1566 (Set)entry.getValue()); 1567 break; 1568 case 4: 1569 permittedSubtreesDN = intersectDN(permittedSubtreesDN, 1570 (Set)entry.getValue()); 1571 break; 1572 case 6: 1573 permittedSubtreesURI = intersectURI(permittedSubtreesURI, 1574 (Set)entry.getValue()); 1575 break; 1576 case 7: 1577 permittedSubtreesIP = intersectIP(permittedSubtreesIP, 1578 (Set)entry.getValue()); 1579 } 1580 } 1581 } 1582 1583 private String extractNameAsString(GeneralName name) 1584 { 1585 return DERIA5String.getInstance(name.getName()).getString(); 1586 } 1587 1588 public void intersectEmptyPermittedSubtree(int nameType) 1589 { 1590 switch (nameType) 1591 { 1592 case 1: 1593 permittedSubtreesEmail = new HashSet(); 1594 break; 1595 case 2: 1596 permittedSubtreesDNS = new HashSet(); 1597 break; 1598 case 4: 1599 permittedSubtreesDN = new HashSet(); 1600 break; 1601 case 6: 1602 permittedSubtreesURI = new HashSet(); 1603 break; 1604 case 7: 1605 permittedSubtreesIP = new HashSet(); 1606 } 1607 } 1608 1609 /** 1610 * Adds a subtree to the excluded set of these name constraints. 1611 * 1612 * @param subtree A subtree with an excluded GeneralName. 1613 */ 1614 public void addExcludedSubtree(GeneralSubtree subtree) 1615 { 1616 GeneralName base = subtree.getBase(); 1617 1618 switch (base.getTagNo()) 1619 { 1620 case 1: 1621 excludedSubtreesEmail = unionEmail(excludedSubtreesEmail, 1622 extractNameAsString(base)); 1623 break; 1624 case 2: 1625 excludedSubtreesDNS = unionDNS(excludedSubtreesDNS, 1626 extractNameAsString(base)); 1627 break; 1628 case 4: 1629 excludedSubtreesDN = unionDN(excludedSubtreesDN, 1630 (ASN1Sequence)base.getName().toASN1Primitive()); 1631 break; 1632 case 6: 1633 excludedSubtreesURI = unionURI(excludedSubtreesURI, 1634 extractNameAsString(base)); 1635 break; 1636 case 7: 1637 excludedSubtreesIP = unionIP(excludedSubtreesIP, ASN1OctetString 1638 .getInstance(base.getName()).getOctets()); 1639 break; 1640 } 1641 } 1642 1643 /** 1644 * Returns the maximum IP address. 1645 * 1646 * @param ip1 The first IP address. 1647 * @param ip2 The second IP address. 1648 * @return The maximum IP address. 1649 */ 1650 private static byte[] max(byte[] ip1, byte[] ip2) 1651 { 1652 for (int i = 0; i < ip1.length; i++) 1653 { 1654 if ((ip1[i] & 0xFFFF) > (ip2[i] & 0xFFFF)) 1655 { 1656 return ip1; 1657 } 1658 } 1659 return ip2; 1660 } 1661 1662 /** 1663 * Returns the minimum IP address. 1664 * 1665 * @param ip1 The first IP address. 1666 * @param ip2 The second IP address. 1667 * @return The minimum IP address. 1668 */ 1669 private static byte[] min(byte[] ip1, byte[] ip2) 1670 { 1671 for (int i = 0; i < ip1.length; i++) 1672 { 1673 if ((ip1[i] & 0xFFFF) < (ip2[i] & 0xFFFF)) 1674 { 1675 return ip1; 1676 } 1677 } 1678 return ip2; 1679 } 1680 1681 /** 1682 * Compares IP address <code>ip1</code> with <code>ip2</code>. If ip1 1683 * is equal to ip2 0 is returned. If ip1 is bigger 1 is returned, -1 1684 * otherwise. 1685 * 1686 * @param ip1 The first IP address. 1687 * @param ip2 The second IP address. 1688 * @return 0 if ip1 is equal to ip2, 1 if ip1 is bigger, -1 otherwise. 1689 */ 1690 private static int compareTo(byte[] ip1, byte[] ip2) 1691 { 1692 if (Arrays.areEqual(ip1, ip2)) 1693 { 1694 return 0; 1695 } 1696 if (Arrays.areEqual(max(ip1, ip2), ip1)) 1697 { 1698 return 1; 1699 } 1700 return -1; 1701 } 1702 1703 /** 1704 * Returns the logical OR of the IP addresses <code>ip1</code> and 1705 * <code>ip2</code>. 1706 * 1707 * @param ip1 The first IP address. 1708 * @param ip2 The second IP address. 1709 * @return The OR of <code>ip1</code> and <code>ip2</code>. 1710 */ 1711 private static byte[] or(byte[] ip1, byte[] ip2) 1712 { 1713 byte[] temp = new byte[ip1.length]; 1714 for (int i = 0; i < ip1.length; i++) 1715 { 1716 temp[i] = (byte)(ip1[i] | ip2[i]); 1717 } 1718 return temp; 1719 } 1720 1721 public int hashCode() 1722 { 1723 return hashCollection(excludedSubtreesDN) 1724 + hashCollection(excludedSubtreesDNS) 1725 + hashCollection(excludedSubtreesEmail) 1726 + hashCollection(excludedSubtreesIP) 1727 + hashCollection(excludedSubtreesURI) 1728 + hashCollection(permittedSubtreesDN) 1729 + hashCollection(permittedSubtreesDNS) 1730 + hashCollection(permittedSubtreesEmail) 1731 + hashCollection(permittedSubtreesIP) 1732 + hashCollection(permittedSubtreesURI); 1733 } 1734 1735 private int hashCollection(Collection coll) 1736 { 1737 if (coll == null) 1738 { 1739 return 0; 1740 } 1741 int hash = 0; 1742 Iterator it1 = coll.iterator(); 1743 while (it1.hasNext()) 1744 { 1745 Object o = it1.next(); 1746 if (o instanceof byte[]) 1747 { 1748 hash += Arrays.hashCode((byte[])o); 1749 } 1750 else 1751 { 1752 hash += o.hashCode(); 1753 } 1754 } 1755 return hash; 1756 } 1757 1758 public boolean equals(Object o) 1759 { 1760 if (!(o instanceof PKIXNameConstraintValidator)) 1761 { 1762 return false; 1763 } 1764 PKIXNameConstraintValidator constraintValidator = (PKIXNameConstraintValidator)o; 1765 return collectionsAreEqual(constraintValidator.excludedSubtreesDN, excludedSubtreesDN) 1766 && collectionsAreEqual(constraintValidator.excludedSubtreesDNS, excludedSubtreesDNS) 1767 && collectionsAreEqual(constraintValidator.excludedSubtreesEmail, excludedSubtreesEmail) 1768 && collectionsAreEqual(constraintValidator.excludedSubtreesIP, excludedSubtreesIP) 1769 && collectionsAreEqual(constraintValidator.excludedSubtreesURI, excludedSubtreesURI) 1770 && collectionsAreEqual(constraintValidator.permittedSubtreesDN, permittedSubtreesDN) 1771 && collectionsAreEqual(constraintValidator.permittedSubtreesDNS, permittedSubtreesDNS) 1772 && collectionsAreEqual(constraintValidator.permittedSubtreesEmail, permittedSubtreesEmail) 1773 && collectionsAreEqual(constraintValidator.permittedSubtreesIP, permittedSubtreesIP) 1774 && collectionsAreEqual(constraintValidator.permittedSubtreesURI, permittedSubtreesURI); 1775 } 1776 1777 private boolean collectionsAreEqual(Collection coll1, Collection coll2) 1778 { 1779 if (coll1 == coll2) 1780 { 1781 return true; 1782 } 1783 if (coll1 == null || coll2 == null) 1784 { 1785 return false; 1786 } 1787 if (coll1.size() != coll2.size()) 1788 { 1789 return false; 1790 } 1791 Iterator it1 = coll1.iterator(); 1792 1793 while (it1.hasNext()) 1794 { 1795 Object a = it1.next(); 1796 Iterator it2 = coll2.iterator(); 1797 boolean found = false; 1798 while (it2.hasNext()) 1799 { 1800 Object b = it2.next(); 1801 if (equals(a, b)) 1802 { 1803 found = true; 1804 break; 1805 } 1806 } 1807 if (!found) 1808 { 1809 return false; 1810 } 1811 } 1812 return true; 1813 } 1814 1815 private boolean equals(Object o1, Object o2) 1816 { 1817 if (o1 == o2) 1818 { 1819 return true; 1820 } 1821 if (o1 == null || o2 == null) 1822 { 1823 return false; 1824 } 1825 if (o1 instanceof byte[] && o2 instanceof byte[]) 1826 { 1827 return Arrays.areEqual((byte[])o1, (byte[])o2); 1828 } 1829 else 1830 { 1831 return o1.equals(o2); 1832 } 1833 } 1834 1835 /** 1836 * Stringifies an IPv4 or v6 address with subnet mask. 1837 * 1838 * @param ip The IP with subnet mask. 1839 * @return The stringified IP address. 1840 */ 1841 private String stringifyIP(byte[] ip) 1842 { 1843 String temp = ""; 1844 for (int i = 0; i < ip.length / 2; i++) 1845 { 1846 temp += Integer.toString(ip[i] & 0x00FF) + "."; 1847 } 1848 temp = temp.substring(0, temp.length() - 1); 1849 temp += "/"; 1850 for (int i = ip.length / 2; i < ip.length; i++) 1851 { 1852 temp += Integer.toString(ip[i] & 0x00FF) + "."; 1853 } 1854 temp = temp.substring(0, temp.length() - 1); 1855 return temp; 1856 } 1857 1858 private String stringifyIPCollection(Set ips) 1859 { 1860 String temp = ""; 1861 temp += "["; 1862 for (Iterator it = ips.iterator(); it.hasNext();) 1863 { 1864 temp += stringifyIP((byte[])it.next()) + ","; 1865 } 1866 if (temp.length() > 1) 1867 { 1868 temp = temp.substring(0, temp.length() - 1); 1869 } 1870 temp += "]"; 1871 return temp; 1872 } 1873 1874 public String toString() 1875 { 1876 String temp = ""; 1877 temp += "permitted:\n"; 1878 if (permittedSubtreesDN != null) 1879 { 1880 temp += "DN:\n"; 1881 temp += permittedSubtreesDN.toString() + "\n"; 1882 } 1883 if (permittedSubtreesDNS != null) 1884 { 1885 temp += "DNS:\n"; 1886 temp += permittedSubtreesDNS.toString() + "\n"; 1887 } 1888 if (permittedSubtreesEmail != null) 1889 { 1890 temp += "Email:\n"; 1891 temp += permittedSubtreesEmail.toString() + "\n"; 1892 } 1893 if (permittedSubtreesURI != null) 1894 { 1895 temp += "URI:\n"; 1896 temp += permittedSubtreesURI.toString() + "\n"; 1897 } 1898 if (permittedSubtreesIP != null) 1899 { 1900 temp += "IP:\n"; 1901 temp += stringifyIPCollection(permittedSubtreesIP) + "\n"; 1902 } 1903 temp += "excluded:\n"; 1904 if (!excludedSubtreesDN.isEmpty()) 1905 { 1906 temp += "DN:\n"; 1907 temp += excludedSubtreesDN.toString() + "\n"; 1908 } 1909 if (!excludedSubtreesDNS.isEmpty()) 1910 { 1911 temp += "DNS:\n"; 1912 temp += excludedSubtreesDNS.toString() + "\n"; 1913 } 1914 if (!excludedSubtreesEmail.isEmpty()) 1915 { 1916 temp += "Email:\n"; 1917 temp += excludedSubtreesEmail.toString() + "\n"; 1918 } 1919 if (!excludedSubtreesURI.isEmpty()) 1920 { 1921 temp += "URI:\n"; 1922 temp += excludedSubtreesURI.toString() + "\n"; 1923 } 1924 if (!excludedSubtreesIP.isEmpty()) 1925 { 1926 temp += "IP:\n"; 1927 temp += stringifyIPCollection(excludedSubtreesIP) + "\n"; 1928 } 1929 return temp; 1930 } 1931} 1932