aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CertSelector.java
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CertSelector.java')
-rw-r--r--libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CertSelector.java2468
1 files changed, 2468 insertions, 0 deletions
diff --git a/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CertSelector.java b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CertSelector.java
new file mode 100644
index 000000000..0f1f814dd
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/jdk1.3/org/spongycastle/jce/cert/X509CertSelector.java
@@ -0,0 +1,2468 @@
+package org.spongycastle.jce.cert;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Object;
+import org.spongycastle.asn1.ASN1ObjectIdentifier;
+import org.spongycastle.asn1.ASN1OctetString;
+import org.spongycastle.asn1.ASN1Sequence;
+import org.spongycastle.asn1.ASN1TaggedObject;
+import org.spongycastle.asn1.DERGeneralizedTime;
+import org.spongycastle.asn1.DEROutputStream;
+import org.spongycastle.asn1.util.ASN1Dump;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.ExtendedKeyUsage;
+import org.spongycastle.asn1.x509.KeyPurposeId;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.asn1.x509.X509Name;
+import org.spongycastle.jce.PrincipalUtil;
+import org.spongycastle.util.Integers;
+
+/**
+ * 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.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier},
+ * {@link org.spongycastle.asn1.DEROutputStream DEROutputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object},
+ * {@link org.spongycastle.asn1.OIDTokenizer OIDTokenizer},
+ * {@link org.spongycastle.asn1.x509.X509Name X509Name},
+ * {@link org.spongycastle.asn1.x509.X509Extensions X509Extensions},
+ * {@link org.spongycastle.asn1.x509.ExtendedKeyUsage ExtendedKeyUsage},
+ * {@link org.spongycastle.asn1.x509.KeyPurposeId KeyPurposeId},
+ * {@link org.spongycastle.asn1.x509.SubjectPublicKeyInfo SubjectPublicKeyInfo},
+ * {@link org.spongycastle.asn1.x509.AlgorithmIdentifier AlgorithmIdentifier}
+ */
+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 ASN1ObjectIdentifier 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.
+ */
+ 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()
+ */
+ 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()
+ */
+ 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.spongycastle.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)
+ */
+ 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 RDN
+ *
+ * RDN ::=
+ * 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.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.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)
+ */
+ public void setIssuer(byte[] issuerDN) throws IOException
+ {
+ if (issuerDN == null)
+ {
+ this.issuerDN = null;
+ this.issuerDNX509 = null;
+ }
+ else
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(issuerDN);
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Object 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.spongycastle.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)
+ */
+ 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.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.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)
+ */
+ public void setSubject(byte[] subjectDN) throws IOException
+ {
+ if (subjectDN == null)
+ {
+ this.subjectDN = null;
+ this.subjectDNX509 = null;
+ }
+ else
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(subjectDN);
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Object 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()
+ */
+ 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()
+ */
+ 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()
+ */
+ 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()
+ */
+ 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()
+ */
+ public void setSubjectPublicKeyAlgID(String oid) throws IOException
+ {
+ if (oid != null)
+ {
+ CertUtil.parseOID(oid);
+ subjectKeyAlgID = new ASN1ObjectIdentifier(oid);
+ }
+ else
+ {
+ subjectKeyAlgID = null;
+ }
+ }
+
+ /**
+ * 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()
+ */
+ 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()
+ */
+ 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()
+ */
+ 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.spongycastle.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()
+ */
+ 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()
+ */
+ 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()
+ */
+ 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
+ */
+ 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(Integers.valueOf(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
+ */
+ public void addSubjectAlternativeName(int type, byte[] name)
+ throws IOException
+ {
+ // TODO check encoded format
+ List tmpList = new ArrayList();
+ tmpList.add(Integers.valueOf(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()
+ */
+ 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()
+ */
+ 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()
+ */
+ 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 ASN1ObjectIdentifier((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()
+ */
+ 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
+ */
+ 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(Integers.valueOf(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
+ */
+ public void addPathToName(int type, byte[] name) throws IOException
+ {
+ // TODO check encoded format
+ List tmpList = new ArrayList();
+ tmpList.add(Integers.valueOf(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)
+ */
+ 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)
+ */
+ 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.spongycastle.asn1.x509.X509Name X509Name} for formatiing
+ * byte[] issuerDN to String.
+ *
+ * @return the required issuer distinguished name in RFC 2253 format (or
+ * <code>null</code>)
+ */
+ 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.spongycastle.asn1.DEROutputStream DEROutputStream},
+ * {@link org.spongycastle.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
+ */
+ 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.toASN1Primitive());
+ 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.spongycastle.asn1.x509.X509Name X509Name} for formatiing
+ * byte[] subjectDN to String.
+ *
+ * @return the required subject distinguished name in RFC 2253 format (or
+ * <code>null</code>)
+ */
+ 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.spongycastle.asn1.DEROutputStream DEROutputStream},
+ * {@link org.spongycastle.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
+ */
+ 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.toASN1Primitive());
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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
+ */
+ 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.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object},
+ * {@link org.spongycastle.asn1.x509.KeyPurposeId KeyPurposeId}
+ *
+ * @return a <code>String</code> describing the contents of the
+ * <code>CertSelector</code>
+ */
+ 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);
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Object derObject = derInStream.readObject();
+ sb.append(" Subject Key Identifier: ")
+ .append(ASN1Dump.dumpAsString(derObject)).append('\n');
+ }
+ if (authorityKeyID != null)
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(
+ authorityKeyID);
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Object 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));
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Object 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));
+ ASN1InputStream derInStream = new ASN1InputStream(inStream);
+ ASN1Object 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.spongycastle.asn1.ASN1InputStream ASN1InputStream},
+ * {@link org.spongycastle.asn1.ASN1Sequence ASN1Sequence},
+ * {@link org.spongycastle.asn1.ASN1ObjectIdentifier ASN1ObjectIdentifier},
+ * {@link org.spongycastle.asn1.ASN1Object ASN1Object},
+ * {@link org.spongycastle.asn1.DERGeneralizedTime DERGeneralizedTime},
+ * {@link org.spongycastle.asn1.x509.X509Name X509Name},
+ * {@link org.spongycastle.asn1.x509.X509Extensions X509Extensions},
+ * {@link org.spongycastle.asn1.x509.ExtendedKeyUsage ExtendedKeyUsage},
+ * {@link org.spongycastle.asn1.x509.KeyPurposeId KeyPurposeId},
+ * {@link org.spongycastle.asn1.x509.SubjectPublicKeyInfo SubjectPublicKeyInfo},
+ * {@link org.spongycastle.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
+ */
+ 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);
+ ASN1InputStream derInputStream = new ASN1InputStream(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);
+ ASN1InputStream derInputStream = new ASN1InputStream(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);
+ ASN1InputStream derInputStream = new ASN1InputStream(inStream);
+ inStream = new ByteArrayInputStream(
+ ((ASN1OctetString)derInputStream.readObject())
+ .getOctets());
+ derInputStream = new ASN1InputStream(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)
+ {
+ return false;
+ }
+ }
+ if (subjectKeyAlgID != null)
+ {
+ try
+ {
+ ByteArrayInputStream inStream = new ByteArrayInputStream(
+ certX509.getPublicKey().getEncoded());
+ ASN1InputStream derInputStream = new ASN1InputStream(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);
+ ASN1InputStream derInputStream = new ASN1InputStream(inStream);
+ ExtendedKeyUsage extendedKeyUsage = ExtendedKeyUsage.getInstance(
+ derInputStream.readObject());
+ tempIter = keyPurposeSet.iterator();
+ while (tempIter.hasNext())
+ {
+ if (!extendedKeyUsage
+ .hasKeyPurposeId((KeyPurposeId)tempIter.next()))
+ {
+ return false;
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ 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);
+ ASN1InputStream derInputStream = new ASN1InputStream(inStream);
+ inStream = new ByteArrayInputStream(
+ ((ASN1OctetString)derInputStream.readObject())
+ .getOctets());
+ derInputStream = new ASN1InputStream(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);
+ ASN1InputStream derInputStream = new ASN1InputStream(inStream);
+ inStream = new ByteArrayInputStream(
+ ((ASN1OctetString)derInputStream.readObject())
+ .getOctets());
+ derInputStream = new ASN1InputStream(inStream);
+ Enumeration altNamesSequence = ((ASN1Sequence)derInputStream
+ .readObject()).getObjects();
+ ASN1TaggedObject altNameObject;
+ boolean test = false;
+ Set testSet = new HashSet(subjectAltNamesByte);
+ List testList;
+ ASN1Object derData;
+ ByteArrayOutputStream outStream;
+ DEROutputStream derOutStream;
+ while (altNamesSequence.hasMoreElements() && !test)
+ {
+ altNameObject = (ASN1TaggedObject)altNamesSequence
+ .nextElement();
+ testList = new ArrayList(2);
+ testList.add(Integers.valueOf(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
+ */
+ 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 ASN1ObjectIdentifier(
+ ((ASN1ObjectIdentifier)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());
+ }
+ }
+}