001 /* X509CertSelector.java -- selects X.509 certificates by criteria. 002 Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 039 package java.security.cert; 040 041 import gnu.classpath.SystemProperties; 042 import gnu.java.security.OID; 043 import gnu.java.security.x509.GnuPKIExtension; 044 import gnu.java.security.x509.ext.CertificatePolicies; 045 import gnu.java.security.x509.ext.Extension; 046 import gnu.java.security.x509.ext.GeneralName; 047 import gnu.java.security.x509.ext.GeneralSubtree; 048 import gnu.java.security.x509.ext.NameConstraints; 049 import gnu.java.security.x509.ext.GeneralName.Kind; 050 051 import java.io.IOException; 052 import java.math.BigInteger; 053 import java.net.InetAddress; 054 import java.security.KeyFactory; 055 import java.security.PublicKey; 056 import java.security.spec.X509EncodedKeySpec; 057 import java.util.ArrayList; 058 import java.util.Arrays; 059 import java.util.Collection; 060 import java.util.Collections; 061 import java.util.Date; 062 import java.util.HashSet; 063 import java.util.Iterator; 064 import java.util.LinkedList; 065 import java.util.List; 066 import java.util.Set; 067 068 import javax.security.auth.x500.X500Principal; 069 070 /** 071 * A concrete implementation of {@link CertSelector} for X.509 certificates, 072 * which allows a number of criteria to be set when accepting certificates, 073 * from validity dates, to issuer and subject distinguished names, to some 074 * of the various X.509 extensions. 075 * 076 * <p>Use of this class requires extensive knowledge of the Internet 077 * Engineering Task Force's Public Key Infrastructure (X.509). The primary 078 * document describing this standard is <a 079 * href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: Internet X.509 080 * Public Key Infrastructure Certificate and Certificate Revocation List 081 * (CRL) Profile</a>. 082 * 083 * <p>Note that this class is not thread-safe. If multiple threads will 084 * use or modify this class then they need to synchronize on the object. 085 * 086 * @author Casey Marshall (csm@gnu.org) 087 * @since 1.4 088 */ 089 public class X509CertSelector implements CertSelector, Cloneable 090 { 091 092 // Constants and fields. 093 // ------------------------------------------------------------------------- 094 095 private static final String AUTH_KEY_ID = "2.5.29.35"; 096 private static final String SUBJECT_KEY_ID = "2.5.29.14"; 097 private static final String NAME_CONSTRAINTS_ID = "2.5.29.30"; 098 099 private static boolean checkOid(int[] oid) 100 { 101 return (oid != null && oid.length > 2 && 102 (oid[0] >= 0 && oid[0] <= 2) && (oid[1] >= 0 && oid[1] <= 39)); 103 } 104 105 private static GeneralName makeName(int id, String name) throws IOException 106 { 107 byte[] nameBytes = null; 108 GeneralName.Kind kind = GeneralName.Kind.forTag(id); 109 switch (Kind.forTag(id)) 110 { 111 case dNSName: 112 case rfc822Name: 113 case uniformResourceIdentifier: 114 nameBytes = name.getBytes("ASCII"); 115 break; 116 117 case iPAddress: 118 InetAddress addr = InetAddress.getByName(name); 119 nameBytes = addr.getAddress(); 120 break; 121 122 case registeredId: 123 OID oid = new OID(name); 124 nameBytes = oid.getDER(); 125 break; 126 127 case directoryName: 128 X500Principal xname = new X500Principal(name); 129 nameBytes = xname.getEncoded(); 130 break; 131 132 case ediPartyName: 133 case x400Address: 134 case otherName: 135 throw new IOException("cannot decode string representation of " 136 + kind); 137 } 138 return new GeneralName(kind, nameBytes); 139 } 140 141 private int basicConstraints; 142 private X509Certificate cert; 143 private BigInteger serialNo; 144 private X500Principal issuer; 145 private X500Principal subject; 146 private byte[] subjectKeyId; 147 private byte[] authKeyId; 148 private boolean[] keyUsage; 149 private Date certValid; 150 private OID sigId; 151 private PublicKey subjectKey; 152 private X509EncodedKeySpec subjectKeySpec; 153 private Set<String> keyPurposeSet; 154 private List<GeneralName> altNames; 155 private boolean matchAllNames; 156 private byte[] nameConstraints; 157 private Set<OID> policy; 158 private List<GeneralName> pathToNames; 159 160 /** 161 * Creates a new X.509 certificate selector. The new selector will be 162 * empty, and will accept any certificate (provided that it is an 163 * {@link X509Certificate}). 164 */ 165 public X509CertSelector() 166 { 167 basicConstraints = -1; 168 } 169 170 /** 171 * Add a name to match in the NameConstraints extension. The argument is 172 * the DER-encoded bytes of a GeneralName structure. 173 * 174 * See the method {@link #addSubjectAlternativeName(int, byte[])} for the 175 * format of the GeneralName structure. 176 * 177 * @param id The name identifier. Must be between 0 and 8. 178 * @param name The DER-encoded bytes of the name to match. 179 * @throws IOException If the name DER is malformed. 180 */ 181 public void addPathToName(int id, byte[] name) throws IOException 182 { 183 GeneralName generalName = new GeneralName(GeneralName.Kind.forTag(id), name); 184 if (pathToNames == null) 185 pathToNames = new LinkedList<GeneralName>(); 186 pathToNames.add(generalName); 187 } 188 189 /** 190 * Add a name to match in the NameConstraints extension. This method will 191 * only recognize certain types of name that have convenient string 192 * encodings. For robustness, you should use the {@link 193 * #addPathToName(int, byte[])} method whenever possible. 194 * 195 * @param id The name identifier. Must be between 0 and 8. 196 * @param name The name. 197 * @throws IOException If the name cannot be decoded. 198 */ 199 public void addPathToName(int id, String name) throws IOException 200 { 201 GeneralName generalName = makeName(id, name); 202 if (pathToNames == null) 203 pathToNames = new LinkedList<GeneralName>(); 204 pathToNames.add(generalName); 205 } 206 207 /** 208 * Add a name, as DER-encoded bytes, to the subject alternative names 209 * criterion. 210 * 211 * The name is a GeneralName structure, which has the ASN.1 format: 212 * 213 * <pre> 214 GeneralName ::= CHOICE { 215 otherName [0] OtherName, 216 rfc822Name [1] IA5String, 217 dNSName [2] IA5String, 218 x400Address [3] ORAddress, 219 directoryName [4] Name, 220 ediPartyName [5] EDIPartyName, 221 uniformResourceIdentifier [6] IA5String, 222 iPAddress [7] OCTET STRING, 223 registeredID [8] OBJECT IDENTIFIER } 224 </pre> 225 * 226 * @param id The type of name this is. 227 * @param name The DER-encoded name. 228 * @throws IOException If the name is not a valid DER sequence. 229 */ 230 public void addSubjectAlternativeName(int id, byte[] name) 231 throws IOException 232 { 233 GeneralName generalName = new GeneralName(GeneralName.Kind.forTag(id), name); 234 if (altNames == null) 235 altNames = new LinkedList<GeneralName>(); 236 altNames.add(generalName); 237 } 238 239 /** 240 * Add a name to the subject alternative names criterion. This method will 241 * only recognize certain types of name that have convenient string 242 * encodings. For robustness, you should use the {@link 243 * #addSubjectAlternativeName(int, byte[])} method whenever possible. 244 * 245 * This method can only decode certain name kinds of names as strings. 246 * 247 * @param id The type of name this is. Must be in the range [0,8]. 248 * @param name The name. 249 * @throws IOException If the id is out of range, or if the name 250 * is null. 251 */ 252 public void addSubjectAlternativeName(int id, String name) 253 throws IOException 254 { 255 GeneralName generalName = makeName(id, name); 256 if (altNames == null) 257 altNames = new LinkedList<GeneralName>(); 258 altNames.add(generalName); 259 } 260 261 public Object clone() 262 { 263 try 264 { 265 return super.clone(); 266 } 267 catch (CloneNotSupportedException shouldNotHappen) 268 { 269 throw new Error(shouldNotHappen); 270 } 271 } 272 273 /** 274 * Returns the authority key identifier criterion, or <code>null</code> if 275 * this value was not set. Note that the byte array is cloned to prevent 276 * modification. 277 * 278 * @return The authority key identifier. 279 */ 280 public byte[] getAuthorityKeyIdentifier() 281 { 282 if (authKeyId != null) 283 return (byte[]) authKeyId.clone(); 284 else 285 return null; 286 } 287 288 /** 289 * Returns the basic constraints criterion, or -1 if this value is not set. 290 * 291 * @return The basic constraints. 292 */ 293 public int getBasicConstraints() 294 { 295 return basicConstraints; 296 } 297 298 /** 299 * Returns the certificate criterion, or <code>null</code> if this value 300 * was not set. 301 * 302 * @return The certificate. 303 */ 304 public X509Certificate getCertificate() 305 { 306 return cert; 307 } 308 309 /** 310 * Returns the date at which certificates must be valid, or <code>null</code> 311 * if this criterion was not set. 312 * 313 * @return The target certificate valitity date. 314 */ 315 public Date getCertificateValid() 316 { 317 if (certValid != null) 318 return (Date) certValid.clone(); 319 else 320 return null; 321 } 322 323 /** 324 * Returns the set of extended key purpose IDs, as an unmodifiable set 325 * of OID strings. Returns <code>null</code> if this criterion is not 326 * set. 327 * 328 * @return The set of key purpose OIDs (strings). 329 */ 330 public Set<String> getExtendedKeyUsage() 331 { 332 if (keyPurposeSet != null) 333 return Collections.unmodifiableSet(keyPurposeSet); 334 else 335 return null; 336 } 337 338 /** 339 * Returns the issuer criterion as a sequence of DER bytes, or 340 * <code>null</code> if this value was not set. 341 * 342 * @return The issuer. 343 */ 344 public byte[] getIssuerAsBytes() throws IOException 345 { 346 if (issuer != null) 347 return issuer.getEncoded(); 348 else 349 return null; 350 } 351 352 /** 353 * Returns the issuer criterion as a string, or <code>null</code> if this 354 * value was not set. 355 * 356 * @return The issuer. 357 */ 358 public String getIssuerAsString() 359 { 360 if (issuer != null) 361 return issuer.getName(); 362 else 363 return null; 364 } 365 366 /** 367 * Returns the public key usage criterion, or <code>null</code> if this 368 * value is not set. Note that the array is cloned to prevent modification. 369 * 370 * @return The public key usage. 371 */ 372 public boolean[] getKeyUsage() 373 { 374 if (keyUsage != null) 375 return (boolean[]) keyUsage.clone(); 376 else 377 return null; 378 } 379 380 /** 381 * Returns whether or not all specified alternative names must match. 382 * If false, a certificate is considered a match if <em>one</em> of the 383 * specified alternative names matches. 384 * 385 * @return true if all names must match. 386 */ 387 public boolean getMatchAllSubjectAltNames() 388 { 389 return matchAllNames; 390 } 391 392 /** 393 * Returns the name constraints criterion, or <code>null</code> if this 394 * value is not set. Note that the byte array is cloned to prevent 395 * modification. 396 * 397 * @return The name constraints. 398 */ 399 public byte[] getNameConstraints() 400 { 401 if (nameConstraints != null) 402 return (byte[]) nameConstraints.clone(); 403 else 404 return null; 405 } 406 407 public Collection<List<?>> getPathToNames() 408 { 409 if (pathToNames != null) 410 { 411 List<List<?>> names = new ArrayList<List<?>>(pathToNames.size()); 412 for (GeneralName name : pathToNames) 413 { 414 List<Object> n = new ArrayList<Object>(2); 415 n.add(name.kind().tag()); 416 n.add(name.name()); 417 names.add(n); 418 } 419 420 return names; 421 } 422 return null; 423 } 424 425 /** 426 * Returns the certificate policy extension that will be matched by this 427 * selector, or null if the certificate policy will not be matched. 428 * 429 * @return The policy to be matched, or null. 430 */ 431 public Set<String> getPolicy() 432 { 433 Set<OID> p = this.policy; 434 if (p != null) 435 { 436 Set<String> strings = new HashSet<String>(p.size()); 437 for (OID o : p) 438 { 439 strings.add(o.toString()); 440 } 441 return strings; 442 } 443 return null; 444 } 445 446 /** 447 * This method, and its related X.509 certificate extension — the 448 * private key usage period — is not supported under the Internet 449 * PKI for X.509 certificates (PKIX), described in RFC 3280. As such, this 450 * method is not supported either. 451 * 452 * <p>Do not use this method. It is not deprecated, as it is not deprecated 453 * in the Java standard, but it is basically a no-operation and simply 454 * returns <code>null</code>. 455 * 456 * @return Null. 457 */ 458 public Date getPrivateKeyValid() 459 { 460 return null; 461 } 462 463 /** 464 * Returns the serial number criterion, or <code>null</code> if this 465 * value was not set. 466 * 467 * @return The serial number. 468 */ 469 public BigInteger getSerialNumber() 470 { 471 return serialNo; 472 } 473 474 /** 475 * Get the subject alternative names criterion. The collection returned 476 * is a collection of pairs: the first element is an {@link Integer} 477 * containing the name type, and the second is a byte array containing 478 * the DER-encoded name bytes. 479 * 480 * @return The subject alternative names criterion. Returns null if this 481 * criterion is not set. 482 */ 483 public Collection<List<?>> getSubjectAlternativeNames() 484 { 485 if (altNames != null) 486 { 487 List<List<?>> names = new ArrayList<List<?>>(altNames.size()); 488 for (GeneralName name : altNames) 489 { 490 List<Object> n = new ArrayList<Object>(2); 491 n.add(name.kind().tag()); 492 n.add(name.name()); 493 names.add(n); 494 } 495 return names; 496 } 497 return null; 498 } 499 500 /** 501 * Returns the subject criterion as a sequence of DER bytes, or 502 * <code>null</code> if this value is not set. 503 * 504 * @return The subject. 505 */ 506 public byte[] getSubjectAsBytes() throws IOException 507 { 508 if (subject != null) 509 return subject.getEncoded(); 510 else 511 return null; 512 } 513 514 /** 515 * Returns the subject criterion as a string, of <code>null</code> if 516 * this value was not set. 517 * 518 * @return The subject. 519 */ 520 public String getSubjectAsString() 521 { 522 if (subject != null) 523 return subject.getName(); 524 else 525 return null; 526 } 527 528 /** 529 * Returns the subject key identifier criterion, or <code>null</code> if 530 * this value was not set. Note that the byte array is cloned to prevent 531 * modification. 532 * 533 * @return The subject key identifier. 534 */ 535 public byte[] getSubjectKeyIdentifier() 536 { 537 if (subjectKeyId != null) 538 return (byte[]) subjectKeyId.clone(); 539 else 540 return null; 541 } 542 543 /** 544 * Returns the subject public key criterion, or <code>null</code> if this 545 * value is not set. 546 * 547 * @return The subject public key. 548 */ 549 public PublicKey getSubjectPublicKey() 550 { 551 return subjectKey; 552 } 553 554 /** 555 * Returns the public key algorithm ID that matching certificates must have, 556 * or <code>null</code> if this criterion was not set. 557 * 558 * @return The public key algorithm ID. 559 */ 560 public String getSubjectPublicKeyAlgID() 561 { 562 return String.valueOf(sigId); 563 } 564 565 /** 566 * Match a certificate. This method will check the given certificate 567 * against all the enabled criteria of this selector, and will return 568 * <code>true</code> if the given certificate matches. 569 * 570 * @param certificate The certificate to check. 571 * @return true if the certificate matches all criteria. 572 */ 573 public boolean match(Certificate certificate) 574 { 575 if (!(certificate instanceof X509Certificate)) 576 return false; 577 X509Certificate cert = (X509Certificate) certificate; 578 if (this.cert != null) 579 { 580 try 581 { 582 byte[] e1 = this.cert.getEncoded(); 583 byte[] e2 = cert.getEncoded(); 584 if (!Arrays.equals(e1, e2)) 585 return false; 586 } 587 catch (CertificateEncodingException cee) 588 { 589 return false; 590 } 591 } 592 if (serialNo != null) 593 { 594 if (!serialNo.equals(cert.getSerialNumber())) 595 return false; 596 } 597 if (certValid != null) 598 { 599 try 600 { 601 cert.checkValidity(certValid); 602 } 603 catch (CertificateException ce) 604 { 605 return false; 606 } 607 } 608 if (issuer != null) 609 { 610 if (!issuer.equals(cert.getIssuerX500Principal())) 611 return false; 612 } 613 if (subject != null) 614 { 615 if (!subject.equals(cert.getSubjectX500Principal())) 616 return false; 617 } 618 if (sigId != null) 619 { 620 if (!sigId.toString().equals(cert.getSigAlgOID())) 621 return false; 622 } 623 if (subjectKeyId != null) 624 { 625 byte[] b = cert.getExtensionValue(SUBJECT_KEY_ID); 626 if (!Arrays.equals(b, subjectKeyId)) 627 return false; 628 } 629 if (authKeyId != null) 630 { 631 byte[] b = cert.getExtensionValue(AUTH_KEY_ID); 632 if (!Arrays.equals(b, authKeyId)) 633 return false; 634 } 635 if (keyUsage != null) 636 { 637 boolean[] b = cert.getKeyUsage(); 638 if (!Arrays.equals(b, keyUsage)) 639 return false; 640 } 641 if (basicConstraints >= 0) 642 { 643 if (cert.getBasicConstraints() != basicConstraints) 644 return false; 645 } 646 if (keyPurposeSet != null) 647 { 648 List kp = null; 649 try 650 { 651 kp = cert.getExtendedKeyUsage(); 652 } 653 catch (CertificateParsingException cpe) 654 { 655 return false; 656 } 657 if (kp == null) 658 return false; 659 for (Iterator it = keyPurposeSet.iterator(); it.hasNext(); ) 660 { 661 if (!kp.contains(it.next())) 662 return false; 663 } 664 } 665 if (altNames != null) 666 { 667 Collection<List<?>> an = null; 668 try 669 { 670 an = cert.getSubjectAlternativeNames(); 671 } 672 catch (CertificateParsingException cpe) 673 { 674 return false; 675 } 676 if (an == null) 677 return false; 678 int match = 0; 679 for (GeneralName name : altNames) 680 { 681 for (List<?> list : an) 682 { 683 try 684 { 685 Integer id = (Integer) list.get(0); 686 Object val = list.get(1); 687 GeneralName n = null; 688 if (val instanceof String) 689 n = makeName(id, (String) val); 690 else if (val instanceof byte[]) 691 { 692 n = new GeneralName(GeneralName.Kind.forTag(id), 693 (byte[]) val); 694 } 695 else 696 continue; 697 if (name.equals(n)) 698 match++; 699 } 700 catch (Exception e) 701 { 702 continue; 703 } 704 } 705 if (match == 0 || (matchAllNames && match < altNames.size())) 706 return false; 707 } 708 } 709 if (nameConstraints != null) 710 { 711 byte[] nc = cert.getExtensionValue(NAME_CONSTRAINTS_ID); 712 if (!Arrays.equals(nameConstraints, nc)) 713 return false; 714 } 715 716 if (policy != null) 717 { 718 CertificatePolicies policies = null; 719 if (cert instanceof GnuPKIExtension) 720 { 721 policies = (CertificatePolicies) 722 ((GnuPKIExtension) cert).getExtension(CertificatePolicies.ID).getValue(); 723 } 724 else 725 { 726 byte[] policiesDer = 727 cert.getExtensionValue(CertificatePolicies.ID.toString()); 728 try 729 { 730 policies = new CertificatePolicies(policiesDer); 731 } 732 catch (IOException ioe) 733 { 734 // ignored 735 } 736 } 737 738 if (policies == null) 739 return false; 740 if (!policies.getPolicies().containsAll(policy)) 741 return false; 742 } 743 744 if (pathToNames != null) 745 { 746 NameConstraints nc = null; 747 if (cert instanceof GnuPKIExtension) 748 { 749 Extension e = 750 ((GnuPKIExtension) cert).getExtension(NameConstraints.ID); 751 if (e != null) 752 nc = (NameConstraints) e.getValue(); 753 } 754 else 755 { 756 byte[] b = cert.getExtensionValue(NameConstraints.ID.toString()); 757 if (b != null) 758 { 759 try 760 { 761 nc = new NameConstraints(b); 762 } 763 catch (IOException ioe) 764 { 765 } 766 } 767 } 768 769 if (nc == null) 770 return false; 771 772 int match = 0; 773 for (GeneralName name : pathToNames) 774 { 775 for (GeneralSubtree subtree : nc.permittedSubtrees()) 776 { 777 if (name.equals(subtree.base())) 778 match++; 779 } 780 } 781 if (match == 0 || (matchAllNames && match < pathToNames.size())) 782 return false; 783 } 784 785 return true; 786 } 787 788 /** 789 * Sets the authority key identifier criterion, or <code>null</code> to clear 790 * this criterion. Note that the byte array is cloned to prevent modification. 791 * 792 * @param authKeyId The authority key identifier. 793 */ 794 public void setAuthorityKeyIdentifier(byte[] authKeyId) 795 { 796 this.authKeyId = authKeyId != null ? (byte[]) authKeyId.clone() : null; 797 } 798 799 /** 800 * Sets the basic constraints criterion. Specify -1 to clear this parameter. 801 * 802 * @param basicConstraints The new basic constraints value. 803 */ 804 public void setBasicConstraints(int basicConstraints) 805 { 806 if (basicConstraints < -1) 807 basicConstraints = -1; 808 this.basicConstraints = basicConstraints; 809 } 810 811 /** 812 * Sets the certificate criterion. If set, only certificates that are 813 * equal to the certificate passed here will be accepted. 814 * 815 * @param cert The certificate. 816 */ 817 public void setCertificate(X509Certificate cert) 818 { 819 this.cert = cert; 820 } 821 822 /** 823 * Sets the date at which certificates must be valid. Specify 824 * <code>null</code> to clear this criterion. 825 * 826 * @param certValid The certificate validity date. 827 */ 828 public void setCertificateValid(Date certValid) 829 { 830 this.certValid = certValid != null ? (Date) certValid.clone() : null; 831 } 832 833 /** 834 * Sets the extended key usage criterion, as a set of OID strings. Specify 835 * <code>null</code> to clear this value. 836 * 837 * @param keyPurposeSet The set of key purpose OIDs. 838 * @throws IOException If any element of the set is not a valid OID string. 839 */ 840 public void setExtendedKeyUsage(Set<String> keyPurposeSet) throws IOException 841 { 842 if (keyPurposeSet == null) 843 { 844 this.keyPurposeSet = null; 845 return; 846 } 847 Set<String> s = new HashSet<String>(); 848 for (Iterator it = keyPurposeSet.iterator(); it.hasNext(); ) 849 { 850 Object o = it.next(); 851 if (!(o instanceof String)) 852 throw new IOException("not a string: " + o); 853 try 854 { 855 OID oid = new OID((String) o); 856 int[] comp = oid.getIDs(); 857 if (!checkOid(comp)) 858 throw new IOException("malformed OID: " + o); 859 } 860 catch (IllegalArgumentException iae) 861 { 862 IOException ioe = new IOException("malformed OID: " + o); 863 ioe.initCause(iae); 864 throw ioe; 865 } 866 } 867 this.keyPurposeSet = s; 868 } 869 870 /** 871 * Sets the issuer, specified as the DER encoding of the issuer's 872 * distinguished name. Only certificates issued by this issuer will 873 * be accepted. 874 * 875 * @param name The DER encoding of the issuer's distinguished name. 876 * @throws IOException If the given name is incorrectly formatted. 877 */ 878 public void setIssuer(byte[] name) throws IOException 879 { 880 if (name != null) 881 { 882 try 883 { 884 issuer = new X500Principal(name); 885 } 886 catch (IllegalArgumentException iae) 887 { 888 throw new IOException(iae.getMessage()); 889 } 890 } 891 else 892 issuer = null; 893 } 894 895 /** 896 * Sets the issuer, specified as a string representation of the issuer's 897 * distinguished name. Only certificates issued by this issuer will 898 * be accepted. 899 * 900 * @param name The string representation of the issuer's distinguished name. 901 * @throws IOException If the given name is incorrectly formatted. 902 */ 903 public void setIssuer(String name) throws IOException 904 { 905 if (name != null) 906 { 907 try 908 { 909 issuer = new X500Principal(name); 910 } 911 catch (IllegalArgumentException iae) 912 { 913 throw new IOException(iae.getMessage()); 914 } 915 } 916 else 917 issuer = null; 918 } 919 920 /** 921 * Sets the public key usage criterion. Specify <code>null</code> to clear 922 * this value. 923 * 924 * @param keyUsage The public key usage. 925 */ 926 public void setKeyUsage(boolean[] keyUsage) 927 { 928 this.keyUsage = keyUsage != null ? (boolean[]) keyUsage.clone() : null; 929 } 930 931 /** 932 * Sets whether or not all subject alternative names must be matched. 933 * If false, then a certificate will be considered a match if one 934 * alternative name matches. 935 * 936 * @param matchAllNames Whether or not all alternative names must be 937 * matched. 938 */ 939 public void setMatchAllSubjectAltNames(boolean matchAllNames) 940 { 941 this.matchAllNames = matchAllNames; 942 } 943 944 /** 945 * Sets the name constraints criterion; specify <code>null</code> to 946 * clear this criterion. Note that if non-null, the argument will be 947 * cloned to prevent modification. 948 * 949 * @param nameConstraints The new name constraints. 950 * @throws IOException If the argument is not a valid DER-encoded 951 * name constraints. 952 */ 953 public void setNameConstraints(byte[] nameConstraints) 954 throws IOException 955 { 956 // Check if the input is well-formed... 957 new NameConstraints(nameConstraints); 958 959 // But we just compare raw byte arrays. 960 this.nameConstraints = nameConstraints != null 961 ? (byte[]) nameConstraints.clone() : null; 962 } 963 964 /** 965 * Sets the pathToNames criterion. The argument is a collection of 966 * pairs, the first element of which is an {@link Integer} giving 967 * the ID of the name, and the second element is either a {@link String} 968 * or a byte array. 969 * 970 * See {@link #addPathToName(int, byte[])} and {@link #addPathToName(int, String)} 971 * for how these arguments are handled. 972 * 973 * @param names The names. 974 * @throws IOException If any argument is malformed. 975 */ 976 public void setPathToNames(Collection<List<?>> names) throws IOException 977 { 978 if (names == null || names.size() == 0) 979 { 980 pathToNames = null; 981 } 982 else 983 { 984 pathToNames = new ArrayList<GeneralName>(names.size()); 985 for (List<?> name : names) 986 { 987 Integer id = (Integer) name.get(0); 988 Object name2 = name.get(1); 989 if (name2 instanceof String) 990 addPathToName(id, (String) name2); 991 else if (name2 instanceof byte[]) 992 addPathToName(id, (byte[]) name2); 993 else 994 throw new IOException("invalid name type: " 995 + name2.getClass().getName()); 996 } 997 } 998 } 999 1000 /** 1001 * Sets the certificate policy to match, or null if this criterion should 1002 * not be checked. Each element if the set must be a dotted-decimal form 1003 * of certificate policy object identifier. 1004 * 1005 * @param policy The policy to match. 1006 * @throws IOException If some element of the policy is not a valid 1007 * policy extenison OID. 1008 */ 1009 public void setPolicy(Set<String> policy) throws IOException 1010 { 1011 if (policy != null) 1012 { 1013 HashSet<OID> p = new HashSet<OID>(policy.size()); 1014 for (String s : policy) 1015 { 1016 try 1017 { 1018 OID oid = new OID(s); 1019 int[] i = oid.getIDs(); 1020 if (!checkOid(i)) 1021 throw new IOException("invalid OID"); 1022 p.add(oid); 1023 } 1024 catch (IOException ioe) 1025 { 1026 throw ioe; 1027 } 1028 catch (Exception x) 1029 { 1030 IOException ioe = new IOException("invalid OID"); 1031 ioe.initCause(x); 1032 throw ioe; 1033 } 1034 } 1035 this.policy = p; 1036 } 1037 else 1038 this.policy = null; 1039 } 1040 1041 /** 1042 * This method, and its related X.509 certificate extension — the 1043 * private key usage period — is not supported under the Internet 1044 * PKI for X.509 certificates (PKIX), described in RFC 3280. As such, this 1045 * method is not supported either. 1046 * 1047 * <p>Do not use this method. It is not deprecated, as it is not deprecated 1048 * in the Java standard, but it is basically a no-operation. 1049 * 1050 * @param UNUSED Is silently ignored. 1051 */ 1052 public void setPrivateKeyValid(Date UNUSED) 1053 { 1054 } 1055 1056 /** 1057 * Sets the serial number of the desired certificate. Only certificates that 1058 * contain this serial number are accepted. 1059 * 1060 * @param serialNo The serial number. 1061 */ 1062 public void setSerialNumber(BigInteger serialNo) 1063 { 1064 this.serialNo = serialNo; 1065 } 1066 1067 /** 1068 * Sets the subject, specified as the DER encoding of the subject's 1069 * distinguished name. Only certificates with the given subject will 1070 * be accepted. 1071 * 1072 * @param name The DER encoding of the subject's distinguished name. 1073 * @throws IOException If the given name is incorrectly formatted. 1074 */ 1075 public void setSubject(byte[] name) throws IOException 1076 { 1077 if (name != null) 1078 { 1079 try 1080 { 1081 subject = new X500Principal(name); 1082 } 1083 catch (IllegalArgumentException iae) 1084 { 1085 throw new IOException(iae.getMessage()); 1086 } 1087 } 1088 else 1089 subject = null; 1090 } 1091 1092 /** 1093 * Sets the subject, specified as a string representation of the 1094 * subject's distinguished name. Only certificates with the given 1095 * subject will be accepted. 1096 * 1097 * @param name The string representation of the subject's distinguished name. 1098 * @throws IOException If the given name is incorrectly formatted. 1099 */ 1100 public void setSubject(String name) throws IOException 1101 { 1102 if (name != null) 1103 { 1104 try 1105 { 1106 subject = new X500Principal(name); 1107 } 1108 catch (IllegalArgumentException iae) 1109 { 1110 throw new IOException(iae.getMessage()); 1111 } 1112 } 1113 else 1114 subject = null; 1115 } 1116 1117 /** 1118 * Sets the subject alternative names critertion. Each element of the 1119 * argument must be a {@link java.util.List} that contains exactly two 1120 * elements: the first an {@link Integer}, representing the type of 1121 * name, and the second either a {@link String} or a byte array, 1122 * representing the name itself. 1123 * 1124 * @param altNames The alternative names. 1125 * @throws IOException If any element of the argument is invalid. 1126 */ 1127 public void setSubjectAlternativeNames(Collection<List<?>> altNames) 1128 throws IOException 1129 { 1130 if (altNames == null || altNames.isEmpty()) 1131 { 1132 this.altNames = null; 1133 return; 1134 } 1135 List<GeneralName> l = new ArrayList<GeneralName>(altNames.size()); 1136 for (List<?> list : altNames) 1137 { 1138 Integer id = (Integer) list.get(0); 1139 Object value = list.get(1); 1140 GeneralName name = null; 1141 if (value instanceof String) 1142 name = makeName(id, (String) value); 1143 else if (value instanceof byte[]) 1144 name = new GeneralName(GeneralName.Kind.forTag(id), (byte[]) value); 1145 else 1146 throw new IOException("invalid name type: " + value.getClass().getName()); 1147 l.add(name); 1148 } 1149 this.altNames = l; 1150 } 1151 1152 /** 1153 * Sets the subject key identifier criterion, or <code>null</code> to clear 1154 * this criterion. Note that the byte array is cloned to prevent modification. 1155 * 1156 * @param subjectKeyId The subject key identifier. 1157 */ 1158 public void setSubjectKeyIdentifier(byte[] subjectKeyId) 1159 { 1160 this.subjectKeyId = subjectKeyId != null ? (byte[]) subjectKeyId.clone() : 1161 null; 1162 } 1163 1164 /** 1165 * Sets the subject public key criterion as a DER-encoded key. Specify 1166 * <code>null</code> to clear this value. 1167 * 1168 * @param key The DER-encoded key bytes. 1169 * @throws IOException If the argument is not a valid DER-encoded key. 1170 */ 1171 public void setSubjectPublicKey(byte[] key) throws IOException 1172 { 1173 if (key == null) 1174 { 1175 subjectKey = null; 1176 subjectKeySpec = null; 1177 return; 1178 } 1179 try 1180 { 1181 subjectKeySpec = new X509EncodedKeySpec(key); 1182 KeyFactory enc = KeyFactory.getInstance("X.509"); 1183 subjectKey = enc.generatePublic(subjectKeySpec); 1184 } 1185 catch (Exception x) 1186 { 1187 subjectKey = null; 1188 subjectKeySpec = null; 1189 IOException ioe = new IOException(x.getMessage()); 1190 ioe.initCause(x); 1191 throw ioe; 1192 } 1193 } 1194 1195 /** 1196 * Sets the subject public key criterion as an opaque representation. 1197 * Specify <code>null</code> to clear this criterion. 1198 * 1199 * @param key The public key. 1200 */ 1201 public void setSubjectPublicKey(PublicKey key) 1202 { 1203 this.subjectKey = key; 1204 if (key == null) 1205 { 1206 subjectKeySpec = null; 1207 return; 1208 } 1209 try 1210 { 1211 KeyFactory enc = KeyFactory.getInstance("X.509"); 1212 subjectKeySpec = (X509EncodedKeySpec) 1213 enc.getKeySpec(key, X509EncodedKeySpec.class); 1214 } 1215 catch (Exception x) 1216 { 1217 subjectKey = null; 1218 subjectKeySpec = null; 1219 } 1220 } 1221 1222 /** 1223 * Sets the public key algorithm ID that matching certificates must have. 1224 * Specify <code>null</code> to clear this criterion. 1225 * 1226 * @param sigId The public key ID. 1227 * @throws IOException If the specified ID is not a valid object identifier. 1228 */ 1229 public void setSubjectPublicKeyAlgID(String sigId) throws IOException 1230 { 1231 if (sigId != null) 1232 { 1233 try 1234 { 1235 OID oid = new OID(sigId); 1236 int[] comp = oid.getIDs(); 1237 if (!checkOid(comp)) 1238 throw new IOException("malformed OID: " + sigId); 1239 this.sigId = oid; 1240 } 1241 catch (IllegalArgumentException iae) 1242 { 1243 IOException ioe = new IOException("malformed OID: " + sigId); 1244 ioe.initCause(iae); 1245 throw ioe; 1246 } 1247 } 1248 else 1249 this.sigId = null; 1250 } 1251 1252 public String toString() 1253 { 1254 StringBuffer str = new StringBuffer(X509CertSelector.class.getName()); 1255 String nl = SystemProperties.getProperty("line.separator"); 1256 String eol = ";" + nl; 1257 str.append(" {").append(nl); 1258 if (cert != null) 1259 str.append(" certificate = ").append(cert).append(eol); 1260 if (basicConstraints >= 0) 1261 str.append(" basic constraints = ").append(basicConstraints).append(eol); 1262 if (serialNo != null) 1263 str.append(" serial number = ").append(serialNo).append(eol); 1264 if (certValid != null) 1265 str.append(" valid date = ").append(certValid).append(eol); 1266 if (issuer != null) 1267 str.append(" issuer = ").append(issuer).append(eol); 1268 if (subject != null) 1269 str.append(" subject = ").append(subject).append(eol); 1270 if (sigId != null) 1271 str.append(" signature OID = ").append(sigId).append(eol); 1272 if (subjectKey != null) 1273 str.append(" subject public key = ").append(subjectKey).append(eol); 1274 if (subjectKeyId != null) 1275 { 1276 str.append(" subject key ID = "); 1277 for (int i = 0; i < subjectKeyId.length; i++) 1278 { 1279 str.append(Character.forDigit((subjectKeyId[i] & 0xF0) >>> 8, 16)); 1280 str.append(Character.forDigit((subjectKeyId[i] & 0x0F), 16)); 1281 if (i < subjectKeyId.length - 1) 1282 str.append(':'); 1283 } 1284 str.append(eol); 1285 } 1286 if (authKeyId != null) 1287 { 1288 str.append(" authority key ID = "); 1289 for (int i = 0; i < authKeyId.length; i++) 1290 { 1291 str.append(Character.forDigit((authKeyId[i] & 0xF0) >>> 8, 16)); 1292 str.append(Character.forDigit((authKeyId[i] & 0x0F), 16)); 1293 if (i < authKeyId.length - 1) 1294 str.append(':'); 1295 } 1296 str.append(eol); 1297 } 1298 if (keyUsage != null) 1299 { 1300 str.append(" key usage = "); 1301 for (int i = 0; i < keyUsage.length; i++) 1302 str.append(keyUsage[i] ? '1' : '0'); 1303 str.append(eol); 1304 } 1305 if (keyPurposeSet != null) 1306 str.append(" key purpose = ").append(keyPurposeSet).append(eol); 1307 if (altNames != null) 1308 str.append(" alternative names = ").append(altNames).append(eol); 1309 if (nameConstraints != null) 1310 str.append(" name constraints = <blob of data>").append(eol); 1311 if (policy != null) 1312 str.append(" policy = ").append(policy).append(eol); 1313 if (pathToNames != null) 1314 str.append(" pathToNames = ").append(pathToNames).append(eol); 1315 str.append("}").append(nl); 1316 return str.toString(); 1317 } 1318 }