Source for java.security.cert.X509CertSelector

   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: 
 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: 
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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: 
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 400:   public byte[] getNameConstraints()
 401:   {
 402:     if (nameConstraints != null)
 403:       return (byte[]) nameConstraints.clone();
 404:     else
 405:       return null;
 406:   }
 407: 
 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:    */
 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 &mdash; the
 449:    * private key usage period &mdash; 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
 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:    */
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 &mdash; the
1044:    * private key usage period &mdash; 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:    */
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:    */
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:    */
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:    */
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:    */
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:    */
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:    */
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:    */
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:    */
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: 
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: }