OSDN Git Service

2006-08-14 Mark Wielaard <mark@klomp.org>
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / security / cert / X509CertSelector.java
1 /* X509CertSelector.java -- selects X.509 certificates by criteria.
2    Copyright (C) 2004, 2005 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
44 import java.io.IOException;
45 import java.math.BigInteger;
46 import java.security.KeyFactory;
47 import java.security.PublicKey;
48 import java.security.spec.X509EncodedKeySpec;
49 import java.util.ArrayList;
50 import java.util.Arrays;
51 import java.util.Collection;
52 import java.util.Collections;
53 import java.util.Date;
54 import java.util.HashSet;
55 import java.util.Iterator;
56 import java.util.LinkedList;
57 import java.util.List;
58 import java.util.Set;
59
60 import javax.security.auth.x500.X500Principal;
61
62 /**
63  * A concrete implementation of {@link CertSelector} for X.509 certificates,
64  * which allows a number of criteria to be set when accepting certificates,
65  * from validity dates, to issuer and subject distinguished names, to some
66  * of the various X.509 extensions.
67  *
68  * <p>Use of this class requires extensive knowledge of the Internet
69  * Engineering Task Force's Public Key Infrastructure (X.509). The primary
70  * document describing this standard is <a
71  * href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: Internet X.509
72  * Public Key Infrastructure Certificate and Certificate Revocation List
73  * (CRL) Profile</a>.
74  *
75  * <p>Note that this class is not thread-safe. If multiple threads will
76  * use or modify this class then they need to synchronize on the object.
77  *
78  * @author Casey Marshall (csm@gnu.org)
79  */
80 public class X509CertSelector implements CertSelector, Cloneable
81 {
82
83   // Constants and fields.
84   // -------------------------------------------------------------------------
85
86   private static final String AUTH_KEY_ID = "2.5.29.35";
87   private static final String SUBJECT_KEY_ID = "2.5.29.14";
88   private static final String NAME_CONSTRAINTS_ID = "2.5.29.30";
89
90   private int basicConstraints;
91   private X509Certificate cert;
92   private BigInteger serialNo;
93   private X500Principal issuer;
94   private X500Principal subject;
95   private byte[] subjectKeyId;
96   private byte[] authKeyId;
97   private boolean[] keyUsage;
98   private Date certValid;
99   private OID sigId;
100   private PublicKey subjectKey;
101   private X509EncodedKeySpec subjectKeySpec;
102   private Set keyPurposeSet;
103   private List altNames;
104   private boolean matchAllNames;
105   private byte[] nameConstraints;
106   private Set policy;
107
108   // Constructors.
109   // ------------------------------------------------------------------------
110
111   /**
112    * Creates a new X.509 certificate selector. The new selector will be
113    * empty, and will accept any certificate (provided that it is an
114    * {@link X509Certificate}).
115    */
116   public X509CertSelector()
117   {
118     basicConstraints = -1;
119   }
120
121   // Instance methods.
122   // ------------------------------------------------------------------------
123
124   /**
125    * Returns the certificate criterion, or <code>null</code> if this value
126    * was not set.
127    *
128    * @return The certificate.
129    */
130   public X509Certificate getCertificate()
131   {
132     return cert;
133   }
134
135   /**
136    * Sets the certificate criterion. If set, only certificates that are
137    * equal to the certificate passed here will be accepted.
138    *
139    * @param cert The certificate.
140    */
141   public void setCertificate(X509Certificate cert)
142   {
143     this.cert = cert;
144   }
145
146   /**
147    * Returns the serial number criterion, or <code>null</code> if this
148    * value was not set.
149    *
150    * @return The serial number.
151    */
152   public BigInteger getSerialNumber()
153   {
154     return serialNo;
155   }
156
157   /**
158    * Sets the serial number of the desired certificate. Only certificates that
159    * contain this serial number are accepted.
160    *
161    * @param serialNo The serial number.
162    */
163   public void setSerialNumber(BigInteger serialNo)
164   {
165     this.serialNo = serialNo;
166   }
167
168   /**
169    * Returns the issuer criterion as a string, or <code>null</code> if this
170    * value was not set.
171    *
172    * @return The issuer.
173    */
174   public String getIssuerAsString()
175   {
176     if (issuer != null)
177       return issuer.getName();
178     else
179       return null;
180   }
181
182   /**
183    * Returns the issuer criterion as a sequence of DER bytes, or
184    * <code>null</code> if this value was not set.
185    *
186    * @return The issuer.
187    */
188   public byte[] getIssuerAsBytes() throws IOException
189   {
190     if (issuer != null)
191       return issuer.getEncoded();
192     else
193       return null;
194   }
195
196   /**
197    * Sets the issuer, specified as a string representation of the issuer's
198    * distinguished name. Only certificates issued by this issuer will
199    * be accepted.
200    *
201    * @param name The string representation of the issuer's distinguished name.
202    * @throws IOException If the given name is incorrectly formatted.
203    */
204   public void setIssuer(String name) throws IOException
205   {
206     if (name != null)
207       {
208         try
209           {
210             issuer = new X500Principal(name);
211           }
212         catch (IllegalArgumentException iae)
213           {
214             throw new IOException(iae.getMessage());
215           }
216       }
217     else
218       issuer = null;
219   }
220
221   /**
222    * Sets the issuer, specified as the DER encoding of the issuer's
223    * distinguished name. Only certificates issued by this issuer will
224    * be accepted.
225    *
226    * @param name The DER encoding of the issuer's distinguished name.
227    * @throws IOException If the given name is incorrectly formatted.
228    */
229   public void setIssuer(byte[] name) throws IOException
230   {
231     if (name != null)
232       {
233         try
234           {
235             issuer = new X500Principal(name);
236           }
237         catch (IllegalArgumentException iae)
238           {
239             throw new IOException(iae.getMessage());
240           }
241       }
242     else
243       issuer = null;
244   }
245
246   /**
247    * Returns the subject criterion as a string, of <code>null</code> if
248    * this value was not set.
249    *
250    * @return The subject.
251    */
252   public String getSubjectAsString()
253   {
254     if (subject != null)
255       return subject.getName();
256     else
257       return null;
258   }
259
260   /**
261    * Returns the subject criterion as a sequence of DER bytes, or
262    * <code>null</code> if this value is not set.
263    *
264    * @return The subject.
265    */
266   public byte[] getSubjectAsBytes() throws IOException
267   {
268     if (subject != null)
269       return subject.getEncoded();
270     else
271       return null;
272   }
273
274   /**
275    * Sets the subject, specified as a string representation of the
276    * subject's distinguished name. Only certificates with the given
277    * subject will be accepted.
278    *
279    * @param name The string representation of the subject's distinguished name.
280    * @throws IOException If the given name is incorrectly formatted.
281    */
282   public void setSubject(String name) throws IOException
283   {
284     if (name != null)
285       {
286         try
287           {
288             subject = new X500Principal(name);
289           }
290         catch (IllegalArgumentException iae)
291           {
292             throw new IOException(iae.getMessage());
293           }
294       }
295     else
296       subject = null;
297   }
298
299   /**
300    * Sets the subject, specified as the DER encoding of the subject's
301    * distinguished name. Only certificates with the given subject will
302    * be accepted.
303    *
304    * @param name The DER encoding of the subject's distinguished name.
305    * @throws IOException If the given name is incorrectly formatted.
306    */
307   public void setSubject(byte[] name) throws IOException
308   {
309     if (name != null)
310       {
311         try
312           {
313             subject = new X500Principal(name);
314           }
315         catch (IllegalArgumentException iae)
316           {
317             throw new IOException(iae.getMessage());
318           }
319       }
320     else
321       subject = null;
322   }
323
324   /**
325    * Returns the subject key identifier criterion, or <code>null</code> if
326    * this value was not set. Note that the byte array is cloned to prevent
327    * modification.
328    *
329    * @return The subject key identifier.
330    */
331   public byte[] getSubjectKeyIdentifier()
332   {
333     if (subjectKeyId != null)
334       return (byte[]) subjectKeyId.clone();
335     else
336       return null;
337   }
338
339   /**
340    * Sets the subject key identifier criterion, or <code>null</code> to clear
341    * this criterion. Note that the byte array is cloned to prevent modification.
342    *
343    * @param subjectKeyId The subject key identifier.
344    */
345   public void setSubjectKeyIdentifier(byte[] subjectKeyId)
346   {
347     this.subjectKeyId = subjectKeyId != null ? (byte[]) subjectKeyId.clone() :
348       null;
349   }
350
351   /**
352    * Returns the authority key identifier criterion, or <code>null</code> if
353    * this value was not set. Note that the byte array is cloned to prevent
354    * modification.
355    *
356    * @return The authority key identifier.
357    */
358   public byte[] getAuthorityKeyIdentifier()
359   {
360     if (authKeyId != null)
361       return (byte[]) authKeyId.clone();
362     else
363       return null;
364   }
365
366   /**
367    * Sets the authority key identifier criterion, or <code>null</code> to clear
368    * this criterion. Note that the byte array is cloned to prevent modification.
369    *
370    * @param authKeyId The authority key identifier.
371    */
372   public void setAuthorityKeyIdentifier(byte[] authKeyId)
373   {
374     this.authKeyId = authKeyId != null ? (byte[]) authKeyId.clone() : null;
375   }
376
377   /**
378    * Returns the date at which certificates must be valid, or <code>null</code>
379    * if this criterion was not set.
380    *
381    * @return The target certificate valitity date.
382    */
383   public Date getCertificateValid()
384   {
385     if (certValid != null)
386       return (Date) certValid.clone();
387     else
388       return null;
389   }
390
391   /**
392    * Sets the date at which certificates must be valid. Specify
393    * <code>null</code> to clear this criterion.
394    *
395    * @param certValid The certificate validity date.
396    */
397   public void setCertificateValid(Date certValid)
398   {
399     this.certValid = certValid != null ? (Date) certValid.clone() : null;
400   }
401
402   /**
403    * This method, and its related X.509 certificate extension &mdash; the
404    * private key usage period &mdash; is not supported under the Internet
405    * PKI for X.509 certificates (PKIX), described in RFC 3280. As such, this
406    * method is not supported either.
407    *
408    * <p>Do not use this method. It is not deprecated, as it is not deprecated
409    * in the Java standard, but it is basically a no-operation and simply
410    * returns <code>null</code>.
411    *
412    * @return Null.
413    */
414   public Date getPrivateKeyValid()
415   {
416     return null;
417   }
418
419   /**
420    * This method, and its related X.509 certificate extension &mdash; the
421    * private key usage period &mdash; is not supported under the Internet
422    * PKI for X.509 certificates (PKIX), described in RFC 3280. As such, this
423    * method is not supported either.
424    *
425    * <p>Do not use this method. It is not deprecated, as it is not deprecated
426    * in the Java standard, but it is basically a no-operation.
427    *
428    * @param UNUSED Is silently ignored.
429    */
430   public void setPrivateKeyValid(Date UNUSED)
431   {
432   }
433
434   /**
435    * Returns the public key algorithm ID that matching certificates must have,
436    * or <code>null</code> if this criterion was not set.
437    *
438    * @return The public key algorithm ID.
439    */
440   public String getSubjectPublicKeyAlgID()
441   {
442     return String.valueOf(sigId);
443   }
444
445   /**
446    * Sets the public key algorithm ID that matching certificates must have.
447    * Specify <code>null</code> to clear this criterion.
448    *
449    * @param sigId The public key ID.
450    * @throws IOException If the specified ID is not a valid object identifier.
451    */
452   public void setSubjectPublicKeyAlgID(String sigId) throws IOException
453   {
454     if (sigId != null)
455       {
456         try
457           {
458             OID oid = new OID(sigId);
459             int[] comp = oid.getIDs();
460             if (!checkOid(comp))
461               throw new IOException("malformed OID: " + sigId);
462             this.sigId = oid;
463           }
464         catch (IllegalArgumentException iae)
465           {
466             IOException ioe = new IOException("malformed OID: " + sigId);
467             ioe.initCause(iae);
468             throw ioe;
469           }
470       }
471     else
472       this.sigId = null;
473   }
474
475   /**
476    * Returns the subject public key criterion, or <code>null</code> if this
477    * value is not set.
478    *
479    * @return The subject public key.
480    */
481   public PublicKey getSubjectPublicKey()
482   {
483     return subjectKey;
484   }
485
486   /**
487    * Sets the subject public key criterion as an opaque representation.
488    * Specify <code>null</code> to clear this criterion.
489    *
490    * @param key The public key.
491    */
492   public void setSubjectPublicKey(PublicKey key)
493   {
494     this.subjectKey = key;
495     if (key == null)
496       {
497         subjectKeySpec = null;
498         return;
499       }
500     try
501       {
502         KeyFactory enc = KeyFactory.getInstance("X.509");
503         subjectKeySpec = (X509EncodedKeySpec)
504           enc.getKeySpec(key, X509EncodedKeySpec.class);
505       }
506     catch (Exception x)
507       {
508         subjectKey = null;
509         subjectKeySpec = null;
510       }
511   }
512
513   /**
514    * Sets the subject public key criterion as a DER-encoded key. Specify
515    * <code>null</code> to clear this value.
516    *
517    * @param key The DER-encoded key bytes.
518    * @throws IOException If the argument is not a valid DER-encoded key.
519    */
520   public void setSubjectPublicKey(byte[] key) throws IOException
521   {
522     if (key == null)
523       {
524         subjectKey = null;
525         subjectKeySpec = null;
526         return;
527       }
528     try
529       {
530         subjectKeySpec = new X509EncodedKeySpec(key);
531         KeyFactory enc = KeyFactory.getInstance("X.509");
532         subjectKey = enc.generatePublic(subjectKeySpec);
533       }
534     catch (Exception x)
535       {
536         subjectKey = null;
537         subjectKeySpec = null;
538         IOException ioe = new IOException(x.getMessage());
539         ioe.initCause(x);
540         throw ioe;
541       }
542   }
543
544   /**
545    * Returns the public key usage criterion, or <code>null</code> if this
546    * value is not set. Note that the array is cloned to prevent modification.
547    *
548    * @return The public key usage.
549    */
550   public boolean[] getKeyUsage()
551   {
552     if (keyUsage != null)
553       return (boolean[]) keyUsage.clone();
554     else
555       return null;
556   }
557
558   /**
559    * Sets the public key usage criterion. Specify <code>null</code> to clear
560    * this value.
561    *
562    * @param keyUsage The public key usage.
563    */
564   public void setKeyUsage(boolean[] keyUsage)
565   {
566     this.keyUsage = keyUsage != null ? (boolean[]) keyUsage.clone() : null;
567   }
568
569   /**
570    * Returns the set of extended key purpose IDs, as an unmodifiable set
571    * of OID strings. Returns <code>null</code> if this criterion is not
572    * set.
573    *
574    * @return The set of key purpose OIDs (strings).
575    */
576   public Set getExtendedKeyUsage()
577   {
578     if (keyPurposeSet != null)
579       return Collections.unmodifiableSet(keyPurposeSet);
580     else
581       return null;
582   }
583
584   /**
585    * Sets the extended key usage criterion, as a set of OID strings. Specify
586    * <code>null</code> to clear this value.
587    *
588    * @param keyPurposeSet The set of key purpose OIDs.
589    * @throws IOException If any element of the set is not a valid OID string.
590    */
591   public void setExtendedKeyUsage(Set keyPurposeSet) throws IOException
592   {
593     if (keyPurposeSet == null)
594       {
595         this.keyPurposeSet = null;
596         return;
597       }
598     Set s = new HashSet();
599     for (Iterator it = keyPurposeSet.iterator(); it.hasNext(); )
600       {
601         Object o = it.next();
602         if (!(o instanceof String))
603           throw new IOException("not a string: " + o);
604         try
605           {
606             OID oid = new OID((String) o);
607             int[] comp = oid.getIDs();
608             if (!checkOid(comp))
609               throw new IOException("malformed OID: " + o);
610           }
611         catch (IllegalArgumentException iae)
612           {
613             IOException ioe = new IOException("malformed OID: " + o);
614             ioe.initCause(iae);
615             throw ioe;
616           }
617       }
618     this.keyPurposeSet = s;
619   }
620
621   /**
622    * Returns whether or not all specified alternative names must match.
623    * If false, a certificate is considered a match if <em>one</em> of the
624    * specified alternative names matches.
625    *
626    * @return true if all names must match.
627    */
628   public boolean getMatchAllSubjectAltNames()
629   {
630     return matchAllNames;
631   }
632
633   /**
634    * Sets whether or not all subject alternative names must be matched.
635    * If false, then a certificate will be considered a match if one
636    * alternative name matches.
637    *
638    * @param matchAllNames Whether or not all alternative names must be
639    *        matched.
640    */
641   public void setMatchAllSubjectAltNames(boolean matchAllNames)
642   {
643     this.matchAllNames = matchAllNames;
644   }
645
646   /**
647    * Sets the subject alternative names critertion. Each element of the
648    * argument must be a {@link java.util.List} that contains exactly two
649    * elements: the first an {@link Integer}, representing the type of
650    * name, and the second either a {@link String} or a byte array,
651    * representing the name itself.
652    *
653    * @param altNames The alternative names.
654    * @throws IOException If any element of the argument is invalid.
655    */
656   public void setSubjectAlternativeNames(Collection altNames)
657     throws IOException
658   {
659     if (altNames == null)
660       {
661         this.altNames = null;
662         return;
663       }
664     List l = new ArrayList(altNames.size());
665     for (Iterator it = altNames.iterator(); it.hasNext(); )
666       {
667         Object o = it.next();
668         if (!(o instanceof List) || ((List) o).size() != 2 ||
669             !(((List) o).get(0) instanceof Integer) ||
670             !(((List) o).get(1) instanceof String) ||
671             !(((List) o).get(1) instanceof byte[]))
672           throw new IOException("illegal alternative name: " + o);
673         Integer i = (Integer) ((List) o).get(0);
674         if (i.intValue() < 0 || i.intValue() > 8)
675           throw new IOException("illegal alternative name: " + o +
676                                 ", bad id: " + i);
677         l.add(new ArrayList((List) o));
678       }
679     this.altNames = l;
680   }
681
682   /**
683    * Add a name to the subject alternative names criterion.
684    *
685    * @param id The type of name this is. Must be in the range [0,8].
686    * @param name The name.
687    * @throws IOException If the id is out of range, or if the name
688    *   is null.
689    */
690   public void addSubjectAlternativeName(int id, String name)
691     throws IOException
692   {
693     if (id < 0 || id > 8 || name == null)
694       throw new IOException("illegal alternative name");
695     if (altNames == null)
696       altNames = new LinkedList();
697     ArrayList l = new ArrayList(2);
698     l.add(Integer.valueOf(id));
699     l.add(name);
700     altNames.add(l);
701   }
702
703   /**
704    * Add a name, as DER-encoded bytes, to the subject alternative names
705    * criterion.
706    *
707    * @param id The type of name this is.
708    */
709   public void addSubjectAlternativeName(int id, byte[] name)
710     throws IOException
711   {
712     if (id < 0 || id > 8 || name == null)
713       throw new IOException("illegal alternative name");
714     if (altNames == null)
715       altNames = new LinkedList();
716     ArrayList l = new ArrayList(2);
717     l.add(Integer.valueOf(id));
718     l.add(name);
719     altNames.add(l);
720   }
721
722   /**
723    * Returns the name constraints criterion, or <code>null</code> if this
724    * value is not set. Note that the byte array is cloned to prevent
725    * modification.
726    *
727    * @return The name constraints.
728    */
729   public byte[] getNameConstraints()
730   {
731     if (nameConstraints != null)
732       return (byte[]) nameConstraints.clone();
733     else
734       return null;
735   }
736
737   /**
738    * Sets the name constraints criterion; specify <code>null</code> to
739    * clear this criterion. Note that if non-null, the argument will be
740    * cloned to prevent modification.
741    *
742    * @param nameConstraints The new name constraints.
743    * @throws IOException If the argument is not a valid DER-encoded
744    *         name constraints.
745    */
746   public void setNameConstraints(byte[] nameConstraints)
747     throws IOException
748   {
749     // FIXME check if the argument is valid.
750     this.nameConstraints = nameConstraints != null
751       ? (byte[]) nameConstraints.clone() : null;
752   }
753
754   /**
755    * Returns the basic constraints criterion, or -1 if this value is not set.
756    *
757    * @return The basic constraints.
758    */
759   public int getBasicConstraints()
760   {
761     return basicConstraints;
762   }
763
764   /**
765    * Sets the basic constraints criterion. Specify -1 to clear this parameter.
766    *
767    * @param basicConstraints The new basic constraints value.
768    */
769   public void setBasicConstraints(int basicConstraints)
770   {
771     if (basicConstraints < -1)
772       basicConstraints = -1;
773     this.basicConstraints = basicConstraints;
774   }
775
776   // The last two criteria not yet implemented are certificate policies
777   // and path-to-names. Both of these are somewhat advanced extensions
778   // (you could probably count the applications that actually use them
779   //  on one hand), and they both have no support in the X509Certificate
780   // class.
781   //
782   // Not having support in X509Certificate is not always a problem; for
783   // example, we can compare DER-encoded values as byte arrays for some
784   // extensions. We can't, however, compare them if they are specified
785   // in a set (as policies are). We need to parse the actual value in the
786   // certificate, and check it against the specified set.
787
788   // FIXME
789 //   public void setPolicy(Set policy) throws IOException
790 //   {
791 //     if (policy != null)
792 //       {
793 //         for (Iterator it = policy.iterator(); it.hasNext(); )
794 //           try
795 //             {
796 //               OID oid = new OID((String) it.next());
797 //               int[] i = oid.getIDs();
798 //               if (!checkOid(i))
799 //                 throw new IOException("invalid OID");
800 //             }
801 //           catch (Exception x)
802 //             {
803 //               throw new IOException("invalid OID");
804 //             }
805 //       }
806 //     this.policy = policy != null ? new HashSet(policy) : null;
807 //   }
808
809   // FIXME
810 //   public void setPathToNames(Collection names) throws IOException
811 //   {
812 //     if (names == null)
813 //       {
814 //         this.names = null;
815 //         return;
816 //       }
817 //     for (Iterator it = names.iterator(); it.hasNext(); )
818 //       {
819 //         try
820 //           {
821 //             List l = (List) it.next();
822 //             if (l.get(1) instanceof String)
823 //               addPathToName(((Integer)l.get(0)).intValue(), (String)l.get(1));
824 //             else
825 //               addPathToName(((Integer)l.get(0)).intValue(), (byte[])l.get(1));
826 //           }
827 //         catch (Exception x)
828 //           {
829 //            this.names = null;
830 //             throw new IOException("invalid names");
831 //           }
832 //       }
833 //   }
834
835   // FIXME
836 //   public void addPathToName(int id, String name) throws IOException
837 //   {
838 //   }
839
840   // FIXME
841 //   public void addPathToName(int id, byte[] name) throws IOException
842 //   {
843 //   }
844
845   // FIXME
846 //   public Collection getSubjectAlternativeNames()
847 //   {
848 //     return null;
849 //   }
850
851   // FIXME
852 //   public Set getPolicy()
853 //   {
854 //     return null;
855 //   }
856
857   // FIXME
858 //   public Collection getPathToNames()
859 //   {
860 //     return null;
861 //   }
862
863   /**
864    * Match a certificate. This method will check the given certificate
865    * against all the enabled criteria of this selector, and will return
866    * <code>true</code> if the given certificate matches.
867    *
868    * @param certificate The certificate to check.
869    * @return true if the certificate matches all criteria.
870    */
871   public boolean match(Certificate certificate)
872   {
873     if (!(certificate instanceof X509Certificate))
874       return false;
875     X509Certificate cert = (X509Certificate) certificate;
876     if (this.cert != null)
877       {
878         try
879           {
880             byte[] e1 = this.cert.getEncoded();
881             byte[] e2 = cert.getEncoded();
882             if (!Arrays.equals(e1, e2))
883               return false;
884           }
885         catch (CertificateEncodingException cee)
886           {
887             return false;
888           }
889       }
890     if (serialNo != null)
891       {
892         if (!serialNo.equals(cert.getSerialNumber()))
893           return false;
894       }
895     if (certValid != null)
896       {
897         try
898           {
899             cert.checkValidity(certValid);
900           }
901         catch (CertificateException ce)
902           {
903             return false;
904           }
905       }
906     if (issuer != null)
907       {
908         if (!issuer.equals(cert.getIssuerX500Principal()))
909           return false;
910       }
911     if (subject != null)
912       {
913         if (!subject.equals(cert.getSubjectX500Principal()))
914           return false;
915       }
916     if (sigId != null)
917       {
918         if (!sigId.toString().equals(cert.getSigAlgOID()))
919           return false;
920       }
921     if (subjectKeyId != null)
922       {
923         byte[] b = cert.getExtensionValue(SUBJECT_KEY_ID);
924         if (!Arrays.equals(b, subjectKeyId))
925           return false;
926       }
927     if (authKeyId != null)
928       {
929         byte[] b = cert.getExtensionValue(AUTH_KEY_ID);
930         if (!Arrays.equals(b, authKeyId))
931           return false;
932       }
933     if (keyUsage != null)
934       {
935         boolean[] b = cert.getKeyUsage();
936         if (!Arrays.equals(b, keyUsage))
937           return false;
938       }
939     if (basicConstraints >= 0)
940       {
941         if (cert.getBasicConstraints() != basicConstraints)
942           return false;
943       }
944     if (keyPurposeSet != null)
945       {
946         List kp = null;
947         try
948           {
949             kp = cert.getExtendedKeyUsage();
950           }
951         catch (CertificateParsingException cpe)
952           {
953             return false;
954           }
955         if (kp == null)
956           return false;
957         for (Iterator it = keyPurposeSet.iterator(); it.hasNext(); )
958           {
959             if (!kp.contains(it.next()))
960               return false;
961           }
962       }
963     if (altNames != null)
964       {
965         Collection an = null;
966         try
967           {
968             an = cert.getSubjectAlternativeNames();
969           }
970         catch (CertificateParsingException cpe)
971           {
972             return false;
973           }
974         if (an == null)
975           return false;
976         int match = 0;
977         for (Iterator it = altNames.iterator(); it.hasNext(); )
978           {
979             List l = (List) it.next();
980             Integer id = (Integer) l.get(0);
981             String s = null;
982             byte[] b = null;
983             if (l.get(1) instanceof String)
984               s = (String) l.get(1);
985             else if (l.get(1) instanceof byte[])
986               b = (byte[]) l.get(1);
987             else
988               return false;
989             for (Iterator it2 = an.iterator(); it2.hasNext(); )
990               {
991                 Object o = it2.next();
992                 if (!(o instanceof List))
993                   continue;
994                 List l2 = (List) o;
995                 if (l2.size() != 2)
996                   continue;
997                 if (!id.equals(l2.get(0)))
998                   continue;
999                 if (s != null && (l2.get(1) instanceof String) &&
1000                     s.equals(l2.get(1)))
1001                   match++;
1002                 else if (b != null && (l2.get(1) instanceof byte[]) &&
1003                          Arrays.equals(b, (byte[]) l2.get(1)))
1004                   match++;
1005               }
1006             if (match == 0 || (matchAllNames && match != altNames.size()))
1007               return false;
1008           }
1009       }
1010     if (nameConstraints != null)
1011       {
1012         byte[] nc = cert.getExtensionValue(NAME_CONSTRAINTS_ID);
1013         if (!Arrays.equals(nameConstraints, nc))
1014           return false;
1015       }
1016
1017     // FIXME check policies.
1018     // FIXME check path-to-names.
1019
1020     return true;
1021   }
1022
1023   public String toString()
1024   {
1025     StringBuffer str = new StringBuffer(X509CertSelector.class.getName());
1026     String nl = SystemProperties.getProperty("line.separator");
1027     String eol = ";" + nl;
1028     str.append(" {").append(nl);
1029     if (cert != null)
1030       str.append("  certificate = ").append(cert).append(eol);
1031     if (basicConstraints >= 0)
1032       str.append("  basic constraints = ").append(basicConstraints).append(eol);
1033     if (serialNo != null)
1034       str.append("  serial number = ").append(serialNo).append(eol);
1035     if (certValid != null)
1036       str.append("  valid date = ").append(certValid).append(eol);
1037     if (issuer != null)
1038       str.append("  issuer = ").append(issuer).append(eol);
1039     if (subject != null)
1040       str.append("  subject = ").append(subject).append(eol);
1041     if (sigId != null)
1042       str.append("  signature OID = ").append(sigId).append(eol);
1043     if (subjectKey != null)
1044       str.append("  subject public key = ").append(subjectKey).append(eol);
1045     if (subjectKeyId != null)
1046       {
1047         str.append("  subject key ID = ");
1048         for (int i = 0; i < subjectKeyId.length; i++)
1049           {
1050             str.append(Character.forDigit((subjectKeyId[i] & 0xF0) >>> 8, 16));
1051             str.append(Character.forDigit((subjectKeyId[i] & 0x0F), 16));
1052             if (i < subjectKeyId.length - 1)
1053               str.append(':');
1054           }
1055         str.append(eol);
1056       }
1057     if (authKeyId != null)
1058       {
1059         str.append("  authority key ID = ");
1060         for (int i = 0; i < authKeyId.length; i++)
1061           {
1062             str.append(Character.forDigit((authKeyId[i] & 0xF0) >>> 8, 16));
1063             str.append(Character.forDigit((authKeyId[i] & 0x0F), 16));
1064             if (i < authKeyId.length - 1)
1065               str.append(':');
1066           }
1067         str.append(eol);
1068       }
1069     if (keyUsage != null)
1070       {
1071         str.append("  key usage = ");
1072         for (int i = 0; i < keyUsage.length; i++)
1073           str.append(keyUsage[i] ? '1' : '0');
1074         str.append(eol);
1075       }
1076     if (keyPurposeSet != null)
1077       str.append("  key purpose = ").append(keyPurposeSet).append(eol);
1078     if (altNames != null)
1079       str.append("  alternative names = ").append(altNames).append(eol);
1080     if (nameConstraints != null)
1081       str.append("  name constraints = <blob of data>").append(eol);
1082     str.append("}").append(nl);
1083     return str.toString();
1084   }
1085
1086   public Object clone()
1087   {
1088     try
1089       {
1090         return super.clone();
1091       }
1092     catch (CloneNotSupportedException shouldNotHappen)
1093       {
1094         throw new Error(shouldNotHappen);
1095       }
1096   }
1097
1098   // Own methods.
1099   // -------------------------------------------------------------------------
1100
1101   private static boolean checkOid(int[] oid)
1102   {
1103     return (oid != null && oid.length > 2 &&
1104             (oid[0] >= 0 && oid[0] <= 2) && (oid[1] >= 0 && oid[1] <= 39));
1105   }
1106 }