blob: 757bfa8926913474e2422808842fae8c4fabc2c3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package java.security.cert;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import javax.security.auth.x500.X500Principal;
import org.apache.harmony.security.asn1.ASN1Integer;
import org.apache.harmony.security.asn1.ASN1OctetString;
import org.apache.harmony.security.x501.Name;
/**
* A CRL selector ({@code CRLSelector} for selecting {@code
* X509CRL}s that match the specified criteria.
* <p>
* When constructed, all criteria are set to default values that will match any
* {@code X509CRL}.
*/
public class X509CRLSelector implements CRLSelector {
// issuerNames criterion:
// contains X.500 distinguished names in CANONICAL format
private ArrayList<String> issuerNames;
// contains X500Principal objects corresponding to the names
// from issuerNames collection (above)
private ArrayList<X500Principal> issuerPrincipals;
// minCRLNumber criterion
private BigInteger minCRL;
// maxCRLNumber criterion
private BigInteger maxCRL;
// dateAndTime criterion
private long dateAndTime = -1;
// the certificate being checked
private X509Certificate certificateChecking;
/**
* Creates a new {@code X509CertSelector}.
*/
public X509CRLSelector() { }
/**
* Sets the criterion for the issuer distinguished names.
* <p>
* The CRL issuer must match at least one of the specified distinguished
* names.
*
* @param issuers
* the list of issuer distinguished names to match, or {@code
* null} if any issuer distinguished name will do.
*/
public void setIssuers(Collection<X500Principal> issuers) {
if (issuers == null) {
issuerNames = null;
issuerPrincipals = null;
return;
}
issuerNames = new ArrayList<String>(issuers.size());
issuerPrincipals = new ArrayList<X500Principal>(issuers);
for (X500Principal issuer: issuers) {
issuerNames.add(issuer.getName(X500Principal.CANONICAL));
}
}
/**
* <b>Do not use:</b> use {@link #setIssuers(Collection)} or one of
* {@link #addIssuerName} instead. Sets the criterion for the issuer
* distinguished names.
* <p>
* The CRL issuer must match at least one of the specified distinguished
* names.
* <p>
* The specified parameter {@code names} is a collection with an entry for
* each name to be included in the criterion. The name is specified as a
* {@code String} or a byte array specifying the name (in RFC 2253 or ASN.1
* DER encoded form)
*
* @param names
* the list of issuer distinguished names to match, or {@code
* null} if any issuer distinguished name will do.
* @throws IOException
* if parsing fails.
*/
public void setIssuerNames(Collection<?> names) throws IOException {
if (names == null) {
issuerNames = null;
issuerPrincipals = null;
return;
}
if (names.size() == 0) {
return;
}
issuerNames = new ArrayList<String>(names.size());
for (Object name: names) {
if (name instanceof String) {
issuerNames.add(
new Name((String) name).getName(
X500Principal.CANONICAL));
} else if (name instanceof byte[]) {
issuerNames.add(
new Name((byte[]) name).getName(
X500Principal.CANONICAL));
} else {
throw new IOException("name neither a String nor a byte[]");
}
}
}
/**
* Adds an issuer to the criterion for the issuer distinguished names.
* <p>
* The CRL issuer must match at least one of the specified distinguished
* names.
*
* @param issuer
* the issuer to add to the criterion
*/
public void addIssuer(X500Principal issuer) {
if (issuer == null) {
throw new NullPointerException("issuer == null");
}
if (issuerNames == null) {
issuerNames = new ArrayList<String>();
}
String name = issuer.getName(X500Principal.CANONICAL);
if (!issuerNames.contains(name)) {
issuerNames.add(name);
}
if (issuerPrincipals == null) {
issuerPrincipals = new ArrayList<X500Principal>(issuerNames.size());
}
// extend the list of issuer Principals
int size = issuerNames.size() - 1;
for (int i=issuerPrincipals.size(); i<size; i++) {
issuerPrincipals.add(new X500Principal(issuerNames.get(i)));
}
issuerPrincipals.add(issuer);
}
/**
* <b>Do not use:</b>, use {@link #addIssuer(X500Principal)} or
* {@link #addIssuerName(byte[])} instead. It can fail to match some CRLs
* because of a loss of encoding information in a RFC 2253 string.
* <p>
* Adds an issuer to the criterion for the issuer distinguished names. The
* CRK issuer must match at least one of the specified distinguished names.
*
* @param iss_name
* the RFC 2253 encoded name.
* @throws IOException
* if parsing fails.
*/
public void addIssuerName(String iss_name) throws IOException {
if (issuerNames == null) {
issuerNames = new ArrayList<String>();
}
if (iss_name == null) {
iss_name = "";
}
String name = new Name(iss_name).getName(X500Principal.CANONICAL);
if (!issuerNames.contains(name)) {
issuerNames.add(name);
}
}
/**
* Adds an issuer to the criterion for the issuer distinguished names.
* <p>
* The CRL issuer must match at least one of the specified distinguished
* names.
*
* @param iss_name
* the issuer to add to the criterion in ASN.1 DER encoded form.
* @throws IOException
* if parsing fails.
*/
public void addIssuerName(byte[] iss_name) throws IOException {
if (iss_name == null) {
throw new NullPointerException("iss_name == null");
}
if (issuerNames == null) {
issuerNames = new ArrayList<String>();
}
String name = new Name(iss_name).getName(X500Principal.CANONICAL);
if (!issuerNames.contains(name)) {
issuerNames.add(name);
}
}
/**
* Sets the criterion for the minimum CRL number.
* <p>
* The CRL must have a number extension with a value greater than or equal
* to the specified parameter.
*
* @param minCRL
* the minimum CRL number or null to not check the minimum CRL
* number
*/
public void setMinCRLNumber(BigInteger minCRL) {
this.minCRL = minCRL;
}
/**
* Sets the criterion for the maximum CRL number.
* <p>
* The CRL must have a number extension with a value less than or equal to
* the specified parameter.
*
* @param maxCRL
* the maximum CRL number or null to not check the maximum CRL
* number.
*/
public void setMaxCRLNumber(BigInteger maxCRL) {
this.maxCRL = maxCRL;
}
/**
* Sets the criterion for the CRL update period.
* <p>
* The CRL's {@code thisUpdate} value must be equal or before the specified
* date and the {@code nextUpdate} value must be after the specified date.
*
* @param dateAndTime
* the date to search for valid CRL's or {@code null} to not
* check the date.
*/
public void setDateAndTime(Date dateAndTime) {
if (dateAndTime == null) {
this.dateAndTime = -1;
return;
}
this.dateAndTime = dateAndTime.getTime();
}
/**
* Sets a certificate hint to find CRLs. It's not a criterion but may help
* finding relevant CRLs.
*
* @param cert
* the certificate hint or {@code null}.
*/
public void setCertificateChecking(X509Certificate cert) {
this.certificateChecking = cert;
}
/**
* Returns the criterion for the issuer distinguished names.
* <p>
* The CRL issuer must match at least one of the distinguished names.
*
* @return the unmodifiable list of issuer distinguished names to match, or
* {@code null} if any issuer distinguished name will do.
*/
public Collection<X500Principal> getIssuers() {
if (issuerNames == null) {
return null;
}
if (issuerPrincipals == null) {
issuerPrincipals = new ArrayList<X500Principal>(issuerNames.size());
}
int size = issuerNames.size();
// extend the list of issuer Principals
for (int i=issuerPrincipals.size(); i<size; i++) {
issuerPrincipals.add(new X500Principal(issuerNames.get(i)));
}
return Collections.unmodifiableCollection(issuerPrincipals);
}
/**
* Returns the criterion for the issuer distinguished names.
* <p>
* The CRL issuer must match at least one of the distinguished names.
*
* @return a copy of the list of issuer distinguished names to match, or
* {@code null} if any issuer distinguished name will do.
*/
public Collection<Object> getIssuerNames() {
if (issuerNames == null) {
return null;
}
return Collections.unmodifiableCollection((ArrayList<?>) issuerNames);
}
/**
* Returns the criterion for the minimum CRL number.
* <p>
* The CRL must have a number extension with a value greater than or equal
* to the returned value.
*
* @return the minimum CRL number or {@code null} if the minimum CRL number
* is not to be checked.
*/
public BigInteger getMinCRL() {
return minCRL;
}
/**
* Returns the criterion for the maximum CRL number.
* <p>
* The CRL must have a number extension with a value less than or equal to
* the returned value.
*
* @return the maximum CRL number or null if the maximum CRL number is not
* checked.
*/
public BigInteger getMaxCRL() {
return maxCRL;
}
/**
* Returns the criterion for the CRL update period.
* <p>
* The CRL's {@code thisUpdate} value must be equal or before the returned
* date and the {@code nextUpdate} value must be after the returned date.
*
* @return the date to search for valid CRL's or {@code null} if the date is
* not checked.
*/
public Date getDateAndTime() {
if (dateAndTime == -1) {
return null;
}
return new Date(dateAndTime);
}
/**
* Returns the certificate hint to find CRLs. It's not a criterion but may
* help finding relevant CRLs.
*
* @return the certificate hint or {@code null} if none set.
*/
public X509Certificate getCertificateChecking() {
return certificateChecking;
}
/**
* Returns a string representation of this {@code X509CRLSelector} instance.
*
* @return a string representation of this {@code X509CRLSelector} instance.
*/
public String toString() {
StringBuilder result = new StringBuilder();
result.append("X509CRLSelector:\n[");
if (issuerNames != null) {
result.append("\n IssuerNames:\n [");
int size = issuerNames.size();
for (int i=0; i<size; i++) {
result.append("\n "
+ issuerNames.get(i));
}
result.append("\n ]");
}
if (minCRL != null) {
result.append("\n minCRL: " + minCRL);
}
if (maxCRL != null) {
result.append("\n maxCRL: " + maxCRL);
}
if (dateAndTime != -1) {
result.append("\n dateAndTime: " + (new Date(dateAndTime)));
}
if (certificateChecking != null) {
result.append("\n certificateChecking: " + certificateChecking);
}
result.append("\n]");
return result.toString();
}
/**
* Returns whether the specified CRL matches all the criteria collected in
* this instance.
*
* @param crl
* the CRL to check.
* @return {@code true} if the CRL matches all the criteria, otherwise
* {@code false}.
*/
public boolean match(CRL crl) {
if (!(crl instanceof X509CRL)) {
return false;
}
X509CRL crlist = (X509CRL) crl;
if ((issuerNames != null) &&
// the search speed depends on the class of issuerNames
!(issuerNames.contains(
crlist.getIssuerX500Principal().getName(
X500Principal.CANONICAL)))) {
return false;
}
if ((minCRL != null) || (maxCRL != null)) {
try {
// As specified in rfc 3280 (http://www.ietf.org/rfc/rfc3280.txt)
// CRL Number Extension's OID is 2.5.29.20 .
byte[] bytes = crlist.getExtensionValue("2.5.29.20");
bytes = (byte[]) ASN1OctetString.getInstance().decode(bytes);
BigInteger crlNumber = new BigInteger((byte[])
ASN1Integer.getInstance().decode(bytes));
if ((minCRL != null) && (crlNumber.compareTo(minCRL) < 0)) {
return false;
}
if ((maxCRL != null) && (crlNumber.compareTo(maxCRL) > 0)) {
return false;
}
} catch (IOException e) {
return false;
}
}
if (dateAndTime != -1) {
Date thisUp = crlist.getThisUpdate();
Date nextUp = crlist.getNextUpdate();
if ((thisUp == null) || (nextUp == null)) {
return false;
}
if ((dateAndTime < thisUp.getTime())
|| (dateAndTime > nextUp.getTime())) {
return false;
}
}
return true;
}
/**
* Clones this {@code X509CRL} instance.
*
* @return the cloned instance.
*/
public Object clone() {
X509CRLSelector result;
try {
result = (X509CRLSelector) super.clone();
if (issuerNames != null) {
result.issuerNames = new ArrayList<String>(issuerNames);
}
} catch (CloneNotSupportedException e) {
result = null;
}
return result;
}
}