- /*
- * @(#)X509CertSelector.java 1.14 03/01/23
- *
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
-
- package java.security.cert;
-
- import java.io.IOException;
- import java.math.BigInteger;
- import java.security.PublicKey;
- import java.util.*;
- import javax.security.auth.x500.X500Principal;
-
- import sun.misc.HexDumpEncoder;
- import sun.security.util.Debug;
- import sun.security.util.DerInputStream;
- import sun.security.util.DerValue;
- import sun.security.util.ObjectIdentifier;
- import sun.security.x509.*;
-
- /**
- * A <code>CertSelector</code> that selects <code>X509Certificates</code> that
- * match all specified criteria. This class is particularly useful when
- * selecting certificates from a <code>CertStore</code> to build a
- * PKIX-compliant certification path.
- * <p>
- * When first constructed, an <code>X509CertSelector</code> has no criteria
- * enabled and each of the <code>get</code> methods return a default value
- * (<code>null</code>, or <code>-1</code> for the {@link #getBasicConstraints
- * getBasicConstraints} method). Therefore, the {@link #match match}
- * method would return <code>true</code> for any <code>X509Certificate</code>.
- * Typically, several criteria are enabled (by calling
- * {@link #setIssuer setIssuer} or
- * {@link #setKeyUsage setKeyUsage}, for instance) and then the
- * <code>X509CertSelector</code> is passed to
- * {@link CertStore#getCertificates CertStore.getCertificates} or some similar
- * method.
- * <p>
- * Several criteria can be enabled (by calling {@link #setIssuer setIssuer}
- * and {@link #setSerialNumber setSerialNumber},
- * for example) such that the <code>match</code> 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.
- * <p>
- * Please refer to RFC 2459 for definitions of the X.509 certificate
- * extensions mentioned below.
- * <p>
- * <b>Concurrent Access</b>
- * <p>
- * 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.
- *
- * @see CertSelector
- * @see X509Certificate
- *
- * @version 1.14, 01/23/03
- * @since 1.4
- * @author Steve Hanna
- */
- public class X509CertSelector implements CertSelector {
-
- private static final Debug debug = Debug.getInstance("certpath");
-
- private final static ObjectIdentifier ANY_EXTENDED_KEY_USAGE =
- ObjectIdentifier.newInternal(new int[] {2, 5, 29, 37, 0});
-
- static {
- CertPathHelperImpl.initialize();
- }
-
- private BigInteger serialNumber;
- private X500Principal issuer;
- private X500Principal subject;
- private byte[] subjectKeyID;
- private byte[] authorityKeyID;
- private Date certificateValid;
- private Date privateKeyValid;
- private ObjectIdentifier subjectPublicKeyAlgID;
- private PublicKey subjectPublicKey;
- private byte[] subjectPublicKeyBytes;
- private boolean[] keyUsage;
- private Set keyPurposeSet, keyPurposeOIDSet;
- private Set subjectAlternativeNames;
- private Set subjectAlternativeGeneralNames;
- private CertificatePolicySet policy;
- private Set policySet;
- private Set pathToNames;
- private Set pathToGeneralNames;
- private NameConstraintsExtension nc;
- private byte[] ncBytes;
- private int basicConstraints = -1;
- private X509Certificate x509Cert;
- private boolean matchAllSubjectAltNames = true;
-
- private static final Boolean FALSE = Boolean.FALSE;
-
- private static final int PRIVATE_KEY_USAGE_ID = 0;
- private static final int SUBJECT_ALT_NAME_ID = 1;
- private static final int NAME_CONSTRAINTS_ID = 2;
- private static final int CERT_POLICIES_ID = 3;
- private static final int EXTENDED_KEY_USAGE_ID = 4;
- private static final int NUM_OF_EXTENSIONS = 5;
- private static final String[] EXTENSION_OIDS = new String[NUM_OF_EXTENSIONS];
-
- static {
- EXTENSION_OIDS[PRIVATE_KEY_USAGE_ID] = "2.5.29.16";
- EXTENSION_OIDS[SUBJECT_ALT_NAME_ID] = "2.5.29.17";
- EXTENSION_OIDS[NAME_CONSTRAINTS_ID] = "2.5.29.30";
- EXTENSION_OIDS[CERT_POLICIES_ID] = "2.5.29.32";
- EXTENSION_OIDS[EXTENDED_KEY_USAGE_ID] = "2.5.29.37";
- };
-
- /* Constants representing the GeneralName types */
- static final int NAME_ANY = 0;
- static final int NAME_RFC822 = 1;
- static final int NAME_DNS = 2;
- static final int NAME_X400 = 3;
- static final int NAME_DIRECTORY = 4;
- static final int NAME_EDI = 5;
- static final int NAME_URI = 6;
- static final int NAME_IP = 7;
- static final int NAME_OID = 8;
-
- /**
- * Creates an <code>X509CertSelector</code>. Initially, no criteria are set
- * so any <code>X509Certificate</code> will match.
- */
- public X509CertSelector() {
- // empty
- }
-
- /**
- * Sets the certificateEquals criterion. The specified
- * <code>X509Certificate</code> must be equal to the
- * <code>X509Certificate</code> passed to the <code>match</code> method.
- * If <code>null</code>, then this check is not applied.
- *
- * <p>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 <code>X509Certificate</code> 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;
- }
-
- // called from CertPathHelperImpl, to be made public in a future release
- void setIssuer(X500Principal issuer) {
- this.issuer = issuer;
- }
-
- /**
- * 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.
- * <p>
- * If <code>issuerDN</code> is not <code>null</code>, it should contain a
- * distinguished name, in RFC 2253 format.
- *
- * @param issuerDN a distinguished name in RFC 2253 format
- * (or <code>null</code>)
- * @throws IOException if a parsing error occurs (incorrect form for DN)
- */
- public void setIssuer(String issuerDN) throws IOException {
- if (issuerDN == null) {
- issuer = null;
- } else {
- issuer = new X500Name(issuerDN, "RFC2253").asX500Principal();
- }
- }
-
- /**
- * Sets the issuer criterion. The specified distinguished name
- * must match the issuer distinguished name in the
- * <code>X509Certificate</code>. If <code>null</code> is specified,
- * the issuer criterion is disabled and any issuer distinguished name will
- * do.
- * <p>
- * 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.
- * <pre><code>
- * 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)) }
- * </code></pre>
- * <p>
- * Note that the byte array specified here is cloned to protect against
- * subsequent modifications.
- *
- * @param issuerDN a byte array containing the distinguished name
- * in ASN.1 DER encoded form (or <code>null</code>)
- * @throws IOException if an encoding error occurs (incorrect form for DN)
- */
- public void setIssuer(byte [] issuerDN) throws IOException {
- try {
- issuer = (issuerDN == null ? null : new X500Principal(issuerDN));
- } catch (IllegalArgumentException e) {
- throw (IOException)new IOException("Invalid name").initCause(e);
- }
- }
-
- // called from CertPathHelperImpl, to be made public in a future release
- void setSubject(X500Principal subject) {
- this.subject = subject;
- }
-
- /**
- * Sets the subject criterion. The specified distinguished name
- * must match the subject distinguished name in the
- * <code>X509Certificate</code>. If <code>null</code>, any subject
- * distinguished name will do.
- * <p>
- * If <code>subjectDN</code> is not <code>null</code>, it should contain a
- * distinguished name, in RFC 2253 format.
- *
- * @param subjectDN a distinguished name in RFC 2253 format
- * (or <code>null</code>)
- * @throws IOException if a parsing error occurs (incorrect form for DN)
- */
- public void setSubject(String subjectDN) throws IOException {
- if (subjectDN == null) {
- subject = null;
- } else {
- subject = new X500Name(subjectDN, "RFC2253").asX500Principal();
- }
- }
-
- /**
- * Sets the subject criterion. The specified distinguished name
- * must match the subject distinguished name in the
- * <code>X509Certificate</code>. If <code>null</code>, any subject
- * distinguished name will do.
- * <p>
- * 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 [] issuerDN) setIssuer(byte [] issuerDN)}.
- *
- * @param subjectDN a byte array containing the distinguished name in
- * ASN.1 DER format (or <code>null</code>)
- * @throws IOException if an encoding error occurs (incorrect form for DN)
- */
- public void setSubject(byte [] subjectDN) throws IOException {
- try {
- subject = (subjectDN == null ? null : new X500Principal(subjectDN));
- } catch (IllegalArgumentException e) {
- throw (IOException)new IOException("Invalid name").initCause(e);
- }
- }
-
- /**
- * 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 <code>null</code>, no
- * subjectKeyIdentifier check will be done.
- * <p>
- * 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.
- * <p>
- * <pre><code>
- * SubjectKeyIdentifier ::= KeyIdentifier
- *
- * KeyIdentifier ::= OCTET STRING
- * </code></pre>
- * <p>
- * 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.
- * <p>
- * 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.
- * <p>
- * 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.
- * <p>
- * <pre><code>
- * AuthorityKeyIdentifier ::= SEQUENCE {
- * keyIdentifier [0] KeyIdentifier OPTIONAL,
- * authorityCertIssuer [1] GeneralNames OPTIONAL,
- * authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
- *
- * KeyIdentifier ::= OCTET STRING
- * </code></pre>
- * <p>
- * Authority key identifiers are not parsed by the
- * <code>X509CertSelector</code>. Instead, the values are
- * compared using a byte-by-byte comparison.
- * <p>
- * When the <code>keyIdentifier</code> field of
- * <code>AuthorityKeyIdentifier</code> is populated, the value is
- * usually taken from the <code>SubjectKeyIdentifier</code> extension
- * in the issuer's certificate. Note, however, that the result of
- * <code>X509Certificate.getExtensionValue(<SubjectKeyIdentifier Object
- * Identifier>)</code> on the issuer's certificate may NOT be used
- * directly as the input to <code>setAuthorityKeyIdentifier</code>.
- * 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
- * <code>SubjectKeyIdentifier</code>
- * extension, it will be necessary to extract the value of the embedded
- * <code>KeyIdentifier</code> OCTET STRING, then DER encode this OCTET
- * STRING inside a SEQUENCE.
- * For more details on SubjectKeyIdentifier, see
- * {@link #setSubjectKeyIdentifier(byte[] subjectKeyID)}.
- * <p>
- * 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
- * <code>X509Certificate</code>. If <code>null</code>, no certificateValid
- * check will be done.
- * <p>
- * Note that the <code>Date</code> supplied here is cloned to protect
- * against subsequent modifications.
- *
- * @param certValid the <code>Date</code> to check (or <code>null</code>)
- * @see #getCertificateValid
- */
- public void setCertificateValid(Date certValid) {
- if (certValid == null) {
- certificateValid = null;
- } else {
- certificateValid = (Date)certValid.clone();
- }
- }
-
- /**
- * Sets 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.
- * <p>
- * Note that the <code>Date</code> supplied here is cloned to protect
- * against subsequent modifications.
- *
- * @param privateKeyValid the <code>Date</code> to check (or
- * <code>null</code>)
- * @see #getPrivateKeyValid
- */
- public void setPrivateKeyValid(Date privateKeyValid) {
- if (privateKeyValid == null) {
- this.privateKeyValid = null;
- } else {
- this.privateKeyValid = (Date)privateKeyValid.clone();
- }
- }
-
- /**
- * Sets 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.
- *
- * @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.
- * @throws 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) {
- subjectPublicKeyAlgID = null;
- } else {
- subjectPublicKeyAlgID = new ObjectIdentifier(oid);
- }
- }
-
- /**
- * 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.
- *
- * @param key the subject public key to check for (or <code>null</code>)
- * @see #getSubjectPublicKey
- */
- public void setSubjectPublicKey(PublicKey key) {
- if (key == null) {
- subjectPublicKey = null;
- subjectPublicKeyBytes = null;
- } else {
- subjectPublicKey = key;
- subjectPublicKeyBytes = 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.
- * <p>
- * Because this method allows the public key to be specified as a byte
- * array, it may be used for unknown key types.
- * <p>
- * If <code>key</code> 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.
- * <pre><code>
- * 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
- * </code></pre>
- * <p>
- * 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>)
- * @throws 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;
- subjectPublicKeyBytes = null;
- } else {
- subjectPublicKeyBytes = (byte[])key.clone();
- subjectPublicKey = X509Key.parse(new DerValue(subjectPublicKeyBytes));
- }
- }
-
- /**
- * Sets the keyUsage criterion. The <code>X509Certificate</code>
- * must allow the specified keyUsage values. If <code>null</code>, no
- * keyUsage check will be done. Note that an <code>X509Certificate</code>
- * that has no keyUsage extension implicitly allows all keyUsage values.
- * <p>
- * 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
- * {@link X509Certificate#getKeyUsage() 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.
- * <p>
- * Note that the <code>Set</code> is cloned to protect against
- * subsequent modifications.
- *
- * @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.
- * @throws 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 = null;
- } else {
- this.keyPurposeSet =
- Collections.unmodifiableSet(new HashSet(keyPurposeSet));
- keyPurposeOIDSet = new HashSet();
- for (Iterator t = this.keyPurposeSet.iterator(); t.hasNext();) {
- String s = (String)t.next();
- keyPurposeOIDSet.add(new ObjectIdentifier(s));
- }
- }
- }
-
- /**
- * 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
- * <code>X509Certificate</code> must contain at least one of the
- * specified subject alternative names.
- *
- * <p>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) {
- this.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
- * setMatchAllSubjectAltNames}).
- * <p>
- * 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.
- * <p>
- * 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.
- * <p>
- * 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)}.
- * <p>
- * 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 getSubjectAlternativeNames} method.
- * <p>
- * Note that a deep copy is performed on the <code>Collection</code> to
- * protect against subsequent modifications.
- *
- * @param names a <code>Collection</code> of names (or <code>null</code>)
- * @throws IOException if a parsing error occurs
- * @see #getSubjectAlternativeNames
- */
- public void setSubjectAlternativeNames(Collection names)
- throws IOException {
- if (names == null) {
- subjectAlternativeNames = null;
- subjectAlternativeGeneralNames = null;
- } else {
- if (names.isEmpty()) {
- subjectAlternativeNames = null;
- subjectAlternativeGeneralNames = null;
- return;
- }
- Set tempNames = cloneAndCheckNames(names);
- // Ensure that we either set both of these or neither
- subjectAlternativeGeneralNames = parseNames(tempNames);
- subjectAlternativeNames = tempNames;
- }
- }
-
- /**
- * 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
- * setMatchAllSubjectAltNames}).
- * <p>
- * 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.
- * <p>
- * 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 type, byte [] name)
- * 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 <code>null</code>)
- * @throws IOException if a parsing error occurs
- */
- public void addSubjectAlternativeName(int type, String name)
- throws IOException {
- addSubjectAlternativeNameInternal(type, name);
- }
-
- /**
- * 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
- * setMatchAllSubjectAltNames}).
- * <p>
- * 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.
- * <p>
- * 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.
- * <pre><code>
- * 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}
- * </code></pre>
- * <p>
- * Note that the byte array supplied here is cloned to protect against
- * subsequent modifications.
- *
- * @param type the name type (0-8, as listed above)
- * @param name a byte array containing the name in ASN.1 DER encoded form
- * @throws IOException if a parsing error occurs
- */
- public void addSubjectAlternativeName(int type, byte[] name)
- throws IOException {
- // clone because byte arrays are modifiable
- addSubjectAlternativeNameInternal(type, name.clone());
- }
-
- /**
- * A private method that adds a name (String or byte array) to the
- * subjectAlternativeNames criterion. The <code>X509Certificate</code>
- * must contain the specified subjectAlternativeName.
- *
- * @param type the name type (0-8, as specified in
- * RFC 2459, section 4.2.1.7)
- * @param name the name in string or byte array form
- * @throws IOException if a parsing error occurs
- */
- private void addSubjectAlternativeNameInternal(int type, Object name)
- throws IOException {
- // First, ensure that the name parses
- GeneralNameInterface tempName = makeGeneralNameInterface(type, name);
- if (subjectAlternativeNames == null) {
- subjectAlternativeNames = new HashSet();
- }
- if (subjectAlternativeGeneralNames == null) {
- subjectAlternativeGeneralNames = new HashSet();
- }
- ArrayList list = new ArrayList();
- list.add(new Integer(type));
- list.add(name);
- subjectAlternativeNames.add(list);
- subjectAlternativeGeneralNames.add(tempName);
- }
-
- /**
- * Parse an argument of the form passed to setSubjectAlternativeNames,
- * returning a <code>Collection</code> of
- * <code>GeneralNameInterface</code>s.
- * Throw an IllegalArgumentException or a ClassCastException
- * if the argument is malformed.
- *
- * @param names a Collection with one entry per name.
- * Each entry is a <code>List</code> whose first entry
- * is an Integer (the name type, 0-8) and whose second
- * entry is a String or a byte array (the name, in
- * string or ASN.1 DER encoded form, respectively).
- * There can be multiple names of the same type. Null is
- * not an acceptable value.
- * @return a Set of <code>GeneralNameInterface</code>s
- * @throws IOException if a parsing error occurs
- */
- private static Set parseNames(Collection names) throws IOException {
- Set genNames = new HashSet();
- Iterator i = names.iterator();
- while (i.hasNext()) {
- Object o = i.next();
- if (!(o instanceof List)) {
- throw new IOException("expected List");
- }
- List nameList = (List) o;
- if (nameList.size() != 2) {
- throw new IOException("name list size not 2");
- }
- o = nameList.get(0);
- if (!(o instanceof Integer)) {
- throw new IOException("expected an Integer");
- }
- int nameType = ((Integer) o).intValue();
- o = nameList.get(1);
- genNames.add(makeGeneralNameInterface(nameType, o));
- }
- return genNames;
- }
-
- /**
- * Compare for equality two objects of the form passed to
- * setSubjectAlternativeNames (or X509CRLSelector.setIssuerNames).
- * Throw an <code>IllegalArgumentException</code> or a
- * <code>ClassCastException</code> if one of the objects is malformed.
- *
- * @param object1 a Collection containing the first object to compare
- * @param object2 a Collection containing the second object to compare
- * @return true if the objects are equal, false otherwise
- */
- static boolean equalNames(Collection object1, Collection object2) {
- if ((object1 == null) || (object2 == null)) {
- return object1 == object2;
- }
- return object1.equals(object2);
- }
-
- /**
- * Make a <code>GeneralNameInterface</code> out of a name type (0-8) and an
- * Object that may be a byte array holding the ASN.1 DER encoded
- * name or a String form of the name. Except for X.509
- * Distinguished Names, the String form of the name must not be the
- * result from calling toString on an existing GeneralNameInterface
- * implementing class. The output of toString is not compatible
- * with the String constructors for names other than Distinguished
- * Names.
- *
- * @param type name type (0-8)
- * @param name name as ASN.1 Der-encoded byte array or String
- * @return a GeneralNameInterface name
- * @throws IOException if a parsing error occurs
- */
- static GeneralNameInterface makeGeneralNameInterface(int type, Object name)
- throws IOException {
- GeneralNameInterface result;
- if (debug != null) {
- debug.println("X509CertSelector.makeGeneralNameInterface("
- + type + ")...");
- }
-
- if (name instanceof String) {
- if (debug != null) {
- debug.println("X509CertSelector.makeGeneralNameInterface() "
- + "name is String: " + name);
- }
- switch (type) {
- case NAME_RFC822:
- result = new RFC822Name((String)name);
- break;
- case NAME_DNS:
- result = new DNSName((String)name);
- break;
- case NAME_DIRECTORY:
- result = new X500Name((String)name, "RFC2253");
- break;
- case NAME_URI:
- result = new URIName((String)name);
- break;
- case NAME_IP:
- result = new IPAddressName((String)name);
- break;
- case NAME_OID:
- result = new OIDName((String)name);
- break;
- default:
- throw new IOException("unable to parse String names of type "
- + type);
- }
- if (debug != null) {
- debug.println("X509CertSelector.makeGeneralNameInterface() "
- + "result: " + result.toString());
- }
- } else if (name instanceof byte[]) {
- DerValue val = new DerValue((byte[]) name);
- if (debug != null) {
- debug.println
- ("X509CertSelector.makeGeneralNameInterface() is byte[]");
- }
-
- switch (type) {
- case NAME_ANY:
- result = new OtherName(val);
- break;
- case NAME_RFC822:
- result = new RFC822Name(val);
- break;
- case NAME_DNS:
- result = new DNSName(val);
- break;
- case NAME_X400:
- result = new X400Address(val);
- break;
- case NAME_DIRECTORY:
- result = new X500Name(val);
- break;
- case NAME_EDI:
- result = new EDIPartyName(val);
- break;
- case NAME_URI:
- result = new URIName(val);
- break;
- case NAME_IP:
- result = new IPAddressName(val);
- break;
- case NAME_OID:
- result = new OIDName(val);
- break;
- default:
- throw new IOException("unable to parse byte array names of "
- + "type " + type);
- }
- if (debug != null) {
- debug.println("X509CertSelector.makeGeneralNameInterface() result: "
- + result.toString());
- }
- } else {
- if (debug != null) {
- debug.println("X509CertSelector.makeGeneralName() input name "
- + "not String or byte array");
- }
- throw new IOException("name not String or byte array");
- }
- return result;
- }
-
-
- /**
- * Sets the name constraints criterion. The <code>X509Certificate</code>
- * must have subject and subject alternative names that
- * meet the specified name constraints.
- * <p>
- * 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.
- *
- * <pre><code>
- * 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}
- * </code></pre>
- * <p>
- * Note that the byte array supplied here is cloned to protect against
- * subsequent modifications.
- *
- * @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.
- * @throws IOException if a parsing error occurs
- * @see #getNameConstraints
- */
- public void setNameConstraints(byte[] bytes) throws IOException {
- if (bytes == null) {
- ncBytes = null;
- nc = null;
- } else {
- ncBytes = (byte[])bytes.clone();
- nc = new NameConstraintsExtension(FALSE, bytes);
- }
- }
-
- /**
- * 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.
- * <p>
- * 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
- * @throws IllegalArgumentException if the value is less than -2
- * @see #getBasicConstraints
- */
- public void setBasicConstraints(int minMaxPathLen) {
- if (minMaxPathLen < -2) {
- throw new IllegalArgumentException("basic constraints less than -2");
- }
- basicConstraints = minMaxPathLen;
- }
-
- /**
- * Sets the policy constraint. The <code>X509Certificate</code> must
- * include at least one of the specified policies in its certificate
- * policies extension. If <code>certPolicySet</code> is empty, then the
- * <code>X509Certificate</code> must include at least some specified policy
- * in its certificate policies extension. If <code>certPolicySet</code> is
- * <code>null</code>, no policy check will be performed.
- * <p>
- * Note that the <code>Set</code> is cloned to protect against
- * subsequent modifications.
- *
- * @param certPolicySet a <code>Set</code> of certificate policy OIDs in
- * string format (or <code>null</code>). Each OID is
- * represented by a set of nonnegative integers
- * separated by periods.
- * @throws 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) {
- policySet = null;
- policy = null;
- } else {
- // Snapshot set and parse it
- Set tempSet = Collections.unmodifiableSet(
- new HashSet(certPolicySet));
- /* Convert to Vector of ObjectIdentifiers */
- Iterator i = tempSet.iterator();
- Vector polIdVector = new Vector();
- while (i.hasNext()) {
- Object o = i.next();
- if (!(o instanceof String)) {
- throw new IOException("non String in certPolicySet");
- }
- polIdVector.add(new CertificatePolicyId(new ObjectIdentifier(
- (String)o)));
- }
- // If everything went OK, make the changes
- policySet = tempSet;
- policy = new CertificatePolicySet(polIdVector);
- }
- }
-
- /**
- * Sets the pathToNames criterion. The <code>X509Certificate</code> must
- * not include name constraints that would prohibit building a
- * path to the specified names.
- * <p>
- * 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.
- * <p>
- * 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.
- * <p>
- * 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 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. If <code>null</code>
- * is supplied as the value for this argument, no
- * pathToNames check will be performed.
- * <p>
- * 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)}.
- * <p>
- * 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 #getPathToNames getPathToNames} method.
- * <p>
- * Note that a deep copy is performed on the <code>Collection</code> to
- * protect against subsequent modifications.
- *
- * @param names a <code>Collection</code> with one entry per name
- * (or <code>null</code>)
- * @throws IOException if a parsing error occurs
- * @see #getPathToNames
- */
- public void setPathToNames(Collection names) throws IOException {
- if ((names == null) || names.isEmpty()) {
- pathToNames = null;
- pathToGeneralNames = null;
- } else {
- Set tempNames = cloneAndCheckNames(names);
- pathToGeneralNames = parseNames(tempNames);
- // Ensure that we either set both of these or neither
- pathToNames = tempNames;
- }
- }
-
- // called from CertPathHelper
- void setPathToNamesInternal(Set names) {
- // set names to non-null dummy value
- // this breaks getPathToNames()
- pathToNames = Collections.EMPTY_SET;
- pathToGeneralNames = names;
- }
-
- /**
- * 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.
- * <p>
- * 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.
- * <p>
- * 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 type, byte [] name)
- * addPathToName(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
- * @throws IOException if a parsing error occurs
- */
- public void addPathToName(int type, String name) throws IOException {
- addPathToNameInternal(type, name);
- }
-
- /**
- * 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.
- * <p>
- * 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.
- * <p>
- * 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 type, byte [] name)
- * addSubjectAlternativeName(int type, byte [] name)}.
- * <p>
- * Note that the byte array supplied here is cloned to protect against
- * subsequent modifications.
- *
- * @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
- * @throws IOException if a parsing error occurs
- */
- public void addPathToName(int type, byte [] name) throws IOException {
- // clone because byte arrays are modifiable
- addPathToNameInternal(type, name.clone());
- }
-
- /**
- * A private method that adds a name (String or byte array) to the
- * pathToNames criterion. The <code>X509Certificate</code> must contain
- * the specified pathToName.
- *
- * @param type the name type (0-8, as specified in
- * RFC 2459, section 4.2.1.7)
- * @param name the name in string or byte array form
- * @throws IOException if an encoding error occurs (incorrect form for DN)
- */
- private void addPathToNameInternal(int type, Object name)
- throws IOException {
- // First, ensure that the name parses
- GeneralNameInterface tempName = makeGeneralNameInterface(type, name);
- if (pathToGeneralNames == null) {
- pathToNames = new HashSet();
- pathToGeneralNames = new HashSet();
- }
- ArrayList list = new ArrayList(2);
- list.add(new Integer(type));
- list.add(name);
- pathToNames.add(list);
- pathToGeneralNames.add(tempName);
- }
-
- /**
- * Returns the certificateEquals criterion. The specified
- * <code>X509Certificate</code> must be equal to the
- * <code>X509Certificate</code> passed to the <code>match</code> method.
- * If <code>null</code>, this check is not applied.
- *
- * @return the <code>X509Certificate</code> to match (or <code>null</code>)
- * @see #setCertificate
- */
- 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
- */
- public BigInteger getSerialNumber() {
- return serialNumber;
- }
-
- // called from CertPathHelperImpl, to be made public in a future release
- X500Principal getIssuer() {
- return issuer;
- }
-
- /**
- * Returns the issuer criterion as a <code>String</code>. 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.
- * <p>
- * If the value returned is not <code>null</code>, it is a
- * distinguished name, in RFC 2253 format.
- *
- * @return the required issuer distinguished name in RFC 2253 format
- * (or <code>null</code>)
- */
- public String getIssuerAsString() {
- return (issuer == null ? null : issuer.getName());
- }
-
- /**
- * 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.
- * <p>
- * 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 [] issuerDN) setIssuer(byte [] issuerDN)}.
- * <p>
- * Note that the byte array returned is cloned to protect against
- * subsequent modifications.
- *
- * @return a byte array containing the required issuer distinguished name
- * in ASN.1 DER format (or <code>null</code>)
- * @throws IOException if an encoding error occurs
- */
- public byte[] getIssuerAsBytes() throws IOException {
- return (issuer == null ? null: issuer.getEncoded());
- }
-
- // called from CertPathHelperImpl, to be made public in a future release
- X500Principal getSubject() {
- return subject;
- }
-
- /**
- * Returns the subject criterion as a <code>String</code>. 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.
- * <p>
- * If the value returned is not <code>null</code>, it is a
- * distinguished name, in RFC 2253 format.
- *
- * @return the required subject distinguished name in RFC 2253 format
- * (or <code>null</code>)
- */
- public String getSubjectAsString() {
- return (subject == null ? null : subject.getName());
- }
-
- /**
- * 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.
- * <p>
- * 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)}.
- * <p>
- * Note that the byte array returned is cloned to protect against
- * subsequent modifications.
- *
- * @return a byte array containing the required subject distinguished name
- * in ASN.1 DER format (or <code>null</code>)
- * @throws IOException if an encoding error occurs
- */
- public byte[] getSubjectAsBytes() throws IOException {
- return (subject == null ? null : subject.getEncoded());
- }
-
- /**
- * 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.
- * <p>
- * 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 null;
- }
- return (byte[])subjectKeyID.clone();
- }
-
- /**
- * 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.
- * <p>
- * 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 null;
- }
- return (byte[])authorityKeyID.clone();
- }
-
- /**
- * 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.
- * <p>
- * 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 (certificateValid == null) {
- return null;
- }
- return (Date)certificateValid.clone();
- }
-
- /**
- * 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.
- * <p>
- * 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 null;
- }
- return (Date)privateKeyValid.clone();
- }
-
- /**
- * 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 (subjectPublicKeyAlgID == null) {
- return null;
- }
- return subjectPublicKeyAlgID.toString();
- }
-
- /**
- * 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.
- * <p>
- * 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 null;
- }
- return (boolean[])keyUsage.clone();
- }
-
- /**
- * 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() {
- return keyPurposeSet;
- }
-
- /**
- * 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.
- * <p>
- * 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).
- * <p>
- * 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)}.
- * <p>
- * 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 (subjectAlternativeNames == null) {
- return null;
- }
- return cloneNames(subjectAlternativeNames);
- }
-
- /**
- * Clone an object of the form passed to
- * setSubjectAlternativeNames and setPathToNames.
- * Throw a <code>RuntimeException</code> if the argument is malformed.
- * <p>
- * This method wraps cloneAndCheckNames, changing any
- * <code>IOException</code> into a <code>RuntimeException</code>. This
- * method should be used when the object being
- * cloned has already been checked, so there should never be any exceptions.
- *
- * @param names a <code>Collection</code> with one entry per name.
- * Each entry is a <code>List</code> whose first entry
- * is an Integer (the name type, 0-8) and whose second
- * entry is a String or a byte array (the name, in
- * string or ASN.1 DER encoded form, respectively).
- * There can be multiple names of the same type. Null
- * is not an acceptable value.
- * @return a deep copy of the specified <code>Collection</code>
- * @throws RuntimeException if a parsing error occurs
- */
- private static Set cloneNames(Collection names) {
- try {
- return cloneAndCheckNames(names);
- } catch (IOException e) {
- throw new RuntimeException("cloneNames encountered IOException: " +
- e.getMessage());
- }
- }
-
- /**
- * Clone and check an argument of the form passed to
- * setSubjectAlternativeNames and setPathToNames.
- * Throw an <code>IOException</code> if the argument is malformed.
- *
- * @param names a <code>Collection</code> with one entry per name.
- * Each entry is a <code>List</code> whose first entry
- * is an Integer (the name type, 0-8) and whose second
- * entry is a String or a byte array (the name, in
- * string or ASN.1 DER encoded form, respectively).
- * There can be multiple names of the same type.
- * <code>null</code> is not an acceptable value.
- * @return a deep copy of the specified <code>Collection</code>
- * @throws IOException if a parsing error occurs
- */
- private static Set cloneAndCheckNames(Collection names) throws IOException {
- // Copy the Lists and Collection
- Set namesCopy = new HashSet();
- Iterator i = names.iterator();
- while (i.hasNext()) {
- Object o = i.next();
- if (!(o instanceof List)) {
- throw new IOException("expected a List");
- }
- namesCopy.add(new ArrayList((List) o));
- }
-
- // Check the contents of the Lists and clone any byte arrays
- i = namesCopy.iterator();
- while (i.hasNext()) {
- List nameList = (List) i.next();
- if (nameList.size() != 2) {
- throw new IOException("name list size not 2");
- }
- Object o = nameList.get(0);
- if (!(o instanceof Integer)) {
- throw new IOException("expected an Integer");
- }
- int nameType = ((Integer) o).intValue();
- if ((nameType < 0) || (nameType > 8)) {
- throw new IOException("name type not 0-8");
- }
- Object nameObject = nameList.get(1);
- if (!(nameObject instanceof byte[]) &&
- !(nameObject instanceof String)) {
- if (debug != null) {
- debug.println("X509CertSelector.cloneAndCheckNames() "
- + "name not byte array");
- }
- throw new IOException("name not byte array or String");
- }
- if (nameObject instanceof byte[]) {
- nameList.set(1, ((byte[]) nameObject).clone());
- }
- }
- return namesCopy;
- }
-
- /**
- * Returns the name constraints criterion. The <code>X509Certificate</code>
- * must have subject and subject alternative names that
- * meet the specified name constraints.
- * <p>
- * 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)}.
- * <p>
- * Note that the byte array returned is cloned to protect against
- * subsequent modifications.
- *
- * @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.
- * @see #setNameConstraints
- */
- public byte[] getNameConstraints() {
- if (ncBytes == null) {
- return null;
- } else {
- return (byte[]) ncBytes.clone();
- }
- }
-
- /**
- * 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 basicConstraints;
- }
-
- /**
- * 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() {
- return policySet;
- }
-
- /**
- * 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.
- * <p>
- * 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).
- * <p>
- * 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)}.
- * <p>
- * 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;
- }
- return cloneNames(pathToNames);
- }
-
- /**
- * Return a printable representation of the <code>CertSelector</code>.
- *
- * @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: " + x509Cert.toString() + "\n");
- }
- if (serialNumber != null) {
- sb.append(" Serial Number: " + serialNumber.toString() + "\n");
- }
- if (issuer != null) {
- sb.append(" Issuer: " + getIssuerAsString() + "\n");
- }
- if (subject != null) {
- sb.append(" Subject: " + getSubjectAsString() + "\n");
- }
- sb.append(" matchAllSubjectAltNames flag: "
- + String.valueOf(matchAllSubjectAltNames) + "\n");
- if (subjectAlternativeNames != null) {
- sb.append(" SubjectAlternativeNames:\n");
- Iterator i = subjectAlternativeNames.iterator();
- while (i.hasNext()) {
- List list = (List) i.next();
- sb.append(" type " + list.get(0) +
- ", name " + list.get(1) + "\n");
- }
- }
- if (subjectKeyID != null) {
- HexDumpEncoder enc = new HexDumpEncoder();
- sb.append(" Subject Key Identifier: " +
- enc.encodeBuffer(subjectKeyID) + "\n");
- }
- if (authorityKeyID != null) {
- HexDumpEncoder enc = new HexDumpEncoder();
- sb.append(" Authority Key Identifier: " +
- enc.encodeBuffer(authorityKeyID) + "\n");
- }
- if (certificateValid != null) {
- sb.append(" Certificate Valid: " +
- certificateValid.toString() + "\n");
- }
- if (privateKeyValid != null) {
- sb.append(" Private Key Valid: " +
- privateKeyValid.toString() + "\n");
- }
- if (subjectPublicKeyAlgID != null) {
- sb.append(" Subject Public Key AlgID: " +
- subjectPublicKeyAlgID.toString() + "\n");
- }
- if (subjectPublicKey != null) {
- sb.append(" Subject Public Key: " +
- subjectPublicKey.toString() + "\n");
- }
- if (keyUsage != null) {
- sb.append(" Key Usage: " + keyUsageToString(keyUsage) + "\n");
- }
- if (keyPurposeSet != null) {
- sb.append(" Extended Key Usage: " +
- keyPurposeSet.toString() + "\n");
- }
- if (policy != null) {
- sb.append(" Policy: " + policy.toString() + "\n");
- }
- if (pathToGeneralNames != null) {
- sb.append(" Path to names:\n");
- Iterator i = pathToGeneralNames.iterator();
- while (i.hasNext()) {
- sb.append(" " + i.next() + "\n");
- }
- }
- sb.append("]");
- return sb.toString();
- }
-
- // Copied from sun.security.x509.KeyUsageExtension
- // (without calling the superclass)
- /**
- * Returns a printable representation of the KeyUsage.
- */
- private static String keyUsageToString(boolean[] k) {
- String s = "KeyUsage [\n";
- try {
- if (k[0]) {
- s += " DigitalSignature\n";
- }
- if (k[1]) {
- s += " Non_repudiation\n";
- }
- if (k[2]) {
- s += " Key_Encipherment\n";
- }
- if (k[3]) {
- s += " Data_Encipherment\n";
- }
- if (k[4]) {
- s += " Key_Agreement\n";
- }
- if (k[5]) {
- s += " Key_CertSign\n";
- }
- if (k[6]) {
- s += " Crl_Sign\n";
- }
- if (k[7]) {
- s += " Encipher_Only\n";
- }
- if (k[8]) {
- s += " Decipher_Only\n";
- }
- } catch (ArrayIndexOutOfBoundsException ex) {}
-
- s += "]\n";
-
- return (s);
- }
-
- /**
- * Returns an Extension object given any X509Certificate and extension oid.
- * Throw an <code>IOException</code> if the extension byte value is
- * malformed.
- *
- * @param cert a <code>X509Certificate</code>
- * @param extId an <code>integer</code> which specifies the extension index.
- * Currently, the supported extensions are as follows:
- * index 0 - PrivateKeyUsageExtension
- * index 1 - SubjectAlternativeNameExtension
- * index 2 - NameConstraintsExtension
- * index 3 - CertificatePoliciesExtension
- * index 4 - ExtendedKeyUsageExtension
- * @return an <code>Extension</code> object whose real type is as specified
- * by the extension oid.
- * @throws IOException if cannot construct the <code>Extension</code>
- * object with the extension encoding retrieved from the passed in
- * <code>X509Certificate</code>.
- */
- private static Extension getExtensionObject(X509Certificate cert, int extId)
- throws IOException {
- if (cert instanceof X509CertImpl) {
- X509CertImpl impl = (X509CertImpl)cert;
- switch (extId) {
- case PRIVATE_KEY_USAGE_ID:
- return impl.getPrivateKeyUsageExtension();
- case SUBJECT_ALT_NAME_ID:
- return impl.getSubjectAlternativeNameExtension();
- case NAME_CONSTRAINTS_ID:
- return impl.getNameConstraintsExtension();
- case CERT_POLICIES_ID:
- return impl.getCertificatePoliciesExtension();
- case EXTENDED_KEY_USAGE_ID:
- return impl.getExtendedKeyUsageExtension();
- default:
- return null;
- }
- }
- byte[] rawExtVal = cert.getExtensionValue(EXTENSION_OIDS[extId]);
- if (rawExtVal == null) {
- return null;
- }
- DerInputStream in = new DerInputStream(rawExtVal);
- byte[] encoded = in.getOctetString();
- switch (extId) {
- case PRIVATE_KEY_USAGE_ID:
- try {
- return new PrivateKeyUsageExtension(FALSE, encoded);
- } catch (CertificateException ex) {
- throw new IOException(ex.getMessage());
- }
- case SUBJECT_ALT_NAME_ID:
- return new SubjectAlternativeNameExtension(FALSE, encoded);
- case NAME_CONSTRAINTS_ID:
- return new NameConstraintsExtension(FALSE, encoded);
- case CERT_POLICIES_ID:
- return new CertificatePoliciesExtension(FALSE, encoded);
- case EXTENDED_KEY_USAGE_ID:
- return new ExtendedKeyUsageExtension(FALSE, encoded);
- default:
- return null;
- }
- }
-
- /**
- * Decides whether a <code>Certificate</code> should be selected.
- *
- * @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) {
- if (!(cert instanceof X509Certificate)) {
- return false;
- }
- X509Certificate xcert = (X509Certificate)cert;
-
- if (debug != null) {
- debug.println("X509CertSelector.match(SN: "
- + (xcert.getSerialNumber()).toString(16) + "\n Issuer: "
- + xcert.getIssuerDN() + "\n Subject: " + xcert.getSubjectDN()
- + ")");
- }
-
- /* match on X509Certificate */
- if (x509Cert != null) {
- if (!x509Cert.equals(xcert)) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "certs don't match");
- }
- return false;
- }
- }
-
- /* match on serial number */
- if (serialNumber != null) {
- if (!serialNumber.equals(xcert.getSerialNumber())) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "serial numbers don't match");
- }
- return false;
- }
- }
-
- /* match on issuer name */
- if (issuer != null) {
- if (!issuer.equals(xcert.getIssuerX500Principal())) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "issuer DNs don't match");
- }
- return false;
- }
- }
-
- /* match on subject name */
- if (subject != null) {
- if (!subject.equals(xcert.getSubjectX500Principal())) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "subject DNs don't match");
- }
- return false;
- }
- }
-
- /* match on certificate validity range */
- if (certificateValid != null) {
- try {
- xcert.checkValidity(certificateValid);
- } catch (CertificateException e) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "certificate not within validity period");
- }
- return false;
- }
- }
-
- /* match on subject public key */
- if (subjectPublicKeyBytes != null) {
- byte[] certKey = xcert.getPublicKey().getEncoded();
- if (!Arrays.equals(subjectPublicKeyBytes, certKey)) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "subject public keys don't match");
- }
- return false;
- }
- }
-
- boolean result = matchBasicConstraints(xcert)
- && matchKeyUsage(xcert)
- && matchExtendedKeyUsage(xcert)
- && matchSubjectKeyID(xcert)
- && matchAuthorityKeyID(xcert)
- && matchPrivateKeyValid(xcert)
- && matchSubjectPublicKeyAlgID(xcert)
- && matchPolicy(xcert)
- && matchSubjectAlternativeNames(xcert)
- && matchPathToNames(xcert)
- && matchNameConstraints(xcert);
-
- if (result && (debug != null)) {
- debug.println("X509CertSelector.match returning: true");
- }
- return result;
- }
-
- /* match on subject key identifier extension value */
- private boolean matchSubjectKeyID(X509Certificate xcert) {
- if (subjectKeyID == null) {
- return true;
- }
- try {
- byte[] extVal = xcert.getExtensionValue("2.5.29.14");
- if (extVal == null) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "no subject key ID extension");
- }
- return false;
- }
- DerInputStream in = new DerInputStream(extVal);
- byte[] certSubjectKeyID = in.getOctetString();
- if (certSubjectKeyID == null ||
- !Arrays.equals(subjectKeyID, certSubjectKeyID)) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "subject key IDs don't match");
- }
- return false;
- }
- } catch (IOException ex) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "exception in subject key ID check");
- }
- return false;
- }
- return true;
- }
-
- /* match on authority key identifier extension value */
- private boolean matchAuthorityKeyID(X509Certificate xcert) {
- if (authorityKeyID == null) {
- return true;
- }
- try {
- byte[] extVal = xcert.getExtensionValue("2.5.29.35");
- if (extVal == null) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "no authority key ID extension");
- }
- return false;
- }
- DerInputStream in = new DerInputStream(extVal);
- byte[] certAuthKeyID = in.getOctetString();
- if (certAuthKeyID == null ||
- !Arrays.equals(authorityKeyID, certAuthKeyID)) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "authority key IDs don't match");
- }
- return false;
- }
- } catch (IOException ex) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "exception in authority key ID check");
- }
- return false;
- }
- return true;
- }
-
- /* match on private key usage range */
- private boolean matchPrivateKeyValid(X509Certificate xcert) {
- if (privateKeyValid == null) {
- return true;
- }
- PrivateKeyUsageExtension ext = null;
- try {
- ext = (PrivateKeyUsageExtension)
- getExtensionObject(xcert, PRIVATE_KEY_USAGE_ID);
- if (ext != null) {
- ext.valid(privateKeyValid);
- }
- } catch (CertificateExpiredException e1) {
- if (debug != null) {
- String time = "n/a";
- try {
- Date notAfter =
- (Date)ext.get(PrivateKeyUsageExtension.NOT_AFTER);
- time = notAfter.toString();
- } catch (CertificateException ex) {
- // not able to retrieve notAfter value
- }
- debug.println("X509CertSelector.match: private key usage not "
- + "within validity date; ext.NOT_After: "
- + time + "; X509CertSelector: "
- + this.toString());
- e1.printStackTrace();
- }
- return false;
- } catch (CertificateNotYetValidException e2) {
- if (debug != null) {
- String time = "n/a";
- try {
- Date notBefore = (Date)
- ext.get(PrivateKeyUsageExtension.NOT_BEFORE);
- time = notBefore.toString();
- } catch (CertificateException ex) {
- // not able to retrieve notBefore value
- }
- debug.println("X509CertSelector.match: private key usage not "
- + "within validity date; ext.NOT_BEFORE: "
- + time + "; X509CertSelector: "
- + this.toString());
- e2.printStackTrace();
- }
- return false;
- } catch (CertificateException e3) {
- if (debug != null) {
- debug.println("X509CertSelector.match: CertificateException "
- + "in private key usage check; X509CertSelector: "
- + this.toString());
- e3.printStackTrace();
- }
- return false;
- } catch (IOException e4) {
- if (debug != null) {
- debug.println("X509CertSelector.match: IOException in "
- + "private key usage check; X509CertSelector: "
- + this.toString());
- e4.printStackTrace();
- }
- return false;
- }
- return true;
- }
-
- /* match on subject public key algorithm OID */
- private boolean matchSubjectPublicKeyAlgID(X509Certificate xcert) {
- if (subjectPublicKeyAlgID == null) {
- return true;
- }
- try {
- byte[] encodedKey = xcert.getPublicKey().getEncoded();
- DerValue val = new DerValue(encodedKey);
- if (val.tag != DerValue.tag_Sequence) {
- throw new IOException("invalid key format");
- }
-
- AlgorithmId algID = AlgorithmId.parse(val.data.getDerValue());
- if (debug != null) {
- debug.println("X509CertSelector.match: subjectPublicKeyAlgID = "
- + subjectPublicKeyAlgID + ", xcert subjectPublicKeyAlgID = "
- + algID.getOID());
- }
- if (!subjectPublicKeyAlgID.equals(algID.getOID())) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "subject public key alg IDs don't match");
- }
- return false;
- }
- } catch (IOException e5) {
- if (debug != null) {
- debug.println("X509CertSelector.match: IOException in subject "
- + "public key algorithm OID check");
- }
- return false;
- }
- return true;
- }
-
- /* match on key usage extension value */
- private boolean matchKeyUsage(X509Certificate xcert) {
- if (keyUsage == null) {
- return true;
- }
- boolean[] certKeyUsage = xcert.getKeyUsage();
- if (certKeyUsage != null) {
- for (int keyBit = 0; keyBit < keyUsage.length; keyBit++) {
- if (keyUsage[keyBit] &&
- ((keyBit >= certKeyUsage.length) || !certKeyUsage[keyBit])) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "key usage bits don't match");
- }
- return false;
- }
- }
- }
- return true;
- }
-
- /* match on extended key usage purpose OIDs */
- private boolean matchExtendedKeyUsage(X509Certificate xcert) {
- if ((keyPurposeSet == null) || keyPurposeSet.isEmpty()) {
- return true;
- }
- try {
- ExtendedKeyUsageExtension ext =
- (ExtendedKeyUsageExtension)getExtensionObject(xcert,
- EXTENDED_KEY_USAGE_ID);
- if (ext != null) {
- Vector certKeyPurposeVector =
- (Vector)ext.get(ExtendedKeyUsageExtension.USAGES);
- if (!certKeyPurposeVector.contains(ANY_EXTENDED_KEY_USAGE)
- && !certKeyPurposeVector.containsAll(keyPurposeOIDSet)) {
- if (debug != null) {
- debug.println("X509CertSelector.match: cert failed "
- + "extendedKeyUsage criterion");
- }
- return false;
- }
- }
- } catch (IOException ex) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "IOException in extended key usage check");
- }
- return false;
- }
- return true;
- }
-
- /* match on subject alternative name extension names */
- private boolean matchSubjectAlternativeNames(X509Certificate xcert) {
- if ((subjectAlternativeNames == null) || subjectAlternativeNames.isEmpty()) {
- return true;
- }
- try {
- SubjectAlternativeNameExtension sanExt =
- (SubjectAlternativeNameExtension) getExtensionObject(xcert,
- SUBJECT_ALT_NAME_ID);
- if (sanExt == null) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "no subject alternative name extension");
- }
- return false;
- }
- GeneralNames certNames = (GeneralNames)
- sanExt.get(SubjectAlternativeNameExtension.SUBJECT_NAME);
- Iterator i = subjectAlternativeGeneralNames.iterator();
- while (i.hasNext()) {
- GeneralNameInterface matchName = (GeneralNameInterface) i.next();
- boolean found = false;
- for (Iterator t = certNames.iterator(); t.hasNext() && !found; ) {
- GeneralNameInterface certName =
- ((GeneralName)t.next()).getName();
- found = certName.equals(matchName);
- }
- if (!found && (matchAllSubjectAltNames || !i.hasNext())) {
- if (debug != null) {
- debug.println("X509CertSelector.match: subject alternative "
- + "name " + matchName + " not found");
- }
- return false;
- } else if (found && !matchAllSubjectAltNames) {
- break;
- }
- }
- } catch (IOException ex) {
- if (debug != null)
- debug.println("X509CertSelector.match: IOException in subject "
- + "alternative name check");
- return false;
- }
- return true;
- }
-
- /* match on name constraints */
- private boolean matchNameConstraints(X509Certificate xcert) {
- if (nc == null) {
- return true;
- }
- try {
- if (!nc.verify(xcert)) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "name constraints not satisfied");
- }
- return false;
- }
- } catch (IOException e) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "IOException in name constraints check");
- }
- return false;
- }
- return true;
- }
-
- /* match on policy OIDs */
- private boolean matchPolicy(X509Certificate xcert) {
- if (policy == null) {
- return true;
- }
- try {
- CertificatePoliciesExtension ext = (CertificatePoliciesExtension)
- getExtensionObject(xcert, CERT_POLICIES_ID);
- if (ext == null) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "no certificate policy extension");
- }
- return false;
- }
- Vector policies = (Vector)ext.get(CertificatePoliciesExtension.POLICIES);
- /*
- * Convert the Vector of PolicyInformation to a Vector
- * of CertificatePolicyIds for easier comparison.
- */
- Vector policyOIDs = new Vector(policies.size());
- Enumeration e = policies.elements();
- while (e.hasMoreElements()) {
- policyOIDs.addElement(
- ((PolicyInformation)e.nextElement()).getPolicyIdentifier());
- }
- if (policy != null) {
- boolean foundOne = false;
- /*
- * if the user passes in an empty policy Set, then
- * we just want to make sure that the candidate certificate
- * has some policy OID in its CertPoliciesExtension
- */
- if (policy.getCertPolicyIds().isEmpty()) {
- if (policyOIDs.isEmpty()) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "cert failed policyAny criterion");
- }
- return false;
- }
- } else {
- for (Iterator e2 = policy.getCertPolicyIds().iterator();
- e2.hasNext() && !foundOne;) {
- if (policyOIDs.contains(e2.next())) {
- foundOne = true;
- }
- }
- if (!foundOne) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "cert failed policyAny criterion");
- }
- return false;
- }
- }
- }
- } catch (IOException ex) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "IOException in certificate policy ID check");
- }
- return false;
- }
- return true;
- }
-
- /* match on pathToNames */
- private boolean matchPathToNames(X509Certificate xcert) {
- if (pathToGeneralNames == null) {
- return true;
- }
- try {
- NameConstraintsExtension ext = (NameConstraintsExtension)
- getExtensionObject(xcert, NAME_CONSTRAINTS_ID);
- if (ext == null) {
- return true;
- }
- if ((debug != null) && debug.isOn("certpath")) {
- debug.println("X509CertSelector.match pathToNames:\n");
- Iterator i = pathToGeneralNames.iterator();
- while (i.hasNext()) {
- debug.println(" " + i.next() + "\n");
- }
- }
-
- GeneralSubtrees permitted = (GeneralSubtrees)
- ext.get(NameConstraintsExtension.PERMITTED_SUBTREES);
- GeneralSubtrees excluded = (GeneralSubtrees)
- ext.get(NameConstraintsExtension.EXCLUDED_SUBTREES);
- if (excluded != null) {
- if (matchExcluded(excluded) == false) {
- return false;
- }
- }
- if (permitted != null) {
- if (matchPermitted(permitted) == false) {
- return false;
- }
- }
- } catch (IOException ex) {
- if (debug != null) {
- debug.println("X509CertSelector.match: "
- + "IOException in name constraints check");
- }
- return false;
- }
- return true;
- }
-
- private boolean matchExcluded(GeneralSubtrees excluded) {
- /*
- * Enumerate through excluded and compare each entry
- * to all pathToNames. If any pathToName is within any of the
- * subtrees listed in excluded, return false.
- */
- for (Iterator t = excluded.iterator(); t.hasNext(); ) {
- GeneralSubtree tree = (GeneralSubtree)t.next();
- GeneralNameInterface excludedName = tree.getName().getName();
- Iterator i = pathToGeneralNames.iterator();
- while (i.hasNext()) {
- GeneralNameInterface pathToName = (GeneralNameInterface) i.next();
- if (excludedName.getType() == pathToName.getType()) {
- switch (pathToName.constrains(excludedName)) {
- case GeneralNameInterface.NAME_WIDENS:
- case GeneralNameInterface.NAME_MATCH:
- if (debug != null) {
- debug.println("X509CertSelector.match: name constraints "
- + "inhibit path to specified name");
- debug.println("X509CertSelector.match: excluded name: " +
- pathToName);
- }
- return false;
- default:
- }
- }
- }
- }
- return true;
- }
-
- private boolean matchPermitted(GeneralSubtrees permitted) {
- /*
- * Enumerate through pathToNames, checking that each pathToName
- * is in at least one of the subtrees listed in permitted.
- * If not, return false. However, if no subtrees of a given type
- * are listed, all names of that type are permitted.
- */
- Iterator i = pathToGeneralNames.iterator();
- while (i.hasNext()) {
- GeneralNameInterface pathToName = (GeneralNameInterface)i.next();
- Iterator t = permitted.iterator();
- boolean permittedNameFound = false;
- boolean nameTypeFound = false;
- String names = "";
- while (t.hasNext() && !permittedNameFound) {
- GeneralSubtree tree = (GeneralSubtree)t.next();
- GeneralNameInterface permittedName = tree.getName().getName();
- if (permittedName.getType() == pathToName.getType()) {
- nameTypeFound = true;
- names = names + " " + permittedName;
- switch (pathToName.constrains(permittedName)) {
- case GeneralNameInterface.NAME_WIDENS:
- case GeneralNameInterface.NAME_MATCH:
- permittedNameFound = true;
- break;
- default:
- }
- }
- }
- if (!permittedNameFound && nameTypeFound) {
- if (debug != null)
- debug.println("X509CertSelector.match: " +
- "name constraints inhibit path to specified name; " +
- "permitted names of type " + pathToName.getType() +
- ": " + names);
- return false;
- }
- }
- return true;
- }
-
- /* match on basic constraints */
- private boolean matchBasicConstraints(X509Certificate xcert) {
- if (basicConstraints == -1) {
- return true;
- }
- int maxPathLen = xcert.getBasicConstraints();
- if (basicConstraints == -2) {
- if (maxPathLen != -1) {
- if (debug != null) {
- debug.println("X509CertSelector.match: not an EE cert");
- }
- return false;
- }
- } else {
- if (maxPathLen < basicConstraints) {
- if (debug != null) {
- debug.println("X509CertSelector.match: maxPathLen too small ("
- + maxPathLen + " < " + basicConstraints + ")");
- }
- return false;
- }
- }
- return true;
- }
-
- private static Set cloneSet(Set set) {
- if (set instanceof HashSet) {
- Object clone = ((HashSet)set).clone();
- return (Set)clone;
- } else {
- return new HashSet(set);
- }
- }
-
- /**
- * Returns a copy of this object.
- *
- * @return the copy
- */
- public Object clone() {
- try {
- Object copy = super.clone();
- // Must clone these because addPathToName et al. modify them
- if (subjectAlternativeNames != null) {
- subjectAlternativeNames = cloneSet(subjectAlternativeNames);
- subjectAlternativeGeneralNames =
- cloneSet(subjectAlternativeGeneralNames);
- }
- if (pathToGeneralNames != null) {
- pathToNames = cloneSet(pathToNames);
- pathToGeneralNames = cloneSet(pathToGeneralNames);
- }
- return copy;
- } catch (CloneNotSupportedException e) {
- /* Cannot happen */
- throw new InternalError(e.toString());
- }
- }
- }