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