OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / libcore / luni / src / main / java / java / security / cert / X509CertSelector.java
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17
18 package java.security.cert;
19
20 import java.io.IOException;
21 import java.math.BigInteger;
22 import java.security.PublicKey;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.Date;
28 import java.util.HashSet;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Set;
32 import javax.security.auth.x500.X500Principal;
33 import org.apache.harmony.security.asn1.ASN1OctetString;
34 import org.apache.harmony.security.x509.AlgorithmIdentifier;
35 import org.apache.harmony.security.x509.CertificatePolicies;
36 import org.apache.harmony.security.x509.GeneralName;
37 import org.apache.harmony.security.x509.GeneralNames;
38 import org.apache.harmony.security.x509.NameConstraints;
39 import org.apache.harmony.security.x509.PolicyInformation;
40 import org.apache.harmony.security.x509.PrivateKeyUsagePeriod;
41 import org.apache.harmony.security.x509.SubjectPublicKeyInfo;
42
43
44
45 /**
46  * A certificate selector ({@code CertSelector} for selecting {@code
47  * X509Certificate}s that match the specified criteria.
48  */
49 public class X509CertSelector implements CertSelector {
50
51     // match criteria
52     private X509Certificate certificateEquals;
53     private BigInteger serialNumber;
54     private X500Principal issuer;
55     private X500Principal subject;
56     private byte[] subjectKeyIdentifier;
57     private byte[] authorityKeyIdentifier;
58     private Date certificateValid;
59     private String subjectPublicKeyAlgID;
60     private Date privateKeyValid;
61     private byte[] subjectPublicKey;
62     private boolean[] keyUsage;
63     private Set extendedKeyUsage;
64     private boolean matchAllNames = true;
65     private int pathLen = -1;
66     private List[] subjectAltNames;
67     private NameConstraints nameConstraints;
68     private Set policies;
69     private ArrayList pathToNames;
70
71     // needed to avoid needless encoding/decoding work
72     private PublicKey subjectPublicKeyImpl;
73     private String issuerName;
74     private byte[] issuerBytes;
75
76     /**
77      * Creates a new {@code X509CertSelector}.
78      */
79     public X509CertSelector() {}
80
81     /**
82      * Sets the certificate that a matching certificate must be equal to.
83      *
84      * @param certificate
85      *            the certificate to match, or null to not check this criteria.
86      */
87     public void setCertificate(X509Certificate certificate) {
88         certificateEquals = certificate;
89     }
90
91     /**
92      * Returns the certificate that a matching certificate must be equal to.
93      *
94      * @return the certificate to match, or null if this criteria is not
95      *         checked.
96      */
97     public X509Certificate getCertificate() {
98         return certificateEquals;
99     }
100
101     /**
102      * Sets the serial number that a certificate must match.
103      *
104      * @param serialNumber
105      *            the serial number to match, or {@code null} to not check the
106      *            serial number.
107      */
108     public void setSerialNumber(BigInteger serialNumber) {
109         this.serialNumber = serialNumber;
110     }
111
112     /**
113      * Returns the serial number that a certificate must match.
114      *
115      * @return the serial number to match, or {@code null} if the serial number
116      *         is not to be checked.
117      */
118     public BigInteger getSerialNumber() {
119         return serialNumber;
120     }
121
122     /**
123      * Sets the issuer that a certificate must match.
124      *
125      * @param issuer
126      *            the issuer to match, or {@code null} if the issuer is not to
127      *            be checked.
128      */
129     public void setIssuer(X500Principal issuer) {
130         this.issuer = issuer;
131         this.issuerName = null;
132         this.issuerBytes = null;
133     }
134
135     /**
136      * Returns the issuer that a certificate must match.
137      *
138      * @return the issuer that a certificate must match, or {@code null} if the
139      *         issuer is not to be checked.
140      */
141     public X500Principal getIssuer() {
142         return issuer;
143     }
144
145     /**
146      * <b>Do not use</b>, use {@link #getIssuer()} or
147      * {@link #getIssuerAsBytes()} instead. Sets the issuer that a certificate
148      * must match.
149      *
150      * @param issuerName
151      *            the issuer in a RFC 2253 format string, or {@code null} to not
152      *            check the issuer.
153      * @throws IOException
154      *             if parsing the issuer fails.
155      */
156     public void setIssuer(String issuerName) throws IOException {
157         if (issuerName == null) {
158             this.issuer = null;
159             this.issuerName = null;
160             this.issuerBytes = null;
161             return;
162         }
163         try {
164             this.issuer = new X500Principal(issuerName);
165             this.issuerName = issuerName;
166             this.issuerBytes = null;
167         } catch (IllegalArgumentException e) {
168             throw new IOException(e.getMessage());
169         }
170     }
171
172     /**
173      * <b>Do not use</b>, use {@link #getIssuer()} or
174      * {@link #getIssuerAsBytes()} instead. Returns the issuer that a
175      * certificate must match in a RFC 2253 format string.
176      *
177      * @return the issuer in a RFC 2253 format string, or {@code null} if the
178      *         issuer is not to be checked.
179      */
180     public String getIssuerAsString() {
181         if (issuer == null) {
182             return null;
183         }
184         if (issuerName == null) {
185             issuerName = issuer.getName();
186         }
187         return issuerName;
188     }
189
190     /**
191      * Sets the issuer that a certificate must match.
192      *
193      * @param issuerDN
194      *            the distinguished issuer name in ASN.1 DER encoded format, or
195      *            {@code null} to not check the issuer.
196      * @throws IOException
197      *             if decoding the issuer fail.
198      */
199     public void setIssuer(byte[] issuerDN) throws IOException {
200         if (issuerDN == null) {
201             issuer = null;
202             return;
203         }
204         try {
205             issuer = new X500Principal(issuerDN);
206             this.issuerName = null;
207             this.issuerBytes = new byte[issuerDN.length];
208             System.arraycopy(issuerDN, 0, this.issuerBytes, 0, issuerDN.length);
209         } catch (IllegalArgumentException e) {
210             throw new IOException(e.getMessage());
211         }
212     }
213
214     /**
215      * Returns the issuer that a certificate must match.
216      *
217      * @return the distinguished issuer name in ASN.1 DER encoded format, or
218      *         {@code null} if the issuer is not to be checked.
219      * @throws IOException
220      *             if encoding the issuer fails.
221      */
222     public byte[] getIssuerAsBytes() throws IOException {
223         if (issuer == null) {
224             return null;
225         }
226         if (issuerBytes == null) {
227             issuerBytes = issuer.getEncoded();
228         }
229         byte[] result = new byte[issuerBytes.length];
230         System.arraycopy(issuerBytes, 0, result, 0, issuerBytes.length);
231         return result;
232     }
233
234     /**
235      * Set the subject that a certificate must match.
236      *
237      * @param subject
238      *            the subject distinguished name or {@code null} to not check
239      *            the subject.
240      */
241     public void setSubject(X500Principal subject) {
242         this.subject = subject;
243     }
244
245     /**
246      * Returns the subject that a certificate must match.
247      *
248      * @return the subject distinguished name, or null if the subject is not to
249      *         be checked.
250      */
251     public X500Principal getSubject() {
252         return subject;
253     }
254
255     /**
256      * <b>Do not use</b>, use {@link #setSubject(byte[])} or
257      * {@link #setSubject(X500Principal)} instead. Returns the subject that a
258      * certificate must match.
259      *
260      * @param subjectDN
261      *            the subject distinguished name in RFC 2253 format or {@code
262      *            null} to not check the subject.
263      * @throws IOException
264      *             if decoding the subject fails.
265      */
266     public void setSubject(String subjectDN) throws IOException {
267         if (subjectDN == null) {
268             subject = null;
269             return;
270         }
271         try {
272             subject = new X500Principal(subjectDN);
273         } catch (IllegalArgumentException e) {
274             throw new IOException(e.getMessage());
275         }
276     }
277
278     /**
279      * <b>Do not use</b>, use {@link #getSubject()} or
280      * {@link #getSubjectAsBytes()} instead. Returns the subject that a
281      * certificate must match.
282      *
283      * @return the subject distinguished name in RFC 2253 format, or {@code
284      *         null} if the subject is not to be checked.
285      */
286     public String getSubjectAsString() {
287         if (subject == null) {
288             return null;
289         }
290         return subject.getName();
291     }
292
293     /**
294      * Sets the subject that a certificate must match.
295      *
296      * @param subjectDN
297      *            the subject distinguished name in ASN.1 DER format, or {@code
298      *            null} to not check the subject.
299      * @throws IOException
300      *             if decoding the subject fails.
301      */
302     public void setSubject(byte[] subjectDN) throws IOException {
303         if (subjectDN == null) {
304             subject = null;
305             return;
306         }
307         try {
308             subject = new X500Principal(subjectDN);
309         } catch (IllegalArgumentException e) {
310             throw new IOException(e.getMessage());
311         }
312     }
313
314     /**
315      * Returns the subject that a certificate must match.
316      *
317      * @return the subject distinguished name in ASN.1 DER format, or {@code
318      *         null} if the subject is not to be checked.
319      * @throws IOException
320      *             if encoding the subject fails.
321      */
322     public byte[] getSubjectAsBytes() throws IOException {
323         if (subject == null) {
324             return null;
325         }
326         return subject.getEncoded();
327     }
328
329     /**
330      * Sets the criterion for the {@literal SubjectKeyIdentifier} extension.
331      * <p>
332      * The {@code subjectKeyIdentifier} should be a single DER encoded value.
333      *
334      * @param subjectKeyIdentifier
335      *            the subject key identifier or {@code null} to disable this
336      *            check.
337      */
338     public void setSubjectKeyIdentifier(byte[] subjectKeyIdentifier) {
339         if (subjectKeyIdentifier == null) {
340             this.subjectKeyIdentifier = null;
341             return;
342         }
343         this.subjectKeyIdentifier = new byte[subjectKeyIdentifier.length];
344         System.arraycopy(subjectKeyIdentifier, 0, this.subjectKeyIdentifier, 0,
345                          subjectKeyIdentifier.length);
346     }
347
348     /**
349      * Returns the criterion for the {@literal SubjectKeyIdentifier} extension.
350      *
351      * @return the subject key identifier or {@code null} if it is not to be
352      *         checked.
353      */
354     public byte[] getSubjectKeyIdentifier() {
355         if (subjectKeyIdentifier == null) {
356             return null;
357         }
358         byte[] res = new byte[subjectKeyIdentifier.length];
359         System.arraycopy(subjectKeyIdentifier, 0, res, 0, res.length);
360         return res;
361     }
362
363     /**
364      * Sets the criterion for the {@literal AuthorityKeyIdentifier} extension.
365      *
366      * @param authorityKeyIdentifier
367      *            the authority key identifier, or {@code null} to disable this
368      *            check.
369      */
370     public void setAuthorityKeyIdentifier(byte[] authorityKeyIdentifier) {
371         if (authorityKeyIdentifier == null) {
372             this.authorityKeyIdentifier = null;
373             return;
374         }
375         this.authorityKeyIdentifier = new byte[authorityKeyIdentifier.length];
376         System.arraycopy(authorityKeyIdentifier, 0,
377                          this.authorityKeyIdentifier, 0,
378                          authorityKeyIdentifier.length);
379     }
380
381     /**
382      * Returns the criterion for the {@literal AuthorityKeyIdentifier}
383      * extension.
384      *
385      * @return the authority key identifier, or {@code null} if it is not to be
386      *         checked.
387      */
388     public byte[] getAuthorityKeyIdentifier() {
389         if (authorityKeyIdentifier == null) {
390             return null;
391         }
392         byte[] res = new byte[authorityKeyIdentifier.length];
393         System.arraycopy(authorityKeyIdentifier, 0, res, 0, res.length);
394         return res;
395     }
396
397     /**
398      * Sets the criterion for the validity date of the certificate.
399      * <p>
400      * The certificate must be valid at the specified date.
401      * @param certificateValid
402      *            the validity date or {@code null} to not check the date.
403      */
404     public void setCertificateValid(Date certificateValid) {
405         this.certificateValid = (certificateValid == null)
406                                 ? null
407                                 : (Date) certificateValid.clone();
408     }
409
410     /**
411      * Returns the criterion for the validity date of the certificate.
412      *
413      * @return the validity date or {@code null} if the date is not to be
414      *         checked.
415      */
416     public Date getCertificateValid() {
417         return (certificateValid == null)
418                                 ? null
419                                 : (Date) certificateValid.clone();
420     }
421
422     /**
423      * Sets the criterion for the validity date of the private key.
424      * <p>
425      * The private key must be valid at the specified date.
426      *
427      * @param privateKeyValid
428      *            the validity date or {@code null} to not check the date.
429      */
430     public void setPrivateKeyValid(Date privateKeyValid) {
431         if (privateKeyValid == null) {
432             this.privateKeyValid = null;
433             return;
434         }
435         this.privateKeyValid = (Date) privateKeyValid.clone();
436     }
437
438     /**
439      * Returns the criterion for the validity date of the private key.
440      * <p>
441      * The private key must be valid at the specified date.
442      *
443      * @return the validity date or {@code null} if the date is not to be
444      *         checked.
445      */
446     public Date getPrivateKeyValid() {
447         if (privateKeyValid != null) {
448             return (Date) privateKeyValid.clone();
449         }
450         return null;
451     }
452
453     private void checkOID(String oid) throws IOException {
454         int beg = 0;
455         int end = oid.indexOf('.', beg);
456         try {
457             int comp = Integer.parseInt(oid.substring(beg, end));
458             beg = end + 1;
459             if ((comp < 0) || (comp > 2)) {
460                 throw new IOException("Bad OID: " + oid);
461             }
462             end = oid.indexOf('.', beg);
463             comp = Integer.parseInt(oid.substring(beg, end));
464             if ((comp < 0) || (comp > 39)) {
465                 throw new IOException("Bad OID: " + oid);
466             }
467         } catch (IndexOutOfBoundsException e) {
468             throw new IOException("Bad OID: " + oid);
469         } catch (NumberFormatException e) {
470             throw new IOException("Bad OID: " + oid);
471         }
472     }
473
474     /**
475      * Sets the criterion for the subject public key signature algorithm.
476      * <p>
477      * The certificate must contain a subject public key with the algorithm
478      * specified.
479      *
480      * @param oid
481      *            the OID (object identifier) of the signature algorithm or
482      *            {@code null} to not check the OID.
483      * @throws IOException
484      *             if the specified object identifier is invalid.
485      */
486     public void setSubjectPublicKeyAlgID(String oid) throws IOException {
487         if (oid == null) {
488             subjectPublicKeyAlgID = null;
489             return;
490         }
491         checkOID(oid);
492         subjectPublicKeyAlgID = oid;
493     }
494
495     /**
496      * Returns the criterion for the subject public key signature algorithm.
497      *
498      * @return the OID (object identifier) or the signature algorithm or {@code
499      *         null} if it's not to be checked.
500      */
501     public String getSubjectPublicKeyAlgID() {
502         return subjectPublicKeyAlgID;
503     }
504
505     /**
506      * Sets the criterion for the subject public key.
507      *
508      * @param key
509      *            the subject public key or {@code null} to not check the key.
510      */
511     public void setSubjectPublicKey(PublicKey key) {
512         subjectPublicKey = (key == null) ? null : key.getEncoded();
513         subjectPublicKeyImpl = key;
514     }
515
516     /**
517      * Sets the criterion for the subject public key.
518      *
519      * @param key
520      *            the subject public key in ASN.1 DER encoded format or {@code null} to
521      *            not check the key.
522      * @throws IOException
523      *             if decoding the the public key fails.
524      */
525     public void setSubjectPublicKey(byte[] key) throws IOException {
526         if (key == null) {
527             subjectPublicKey = null;
528             subjectPublicKeyImpl = null;
529             return;
530         }
531         subjectPublicKey = new byte[key.length];
532         System.arraycopy(key, 0, subjectPublicKey, 0, key.length);
533         subjectPublicKeyImpl =
534             ((SubjectPublicKeyInfo) SubjectPublicKeyInfo.ASN1.decode(key))
535             .getPublicKey();
536     }
537
538     /**
539      * Returns the criterion for the subject public key.
540      *
541      * @return the subject public key or {@code null} if the key is not to be
542      *         checked.
543      */
544     public PublicKey getSubjectPublicKey() {
545         return subjectPublicKeyImpl;
546     }
547
548     /**
549      * Sets the criterion for the {@literal KeyUsage} extension.
550      *
551      * @param keyUsage
552      *            the boolean array in the format as returned by
553      *            {@link X509Certificate#getKeyUsage()}, or {@code null} to not
554      *            check the key usage.
555      */
556     public void setKeyUsage(boolean[] keyUsage) {
557         if (keyUsage == null) {
558             this.keyUsage = null;
559             return;
560         }
561         this.keyUsage = new boolean[keyUsage.length];
562         System.arraycopy(keyUsage, 0, this.keyUsage, 0, keyUsage.length);
563     }
564
565     /**
566      * Returns the criterion for the {@literal KeyUsage} extension.
567      *
568      * @return the boolean array in the format as returned by
569      *         {@link X509Certificate#getKeyUsage()}, or {@code null} if the key
570      *         usage is not to be checked.
571      */
572     public boolean[] getKeyUsage() {
573         if (keyUsage == null) {
574             return null;
575         }
576         boolean[] result = new boolean[keyUsage.length];
577         System.arraycopy(keyUsage, 0, result, 0, keyUsage.length);
578         return result;
579     }
580
581     /**
582      * Sets the criterion for the {@literal ExtendedKeyUsage} extension.
583      *
584      * @param keyUsage
585      *            the set of key usage OIDs, or {@code null} to not check it.
586      * @throws IOException
587      *             if one of the OIDs is invalid.
588      */
589     public void setExtendedKeyUsage(Set<String> keyUsage)
590                              throws IOException {
591         extendedKeyUsage = null;
592         if ((keyUsage == null) || (keyUsage.size() == 0)) {
593             return;
594         }
595         HashSet key_u = new HashSet();
596         Iterator it = keyUsage.iterator();
597         while (it.hasNext()) {
598             String usage = (String) it.next();
599             checkOID(usage);
600             key_u.add(usage);
601         }
602         extendedKeyUsage = Collections.unmodifiableSet(key_u);
603     }
604
605     /**
606      * Returns the criterion for the {@literal ExtendedKeyUsage} extension.
607      *
608      * @return the set of key usage OIDs, or {@code null} if it's not to be
609      *         checked.
610      */
611     public Set<String> getExtendedKeyUsage() {
612         return extendedKeyUsage;
613     }
614
615     /**
616      * Sets the flag for the matching behavior for subject alternative names.
617      * <p>
618      * The flag indicates whether a certificate must contain all or at least one
619      * of the subject alternative names specified by {@link
620      * #setSubjectAlternativeNames} or {@link #addSubjectAlternativeName}.
621      *
622      * @param matchAllNames
623      *            {@code true} if a certificate must contain all of the
624      *            specified subject alternative names, otherwise {@code false}.
625      */
626     public void setMatchAllSubjectAltNames(boolean matchAllNames) {
627         this.matchAllNames = matchAllNames;
628     }
629
630     /**
631      * Returns the flag for the matching behavior for subject alternative names.
632      * <p>
633      * The flag indicates whether a certificate must contain all or at least one
634      * of the subject alternative names specified by {@link
635      * #setSubjectAlternativeNames} or {@link #addSubjectAlternativeName}.
636      *
637      * @return {@code true} if a certificate must contain all of the specified
638      *         subject alternative names, otherwise {@code false}.
639      */
640     public boolean getMatchAllSubjectAltNames() {
641         return matchAllNames;
642     }
643
644     /**
645      * Sets the criterion for subject alternative names.
646      * <p>
647      * the certificate must contain all or at least one of the specified subject
648      * alternative names. The behavior is specified by
649      * {@link #getMatchAllSubjectAltNames}.
650      * <p>
651      * The specified parameter {@code names} is a collection with an entry for
652      * each name to be included in the criterion. The name is specified as a
653      * {@code List}, the first entry must be an {@code Integer} specifying the
654      * name type (0-8), the second entry must be a {@code String} or a byte
655      * array specifying the name (in string or ASN.1 DER encoded form)
656      *
657      * @param names
658      *            the names collection or {@code null} to not perform this check.
659      * @throws IOException
660      *             if the decoding of a name fails.
661      */
662     public void setSubjectAlternativeNames(Collection<List<?>> names)
663                                     throws IOException {
664         subjectAltNames = null;
665         if ((names == null) || (names.size() == 0)) {
666             return;
667         }
668         Iterator it = names.iterator();
669         while (it.hasNext()) {
670             List name = (List) it.next();
671             int tag = ((Integer) name.get(0)).intValue();
672             Object value = name.get(1);
673             if (value instanceof String) {
674                 addSubjectAlternativeName(tag, (String) value);
675             } else if (value instanceof byte[]) {
676                 addSubjectAlternativeName(tag, (byte[]) value);
677             } else {
678                 throw new IOException("name neither a String nor a byte[]");
679             }
680         }
681     }
682
683     /**
684      * Adds a subject alternative name to the respective criterion.
685      *
686      * @param tag
687      *            the type of the name
688      * @param name
689      *            the name in string format.
690      * @throws IOException
691      *             if parsing the name fails.
692      */
693     public void addSubjectAlternativeName(int tag, String name)
694                                                        throws IOException {
695         GeneralName alt_name = new GeneralName(tag, name);
696         // create only if there was not any errors
697         if (subjectAltNames == null) {
698             subjectAltNames = new ArrayList[9];
699         }
700         if (subjectAltNames[tag] == null) {
701             subjectAltNames[tag] = new ArrayList();
702         }
703         subjectAltNames[tag].add(alt_name);
704     }
705
706     /**
707      * Adds a subject alternative name to the respective criterion.
708      *
709      * @param tag
710      *            the type of the name.
711      * @param name
712      *            the name in ASN.1 DER encoded form.
713      * @throws IOException
714      *             if the decoding of the name fails.
715      */
716     public void addSubjectAlternativeName(int tag, byte[] name)
717                                             throws IOException {
718         GeneralName alt_name = new GeneralName(tag, name);
719         // create only if there was not any errors
720         if (subjectAltNames == null) {
721             subjectAltNames = new ArrayList[9];
722         }
723         if (subjectAltNames[tag] == null) {
724             subjectAltNames[tag] = new ArrayList();
725         }
726         subjectAltNames[tag].add(alt_name);
727     }
728
729     /**
730      * Returns the criterion for subject alternative names.
731      * <p>
732      * the certificate must contain all or at least one of the specified subject
733      * alternative names. The behavior is specified by
734      * {@link #getMatchAllSubjectAltNames}.
735      * <p>
736      * The subject alternative names is a collection with an entry for each name
737      * included in the criterion. The name is specified as a {@code List}, the
738      * first entry is an {@code Integer} specifying the name type (0-8), the
739      * second entry is byte array specifying the name in ASN.1 DER encoded form)
740      *
741      * @return the names collection or {@code null} if none specified.
742      */
743     public Collection<List<?>> getSubjectAlternativeNames() {
744         if (subjectAltNames == null) {
745             return null;
746         }
747         ArrayList result = new ArrayList();
748         for (int tag=0; tag<9; tag++) {
749             if (subjectAltNames[tag] != null) {
750                 for (int name=0; name<subjectAltNames[tag].size(); name++) {
751                     Object neim = subjectAltNames[tag].get(name);
752                     if (neim instanceof byte[]) {
753                         byte[] arr_neim = (byte[]) neim;
754                         neim = new byte[arr_neim.length];
755                         System.arraycopy(arr_neim, 0, neim, 0, arr_neim.length);
756                     }
757                     List list = new ArrayList(2);
758                     list.add(Integer.valueOf(tag)); // android-changed
759                     list.add(neim);
760                     result.add(list);
761                 }
762             }
763         }
764         return result;
765     }
766
767     /**
768      * Sets the criterion for the name constraints.
769      * <p>
770      * The certificate must constraint subject and subject alternative names
771      * that match the specified name constraints.
772      * <p>
773      * The name constraints in ASN.1:
774      *
775      * <pre>
776      * NameConstraints ::= SEQUENCE {
777      *        permittedSubtrees       [0]     GeneralSubtrees OPTIONAL,
778      *        excludedSubtrees        [1]     GeneralSubtrees OPTIONAL }
779      *
780      * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
781      *
782      * GeneralSubtree ::= SEQUENCE {
783      *        base                    GeneralName,
784      *        minimum         [0]     BaseDistance DEFAULT 0,
785      *        maximum         [1]     BaseDistance OPTIONAL }
786      *
787      * BaseDistance ::= INTEGER (0..MAX)
788      *
789      * GeneralName ::= CHOICE {
790      *        otherName                       [0]     OtherName,
791      *        rfc822Name                      [1]     IA5String,
792      *        dNSName                         [2]     IA5String,
793      *        x400Address                     [3]     ORAddress,
794      *        directoryName                   [4]     Name,
795      *        ediPartyName                    [5]     EDIPartyName,
796      *        uniformResourceIdentifier       [6]     IA5String,
797      *        iPAddress                       [7]     OCTET STRING,
798      *        registeredID                    [8]     OBJECT IDENTIFIER}
799      *
800      * </pre>
801      *
802      * @param bytes
803      *            the name constraints in ASN.1 DER encoded format, or null to
804      *            not check any constraints.
805      * @throws IOException
806      *             if decoding the name constraints fail.
807      */
808     public void setNameConstraints(byte[] bytes) throws IOException {
809         this.nameConstraints = (bytes == null)
810             ? null
811             : (NameConstraints) NameConstraints.ASN1.decode(bytes);
812     }
813
814     /**
815      * Returns the criterion for the name constraints.
816      *
817      * @return the name constraints or {@code null} if none specified.
818      * @see #setNameConstraints
819      */
820     public byte[] getNameConstraints() {
821         return (nameConstraints == null)
822             ? null
823             : nameConstraints.getEncoded();
824     }
825
826     /**
827      * Sets the criterion for the basic constraints extension.
828      * <p>
829      * A value greater than or equal to zero indicates that a certificate must
830      * include a basic constraints extension with a path length of a least that
831      * value. A value of {@code -2} indicates that only end-entity certificates
832      * are accepted. A value of {@code -1} indicates that no check is done.
833      *
834      * @param pathLen
835      *            the value specifying the criterion.
836      * @throws IllegalArgumentException
837      *             if {@code pathLen} is less than {@code -2}.
838      */
839     public void setBasicConstraints(int pathLen) {
840         if (pathLen < -2) {
841             throw new IllegalArgumentException("pathLen < -2");
842         }
843         this.pathLen = pathLen;
844     }
845
846     /**
847      * Returns the criterion for the basic constraints extension.
848      * <p>
849      * A value greater than or equal to zero indicates that a certificate must
850      * include a basic constraints extension with a path length of a least that
851      * value. A value of {@code -2} indicates that only end-entity certificates
852      * are accepted. A value of {@code -1} indicates that no check is done.
853      *
854      * @return the value of the criterion.
855      */
856     public int getBasicConstraints() {
857         return pathLen;
858     }
859
860     /**
861      * Sets the criterion for the policy constraint.
862      * <p>
863      * The certificate must have at least one of the specified certificate
864      * policy extensions. For an empty set the certificate must have at least
865      * some policies in its policy extension.
866      *
867      * @param policies
868      *            the certificate policy OIDs, an empty set, or {@code null} to
869      *            not perform this check.
870      * @throws IOException
871      *             if parsing the specified OIDs fails.
872      */
873     public void setPolicy(Set<String> policies) throws IOException {
874         if (policies == null) {
875             this.policies = null;
876             return;
877         }
878         HashSet pols = new HashSet(policies.size());
879         Iterator it = policies.iterator();
880         while (it.hasNext()) {
881             String certPolicyId = (String) it.next();
882             checkOID(certPolicyId);
883             pols.add(certPolicyId);
884         }
885         this.policies = Collections.unmodifiableSet(pols);
886     }
887
888     /**
889      * Returns the criterion for the policy constraint.
890      * <p>
891      * The certificate must have at least one of the certificate policy
892      * extensions. For an empty set the certificate must have at least some
893      * policies in its policy extension.
894      *
895      * @return the certificate policy OIDs, an empty set, or {@code null} if not
896      *         to be checked.
897      */
898     public Set<String> getPolicy() {
899         return policies;
900     }
901
902     /**
903      * Sets the criterion for the pathToNames constraint.
904      * <p>
905      * This allows to specify the complete set of names, a certificate's name
906      * constraints must permit.
907      * <p>
908      * The specified parameter {@code names} is a collection with an entry for
909      * each name to be included in the criterion. The name is specified as a
910      * {@code List}, the first entry must be an {@code Integer} specifying the
911      * name type (0-8), the second entry must be a {@code String} or a byte
912      * array specifying the name (in string or ASN.1 DER encoded form)
913      *
914      * @param names
915      *            the names collection or {@code null} to not perform this
916      *            check.
917      * @throws IOException
918      *             if decoding fails.
919      */
920     public void setPathToNames(Collection<List<?>> names)
921                                                         throws IOException {
922         pathToNames = null;
923         if ((names == null) || (names.size() == 0)) {
924             return;
925         }
926         Iterator it = names.iterator();
927         while (it.hasNext()) {
928             List name = (List) it.next();
929             int tag = ((Integer) name.get(0)).intValue();
930             Object value = name.get(1);
931             if (value instanceof String) {
932                 addPathToName(tag, (String) value);
933             } else if (value instanceof byte[]) {
934                 addPathToName(tag, (byte[]) value);
935             } else {
936                 throw new IOException("name neither a String nor a byte[]");
937             }
938         }
939     }
940
941     /**
942      * Adds a {@literal "pathToName"} to the respective criterion.
943      *
944      * @param type
945      *            the type of the name.
946      * @param name
947      *            the name in string format.
948      * @throws IOException
949      *             if parsing fails.
950      * @see #setPathToNames
951      */
952     public void addPathToName(int type, String name) throws IOException {
953         GeneralName path_name = new GeneralName(type, name);
954         // create only if there was not any errors
955         if (pathToNames == null) {
956             pathToNames = new ArrayList();
957         }
958         pathToNames.add(path_name);
959     }
960
961     /**
962      * Adds a {@literal "pathToName"} to the respective criterion.
963      *
964      * @param type
965      *            the type of the name
966      * @param name
967      *            the name in ASN.1 DER encoded form.
968      * @throws IOException
969      *             if decoding fails.
970      * @see #setPathToNames
971      */
972     public void addPathToName(int type, byte[] name) throws IOException {
973         GeneralName path_name= new GeneralName(type, name);
974         // create only if there was not any errors
975         if (pathToNames == null) {
976             pathToNames = new ArrayList();
977         }
978         pathToNames.add(path_name);
979     }
980
981     /**
982      * Returns the criterion for the pathToNames constraint.
983      * <p>
984      * The constraint is a collection with an entry for each name to be included
985      * in the criterion. The name is specified as a {@code List}, the first
986      * entry is an {@code Integer} specifying the name type (0-8), the second
987      * entry is a byte array specifying the name in ASN.1 DER encoded form.
988      *
989      * @return the pathToNames constraint or {@code null} if none specified.
990      */
991     public Collection<List<?>> getPathToNames() {
992         if (pathToNames == null) {
993             return null;
994         }
995         ArrayList result = new ArrayList();
996         Iterator it = pathToNames.iterator();
997         while (it.hasNext()) {
998             GeneralName name = (GeneralName) it.next();
999             result.add(name.getAsList());
1000         }
1001         return result;
1002     }
1003
1004     /**
1005      * Returns a string representation of this {@code X509CertSelector}
1006      * instance.
1007      *
1008      * @return a string representation of this {@code X509CertSelector}
1009      *         instance.
1010      */
1011     public String toString() {
1012         // For convenient reading of the string representation
1013         // all of the fields named according to the rfc 3280
1014         // (http://www.ietf.org/rfc/rfc3280.txt).
1015
1016         StringBuilder result = new StringBuilder();
1017         result.append("X509CertSelector: \n[");
1018         if (this.certificateEquals != null) {
1019             result.append("\n  certificateEquals: " + certificateEquals);
1020         }
1021         if (this.serialNumber != null) {
1022             //FIXME: needs DRL's BigInteger.toString implementation
1023             //result.append("\n  serialNumber: " + serialNumber);
1024         }
1025         if (this.issuer != null) {
1026             result.append("\n  issuer: " + issuer);
1027         }
1028         if (this.subject != null) {
1029             result.append("\n  subject: " + subject);
1030         }
1031         if (this.subjectKeyIdentifier != null) {
1032             result.append("\n  subjectKeyIdentifier: "
1033                     + getBytesAsString(subjectKeyIdentifier));
1034         }
1035         if (this.authorityKeyIdentifier != null) {
1036             result.append("\n  authorityKeyIdentifier: "
1037                     + getBytesAsString(authorityKeyIdentifier));
1038         }
1039         if (this.certificateValid != null) {
1040             result.append("\n  certificateValid: " + certificateValid);
1041         }
1042         if (this.subjectPublicKeyAlgID != null) {
1043             result.append("\n  subjectPublicKeyAlgID: "
1044                     + subjectPublicKeyAlgID);
1045         }
1046         if (this.privateKeyValid != null) {
1047             result.append("\n  privateKeyValid: " + privateKeyValid);
1048         }
1049         if (this.subjectPublicKey != null) {
1050             result.append("\n  subjectPublicKey: "
1051                     + getBytesAsString(subjectPublicKey));
1052         }
1053         if (this.keyUsage != null) {
1054             result.append("\n  keyUsage: \n  [");
1055             String[] kuNames = new String[] {
1056                 "digitalSignature", "nonRepudiation", "keyEncipherment",
1057                 "dataEncipherment", "keyAgreement", "keyCertSign", "cRLSign",
1058                 "encipherOnly", "decipherOnly"
1059             };
1060             for (int i=0; i<9; i++) {
1061                 if (keyUsage[i]) {
1062                     result.append("\n    " + kuNames[i]);
1063                 }
1064             }
1065             result.append("\n  ]");
1066         }
1067         if (this.extendedKeyUsage != null) {
1068             result.append("\n  extendedKeyUsage: "
1069                     + extendedKeyUsage.toString());
1070         }
1071         result.append("\n  matchAllNames: " + matchAllNames);
1072         result.append("\n  pathLen: " + pathLen);
1073         if (this.subjectAltNames != null) {
1074             result.append("\n  subjectAltNames:  \n  [");
1075             for (int i=0; i<9; i++) {
1076                 List names = this.subjectAltNames[i];
1077                 if (names != null) {
1078                     int size = names.size();
1079                     for (int j=0; j<size; j++) {
1080                         result.append("\n    "
1081                             + ((GeneralName)names.get(j)).toString());
1082                     }
1083                 }
1084             }
1085             result.append("\n  ]");
1086         }
1087         if (this.nameConstraints != null) {
1088         }
1089         if (this.policies != null) {
1090             result.append("\n  policies: " + policies.toString());
1091         }
1092         if (this.pathToNames != null) {
1093             result.append("\n  pathToNames:  \n  [");
1094             int size = pathToNames.size();
1095             for (int i = 0; i < size; i++) {
1096                 result.append("\n    "
1097                     + ((GeneralName)pathToNames.get(i)).toString());
1098             }
1099         }
1100         result.append("\n]");
1101         return result.toString();
1102     }
1103
1104     private String getBytesAsString(byte[] data) {
1105         String result = "";
1106         for (int i=0; i<data.length; i++) {
1107             String tail = Integer.toHexString(0x00ff & data[i]);
1108             if (tail.length() == 1) {
1109                 tail = "0" + tail;
1110             }
1111             result += tail + " ";
1112         }
1113         return result;
1114     }
1115
1116     private byte[] getExtensionValue(X509Certificate cert, String oid) {
1117         try {
1118             byte[] bytes = cert.getExtensionValue(oid);
1119             if (bytes == null) {
1120                 return null;
1121             }
1122             return (byte[]) ASN1OctetString.getInstance().decode(bytes);
1123         } catch (IOException e) {
1124             return null;
1125         }
1126     }
1127
1128     /**
1129      * Returns whether the specified certificate matches all the criteria
1130      * collected in this instance.
1131      *
1132      * @param certificate
1133      *            the certificate to check.
1134      * @return {@code true} if the certificate matches all the criteria,
1135      *         otherwise {@code false}.
1136      */
1137     public boolean match(Certificate certificate) {
1138         if (! (certificate instanceof X509Certificate)) {
1139             return false;
1140         }
1141
1142         X509Certificate cert = (X509Certificate) certificate;
1143         if ((certificateEquals != null) &&
1144             !certificateEquals.equals(cert)) {
1145             return false;
1146         }
1147         if ((serialNumber != null) &&
1148             !serialNumber.equals(cert.getSerialNumber())) {
1149             return false;
1150         }
1151         if ((issuer != null) &&
1152             !issuer.equals(cert.getIssuerX500Principal())) {
1153             return false;
1154         }
1155         if ((subject != null) &&
1156             !subject.equals(cert.getSubjectX500Principal())) {
1157             return false;
1158         }
1159         if ((subjectKeyIdentifier != null) &&
1160             !Arrays.equals(subjectKeyIdentifier,
1161             // Here and later all of the extension OIDs
1162             // are taken from rfc 3280 (http://www.ietf.org/rfc/rfc3280.txt)
1163                            getExtensionValue(cert, "2.5.29.14"))) {
1164             return false;
1165         }
1166         if ((authorityKeyIdentifier != null) &&
1167             !Arrays.equals(authorityKeyIdentifier,
1168                            getExtensionValue(cert, "2.5.29.35"))) {
1169             return false;
1170         }
1171         if (certificateValid != null) {
1172             try {
1173                 cert.checkValidity(certificateValid);
1174             } catch(CertificateExpiredException e) {
1175                 return false;
1176             } catch(CertificateNotYetValidException e) {
1177                 return false;
1178             }
1179         }
1180         if (privateKeyValid != null) {
1181             try {
1182                 byte[] bytes = getExtensionValue(cert, "2.5.29.16");
1183                 if (bytes == null) {
1184                     return false;
1185                 }
1186                 PrivateKeyUsagePeriod pkup = (PrivateKeyUsagePeriod)
1187                                     PrivateKeyUsagePeriod.ASN1.decode(bytes);
1188                 Date notBefore = pkup.getNotBefore();
1189                 Date notAfter = pkup.getNotAfter();
1190                 if ((notBefore == null) && (notAfter == null)) {
1191                     return false;
1192                 }
1193                 if ((notBefore != null)
1194                     && notBefore.compareTo(privateKeyValid) > 0) {
1195                     return false;
1196                 }
1197                 if ((notAfter != null)
1198                     && notAfter.compareTo(privateKeyValid) < 0) {
1199                     return false;
1200                 }
1201             } catch (IOException e) {
1202                 return false;
1203             }
1204         }
1205         if (subjectPublicKeyAlgID  != null) {
1206             try {
1207                 byte[] encoding = cert.getPublicKey().getEncoded();
1208                 AlgorithmIdentifier ai = ((SubjectPublicKeyInfo)
1209                         SubjectPublicKeyInfo.ASN1.decode(encoding))
1210                         .getAlgorithmIdentifier();
1211                 if (!subjectPublicKeyAlgID.equals(ai.getAlgorithm())) {
1212                     return false;
1213                 }
1214             } catch (IOException e) {
1215                 e.printStackTrace();
1216                 return false;
1217             }
1218         }
1219         if (subjectPublicKey != null) {
1220             if (!Arrays.equals(subjectPublicKey,
1221                                cert.getPublicKey().getEncoded())) {
1222                 return false;
1223             }
1224         }
1225         if (keyUsage != null) {
1226             boolean[] ku = cert.getKeyUsage();
1227             if (ku != null) {
1228                 int i = 0;
1229                 int min_length = (ku.length < keyUsage.length) ? ku.length
1230                         : keyUsage.length;
1231                 for (; i < min_length; i++) {
1232                     if (keyUsage[i] && !ku[i]) {
1233                         // the specified keyUsage allows,
1234                         // but certificate does not.
1235                         return false;
1236                     }
1237                 }
1238                 for (; i<keyUsage.length; i++) {
1239                     if (keyUsage[i]) {
1240                         return false;
1241                     }
1242                 }
1243             }
1244         }
1245         if (extendedKeyUsage != null) {
1246             try {
1247                 List keyUsage = cert.getExtendedKeyUsage();
1248                 if (keyUsage != null) {
1249                     if (!keyUsage.containsAll(extendedKeyUsage)) {
1250                         return false;
1251                     }
1252                 }
1253             } catch (CertificateParsingException e) {
1254                 return false;
1255             }
1256         }
1257         if (pathLen != -1) {
1258             int p_len = cert.getBasicConstraints();
1259             if ((pathLen < 0) && (p_len >= 0)) {
1260                 // need end-entity but got CA
1261                 return false;
1262             }
1263             if ((pathLen > 0) && (pathLen > p_len)) {
1264                 // allowed _pathLen is small
1265                 return false;
1266             }
1267         }
1268         if (subjectAltNames != null) {
1269             PASSED:
1270             try {
1271                 byte[] bytes = getExtensionValue(cert, "2.5.29.17");
1272                 if (bytes == null) {
1273                     return false;
1274                 }
1275                 List sans = ((GeneralNames) GeneralNames.ASN1.decode(bytes))
1276                             .getNames();
1277                 if ((sans == null) || (sans.size() == 0)) {
1278                     return false;
1279                 }
1280                 boolean[][] map = new boolean[9][];
1281                 // initialize the check map
1282                 for (int i=0; i<9; i++) {
1283                     map[i] = (subjectAltNames[i] == null)
1284                                 ? new boolean[0]
1285                                 : new boolean[subjectAltNames[i].size()];
1286                 }
1287                 Iterator it = sans.iterator();
1288                 while (it.hasNext()) {
1289                     GeneralName name = (GeneralName) it.next();
1290                     int tag = name.getTag();
1291                     for (int i=0; i<map[tag].length; i++) {
1292                         if (((GeneralName) subjectAltNames[tag].get(i))
1293                                                             .equals(name)) {
1294                             if (!matchAllNames) {
1295                                 break PASSED;
1296                             }
1297                             map[tag][i] = true;
1298                         }
1299                     }
1300                 }
1301                 if (!matchAllNames) {
1302                     // there was not any match
1303                     return false;
1304                 }
1305                 // else check the map
1306                 for (int tag=0; tag<9; tag++) {
1307                     for (int name=0; name<map[tag].length; name++) {
1308                         if (!map[tag][name]) {
1309                             return false;
1310                         }
1311                     }
1312                 }
1313             } catch (IOException e) {
1314                 e.printStackTrace();
1315                 return false;
1316             }
1317         }
1318         if (nameConstraints != null) {
1319             if (!nameConstraints.isAcceptable(cert)) {
1320                 return false;
1321             }
1322         }
1323         if (policies != null) {
1324             byte[] bytes = getExtensionValue(cert, "2.5.29.32");
1325             if (bytes == null) {
1326                 return false;
1327             }
1328             if (policies.size() == 0) {
1329                 // if certificate has such extension than it has at least
1330                 // one policy in it.
1331                 return true;
1332             }
1333             PASSED:
1334             try {
1335                 List policyInformations = ((CertificatePolicies)
1336                         CertificatePolicies.ASN1.decode(bytes))
1337                         .getPolicyInformations();
1338                 Iterator it = policyInformations.iterator();
1339                 while (it.hasNext()) {
1340                     if (policies.contains(((PolicyInformation) it.next())
1341                                           .getPolicyIdentifier())) {
1342                         break PASSED;
1343                     }
1344                 }
1345                 return false;
1346             } catch (IOException e) {
1347                 // the extension is invalid
1348                 return false;
1349             }
1350         }
1351         if (pathToNames != null) {
1352             byte[] bytes = getExtensionValue(cert, "2.5.29.30");
1353             if (bytes != null) {
1354                 NameConstraints nameConstraints;
1355                 try {
1356                     nameConstraints =
1357                         (NameConstraints) NameConstraints.ASN1.decode(bytes);
1358                 } catch (IOException e) {
1359                     // the extension is invalid;
1360                     return false;
1361                 }
1362                 if (!nameConstraints.isAcceptable(pathToNames)) {
1363                     return false;
1364                 }
1365             }
1366         }
1367         return true;
1368     }
1369
1370     /**
1371      * Clones this {@code X509CertSelector} instance.
1372      *
1373      * @return the cloned instance.
1374      */
1375     public Object clone() {
1376         X509CertSelector result;
1377
1378         try {
1379             result = (X509CertSelector) super.clone();
1380         } catch (CloneNotSupportedException e) {
1381             return null;
1382         }
1383
1384         if (this.subjectKeyIdentifier != null) {
1385             result.subjectKeyIdentifier =
1386                 new byte[this.subjectKeyIdentifier.length];
1387             System.arraycopy(this.subjectKeyIdentifier, 0,
1388                     result.subjectKeyIdentifier, 0,
1389                     this.subjectKeyIdentifier.length);
1390         }
1391         if (this.authorityKeyIdentifier != null) {
1392             result.authorityKeyIdentifier =
1393                 new byte[this.authorityKeyIdentifier.length];
1394             System.arraycopy(this.authorityKeyIdentifier, 0,
1395                     result.authorityKeyIdentifier, 0,
1396                     this.authorityKeyIdentifier.length);
1397         }
1398         if (this.subjectPublicKey != null) {
1399             result.subjectPublicKey = new byte[this.subjectPublicKey.length];
1400             System.arraycopy(this.subjectPublicKey, 0, result.subjectPublicKey,
1401                     0, this.subjectPublicKey.length);
1402         }
1403         if (this.keyUsage != null) {
1404             result.keyUsage = new boolean[this.keyUsage.length];
1405             System.arraycopy(this.keyUsage, 0, result.keyUsage, 0,
1406                     this.keyUsage.length);
1407         }
1408         result.extendedKeyUsage = (this.extendedKeyUsage == null)
1409             ? null
1410             : new HashSet(this.extendedKeyUsage);
1411         if (this.subjectAltNames != null) {
1412             result.subjectAltNames = new ArrayList[9];
1413             for (int i=0; i<9; i++) {
1414                 if (this.subjectAltNames[i] != null) {
1415                     result.subjectAltNames[i] =
1416                         new ArrayList(this.subjectAltNames[i]);
1417                 }
1418             }
1419         }
1420         result.policies = (this.policies == null)
1421             ? null
1422             : new HashSet(this.policies);
1423         result.pathToNames = (this.pathToNames == null)
1424             ? null
1425             : new ArrayList(this.pathToNames);
1426         return result;
1427     }
1428 }