/* | 
|
 * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. | 
|
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|
 * | 
|
 * This code is free software; you can redistribute it and/or modify it | 
|
 * under the terms of the GNU General Public License version 2 only, as | 
|
 * published by the Free Software Foundation.  Oracle designates this | 
|
 * particular file as subject to the "Classpath" exception as provided | 
|
 * by Oracle in the LICENSE file that accompanied this code. | 
|
 * | 
|
 * This code is distributed in the hope that it will be useful, but WITHOUT | 
|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
|
 * version 2 for more details (a copy is included in the LICENSE file that | 
|
 * accompanied this code). | 
|
 * | 
|
 * You should have received a copy of the GNU General Public License version | 
|
 * 2 along with this work; if not, write to the Free Software Foundation, | 
|
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|
 * | 
|
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|
 * or visit www.oracle.com if you need additional information or have any | 
|
 * questions. | 
|
*/  | 
|
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} that selects {@code X509Certificates} that | 
|
 * match all specified criteria. This class is particularly useful when | 
|
 * selecting certificates from a {@code CertStore} to build a | 
|
 * PKIX-compliant certification path. | 
|
 * <p> | 
|
 * When first constructed, an {@code X509CertSelector} has no criteria | 
|
 * enabled and each of the {@code get} methods return a default value | 
|
 * ({@code null}, or {@code -1} for the {@link #getBasicConstraints | 
|
 * getBasicConstraints} method). Therefore, the {@link #match match} | 
|
 * method would return {@code true} for any {@code X509Certificate}. | 
|
 * Typically, several criteria are enabled (by calling | 
|
 * {@link #setIssuer setIssuer} or | 
|
 * {@link #setKeyUsage setKeyUsage}, for instance) and then the | 
|
 * {@code X509CertSelector} 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} method | 
|
 * usually uniquely matches a single {@code X509Certificate}. 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 <a href="http://tools.ietf.org/html/rfc5280">RFC 5280: | 
|
 * Internet X.509 Public Key Infrastructure Certificate and CRL Profile</a> 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 | 
|
 * | 
|
 * @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<String> keyPurposeSet;  | 
|
private Set<ObjectIdentifier> keyPurposeOIDSet;  | 
|
private Set<List<?>> subjectAlternativeNames;  | 
|
private Set<GeneralNameInterface> subjectAlternativeGeneralNames;  | 
|
private CertificatePolicySet policy;  | 
|
private Set<String> policySet;  | 
|
private Set<List<?>> pathToNames;  | 
|
private Set<GeneralNameInterface> 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}. Initially, no criteria are set | 
|
     * so any {@code X509Certificate} will match. | 
|
*/  | 
|
    public X509CertSelector() { | 
|
// empty  | 
|
}  | 
|
    /** | 
|
     * Sets the certificateEquals criterion. The specified | 
|
     * {@code X509Certificate} must be equal to the | 
|
     * {@code X509Certificate} passed to the {@code match} method. | 
|
     * If {@code null}, 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} to match (or | 
|
     * {@code null}) | 
|
     * @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}. If {@code null}, any certificate | 
|
     * serial number will do. | 
|
     * | 
|
     * @param serial the certificate serial number to match | 
|
     *        (or {@code null}) | 
|
     * @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}. If {@code null}, any issuer | 
|
     * distinguished name will do. | 
|
     * | 
|
     * @param issuer a distinguished name as X500Principal | 
|
     *                 (or {@code null}) | 
|
     * @since 1.5 | 
|
*/  | 
|
public void setIssuer(X500Principal issuer) {  | 
|
this.issuer = issuer;  | 
|
}  | 
|
    /** | 
|
     * <strong>Denigrated</strong>, use {@linkplain #setIssuer(X500Principal)} | 
|
     * or {@linkplain #setIssuer(byte[])} instead. This method should not be | 
|
     * relied on as it can fail to match some certificates because of a loss of | 
|
     * encoding information in the | 
|
     * <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a> String form | 
|
     * of some distinguished names. | 
|
     * <p> | 
|
     * Sets the issuer criterion. The specified distinguished name | 
|
     * must match the issuer distinguished name in the | 
|
     * {@code X509Certificate}. If {@code null}, any issuer | 
|
     * distinguished name will do. | 
|
     * <p> | 
|
     * If {@code issuerDN} is not {@code null}, it should contain a | 
|
     * distinguished name, in RFC 2253 format. | 
|
     * | 
|
     * @param issuerDN a distinguished name in RFC 2253 format | 
|
     *                 (or {@code null}) | 
|
     * @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).asX500Principal();  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Sets the issuer criterion. The specified distinguished name | 
|
     * must match the issuer distinguished name in the | 
|
     * {@code X509Certificate}. If {@code null} is specified, | 
|
     * the issuer criterion is disabled and any issuer distinguished name will | 
|
     * do. | 
|
     * <p> | 
|
     * If {@code issuerDN} is not {@code null}, 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)) } | 
|
     * }</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}) | 
|
     * @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 new IOException("Invalid name", e);  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Sets the subject criterion. The specified distinguished name | 
|
     * must match the subject distinguished name in the | 
|
     * {@code X509Certificate}. If {@code null}, any subject | 
|
     * distinguished name will do. | 
|
     * | 
|
     * @param subject a distinguished name as X500Principal | 
|
     *                  (or {@code null}) | 
|
     * @since 1.5 | 
|
*/  | 
|
public void setSubject(X500Principal subject) {  | 
|
this.subject = subject;  | 
|
}  | 
|
    /** | 
|
     * <strong>Denigrated</strong>, use {@linkplain #setSubject(X500Principal)} | 
|
     * or {@linkplain #setSubject(byte[])} instead. This method should not be | 
|
     * relied on as it can fail to match some certificates because of a loss of | 
|
     * encoding information in the RFC 2253 String form of some distinguished | 
|
     * names. | 
|
     * <p> | 
|
     * Sets the subject criterion. The specified distinguished name | 
|
     * must match the subject distinguished name in the | 
|
     * {@code X509Certificate}. If {@code null}, any subject | 
|
     * distinguished name will do. | 
|
     * <p> | 
|
     * If {@code subjectDN} is not {@code null}, it should contain a | 
|
     * distinguished name, in RFC 2253 format. | 
|
     * | 
|
     * @param subjectDN a distinguished name in RFC 2253 format | 
|
     *                  (or {@code null}) | 
|
     * @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).asX500Principal();  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Sets the subject criterion. The specified distinguished name | 
|
     * must match the subject distinguished name in the | 
|
     * {@code X509Certificate}. If {@code null}, any subject | 
|
     * distinguished name will do. | 
|
     * <p> | 
|
     * If {@code subjectDN} is not {@code null}, 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}) | 
|
     * @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 new IOException("Invalid name", e);  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Sets the subjectKeyIdentifier criterion. The | 
|
     * {@code X509Certificate} must contain a SubjectKeyIdentifier | 
|
     * extension for which the contents of the extension | 
|
     * matches the specified criterion value. | 
|
     * If the criterion value is {@code null}, no | 
|
     * subjectKeyIdentifier check will be done. | 
|
     * <p> | 
|
     * If {@code subjectKeyID} is not {@code null}, 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. | 
|
     * | 
|
     * <pre>{@code | 
|
     * SubjectKeyIdentifier ::= KeyIdentifier | 
|
     * | 
|
     * KeyIdentifier ::= OCTET STRING | 
|
     * }</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}. 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}) | 
|
     * @see #getSubjectKeyIdentifier | 
|
*/  | 
|
    public void setSubjectKeyIdentifier(byte[] subjectKeyID) { | 
|
if (subjectKeyID == null) {  | 
|
this.subjectKeyID = null;  | 
|
        } else { | 
|
this.subjectKeyID = subjectKeyID.clone();  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Sets the authorityKeyIdentifier criterion. The | 
|
     * {@code X509Certificate} 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}, no | 
|
     * authorityKeyIdentifier check will be done. | 
|
     * <p> | 
|
     * If {@code authorityKeyID} is not {@code null}, 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. | 
|
     * | 
|
     * <pre>{@code | 
|
     * AuthorityKeyIdentifier ::= SEQUENCE { | 
|
     *    keyIdentifier             [0] KeyIdentifier           OPTIONAL, | 
|
     *    authorityCertIssuer       [1] GeneralNames            OPTIONAL, | 
|
     *    authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL  } | 
|
     * | 
|
     * KeyIdentifier ::= OCTET STRING | 
|
     * }</pre> | 
|
     * <p> | 
|
     * Authority key identifiers are not parsed by the | 
|
     * {@code X509CertSelector}.  Instead, the values are | 
|
     * compared using a byte-by-byte comparison. | 
|
     * <p> | 
|
     * When the {@code keyIdentifier} field of | 
|
     * {@code AuthorityKeyIdentifier} is populated, the value is | 
|
     * usually taken from the {@code SubjectKeyIdentifier} extension | 
|
     * in the issuer's certificate.  Note, however, that the result of | 
|
     * {@code X509Certificate.getExtensionValue(<SubjectKeyIdentifier Object | 
|
     * Identifier>)} on the issuer's certificate may NOT be used | 
|
     * directly as the input to {@code 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 | 
|
     * {@code SubjectKeyIdentifier} | 
|
     * extension, it will be necessary to extract the value of the embedded | 
|
     * {@code KeyIdentifier} 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}) | 
|
     * @see #getAuthorityKeyIdentifier | 
|
*/  | 
|
    public void setAuthorityKeyIdentifier(byte[] authorityKeyID) { | 
|
if (authorityKeyID == null) {  | 
|
this.authorityKeyID = null;  | 
|
        } else { | 
|
this.authorityKeyID = authorityKeyID.clone();  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Sets the certificateValid criterion. The specified date must fall | 
|
     * within the certificate validity period for the | 
|
     * {@code X509Certificate}. If {@code null}, no certificateValid | 
|
     * check will be done. | 
|
     * <p> | 
|
     * Note that the {@code Date} supplied here is cloned to protect | 
|
     * against subsequent modifications. | 
|
     * | 
|
     * @param certValid the {@code Date} to check (or {@code null}) | 
|
     * @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}. If {@code null}, no privateKeyValid | 
|
     * check will be done. | 
|
     * <p> | 
|
     * Note that the {@code Date} supplied here is cloned to protect | 
|
     * against subsequent modifications. | 
|
     * | 
|
     * @param privateKeyValid the {@code Date} to check (or | 
|
     *                        {@code null}) | 
|
     * @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} must contain a subject public key | 
|
     * with the specified algorithm. If {@code null}, no | 
|
     * subjectPublicKeyAlgID check will be done. | 
|
     * | 
|
     * @param oid The object identifier (OID) of the algorithm to check | 
|
     *            for (or {@code null}). 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} must contain the specified subject public | 
|
     * key. If {@code null}, no subjectPublicKey check will be done. | 
|
     * | 
|
     * @param key the subject public key to check for (or {@code null}) | 
|
     * @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} | 
|
     * must contain the specified subject public key. If {@code null}, | 
|
     * 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} is not {@code null}, 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 | 
|
     * }</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}) | 
|
     * @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 = key.clone();  | 
|
subjectPublicKey = X509Key.parse(new DerValue(subjectPublicKeyBytes));  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Sets the keyUsage criterion. The {@code X509Certificate} | 
|
     * must allow the specified keyUsage values. If {@code null}, no | 
|
     * keyUsage check will be done. Note that an {@code X509Certificate} | 
|
     * 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}. | 
|
     * @see #getKeyUsage | 
|
*/  | 
|
    public void setKeyUsage(boolean[] keyUsage) { | 
|
if (keyUsage == null) {  | 
|
this.keyUsage = null;  | 
|
        } else { | 
|
this.keyUsage = keyUsage.clone();  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Sets the extendedKeyUsage criterion. The {@code X509Certificate} | 
|
     * must allow the specified key purposes in its extended key usage | 
|
     * extension. If {@code keyPurposeSet} is empty or {@code null}, | 
|
     * no extendedKeyUsage check will be done. Note that an | 
|
     * {@code X509Certificate} that has no extendedKeyUsage extension | 
|
     * implicitly allows all key purposes. | 
|
     * <p> | 
|
     * Note that the {@code Set} is cloned to protect against | 
|
     * subsequent modifications. | 
|
     * | 
|
     * @param keyPurposeSet a {@code Set} of key purpose OIDs in string | 
|
     * format (or {@code null}). 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<String> keyPurposeSet) throws IOException {  | 
|
if ((keyPurposeSet == null) || keyPurposeSet.isEmpty()) {  | 
|
this.keyPurposeSet = null;  | 
|
keyPurposeOIDSet = null;  | 
|
        } else { | 
|
this.keyPurposeSet =  | 
|
Collections.unmodifiableSet(new HashSet<String>(keyPurposeSet));  | 
|
keyPurposeOIDSet = new HashSet<ObjectIdentifier>();  | 
|
for (String s : this.keyPurposeSet) {  | 
|
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} must contain all of the | 
|
     * specified subject alternative names. If disabled, the | 
|
     * {@code X509Certificate} must contain at least one of the | 
|
     * specified subject alternative names. | 
|
     * | 
|
     * <p>The matchAllNames flag is {@code true} by default. | 
|
     * | 
|
     * @param matchAllNames if {@code true}, the flag is enabled; | 
|
     * if {@code false}, the flag is disabled. | 
|
     * @see #getMatchAllSubjectAltNames | 
|
*/  | 
|
    public void setMatchAllSubjectAltNames(boolean matchAllNames) { | 
|
this.matchAllSubjectAltNames = matchAllNames;  | 
|
}  | 
|
    /** | 
|
     * Sets the subjectAlternativeNames criterion. The | 
|
     * {@code X509Certificate} 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} parameter (if not {@code null}) is a | 
|
     * {@code Collection} with one | 
|
     * entry for each name to be included in the subject alternative name | 
|
     * criterion. Each entry is a {@code List} whose first entry is an | 
|
     * {@code Integer} (the name type, 0-8) and whose second | 
|
     * entry is a {@code 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. If {@code null} | 
|
     * is supplied as the value for this argument, no | 
|
     * subjectAlternativeNames check will be performed. | 
|
     * <p> | 
|
     * Each subject alternative name in the {@code Collection} | 
|
     * may be specified either as a {@code String} 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> | 
|
     * <strong>Note:</strong> for distinguished names, specify the byte | 
|
     * array form instead of the String form. See the note in | 
|
     * {@link #addSubjectAlternativeName(int, String)} for more information. | 
|
     * <p> | 
|
     * Note that the {@code names} parameter can contain duplicate | 
|
     * names (same name and name type), but they may be removed from the | 
|
     * {@code Collection} of names returned by the | 
|
     * {@link #getSubjectAlternativeNames getSubjectAlternativeNames} method. | 
|
     * <p> | 
|
     * Note that a deep copy is performed on the {@code Collection} to | 
|
     * protect against subsequent modifications. | 
|
     * | 
|
     * @param names a {@code Collection} of names (or {@code null}) | 
|
     * @throws IOException if a parsing error occurs | 
|
     * @see #getSubjectAlternativeNames | 
|
*/  | 
|
public void setSubjectAlternativeNames(Collection<List<?>> names)  | 
|
throws IOException {  | 
|
if (names == null) {  | 
|
subjectAlternativeNames = null;  | 
|
subjectAlternativeGeneralNames = null;  | 
|
        } else { | 
|
if (names.isEmpty()) {  | 
|
subjectAlternativeNames = null;  | 
|
subjectAlternativeGeneralNames = null;  | 
|
return;  | 
|
}  | 
|
Set<List<?>> 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} 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. | 
|
     * <a href="http://www.ietf.org/rfc/rfc822.txt">RFC 822</a>, DNS, and URI | 
|
     * names use the well-established string formats for those types (subject to | 
|
     * the restrictions included in RFC 5280). 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. | 
|
     * <p> | 
|
     * <strong>Note:</strong> for distinguished names, use | 
|
     * {@linkplain #addSubjectAlternativeName(int, byte[])} instead. | 
|
     * This method should not be relied on as it can fail to match some | 
|
     * certificates because of a loss of encoding information in the RFC 2253 | 
|
     * String form of some distinguished names. | 
|
     * | 
|
     * @param type the name type (0-8, as specified in | 
|
     *             RFC 5280, section 4.2.1.6) | 
|
     * @param name the name in string form (not {@code null}) | 
|
     * @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} 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 5280 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} | 
|
     * }</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} | 
|
     * must contain the specified subjectAlternativeName. | 
|
     * | 
|
     * @param type the name type (0-8, as specified in | 
|
     *             RFC 5280, section 4.2.1.6) | 
|
     * @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<List<?>>();  | 
|
}  | 
|
if (subjectAlternativeGeneralNames == null) {  | 
|
subjectAlternativeGeneralNames = new HashSet<GeneralNameInterface>();  | 
|
}  | 
|
List<Object> list = new ArrayList<Object>(2);  | 
|
list.add(Integer.valueOf(type));  | 
|
list.add(name);  | 
|
subjectAlternativeNames.add(list);  | 
|
subjectAlternativeGeneralNames.add(tempName);  | 
|
}  | 
|
    /** | 
|
     * Parse an argument of the form passed to setSubjectAlternativeNames, | 
|
     * returning a {@code Collection} of | 
|
     * {@code GeneralNameInterface}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} 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}s | 
|
     * @throws IOException if a parsing error occurs | 
|
*/  | 
|
private static Set<GeneralNameInterface> parseNames(Collection<List<?>> names) throws IOException {  | 
|
Set<GeneralNameInterface> genNames = new HashSet<GeneralNameInterface>();  | 
|
for (List<?> nameList : names) {  | 
|
            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();  | 
|
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} or a | 
|
     * {@code ClassCastException} 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} 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);  | 
|
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} | 
|
     * 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 5280 | 
|
     * 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} | 
|
     * }</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}, | 
|
     *              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 = bytes.clone();  | 
|
nc = new NameConstraintsExtension(FALSE, bytes);  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Sets the basic constraints constraint. If the value is greater than or | 
|
     * equal to zero, {@code X509Certificates} 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} must | 
|
     * include at least one of the specified policies in its certificate | 
|
     * policies extension. If {@code certPolicySet} is empty, then the | 
|
     * {@code X509Certificate} must include at least some specified policy | 
|
     * in its certificate policies extension. If {@code certPolicySet} is | 
|
     * {@code null}, no policy check will be performed. | 
|
     * <p> | 
|
     * Note that the {@code Set} is cloned to protect against | 
|
     * subsequent modifications. | 
|
     * | 
|
     * @param certPolicySet a {@code Set} of certificate policy OIDs in | 
|
     *                      string format (or {@code null}). 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<String> certPolicySet) throws IOException {  | 
|
if (certPolicySet == null) {  | 
|
policySet = null;  | 
|
policy = null;  | 
|
        } else { | 
|
            // Snapshot set and parse it | 
|
Set<String> tempSet = Collections.unmodifiableSet  | 
|
(new HashSet<String>(certPolicySet));  | 
|
            /* Convert to Vector of ObjectIdentifiers */ | 
|
Iterator<String> i = tempSet.iterator();  | 
|
Vector<CertificatePolicyId> polIdVector = new Vector<CertificatePolicyId>();  | 
|
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} 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}'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} parameter (if not {@code null}) is a | 
|
     * {@code Collection} with one | 
|
     * entry for each name to be included in the pathToNames | 
|
     * criterion. Each entry is a {@code List} whose first entry is an | 
|
     * {@code Integer} (the name type, 0-8) and whose second | 
|
     * entry is a {@code 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. If {@code null} | 
|
     * is supplied as the value for this argument, no | 
|
     * pathToNames check will be performed. | 
|
     * <p> | 
|
     * Each name in the {@code Collection} | 
|
     * may be specified either as a {@code String} 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> | 
|
     * <strong>Note:</strong> for distinguished names, specify the byte | 
|
     * array form instead of the String form. See the note in | 
|
     * {@link #addPathToName(int, String)} for more information. | 
|
     * <p> | 
|
     * Note that the {@code names} parameter can contain duplicate | 
|
     * names (same name and name type), but they may be removed from the | 
|
     * {@code Collection} of names returned by the | 
|
     * {@link #getPathToNames getPathToNames} method. | 
|
     * <p> | 
|
     * Note that a deep copy is performed on the {@code Collection} to | 
|
     * protect against subsequent modifications. | 
|
     * | 
|
     * @param names a {@code Collection} with one entry per name | 
|
     *              (or {@code null}) | 
|
     * @throws IOException if a parsing error occurs | 
|
     * @see #getPathToNames | 
|
*/  | 
|
public void setPathToNames(Collection<List<?>> names) throws IOException {  | 
|
if ((names == null) || names.isEmpty()) {  | 
|
pathToNames = null;  | 
|
pathToGeneralNames = null;  | 
|
        } else { | 
|
Set<List<?>> tempNames = cloneAndCheckNames(names);  | 
|
pathToGeneralNames = parseNames(tempNames);  | 
|
            // Ensure that we either set both of these or neither | 
|
pathToNames = tempNames;  | 
|
}  | 
|
}  | 
|
    // called from CertPathHelper | 
|
void setPathToNamesInternal(Set<GeneralNameInterface> names) {  | 
|
// set names to non-null dummy value  | 
|
        // this breaks getPathToNames() | 
|
pathToNames = Collections.<List<?>>emptySet();  | 
|
pathToGeneralNames = names;  | 
|
}  | 
|
    /** | 
|
     * Adds a name to the pathToNames criterion. The {@code X509Certificate} | 
|
     * 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}'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 5280). 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. | 
|
     * <p> | 
|
     * <strong>Note:</strong> for distinguished names, use | 
|
     * {@linkplain #addPathToName(int, byte[])} instead. | 
|
     * This method should not be relied on as it can fail to match some | 
|
     * certificates because of a loss of encoding information in the RFC 2253 | 
|
     * String form of some distinguished names. | 
|
     * | 
|
     * @param type the name type (0-8, as specified in | 
|
     *             RFC 5280, section 4.2.1.6) | 
|
     * @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} | 
|
     * 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}'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 5280 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 5280, section 4.2.1.6) | 
|
     * @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} must contain | 
|
     * the specified pathToName. | 
|
     * | 
|
     * @param type the name type (0-8, as specified in | 
|
     *             RFC 5280, section 4.2.1.6) | 
|
     * @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<List<?>>();  | 
|
pathToGeneralNames = new HashSet<GeneralNameInterface>();  | 
|
}  | 
|
List<Object> list = new ArrayList<Object>(2);  | 
|
list.add(Integer.valueOf(type));  | 
|
list.add(name);  | 
|
pathToNames.add(list);  | 
|
pathToGeneralNames.add(tempName);  | 
|
}  | 
|
    /** | 
|
     * Returns the certificateEquals criterion. The specified | 
|
     * {@code X509Certificate} must be equal to the | 
|
     * {@code X509Certificate} passed to the {@code match} method. | 
|
     * If {@code null}, this check is not applied. | 
|
     * | 
|
     * @return the {@code X509Certificate} to match (or {@code null}) | 
|
     * @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}. If {@code null}, any certificate | 
|
     * serial number will do. | 
|
     * | 
|
     * @return the certificate serial number to match | 
|
     *                (or {@code null}) | 
|
     * @see #setSerialNumber | 
|
*/  | 
|
public BigInteger getSerialNumber() {  | 
|
return serialNumber;  | 
|
}  | 
|
    /** | 
|
     * Returns the issuer criterion as an {@code X500Principal}. This | 
|
     * distinguished name must match the issuer distinguished name in the | 
|
     * {@code X509Certificate}. If {@code null}, the issuer criterion | 
|
     * is disabled and any issuer distinguished name will do. | 
|
     * | 
|
     * @return the required issuer distinguished name as X500Principal | 
|
     *         (or {@code null}) | 
|
     * @since 1.5 | 
|
*/  | 
|
public X500Principal getIssuer() {  | 
|
return issuer;  | 
|
}  | 
|
    /** | 
|
     * <strong>Denigrated</strong>, use {@linkplain #getIssuer()} or | 
|
     * {@linkplain #getIssuerAsBytes()} instead. This method should not be | 
|
     * relied on as it can fail to match some certificates because of a loss of | 
|
     * encoding information in the RFC 2253 String form of some distinguished | 
|
     * names. | 
|
     * <p> | 
|
     * Returns the issuer criterion as a {@code String}. This | 
|
     * distinguished name must match the issuer distinguished name in the | 
|
     * {@code X509Certificate}. If {@code null}, the issuer criterion | 
|
     * is disabled and any issuer distinguished name will do. | 
|
     * <p> | 
|
     * If the value returned is not {@code null}, it is a | 
|
     * distinguished name, in RFC 2253 format. | 
|
     * | 
|
     * @return the required issuer distinguished name in RFC 2253 format | 
|
     *         (or {@code null}) | 
|
*/  | 
|
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}. If {@code null}, the issuer criterion | 
|
     * is disabled and any issuer distinguished name will do. | 
|
     * <p> | 
|
     * If the value returned is not {@code null}, 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}) | 
|
     * @throws IOException if an encoding error occurs | 
|
*/  | 
|
public byte[] getIssuerAsBytes() throws IOException {  | 
|
return (issuer == null ? null: issuer.getEncoded());  | 
|
}  | 
|
    /** | 
|
     * Returns the subject criterion as an {@code X500Principal}. This | 
|
     * distinguished name must match the subject distinguished name in the | 
|
     * {@code X509Certificate}. If {@code null}, the subject criterion | 
|
     * is disabled and any subject distinguished name will do. | 
|
     * | 
|
     * @return the required subject distinguished name as X500Principal | 
|
     *         (or {@code null}) | 
|
     * @since 1.5 | 
|
*/  | 
|
public X500Principal getSubject() {  | 
|
return subject;  | 
|
}  | 
|
    /** | 
|
     * <strong>Denigrated</strong>, use {@linkplain #getSubject()} or | 
|
     * {@linkplain #getSubjectAsBytes()} instead. This method should not be | 
|
     * relied on as it can fail to match some certificates because of a loss of | 
|
     * encoding information in the RFC 2253 String form of some distinguished | 
|
     * names. | 
|
     * <p> | 
|
     * Returns the subject criterion as a {@code String}. This | 
|
     * distinguished name must match the subject distinguished name in the | 
|
     * {@code X509Certificate}. If {@code null}, the subject criterion | 
|
     * is disabled and any subject distinguished name will do. | 
|
     * <p> | 
|
     * If the value returned is not {@code null}, it is a | 
|
     * distinguished name, in RFC 2253 format. | 
|
     * | 
|
     * @return the required subject distinguished name in RFC 2253 format | 
|
     *         (or {@code null}) | 
|
*/  | 
|
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}. If {@code null}, the subject criterion | 
|
     * is disabled and any subject distinguished name will do. | 
|
     * <p> | 
|
     * If the value returned is not {@code null}, 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}) | 
|
     * @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} must contain a SubjectKeyIdentifier | 
|
     * extension with the specified value. If {@code null}, 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}) | 
|
     * @see #setSubjectKeyIdentifier | 
|
*/  | 
|
    public byte[] getSubjectKeyIdentifier() { | 
|
if (subjectKeyID == null) {  | 
|
return null;  | 
|
}  | 
|
return subjectKeyID.clone();  | 
|
}  | 
|
    /** | 
|
     * Returns the authorityKeyIdentifier criterion. The | 
|
     * {@code X509Certificate} must contain a AuthorityKeyIdentifier | 
|
     * extension with the specified value. If {@code null}, 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}) | 
|
     * @see #setAuthorityKeyIdentifier | 
|
*/  | 
|
    public byte[] getAuthorityKeyIdentifier() { | 
|
if (authorityKeyID == null) {  | 
|
return null;  | 
|
}  | 
|
return authorityKeyID.clone();  | 
|
}  | 
|
    /** | 
|
     * Returns the certificateValid criterion. The specified date must fall | 
|
     * within the certificate validity period for the | 
|
     * {@code X509Certificate}. If {@code null}, no certificateValid | 
|
     * check will be done. | 
|
     * <p> | 
|
     * Note that the {@code Date} returned is cloned to protect against | 
|
     * subsequent modifications. | 
|
     * | 
|
     * @return the {@code Date} to check (or {@code null}) | 
|
     * @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}. If {@code null}, no privateKeyValid | 
|
     * check will be done. | 
|
     * <p> | 
|
     * Note that the {@code Date} returned is cloned to protect against | 
|
     * subsequent modifications. | 
|
     * | 
|
     * @return the {@code Date} to check (or {@code null}) | 
|
     * @see #setPrivateKeyValid | 
|
*/  | 
|
public Date getPrivateKeyValid() {  | 
|
if (privateKeyValid == null) {  | 
|
return null;  | 
|
}  | 
|
return (Date)privateKeyValid.clone();  | 
|
}  | 
|
    /** | 
|
     * Returns the subjectPublicKeyAlgID criterion. The | 
|
     * {@code X509Certificate} must contain a subject public key | 
|
     * with the specified algorithm. If {@code null}, no | 
|
     * subjectPublicKeyAlgID check will be done. | 
|
     * | 
|
     * @return the object identifier (OID) of the signature algorithm to check | 
|
     *         for (or {@code null}). 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} must contain the specified subject | 
|
     * public key. If {@code null}, no subjectPublicKey check will be done. | 
|
     * | 
|
     * @return the subject public key to check for (or {@code null}) | 
|
     * @see #setSubjectPublicKey | 
|
*/  | 
|
public PublicKey getSubjectPublicKey() {  | 
|
return subjectPublicKey;  | 
|
}  | 
|
    /** | 
|
     * Returns the keyUsage criterion. The {@code X509Certificate} | 
|
     * 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}. | 
|
     * @see #setKeyUsage | 
|
*/  | 
|
    public boolean[] getKeyUsage() { | 
|
if (keyUsage == null) {  | 
|
return null;  | 
|
}  | 
|
return keyUsage.clone();  | 
|
}  | 
|
    /** | 
|
     * Returns the extendedKeyUsage criterion. The {@code X509Certificate} | 
|
     * must allow the specified key purposes in its extended key usage | 
|
     * extension. If the {@code keyPurposeSet} returned is empty or | 
|
     * {@code null}, no extendedKeyUsage check will be done. Note that an | 
|
     * {@code X509Certificate} that has no extendedKeyUsage extension | 
|
     * implicitly allows all key purposes. | 
|
     * | 
|
     * @return an immutable {@code Set} of key purpose OIDs in string | 
|
     * format (or {@code null}) | 
|
     * @see #setExtendedKeyUsage | 
|
*/  | 
|
public Set<String> getExtendedKeyUsage() {  | 
|
return keyPurposeSet;  | 
|
}  | 
|
    /** | 
|
     * Indicates if the {@code X509Certificate} must contain all | 
|
     * or at least one of the subjectAlternativeNames | 
|
     * specified in the {@link #setSubjectAlternativeNames | 
|
     * setSubjectAlternativeNames} or {@link #addSubjectAlternativeName | 
|
     * addSubjectAlternativeName} methods. If {@code true}, | 
|
     * the {@code X509Certificate} must contain all of the | 
|
     * specified subject alternative names. If {@code false}, the | 
|
     * {@code X509Certificate} must contain at least one of the | 
|
     * specified subject alternative names. | 
|
     * | 
|
     * @return {@code true} if the flag is enabled; | 
|
     * {@code false} if the flag is disabled. The flag is | 
|
     * {@code true} by default. | 
|
     * @see #setMatchAllSubjectAltNames | 
|
*/  | 
|
    public boolean getMatchAllSubjectAltNames() { | 
|
return matchAllSubjectAltNames;  | 
|
}  | 
|
    /** | 
|
     * Returns a copy of the subjectAlternativeNames criterion. | 
|
     * The {@code X509Certificate} 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}, no subjectAlternativeNames check will be performed. | 
|
     * <p> | 
|
     * If the value returned is not {@code null}, it is a | 
|
     * {@code Collection} with | 
|
     * one entry for each name to be included in the subject alternative name | 
|
     * criterion. Each entry is a {@code List} whose first entry is an | 
|
     * {@code Integer} (the name type, 0-8) and whose second | 
|
     * entry is a {@code 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.  Note that the | 
|
     * {@code Collection} returned may contain duplicate names (same name | 
|
     * and name type). | 
|
     * <p> | 
|
     * Each subject alternative name in the {@code Collection} | 
|
     * may be specified either as a {@code String} 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} to | 
|
     * protect against subsequent modifications. | 
|
     * | 
|
     * @return a {@code Collection} of names (or {@code null}) | 
|
     * @see #setSubjectAlternativeNames | 
|
*/  | 
|
public Collection<List<?>> getSubjectAlternativeNames() {  | 
|
if (subjectAlternativeNames == null) {  | 
|
return null;  | 
|
}  | 
|
return cloneNames(subjectAlternativeNames);  | 
|
}  | 
|
    /** | 
|
     * Clone an object of the form passed to | 
|
     * setSubjectAlternativeNames and setPathToNames. | 
|
     * Throw a {@code RuntimeException} if the argument is malformed. | 
|
     * <p> | 
|
     * This method wraps cloneAndCheckNames, changing any | 
|
     * {@code IOException} into a {@code RuntimeException}. 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} with one entry per name. | 
|
     *              Each entry is a {@code List} 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} | 
|
     * @throws RuntimeException if a parsing error occurs | 
|
*/  | 
|
private static Set<List<?>> cloneNames(Collection<List<?>> 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} if the argument is malformed. | 
|
     * | 
|
     * @param names a {@code Collection} with one entry per name. | 
|
     *              Each entry is a {@code List} 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} is not an acceptable value. | 
|
     * @return a deep copy of the specified {@code Collection} | 
|
     * @throws IOException if a parsing error occurs | 
|
*/  | 
|
private static Set<List<?>> cloneAndCheckNames(Collection<List<?>> names) throws IOException {  | 
|
        // Copy the Lists and Collection | 
|
Set<List<?>> namesCopy = new HashSet<List<?>>();  | 
|
for (List<?> o : names)  | 
|
        { | 
|
namesCopy.add(new ArrayList<Object>(o));  | 
|
}  | 
|
        // Check the contents of the Lists and clone any byte arrays | 
|
for (List<?> list : namesCopy) {  | 
|
@SuppressWarnings("unchecked") // See javadoc for parameter "names".  | 
|
List<Object> nameList = (List<Object>)list;  | 
|
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} | 
|
     * 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 5280 | 
|
     * 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} if no name constraints check will be performed. | 
|
     * @see #setNameConstraints | 
|
*/  | 
|
    public byte[] getNameConstraints() { | 
|
if (ncBytes == null) {  | 
|
return null;  | 
|
        } else { | 
|
return ncBytes.clone();  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Returns the basic constraints constraint. If the value is greater than | 
|
     * or equal to zero, the {@code X509Certificates} 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} must | 
|
     * include at least one of the specified policies in its certificate policies | 
|
     * extension. If the {@code Set} returned is empty, then the | 
|
     * {@code X509Certificate} must include at least some specified policy | 
|
     * in its certificate policies extension. If the {@code Set} returned is | 
|
     * {@code null}, no policy check will be performed. | 
|
     * | 
|
     * @return an immutable {@code Set} of certificate policy OIDs in | 
|
     *         string format (or {@code null}) | 
|
     * @see #setPolicy | 
|
*/  | 
|
public Set<String> getPolicy() {  | 
|
return policySet;  | 
|
}  | 
|
    /** | 
|
     * Returns a copy of the pathToNames criterion. The | 
|
     * {@code X509Certificate} must not include name constraints that would | 
|
     * prohibit building a path to the specified names. If the value | 
|
     * returned is {@code null}, no pathToNames check will be performed. | 
|
     * <p> | 
|
     * If the value returned is not {@code null}, it is a | 
|
     * {@code Collection} with one | 
|
     * entry for each name to be included in the pathToNames | 
|
     * criterion. Each entry is a {@code List} whose first entry is an | 
|
     * {@code Integer} (the name type, 0-8) and whose second | 
|
     * entry is a {@code 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. Note that the | 
|
     * {@code Collection} returned may contain duplicate names (same | 
|
     * name and name type). | 
|
     * <p> | 
|
     * Each name in the {@code Collection} | 
|
     * may be specified either as a {@code String} 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} to | 
|
     * protect against subsequent modifications. | 
|
     * | 
|
     * @return a {@code Collection} of names (or {@code null}) | 
|
     * @see #setPathToNames | 
|
*/  | 
|
public Collection<List<?>> getPathToNames() {  | 
|
if (pathToNames == null) {  | 
|
return null;  | 
|
}  | 
|
return cloneNames(pathToNames);  | 
|
}  | 
|
    /** | 
|
     * Return a printable representation of the {@code CertSelector}. | 
|
     * | 
|
     * @return a {@code String} describing the contents of the | 
|
     *         {@code CertSelector} | 
|
*/  | 
|
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<List<?>> i = subjectAlternativeNames.iterator();  | 
|
while (i.hasNext()) {  | 
|
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<GeneralNameInterface> 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} if the extension byte value is | 
|
     * malformed. | 
|
     * | 
|
     * @param cert a {@code X509Certificate} | 
|
     * @param extId an {@code integer} 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} object whose real type is as specified | 
|
     * by the extension oid. | 
|
     * @throws IOException if cannot construct the {@code Extension} | 
|
     * object with the extension encoding retrieved from the passed in | 
|
     * {@code X509Certificate}. | 
|
*/  | 
|
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} should be selected. | 
|
     * | 
|
     * @param cert the {@code Certificate} to be checked | 
|
     * @return {@code true} if the {@code Certificate} should be | 
|
     *         selected, {@code false} 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\nX509CertSelector.match: subjectKeyID: " + | 
|
Arrays.toString(subjectKeyID) +  | 
|
                        "\nX509CertSelector.match: certSubjectKeyID: " + | 
|
Arrays.toString(certSubjectKeyID));  | 
|
}  | 
|
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 = 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 = 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 (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((Object)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<ObjectIdentifier> certKeyPurposeVector =  | 
|
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 =  | 
|
sanExt.get(SubjectAlternativeNameExtension.SUBJECT_NAME);  | 
|
Iterator<GeneralNameInterface> i =  | 
|
subjectAlternativeGeneralNames.iterator();  | 
|
while (i.hasNext()) {  | 
|
GeneralNameInterface matchName = i.next();  | 
|
boolean found = false;  | 
|
for (Iterator<GeneralName> t = certNames.iterator();  | 
|
t.hasNext() && !found; ) {  | 
|
GeneralNameInterface certName = (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;  | 
|
}  | 
|
List<PolicyInformation> policies = ext.get(CertificatePoliciesExtension.POLICIES);  | 
|
            /* | 
|
             * Convert the Vector of PolicyInformation to a Vector | 
|
             * of CertificatePolicyIds for easier comparison. | 
|
*/  | 
|
List<CertificatePolicyId> policyIDs = new ArrayList<CertificatePolicyId>(policies.size());  | 
|
for (PolicyInformation info : policies) {  | 
|
policyIDs.add(info.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 (policyIDs.isEmpty()) {  | 
|
if (debug != null) {  | 
|
debug.println("X509CertSelector.match: "  | 
|
                                + "cert failed policyAny criterion"); | 
|
}  | 
|
return false;  | 
|
}  | 
|
                } else { | 
|
for (CertificatePolicyId id : policy.getCertPolicyIds()) {  | 
|
if (policyIDs.contains(id)) {  | 
|
foundOne = true;  | 
|
break;  | 
|
}  | 
|
}  | 
|
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<GeneralNameInterface> i =  | 
|
pathToGeneralNames.iterator();  | 
|
while (i.hasNext()) {  | 
|
debug.println(" " + i.next() + "\n");  | 
|
}  | 
|
}  | 
|
GeneralSubtrees permitted =  | 
|
ext.get(NameConstraintsExtension.PERMITTED_SUBTREES);  | 
|
GeneralSubtrees excluded =  | 
|
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<GeneralSubtree> t = excluded.iterator(); t.hasNext(); ) {  | 
|
GeneralSubtree tree = t.next();  | 
|
GeneralNameInterface excludedName = tree.getName().getName();  | 
|
Iterator<GeneralNameInterface> i = pathToGeneralNames.iterator();  | 
|
while (i.hasNext()) {  | 
|
GeneralNameInterface pathToName = 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<GeneralNameInterface> i = pathToGeneralNames.iterator();  | 
|
while (i.hasNext()) {  | 
|
GeneralNameInterface pathToName = i.next();  | 
|
Iterator<GeneralSubtree> t = permitted.iterator();  | 
|
boolean permittedNameFound = false;  | 
|
boolean nameTypeFound = false;  | 
|
String names = "";  | 
|
while (t.hasNext() && !permittedNameFound) {  | 
|
GeneralSubtree tree = 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: cert's maxPathLen " +  | 
|
                            "is less than the min maxPathLen set by " + | 
|
                            "basicConstraints. " + | 
|
"(" + maxPathLen + " < " + basicConstraints + ")");  | 
|
}  | 
|
return false;  | 
|
}  | 
|
}  | 
|
return true;  | 
|
}  | 
|
@SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly  | 
|
private static <T> Set<T> cloneSet(Set<T> set) {  | 
|
if (set instanceof HashSet) {  | 
|
Object clone = ((HashSet<T>)set).clone();  | 
|
return (Set<T>)clone;  | 
|
        } else { | 
|
return new HashSet<T>(set);  | 
|
}  | 
|
}  | 
|
    /** | 
|
     * Returns a copy of this object. | 
|
     * | 
|
     * @return the copy | 
|
*/  | 
|
public Object clone() {  | 
|
        try { | 
|
X509CertSelector copy = (X509CertSelector)super.clone();  | 
|
            // Must clone these because addPathToName et al. modify them | 
|
if (subjectAlternativeNames != null) {  | 
|
copy.subjectAlternativeNames =  | 
|
cloneSet(subjectAlternativeNames);  | 
|
copy.subjectAlternativeGeneralNames =  | 
|
cloneSet(subjectAlternativeGeneralNames);  | 
|
}  | 
|
if (pathToGeneralNames != null) {  | 
|
copy.pathToNames = cloneSet(pathToNames);  | 
|
copy.pathToGeneralNames = cloneSet(pathToGeneralNames);  | 
|
}  | 
|
return copy;  | 
|
} catch (CloneNotSupportedException e) {  | 
|
            /* Cannot happen */ | 
|
throw new InternalError(e.toString(), e);  | 
|
}  | 
|
}  | 
|
}  |