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