0N/A/*
2362N/A * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage java.security.cert;
0N/A
0N/Aimport java.io.IOException;
0N/Aimport java.math.BigInteger;
0N/Aimport java.security.PublicKey;
0N/Aimport java.util.*;
0N/Aimport javax.security.auth.x500.X500Principal;
0N/A
0N/Aimport sun.misc.HexDumpEncoder;
0N/Aimport sun.security.util.Debug;
0N/Aimport sun.security.util.DerInputStream;
0N/Aimport sun.security.util.DerValue;
0N/Aimport sun.security.util.ObjectIdentifier;
0N/Aimport sun.security.x509.*;
0N/A
0N/A/**
0N/A * A <code>CertSelector</code> that selects <code>X509Certificates</code> that
0N/A * match all specified criteria. This class is particularly useful when
0N/A * selecting certificates from a <code>CertStore</code> to build a
0N/A * PKIX-compliant certification path.
0N/A * <p>
0N/A * When first constructed, an <code>X509CertSelector</code> has no criteria
0N/A * enabled and each of the <code>get</code> methods return a default value
0N/A * (<code>null</code>, or <code>-1</code> for the {@link #getBasicConstraints
0N/A * getBasicConstraints} method). Therefore, the {@link #match match}
0N/A * method would return <code>true</code> for any <code>X509Certificate</code>.
0N/A * Typically, several criteria are enabled (by calling
0N/A * {@link #setIssuer setIssuer} or
0N/A * {@link #setKeyUsage setKeyUsage}, for instance) and then the
0N/A * <code>X509CertSelector</code> is passed to
0N/A * {@link CertStore#getCertificates CertStore.getCertificates} or some similar
0N/A * method.
0N/A * <p>
0N/A * Several criteria can be enabled (by calling {@link #setIssuer setIssuer}
0N/A * and {@link #setSerialNumber setSerialNumber},
0N/A * for example) such that the <code>match</code> method
0N/A * usually uniquely matches a single <code>X509Certificate</code>. We say
0N/A * usually, since it is possible for two issuing CAs to have the same
0N/A * distinguished name and each issue a certificate with the same serial
0N/A * number. Other unique combinations include the issuer, subject,
0N/A * subjectKeyIdentifier and/or the subjectPublicKey criteria.
0N/A * <p>
0N/A * Please refer to <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280:
0N/A * Internet X.509 Public Key Infrastructure Certificate and CRL Profile</a> for
0N/A * definitions of the X.509 certificate extensions mentioned below.
0N/A * <p>
0N/A * <b>Concurrent Access</b>
0N/A * <p>
0N/A * Unless otherwise specified, the methods defined in this class are not
0N/A * thread-safe. Multiple threads that need to access a single
0N/A * object concurrently should synchronize amongst themselves and
0N/A * provide the necessary locking. Multiple threads each manipulating
0N/A * separate objects need not synchronize.
0N/A *
0N/A * @see CertSelector
0N/A * @see X509Certificate
0N/A *
0N/A * @since 1.4
0N/A * @author Steve Hanna
0N/A */
0N/Apublic class X509CertSelector implements CertSelector {
0N/A
0N/A private static final Debug debug = Debug.getInstance("certpath");
0N/A
0N/A private final static ObjectIdentifier ANY_EXTENDED_KEY_USAGE =
0N/A ObjectIdentifier.newInternal(new int[] {2, 5, 29, 37, 0});
0N/A
0N/A static {
0N/A CertPathHelperImpl.initialize();
0N/A }
0N/A
0N/A private BigInteger serialNumber;
0N/A private X500Principal issuer;
0N/A private X500Principal subject;
0N/A private byte[] subjectKeyID;
0N/A private byte[] authorityKeyID;
0N/A private Date certificateValid;
0N/A private Date privateKeyValid;
0N/A private ObjectIdentifier subjectPublicKeyAlgID;
0N/A private PublicKey subjectPublicKey;
0N/A private byte[] subjectPublicKeyBytes;
0N/A private boolean[] keyUsage;
0N/A private Set<String> keyPurposeSet;
0N/A private Set<ObjectIdentifier> keyPurposeOIDSet;
0N/A private Set<List<?>> subjectAlternativeNames;
0N/A private Set<GeneralNameInterface> subjectAlternativeGeneralNames;
0N/A private CertificatePolicySet policy;
0N/A private Set<String> policySet;
0N/A private Set<List<?>> pathToNames;
0N/A private Set<GeneralNameInterface> pathToGeneralNames;
0N/A private NameConstraintsExtension nc;
0N/A private byte[] ncBytes;
0N/A private int basicConstraints = -1;
0N/A private X509Certificate x509Cert;
0N/A private boolean matchAllSubjectAltNames = true;
0N/A
0N/A private static final Boolean FALSE = Boolean.FALSE;
0N/A
0N/A private static final int PRIVATE_KEY_USAGE_ID = 0;
0N/A private static final int SUBJECT_ALT_NAME_ID = 1;
0N/A private static final int NAME_CONSTRAINTS_ID = 2;
0N/A private static final int CERT_POLICIES_ID = 3;
0N/A private static final int EXTENDED_KEY_USAGE_ID = 4;
0N/A private static final int NUM_OF_EXTENSIONS = 5;
0N/A private static final String[] EXTENSION_OIDS = new String[NUM_OF_EXTENSIONS];
0N/A
0N/A static {
0N/A EXTENSION_OIDS[PRIVATE_KEY_USAGE_ID] = "2.5.29.16";
0N/A EXTENSION_OIDS[SUBJECT_ALT_NAME_ID] = "2.5.29.17";
0N/A EXTENSION_OIDS[NAME_CONSTRAINTS_ID] = "2.5.29.30";
0N/A EXTENSION_OIDS[CERT_POLICIES_ID] = "2.5.29.32";
0N/A EXTENSION_OIDS[EXTENDED_KEY_USAGE_ID] = "2.5.29.37";
0N/A };
0N/A
0N/A /* Constants representing the GeneralName types */
0N/A static final int NAME_ANY = 0;
0N/A static final int NAME_RFC822 = 1;
0N/A static final int NAME_DNS = 2;
0N/A static final int NAME_X400 = 3;
0N/A static final int NAME_DIRECTORY = 4;
0N/A static final int NAME_EDI = 5;
0N/A static final int NAME_URI = 6;
0N/A static final int NAME_IP = 7;
0N/A static final int NAME_OID = 8;
0N/A
0N/A /**
0N/A * Creates an <code>X509CertSelector</code>. Initially, no criteria are set
0N/A * so any <code>X509Certificate</code> will match.
0N/A */
0N/A public X509CertSelector() {
0N/A // empty
0N/A }
0N/A
0N/A /**
0N/A * Sets the certificateEquals criterion. The specified
0N/A * <code>X509Certificate</code> must be equal to the
0N/A * <code>X509Certificate</code> passed to the <code>match</code> method.
0N/A * If <code>null</code>, then this check is not applied.
0N/A *
0N/A * <p>This method is particularly useful when it is necessary to
0N/A * match a single certificate. Although other criteria can be specified
0N/A * in conjunction with the certificateEquals criterion, it is usually not
0N/A * practical or necessary.
0N/A *
0N/A * @param cert the <code>X509Certificate</code> to match (or
0N/A * <code>null</code>)
0N/A * @see #getCertificate
0N/A */
0N/A public void setCertificate(X509Certificate cert) {
0N/A x509Cert = cert;
0N/A }
0N/A
0N/A /**
0N/A * Sets the serialNumber criterion. The specified serial number
0N/A * must match the certificate serial number in the
0N/A * <code>X509Certificate</code>. If <code>null</code>, any certificate
0N/A * serial number will do.
0N/A *
0N/A * @param serial the certificate serial number to match
0N/A * (or <code>null</code>)
0N/A * @see #getSerialNumber
0N/A */
0N/A public void setSerialNumber(BigInteger serial) {
0N/A serialNumber = serial;
0N/A }
0N/A
0N/A /**
0N/A * Sets the issuer criterion. The specified distinguished name
0N/A * must match the issuer distinguished name in the
0N/A * <code>X509Certificate</code>. If <code>null</code>, any issuer
0N/A * distinguished name will do.
0N/A *
0N/A * @param issuer a distinguished name as X500Principal
0N/A * (or <code>null</code>)
0N/A * @since 1.5
0N/A */
0N/A public void setIssuer(X500Principal issuer) {
0N/A this.issuer = issuer;
0N/A }
0N/A
0N/A /**
0N/A * <strong>Denigrated</strong>, use {@linkplain #setIssuer(X500Principal)}
0N/A * or {@linkplain #setIssuer(byte[])} instead. This method should not be
0N/A * relied on as it can fail to match some certificates because of a loss of
0N/A * encoding information in the
0N/A * <a href="http://www.ietf.org/rfc/rfc2253.txt">RFC 2253</a> String form
0N/A * of some distinguished names.
0N/A * <p>
0N/A * Sets the issuer criterion. The specified distinguished name
0N/A * must match the issuer distinguished name in the
0N/A * <code>X509Certificate</code>. If <code>null</code>, any issuer
0N/A * distinguished name will do.
0N/A * <p>
0N/A * If <code>issuerDN</code> is not <code>null</code>, it should contain a
0N/A * distinguished name, in RFC 2253 format.
0N/A *
0N/A * @param issuerDN a distinguished name in RFC 2253 format
0N/A * (or <code>null</code>)
0N/A * @throws IOException if a parsing error occurs (incorrect form for DN)
0N/A */
0N/A public void setIssuer(String issuerDN) throws IOException {
0N/A if (issuerDN == null) {
0N/A issuer = null;
0N/A } else {
0N/A issuer = new X500Name(issuerDN).asX500Principal();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Sets the issuer criterion. The specified distinguished name
0N/A * must match the issuer distinguished name in the
0N/A * <code>X509Certificate</code>. If <code>null</code> is specified,
0N/A * the issuer criterion is disabled and any issuer distinguished name will
0N/A * do.
0N/A * <p>
0N/A * If <code>issuerDN</code> is not <code>null</code>, it should contain a
0N/A * single DER encoded distinguished name, as defined in X.501. The ASN.1
0N/A * notation for this structure is as follows.
0N/A * <pre><code>
0N/A * Name ::= CHOICE {
0N/A * RDNSequence }
0N/A *
0N/A * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
0N/A *
0N/A * RelativeDistinguishedName ::=
0N/A * SET SIZE (1 .. MAX) OF AttributeTypeAndValue
0N/A *
0N/A * AttributeTypeAndValue ::= SEQUENCE {
0N/A * type AttributeType,
0N/A * value AttributeValue }
0N/A *
0N/A * AttributeType ::= OBJECT IDENTIFIER
0N/A *
0N/A * AttributeValue ::= ANY DEFINED BY AttributeType
0N/A * ....
0N/A * DirectoryString ::= CHOICE {
0N/A * teletexString TeletexString (SIZE (1..MAX)),
0N/A * printableString PrintableString (SIZE (1..MAX)),
0N/A * universalString UniversalString (SIZE (1..MAX)),
0N/A * utf8String UTF8String (SIZE (1.. MAX)),
0N/A * bmpString BMPString (SIZE (1..MAX)) }
0N/A * </code></pre>
0N/A * <p>
0N/A * Note that the byte array specified here is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @param issuerDN a byte array containing the distinguished name
0N/A * in ASN.1 DER encoded form (or <code>null</code>)
0N/A * @throws IOException if an encoding error occurs (incorrect form for DN)
0N/A */
0N/A public void setIssuer(byte[] issuerDN) throws IOException {
0N/A try {
0N/A issuer = (issuerDN == null ? null : new X500Principal(issuerDN));
0N/A } catch (IllegalArgumentException e) {
0N/A throw (IOException)new IOException("Invalid name").initCause(e);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Sets the subject criterion. The specified distinguished name
0N/A * must match the subject distinguished name in the
0N/A * <code>X509Certificate</code>. If <code>null</code>, any subject
0N/A * distinguished name will do.
0N/A *
0N/A * @param subject a distinguished name as X500Principal
0N/A * (or <code>null</code>)
0N/A * @since 1.5
0N/A */
0N/A public void setSubject(X500Principal subject) {
0N/A this.subject = subject;
0N/A }
0N/A
0N/A /**
0N/A * <strong>Denigrated</strong>, use {@linkplain #setSubject(X500Principal)}
0N/A * or {@linkplain #setSubject(byte[])} instead. This method should not be
0N/A * relied on as it can fail to match some certificates because of a loss of
0N/A * encoding information in the RFC 2253 String form of some distinguished
0N/A * names.
0N/A * <p>
0N/A * Sets the subject criterion. The specified distinguished name
0N/A * must match the subject distinguished name in the
0N/A * <code>X509Certificate</code>. If <code>null</code>, any subject
0N/A * distinguished name will do.
0N/A * <p>
0N/A * If <code>subjectDN</code> is not <code>null</code>, it should contain a
0N/A * distinguished name, in RFC 2253 format.
0N/A *
0N/A * @param subjectDN a distinguished name in RFC 2253 format
0N/A * (or <code>null</code>)
0N/A * @throws IOException if a parsing error occurs (incorrect form for DN)
0N/A */
0N/A public void setSubject(String subjectDN) throws IOException {
0N/A if (subjectDN == null) {
0N/A subject = null;
0N/A } else {
0N/A subject = new X500Name(subjectDN).asX500Principal();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Sets the subject criterion. The specified distinguished name
0N/A * must match the subject distinguished name in the
0N/A * <code>X509Certificate</code>. If <code>null</code>, any subject
0N/A * distinguished name will do.
0N/A * <p>
0N/A * If <code>subjectDN</code> is not <code>null</code>, it should contain a
0N/A * single DER encoded distinguished name, as defined in X.501. For the ASN.1
0N/A * notation for this structure, see
0N/A * {@link #setIssuer(byte [] issuerDN) setIssuer(byte [] issuerDN)}.
0N/A *
0N/A * @param subjectDN a byte array containing the distinguished name in
0N/A * ASN.1 DER format (or <code>null</code>)
0N/A * @throws IOException if an encoding error occurs (incorrect form for DN)
0N/A */
0N/A public void setSubject(byte[] subjectDN) throws IOException {
0N/A try {
0N/A subject = (subjectDN == null ? null : new X500Principal(subjectDN));
0N/A } catch (IllegalArgumentException e) {
0N/A throw (IOException)new IOException("Invalid name").initCause(e);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Sets the subjectKeyIdentifier criterion. The
0N/A * <code>X509Certificate</code> must contain a SubjectKeyIdentifier
0N/A * extension for which the contents of the extension
0N/A * matches the specified criterion value.
0N/A * If the criterion value is <code>null</code>, no
0N/A * subjectKeyIdentifier check will be done.
0N/A * <p>
0N/A * If <code>subjectKeyID</code> is not <code>null</code>, it
0N/A * should contain a single DER encoded value corresponding to the contents
0N/A * of the extension value (not including the object identifier,
0N/A * criticality setting, and encapsulating OCTET STRING)
0N/A * for a SubjectKeyIdentifier extension.
0N/A * The ASN.1 notation for this structure follows.
0N/A * <p>
0N/A * <pre><code>
0N/A * SubjectKeyIdentifier ::= KeyIdentifier
0N/A *
0N/A * KeyIdentifier ::= OCTET STRING
0N/A * </code></pre>
0N/A * <p>
0N/A * Since the format of subject key identifiers is not mandated by
0N/A * any standard, subject key identifiers are not parsed by the
0N/A * <code>X509CertSelector</code>. Instead, the values are compared using
0N/A * a byte-by-byte comparison.
0N/A * <p>
0N/A * Note that the byte array supplied here is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @param subjectKeyID the subject key identifier (or <code>null</code>)
0N/A * @see #getSubjectKeyIdentifier
0N/A */
0N/A public void setSubjectKeyIdentifier(byte[] subjectKeyID) {
0N/A if (subjectKeyID == null) {
0N/A this.subjectKeyID = null;
0N/A } else {
28N/A this.subjectKeyID = subjectKeyID.clone();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Sets the authorityKeyIdentifier criterion. The
0N/A * <code>X509Certificate</code> must contain an
0N/A * AuthorityKeyIdentifier extension for which the contents of the
0N/A * extension value matches the specified criterion value.
0N/A * If the criterion value is <code>null</code>, no
0N/A * authorityKeyIdentifier check will be done.
0N/A * <p>
0N/A * If <code>authorityKeyID</code> is not <code>null</code>, it
0N/A * should contain a single DER encoded value corresponding to the contents
0N/A * of the extension value (not including the object identifier,
0N/A * criticality setting, and encapsulating OCTET STRING)
0N/A * for an AuthorityKeyIdentifier extension.
0N/A * The ASN.1 notation for this structure follows.
0N/A * <p>
0N/A * <pre><code>
0N/A * AuthorityKeyIdentifier ::= SEQUENCE {
0N/A * keyIdentifier [0] KeyIdentifier OPTIONAL,
0N/A * authorityCertIssuer [1] GeneralNames OPTIONAL,
0N/A * authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
0N/A *
0N/A * KeyIdentifier ::= OCTET STRING
0N/A * </code></pre>
0N/A * <p>
0N/A * Authority key identifiers are not parsed by the
0N/A * <code>X509CertSelector</code>. Instead, the values are
0N/A * compared using a byte-by-byte comparison.
0N/A * <p>
0N/A * When the <code>keyIdentifier</code> field of
0N/A * <code>AuthorityKeyIdentifier</code> is populated, the value is
0N/A * usually taken from the <code>SubjectKeyIdentifier</code> extension
0N/A * in the issuer's certificate. Note, however, that the result of
0N/A * <code>X509Certificate.getExtensionValue(&lt;SubjectKeyIdentifier Object
0N/A * Identifier&gt;)</code> on the issuer's certificate may NOT be used
0N/A * directly as the input to <code>setAuthorityKeyIdentifier</code>.
0N/A * This is because the SubjectKeyIdentifier contains
0N/A * only a KeyIdentifier OCTET STRING, and not a SEQUENCE of
0N/A * KeyIdentifier, GeneralNames, and CertificateSerialNumber.
0N/A * In order to use the extension value of the issuer certificate's
0N/A * <code>SubjectKeyIdentifier</code>
0N/A * extension, it will be necessary to extract the value of the embedded
0N/A * <code>KeyIdentifier</code> OCTET STRING, then DER encode this OCTET
0N/A * STRING inside a SEQUENCE.
0N/A * For more details on SubjectKeyIdentifier, see
0N/A * {@link #setSubjectKeyIdentifier(byte[] subjectKeyID)}.
0N/A * <p>
0N/A * Note also that the byte array supplied here is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @param authorityKeyID the authority key identifier
0N/A * (or <code>null</code>)
0N/A * @see #getAuthorityKeyIdentifier
0N/A */
0N/A public void setAuthorityKeyIdentifier(byte[] authorityKeyID) {
0N/A if (authorityKeyID == null) {
0N/A this.authorityKeyID = null;
0N/A } else {
28N/A this.authorityKeyID = authorityKeyID.clone();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Sets the certificateValid criterion. The specified date must fall
0N/A * within the certificate validity period for the
0N/A * <code>X509Certificate</code>. If <code>null</code>, no certificateValid
0N/A * check will be done.
0N/A * <p>
0N/A * Note that the <code>Date</code> supplied here is cloned to protect
0N/A * against subsequent modifications.
0N/A *
0N/A * @param certValid the <code>Date</code> to check (or <code>null</code>)
0N/A * @see #getCertificateValid
0N/A */
0N/A public void setCertificateValid(Date certValid) {
0N/A if (certValid == null) {
0N/A certificateValid = null;
0N/A } else {
0N/A certificateValid = (Date)certValid.clone();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Sets the privateKeyValid criterion. The specified date must fall
0N/A * within the private key validity period for the
0N/A * <code>X509Certificate</code>. If <code>null</code>, no privateKeyValid
0N/A * check will be done.
0N/A * <p>
0N/A * Note that the <code>Date</code> supplied here is cloned to protect
0N/A * against subsequent modifications.
0N/A *
0N/A * @param privateKeyValid the <code>Date</code> to check (or
0N/A * <code>null</code>)
0N/A * @see #getPrivateKeyValid
0N/A */
0N/A public void setPrivateKeyValid(Date privateKeyValid) {
0N/A if (privateKeyValid == null) {
0N/A this.privateKeyValid = null;
0N/A } else {
0N/A this.privateKeyValid = (Date)privateKeyValid.clone();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Sets the subjectPublicKeyAlgID criterion. The
0N/A * <code>X509Certificate</code> must contain a subject public key
0N/A * with the specified algorithm. If <code>null</code>, no
0N/A * subjectPublicKeyAlgID check will be done.
0N/A *
0N/A * @param oid The object identifier (OID) of the algorithm to check
0N/A * for (or <code>null</code>). An OID is represented by a
0N/A * set of nonnegative integers separated by periods.
0N/A * @throws IOException if the OID is invalid, such as
0N/A * the first component being not 0, 1 or 2 or the second component
0N/A * being greater than 39.
0N/A *
0N/A * @see #getSubjectPublicKeyAlgID
0N/A */
0N/A public void setSubjectPublicKeyAlgID(String oid) throws IOException {
0N/A if (oid == null) {
0N/A subjectPublicKeyAlgID = null;
0N/A } else {
0N/A subjectPublicKeyAlgID = new ObjectIdentifier(oid);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Sets the subjectPublicKey criterion. The
0N/A * <code>X509Certificate</code> must contain the specified subject public
0N/A * key. If <code>null</code>, no subjectPublicKey check will be done.
0N/A *
0N/A * @param key the subject public key to check for (or <code>null</code>)
0N/A * @see #getSubjectPublicKey
0N/A */
0N/A public void setSubjectPublicKey(PublicKey key) {
0N/A if (key == null) {
0N/A subjectPublicKey = null;
0N/A subjectPublicKeyBytes = null;
0N/A } else {
0N/A subjectPublicKey = key;
0N/A subjectPublicKeyBytes = key.getEncoded();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Sets the subjectPublicKey criterion. The <code>X509Certificate</code>
0N/A * must contain the specified subject public key. If <code>null</code>,
0N/A * no subjectPublicKey check will be done.
0N/A * <p>
0N/A * Because this method allows the public key to be specified as a byte
0N/A * array, it may be used for unknown key types.
0N/A * <p>
0N/A * If <code>key</code> is not <code>null</code>, it should contain a
0N/A * single DER encoded SubjectPublicKeyInfo structure, as defined in X.509.
0N/A * The ASN.1 notation for this structure is as follows.
0N/A * <pre><code>
0N/A * SubjectPublicKeyInfo ::= SEQUENCE {
0N/A * algorithm AlgorithmIdentifier,
0N/A * subjectPublicKey BIT STRING }
0N/A *
0N/A * AlgorithmIdentifier ::= SEQUENCE {
0N/A * algorithm OBJECT IDENTIFIER,
0N/A * parameters ANY DEFINED BY algorithm OPTIONAL }
0N/A * -- contains a value of the type
0N/A * -- registered for use with the
0N/A * -- algorithm object identifier value
0N/A * </code></pre>
0N/A * <p>
0N/A * Note that the byte array supplied here is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @param key a byte array containing the subject public key in ASN.1 DER
0N/A * form (or <code>null</code>)
0N/A * @throws IOException if an encoding error occurs (incorrect form for
0N/A * subject public key)
0N/A * @see #getSubjectPublicKey
0N/A */
0N/A public void setSubjectPublicKey(byte[] key) throws IOException {
0N/A if (key == null) {
0N/A subjectPublicKey = null;
0N/A subjectPublicKeyBytes = null;
0N/A } else {
28N/A subjectPublicKeyBytes = key.clone();
0N/A subjectPublicKey = X509Key.parse(new DerValue(subjectPublicKeyBytes));
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Sets the keyUsage criterion. The <code>X509Certificate</code>
0N/A * must allow the specified keyUsage values. If <code>null</code>, no
0N/A * keyUsage check will be done. Note that an <code>X509Certificate</code>
0N/A * that has no keyUsage extension implicitly allows all keyUsage values.
0N/A * <p>
0N/A * Note that the boolean array supplied here is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @param keyUsage a boolean array in the same format as the boolean
0N/A * array returned by
0N/A * {@link X509Certificate#getKeyUsage() X509Certificate.getKeyUsage()}.
0N/A * Or <code>null</code>.
0N/A * @see #getKeyUsage
0N/A */
0N/A public void setKeyUsage(boolean[] keyUsage) {
0N/A if (keyUsage == null) {
0N/A this.keyUsage = null;
0N/A } else {
28N/A this.keyUsage = keyUsage.clone();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Sets the extendedKeyUsage criterion. The <code>X509Certificate</code>
0N/A * must allow the specified key purposes in its extended key usage
0N/A * extension. If <code>keyPurposeSet</code> is empty or <code>null</code>,
0N/A * no extendedKeyUsage check will be done. Note that an
0N/A * <code>X509Certificate</code> that has no extendedKeyUsage extension
0N/A * implicitly allows all key purposes.
0N/A * <p>
0N/A * Note that the <code>Set</code> is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @param keyPurposeSet a <code>Set</code> of key purpose OIDs in string
0N/A * format (or <code>null</code>). Each OID is represented by a set of
0N/A * nonnegative integers separated by periods.
0N/A * @throws IOException if the OID is invalid, such as
0N/A * the first component being not 0, 1 or 2 or the second component
0N/A * being greater than 39.
0N/A * @see #getExtendedKeyUsage
0N/A */
0N/A public void setExtendedKeyUsage(Set<String> keyPurposeSet) throws IOException {
0N/A if ((keyPurposeSet == null) || keyPurposeSet.isEmpty()) {
0N/A this.keyPurposeSet = null;
0N/A keyPurposeOIDSet = null;
0N/A } else {
0N/A this.keyPurposeSet =
0N/A Collections.unmodifiableSet(new HashSet<String>(keyPurposeSet));
0N/A keyPurposeOIDSet = new HashSet<ObjectIdentifier>();
0N/A for (String s : this.keyPurposeSet) {
0N/A keyPurposeOIDSet.add(new ObjectIdentifier(s));
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Enables/disables matching all of the subjectAlternativeNames
0N/A * specified in the {@link #setSubjectAlternativeNames
0N/A * setSubjectAlternativeNames} or {@link #addSubjectAlternativeName
0N/A * addSubjectAlternativeName} methods. If enabled,
0N/A * the <code>X509Certificate</code> must contain all of the
0N/A * specified subject alternative names. If disabled, the
0N/A * <code>X509Certificate</code> must contain at least one of the
0N/A * specified subject alternative names.
0N/A *
0N/A * <p>The matchAllNames flag is <code>true</code> by default.
0N/A *
0N/A * @param matchAllNames if <code>true</code>, the flag is enabled;
0N/A * if <code>false</code>, the flag is disabled.
0N/A * @see #getMatchAllSubjectAltNames
0N/A */
0N/A public void setMatchAllSubjectAltNames(boolean matchAllNames) {
0N/A this.matchAllSubjectAltNames = matchAllNames;
0N/A }
0N/A
0N/A /**
0N/A * Sets the subjectAlternativeNames criterion. The
0N/A * <code>X509Certificate</code> must contain all or at least one of the
0N/A * specified subjectAlternativeNames, depending on the value of
0N/A * the matchAllNames flag (see {@link #setMatchAllSubjectAltNames
0N/A * setMatchAllSubjectAltNames}).
0N/A * <p>
0N/A * This method allows the caller to specify, with a single method call,
0N/A * the complete set of subject alternative names for the
0N/A * subjectAlternativeNames criterion. The specified value replaces
0N/A * the previous value for the subjectAlternativeNames criterion.
0N/A * <p>
0N/A * The <code>names</code> parameter (if not <code>null</code>) is a
0N/A * <code>Collection</code> with one
0N/A * entry for each name to be included in the subject alternative name
0N/A * criterion. Each entry is a <code>List</code> whose first entry is an
0N/A * <code>Integer</code> (the name type, 0-8) and whose second
0N/A * entry is a <code>String</code> or a byte array (the name, in
0N/A * string or ASN.1 DER encoded form, respectively).
0N/A * There can be multiple names of the same type. If <code>null</code>
0N/A * is supplied as the value for this argument, no
0N/A * subjectAlternativeNames check will be performed.
0N/A * <p>
0N/A * Each subject alternative name in the <code>Collection</code>
0N/A * may be specified either as a <code>String</code> or as an ASN.1 encoded
0N/A * byte array. For more details about the formats used, see
0N/A * {@link #addSubjectAlternativeName(int type, String name)
0N/A * addSubjectAlternativeName(int type, String name)} and
0N/A * {@link #addSubjectAlternativeName(int type, byte [] name)
0N/A * addSubjectAlternativeName(int type, byte [] name)}.
0N/A * <p>
0N/A * <strong>Note:</strong> for distinguished names, specify the byte
0N/A * array form instead of the String form. See the note in
0N/A * {@link #addSubjectAlternativeName(int, String)} for more information.
0N/A * <p>
0N/A * Note that the <code>names</code> parameter can contain duplicate
0N/A * names (same name and name type), but they may be removed from the
0N/A * <code>Collection</code> of names returned by the
0N/A * {@link #getSubjectAlternativeNames getSubjectAlternativeNames} method.
0N/A * <p>
0N/A * Note that a deep copy is performed on the <code>Collection</code> to
0N/A * protect against subsequent modifications.
0N/A *
0N/A * @param names a <code>Collection</code> of names (or <code>null</code>)
0N/A * @throws IOException if a parsing error occurs
0N/A * @see #getSubjectAlternativeNames
0N/A */
0N/A public void setSubjectAlternativeNames(Collection<List<?>> names)
0N/A throws IOException {
0N/A if (names == null) {
0N/A subjectAlternativeNames = null;
0N/A subjectAlternativeGeneralNames = null;
0N/A } else {
0N/A if (names.isEmpty()) {
0N/A subjectAlternativeNames = null;
0N/A subjectAlternativeGeneralNames = null;
0N/A return;
0N/A }
0N/A Set<List<?>> tempNames = cloneAndCheckNames(names);
0N/A // Ensure that we either set both of these or neither
0N/A subjectAlternativeGeneralNames = parseNames(tempNames);
0N/A subjectAlternativeNames = tempNames;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Adds a name to the subjectAlternativeNames criterion. The
0N/A * <code>X509Certificate</code> must contain all or at least one
0N/A * of the specified subjectAlternativeNames, depending on the value of
0N/A * the matchAllNames flag (see {@link #setMatchAllSubjectAltNames
0N/A * setMatchAllSubjectAltNames}).
0N/A * <p>
0N/A * This method allows the caller to add a name to the set of subject
0N/A * alternative names.
0N/A * The specified name is added to any previous value for the
0N/A * subjectAlternativeNames criterion. If the specified name is a
0N/A * duplicate, it may be ignored.
0N/A * <p>
0N/A * The name is provided in string format.
0N/A * <a href="http://www.ietf.org/rfc/rfc822.txt">RFC 822</a>, DNS, and URI
0N/A * names use the well-established string formats for those types (subject to
0N/A * the restrictions included in RFC 3280). IPv4 address names are
0N/A * supplied using dotted quad notation. OID address names are represented
0N/A * as a series of nonnegative integers separated by periods. And
0N/A * directory names (distinguished names) are supplied in RFC 2253 format.
0N/A * No standard string format is defined for otherNames, X.400 names,
0N/A * EDI party names, IPv6 address names, or any other type of names. They
0N/A * should be specified using the
0N/A * {@link #addSubjectAlternativeName(int type, byte [] name)
0N/A * addSubjectAlternativeName(int type, byte [] name)}
0N/A * method.
0N/A * <p>
0N/A * <strong>Note:</strong> for distinguished names, use
0N/A * {@linkplain #addSubjectAlternativeName(int, byte[])} instead.
0N/A * This method should not be relied on as it can fail to match some
0N/A * certificates because of a loss of encoding information in the RFC 2253
0N/A * String form of some distinguished names.
0N/A *
0N/A * @param type the name type (0-8, as specified in
0N/A * RFC 3280, section 4.2.1.7)
0N/A * @param name the name in string form (not <code>null</code>)
0N/A * @throws IOException if a parsing error occurs
0N/A */
0N/A public void addSubjectAlternativeName(int type, String name)
0N/A throws IOException {
0N/A addSubjectAlternativeNameInternal(type, name);
0N/A }
0N/A
0N/A /**
0N/A * Adds a name to the subjectAlternativeNames criterion. The
0N/A * <code>X509Certificate</code> must contain all or at least one
0N/A * of the specified subjectAlternativeNames, depending on the value of
0N/A * the matchAllNames flag (see {@link #setMatchAllSubjectAltNames
0N/A * setMatchAllSubjectAltNames}).
0N/A * <p>
0N/A * This method allows the caller to add a name to the set of subject
0N/A * alternative names.
0N/A * The specified name is added to any previous value for the
0N/A * subjectAlternativeNames criterion. If the specified name is a
0N/A * duplicate, it may be ignored.
0N/A * <p>
0N/A * The name is provided as a byte array. This byte array should contain
0N/A * the DER encoded name, as it would appear in the GeneralName structure
0N/A * defined in RFC 3280 and X.509. The encoded byte array should only contain
0N/A * the encoded value of the name, and should not include the tag associated
0N/A * with the name in the GeneralName structure. The ASN.1 definition of this
0N/A * structure appears below.
0N/A * <pre><code>
0N/A * GeneralName ::= CHOICE {
0N/A * otherName [0] OtherName,
0N/A * rfc822Name [1] IA5String,
0N/A * dNSName [2] IA5String,
0N/A * x400Address [3] ORAddress,
0N/A * directoryName [4] Name,
0N/A * ediPartyName [5] EDIPartyName,
0N/A * uniformResourceIdentifier [6] IA5String,
0N/A * iPAddress [7] OCTET STRING,
0N/A * registeredID [8] OBJECT IDENTIFIER}
0N/A * </code></pre>
0N/A * <p>
0N/A * Note that the byte array supplied here is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @param type the name type (0-8, as listed above)
0N/A * @param name a byte array containing the name in ASN.1 DER encoded form
0N/A * @throws IOException if a parsing error occurs
0N/A */
0N/A public void addSubjectAlternativeName(int type, byte[] name)
0N/A throws IOException {
0N/A // clone because byte arrays are modifiable
0N/A addSubjectAlternativeNameInternal(type, name.clone());
0N/A }
0N/A
0N/A /**
0N/A * A private method that adds a name (String or byte array) to the
0N/A * subjectAlternativeNames criterion. The <code>X509Certificate</code>
0N/A * must contain the specified subjectAlternativeName.
0N/A *
0N/A * @param type the name type (0-8, as specified in
0N/A * RFC 3280, section 4.2.1.7)
0N/A * @param name the name in string or byte array form
0N/A * @throws IOException if a parsing error occurs
0N/A */
0N/A private void addSubjectAlternativeNameInternal(int type, Object name)
0N/A throws IOException {
0N/A // First, ensure that the name parses
0N/A GeneralNameInterface tempName = makeGeneralNameInterface(type, name);
0N/A if (subjectAlternativeNames == null) {
0N/A subjectAlternativeNames = new HashSet<List<?>>();
0N/A }
0N/A if (subjectAlternativeGeneralNames == null) {
0N/A subjectAlternativeGeneralNames = new HashSet<GeneralNameInterface>();
0N/A }
0N/A List<Object> list = new ArrayList<Object>(2);
0N/A list.add(Integer.valueOf(type));
0N/A list.add(name);
0N/A subjectAlternativeNames.add(list);
0N/A subjectAlternativeGeneralNames.add(tempName);
0N/A }
0N/A
0N/A /**
0N/A * Parse an argument of the form passed to setSubjectAlternativeNames,
0N/A * returning a <code>Collection</code> of
0N/A * <code>GeneralNameInterface</code>s.
0N/A * Throw an IllegalArgumentException or a ClassCastException
0N/A * if the argument is malformed.
0N/A *
0N/A * @param names a Collection with one entry per name.
0N/A * Each entry is a <code>List</code> whose first entry
0N/A * is an Integer (the name type, 0-8) and whose second
0N/A * entry is a String or a byte array (the name, in
0N/A * string or ASN.1 DER encoded form, respectively).
0N/A * There can be multiple names of the same type. Null is
0N/A * not an acceptable value.
0N/A * @return a Set of <code>GeneralNameInterface</code>s
0N/A * @throws IOException if a parsing error occurs
0N/A */
0N/A private static Set<GeneralNameInterface> parseNames(Collection<List<?>> names) throws IOException {
0N/A Set<GeneralNameInterface> genNames = new HashSet<GeneralNameInterface>();
0N/A for (List<?> nameList : names) {
0N/A if (nameList.size() != 2) {
0N/A throw new IOException("name list size not 2");
0N/A }
0N/A Object o = nameList.get(0);
0N/A if (!(o instanceof Integer)) {
0N/A throw new IOException("expected an Integer");
0N/A }
0N/A int nameType = ((Integer)o).intValue();
0N/A o = nameList.get(1);
0N/A genNames.add(makeGeneralNameInterface(nameType, o));
0N/A }
0N/A
0N/A return genNames;
0N/A }
0N/A
0N/A /**
0N/A * Compare for equality two objects of the form passed to
0N/A * setSubjectAlternativeNames (or X509CRLSelector.setIssuerNames).
0N/A * Throw an <code>IllegalArgumentException</code> or a
0N/A * <code>ClassCastException</code> if one of the objects is malformed.
0N/A *
0N/A * @param object1 a Collection containing the first object to compare
0N/A * @param object2 a Collection containing the second object to compare
0N/A * @return true if the objects are equal, false otherwise
0N/A */
0N/A static boolean equalNames(Collection object1, Collection object2) {
0N/A if ((object1 == null) || (object2 == null)) {
0N/A return object1 == object2;
0N/A }
0N/A return object1.equals(object2);
0N/A }
0N/A
0N/A /**
0N/A * Make a <code>GeneralNameInterface</code> out of a name type (0-8) and an
0N/A * Object that may be a byte array holding the ASN.1 DER encoded
0N/A * name or a String form of the name. Except for X.509
0N/A * Distinguished Names, the String form of the name must not be the
0N/A * result from calling toString on an existing GeneralNameInterface
0N/A * implementing class. The output of toString is not compatible
0N/A * with the String constructors for names other than Distinguished
0N/A * Names.
0N/A *
0N/A * @param type name type (0-8)
0N/A * @param name name as ASN.1 Der-encoded byte array or String
0N/A * @return a GeneralNameInterface name
0N/A * @throws IOException if a parsing error occurs
0N/A */
0N/A static GeneralNameInterface makeGeneralNameInterface(int type, Object name)
0N/A throws IOException {
0N/A GeneralNameInterface result;
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.makeGeneralNameInterface("
0N/A + type + ")...");
0N/A }
0N/A
0N/A if (name instanceof String) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.makeGeneralNameInterface() "
0N/A + "name is String: " + name);
0N/A }
0N/A switch (type) {
0N/A case NAME_RFC822:
0N/A result = new RFC822Name((String)name);
0N/A break;
0N/A case NAME_DNS:
0N/A result = new DNSName((String)name);
0N/A break;
0N/A case NAME_DIRECTORY:
0N/A result = new X500Name((String)name);
0N/A break;
0N/A case NAME_URI:
0N/A result = new URIName((String)name);
0N/A break;
0N/A case NAME_IP:
0N/A result = new IPAddressName((String)name);
0N/A break;
0N/A case NAME_OID:
0N/A result = new OIDName((String)name);
0N/A break;
0N/A default:
0N/A throw new IOException("unable to parse String names of type "
0N/A + type);
0N/A }
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.makeGeneralNameInterface() "
0N/A + "result: " + result.toString());
0N/A }
0N/A } else if (name instanceof byte[]) {
0N/A DerValue val = new DerValue((byte[]) name);
0N/A if (debug != null) {
0N/A debug.println
0N/A ("X509CertSelector.makeGeneralNameInterface() is byte[]");
0N/A }
0N/A
0N/A switch (type) {
0N/A case NAME_ANY:
0N/A result = new OtherName(val);
0N/A break;
0N/A case NAME_RFC822:
0N/A result = new RFC822Name(val);
0N/A break;
0N/A case NAME_DNS:
0N/A result = new DNSName(val);
0N/A break;
0N/A case NAME_X400:
0N/A result = new X400Address(val);
0N/A break;
0N/A case NAME_DIRECTORY:
0N/A result = new X500Name(val);
0N/A break;
0N/A case NAME_EDI:
0N/A result = new EDIPartyName(val);
0N/A break;
0N/A case NAME_URI:
0N/A result = new URIName(val);
0N/A break;
0N/A case NAME_IP:
0N/A result = new IPAddressName(val);
0N/A break;
0N/A case NAME_OID:
0N/A result = new OIDName(val);
0N/A break;
0N/A default:
0N/A throw new IOException("unable to parse byte array names of "
0N/A + "type " + type);
0N/A }
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.makeGeneralNameInterface() result: "
0N/A + result.toString());
0N/A }
0N/A } else {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.makeGeneralName() input name "
0N/A + "not String or byte array");
0N/A }
0N/A throw new IOException("name not String or byte array");
0N/A }
0N/A return result;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Sets the name constraints criterion. The <code>X509Certificate</code>
0N/A * must have subject and subject alternative names that
0N/A * meet the specified name constraints.
0N/A * <p>
0N/A * The name constraints are specified as a byte array. This byte array
0N/A * should contain the DER encoded form of the name constraints, as they
0N/A * would appear in the NameConstraints structure defined in RFC 3280
0N/A * and X.509. The ASN.1 definition of this structure appears below.
0N/A *
0N/A * <pre><code>
0N/A * NameConstraints ::= SEQUENCE {
0N/A * permittedSubtrees [0] GeneralSubtrees OPTIONAL,
0N/A * excludedSubtrees [1] GeneralSubtrees OPTIONAL }
0N/A *
0N/A * GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
0N/A *
0N/A * GeneralSubtree ::= SEQUENCE {
0N/A * base GeneralName,
0N/A * minimum [0] BaseDistance DEFAULT 0,
0N/A * maximum [1] BaseDistance OPTIONAL }
0N/A *
0N/A * BaseDistance ::= INTEGER (0..MAX)
0N/A *
0N/A * GeneralName ::= CHOICE {
0N/A * otherName [0] OtherName,
0N/A * rfc822Name [1] IA5String,
0N/A * dNSName [2] IA5String,
0N/A * x400Address [3] ORAddress,
0N/A * directoryName [4] Name,
0N/A * ediPartyName [5] EDIPartyName,
0N/A * uniformResourceIdentifier [6] IA5String,
0N/A * iPAddress [7] OCTET STRING,
0N/A * registeredID [8] OBJECT IDENTIFIER}
0N/A * </code></pre>
0N/A * <p>
0N/A * Note that the byte array supplied here is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @param bytes a byte array containing the ASN.1 DER encoding of
0N/A * a NameConstraints extension to be used for checking
0N/A * name constraints. Only the value of the extension is
0N/A * included, not the OID or criticality flag. Can be
0N/A * <code>null</code>,
0N/A * in which case no name constraints check will be performed.
0N/A * @throws IOException if a parsing error occurs
0N/A * @see #getNameConstraints
0N/A */
0N/A public void setNameConstraints(byte[] bytes) throws IOException {
0N/A if (bytes == null) {
0N/A ncBytes = null;
0N/A nc = null;
0N/A } else {
28N/A ncBytes = bytes.clone();
0N/A nc = new NameConstraintsExtension(FALSE, bytes);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Sets the basic constraints constraint. If the value is greater than or
0N/A * equal to zero, <code>X509Certificates</code> must include a
0N/A * basicConstraints extension with
0N/A * a pathLen of at least this value. If the value is -2, only end-entity
0N/A * certificates are accepted. If the value is -1, no check is done.
0N/A * <p>
0N/A * This constraint is useful when building a certification path forward
0N/A * (from the target toward the trust anchor. If a partial path has been
0N/A * built, any candidate certificate must have a maxPathLen value greater
0N/A * than or equal to the number of certificates in the partial path.
0N/A *
0N/A * @param minMaxPathLen the value for the basic constraints constraint
0N/A * @throws IllegalArgumentException if the value is less than -2
0N/A * @see #getBasicConstraints
0N/A */
0N/A public void setBasicConstraints(int minMaxPathLen) {
0N/A if (minMaxPathLen < -2) {
0N/A throw new IllegalArgumentException("basic constraints less than -2");
0N/A }
0N/A basicConstraints = minMaxPathLen;
0N/A }
0N/A
0N/A /**
0N/A * Sets the policy constraint. The <code>X509Certificate</code> must
0N/A * include at least one of the specified policies in its certificate
0N/A * policies extension. If <code>certPolicySet</code> is empty, then the
0N/A * <code>X509Certificate</code> must include at least some specified policy
0N/A * in its certificate policies extension. If <code>certPolicySet</code> is
0N/A * <code>null</code>, no policy check will be performed.
0N/A * <p>
0N/A * Note that the <code>Set</code> is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @param certPolicySet a <code>Set</code> of certificate policy OIDs in
0N/A * string format (or <code>null</code>). Each OID is
0N/A * represented by a set of nonnegative integers
0N/A * separated by periods.
0N/A * @throws IOException if a parsing error occurs on the OID such as
0N/A * the first component is not 0, 1 or 2 or the second component is
0N/A * greater than 39.
0N/A * @see #getPolicy
0N/A */
0N/A public void setPolicy(Set<String> certPolicySet) throws IOException {
0N/A if (certPolicySet == null) {
0N/A policySet = null;
0N/A policy = null;
0N/A } else {
0N/A // Snapshot set and parse it
0N/A Set<String> tempSet = Collections.unmodifiableSet
0N/A (new HashSet<String>(certPolicySet));
0N/A /* Convert to Vector of ObjectIdentifiers */
0N/A Iterator<String> i = tempSet.iterator();
0N/A Vector<CertificatePolicyId> polIdVector = new Vector<CertificatePolicyId>();
0N/A while (i.hasNext()) {
0N/A Object o = i.next();
0N/A if (!(o instanceof String)) {
0N/A throw new IOException("non String in certPolicySet");
0N/A }
0N/A polIdVector.add(new CertificatePolicyId(new ObjectIdentifier(
0N/A (String)o)));
0N/A }
0N/A // If everything went OK, make the changes
0N/A policySet = tempSet;
0N/A policy = new CertificatePolicySet(polIdVector);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Sets the pathToNames criterion. The <code>X509Certificate</code> must
0N/A * not include name constraints that would prohibit building a
0N/A * path to the specified names.
0N/A * <p>
0N/A * This method allows the caller to specify, with a single method call,
0N/A * the complete set of names which the <code>X509Certificates</code>'s
0N/A * name constraints must permit. The specified value replaces
0N/A * the previous value for the pathToNames criterion.
0N/A * <p>
0N/A * This constraint is useful when building a certification path forward
0N/A * (from the target toward the trust anchor. If a partial path has been
0N/A * built, any candidate certificate must not include name constraints that
0N/A * would prohibit building a path to any of the names in the partial path.
0N/A * <p>
0N/A * The <code>names</code> parameter (if not <code>null</code>) is a
0N/A * <code>Collection</code> with one
0N/A * entry for each name to be included in the pathToNames
0N/A * criterion. Each entry is a <code>List</code> whose first entry is an
0N/A * <code>Integer</code> (the name type, 0-8) and whose second
0N/A * entry is a <code>String</code> or a byte array (the name, in
0N/A * string or ASN.1 DER encoded form, respectively).
0N/A * There can be multiple names of the same type. If <code>null</code>
0N/A * is supplied as the value for this argument, no
0N/A * pathToNames check will be performed.
0N/A * <p>
0N/A * Each name in the <code>Collection</code>
0N/A * may be specified either as a <code>String</code> or as an ASN.1 encoded
0N/A * byte array. For more details about the formats used, see
0N/A * {@link #addPathToName(int type, String name)
0N/A * addPathToName(int type, String name)} and
0N/A * {@link #addPathToName(int type, byte [] name)
0N/A * addPathToName(int type, byte [] name)}.
0N/A * <p>
0N/A * <strong>Note:</strong> for distinguished names, specify the byte
0N/A * array form instead of the String form. See the note in
0N/A * {@link #addPathToName(int, String)} for more information.
0N/A * <p>
0N/A * Note that the <code>names</code> parameter can contain duplicate
0N/A * names (same name and name type), but they may be removed from the
0N/A * <code>Collection</code> of names returned by the
0N/A * {@link #getPathToNames getPathToNames} method.
0N/A * <p>
0N/A * Note that a deep copy is performed on the <code>Collection</code> to
0N/A * protect against subsequent modifications.
0N/A *
0N/A * @param names a <code>Collection</code> with one entry per name
0N/A * (or <code>null</code>)
0N/A * @throws IOException if a parsing error occurs
0N/A * @see #getPathToNames
0N/A */
0N/A public void setPathToNames(Collection<List<?>> names) throws IOException {
0N/A if ((names == null) || names.isEmpty()) {
0N/A pathToNames = null;
0N/A pathToGeneralNames = null;
0N/A } else {
0N/A Set<List<?>> tempNames = cloneAndCheckNames(names);
0N/A pathToGeneralNames = parseNames(tempNames);
0N/A // Ensure that we either set both of these or neither
0N/A pathToNames = tempNames;
0N/A }
0N/A }
0N/A
0N/A // called from CertPathHelper
0N/A void setPathToNamesInternal(Set<GeneralNameInterface> names) {
0N/A // set names to non-null dummy value
0N/A // this breaks getPathToNames()
0N/A pathToNames = Collections.<List<?>>emptySet();
0N/A pathToGeneralNames = names;
0N/A }
0N/A
0N/A /**
0N/A * Adds a name to the pathToNames criterion. The <code>X509Certificate</code>
0N/A * must not include name constraints that would prohibit building a
0N/A * path to the specified name.
0N/A * <p>
0N/A * This method allows the caller to add a name to the set of names which
0N/A * the <code>X509Certificates</code>'s name constraints must permit.
0N/A * The specified name is added to any previous value for the
0N/A * pathToNames criterion. If the name is a duplicate, it may be ignored.
0N/A * <p>
0N/A * The name is provided in string format. RFC 822, DNS, and URI names
0N/A * use the well-established string formats for those types (subject to
0N/A * the restrictions included in RFC 3280). IPv4 address names are
0N/A * supplied using dotted quad notation. OID address names are represented
0N/A * as a series of nonnegative integers separated by periods. And
0N/A * directory names (distinguished names) are supplied in RFC 2253 format.
0N/A * No standard string format is defined for otherNames, X.400 names,
0N/A * EDI party names, IPv6 address names, or any other type of names. They
0N/A * should be specified using the
0N/A * {@link #addPathToName(int type, byte [] name)
0N/A * addPathToName(int type, byte [] name)} method.
0N/A * <p>
0N/A * <strong>Note:</strong> for distinguished names, use
0N/A * {@linkplain #addPathToName(int, byte[])} instead.
0N/A * This method should not be relied on as it can fail to match some
0N/A * certificates because of a loss of encoding information in the RFC 2253
0N/A * String form of some distinguished names.
0N/A *
0N/A * @param type the name type (0-8, as specified in
0N/A * RFC 3280, section 4.2.1.7)
0N/A * @param name the name in string form
0N/A * @throws IOException if a parsing error occurs
0N/A */
0N/A public void addPathToName(int type, String name) throws IOException {
0N/A addPathToNameInternal(type, name);
0N/A }
0N/A
0N/A /**
0N/A * Adds a name to the pathToNames criterion. The <code>X509Certificate</code>
0N/A * must not include name constraints that would prohibit building a
0N/A * path to the specified name.
0N/A * <p>
0N/A * This method allows the caller to add a name to the set of names which
0N/A * the <code>X509Certificates</code>'s name constraints must permit.
0N/A * The specified name is added to any previous value for the
0N/A * pathToNames criterion. If the name is a duplicate, it may be ignored.
0N/A * <p>
0N/A * The name is provided as a byte array. This byte array should contain
0N/A * the DER encoded name, as it would appear in the GeneralName structure
0N/A * defined in RFC 3280 and X.509. The ASN.1 definition of this structure
0N/A * appears in the documentation for
0N/A * {@link #addSubjectAlternativeName(int type, byte [] name)
0N/A * addSubjectAlternativeName(int type, byte [] name)}.
0N/A * <p>
0N/A * Note that the byte array supplied here is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @param type the name type (0-8, as specified in
0N/A * RFC 3280, section 4.2.1.7)
0N/A * @param name a byte array containing the name in ASN.1 DER encoded form
0N/A * @throws IOException if a parsing error occurs
0N/A */
0N/A public void addPathToName(int type, byte [] name) throws IOException {
0N/A // clone because byte arrays are modifiable
0N/A addPathToNameInternal(type, name.clone());
0N/A }
0N/A
0N/A /**
0N/A * A private method that adds a name (String or byte array) to the
0N/A * pathToNames criterion. The <code>X509Certificate</code> must contain
0N/A * the specified pathToName.
0N/A *
0N/A * @param type the name type (0-8, as specified in
0N/A * RFC 3280, section 4.2.1.7)
0N/A * @param name the name in string or byte array form
0N/A * @throws IOException if an encoding error occurs (incorrect form for DN)
0N/A */
0N/A private void addPathToNameInternal(int type, Object name)
0N/A throws IOException {
0N/A // First, ensure that the name parses
0N/A GeneralNameInterface tempName = makeGeneralNameInterface(type, name);
0N/A if (pathToGeneralNames == null) {
0N/A pathToNames = new HashSet<List<?>>();
0N/A pathToGeneralNames = new HashSet<GeneralNameInterface>();
0N/A }
0N/A List<Object> list = new ArrayList<Object>(2);
0N/A list.add(Integer.valueOf(type));
0N/A list.add(name);
0N/A pathToNames.add(list);
0N/A pathToGeneralNames.add(tempName);
0N/A }
0N/A
0N/A /**
0N/A * Returns the certificateEquals criterion. The specified
0N/A * <code>X509Certificate</code> must be equal to the
0N/A * <code>X509Certificate</code> passed to the <code>match</code> method.
0N/A * If <code>null</code>, this check is not applied.
0N/A *
0N/A * @return the <code>X509Certificate</code> to match (or <code>null</code>)
0N/A * @see #setCertificate
0N/A */
0N/A public X509Certificate getCertificate() {
0N/A return x509Cert;
0N/A }
0N/A
0N/A /**
0N/A * Returns the serialNumber criterion. The specified serial number
0N/A * must match the certificate serial number in the
0N/A * <code>X509Certificate</code>. If <code>null</code>, any certificate
0N/A * serial number will do.
0N/A *
0N/A * @return the certificate serial number to match
0N/A * (or <code>null</code>)
0N/A * @see #setSerialNumber
0N/A */
0N/A public BigInteger getSerialNumber() {
0N/A return serialNumber;
0N/A }
0N/A
0N/A /**
0N/A * Returns the issuer criterion as an <code>X500Principal</code>. This
0N/A * distinguished name must match the issuer distinguished name in the
0N/A * <code>X509Certificate</code>. If <code>null</code>, the issuer criterion
0N/A * is disabled and any issuer distinguished name will do.
0N/A *
0N/A * @return the required issuer distinguished name as X500Principal
0N/A * (or <code>null</code>)
0N/A * @since 1.5
0N/A */
0N/A public X500Principal getIssuer() {
0N/A return issuer;
0N/A }
0N/A
0N/A /**
0N/A * <strong>Denigrated</strong>, use {@linkplain #getIssuer()} or
0N/A * {@linkplain #getIssuerAsBytes()} instead. This method should not be
0N/A * relied on as it can fail to match some certificates because of a loss of
0N/A * encoding information in the RFC 2253 String form of some distinguished
0N/A * names.
0N/A * <p>
0N/A * Returns the issuer criterion as a <code>String</code>. This
0N/A * distinguished name must match the issuer distinguished name in the
0N/A * <code>X509Certificate</code>. If <code>null</code>, the issuer criterion
0N/A * is disabled and any issuer distinguished name will do.
0N/A * <p>
0N/A * If the value returned is not <code>null</code>, it is a
0N/A * distinguished name, in RFC 2253 format.
0N/A *
0N/A * @return the required issuer distinguished name in RFC 2253 format
0N/A * (or <code>null</code>)
0N/A */
0N/A public String getIssuerAsString() {
0N/A return (issuer == null ? null : issuer.getName());
0N/A }
0N/A
0N/A /**
0N/A * Returns the issuer criterion as a byte array. This distinguished name
0N/A * must match the issuer distinguished name in the
0N/A * <code>X509Certificate</code>. If <code>null</code>, the issuer criterion
0N/A * is disabled and any issuer distinguished name will do.
0N/A * <p>
0N/A * If the value returned is not <code>null</code>, it is a byte
0N/A * array containing a single DER encoded distinguished name, as defined in
0N/A * X.501. The ASN.1 notation for this structure is supplied in the
0N/A * documentation for
0N/A * {@link #setIssuer(byte [] issuerDN) setIssuer(byte [] issuerDN)}.
0N/A * <p>
0N/A * Note that the byte array returned is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @return a byte array containing the required issuer distinguished name
0N/A * in ASN.1 DER format (or <code>null</code>)
0N/A * @throws IOException if an encoding error occurs
0N/A */
0N/A public byte[] getIssuerAsBytes() throws IOException {
0N/A return (issuer == null ? null: issuer.getEncoded());
0N/A }
0N/A
0N/A /**
0N/A * Returns the subject criterion as an <code>X500Principal</code>. This
0N/A * distinguished name must match the subject distinguished name in the
0N/A * <code>X509Certificate</code>. If <code>null</code>, the subject criterion
0N/A * is disabled and any subject distinguished name will do.
0N/A *
0N/A * @return the required subject distinguished name as X500Principal
0N/A * (or <code>null</code>)
0N/A * @since 1.5
0N/A */
0N/A public X500Principal getSubject() {
0N/A return subject;
0N/A }
0N/A
0N/A /**
0N/A * <strong>Denigrated</strong>, use {@linkplain #getSubject()} or
0N/A * {@linkplain #getSubjectAsBytes()} instead. This method should not be
0N/A * relied on as it can fail to match some certificates because of a loss of
0N/A * encoding information in the RFC 2253 String form of some distinguished
0N/A * names.
0N/A * <p>
0N/A * Returns the subject criterion as a <code>String</code>. This
0N/A * distinguished name must match the subject distinguished name in the
0N/A * <code>X509Certificate</code>. If <code>null</code>, the subject criterion
0N/A * is disabled and any subject distinguished name will do.
0N/A * <p>
0N/A * If the value returned is not <code>null</code>, it is a
0N/A * distinguished name, in RFC 2253 format.
0N/A *
0N/A * @return the required subject distinguished name in RFC 2253 format
0N/A * (or <code>null</code>)
0N/A */
0N/A public String getSubjectAsString() {
0N/A return (subject == null ? null : subject.getName());
0N/A }
0N/A
0N/A /**
0N/A * Returns the subject criterion as a byte array. This distinguished name
0N/A * must match the subject distinguished name in the
0N/A * <code>X509Certificate</code>. If <code>null</code>, the subject criterion
0N/A * is disabled and any subject distinguished name will do.
0N/A * <p>
0N/A * If the value returned is not <code>null</code>, it is a byte
0N/A * array containing a single DER encoded distinguished name, as defined in
0N/A * X.501. The ASN.1 notation for this structure is supplied in the
0N/A * documentation for
0N/A * {@link #setSubject(byte [] subjectDN) setSubject(byte [] subjectDN)}.
0N/A * <p>
0N/A * Note that the byte array returned is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @return a byte array containing the required subject distinguished name
0N/A * in ASN.1 DER format (or <code>null</code>)
0N/A * @throws IOException if an encoding error occurs
0N/A */
0N/A public byte[] getSubjectAsBytes() throws IOException {
0N/A return (subject == null ? null : subject.getEncoded());
0N/A }
0N/A
0N/A /**
0N/A * Returns the subjectKeyIdentifier criterion. The
0N/A * <code>X509Certificate</code> must contain a SubjectKeyIdentifier
0N/A * extension with the specified value. If <code>null</code>, no
0N/A * subjectKeyIdentifier check will be done.
0N/A * <p>
0N/A * Note that the byte array returned is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @return the key identifier (or <code>null</code>)
0N/A * @see #setSubjectKeyIdentifier
0N/A */
0N/A public byte[] getSubjectKeyIdentifier() {
0N/A if (subjectKeyID == null) {
0N/A return null;
0N/A }
28N/A return subjectKeyID.clone();
0N/A }
0N/A
0N/A /**
0N/A * Returns the authorityKeyIdentifier criterion. The
0N/A * <code>X509Certificate</code> must contain a AuthorityKeyIdentifier
0N/A * extension with the specified value. If <code>null</code>, no
0N/A * authorityKeyIdentifier check will be done.
0N/A * <p>
0N/A * Note that the byte array returned is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @return the key identifier (or <code>null</code>)
0N/A * @see #setAuthorityKeyIdentifier
0N/A */
0N/A public byte[] getAuthorityKeyIdentifier() {
0N/A if (authorityKeyID == null) {
0N/A return null;
0N/A }
28N/A return authorityKeyID.clone();
0N/A }
0N/A
0N/A /**
0N/A * Returns the certificateValid criterion. The specified date must fall
0N/A * within the certificate validity period for the
0N/A * <code>X509Certificate</code>. If <code>null</code>, no certificateValid
0N/A * check will be done.
0N/A * <p>
0N/A * Note that the <code>Date</code> returned is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @return the <code>Date</code> to check (or <code>null</code>)
0N/A * @see #setCertificateValid
0N/A */
0N/A public Date getCertificateValid() {
0N/A if (certificateValid == null) {
0N/A return null;
0N/A }
0N/A return (Date)certificateValid.clone();
0N/A }
0N/A
0N/A /**
0N/A * Returns the privateKeyValid criterion. The specified date must fall
0N/A * within the private key validity period for the
0N/A * <code>X509Certificate</code>. If <code>null</code>, no privateKeyValid
0N/A * check will be done.
0N/A * <p>
0N/A * Note that the <code>Date</code> returned is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @return the <code>Date</code> to check (or <code>null</code>)
0N/A * @see #setPrivateKeyValid
0N/A */
0N/A public Date getPrivateKeyValid() {
0N/A if (privateKeyValid == null) {
0N/A return null;
0N/A }
0N/A return (Date)privateKeyValid.clone();
0N/A }
0N/A
0N/A /**
0N/A * Returns the subjectPublicKeyAlgID criterion. The
0N/A * <code>X509Certificate</code> must contain a subject public key
0N/A * with the specified algorithm. If <code>null</code>, no
0N/A * subjectPublicKeyAlgID check will be done.
0N/A *
0N/A * @return the object identifier (OID) of the signature algorithm to check
0N/A * for (or <code>null</code>). An OID is represented by a set of
0N/A * nonnegative integers separated by periods.
0N/A * @see #setSubjectPublicKeyAlgID
0N/A */
0N/A public String getSubjectPublicKeyAlgID() {
0N/A if (subjectPublicKeyAlgID == null) {
0N/A return null;
0N/A }
0N/A return subjectPublicKeyAlgID.toString();
0N/A }
0N/A
0N/A /**
0N/A * Returns the subjectPublicKey criterion. The
0N/A * <code>X509Certificate</code> must contain the specified subject
0N/A * public key. If <code>null</code>, no subjectPublicKey check will be done.
0N/A *
0N/A * @return the subject public key to check for (or <code>null</code>)
0N/A * @see #setSubjectPublicKey
0N/A */
0N/A public PublicKey getSubjectPublicKey() {
0N/A return subjectPublicKey;
0N/A }
0N/A
0N/A /**
0N/A * Returns the keyUsage criterion. The <code>X509Certificate</code>
0N/A * must allow the specified keyUsage values. If null, no keyUsage
0N/A * check will be done.
0N/A * <p>
0N/A * Note that the boolean array returned is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @return a boolean array in the same format as the boolean
0N/A * array returned by
0N/A * {@link X509Certificate#getKeyUsage() X509Certificate.getKeyUsage()}.
0N/A * Or <code>null</code>.
0N/A * @see #setKeyUsage
0N/A */
0N/A public boolean[] getKeyUsage() {
0N/A if (keyUsage == null) {
0N/A return null;
0N/A }
28N/A return keyUsage.clone();
0N/A }
0N/A
0N/A /**
0N/A * Returns the extendedKeyUsage criterion. The <code>X509Certificate</code>
0N/A * must allow the specified key purposes in its extended key usage
0N/A * extension. If the <code>keyPurposeSet</code> returned is empty or
0N/A * <code>null</code>, no extendedKeyUsage check will be done. Note that an
0N/A * <code>X509Certificate</code> that has no extendedKeyUsage extension
0N/A * implicitly allows all key purposes.
0N/A *
0N/A * @return an immutable <code>Set</code> of key purpose OIDs in string
0N/A * format (or <code>null</code>)
0N/A * @see #setExtendedKeyUsage
0N/A */
0N/A public Set<String> getExtendedKeyUsage() {
0N/A return keyPurposeSet;
0N/A }
0N/A
0N/A /**
0N/A * Indicates if the <code>X509Certificate</code> must contain all
0N/A * or at least one of the subjectAlternativeNames
0N/A * specified in the {@link #setSubjectAlternativeNames
0N/A * setSubjectAlternativeNames} or {@link #addSubjectAlternativeName
0N/A * addSubjectAlternativeName} methods. If <code>true</code>,
0N/A * the <code>X509Certificate</code> must contain all of the
0N/A * specified subject alternative names. If <code>false</code>, the
0N/A * <code>X509Certificate</code> must contain at least one of the
0N/A * specified subject alternative names.
0N/A *
0N/A * @return <code>true</code> if the flag is enabled;
0N/A * <code>false</code> if the flag is disabled. The flag is
0N/A * <code>true</code> by default.
0N/A * @see #setMatchAllSubjectAltNames
0N/A */
0N/A public boolean getMatchAllSubjectAltNames() {
0N/A return matchAllSubjectAltNames;
0N/A }
0N/A
0N/A /**
0N/A * Returns a copy of the subjectAlternativeNames criterion.
0N/A * The <code>X509Certificate</code> must contain all or at least one
0N/A * of the specified subjectAlternativeNames, depending on the value
0N/A * of the matchAllNames flag (see {@link #getMatchAllSubjectAltNames
0N/A * getMatchAllSubjectAltNames}). If the value returned is
0N/A * <code>null</code>, no subjectAlternativeNames check will be performed.
0N/A * <p>
0N/A * If the value returned is not <code>null</code>, it is a
0N/A * <code>Collection</code> with
0N/A * one entry for each name to be included in the subject alternative name
0N/A * criterion. Each entry is a <code>List</code> whose first entry is an
0N/A * <code>Integer</code> (the name type, 0-8) and whose second
0N/A * entry is a <code>String</code> or a byte array (the name, in
0N/A * string or ASN.1 DER encoded form, respectively).
0N/A * There can be multiple names of the same type. Note that the
0N/A * <code>Collection</code> returned may contain duplicate names (same name
0N/A * and name type).
0N/A * <p>
0N/A * Each subject alternative name in the <code>Collection</code>
0N/A * may be specified either as a <code>String</code> or as an ASN.1 encoded
0N/A * byte array. For more details about the formats used, see
0N/A * {@link #addSubjectAlternativeName(int type, String name)
0N/A * addSubjectAlternativeName(int type, String name)} and
0N/A * {@link #addSubjectAlternativeName(int type, byte [] name)
0N/A * addSubjectAlternativeName(int type, byte [] name)}.
0N/A * <p>
0N/A * Note that a deep copy is performed on the <code>Collection</code> to
0N/A * protect against subsequent modifications.
0N/A *
0N/A * @return a <code>Collection</code> of names (or <code>null</code>)
0N/A * @see #setSubjectAlternativeNames
0N/A */
0N/A public Collection<List<?>> getSubjectAlternativeNames() {
0N/A if (subjectAlternativeNames == null) {
0N/A return null;
0N/A }
0N/A return cloneNames(subjectAlternativeNames);
0N/A }
0N/A
0N/A /**
0N/A * Clone an object of the form passed to
0N/A * setSubjectAlternativeNames and setPathToNames.
0N/A * Throw a <code>RuntimeException</code> if the argument is malformed.
0N/A * <p>
0N/A * This method wraps cloneAndCheckNames, changing any
0N/A * <code>IOException</code> into a <code>RuntimeException</code>. This
0N/A * method should be used when the object being
0N/A * cloned has already been checked, so there should never be any exceptions.
0N/A *
0N/A * @param names a <code>Collection</code> with one entry per name.
0N/A * Each entry is a <code>List</code> whose first entry
0N/A * is an Integer (the name type, 0-8) and whose second
0N/A * entry is a String or a byte array (the name, in
0N/A * string or ASN.1 DER encoded form, respectively).
0N/A * There can be multiple names of the same type. Null
0N/A * is not an acceptable value.
0N/A * @return a deep copy of the specified <code>Collection</code>
0N/A * @throws RuntimeException if a parsing error occurs
0N/A */
0N/A private static Set<List<?>> cloneNames(Collection<List<?>> names) {
0N/A try {
0N/A return cloneAndCheckNames(names);
0N/A } catch (IOException e) {
0N/A throw new RuntimeException("cloneNames encountered IOException: " +
0N/A e.getMessage());
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Clone and check an argument of the form passed to
0N/A * setSubjectAlternativeNames and setPathToNames.
0N/A * Throw an <code>IOException</code> if the argument is malformed.
0N/A *
0N/A * @param names a <code>Collection</code> with one entry per name.
0N/A * Each entry is a <code>List</code> whose first entry
0N/A * is an Integer (the name type, 0-8) and whose second
0N/A * entry is a String or a byte array (the name, in
0N/A * string or ASN.1 DER encoded form, respectively).
0N/A * There can be multiple names of the same type.
0N/A * <code>null</code> is not an acceptable value.
0N/A * @return a deep copy of the specified <code>Collection</code>
0N/A * @throws IOException if a parsing error occurs
0N/A */
0N/A private static Set<List<?>> cloneAndCheckNames(Collection<List<?>> names) throws IOException {
0N/A // Copy the Lists and Collection
0N/A Set<List<?>> namesCopy = new HashSet<List<?>>();
0N/A Iterator<List<?>> i = names.iterator();
0N/A while (i.hasNext()) {
0N/A Object o = i.next();
0N/A if (!(o instanceof List)) {
0N/A throw new IOException("expected a List");
0N/A }
0N/A namesCopy.add(new ArrayList<Object>((List<?>)o));
0N/A }
0N/A
0N/A // Check the contents of the Lists and clone any byte arrays
0N/A i = namesCopy.iterator();
0N/A while (i.hasNext()) {
0N/A List<Object> nameList = (List<Object>)i.next();
0N/A if (nameList.size() != 2) {
0N/A throw new IOException("name list size not 2");
0N/A }
0N/A Object o = nameList.get(0);
0N/A if (!(o instanceof Integer)) {
0N/A throw new IOException("expected an Integer");
0N/A }
0N/A int nameType = ((Integer)o).intValue();
0N/A if ((nameType < 0) || (nameType > 8)) {
0N/A throw new IOException("name type not 0-8");
0N/A }
0N/A Object nameObject = nameList.get(1);
0N/A if (!(nameObject instanceof byte[]) &&
0N/A !(nameObject instanceof String)) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.cloneAndCheckNames() "
0N/A + "name not byte array");
0N/A }
0N/A throw new IOException("name not byte array or String");
0N/A }
0N/A if (nameObject instanceof byte[]) {
0N/A nameList.set(1, ((byte[]) nameObject).clone());
0N/A }
0N/A }
0N/A return namesCopy;
0N/A }
0N/A
0N/A /**
0N/A * Returns the name constraints criterion. The <code>X509Certificate</code>
0N/A * must have subject and subject alternative names that
0N/A * meet the specified name constraints.
0N/A * <p>
0N/A * The name constraints are returned as a byte array. This byte array
0N/A * contains the DER encoded form of the name constraints, as they
0N/A * would appear in the NameConstraints structure defined in RFC 3280
0N/A * and X.509. The ASN.1 notation for this structure is supplied in the
0N/A * documentation for
0N/A * {@link #setNameConstraints(byte [] bytes) setNameConstraints(byte [] bytes)}.
0N/A * <p>
0N/A * Note that the byte array returned is cloned to protect against
0N/A * subsequent modifications.
0N/A *
0N/A * @return a byte array containing the ASN.1 DER encoding of
0N/A * a NameConstraints extension used for checking name constraints.
0N/A * <code>null</code> if no name constraints check will be performed.
0N/A * @see #setNameConstraints
0N/A */
0N/A public byte[] getNameConstraints() {
0N/A if (ncBytes == null) {
0N/A return null;
0N/A } else {
28N/A return ncBytes.clone();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the basic constraints constraint. If the value is greater than
0N/A * or equal to zero, the <code>X509Certificates</code> must include a
0N/A * basicConstraints extension with a pathLen of at least this value.
0N/A * If the value is -2, only end-entity certificates are accepted. If
0N/A * the value is -1, no basicConstraints check is done.
0N/A *
0N/A * @return the value for the basic constraints constraint
0N/A * @see #setBasicConstraints
0N/A */
0N/A public int getBasicConstraints() {
0N/A return basicConstraints;
0N/A }
0N/A
0N/A /**
0N/A * Returns the policy criterion. The <code>X509Certificate</code> must
0N/A * include at least one of the specified policies in its certificate policies
0N/A * extension. If the <code>Set</code> returned is empty, then the
0N/A * <code>X509Certificate</code> must include at least some specified policy
0N/A * in its certificate policies extension. If the <code>Set</code> returned is
0N/A * <code>null</code>, no policy check will be performed.
0N/A *
0N/A * @return an immutable <code>Set</code> of certificate policy OIDs in
0N/A * string format (or <code>null</code>)
0N/A * @see #setPolicy
0N/A */
0N/A public Set<String> getPolicy() {
0N/A return policySet;
0N/A }
0N/A
0N/A /**
0N/A * Returns a copy of the pathToNames criterion. The
0N/A * <code>X509Certificate</code> must not include name constraints that would
0N/A * prohibit building a path to the specified names. If the value
0N/A * returned is <code>null</code>, no pathToNames check will be performed.
0N/A * <p>
0N/A * If the value returned is not <code>null</code>, it is a
0N/A * <code>Collection</code> with one
0N/A * entry for each name to be included in the pathToNames
0N/A * criterion. Each entry is a <code>List</code> whose first entry is an
0N/A * <code>Integer</code> (the name type, 0-8) and whose second
0N/A * entry is a <code>String</code> or a byte array (the name, in
0N/A * string or ASN.1 DER encoded form, respectively).
0N/A * There can be multiple names of the same type. Note that the
0N/A * <code>Collection</code> returned may contain duplicate names (same
0N/A * name and name type).
0N/A * <p>
0N/A * Each name in the <code>Collection</code>
0N/A * may be specified either as a <code>String</code> or as an ASN.1 encoded
0N/A * byte array. For more details about the formats used, see
0N/A * {@link #addPathToName(int type, String name)
0N/A * addPathToName(int type, String name)} and
0N/A * {@link #addPathToName(int type, byte [] name)
0N/A * addPathToName(int type, byte [] name)}.
0N/A * <p>
0N/A * Note that a deep copy is performed on the <code>Collection</code> to
0N/A * protect against subsequent modifications.
0N/A *
0N/A * @return a <code>Collection</code> of names (or <code>null</code>)
0N/A * @see #setPathToNames
0N/A */
0N/A public Collection<List<?>> getPathToNames() {
0N/A if (pathToNames == null) {
0N/A return null;
0N/A }
0N/A return cloneNames(pathToNames);
0N/A }
0N/A
0N/A /**
0N/A * Return a printable representation of the <code>CertSelector</code>.
0N/A *
0N/A * @return a <code>String</code> describing the contents of the
0N/A * <code>CertSelector</code>
0N/A */
0N/A public String toString() {
0N/A StringBuffer sb = new StringBuffer();
0N/A sb.append("X509CertSelector: [\n");
0N/A if (x509Cert != null) {
0N/A sb.append(" Certificate: " + x509Cert.toString() + "\n");
0N/A }
0N/A if (serialNumber != null) {
0N/A sb.append(" Serial Number: " + serialNumber.toString() + "\n");
0N/A }
0N/A if (issuer != null) {
0N/A sb.append(" Issuer: " + getIssuerAsString() + "\n");
0N/A }
0N/A if (subject != null) {
0N/A sb.append(" Subject: " + getSubjectAsString() + "\n");
0N/A }
0N/A sb.append(" matchAllSubjectAltNames flag: "
0N/A + String.valueOf(matchAllSubjectAltNames) + "\n");
0N/A if (subjectAlternativeNames != null) {
0N/A sb.append(" SubjectAlternativeNames:\n");
0N/A Iterator<List<?>> i = subjectAlternativeNames.iterator();
0N/A while (i.hasNext()) {
0N/A List<?> list = i.next();
0N/A sb.append(" type " + list.get(0) +
0N/A ", name " + list.get(1) + "\n");
0N/A }
0N/A }
0N/A if (subjectKeyID != null) {
0N/A HexDumpEncoder enc = new HexDumpEncoder();
0N/A sb.append(" Subject Key Identifier: " +
0N/A enc.encodeBuffer(subjectKeyID) + "\n");
0N/A }
0N/A if (authorityKeyID != null) {
0N/A HexDumpEncoder enc = new HexDumpEncoder();
0N/A sb.append(" Authority Key Identifier: " +
0N/A enc.encodeBuffer(authorityKeyID) + "\n");
0N/A }
0N/A if (certificateValid != null) {
0N/A sb.append(" Certificate Valid: " +
0N/A certificateValid.toString() + "\n");
0N/A }
0N/A if (privateKeyValid != null) {
0N/A sb.append(" Private Key Valid: " +
0N/A privateKeyValid.toString() + "\n");
0N/A }
0N/A if (subjectPublicKeyAlgID != null) {
0N/A sb.append(" Subject Public Key AlgID: " +
0N/A subjectPublicKeyAlgID.toString() + "\n");
0N/A }
0N/A if (subjectPublicKey != null) {
0N/A sb.append(" Subject Public Key: " +
0N/A subjectPublicKey.toString() + "\n");
0N/A }
0N/A if (keyUsage != null) {
0N/A sb.append(" Key Usage: " + keyUsageToString(keyUsage) + "\n");
0N/A }
0N/A if (keyPurposeSet != null) {
0N/A sb.append(" Extended Key Usage: " +
0N/A keyPurposeSet.toString() + "\n");
0N/A }
0N/A if (policy != null) {
0N/A sb.append(" Policy: " + policy.toString() + "\n");
0N/A }
0N/A if (pathToGeneralNames != null) {
0N/A sb.append(" Path to names:\n");
0N/A Iterator<GeneralNameInterface> i = pathToGeneralNames.iterator();
0N/A while (i.hasNext()) {
0N/A sb.append(" " + i.next() + "\n");
0N/A }
0N/A }
0N/A sb.append("]");
0N/A return sb.toString();
0N/A }
0N/A
0N/A // Copied from sun.security.x509.KeyUsageExtension
0N/A // (without calling the superclass)
0N/A /**
0N/A * Returns a printable representation of the KeyUsage.
0N/A */
0N/A private static String keyUsageToString(boolean[] k) {
0N/A String s = "KeyUsage [\n";
0N/A try {
0N/A if (k[0]) {
0N/A s += " DigitalSignature\n";
0N/A }
0N/A if (k[1]) {
0N/A s += " Non_repudiation\n";
0N/A }
0N/A if (k[2]) {
0N/A s += " Key_Encipherment\n";
0N/A }
0N/A if (k[3]) {
0N/A s += " Data_Encipherment\n";
0N/A }
0N/A if (k[4]) {
0N/A s += " Key_Agreement\n";
0N/A }
0N/A if (k[5]) {
0N/A s += " Key_CertSign\n";
0N/A }
0N/A if (k[6]) {
0N/A s += " Crl_Sign\n";
0N/A }
0N/A if (k[7]) {
0N/A s += " Encipher_Only\n";
0N/A }
0N/A if (k[8]) {
0N/A s += " Decipher_Only\n";
0N/A }
0N/A } catch (ArrayIndexOutOfBoundsException ex) {}
0N/A
0N/A s += "]\n";
0N/A
0N/A return (s);
0N/A }
0N/A
0N/A /**
0N/A * Returns an Extension object given any X509Certificate and extension oid.
0N/A * Throw an <code>IOException</code> if the extension byte value is
0N/A * malformed.
0N/A *
0N/A * @param cert a <code>X509Certificate</code>
0N/A * @param extId an <code>integer</code> which specifies the extension index.
0N/A * Currently, the supported extensions are as follows:
0N/A * index 0 - PrivateKeyUsageExtension
0N/A * index 1 - SubjectAlternativeNameExtension
0N/A * index 2 - NameConstraintsExtension
0N/A * index 3 - CertificatePoliciesExtension
0N/A * index 4 - ExtendedKeyUsageExtension
0N/A * @return an <code>Extension</code> object whose real type is as specified
0N/A * by the extension oid.
0N/A * @throws IOException if cannot construct the <code>Extension</code>
0N/A * object with the extension encoding retrieved from the passed in
0N/A * <code>X509Certificate</code>.
0N/A */
0N/A private static Extension getExtensionObject(X509Certificate cert, int extId)
0N/A throws IOException {
0N/A if (cert instanceof X509CertImpl) {
0N/A X509CertImpl impl = (X509CertImpl)cert;
0N/A switch (extId) {
0N/A case PRIVATE_KEY_USAGE_ID:
0N/A return impl.getPrivateKeyUsageExtension();
0N/A case SUBJECT_ALT_NAME_ID:
0N/A return impl.getSubjectAlternativeNameExtension();
0N/A case NAME_CONSTRAINTS_ID:
0N/A return impl.getNameConstraintsExtension();
0N/A case CERT_POLICIES_ID:
0N/A return impl.getCertificatePoliciesExtension();
0N/A case EXTENDED_KEY_USAGE_ID:
0N/A return impl.getExtendedKeyUsageExtension();
0N/A default:
0N/A return null;
0N/A }
0N/A }
0N/A byte[] rawExtVal = cert.getExtensionValue(EXTENSION_OIDS[extId]);
0N/A if (rawExtVal == null) {
0N/A return null;
0N/A }
0N/A DerInputStream in = new DerInputStream(rawExtVal);
0N/A byte[] encoded = in.getOctetString();
0N/A switch (extId) {
0N/A case PRIVATE_KEY_USAGE_ID:
0N/A try {
0N/A return new PrivateKeyUsageExtension(FALSE, encoded);
0N/A } catch (CertificateException ex) {
0N/A throw new IOException(ex.getMessage());
0N/A }
0N/A case SUBJECT_ALT_NAME_ID:
0N/A return new SubjectAlternativeNameExtension(FALSE, encoded);
0N/A case NAME_CONSTRAINTS_ID:
0N/A return new NameConstraintsExtension(FALSE, encoded);
0N/A case CERT_POLICIES_ID:
0N/A return new CertificatePoliciesExtension(FALSE, encoded);
0N/A case EXTENDED_KEY_USAGE_ID:
0N/A return new ExtendedKeyUsageExtension(FALSE, encoded);
0N/A default:
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Decides whether a <code>Certificate</code> should be selected.
0N/A *
0N/A * @param cert the <code>Certificate</code> to be checked
0N/A * @return <code>true</code> if the <code>Certificate</code> should be
0N/A * selected, <code>false</code> otherwise
0N/A */
0N/A public boolean match(Certificate cert) {
0N/A if (!(cert instanceof X509Certificate)) {
0N/A return false;
0N/A }
0N/A X509Certificate xcert = (X509Certificate)cert;
0N/A
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match(SN: "
0N/A + (xcert.getSerialNumber()).toString(16) + "\n Issuer: "
0N/A + xcert.getIssuerDN() + "\n Subject: " + xcert.getSubjectDN()
0N/A + ")");
0N/A }
0N/A
0N/A /* match on X509Certificate */
0N/A if (x509Cert != null) {
0N/A if (!x509Cert.equals(xcert)) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "certs don't match");
0N/A }
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A /* match on serial number */
0N/A if (serialNumber != null) {
0N/A if (!serialNumber.equals(xcert.getSerialNumber())) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "serial numbers don't match");
0N/A }
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A /* match on issuer name */
0N/A if (issuer != null) {
0N/A if (!issuer.equals(xcert.getIssuerX500Principal())) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "issuer DNs don't match");
0N/A }
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A /* match on subject name */
0N/A if (subject != null) {
0N/A if (!subject.equals(xcert.getSubjectX500Principal())) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "subject DNs don't match");
0N/A }
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A /* match on certificate validity range */
0N/A if (certificateValid != null) {
0N/A try {
0N/A xcert.checkValidity(certificateValid);
0N/A } catch (CertificateException e) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "certificate not within validity period");
0N/A }
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A /* match on subject public key */
0N/A if (subjectPublicKeyBytes != null) {
0N/A byte[] certKey = xcert.getPublicKey().getEncoded();
0N/A if (!Arrays.equals(subjectPublicKeyBytes, certKey)) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "subject public keys don't match");
0N/A }
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A boolean result = matchBasicConstraints(xcert)
0N/A && matchKeyUsage(xcert)
0N/A && matchExtendedKeyUsage(xcert)
0N/A && matchSubjectKeyID(xcert)
0N/A && matchAuthorityKeyID(xcert)
0N/A && matchPrivateKeyValid(xcert)
0N/A && matchSubjectPublicKeyAlgID(xcert)
0N/A && matchPolicy(xcert)
0N/A && matchSubjectAlternativeNames(xcert)
0N/A && matchPathToNames(xcert)
0N/A && matchNameConstraints(xcert);
0N/A
0N/A if (result && (debug != null)) {
0N/A debug.println("X509CertSelector.match returning: true");
0N/A }
0N/A return result;
0N/A }
0N/A
0N/A /* match on subject key identifier extension value */
0N/A private boolean matchSubjectKeyID(X509Certificate xcert) {
0N/A if (subjectKeyID == null) {
0N/A return true;
0N/A }
0N/A try {
0N/A byte[] extVal = xcert.getExtensionValue("2.5.29.14");
0N/A if (extVal == null) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "no subject key ID extension");
0N/A }
0N/A return false;
0N/A }
0N/A DerInputStream in = new DerInputStream(extVal);
0N/A byte[] certSubjectKeyID = in.getOctetString();
0N/A if (certSubjectKeyID == null ||
0N/A !Arrays.equals(subjectKeyID, certSubjectKeyID)) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "subject key IDs don't match");
0N/A }
0N/A return false;
0N/A }
0N/A } catch (IOException ex) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "exception in subject key ID check");
0N/A }
0N/A return false;
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A /* match on authority key identifier extension value */
0N/A private boolean matchAuthorityKeyID(X509Certificate xcert) {
0N/A if (authorityKeyID == null) {
0N/A return true;
0N/A }
0N/A try {
0N/A byte[] extVal = xcert.getExtensionValue("2.5.29.35");
0N/A if (extVal == null) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "no authority key ID extension");
0N/A }
0N/A return false;
0N/A }
0N/A DerInputStream in = new DerInputStream(extVal);
0N/A byte[] certAuthKeyID = in.getOctetString();
0N/A if (certAuthKeyID == null ||
0N/A !Arrays.equals(authorityKeyID, certAuthKeyID)) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "authority key IDs don't match");
0N/A }
0N/A return false;
0N/A }
0N/A } catch (IOException ex) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "exception in authority key ID check");
0N/A }
0N/A return false;
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A /* match on private key usage range */
0N/A private boolean matchPrivateKeyValid(X509Certificate xcert) {
0N/A if (privateKeyValid == null) {
0N/A return true;
0N/A }
0N/A PrivateKeyUsageExtension ext = null;
0N/A try {
0N/A ext = (PrivateKeyUsageExtension)
0N/A getExtensionObject(xcert, PRIVATE_KEY_USAGE_ID);
0N/A if (ext != null) {
0N/A ext.valid(privateKeyValid);
0N/A }
0N/A } catch (CertificateExpiredException e1) {
0N/A if (debug != null) {
0N/A String time = "n/a";
0N/A try {
0N/A Date notAfter =
0N/A (Date)ext.get(PrivateKeyUsageExtension.NOT_AFTER);
0N/A time = notAfter.toString();
0N/A } catch (CertificateException ex) {
0N/A // not able to retrieve notAfter value
0N/A }
0N/A debug.println("X509CertSelector.match: private key usage not "
0N/A + "within validity date; ext.NOT_After: "
0N/A + time + "; X509CertSelector: "
0N/A + this.toString());
0N/A e1.printStackTrace();
0N/A }
0N/A return false;
0N/A } catch (CertificateNotYetValidException e2) {
0N/A if (debug != null) {
0N/A String time = "n/a";
0N/A try {
0N/A Date notBefore = (Date)
0N/A ext.get(PrivateKeyUsageExtension.NOT_BEFORE);
0N/A time = notBefore.toString();
0N/A } catch (CertificateException ex) {
0N/A // not able to retrieve notBefore value
0N/A }
0N/A debug.println("X509CertSelector.match: private key usage not "
0N/A + "within validity date; ext.NOT_BEFORE: "
0N/A + time + "; X509CertSelector: "
0N/A + this.toString());
0N/A e2.printStackTrace();
0N/A }
0N/A return false;
0N/A } catch (CertificateException e3) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: CertificateException "
0N/A + "in private key usage check; X509CertSelector: "
0N/A + this.toString());
0N/A e3.printStackTrace();
0N/A }
0N/A return false;
0N/A } catch (IOException e4) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: IOException in "
0N/A + "private key usage check; X509CertSelector: "
0N/A + this.toString());
0N/A e4.printStackTrace();
0N/A }
0N/A return false;
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A /* match on subject public key algorithm OID */
0N/A private boolean matchSubjectPublicKeyAlgID(X509Certificate xcert) {
0N/A if (subjectPublicKeyAlgID == null) {
0N/A return true;
0N/A }
0N/A try {
0N/A byte[] encodedKey = xcert.getPublicKey().getEncoded();
0N/A DerValue val = new DerValue(encodedKey);
0N/A if (val.tag != DerValue.tag_Sequence) {
0N/A throw new IOException("invalid key format");
0N/A }
0N/A
0N/A AlgorithmId algID = AlgorithmId.parse(val.data.getDerValue());
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: subjectPublicKeyAlgID = "
0N/A + subjectPublicKeyAlgID + ", xcert subjectPublicKeyAlgID = "
0N/A + algID.getOID());
0N/A }
0N/A if (!subjectPublicKeyAlgID.equals(algID.getOID())) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "subject public key alg IDs don't match");
0N/A }
0N/A return false;
0N/A }
0N/A } catch (IOException e5) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: IOException in subject "
0N/A + "public key algorithm OID check");
0N/A }
0N/A return false;
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A /* match on key usage extension value */
0N/A private boolean matchKeyUsage(X509Certificate xcert) {
0N/A if (keyUsage == null) {
0N/A return true;
0N/A }
0N/A boolean[] certKeyUsage = xcert.getKeyUsage();
0N/A if (certKeyUsage != null) {
0N/A for (int keyBit = 0; keyBit < keyUsage.length; keyBit++) {
0N/A if (keyUsage[keyBit] &&
0N/A ((keyBit >= certKeyUsage.length) || !certKeyUsage[keyBit])) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "key usage bits don't match");
0N/A }
0N/A return false;
0N/A }
0N/A }
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A /* match on extended key usage purpose OIDs */
0N/A private boolean matchExtendedKeyUsage(X509Certificate xcert) {
0N/A if ((keyPurposeSet == null) || keyPurposeSet.isEmpty()) {
0N/A return true;
0N/A }
0N/A try {
0N/A ExtendedKeyUsageExtension ext =
0N/A (ExtendedKeyUsageExtension)getExtensionObject(xcert,
0N/A EXTENDED_KEY_USAGE_ID);
0N/A if (ext != null) {
0N/A Vector<ObjectIdentifier> certKeyPurposeVector =
0N/A (Vector<ObjectIdentifier>)ext.get(ExtendedKeyUsageExtension.USAGES);
0N/A if (!certKeyPurposeVector.contains(ANY_EXTENDED_KEY_USAGE)
0N/A && !certKeyPurposeVector.containsAll(keyPurposeOIDSet)) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: cert failed "
0N/A + "extendedKeyUsage criterion");
0N/A }
0N/A return false;
0N/A }
0N/A }
0N/A } catch (IOException ex) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "IOException in extended key usage check");
0N/A }
0N/A return false;
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A /* match on subject alternative name extension names */
0N/A private boolean matchSubjectAlternativeNames(X509Certificate xcert) {
0N/A if ((subjectAlternativeNames == null) || subjectAlternativeNames.isEmpty()) {
0N/A return true;
0N/A }
0N/A try {
0N/A SubjectAlternativeNameExtension sanExt =
0N/A (SubjectAlternativeNameExtension) getExtensionObject(xcert,
0N/A SUBJECT_ALT_NAME_ID);
0N/A if (sanExt == null) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "no subject alternative name extension");
0N/A }
0N/A return false;
0N/A }
0N/A GeneralNames certNames = (GeneralNames)
0N/A sanExt.get(SubjectAlternativeNameExtension.SUBJECT_NAME);
0N/A Iterator<GeneralNameInterface> i =
0N/A subjectAlternativeGeneralNames.iterator();
0N/A while (i.hasNext()) {
0N/A GeneralNameInterface matchName = i.next();
0N/A boolean found = false;
0N/A for (Iterator<GeneralName> t = certNames.iterator();
0N/A t.hasNext() && !found; ) {
0N/A GeneralNameInterface certName = (t.next()).getName();
0N/A found = certName.equals(matchName);
0N/A }
0N/A if (!found && (matchAllSubjectAltNames || !i.hasNext())) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: subject alternative "
0N/A + "name " + matchName + " not found");
0N/A }
0N/A return false;
0N/A } else if (found && !matchAllSubjectAltNames) {
0N/A break;
0N/A }
0N/A }
0N/A } catch (IOException ex) {
0N/A if (debug != null)
0N/A debug.println("X509CertSelector.match: IOException in subject "
0N/A + "alternative name check");
0N/A return false;
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A /* match on name constraints */
0N/A private boolean matchNameConstraints(X509Certificate xcert) {
0N/A if (nc == null) {
0N/A return true;
0N/A }
0N/A try {
0N/A if (!nc.verify(xcert)) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "name constraints not satisfied");
0N/A }
0N/A return false;
0N/A }
0N/A } catch (IOException e) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "IOException in name constraints check");
0N/A }
0N/A return false;
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A /* match on policy OIDs */
0N/A private boolean matchPolicy(X509Certificate xcert) {
0N/A if (policy == null) {
0N/A return true;
0N/A }
0N/A try {
0N/A CertificatePoliciesExtension ext = (CertificatePoliciesExtension)
0N/A getExtensionObject(xcert, CERT_POLICIES_ID);
0N/A if (ext == null) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "no certificate policy extension");
0N/A }
0N/A return false;
0N/A }
0N/A List<PolicyInformation> policies = (List<PolicyInformation>)ext.get(CertificatePoliciesExtension.POLICIES);
0N/A /*
0N/A * Convert the Vector of PolicyInformation to a Vector
0N/A * of CertificatePolicyIds for easier comparison.
0N/A */
0N/A List<CertificatePolicyId> policyIDs = new ArrayList<CertificatePolicyId>(policies.size());
0N/A for (PolicyInformation info : policies) {
0N/A policyIDs.add(info.getPolicyIdentifier());
0N/A }
0N/A if (policy != null) {
0N/A boolean foundOne = false;
0N/A /*
0N/A * if the user passes in an empty policy Set, then
0N/A * we just want to make sure that the candidate certificate
0N/A * has some policy OID in its CertPoliciesExtension
0N/A */
0N/A if (policy.getCertPolicyIds().isEmpty()) {
0N/A if (policyIDs.isEmpty()) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "cert failed policyAny criterion");
0N/A }
0N/A return false;
0N/A }
0N/A } else {
0N/A for (CertificatePolicyId id : policy.getCertPolicyIds()) {
0N/A if (policyIDs.contains(id)) {
0N/A foundOne = true;
0N/A break;
0N/A }
0N/A }
0N/A if (!foundOne) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "cert failed policyAny criterion");
0N/A }
0N/A return false;
0N/A }
0N/A }
0N/A }
0N/A } catch (IOException ex) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "IOException in certificate policy ID check");
0N/A }
0N/A return false;
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A /* match on pathToNames */
0N/A private boolean matchPathToNames(X509Certificate xcert) {
0N/A if (pathToGeneralNames == null) {
0N/A return true;
0N/A }
0N/A try {
0N/A NameConstraintsExtension ext = (NameConstraintsExtension)
0N/A getExtensionObject(xcert, NAME_CONSTRAINTS_ID);
0N/A if (ext == null) {
0N/A return true;
0N/A }
0N/A if ((debug != null) && debug.isOn("certpath")) {
0N/A debug.println("X509CertSelector.match pathToNames:\n");
0N/A Iterator<GeneralNameInterface> i =
0N/A pathToGeneralNames.iterator();
0N/A while (i.hasNext()) {
0N/A debug.println(" " + i.next() + "\n");
0N/A }
0N/A }
0N/A
0N/A GeneralSubtrees permitted = (GeneralSubtrees)
0N/A ext.get(NameConstraintsExtension.PERMITTED_SUBTREES);
0N/A GeneralSubtrees excluded = (GeneralSubtrees)
0N/A ext.get(NameConstraintsExtension.EXCLUDED_SUBTREES);
0N/A if (excluded != null) {
0N/A if (matchExcluded(excluded) == false) {
0N/A return false;
0N/A }
0N/A }
0N/A if (permitted != null) {
0N/A if (matchPermitted(permitted) == false) {
0N/A return false;
0N/A }
0N/A }
0N/A } catch (IOException ex) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: "
0N/A + "IOException in name constraints check");
0N/A }
0N/A return false;
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A private boolean matchExcluded(GeneralSubtrees excluded) {
0N/A /*
0N/A * Enumerate through excluded and compare each entry
0N/A * to all pathToNames. If any pathToName is within any of the
0N/A * subtrees listed in excluded, return false.
0N/A */
0N/A for (Iterator<GeneralSubtree> t = excluded.iterator(); t.hasNext(); ) {
0N/A GeneralSubtree tree = t.next();
0N/A GeneralNameInterface excludedName = tree.getName().getName();
0N/A Iterator<GeneralNameInterface> i = pathToGeneralNames.iterator();
0N/A while (i.hasNext()) {
0N/A GeneralNameInterface pathToName = i.next();
0N/A if (excludedName.getType() == pathToName.getType()) {
0N/A switch (pathToName.constrains(excludedName)) {
0N/A case GeneralNameInterface.NAME_WIDENS:
0N/A case GeneralNameInterface.NAME_MATCH:
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: name constraints "
0N/A + "inhibit path to specified name");
0N/A debug.println("X509CertSelector.match: excluded name: " +
0N/A pathToName);
0N/A }
0N/A return false;
0N/A default:
0N/A }
0N/A }
0N/A }
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A private boolean matchPermitted(GeneralSubtrees permitted) {
0N/A /*
0N/A * Enumerate through pathToNames, checking that each pathToName
0N/A * is in at least one of the subtrees listed in permitted.
0N/A * If not, return false. However, if no subtrees of a given type
0N/A * are listed, all names of that type are permitted.
0N/A */
0N/A Iterator<GeneralNameInterface> i = pathToGeneralNames.iterator();
0N/A while (i.hasNext()) {
0N/A GeneralNameInterface pathToName = i.next();
0N/A Iterator<GeneralSubtree> t = permitted.iterator();
0N/A boolean permittedNameFound = false;
0N/A boolean nameTypeFound = false;
0N/A String names = "";
0N/A while (t.hasNext() && !permittedNameFound) {
0N/A GeneralSubtree tree = t.next();
0N/A GeneralNameInterface permittedName = tree.getName().getName();
0N/A if (permittedName.getType() == pathToName.getType()) {
0N/A nameTypeFound = true;
0N/A names = names + " " + permittedName;
0N/A switch (pathToName.constrains(permittedName)) {
0N/A case GeneralNameInterface.NAME_WIDENS:
0N/A case GeneralNameInterface.NAME_MATCH:
0N/A permittedNameFound = true;
0N/A break;
0N/A default:
0N/A }
0N/A }
0N/A }
0N/A if (!permittedNameFound && nameTypeFound) {
0N/A if (debug != null)
0N/A debug.println("X509CertSelector.match: " +
0N/A "name constraints inhibit path to specified name; " +
0N/A "permitted names of type " + pathToName.getType() +
0N/A ": " + names);
0N/A return false;
0N/A }
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A /* match on basic constraints */
0N/A private boolean matchBasicConstraints(X509Certificate xcert) {
0N/A if (basicConstraints == -1) {
0N/A return true;
0N/A }
0N/A int maxPathLen = xcert.getBasicConstraints();
0N/A if (basicConstraints == -2) {
0N/A if (maxPathLen != -1) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: not an EE cert");
0N/A }
0N/A return false;
0N/A }
0N/A } else {
0N/A if (maxPathLen < basicConstraints) {
0N/A if (debug != null) {
0N/A debug.println("X509CertSelector.match: maxPathLen too small ("
0N/A + maxPathLen + " < " + basicConstraints + ")");
0N/A }
0N/A return false;
0N/A }
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A private static Set<?> cloneSet(Set<?> set) {
0N/A if (set instanceof HashSet) {
0N/A Object clone = ((HashSet<?>)set).clone();
0N/A return (Set<?>)clone;
0N/A } else {
0N/A return new HashSet<Object>(set);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns a copy of this object.
0N/A *
0N/A * @return the copy
0N/A */
0N/A public Object clone() {
0N/A try {
0N/A X509CertSelector copy = (X509CertSelector)super.clone();
0N/A // Must clone these because addPathToName et al. modify them
0N/A if (subjectAlternativeNames != null) {
0N/A copy.subjectAlternativeNames =
0N/A (Set<List<?>>)cloneSet(subjectAlternativeNames);
0N/A copy.subjectAlternativeGeneralNames =
0N/A (Set<GeneralNameInterface>)cloneSet
0N/A (subjectAlternativeGeneralNames);
0N/A }
0N/A if (pathToGeneralNames != null) {
0N/A copy.pathToNames =
0N/A (Set<List<?>>)cloneSet(pathToNames);
0N/A copy.pathToGeneralNames =
0N/A (Set<GeneralNameInterface>)cloneSet
0N/A (pathToGeneralNames);
0N/A }
0N/A return copy;
0N/A } catch (CloneNotSupportedException e) {
0N/A /* Cannot happen */
0N/A throw new InternalError(e.toString());
0N/A }
0N/A }
0N/A}