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.security.OID;
  43: import gnu.java.security.x509.GnuPKIExtension;
  44: import gnu.java.security.x509.ext.CertificatePolicies;
  45: import gnu.java.security.x509.ext.Extension;
  46: import gnu.java.security.x509.ext.GeneralName;
  47: import gnu.java.security.x509.ext.GeneralSubtree;
  48: import gnu.java.security.x509.ext.NameConstraints;
  49: import gnu.java.security.x509.ext.GeneralName.Kind;
  50: 
  51: import java.io.IOException;
  52: import java.math.BigInteger;
  53: import java.net.InetAddress;
  54: import java.security.KeyFactory;
  55: import java.security.PublicKey;
  56: import java.security.spec.X509EncodedKeySpec;
  57: import java.util.ArrayList;
  58: import java.util.Arrays;
  59: import java.util.Collection;
  60: import java.util.Collections;
  61: import java.util.Date;
  62: import java.util.HashSet;
  63: import java.util.Iterator;
  64: import java.util.LinkedList;
  65: import java.util.List;
  66: import java.util.Set;
  67: 
  68: import javax.security.auth.x500.X500Principal;
  69: 
  70: /**
  71:  * A concrete implementation of {@link CertSelector} for X.509 certificates,
  72:  * which allows a number of criteria to be set when accepting certificates,
  73:  * from validity dates, to issuer and subject distinguished names, to some
  74:  * of the various X.509 extensions.
  75:  *
  76:  * <p>Use of this class requires extensive knowledge of the Internet
  77:  * Engineering Task Force's Public Key Infrastructure (X.509). The primary
  78:  * document describing this standard is <a
  79:  * href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: Internet X.509
  80:  * Public Key Infrastructure Certificate and Certificate Revocation List
  81:  * (CRL) Profile</a>.
  82:  *
  83:  * <p>Note that this class is not thread-safe. If multiple threads will
  84:  * use or modify this class then they need to synchronize on the object.
  85:  *
  86:  * @author Casey Marshall (csm@gnu.org)
  87:  * @since 1.4
  88:  */
  89: public class X509CertSelector implements CertSelector, Cloneable
  90: {
  91: 
  92:   // Constants and fields.
  93:   // -------------------------------------------------------------------------
  94: 
  95:   private static final String AUTH_KEY_ID = "2.5.29.35";
  96:   private static final String SUBJECT_KEY_ID = "2.5.29.14";
  97:   private static final String NAME_CONSTRAINTS_ID = "2.5.29.30";
  98: 
  99:   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 &mdash; the
 448:    * private key usage period &mdash; 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: