/*
* Copyright (C) 2014 The Android Open Source Project
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.security.cert;
import java.io.IOException;
import java.math.BigInteger;
import java.security.PublicKey;
import java.util.*;
import javax.security.auth.x500.X500Principal;
import sun.misc.HexDumpEncoder;
import sun.security.util.Debug;
import sun.security.util.DerInputStream;
import sun.security.util.DerValue;
import sun.security.util.ObjectIdentifier;
import sun.security.x509.*;
/**
* A {@code CertSelector} that selects {@code X509Certificates} that
* match all specified criteria. This class is particularly useful when
* selecting certificates from a {@code CertStore} to build a
* PKIX-compliant certification path.
*
* When first constructed, an {@code X509CertSelector} has no criteria
* enabled and each of the {@code get} methods return a default value
* ({@code null}, or {@code -1} for the {@link #getBasicConstraints
* getBasicConstraints} method). Therefore, the {@link #match match}
* method would return {@code true} for any {@code X509Certificate}.
* Typically, several criteria are enabled (by calling
* {@link #setIssuer setIssuer} or
* {@link #setKeyUsage setKeyUsage}, for instance) and then the
* {@code X509CertSelector} is passed to
* {@link CertStore#getCertificates CertStore.getCertificates} or some similar
* method.
*
* Several criteria can be enabled (by calling {@link #setIssuer setIssuer}
* and {@link #setSerialNumber setSerialNumber},
* for example) such that the {@code match} method
* usually uniquely matches a single {@code X509Certificate}. We say
* usually, since it is possible for two issuing CAs to have the same
* distinguished name and each issue a certificate with the same serial
* number. Other unique combinations include the issuer, subject,
* subjectKeyIdentifier and/or the subjectPublicKey criteria.
*
* Unless otherwise specified, the methods defined in this class are not
* thread-safe. Multiple threads that need to access a single
* object concurrently should synchronize amongst themselves and
* provide the necessary locking. Multiple threads each manipulating
* separate objects need not synchronize.
*
* @see CertSelector
* @see X509Certificate
*
* @since 1.4
* @author Steve Hanna
*/
public class X509CertSelector implements CertSelector {
private static final Debug debug = Debug.getInstance("certpath");
private final static ObjectIdentifier ANY_EXTENDED_KEY_USAGE =
ObjectIdentifier.newInternal(new int[] {2, 5, 29, 37, 0});
static {
CertPathHelperImpl.initialize();
}
private BigInteger serialNumber;
private X500Principal issuer;
private X500Principal subject;
private byte[] subjectKeyID;
private byte[] authorityKeyID;
private Date certificateValid;
private Date privateKeyValid;
private ObjectIdentifier subjectPublicKeyAlgID;
private PublicKey subjectPublicKey;
private byte[] subjectPublicKeyBytes;
private boolean[] keyUsage;
private Set keyPurposeSet;
private Set keyPurposeOIDSet;
private Set> subjectAlternativeNames;
private Set subjectAlternativeGeneralNames;
private CertificatePolicySet policy;
private Set policySet;
private Set> pathToNames;
private Set pathToGeneralNames;
private NameConstraintsExtension nc;
private byte[] ncBytes;
private int basicConstraints = -1;
private X509Certificate x509Cert;
private boolean matchAllSubjectAltNames = true;
private static final Boolean FALSE = Boolean.FALSE;
private static final int PRIVATE_KEY_USAGE_ID = 0;
private static final int SUBJECT_ALT_NAME_ID = 1;
private static final int NAME_CONSTRAINTS_ID = 2;
private static final int CERT_POLICIES_ID = 3;
private static final int EXTENDED_KEY_USAGE_ID = 4;
private static final int NUM_OF_EXTENSIONS = 5;
private static final String[] EXTENSION_OIDS = new String[NUM_OF_EXTENSIONS];
static {
EXTENSION_OIDS[PRIVATE_KEY_USAGE_ID] = "2.5.29.16";
EXTENSION_OIDS[SUBJECT_ALT_NAME_ID] = "2.5.29.17";
EXTENSION_OIDS[NAME_CONSTRAINTS_ID] = "2.5.29.30";
EXTENSION_OIDS[CERT_POLICIES_ID] = "2.5.29.32";
EXTENSION_OIDS[EXTENDED_KEY_USAGE_ID] = "2.5.29.37";
};
/* Constants representing the GeneralName types */
static final int NAME_ANY = 0;
static final int NAME_RFC822 = 1;
static final int NAME_DNS = 2;
static final int NAME_X400 = 3;
static final int NAME_DIRECTORY = 4;
static final int NAME_EDI = 5;
static final int NAME_URI = 6;
static final int NAME_IP = 7;
static final int NAME_OID = 8;
/**
* Creates an {@code X509CertSelector}. Initially, no criteria are set
* so any {@code X509Certificate} will match.
*/
public X509CertSelector() {
// empty
}
/**
* Sets the certificateEquals criterion. The specified
* {@code X509Certificate} must be equal to the
* {@code X509Certificate} passed to the {@code match} method.
* If {@code null}, then this check is not applied.
*
*
This method is particularly useful when it is necessary to
* match a single certificate. Although other criteria can be specified
* in conjunction with the certificateEquals criterion, it is usually not
* practical or necessary.
*
* @param cert the {@code X509Certificate} to match (or
* {@code null})
* @see #getCertificate
*/
public void setCertificate(X509Certificate cert) {
x509Cert = cert;
}
/**
* Sets the serialNumber criterion. The specified serial number
* must match the certificate serial number in the
* {@code X509Certificate}. If {@code null}, any certificate
* serial number will do.
*
* @param serial the certificate serial number to match
* (or {@code null})
* @see #getSerialNumber
*/
public void setSerialNumber(BigInteger serial) {
serialNumber = serial;
}
/**
* Sets the issuer criterion. The specified distinguished name
* must match the issuer distinguished name in the
* {@code X509Certificate}. If {@code null}, any issuer
* distinguished name will do.
*
* @param issuer a distinguished name as X500Principal
* (or {@code null})
* @since 1.5
*/
public void setIssuer(X500Principal issuer) {
this.issuer = issuer;
}
/**
* Denigrated, use {@linkplain #setIssuer(X500Principal)}
* or {@linkplain #setIssuer(byte[])} instead. This method should not be
* relied on as it can fail to match some certificates because of a loss of
* encoding information in the
* RFC 2253 String form
* of some distinguished names.
*
* Sets the issuer criterion. The specified distinguished name
* must match the issuer distinguished name in the
* {@code X509Certificate}. If {@code null}, any issuer
* distinguished name will do.
*
* If {@code issuerDN} is not {@code null}, it should contain a
* distinguished name, in RFC 2253 format.
*
* @param issuerDN a distinguished name in RFC 2253 format
* (or {@code null})
* @throws IOException if a parsing error occurs (incorrect form for DN)
*/
public void setIssuer(String issuerDN) throws IOException {
if (issuerDN == null) {
issuer = null;
} else {
issuer = new X500Name(issuerDN).asX500Principal();
}
}
/**
* Sets the issuer criterion. The specified distinguished name
* must match the issuer distinguished name in the
* {@code X509Certificate}. If {@code null} is specified,
* the issuer criterion is disabled and any issuer distinguished name will
* do.
*
* If {@code issuerDN} is not {@code null}, it should contain a
* single DER encoded distinguished name, as defined in X.501. The ASN.1
* notation for this structure is as follows.
*
* Note that the byte array specified here is cloned to protect against
* subsequent modifications.
*
* @param issuerDN a byte array containing the distinguished name
* in ASN.1 DER encoded form (or {@code null})
* @throws IOException if an encoding error occurs (incorrect form for DN)
*/
public void setIssuer(byte[] issuerDN) throws IOException {
try {
issuer = (issuerDN == null ? null : new X500Principal(issuerDN));
} catch (IllegalArgumentException e) {
throw new IOException("Invalid name", e);
}
}
/**
* Sets the subject criterion. The specified distinguished name
* must match the subject distinguished name in the
* {@code X509Certificate}. If {@code null}, any subject
* distinguished name will do.
*
* @param subject a distinguished name as X500Principal
* (or {@code null})
* @since 1.5
*/
public void setSubject(X500Principal subject) {
this.subject = subject;
}
/**
* Denigrated, use {@linkplain #setSubject(X500Principal)}
* or {@linkplain #setSubject(byte[])} instead. This method should not be
* relied on as it can fail to match some certificates because of a loss of
* encoding information in the RFC 2253 String form of some distinguished
* names.
*
* Sets the subject criterion. The specified distinguished name
* must match the subject distinguished name in the
* {@code X509Certificate}. If {@code null}, any subject
* distinguished name will do.
*
* If {@code subjectDN} is not {@code null}, it should contain a
* distinguished name, in RFC 2253 format.
*
* @param subjectDN a distinguished name in RFC 2253 format
* (or {@code null})
* @throws IOException if a parsing error occurs (incorrect form for DN)
*/
public void setSubject(String subjectDN) throws IOException {
if (subjectDN == null) {
subject = null;
} else {
subject = new X500Name(subjectDN).asX500Principal();
}
}
/**
* Sets the subject criterion. The specified distinguished name
* must match the subject distinguished name in the
* {@code X509Certificate}. If {@code null}, any subject
* distinguished name will do.
*
* If {@code subjectDN} is not {@code null}, it should contain a
* single DER encoded distinguished name, as defined in X.501. For the ASN.1
* notation for this structure, see
* {@link #setIssuer(byte [] issuerDN) setIssuer(byte [] issuerDN)}.
*
* @param subjectDN a byte array containing the distinguished name in
* ASN.1 DER format (or {@code null})
* @throws IOException if an encoding error occurs (incorrect form for DN)
*/
public void setSubject(byte[] subjectDN) throws IOException {
try {
subject = (subjectDN == null ? null : new X500Principal(subjectDN));
} catch (IllegalArgumentException e) {
throw new IOException("Invalid name", e);
}
}
/**
* Sets the subjectKeyIdentifier criterion. The
* {@code X509Certificate} must contain a SubjectKeyIdentifier
* extension for which the contents of the extension
* matches the specified criterion value.
* If the criterion value is {@code null}, no
* subjectKeyIdentifier check will be done.
*
* If {@code subjectKeyID} is not {@code null}, it
* should contain a single DER encoded value corresponding to the contents
* of the extension value (not including the object identifier,
* criticality setting, and encapsulating OCTET STRING)
* for a SubjectKeyIdentifier extension.
* The ASN.1 notation for this structure follows.
*
*
* Since the format of subject key identifiers is not mandated by
* any standard, subject key identifiers are not parsed by the
* {@code X509CertSelector}. Instead, the values are compared using
* a byte-by-byte comparison.
*
* Note that the byte array supplied here is cloned to protect against
* subsequent modifications.
*
* @param subjectKeyID the subject key identifier (or {@code null})
* @see #getSubjectKeyIdentifier
*/
public void setSubjectKeyIdentifier(byte[] subjectKeyID) {
if (subjectKeyID == null) {
this.subjectKeyID = null;
} else {
this.subjectKeyID = subjectKeyID.clone();
}
}
/**
* Sets the authorityKeyIdentifier criterion. The
* {@code X509Certificate} must contain an
* AuthorityKeyIdentifier extension for which the contents of the
* extension value matches the specified criterion value.
* If the criterion value is {@code null}, no
* authorityKeyIdentifier check will be done.
*
* If {@code authorityKeyID} is not {@code null}, it
* should contain a single DER encoded value corresponding to the contents
* of the extension value (not including the object identifier,
* criticality setting, and encapsulating OCTET STRING)
* for an AuthorityKeyIdentifier extension.
* The ASN.1 notation for this structure follows.
*
*
* Authority key identifiers are not parsed by the
* {@code X509CertSelector}. Instead, the values are
* compared using a byte-by-byte comparison.
*
* When the {@code keyIdentifier} field of
* {@code AuthorityKeyIdentifier} is populated, the value is
* usually taken from the {@code SubjectKeyIdentifier} extension
* in the issuer's certificate. Note, however, that the result of
* {@code X509Certificate.getExtensionValue()} on the issuer's certificate may NOT be used
* directly as the input to {@code setAuthorityKeyIdentifier}.
* This is because the SubjectKeyIdentifier contains
* only a KeyIdentifier OCTET STRING, and not a SEQUENCE of
* KeyIdentifier, GeneralNames, and CertificateSerialNumber.
* In order to use the extension value of the issuer certificate's
* {@code SubjectKeyIdentifier}
* extension, it will be necessary to extract the value of the embedded
* {@code KeyIdentifier} OCTET STRING, then DER encode this OCTET
* STRING inside a SEQUENCE.
* For more details on SubjectKeyIdentifier, see
* {@link #setSubjectKeyIdentifier(byte[] subjectKeyID)}.
*
* Note also that the byte array supplied here is cloned to protect against
* subsequent modifications.
*
* @param authorityKeyID the authority key identifier
* (or {@code null})
* @see #getAuthorityKeyIdentifier
*/
public void setAuthorityKeyIdentifier(byte[] authorityKeyID) {
if (authorityKeyID == null) {
this.authorityKeyID = null;
} else {
this.authorityKeyID = authorityKeyID.clone();
}
}
/**
* Sets the certificateValid criterion. The specified date must fall
* within the certificate validity period for the
* {@code X509Certificate}. If {@code null}, no certificateValid
* check will be done.
*
* Note that the {@code Date} supplied here is cloned to protect
* against subsequent modifications.
*
* @param certValid the {@code Date} to check (or {@code null})
* @see #getCertificateValid
*/
public void setCertificateValid(Date certValid) {
if (certValid == null) {
certificateValid = null;
} else {
certificateValid = (Date)certValid.clone();
}
}
/**
* Sets the privateKeyValid criterion. The specified date must fall
* within the private key validity period for the
* {@code X509Certificate}. If {@code null}, no privateKeyValid
* check will be done.
*
* Note that the {@code Date} supplied here is cloned to protect
* against subsequent modifications.
*
* @param privateKeyValid the {@code Date} to check (or
* {@code null})
* @see #getPrivateKeyValid
*/
public void setPrivateKeyValid(Date privateKeyValid) {
if (privateKeyValid == null) {
this.privateKeyValid = null;
} else {
this.privateKeyValid = (Date)privateKeyValid.clone();
}
}
/**
* Sets the subjectPublicKeyAlgID criterion. The
* {@code X509Certificate} must contain a subject public key
* with the specified algorithm. If {@code null}, no
* subjectPublicKeyAlgID check will be done.
*
* @param oid The object identifier (OID) of the algorithm to check
* for (or {@code null}). An OID is represented by a
* set of nonnegative integers separated by periods.
* @throws IOException if the OID is invalid, such as
* the first component being not 0, 1 or 2 or the second component
* being greater than 39.
*
* @see #getSubjectPublicKeyAlgID
*/
public void setSubjectPublicKeyAlgID(String oid) throws IOException {
if (oid == null) {
subjectPublicKeyAlgID = null;
} else {
subjectPublicKeyAlgID = new ObjectIdentifier(oid);
}
}
/**
* Sets the subjectPublicKey criterion. The
* {@code X509Certificate} must contain the specified subject public
* key. If {@code null}, no subjectPublicKey check will be done.
*
* @param key the subject public key to check for (or {@code null})
* @see #getSubjectPublicKey
*/
public void setSubjectPublicKey(PublicKey key) {
if (key == null) {
subjectPublicKey = null;
subjectPublicKeyBytes = null;
} else {
subjectPublicKey = key;
subjectPublicKeyBytes = key.getEncoded();
}
}
/**
* Sets the subjectPublicKey criterion. The {@code X509Certificate}
* must contain the specified subject public key. If {@code null},
* no subjectPublicKey check will be done.
*
* Because this method allows the public key to be specified as a byte
* array, it may be used for unknown key types.
*
* If {@code key} is not {@code null}, it should contain a
* single DER encoded SubjectPublicKeyInfo structure, as defined in X.509.
* The ASN.1 notation for this structure is as follows.
*
{@code
* SubjectPublicKeyInfo ::= SEQUENCE {
* algorithm AlgorithmIdentifier,
* subjectPublicKey BIT STRING }
*
* AlgorithmIdentifier ::= SEQUENCE {
* algorithm OBJECT IDENTIFIER,
* parameters ANY DEFINED BY algorithm OPTIONAL }
* -- contains a value of the type
* -- registered for use with the
* -- algorithm object identifier value
* }
*
* Note that the byte array supplied here is cloned to protect against
* subsequent modifications.
*
* @param key a byte array containing the subject public key in ASN.1 DER
* form (or {@code null})
* @throws IOException if an encoding error occurs (incorrect form for
* subject public key)
* @see #getSubjectPublicKey
*/
public void setSubjectPublicKey(byte[] key) throws IOException {
if (key == null) {
subjectPublicKey = null;
subjectPublicKeyBytes = null;
} else {
subjectPublicKeyBytes = key.clone();
subjectPublicKey = X509Key.parse(new DerValue(subjectPublicKeyBytes));
}
}
/**
* Sets the keyUsage criterion. The {@code X509Certificate}
* must allow the specified keyUsage values. If {@code null}, no
* keyUsage check will be done. Note that an {@code X509Certificate}
* that has no keyUsage extension implicitly allows all keyUsage values.
*
* Note that the boolean array supplied here is cloned to protect against
* subsequent modifications.
*
* @param keyUsage a boolean array in the same format as the boolean
* array returned by
* {@link X509Certificate#getKeyUsage() X509Certificate.getKeyUsage()}.
* Or {@code null}.
* @see #getKeyUsage
*/
public void setKeyUsage(boolean[] keyUsage) {
if (keyUsage == null) {
this.keyUsage = null;
} else {
this.keyUsage = keyUsage.clone();
}
}
/**
* Sets the extendedKeyUsage criterion. The {@code X509Certificate}
* must allow the specified key purposes in its extended key usage
* extension. If {@code keyPurposeSet} is empty or {@code null},
* no extendedKeyUsage check will be done. Note that an
* {@code X509Certificate} that has no extendedKeyUsage extension
* implicitly allows all key purposes.
*
* Note that the {@code Set} is cloned to protect against
* subsequent modifications.
*
* @param keyPurposeSet a {@code Set} of key purpose OIDs in string
* format (or {@code null}). Each OID is represented by a set of
* nonnegative integers separated by periods.
* @throws IOException if the OID is invalid, such as
* the first component being not 0, 1 or 2 or the second component
* being greater than 39.
* @see #getExtendedKeyUsage
*/
public void setExtendedKeyUsage(Set keyPurposeSet) throws IOException {
if ((keyPurposeSet == null) || keyPurposeSet.isEmpty()) {
this.keyPurposeSet = null;
keyPurposeOIDSet = null;
} else {
this.keyPurposeSet =
Collections.unmodifiableSet(new HashSet(keyPurposeSet));
keyPurposeOIDSet = new HashSet();
for (String s : this.keyPurposeSet) {
keyPurposeOIDSet.add(new ObjectIdentifier(s));
}
}
}
/**
* Enables/disables matching all of the subjectAlternativeNames
* specified in the {@link #setSubjectAlternativeNames
* setSubjectAlternativeNames} or {@link #addSubjectAlternativeName
* addSubjectAlternativeName} methods. If enabled,
* the {@code X509Certificate} must contain all of the
* specified subject alternative names. If disabled, the
* {@code X509Certificate} must contain at least one of the
* specified subject alternative names.
*
*
The matchAllNames flag is {@code true} by default.
*
* @param matchAllNames if {@code true}, the flag is enabled;
* if {@code false}, the flag is disabled.
* @see #getMatchAllSubjectAltNames
*/
public void setMatchAllSubjectAltNames(boolean matchAllNames) {
this.matchAllSubjectAltNames = matchAllNames;
}
/**
* Sets the subjectAlternativeNames criterion. The
* {@code X509Certificate} must contain all or at least one of the
* specified subjectAlternativeNames, depending on the value of
* the matchAllNames flag (see {@link #setMatchAllSubjectAltNames
* setMatchAllSubjectAltNames}).
*
* This method allows the caller to specify, with a single method call,
* the complete set of subject alternative names for the
* subjectAlternativeNames criterion. The specified value replaces
* the previous value for the subjectAlternativeNames criterion.
*
* The {@code names} parameter (if not {@code null}) is a
* {@code Collection} with one
* entry for each name to be included in the subject alternative name
* criterion. Each entry is a {@code List} whose first entry is an
* {@code Integer} (the name type, 0-8) and whose second
* entry is a {@code String} or a byte array (the name, in
* string or ASN.1 DER encoded form, respectively).
* There can be multiple names of the same type. If {@code null}
* is supplied as the value for this argument, no
* subjectAlternativeNames check will be performed.
*
* Each subject alternative name in the {@code Collection}
* may be specified either as a {@code String} or as an ASN.1 encoded
* byte array. For more details about the formats used, see
* {@link #addSubjectAlternativeName(int type, String name)
* addSubjectAlternativeName(int type, String name)} and
* {@link #addSubjectAlternativeName(int type, byte [] name)
* addSubjectAlternativeName(int type, byte [] name)}.
*
* Note: for distinguished names, specify the byte
* array form instead of the String form. See the note in
* {@link #addSubjectAlternativeName(int, String)} for more information.
*
* Note that the {@code names} parameter can contain duplicate
* names (same name and name type), but they may be removed from the
* {@code Collection} of names returned by the
* {@link #getSubjectAlternativeNames getSubjectAlternativeNames} method.
*
* Note that a deep copy is performed on the {@code Collection} to
* protect against subsequent modifications.
*
* @param names a {@code Collection} of names (or {@code null})
* @throws IOException if a parsing error occurs
* @see #getSubjectAlternativeNames
*/
public void setSubjectAlternativeNames(Collection> names)
throws IOException {
if (names == null) {
subjectAlternativeNames = null;
subjectAlternativeGeneralNames = null;
} else {
if (names.isEmpty()) {
subjectAlternativeNames = null;
subjectAlternativeGeneralNames = null;
return;
}
Set> tempNames = cloneAndCheckNames(names);
// Ensure that we either set both of these or neither
subjectAlternativeGeneralNames = parseNames(tempNames);
subjectAlternativeNames = tempNames;
}
}
/**
* Adds a name to the subjectAlternativeNames criterion. The
* {@code X509Certificate} must contain all or at least one
* of the specified subjectAlternativeNames, depending on the value of
* the matchAllNames flag (see {@link #setMatchAllSubjectAltNames
* setMatchAllSubjectAltNames}).
*
* This method allows the caller to add a name to the set of subject
* alternative names.
* The specified name is added to any previous value for the
* subjectAlternativeNames criterion. If the specified name is a
* duplicate, it may be ignored.
*
* The name is provided in string format.
* RFC 822, DNS, and URI
* names use the well-established string formats for those types (subject to
* the restrictions included in RFC 3280). IPv4 address names are
* supplied using dotted quad notation. OID address names are represented
* as a series of nonnegative integers separated by periods. And
* directory names (distinguished names) are supplied in RFC 2253 format.
* No standard string format is defined for otherNames, X.400 names,
* EDI party names, IPv6 address names, or any other type of names. They
* should be specified using the
* {@link #addSubjectAlternativeName(int type, byte [] name)
* addSubjectAlternativeName(int type, byte [] name)}
* method.
*
* Note: for distinguished names, use
* {@linkplain #addSubjectAlternativeName(int, byte[])} instead.
* This method should not be relied on as it can fail to match some
* certificates because of a loss of encoding information in the RFC 2253
* String form of some distinguished names.
*
* @param type the name type (0-8, as specified in
* RFC 3280, section 4.2.1.7)
* @param name the name in string form (not {@code null})
* @throws IOException if a parsing error occurs
*/
public void addSubjectAlternativeName(int type, String name)
throws IOException {
addSubjectAlternativeNameInternal(type, name);
}
/**
* Adds a name to the subjectAlternativeNames criterion. The
* {@code X509Certificate} must contain all or at least one
* of the specified subjectAlternativeNames, depending on the value of
* the matchAllNames flag (see {@link #setMatchAllSubjectAltNames
* setMatchAllSubjectAltNames}).
*
* This method allows the caller to add a name to the set of subject
* alternative names.
* The specified name is added to any previous value for the
* subjectAlternativeNames criterion. If the specified name is a
* duplicate, it may be ignored.
*
* The name is provided as a byte array. This byte array should contain
* the DER encoded name, as it would appear in the GeneralName structure
* defined in RFC 3280 and X.509. The encoded byte array should only contain
* the encoded value of the name, and should not include the tag associated
* with the name in the GeneralName structure. The ASN.1 definition of this
* structure appears below.
*
* Note that the byte array supplied here is cloned to protect against
* subsequent modifications.
*
* @param type the name type (0-8, as listed above)
* @param name a byte array containing the name in ASN.1 DER encoded form
* @throws IOException if a parsing error occurs
*/
public void addSubjectAlternativeName(int type, byte[] name)
throws IOException {
// clone because byte arrays are modifiable
addSubjectAlternativeNameInternal(type, name.clone());
}
/**
* A private method that adds a name (String or byte array) to the
* subjectAlternativeNames criterion. The {@code X509Certificate}
* must contain the specified subjectAlternativeName.
*
* @param type the name type (0-8, as specified in
* RFC 3280, section 4.2.1.7)
* @param name the name in string or byte array form
* @throws IOException if a parsing error occurs
*/
private void addSubjectAlternativeNameInternal(int type, Object name)
throws IOException {
// First, ensure that the name parses
GeneralNameInterface tempName = makeGeneralNameInterface(type, name);
if (subjectAlternativeNames == null) {
subjectAlternativeNames = new HashSet>();
}
if (subjectAlternativeGeneralNames == null) {
subjectAlternativeGeneralNames = new HashSet();
}
List