Logo Search packages:      
Sourcecode: bouncycastle version File versions

X509CertSelector.java

package java.security.cert;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.PublicKey;
import java.text.SimpleDateFormat;
import java.util.*;

import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERGeneralizedTime;
import org.bouncycastle.asn1.DERInputStream;
import org.bouncycastle.asn1.DERObject;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.DEROutputStream;
import org.bouncycastle.asn1.util.ASN1Dump;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.asn1.x509.X509Name;

import org.bouncycastle.jce.PrincipalUtil;

/**
 * A <code>CertSelector</code> that selects <code>X509Certificates that match all
 * specified criteria. This class is particularly useful when
 * selecting certificates from a CertStore to build a PKIX-compliant
 * certification path.<br />
 * <br />
 * When first constructed, an <code>X509CertSelector</code> has no criteria enabled
 * and each of the get methods return a default value (<code>null</code>, or -1 for
 * the {@link #getBasicConstraints} method). Therefore, the {@link #match} method would
 * return true for any <code>X509Certificate</code>. Typically, several criteria
 * are enabled (by calling {@link #setIssuer} or {@link #setKeyUsage}, for instance) and
 * then the <code>X509CertSelector</code> is passed to {@link CertStore#getCertificates} or
 * some similar method.<br />
 * <br />
 * Several criteria can be enabled (by calling {@link #setIssuer} and
 * {@link #setSerialNumber}, for example) such that the match method usually
 * uniquely matches a single <code>X509Certificate</code>. We say usually, since it
 * is possible for two issuing CAs to have the same distinguished name
 * and each issue a certificate with the same serial number. Other
 * unique combinations include the issuer, subject,
 * subjectKeyIdentifier and/or the subjectPublicKey criteria.<br />
 * <br />
 * Please refer to RFC 2459 for definitions of the X.509 certificate
 * extensions mentioned below.<br />
 * <br />
 * <b>Concurrent Access</b><br />
 * <br />
 * Unless otherwise specified, the methods defined in this class are
 * not thread-safe. Multiple threads that need to access a single
 * object concurrently should synchronize amongst themselves and
 * provide the necessary locking. Multiple threads each manipulating
 * separate objects need not synchronize.<br />
 * <br />
 * <b>TODO: implement name constraints</b>
 * <b>TODO: implement match check for path to names</b><br />
 * <br />
 * Uses {@link org.bouncycastle.asn1.DERInputStream DERInputStream},
 * {@link org.bouncycastle.asn1.ASN1Sequence ASN1Sequence},
 * {@link org.bouncycastle.asn1.DERObjectIdentifier DERObjectIdentifier},
 * {@link org.bouncycastle.asn1.DEROutputStream DEROutputStream},
 * {@link org.bouncycastle.asn1.DERObject DERObject},
 * {@link org.bouncycastle.asn1.OIDTokenizer OIDTokenizer},
 * {@link org.bouncycastle.asn1.x509.X509Name X509Name},
 * {@link org.bouncycastle.asn1.x509.X509Extensions X509Extensions},
 * {@link org.bouncycastle.asn1.x509.ExtendedKeyUsage ExtendedKeyUsage},
 * {@link org.bouncycastle.asn1.x509.KeyPurposeId KeyPurposeId},
 * {@link org.bouncycastle.asn1.x509.SubjectPublicKeyInfo SubjectPublicKeyInfo},
 * {@link org.bouncycastle.asn1.x509.AlgorithmIdentifier AlgorithmIdentifier} and
 * {@link org.bouncycastle.asn1.util.ASN1Dump#_dumpAsString _dumpAsString}
 **/
00079 public class X509CertSelector implements CertSelector
{
    private static final Hashtable keyPurposeIdMap = new Hashtable();
    static {
    keyPurposeIdMap.put(KeyPurposeId.id_kp_serverAuth.getId(), KeyPurposeId.id_kp_serverAuth);
    keyPurposeIdMap.put(KeyPurposeId.id_kp_clientAuth.getId(), KeyPurposeId.id_kp_clientAuth);
    keyPurposeIdMap.put(KeyPurposeId.id_kp_codeSigning.getId(), KeyPurposeId.id_kp_codeSigning);
    keyPurposeIdMap.put(KeyPurposeId.id_kp_emailProtection.getId(), KeyPurposeId.id_kp_emailProtection);
    keyPurposeIdMap.put(KeyPurposeId.id_kp_ipsecEndSystem.getId(), KeyPurposeId.id_kp_ipsecEndSystem);
    keyPurposeIdMap.put(KeyPurposeId.id_kp_ipsecTunnel.getId(), KeyPurposeId.id_kp_ipsecTunnel);
    keyPurposeIdMap.put(KeyPurposeId.id_kp_ipsecUser.getId(), KeyPurposeId.id_kp_ipsecUser);
    keyPurposeIdMap.put(KeyPurposeId. id_kp_timeStamping.getId(), KeyPurposeId. id_kp_timeStamping);
    }

    private X509Certificate x509Cert = null;
    private BigInteger serialNumber = null;
    private Object issuerDN = null;
    private X509Name issuerDNX509 = null;
    private Object subjectDN = null;
    private X509Name subjectDNX509 = null;
    private byte[] subjectKeyID = null;
    private byte[] authorityKeyID = null;
    private Date certValid = null;
    private Date privateKeyValid = null;
    private DERObjectIdentifier subjectKeyAlgID = null;
    private PublicKey subjectPublicKey = null;
    private byte[] subjectPublicKeyByte = null;
    private boolean[] keyUsage = null;
    private Set keyPurposeSet = null;
    private boolean matchAllSubjectAltNames = true;
    private Set subjectAltNames = null;
    private Set subjectAltNamesByte = null;
    private int minMaxPathLen = -1;
    private Set policy = null;
    private Set policyOID = null;
    private Set pathToNames = null;
    private Set pathToNamesByte = null;

    /**
     * Creates an <code>X509CertSelector</code>. Initially, no criteria are set
     * so any <code>X509Certificate</code> will match.
     **/
00121     public X509CertSelector() {}

        /**
     * Sets the certificateEquals criterion. The specified
     * <code>X509Certificate</code> must be equal to the <code>X509Certificate</code> passed
     * to the match method. If <code>null</code>, then this check is not
     * applied.<br />
     * <br />
     * This method is particularly useful when it is necessary to
     * match a single certificate. Although other criteria can be
     * specified in conjunction with the certificateEquals
     * criterion, it is usually not practical or necessary.
     *
     * @param cert the X509Certificate to match (or <code>null</code>)
     *
     * @see #getCertificate()
     **/
00138     public void setCertificate(X509Certificate cert)
    {
        x509Cert = cert;
    }

    /**
     * Sets the serialNumber criterion. The specified serial
     * number must match the certificate serial number in the
     * <code>X509Certificate</code>. If <code>null</code>, any certificate serial number
     * will do.
     * 
     * @param serial the certificate serial number to match (or <code>null</code>)
     *
     * @see #getSerialNumber()
     **/
00153     public void setSerialNumber(BigInteger serial)
    {
        serialNumber = serial;
    }

    /**
     * Sets the issuer criterion. The specified distinguished name
     * must match the issuer distinguished name in the
     * <code>X509Certificate</code>. If <code>null</code>, any
     * issuer distinguished name will do.<br />
     * <br />
     * If <code>issuerDN</code> is not <code>null</code>, it
     * should contain a distinguished name, in RFC 2253 format.<br />
     * <br />
     * Uses {@link org.bouncycastle.asn1.x509.X509Name X509Name}
     * for parsing the issuerDN.
     *
     * @param issuerDN  a distinguished name in RFC 2253 format (or <code>null</code>)
     *
     * @exception IOException  if a parsing error occurs (incorrect form for DN)
     **/
00174     public void setIssuer( String issuerDN )
        throws IOException
    {
        if (issuerDN == null)
        {
            this.issuerDN = null;
            this.issuerDNX509 = null;
        }
        else
        {
            X509Name nameX509;
            try {
            nameX509 = new X509Name(issuerDN);
            } catch ( IllegalArgumentException ex ) {
            throw new IOException(ex.getMessage());
            }
            this.issuerDNX509 = nameX509;
            this.issuerDN = issuerDN;
        }
    }

    /**
     * Sets the issuer criterion. The specified distinguished name
     * must match the issuer distinguished name in the
     * <code>X509Certificate</code>. If null is specified, the issuer criterion
     * is disabled and any issuer distinguished name will do.<br />
     * <br />
     * If <code>issuerDN</code> is not <code>null</code>, it should contain a single DER
     * encoded distinguished name, as defined in X.501. The ASN.1
     * notation for this structure is as follows.<br />
     * <br /> <pre>
     *   Name ::= CHOICE {
     *     RDNSequence }
     *
     *   RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
     *
     *   RelativeDistinguishedName ::=
     *     SET SIZE (1 .. MAX) OF AttributeTypeAndValue
     *
     *   AttributeTypeAndValue ::= SEQUENCE {
     *     type     AttributeType,
     *     value    AttributeValue }
     *
     *   AttributeType ::= OBJECT IDENTIFIER
     *
     *   AttributeValue ::= ANY DEFINED BY AttributeType
     *   ....
     *   DirectoryString ::= CHOICE {
     *     teletexString           TeletexString (SIZE (1..MAX)),
     *     printableString         PrintableString (SIZE (1..MAX)),
     *     universalString         UniversalString (SIZE (1..MAX)),
     *     utf8String              UTF8String (SIZE (1.. MAX)),
     *     bmpString               BMPString (SIZE (1..MAX)) }
     * </pre><br />
     * <br />
     * Note that the byte array specified here is cloned to
     * protect against subsequent modifications.<br />
     * <br />
     * Uses {@link org.bouncycastle.asn1.DERInputStream DERInputStream},
     * {@link org.bouncycastle.asn1.DERObject DERObject},
     * {@link org.bouncycastle.asn1.ASN1Sequence ASN1Sequence},
     * {@link org.bouncycastle.asn1.x509.X509Name X509Name}
     *
     * @param issuerDN - a byte array containing the distinguished
     * name in ASN.1 DER encoded form (or <code>null</code>)
     *
     * @exception IOException if an encoding error occurs
     * (incorrect form for DN)
     **/
00243     public void setIssuer(byte[] issuerDN)
    throws IOException
    {
        if (issuerDN == null)
        {
            this.issuerDN = null;
            this.issuerDNX509 = null;
        }
        else
        {
            ByteArrayInputStream inStream = new ByteArrayInputStream(issuerDN);
            DERInputStream derInStream = new DERInputStream(inStream);
            DERObject obj = derInStream.readObject();
            if ( obj instanceof ASN1Sequence )
            {
            this.issuerDNX509 = new X509Name((ASN1Sequence)obj);
            }
            else
            {
            throw new IOException("parsing error");
            }
            this.issuerDN = (byte[])issuerDN.clone();
        }
    }

    /**
     * Sets the subject criterion. The specified distinguished
     * name must match the subject distinguished name in the
     * <code>X509Certificate</code>. If null, any subject distinguished name
     * will do.<br />
     * <br />
     * If <code>subjectDN</code> is not <code>null</code>, it
     * should contain a distinguished name, in RFC 2253 format.<br />
     * <br />
     * Uses {@link org.bouncycastle.asn1.x509.X509Name X509Name}
     * for parsing the subjectDN.
     *
     * @param subjectDN a distinguished name in RFC 2253 format (or <code>null</code>)
     *
     * @exception IOException if a parsing error occurs (incorrect form for DN)
     **/
00284     public void setSubject(String subjectDN)
        throws IOException
    {
        if (subjectDN == null)
        {
            this.subjectDN = null;
            this.subjectDNX509 = null;
        }
        else
        {
            X509Name nameX509;
            try
            {
                nameX509 = new X509Name(subjectDN);
            }
            catch (IllegalArgumentException ex)
            {
                throw new IOException(ex.getMessage());
            }

            this.subjectDNX509 = nameX509;
            this.subjectDN = subjectDN;
        }
    }
    
    /**
     * Sets the subject criterion. The specified distinguished
     * name must match the subject distinguished name in the
     * <code>X509Certificate</code>. If null, any subject distinguished name
     * will do.<br />
     * <br />
     * If <code>subjectDN</code> is not <code>null</code>, it should contain a single DER
     * encoded distinguished name, as defined in X.501. For the
     * ASN.1 notation for this structure, see 
     * {@link #setIssuer(byte []) setIssuer(byte [] issuerDN)}.<br />
     * <br />
     * Uses {@link org.bouncycastle.asn1.DERInputStream DERInputStream},
     * {@link org.bouncycastle.asn1.DERObject DERObject},
     * {@link org.bouncycastle.asn1.ASN1Sequence ASN1Sequence},
     * {@link org.bouncycastle.asn1.x509.X509Name X509Name}
     *
     * @param subjectDN a byte array containing the distinguished
     * name in ASN.1 DER format (or <code>null</code>)
     *
     * @exception IOException if an encoding error occurs (incorrect form for DN)
     **/
00330     public void setSubject(byte[] subjectDN)
        throws IOException
    {
        if (subjectDN == null)
        {
            this.subjectDN = null;
            this.subjectDNX509 = null;
        }
        else
        {
            ByteArrayInputStream inStream = new ByteArrayInputStream(subjectDN);
            DERInputStream derInStream = new DERInputStream(inStream);
            DERObject obj = derInStream.readObject();

            if (obj instanceof ASN1Sequence)
            {
                this.subjectDNX509 = new X509Name((ASN1Sequence)obj);
            }
            else
            {
                throw new IOException("parsing error");
            }
            this.subjectDN = (byte[])subjectDN.clone();
        }
    }

    /**
     * Sets the subjectKeyIdentifier criterion. The
     * <code>X509Certificate</code> must contain a SubjectKeyIdentifier
     * extension for which the contents of the extension matches
     * the specified criterion value. If the criterion value is
     * null, no subjectKeyIdentifier check will be done.<br />
     * <br />
     * If <code>subjectKeyID</code> is not <code>null</code>, it should contain a single DER
     * encoded value corresponding to the contents of the
     * extension value (not including the object identifier,
     * criticality setting, and encapsulating OCTET STRING) for a
     * SubjectKeyIdentifier extension. The ASN.1 notation for this
     * structure follows.<br />
     * <br />
     * <pre>
     *   SubjectKeyIdentifier ::= KeyIdentifier
     *
     *   KeyIdentifier ::= OCTET STRING
     * </pre><br />
     * <br />
     * Since the format of subject key identifiers is not mandated
     * by any standard, subject key identifiers are not parsed by
     * the <code>X509CertSelector</code>. Instead, the values are compared
     * using a byte-by-byte comparison.<br />
     * <br />
     * Note that the byte array supplied here is cloned to protect
     * against subsequent modifications.
     * 
     * @param subjectKeyID - the subject key identifier (or <code>null</code>)
     *
     * @see #getSubjectKeyIdentifier()
    **/
00388     public void setSubjectKeyIdentifier(byte[] subjectKeyID)
    {
        if (subjectKeyID == null)
        {
            this.subjectKeyID = null;
        }
        else
        {
            this.subjectKeyID = (byte[])subjectKeyID.clone();
        }
    }

    /**
     * Sets the authorityKeyIdentifier criterion. The
     * <code>X509Certificate</code> must contain an AuthorityKeyIdentifier
     * extension for which the contents of the extension value
     * matches the specified criterion value. If the criterion
     * value is <code>null</code>, no authorityKeyIdentifier check will be
     * done.<br />
     * <br />
     * If <code>authorityKeyID</code> is not <code>null</code>, it should contain a single
     * DER encoded value corresponding to the contents of the
     * extension value (not including the object identifier,
     * criticality setting, and encapsulating OCTET STRING) for an
     * AuthorityKeyIdentifier extension. The ASN.1 notation for
     * this structure follows.<br />
     * <br />
     * <pre>
     *   AuthorityKeyIdentifier ::= SEQUENCE {
     *     keyIdentifier             [0] KeyIdentifier           OPTIONAL,
     *     authorityCertIssuer       [1] GeneralNames            OPTIONAL,
     *     authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL  }
     *
     *   KeyIdentifier ::= OCTET STRING
     * </pre><br />
     * <br />
     * Authority key identifiers are not parsed by the
     * <code>X509CertSelector</code>. Instead, the values are compared using a
     * byte-by-byte comparison.<br />
     * <br />
     * When the <code>keyIdentifier</code> field of <code>AuthorityKeyIdentifier</code> is
     * populated, the value is usually taken from the
     * SubjectKeyIdentifier extension in the issuer's
     * certificate. Note, however, that the result of
     * X509Certificate.getExtensionValue(<SubjectKeyIdentifier
     * Object Identifier>) on the issuer's certificate may NOT be
     * used directly as the input to
     * setAuthorityKeyIdentifier. This is because the
     * SubjectKeyIdentifier contains only a KeyIdentifier OCTET
     * STRING, and not a SEQUENCE of KeyIdentifier, GeneralNames,
     * and CertificateSerialNumber. In order to use the extension
     * value of the issuer certificate's SubjectKeyIdentifier
     * extension, it will be necessary to extract the value of the
     * embedded KeyIdentifier OCTET STRING, then DER encode this
     * OCTET STRING inside a SEQUENCE. For more details on
     * SubjectKeyIdentifier, see
     * {@link #setSubjectKeyIdentifier(byte[])  setSubjectKeyIdentifier(byte[] subjectKeyID }).<br />
     * <br />
     * Note also that the byte array supplied here is cloned to
     * protect against subsequent modifications.
     *
     * @param authorityKeyID the authority key identifier (or <code>null</code>)
     *
     * @see #getAuthorityKeyIdentifier()
     **/
00453     public void setAuthorityKeyIdentifier(byte[] authorityKeyID)
    {
        if (authorityKeyID == null)
        {
            this.authorityKeyID = null;
        }
        else
        {
            this.authorityKeyID = (byte[])authorityKeyID.clone();
        }
    }

    /**
     * Sets the certificateValid criterion. The specified date
     * must fall within the certificate validity period for the
     * X509Certificate. If <code>null</code>, no certificateValid check will be
     * done.<br />
     * <br />
     * Note that the Date supplied here is cloned to protect
     * against subsequent modifications.
     *
     * @param certValid the Date to check (or <code>null</code>)
     *
     * @see #getCertificateValid()
     **/
00478     public void setCertificateValid(Date certValid)
    {
        if (certValid == null)
        {
            this.certValid = null;
        }
        else
        {
            this.certValid = new Date(certValid.getTime());
        }
    }

    /**
     * Sets the privateKeyValid criterion. The specified date must
     * fall within the private key validity period for the
     * X509Certificate. If <code>null</code>, no privateKeyValid check will be
     * done.<br />
     * <br />
     * Note that the Date supplied here is cloned to protect
     * against subsequent modifications.
     *
     * @param privateKeyValid the Date to check (or <code>null</code>)
     *
     * @see #getPrivateKeyValid()
     **/
00503     public void setPrivateKeyValid(Date privateKeyValid)
    {
        if (privateKeyValid == null)
        {
            this.privateKeyValid = null;
        }
        else
        {
            this.privateKeyValid = new Date(privateKeyValid.getTime());
        }
    }

    /**
     * Sets the subjectPublicKeyAlgID criterion. The
     * X509Certificate must contain a subject public key with the
     * specified algorithm. If <code>null</code>, no subjectPublicKeyAlgID
     * check will be done.
     *
     * @param oid  The object identifier (OID) of the algorithm to
     * check for (or <code>null</code>). An OID is represented by a set of
     * nonnegative integers separated by periods.
     *
     * @exception IOException if the OID is invalid, such as the
     * first component being not 0, 1 or 2 or the second component
     * being greater than 39.
     *
     * @see #getSubjectPublicKeyAlgID()
     **/
00531     public void setSubjectPublicKeyAlgID(
        String oid)
        throws IOException
    {
        CertUtil.parseOID(oid);
        subjectKeyAlgID = new DERObjectIdentifier(oid);
    }

    /**
     * Sets the subjectPublicKey criterion. The X509Certificate
     * must contain the specified subject public key. If null, no
     * subjectPublicKey check will be done.
     *
     * @param key the subject public key to check for (or null)
     *
     * @see #getSubjectPublicKey()
     **/
00548     public void setSubjectPublicKey(
        PublicKey key)
    {
        if (key == null)
        {
            subjectPublicKey = null;
            subjectPublicKeyByte = null;
        }
        else
        {
            subjectPublicKey = key;
            subjectPublicKeyByte = key.getEncoded();
        }
    }

    /**
     * Sets the subjectPublicKey criterion. The <code>X509Certificate</code>
     * must contain the specified subject public key. If <code>null</code>, no
     * subjectPublicKey check will be done.<br />
     * <br />
     * Because this method allows the public key to be specified
     * as a byte array, it may be used for unknown key types.<br />
     * <br />
     * If key is not <code>null</code>, it should contain a single DER encoded
     * SubjectPublicKeyInfo structure, as defined in X.509. The
     * ASN.1 notation for this structure is as follows.<br />
     * <br />
     * <pre>
     *   SubjectPublicKeyInfo  ::=  SEQUENCE  {
     *     algorithm            AlgorithmIdentifier,
     *     subjectPublicKey     BIT STRING  }
     *
     *   AlgorithmIdentifier  ::=  SEQUENCE  {
     *     algorithm               OBJECT IDENTIFIER,
     *     parameters              ANY DEFINED BY algorithm OPTIONAL  }
     *                               -- contains a value of the type
     *                               -- registered for use with the
     *                               -- algorithm object identifier value
     * </pre><br />
     * <br />
     * Note that the byte array supplied here is cloned to protect
     * against subsequent modifications.
     *
     * @param key a byte array containing the subject public key in ASN.1 DER form (or <code>null</code>)
     *
     * @exception IOException if an encoding error occurs (incorrect form for subject public key)
     *
     * @see #getSubjectPublicKey()
     **/
00597     public void setSubjectPublicKey(
        byte[] key)
        throws IOException
    {
        if (key == null)
        {
            subjectPublicKey = null;
            subjectPublicKeyByte = null;
        }
        else
        {
            subjectPublicKey = null;
            subjectPublicKeyByte = (byte[])key.clone();
    // TODO
    // try to generyte PublicKey Object from subjectPublicKeyByte
        }
    }

    /**
     * Sets the keyUsage criterion. The X509Certificate  must
     * allow the specified keyUsage values. If null, no keyUsage
     * check will be done. Note that an X509Certificate that has
     * no keyUsage extension implicitly allows all keyUsage
     * values.<br />
     * <br />
     * Note that the boolean array supplied here is cloned to
     * protect against subsequent modifications.
     *
     * @param keyUsage a boolean array in the same format as the boolean array returned by X509Certificate.getKeyUsage(). Or <code>null</code>.
     *
     * @see #getKeyUsage()
     **/
00629     public void setKeyUsage(boolean[] keyUsage)
    {
        if (keyUsage == null)
        {
            this.keyUsage = null;
        }
        else
        {
            this.keyUsage = (boolean[])keyUsage.clone();
        }
    }

    /**
     * Sets the extendedKeyUsage criterion. The <code>X509Certificate</code>
     * must allow the specified key purposes in its extended key
     * usage extension. If <code>keyPurposeSet</code> is empty or <code>null</code>, no
     * extendedKeyUsage check will be done. Note that an
     * <code>X509Certificate</code> that has no extendedKeyUsage extension
     * implicitly allows all key purposes.<br />
     * <br />
     * Note that the Set is cloned to protect against subsequent
     * modifications.<br />
     * <br />
     * Uses {@link org.bouncycastle.asn1.x509.KeyPurposeId KeyPurposeId}
     *
     * @param keyPurposeSet a <code>Set</code> of key purpose OIDs in string
     * format (or <code>null</code>). Each OID is represented by a set of
     * nonnegative integers separated by periods.
     *
     * @exception IOException if the OID is invalid, such as the
     * first component being not 0, 1 or 2 or the second component
     * being greater than 39.
     *
     * @see #getExtendedKeyUsage()
     **/
00664     public void setExtendedKeyUsage(
        Set keyPurposeSet)
        throws IOException
    {
        if ( keyPurposeSet == null || keyPurposeSet.isEmpty() )
        {
            this.keyPurposeSet = keyPurposeSet;
        }
        else
        {
            this.keyPurposeSet = new HashSet();
            Iterator iter = keyPurposeSet.iterator();
            Object obj;
            KeyPurposeId purposeID;
            while (iter.hasNext())
            {
                obj = iter.next();
                if (obj instanceof String)
                {
                    purposeID = (KeyPurposeId)keyPurposeIdMap.get((String)obj);
                    if ( purposeID == null )
                    {
                        throw new IOException("unknown purposeID " + (String)obj);
                    }
                    this.keyPurposeSet.add( purposeID );
                }
            }
        }
    }
    
    /**
     * Enables/disables matching all of the
     * subjectAlternativeNames specified in the
     * {@link #setSubjectAlternativeNames setSubjectAlternativeNames} or
     * {@link #addSubjectAlternativeName addSubjectAlternativeName}
     * methods. If enabled, the <code>X509Certificate</code> must contain all
     * of the specified subject alternative names. If disabled,
     * the X509Certificate must contain at least one of the
     * specified subject alternative names.<br />
     * <br />
     * The matchAllNames flag is <code>true</code> by default.
     *
     * @param matchAllNames if <code>true</code>, the flag is enabled; if <code>false</code>, the flag is disabled.
     *
     * @see #getMatchAllSubjectAltNames()
     **/
00710     public void setMatchAllSubjectAltNames(boolean matchAllNames)
    {
        matchAllSubjectAltNames = matchAllNames;
    }

    /**
     * Sets the subjectAlternativeNames criterion. The
     * <code>X509Certificate</code> must contain all or at least one of the
     * specified subjectAlternativeNames, depending on the value
     * of the matchAllNames flag (see {@link #setMatchAllSubjectAltNames}).<br />
     * <br />
     * This method allows the caller to specify, with a single
     * method call, the complete set of subject alternative names
     * for the subjectAlternativeNames criterion. The specified
     * value replaces the previous value for the
     * subjectAlternativeNames criterion.<br />
     * <br />
     * The <code>names</code> parameter (if not <code>null</code>) is a <code>Collection</code> with one
     * entry for each name to be included in the subject
     * alternative name criterion. Each entry is a <code>List</code> whose
     * first entry is an <code>Integer</code> (the name type, 0-8) and whose
     * second entry is a <code>String</code> or a byte array (the name, in
     * string or ASN.1 DER encoded form, respectively). There can
     * be multiple names of the same type. If <code>null</code> is supplied as
     * the value for this argument, no subjectAlternativeNames
     * check will be performed.<br />
     * <br />
     * Each subject alternative name in the <code>Collection</code> may be
     * specified either as a <code>String</code> or as an ASN.1 encoded byte
     * array. For more details about the formats used, see
     * {@link #addSubjectAlternativeName(int, String) addSubjectAlternativeName(int type, String name)} and
     * {@link #addSubjectAlternativeName(int, byte[]) addSubjectAlternativeName(int type, byte [] name}).<br />
     * <br />
     * Note that the <code>names</code> parameter can contain duplicate names
     * (same name and name type), but they may be removed from the
     * <code>Collection</code> of names returned by the
     * {@link #getSubjectAlternativeNames} method.<br />
     * <br />
     * Note that a deep copy is performed on the Collection to
     * protect against subsequent modifications.
     *
     * @param names - a Collection of names (or null)
     *
     * @exception IOException if a parsing error occurs
     *
     * @see #getSubjectAlternativeNames()
     **/
00757     public void setSubjectAlternativeNames(
        Collection names)
        throws IOException
    {
        try
        {
            if (names == null || names.isEmpty())
            {
                subjectAltNames = null;
                subjectAltNamesByte = null;
            }
            else
            {
                subjectAltNames = new HashSet();
                subjectAltNamesByte = new HashSet();
                Iterator iter = names.iterator();
                List item;
                int type;
                Object data;
                while ( iter.hasNext() ) {
                    item = (List)iter.next();
                    type = ((Integer)item.get(0)).intValue();
                    data = item.get(1);
                    if ( data instanceof String ) {
                    addSubjectAlternativeName( type, (String)data );
                    } else if ( data instanceof byte[] ) {
                    addSubjectAlternativeName( type, (byte[])data );
                    } else {
                    throw new IOException("parsing error: unknown data type");
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw new IOException("parsing exception:\n" + ex.toString());
        }
    }

    /**
     * Adds a name to the subjectAlternativeNames criterion. The
     * <code>X509Certificate</code> must contain all or at least one of the
     * specified subjectAlternativeNames, depending on the value
     * of the matchAllNames flag (see {@link #setMatchAllSubjectAltNames}).<br />
     * <br />
     * This method allows the caller to add a name to the set of
     * subject alternative names. The specified name is added to
     * any previous value for the subjectAlternativeNames
     * criterion. If the specified name is a duplicate, it may be
     * ignored.<br />
     * <br />
     * The name is provided in string format. RFC 822, DNS, and
     * URI names use the well-established string formats for those
     * types (subject to the restrictions included in RFC
     * 2459). IPv4 address names are supplied using dotted quad
     * notation. OID address names are represented as a series of
     * nonnegative integers separated by periods. And directory
     * names (distinguished names) are supplied in RFC 2253
     * format. No standard string format is defined for
     * otherNames, X.400 names, EDI party names, IPv6 address
     * names, or any other type of names. They should be specified
     * using the {@link #addSubjectAlternativeName(int, byte[]) addSubjectAlternativeName(int type, byte [] name)}
     * method.
     *
     * @param type the name type (0-8, as specified in RFC 2459, section 4.2.1.7)
     * @param name - the name in string form (not null)
     *
     * @exception IOException if a parsing error occurs
     **/
00826     public void addSubjectAlternativeName(
        int     type,
        String  name)
        throws IOException
    {
        //TODO full implementation of CertUtil.parseGeneralName
        byte[] encoded = CertUtil.parseGeneralName(type,name);
        List tmpList = new ArrayList();
        tmpList.add(new Integer(type));
        tmpList.add(name);
        subjectAltNames.add(tmpList);
        tmpList.set(1,encoded);
        subjectAltNamesByte.add(tmpList);
    }

    /**
     * Adds a name to the subjectAlternativeNames criterion. The
     * <code>X509Certificate</code> must contain all or at least one of the
     * specified subjectAlternativeNames, depending on the value
     * of the matchAllNames flag (see {@link #setMatchAllSubjectAltNames}).<br />
     * <br />
     * This method allows the caller to add a name to the set of
     * subject alternative names. The specified name is added to
     * any previous value for the subjectAlternativeNames
     * criterion. If the specified name is a duplicate, it may be
     * ignored.<br />
     * <br />
     * The name is provided as a byte array. This byte array
     * should contain the DER encoded name, as it would appear in
     * the GeneralName structure defined in RFC 2459 and
     * X.509. The encoded byte array should only contain the
     * encoded value of the name, and should not include the tag
     * associated with the name in the GeneralName structure. The
     * ASN.1 definition of this structure appears below.<br />
     * <br />
     * <pre>
     *   GeneralName ::= CHOICE {
     *       otherName                       [0]     OtherName,
     *       rfc822Name                      [1]     IA5String,
     *       dNSName                         [2]     IA5String,
     *       x400Address                     [3]     ORAddress,
     *       directoryName                   [4]     Name,
     *       ediPartyName                    [5]     EDIPartyName,
     *       uniformResourceIdentifier       [6]     IA5String,
     *       iPAddress                       [7]     OCTET STRING,
     *       registeredID                    [8]     OBJECT IDENTIFIER}
     * </pre><br />
     * <br />
     * Note that the byte array supplied here is cloned to protect
     * against subsequent modifications.<br />
     * <br />
     * <b>TODO: check encoded format</b>
     *
     * @param type the name type (0-8, as listed above)
     * @param name a byte array containing the name in ASN.1 DER encoded form
     *
     * @exception IOException if a parsing error occurs
     **/
00884     public void addSubjectAlternativeName(
        int     type,
        byte[]  name)
        throws IOException
    {
        //TODO check encoded format
        List tmpList = new ArrayList();
        tmpList.add(new Integer(type));
        tmpList.add(name.clone());
        subjectAltNames.add(tmpList);
        subjectAltNamesByte.add(tmpList);
    }

    /**
     * Sets the name constraints criterion. The <code>X509Certificate</code>
     * must have subject and subject alternative names that meet
     * the specified name constraints.<br />
     * <br />
     * The name constraints are specified as a byte array. This
     * byte array should contain the DER encoded form of the name
     * constraints, as they would appear in the NameConstraints
     * structure defined in RFC 2459 and X.509. The ASN.1
     * definition of this structure appears below.<br />
     * <br />
     * <pre>
     *  NameConstraints ::= SEQUENCE {
     *       permittedSubtrees       [0]     GeneralSubtrees OPTIONAL,
     *       excludedSubtrees        [1]     GeneralSubtrees OPTIONAL }
     *
     *  GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
     *
     *  GeneralSubtree ::= SEQUENCE {
     *       base                    GeneralName,
     *       minimum         [0]     BaseDistance DEFAULT 0,
     *       maximum         [1]     BaseDistance OPTIONAL }
     *
     *  BaseDistance ::= INTEGER (0..MAX)
     *
     *  GeneralName ::= CHOICE {
     *       otherName                       [0]     OtherName,
     *       rfc822Name                      [1]     IA5String,
     *       dNSName                         [2]     IA5String,
     *       x400Address                     [3]     ORAddress,
     *       directoryName                   [4]     Name,
     *       ediPartyName                    [5]     EDIPartyName,
     *       uniformResourceIdentifier       [6]     IA5String,
     *       iPAddress                       [7]     OCTET STRING,
     *       registeredID                    [8]     OBJECT IDENTIFIER}
     * </pre><br />
     * <br />
     * Note that the byte array supplied here is cloned to protect
     * against subsequent modifications.<br />
     * <br />
     * <b>TODO: implement this</b>
     *
     * @param bytes a byte array containing the ASN.1 DER encoding
     * of a NameConstraints extension to be used for checking name
     * constraints. Only the value of the extension is included,
     * not the OID or criticality flag. Can be <code>null</code>, in which case
     * no name constraints check will be performed
     *
     * @exception IOException if a parsing error occurs
     * @exception UnsupportedOperationException because this method
     * is not supported
     * @see #getNameConstraints()
     **/
00950     public void setNameConstraints(
        byte[] bytes)
        throws IOException
    {
        throw new UnsupportedOperationException();
    }

        /**
     * Sets the basic constraints constraint. If the value is
     * greater than or equal to zero, <code>X509Certificates</code> must
     * include a basicConstraints extension with a pathLen of at
     * least this value. If the value is -2, only end-entity
     * certificates are accepted. If the value is -1, no check is
     * done.<br />
     * <br />
     * This constraint is useful when building a certification
     * path forward (from the target toward the trust anchor. If a
     * partial path has been built, any candidate certificate must
     * have a maxPathLen value greater than or equal to the number
     * of certificates in the partial path.
     *
     * @param minMaxPathLen the value for the basic constraints constraint
     *
     * @exception IllegalArgumentException if the value is less than -2
     *
     * @see #getBasicConstraints()
     **/
00977     public void setBasicConstraints(int minMaxPathLen)
    {
        if (minMaxPathLen < -2)
            throw new IllegalArgumentException( "minMaxPathLen must be >= -2" );

        this.minMaxPathLen = minMaxPathLen;
    }

    /**
     * Sets the policy constraint. The X509Certificate must
     * include at least one of the specified policies in its
     * certificate policies extension. If certPolicySet is empty,
     * then the X509Certificate must include at least some
     * specified policy in its certificate policies extension. If
     * certPolicySet is null, no policy check will be performed.<br />
     * <br />
     * Note that the Set is cloned to protect against subsequent
     * modifications.<br />
     * <br />
     * <b>TODO: implement match check for this</b>
     *
     * @param certPolicySet a Set of certificate policy OIDs in
     * string format (or null). Each OID is represented by a set
     * of nonnegative integers separated by periods.
     *
     * @exception IOException if a parsing error occurs on the OID
     * such as the first component is not 0, 1 or 2 or the second
     * component is greater than 39.
     *
     * @see #getPolicy()
     **/
01008     public void setPolicy(
        Set certPolicySet)
        throws IOException
    {
        if (certPolicySet == null)
        {
            policy = null;
            policyOID = null;
        }
        else
        {
            policyOID = new HashSet();
            Iterator iter = certPolicySet.iterator();
            Object item;
            while (iter.hasNext())
            {
                item = iter.next();
                if (item instanceof String)
                {
                    CertUtil.parseOID((String)item);
                    policyOID.add(new DERObjectIdentifier((String)item));
                }
                else
                {
                    throw new IOException("certPolicySet contains null values or non String objects");
                }
            }
            policy = new HashSet( certPolicySet );
        }
    }

    /**
     * Sets the pathToNames criterion. The <code>X509Certificate</code> must
     * not include name constraints that would prohibit building a
     * path to the specified names.<br />
     * <br />
     * This method allows the caller to specify, with a single
     * method call, the complete set of names which the
     * <code>X509Certificates</code>'s name constraints must permit. The
     * specified value replaces the previous value for the
     * pathToNames criterion.<br />
     * <br />
     * This constraint is useful when building a certification
     * path forward (from the target toward the trust anchor. If a
     * partial path has been built, any candidate certificate must
     * not include name constraints that would prohibit building a
     * path to any of the names in the partial path.<br />
     * <br />
     * The names parameter (if not <code>null</code>) is a <code>Collection</code> with one
     * entry for each name to be included in the pathToNames
     * criterion. Each entry is a <code>List</code> whose first entry is an
     * Integer (the name type, 0-8) and whose second entry is a
     * <code>String</code> or a byte array (the name, in string or ASN.1 DER
     * encoded form, respectively). There can be multiple names of
     * the same type. If <code>null</code> is supplied as the value for this
     * argument, no pathToNames check will be performed.<br />
     * <br />
     * Each name in the Collection may be specified either as a
     * String or as an ASN.1 encoded byte array. For more details
     * about the formats used, see 
     * {@link #addPathToName(int, String) addPathToName(int type, String name)}
     * and {@link #addPathToName(int, byte[]) addPathToName(int type, byte [] name)}.<br />
     * <br />
     * Note that the names parameter can contain duplicate names
     * (same name and name type), but they may be removed from the
     * Collection of names returned by the {@link #getPathToNames} method.<br />
     * <br />
     * Note that a deep copy is performed on the Collection to
     * protect against subsequent modifications.<br />
     * <br />
     * <b>TODO: implement this match check for this</b>
     *
     * @param names a Collection with one entry per name (or <code>null</code>)
     *
     * @exception IOException if a parsing error occurs
     * @exception UnsupportedOperationException because this method
     * is not supported
     *
     * @see #getPathToNames()
     **/
01088     public void setPathToNames(
        Collection names)
        throws IOException
    {
        try
        {
            if (names == null || names.isEmpty())
            {
                pathToNames = null;
                pathToNamesByte = null;
            }
            else
            {
                pathToNames = new HashSet();
                pathToNamesByte = new HashSet();
                Iterator iter = names.iterator();
                List item;
                int type;
                Object data;

                while ( iter.hasNext() ) {
                    item = (List)iter.next();
                    type = ((Integer)item.get(0)).intValue();
                    data = item.get(1);
                    if (data instanceof String)
                    {
                        addPathToName( type, (String)data );
                    }
                    else if (data instanceof byte[])
                    {
                        addPathToName( type, (byte[])data );
                    }
                    else
                    {
                        throw new IOException("parsing error: unknown data type");
                    }
                }
            }
        }
        catch (Exception ex)
        {
            throw new IOException("parsing exception:\n" + ex.toString());
        }
    }

    /**
     * Adds a name to the pathToNames criterion. The
     * <code>X509Certificate</code>  must not include name constraints that
     * would prohibit building a path to the specified name.<br />
     * <br />
     * This method allows the caller to add a name to the set of
     * names which the <code>X509Certificates</code>'s name constraints must
     * permit. The specified name is added to any previous value
     * for the pathToNames criterion. If the name is a duplicate,
     * it may be ignored.<br />
     * <br />
     * The name is provided in string format. RFC 822, DNS, and
     * URI names use the well-established string formats for those
     * types (subject to the restrictions included in RFC
     * 2459). IPv4 address names are supplied using dotted quad
     * notation. OID address names are represented as a series of
     * nonnegative integers separated by periods. And directory
     * names (distinguished names) are supplied in RFC 2253
     * format. No standard string format is defined for
     * otherNames, X.400 names, EDI party names, IPv6 address
     * names, or any other type of names. They should be specified
     * using the {@link #addPathToName(int, byte[]) addPathToName(int type, byte [] name)} method.<br />
     * <br />
     * <b>TODO: implement this match check for this</b>
     *
     * @param type the name type (0-8, as specified in RFC 2459, section 4.2.1.7)
     * @param name the name in string form
     *
     * @exceptrion IOException if a parsing error occurs
     **/
01163     public void addPathToName(int type, String name)
    throws IOException
    {
            //TODO full implementation of CertUtil.parseGeneralName
        byte[] encoded = CertUtil.parseGeneralName(type,name);
        List tmpList = new ArrayList();
        tmpList.add(new Integer(type));
        tmpList.add(name);
        pathToNames.add(tmpList);
        tmpList.set(1,encoded);
        pathToNamesByte.add(tmpList);
        throw new UnsupportedOperationException();
    }

    /**
     * Adds a name to the pathToNames criterion. The
     * <code>X509Certificate</code>  must not include name constraints that
     * would prohibit building a path to the specified name.<br />
     * <br />
     * This method allows the caller to add a name to the set of
     * names which the <code>X509Certificates</code>'s name constraints must
     * permit. The specified name is added to any previous value
     * for the pathToNames criterion. If the name is a duplicate,
     * it may be ignored.<br />
     * <br />
     * The name is provided as a byte array. This byte array should
     * contain the DER encoded name, as it would appear in the
     * GeneralName structure defined in RFC 2459 and X.509. The
     * ASN.1 definition of this structure appears in the
     * documentation for {@link #addSubjectAlternativeName(int,byte[]) addSubjectAlternativeName(int type, byte[] name)}.<br />
     * <br />
     * Note that the byte array supplied here is cloned to protect
     * against subsequent modifications.<br />
     * <br />
     * <b>TODO: implement this match check for this</b>
     *
     * @param type the name type (0-8, as specified in RFC 2459, section 4.2.1.7)
     * @param name a byte array containing the name in ASN.1 DER encoded form
     *
     * @exception IOException if a parsing error occurs
     **/
01204     public void addPathToName(
        int     type,
        byte[]  name)
        throws IOException
    {
        //TODO check encoded format
        List tmpList = new ArrayList();
        tmpList.add(new Integer(type));
        tmpList.add(name.clone());
        pathToNames.add(tmpList);
        pathToNamesByte.add(tmpList);
    }
    

    /** 
     * Returns the certificateEquals criterion. The specified
     * <code>X509Certificate</code> must be equal to the <code>X509Certificate</code> passed
     * to the match method. If <code>null</code>, this check is not applied.
     * 
     * @retrun the <code>X509Certificate</code> to match (or <code>null</code>)
     *
     * @see #setCertificate(java.security.cert.X509Certificate)
     **/
01227     public X509Certificate getCertificate()
    {
        return x509Cert;
    }

    /**
     * Returns the serialNumber criterion. The specified serial
     * number must match the certificate serial number in the
     * <code>X509Certificate</code>. If <code>null</code>, any certificate serial number
     * will do.
     *
     * @return the certificate serial number to match (or <code>null</code>)
     *
     * @see #setSerialNumber(java.math.BigInteger)
     **/
01242     public BigInteger getSerialNumber()
    {
        return serialNumber;
    }

    /**
     * Returns the issuer criterion as a String. This
     * distinguished name must match the issuer distinguished name
     * in the <code>X509Certificate</code>. If <code>null</code>, the issuer criterion is
     * disabled and any issuer distinguished name will do.<br />
     * <br />
     * If the value returned is not <code>null</code>, it is a distinguished
     * name, in RFC 2253 format.<br />
     * <br />
     * Uses {@link org.bouncycastle.asn1.x509.X509Name X509Name}
     * for formatiing byte[] issuerDN to String.
     *
     * @return the required issuer distinguished name in RFC 2253
     * format (or <code>null</code>)
     **/
01262     public String getIssuerAsString()
    {
        if (issuerDN instanceof String)
        {
            return new String((String)issuerDN);
        }
        else if (issuerDNX509 != null)
        {
            return issuerDNX509.toString();
        }

        return null;
    }

    /**
     * Returns the issuer criterion as a byte array. This
     * distinguished name must match the issuer distinguished name
     * in the <code>X509Certificate</code>. If <code>null</code>, the issuer criterion is
     * disabled and any issuer distinguished name will do.<br />
     * <br />
     * If the value returned is not <code>null</code>, it is a byte array
     * containing a single DER encoded distinguished name, as
     * defined in X.501. The ASN.1 notation for this structure is
     * supplied in the documentation for
     * {@link #setIssuer(byte[]) setIssuer(byte [] issuerDN)}.<br />
     * <br />
     * Note that the byte array returned is cloned to protect
     * against subsequent modifications.<br />
     * <br />
     * Uses {@link org.bouncycastle.asn1.DEROutputStream DEROutputStream},
     * {@link org.bouncycastle.asn1.x509.X509Name X509Name} to
     * gnerate byte[] output  for String issuerDN.
     *
     * @return a byte array containing the required issuer
     * distinguished name in ASN.1 DER format (or
     * <code>null</code>)
     *
     * @exception IOException  if an encoding error occurs
     **/
01301     public byte[] getIssuerAsBytes()
    throws IOException
    {
        if (issuerDN instanceof byte[])
        {
            return (byte[])((byte[])issuerDN).clone();
        }
        else if (issuerDNX509 != null)
        {
            ByteArrayOutputStream outStream = new ByteArrayOutputStream();
            DEROutputStream derOutStream = new DEROutputStream(outStream);

            derOutStream.writeObject(issuerDNX509.getDERObject());
            derOutStream.close();

            return outStream.toByteArray();
        }

        return null;
    }

    /**
     * Returns the subject criterion as a String. This
     * distinguished name must match the subject distinguished
     * name in the <code>X509Certificate</code>. If <code>null</code>, the subject criterion
     * is disabled and any subject distinguished name will do.<br />
     * <br />
     * If the value returned is not <code>null</code>, it is a distinguished
     * name, in RFC 2253 format.<br />
     * <br />
     * Uses {@link org.bouncycastle.asn1.x509.X509Name X509Name}
     * for formatiing byte[] subjectDN to String.
     *
     * @return the required subject distinguished name in RFC 2253 format (or <code>null</code>)
     **/
01336     public String getSubjectAsString()
    {
        if (subjectDN instanceof String)
        {
            return new String((String)subjectDN);
        }
        else if (subjectDNX509 != null)
        {
            return subjectDNX509.toString();
        }

        return null;
    }

    /**
     * Returns the subject criterion as a byte array. This distinguished name
     * must match the subject distinguished name in the
     * <code>X509Certificate</code>. If <code>null</code>, the subject criterion
     * is disabled and any subject distinguished name will do.<br />
     * <br />
     * If the value returned is not <code>null</code>, it is a byte
     * array containing a single DER encoded distinguished name, as defined in
     * X.501. The ASN.1 notation for this structure is supplied in the
     * documentation for
     * {@link #setSubject(byte [] subjectDN) setSubject(byte [] subjectDN)}.<br />
     * <br />
     * Note that the byte array returned is cloned to protect against
     * subsequent modifications.<br />
     * <br />
     * Uses {@link org.bouncycastle.asn1.DEROutputStream DEROutputStream},
     * {@link org.bouncycastle.asn1.x509.X509Name X509Name} to
     * gnerate byte[] output  for String subjectDN.
     *
     * @return a byte array containing the required subject distinguished name
     *         in ASN.1 DER format (or <code>null</code>)
     *
     * @exception IOException if an encoding error occurs
     */
01374     public byte[] getSubjectAsBytes()
    throws IOException
    {
        if (subjectDN instanceof byte[])
        {
            return (byte[])((byte[])subjectDN).clone();
        }
        else if (subjectDNX509 != null)
        {
                ByteArrayOutputStream outStream = new ByteArrayOutputStream();
                DEROutputStream derOutStream = new DEROutputStream(outStream);

                derOutStream.writeObject(subjectDNX509.getDERObject());
                derOutStream.close();

                return outStream.toByteArray();
        }

        return null;
    }

    /**
     * Returns the subjectKeyIdentifier criterion. The
     * <code>X509Certificate</code> must contain a SubjectKeyIdentifier
     * extension with the specified value. If <code>null</code>, no
     * subjectKeyIdentifier check will be done.<br />
     * <br />
     * Note that the byte array returned is cloned to protect against
     * subsequent modifications.
     *
     * @return the key identifier (or <code>null</code>)
     *
     * @see #setSubjectKeyIdentifier
     */
01408     public byte[] getSubjectKeyIdentifier()
    {
        if (subjectKeyID != null)
        {
            return (byte[])subjectKeyID.clone();
        }

        return null;
    }

    /**
     * Returns the authorityKeyIdentifier criterion. The
     * <code>X509Certificate</code> must contain a AuthorityKeyIdentifier
     * extension with the specified value. If <code>null</code>, no
     * authorityKeyIdentifier check will be done.<br />
     * <br />
     * Note that the byte array returned is cloned to protect against
     * subsequent modifications.
     *
     * @return the key identifier (or <code>null</code>)
     *
     * @see #setAuthorityKeyIdentifier
     */
01431     public byte[] getAuthorityKeyIdentifier()
    {
        if (authorityKeyID != null)
        {
            return (byte[])authorityKeyID.clone();
        }

        return null;
    }

    /**
     * Returns the certificateValid criterion. The specified date must fall
     * within the certificate validity period for the
     * <code>X509Certificate</code>. If <code>null</code>, no certificateValid
     * check will be done.<br />
     * <br />
     * Note that the <code>Date</code> returned is cloned to protect against
     * subsequent modifications.
     *
     * @return the <code>Date</code> to check (or <code>null</code>)
     *
     * @see #setCertificateValid
     */
01454     public Date getCertificateValid()
    {
        if (certValid != null)
        {
            return new Date(certValid.getTime());
        }

        return null;
    }

    /**
     * Returns the privateKeyValid criterion. The specified date must fall
     * within the private key validity period for the
     * <code>X509Certificate</code>. If <code>null</code>, no privateKeyValid
     * check will be done.<br />
     * <br />
     * Note that the <code>Date</code> returned is cloned to protect against
     * subsequent modifications.
     *
     * @return the <code>Date</code> to check (or <code>null</code>)
     *
     * @see #setPrivateKeyValid
     */
01477     public Date getPrivateKeyValid()
    {
        if (privateKeyValid != null)
        {
            return new Date(privateKeyValid.getTime());
        }

        return null;
    }

    /**
     * Returns the subjectPublicKeyAlgID criterion. The
     * <code>X509Certificate</code> must contain a subject public key
     * with the specified algorithm. If <code>null</code>, no
     * subjectPublicKeyAlgID check will be done.
     * 
     * @return the object identifier (OID) of the signature algorithm to check
     *         for (or <code>null</code>). An OID is represented by a set of
     *         nonnegative integers separated by periods.
     *
     * @see #setSubjectPublicKeyAlgID
     */
01499     public String getSubjectPublicKeyAlgID()
    {
        if (subjectKeyAlgID != null)
        {
            return subjectKeyAlgID.toString();
        }

        return null;
    }

    /**
     * Returns the subjectPublicKey criterion. The
     * <code>X509Certificate</code> must contain the specified subject
     * public key. If <code>null</code>, no subjectPublicKey check will be done.
     * 
     * @return the subject public key to check for (or <code>null</code>)
     *
     * @see #setSubjectPublicKey
     */
01518     public PublicKey getSubjectPublicKey()
    {
        return subjectPublicKey;
    }

    /**
     * Returns the keyUsage criterion. The <code>X509Certificate</code>
     * must allow the specified keyUsage values. If null, no keyUsage
     * check will be done.<br />
     * <br />
     * Note that the boolean array returned is cloned to protect against
     * subsequent modifications.
     *
     * @return a boolean array in the same format as the boolean
     *                 array returned by
     * {@link X509Certificate#getKeyUsage() X509Certificate.getKeyUsage()}.
     *                 Or <code>null</code>.
     *
     * @see #setKeyUsage
     */
01538     public boolean[] getKeyUsage()
    {
        if (keyUsage != null)
        {
            return (boolean[])keyUsage.clone();
        }

        return null;
    }

    /**
     * Returns the extendedKeyUsage criterion. The <code>X509Certificate</code>
     * must allow the specified key purposes in its extended key usage
     * extension. If the <code>keyPurposeSet</code> returned is empty or
     * <code>null</code>, no extendedKeyUsage check will be done. Note that an 
     * <code>X509Certificate</code> that has no extendedKeyUsage extension 
     * implicitly allows all key purposes.
     *
     * @return an immutable <code>Set</code> of key purpose OIDs in string
     * format (or <code>null</code>)
     * @see #setExtendedKeyUsage
     */
01560     public Set getExtendedKeyUsage()
    {
        if ( keyPurposeSet == null || keyPurposeSet.isEmpty() )
        {
            return keyPurposeSet;
        }

        Set returnSet = new HashSet();
        Iterator iter = keyPurposeSet.iterator();
        while ( iter.hasNext() )
        {
            returnSet.add( iter.next().toString() );
        }

        return Collections.unmodifiableSet(returnSet);
    }

    /**
     * Indicates if the <code>X509Certificate</code> must contain all
     * or at least one of the subjectAlternativeNames 
     * specified in the {@link #setSubjectAlternativeNames
     * setSubjectAlternativeNames} or {@link #addSubjectAlternativeName
     * addSubjectAlternativeName} methods. If <code>true</code>, 
     * the <code>X509Certificate</code> must contain all of the 
     * specified subject alternative names. If <code>false</code>, the 
     * <code>X509Certificate</code> must contain at least one of the 
     * specified subject alternative names.
     *
     * @return <code>true</code> if the flag is enabled;
     * <code>false</code> if the flag is disabled. The flag is
     * <code>true</code> by default.
     *
     * @see #setMatchAllSubjectAltNames
     */
01594     public boolean getMatchAllSubjectAltNames()
    {
        return matchAllSubjectAltNames;
    }

    /**
     * Returns a copy of the subjectAlternativeNames criterion.
     * The <code>X509Certificate</code> must contain all or at least one
     * of the specified subjectAlternativeNames, depending on the value
     * of the matchAllNames flag (see {@link #getMatchAllSubjectAltNames
     * getMatchAllSubjectAltNames}). If the value returned is <code>null</code>, 
     * no subjectAlternativeNames check will be performed.<br />
     * <br />
     * If the value returned is not <code>null</code>, it is a
     * <code>Collection</code> with
     * one entry for each name to be included in the subject alternative name
     * criterion. Each entry is a <code>List</code> whose first entry is an
     * <code>Integer</code> (the name type, 0-8) and whose second
     * entry is a <code>String</code> or a byte array (the name, in
     * string or ASN.1 DER encoded form, respectively).
     * There can be multiple names of the same type.  Note that the
     * <code>Collection</code> returned may contain duplicate names (same name
     * and name type).<br />
     * <br />
     * Each subject alternative name in the <code>Collection</code>
     * may be specified either as a <code>String</code> or as an ASN.1 encoded
     * byte array. For more details about the formats used, see
     * {@link #addSubjectAlternativeName(int type, String name) 
     * addSubjectAlternativeName(int type, String name)} and
     * {@link #addSubjectAlternativeName(int type, byte [] name) 
     * addSubjectAlternativeName(int type, byte [] name)}.<br />
     * <br />
     * Note that a deep copy is performed on the <code>Collection</code> to
     * protect against subsequent modifications.
     *
     * @return a <code>Collection</code> of names (or <code>null</code>)
     *
     * @see #setSubjectAlternativeNames
     */
01633     public Collection getSubjectAlternativeNames()
    {
        if (subjectAltNames != null)
        {
            return null;
        }

        Set returnAltNames = new HashSet();
        List returnList;
        Iterator iter = subjectAltNames.iterator();
        List obj;
        while ( iter.hasNext() )
        {
            obj = (List)iter.next();
            returnList = new ArrayList();
            returnList.add(obj.get(0));
            if ( obj.get(1) instanceof byte[] )
            {
            returnList.add(((byte[])obj.get(1)).clone());
            }
            else
            {
            returnList.add(obj.get(1));
            }
            returnAltNames.add(returnList);
        }

        return returnAltNames;
    }

    /**
     * Returns the name constraints criterion. The <code>X509Certificate</code>
     * must have subject and subject alternative names that
     * meet the specified name constraints.<br />
     * <br />
     * The name constraints are returned as a byte array. This byte array
     * contains the DER encoded form of the name constraints, as they
     * would appear in the NameConstraints structure defined in RFC 2459
     * and X.509. The ASN.1 notation for this structure is supplied in the
     * documentation for
     * {@link #setNameConstraints(byte [] bytes) setNameConstraints(byte [] bytes)}.<br />
     * <br />
     * Note that the byte array returned is cloned to protect against
     * subsequent modifications.<br />
     * <br />
     * <b>TODO: implement this</b>
     *
     * @return a byte array containing the ASN.1 DER encoding of
     *         a NameConstraints extension used for checking name constraints.
     *         <code>null</code> if no name constraints check will be performed.
     *
     * @exception UnsupportedOperationException because this method
     * is not supported
     *
     * @see #setNameConstraints
     */
01689     public byte[] getNameConstraints()
    {
        throw new UnsupportedOperationException();
    }

    /**
     * Returns the basic constraints constraint. If the value is greater than
     * or equal to zero, the <code>X509Certificates</code> must include a
     * basicConstraints extension with a pathLen of at least this value.
     * If the value is -2, only end-entity certificates are accepted. If
     * the value is -1, no basicConstraints check is done.
     *
     * @return the value for the basic constraints constraint
     *
     * @see #setBasicConstraints
     */
01705     public int getBasicConstraints()
    {
        return minMaxPathLen;
    }

    /**
     * Returns the policy criterion. The <code>X509Certificate</code> must
     * include at least one of the specified policies in its certificate policies
     * extension. If the <code>Set</code> returned is empty, then the 
     * <code>X509Certificate</code> must include at least some specified policy
     * in its certificate policies extension. If the <code>Set</code> returned is
     * <code>null</code>, no policy check will be performed.
     *
     * @return an immutable <code>Set</code> of certificate policy OIDs in
     *         string format (or <code>null</code>)
     *
     * @see #setPolicy
     */
01723     public Set getPolicy()
    {
        if (policy == null)
        {
            return null;
        }

        return Collections.unmodifiableSet(policy);
    }

    /**
     * Returns a copy of the pathToNames criterion. The
     * <code>X509Certificate</code> must not include name constraints that would
     * prohibit building a path to the specified names. If the value
     * returned is <code>null</code>, no pathToNames check will be performed.<br />
     * <br />
     * If the value returned is not <code>null</code>, it is a
     * <code>Collection</code> with one
     * entry for each name to be included in the pathToNames
     * criterion. Each entry is a <code>List</code> whose first entry is an
     * <code>Integer</code> (the name type, 0-8) and whose second
     * entry is a <code>String</code> or a byte array (the name, in
     * string or ASN.1 DER encoded form, respectively).
     * There can be multiple names of the same type. Note that the
     * <code>Collection</code> returned may contain duplicate names (same
     * name and name type).<br />
     * <br />
     * Each name in the <code>Collection</code>
     * may be specified either as a <code>String</code> or as an ASN.1 encoded
     * byte array. For more details about the formats used, see
     * {@link #addPathToName(int type, String name) 
     * addPathToName(int type, String name)} and
     * {@link #addPathToName(int type, byte [] name) 
     * addPathToName(int type, byte [] name)}.<br />
     * <br />
     * Note that a deep copy is performed on the <code>Collection</code> to
     * protect against subsequent modifications.
     *
     * @return a <code>Collection</code> of names (or <code>null</code>)
     *
     * @see #setPathToNames
     */
01765     public Collection getPathToNames()
    {
        if (pathToNames == null)
        {
            return null;
        }

        Set returnPathToNames = new HashSet();
        List returnList;
        Iterator iter = pathToNames.iterator();
        List obj;

        while (iter.hasNext())
        {
            obj = (List)iter.next();
            returnList = new ArrayList();
            returnList.add(obj.get(0));
            if ( obj.get(1) instanceof byte[] )
            {
            returnList.add(((byte[])obj.get(1)).clone());
            }
            else
            {
            returnList.add(obj.get(1));
            }
            returnPathToNames.add(returnList);
        }

        return returnPathToNames;
    }

    /**
     * Return a printable representation of the <code>CertSelector</code>.<br />
     * <br />
     * <b>TODO: implement output for currently unsupported options(name constraints)</b><br />
     * <br />
     * Uses {@link org.bouncycastle.asn1.DERInputStream DERInputStream},
     * {@link org.bouncycastle.asn1.DERObject DERObject},
     * {@link org.bouncycastle.asn1.x509.KeyPurposeId KeyPurposeId} and
     * {@link org.bouncycastle.asn1.util.ASN1Dump#_dumpAsString _dumpAsString}
     * to format output as String.
     *
     * @return a <code>String</code> describing the contents of the
     *         <code>CertSelector</code>
     */
01810     public String toString()
    {
        StringBuffer sb = new StringBuffer();
        sb.append("X509CertSelector: [\n");
        if (x509Cert != null)
            sb.append("  Certificate: ").append(x509Cert).append('\n');
        if (serialNumber != null)
            sb.append("  Serial Number: ").append(serialNumber).append('\n');
        if (issuerDN != null)
            sb.append("  Issuer: ").append(getIssuerAsString()).append('\n');
        if (subjectDN != null)
            sb.append("  Subject: ").append(getSubjectAsString()).append('\n');
        try {
            if ( subjectKeyID != null )
            {
            ByteArrayInputStream inStream = new ByteArrayInputStream(subjectKeyID);
            DERInputStream derInStream = new DERInputStream(inStream);
            DERObject derObject = derInStream.readObject();
            sb.append("  Subject Key Identifier: ").append(ASN1Dump.dumpAsString(derObject)).append('\n');
            }
            if ( authorityKeyID != null )
            {
            ByteArrayInputStream inStream = new ByteArrayInputStream(authorityKeyID);
            DERInputStream derInStream = new DERInputStream(inStream);
            DERObject derObject = derInStream.readObject();
            sb.append("  Authority Key Identifier: ").append(ASN1Dump.dumpAsString(derObject)).append('\n');
            }
        } catch ( IOException ex ) {
            sb.append( ex.getMessage()).append('\n');
        }
        if (certValid != null)
            sb.append("  Certificate Valid: ").append( certValid).append('\n');
        if (privateKeyValid != null)
            sb.append("  Private Key Valid: ").append(privateKeyValid).append('\n');
        if (subjectKeyAlgID != null)
            sb.append("  Subject Public Key AlgID: ").append(subjectKeyAlgID).append('\n');
        if (subjectPublicKey != null)
            sb.append("  Subject Public Key: ").append(subjectPublicKey).append('\n');
        if (keyUsage != null)
            sb.append("  Key Usage: ").append(keyUsage).append('\n');
        if (keyPurposeSet != null)
            sb.append("  Extended Key Usage: ").append(keyPurposeSet).append('\n');
        if (policy != null)
            sb.append("  Policy: ").append(policy).append('\n');
        sb.append("  matchAllSubjectAltNames flag: ")
             .append(matchAllSubjectAltNames).append('\n');
        if ( subjectAltNamesByte != null )
        {
            sb.append("   SubjectAlternativNames: \n[");
            Iterator iter = subjectAltNamesByte.iterator();
            List obj;
            try {
            while ( iter.hasNext() )
            {
                obj = (List)iter.next();
                ByteArrayInputStream inStream = new ByteArrayInputStream((byte[])obj.get(1));
                DERInputStream derInStream = new DERInputStream(inStream);
                DERObject derObject = derInStream.readObject();
                sb.append("  Type: ").append(obj.get(0)).append(" Data: ").append(ASN1Dump.dumpAsString(derObject)).append('\n');
            }
            } catch ( IOException ex ) {
            sb.append( ex.getMessage()).append('\n');
            }
            sb.append("]\n");
        }
        if ( pathToNamesByte != null )
        {
            sb.append("   PathToNamesNames: \n[");
            Iterator iter = pathToNamesByte.iterator();
            List obj;
            try {
            while ( iter.hasNext() )
            {
                obj = (List)iter.next();
                ByteArrayInputStream inStream = new ByteArrayInputStream((byte[])obj.get(1));
                DERInputStream derInStream = new DERInputStream(inStream);
                DERObject derObject = derInStream.readObject();
                sb.append("  Type: ").append(obj.get(0)).append(" Data: ").append(ASN1Dump.dumpAsString(derObject)).append('\n');
            }
            } catch ( IOException ex ) {
            sb.append( ex.getMessage()).append('\n');
            }
            sb.append("]\n");
        }
        sb.append(']');
        return sb.toString();
    }

    /**
     * Decides whether a <code>Certificate</code> should be selected.<br />
     * <br />
     * <b>TODO: implement missing tests (name constraints and path to names)</b><br />
     * <br />
     * Uses {@link org.bouncycastle.asn1.DERInputStream DERInputStream},
     * {@link org.bouncycastle.asn1.ASN1Sequence ASN1Sequence},
     * {@link org.bouncycastle.asn1.DERObjectIdentifier DERObjectIdentifier},
     * {@link org.bouncycastle.asn1.DERObject DERObject},
     * {@link org.bouncycastle.asn1.DERGeneralizedTime DERGeneralizedTime},
     * {@link org.bouncycastle.asn1.x509.X509Name X509Name},
     * {@link org.bouncycastle.asn1.x509.X509Extensions X509Extensions},
     * {@link org.bouncycastle.asn1.x509.ExtendedKeyUsage ExtendedKeyUsage},
     * {@link org.bouncycastle.asn1.x509.KeyPurposeId KeyPurposeId},
     * {@link org.bouncycastle.asn1.x509.SubjectPublicKeyInfo SubjectPublicKeyInfo},
     * {@link org.bouncycastle.asn1.x509.AlgorithmIdentifier AlgorithmIdentifier}
     * to access X509 extensions
     *
     * @param cert the <code>Certificate</code> to be checked
     *
     * @return <code>true</code> if the <code>Certificate</code> should be
     *         selected, <code>false</code> otherwise
     */
01921     public boolean match(Certificate cert)
    {
        boolean[] booleanArray;
        List tempList;
        Iterator tempIter;

        if ( ! ( cert instanceof X509Certificate ) )
            return false;
        X509Certificate certX509 = (X509Certificate)cert;

        if ( x509Cert != null && ! x509Cert.equals(certX509) )
            return false;
        if ( serialNumber != null && ! serialNumber.equals(certX509.getSerialNumber() ) )
            return false;
        try {
            if ( issuerDNX509 != null )
            {
                if ( ! issuerDNX509.equals(PrincipalUtil.getIssuerX509Principal(certX509), true))
                    return false;
            }
            if ( subjectDNX509 != null )
            {
                if ( ! subjectDNX509.equals(PrincipalUtil.getSubjectX509Principal(certX509), true))
                    return false;
            }
        } catch ( Exception ex ) {
            return false;
        }
        if ( subjectKeyID != null )
        {
            byte[] data = certX509.getExtensionValue(X509Extensions.SubjectKeyIdentifier.getId());
            if ( data == null )
            return false;
            try {
            ByteArrayInputStream inStream = new ByteArrayInputStream(data);
            DERInputStream derInputStream = new DERInputStream(inStream);
            byte[] testData = ((ASN1OctetString)derInputStream.readObject()).getOctets();
            if ( ! Arrays.equals( subjectKeyID, testData ) )
                return false;
            } catch ( IOException ex ) {
            return false;
            }
        }
        if ( authorityKeyID != null )
        {
            byte[] data = certX509.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
            if ( data == null )
            return false;
            try {
            ByteArrayInputStream inStream = new ByteArrayInputStream(data);
            DERInputStream derInputStream = new DERInputStream(inStream);
            byte[] testData = ((ASN1OctetString)derInputStream.readObject()).getOctets();
            if ( ! Arrays.equals( authorityKeyID, testData ) )
                return false;
            } catch ( IOException ex ) {
            return false;
            }
        }
        if ( certValid != null )
        {
            if ( certX509.getNotAfter() != null && certValid.after(certX509.getNotAfter()) )
            return false;
            if ( certX509.getNotBefore() != null && certValid.before(certX509.getNotBefore()) )
            return false;
        }
        if (privateKeyValid != null)
        {
            try {
            byte[] data = certX509.getExtensionValue(X509Extensions.PrivateKeyUsagePeriod.getId());
            if ( data != null )
            {
                ByteArrayInputStream inStream = new ByteArrayInputStream(data);
                DERInputStream derInputStream = new DERInputStream(inStream);
                inStream = new ByteArrayInputStream(((ASN1OctetString)derInputStream.readObject()).getOctets());
                derInputStream = new DERInputStream(inStream);
                //TODO fix this, Sequence contains tagged objects
                ASN1Sequence derObject = (ASN1Sequence)derInputStream.readObject();
                DERGeneralizedTime derDate = DERGeneralizedTime.getInstance( derObject.getObjectAt(0) );
                SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssZ");
                if ( privateKeyValid.before(dateF.parse(derDate.getTime())) )
                return false;
                derDate = DERGeneralizedTime.getInstance(derObject.getObjectAt(1));
                if ( privateKeyValid.after(dateF.parse(derDate.getTime())) )
                return false;
            }
            } catch ( Exception ex ) {
            ex.printStackTrace();
            return false;
            }
        }
        if ( subjectKeyAlgID != null )
        {
            try {
            ByteArrayInputStream inStream = new ByteArrayInputStream(certX509.getPublicKey().getEncoded());
            DERInputStream derInputStream = new DERInputStream(inStream);
            SubjectPublicKeyInfo publicKeyInfo = new SubjectPublicKeyInfo((ASN1Sequence)derInputStream.readObject());
            AlgorithmIdentifier algInfo = publicKeyInfo.getAlgorithmId();
            if ( ! algInfo.getObjectId().equals(subjectKeyAlgID) )
                return false;
            } catch ( Exception ex ) {
            return false;
            }
        }
            if ( subjectPublicKeyByte != null ) {
            if ( ! Arrays.equals(subjectPublicKeyByte, certX509.getPublicKey().getEncoded()) )
                return false;
            }
            if ( subjectPublicKey != null ) { 
            if ( ! subjectPublicKey.equals(certX509.getPublicKey()) )
                return false;
            }
            if ( keyUsage != null ) {
            booleanArray = certX509.getKeyUsage();
            if ( booleanArray != null ) {
                for ( int i = 0; i < keyUsage.length; i++ ) {
                if ( keyUsage[i] && ( booleanArray.length <= i || ! booleanArray[i] ) )
                     return false;
                }
            }
            }
            if ( keyPurposeSet != null && ! keyPurposeSet.isEmpty() ) {
            try {
                byte[] data = certX509.getExtensionValue( X509Extensions.ExtendedKeyUsage.getId() );
                if ( data != null ) {
                ByteArrayInputStream inStream = new ByteArrayInputStream(data);
                DERInputStream derInputStream = new DERInputStream(inStream);
                ExtendedKeyUsage extendedKeyUsage = new ExtendedKeyUsage((ASN1Sequence)derInputStream.readObject());
                tempIter = keyPurposeSet.iterator();
                while( tempIter.hasNext() ) {
                    if ( ! extendedKeyUsage.hasKeyPurposeId((KeyPurposeId)tempIter.next()) )
                    return false;
                }
                }
            } catch ( Exception ex ) {
                ex.printStackTrace();
                return false;
            }
            }
            if ( minMaxPathLen != -1 ) {
            if ( minMaxPathLen == -2 && certX509.getBasicConstraints() != -1 )
                return false;
            if ( minMaxPathLen >= 0 && certX509.getBasicConstraints() < minMaxPathLen )
                return false;
            }
            if ( policyOID != null ) {
            try {
                byte[] data = certX509.getExtensionValue( X509Extensions.CertificatePolicies.getId() );
                if ( data == null )
                return false;
                if ( ! policyOID.isEmpty() )
                {
                ByteArrayInputStream inStream = new ByteArrayInputStream(data);
                DERInputStream derInputStream = new DERInputStream(inStream);
                inStream = new ByteArrayInputStream(((ASN1OctetString)derInputStream.readObject()).getOctets());
                derInputStream = new DERInputStream(inStream);
                Enumeration policySequence = ((ASN1Sequence)derInputStream.readObject()).getObjects();
                ASN1Sequence policyObject;
                boolean test = false;
                while ( policySequence.hasMoreElements() && ! test )
                {
                    policyObject = (ASN1Sequence)policySequence.nextElement();
                    if ( policyOID.contains(policyObject.getObjectAt(0)) )
                    test = true;
                }
                if ( ! test )
                    return false; 
                }
            } catch ( Exception ex ) {
                ex.printStackTrace();
                return false;
            }
            }
            if ( subjectAltNamesByte != null )
            {
                try
                {
                    byte[] data = certX509.getExtensionValue(X509Extensions.SubjectAlternativeName.getId());
                    if (data == null)
                    {
                        return false;
                    }
                    ByteArrayInputStream inStream = new ByteArrayInputStream(data);
                    DERInputStream derInputStream = new DERInputStream(inStream);
                    inStream = new ByteArrayInputStream(((ASN1OctetString)derInputStream.readObject()).getOctets());
                    derInputStream = new DERInputStream(inStream);
                    Enumeration altNamesSequence = ((ASN1Sequence)derInputStream.readObject()).getObjects();
                    ASN1TaggedObject altNameObject;
                    boolean test = false;
                    Set testSet = new HashSet( subjectAltNamesByte );
                    List testList;
                    DERObject derData;
                    ByteArrayOutputStream outStream;
                    DEROutputStream derOutStream;
                    while (altNamesSequence.hasMoreElements() && !test)
                    {
                        altNameObject = (ASN1TaggedObject)altNamesSequence.nextElement();
                        testList = new ArrayList(2);
                        testList.add(new Integer(altNameObject.getTagNo()));
                        derData = altNameObject.getObject();
                        outStream = new ByteArrayOutputStream();
                        derOutStream = new DEROutputStream(outStream);
                        derOutStream.writeObject( derData );
                        derOutStream.close();
                        testList.add(outStream.toByteArray());

                        if (testSet.remove(testList))
                        {
                            test = true;
                        }

                        if (matchAllSubjectAltNames && !testSet.isEmpty())
                        {
                            test = false;
                        }
                    }
                    if (!test)
                    {
                        return false;
                    }
                }
                catch ( Exception ex )
                {
                    ex.printStackTrace();
                    return false;
                }
            }

            return true;
    }

    /**
     * Returns a copy of this object.
     *
     * @return the copy
     */
02156     public Object clone()
    {
        try
        {
            X509CertSelector copy = (X509CertSelector)super.clone();
            if (issuerDN instanceof byte[] )
            copy.issuerDN = ((byte[])issuerDN).clone();
            if (subjectDN instanceof byte[] )
            copy.subjectDN = ((byte[])subjectDN).clone();
            if ( subjectKeyID != null )
            copy.subjectKeyID = (byte[])subjectKeyID.clone();
            if ( authorityKeyID != null )
            copy.authorityKeyID = (byte[])authorityKeyID.clone();
            if ( subjectPublicKeyByte != null )
            copy.subjectPublicKeyByte = (byte[])subjectPublicKeyByte.clone();
            if ( keyUsage != null )
            copy.keyUsage = (boolean[])keyUsage.clone();
            if ( keyPurposeSet != null )
            copy.keyPurposeSet = new HashSet( keyPurposeSet );
            if ( policy != null )
            {
            copy.policy = new HashSet(policy);
            copy.policyOID = new HashSet();
            Iterator iter = policyOID.iterator();
            while ( iter.hasNext() )
            {
                copy.policyOID.add(new DERObjectIdentifier(((DERObjectIdentifier)iter.next()).getId()));
            }
            }
            if ( subjectAltNames != null ) {
            copy.subjectAltNames = new HashSet(getSubjectAlternativeNames());
            Iterator iter = subjectAltNamesByte.iterator();
            List obj;
            List cloneObj;
            while ( iter.hasNext() )
            {
                obj = (List)iter.next();
                cloneObj = new ArrayList();
                cloneObj.add(obj.get(0));
                cloneObj.add(((byte[])obj.get(1)).clone());
                copy.subjectAltNamesByte.add(cloneObj);
            }
            }
            if ( pathToNames != null ) {
            copy.pathToNames = new HashSet(getPathToNames());
            Iterator iter = pathToNamesByte.iterator();
            List obj;
            List cloneObj;
            while ( iter.hasNext() )
            {
                obj = (List)iter.next();
                cloneObj = new ArrayList();
                cloneObj.add(obj.get(0));
                cloneObj.add(((byte[])obj.get(1)).clone());
                copy.pathToNamesByte.add(cloneObj);
            }
            }
            return copy;
        }
        catch (CloneNotSupportedException e)
        {
            /* Cannot happen */
            throw new InternalError(e.toString());
        }
    }
}

Generated by  Doxygen 1.6.0   Back to index