/*
 * Copyright (c) 2010, 2019, 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 sun.security.util;

import sun.security.validator.Validator;

import java.security.CryptoPrimitive;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorException.BasicReason;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.Collection;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

Algorithm constraints for disabled algorithms property See the "jdk.certpath.disabledAlgorithms" specification in java.security for the syntax of the disabled algorithm string.
/** * Algorithm constraints for disabled algorithms property * * See the "jdk.certpath.disabledAlgorithms" specification in java.security * for the syntax of the disabled algorithm string. */
public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { private static final Debug debug = Debug.getInstance("certpath"); // Disabled algorithm security property for certificate path public static final String PROPERTY_CERTPATH_DISABLED_ALGS = "jdk.certpath.disabledAlgorithms"; // Legacy algorithm security property for certificate path and jar public static final String PROPERTY_SECURITY_LEGACY_ALGS = "jdk.security.legacyAlgorithms"; // Disabled algorithm security property for TLS public static final String PROPERTY_TLS_DISABLED_ALGS = "jdk.tls.disabledAlgorithms"; // Disabled algorithm security property for jar public static final String PROPERTY_JAR_DISABLED_ALGS = "jdk.jar.disabledAlgorithms"; // Property for disabled EC named curves private static final String PROPERTY_DISABLED_EC_CURVES = "jdk.disabled.namedCurves"; private final List<String> disabledAlgorithms; private final Constraints algorithmConstraints;
Initialize algorithm constraints with the specified security property.
Params:
  • propertyName – the security property name that define the disabled algorithm constraints
/** * Initialize algorithm constraints with the specified security property. * * @param propertyName the security property name that define the disabled * algorithm constraints */
public DisabledAlgorithmConstraints(String propertyName) { this(propertyName, new AlgorithmDecomposer()); }
Initialize algorithm constraints with the specified security property for a specific usage type.
Params:
  • propertyName – the security property name that define the disabled algorithm constraints
  • decomposer – an alternate AlgorithmDecomposer.
/** * Initialize algorithm constraints with the specified security property * for a specific usage type. * * @param propertyName the security property name that define the disabled * algorithm constraints * @param decomposer an alternate AlgorithmDecomposer. */
public DisabledAlgorithmConstraints(String propertyName, AlgorithmDecomposer decomposer) { super(decomposer); disabledAlgorithms = getAlgorithms(propertyName); // Check for alias int ecindex = -1, i = 0; for (String s : disabledAlgorithms) { if (s.regionMatches(true, 0,"include ", 0, 8)) { if (s.regionMatches(true, 8, PROPERTY_DISABLED_EC_CURVES, 0, PROPERTY_DISABLED_EC_CURVES.length())) { ecindex = i; break; } } i++; } if (ecindex > -1) { disabledAlgorithms.remove(ecindex); disabledAlgorithms.addAll(ecindex, getAlgorithms(PROPERTY_DISABLED_EC_CURVES)); } algorithmConstraints = new Constraints(disabledAlgorithms); } /* * This only checks if the algorithm has been completely disabled. If * there are keysize or other limit, this method allow the algorithm. */ @Override public final boolean permits(Set<CryptoPrimitive> primitives, String algorithm, AlgorithmParameters parameters) { if (!checkAlgorithm(disabledAlgorithms, algorithm, decomposer)) { return false; } if (parameters != null) { return algorithmConstraints.permits(algorithm, parameters); } return true; } /* * Checks if the key algorithm has been disabled or constraints have been * placed on the key. */ @Override public final boolean permits(Set<CryptoPrimitive> primitives, Key key) { return checkConstraints(primitives, "", key, null); } /* * Checks if the key algorithm has been disabled or if constraints have * been placed on the key. */ @Override public final boolean permits(Set<CryptoPrimitive> primitives, String algorithm, Key key, AlgorithmParameters parameters) { if (algorithm == null || algorithm.isEmpty()) { throw new IllegalArgumentException("No algorithm name specified"); } return checkConstraints(primitives, algorithm, key, parameters); } public final void permits(ConstraintsParameters cp) throws CertPathValidatorException { permits(cp.getAlgorithm(), cp); } public final void permits(String algorithm, Key key, AlgorithmParameters params, String variant) throws CertPathValidatorException { permits(algorithm, new ConstraintsParameters(algorithm, params, key, (variant == null) ? Validator.VAR_GENERIC : variant)); } /* * Check if a x509Certificate object is permitted. Check if all * algorithms are allowed, certificate constraints, and the * public key against key constraints. * * Uses new style permit() which throws exceptions. */ public final void permits(String algorithm, ConstraintsParameters cp) throws CertPathValidatorException { // Check if named curves in the ConstraintParameters are disabled. if (cp.getNamedCurve() != null) { for (String curve : cp.getNamedCurve()) { if (!checkAlgorithm(disabledAlgorithms, curve, decomposer)) { throw new CertPathValidatorException( "Algorithm constraints check failed on disabled " + "algorithm: " + curve, null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); } } } algorithmConstraints.permits(algorithm, cp); } // Check if a string is contained inside the property public boolean checkProperty(String param) { param = param.toLowerCase(Locale.ENGLISH); for (String block : disabledAlgorithms) { if (block.toLowerCase(Locale.ENGLISH).indexOf(param) >= 0) { return true; } } return false; } // Check algorithm constraints with key and algorithm private boolean checkConstraints(Set<CryptoPrimitive> primitives, String algorithm, Key key, AlgorithmParameters parameters) { // check the key parameter, it cannot be null. if (key == null) { throw new IllegalArgumentException("The key cannot be null"); } // check the signature algorithm with parameters if (algorithm != null && !algorithm.isEmpty()) { if (!permits(primitives, algorithm, parameters)) { return false; } } // check the key algorithm if (!permits(primitives, key.getAlgorithm(), null)) { return false; } // If this is an elliptic curve, check disabled the named curve. for (String curve : ConstraintsParameters.getNamedCurveFromKey(key)) { if (!permits(primitives, curve, null)) { return false; } } // check the key constraints return algorithmConstraints.permits(key); }
Key and Certificate Constraints The complete disabling of an algorithm is not handled by Constraints or Constraint classes. That is addressed with permit(Set, String, AlgorithmParameters) When passing a Key to permit(), the boolean return values follow the same as the interface class AlgorithmConstraints.permit(). This is to maintain compatibility: 'true' means the operation is allowed. 'false' means it failed the constraints and is disallowed. When passing ConstraintsParameters through permit(), an exception will be thrown on a failure to better identify why the operation was disallowed.
/** * Key and Certificate Constraints * * The complete disabling of an algorithm is not handled by Constraints or * Constraint classes. That is addressed with * permit(Set<CryptoPrimitive>, String, AlgorithmParameters) * * When passing a Key to permit(), the boolean return values follow the * same as the interface class AlgorithmConstraints.permit(). This is to * maintain compatibility: * 'true' means the operation is allowed. * 'false' means it failed the constraints and is disallowed. * * When passing ConstraintsParameters through permit(), an exception * will be thrown on a failure to better identify why the operation was * disallowed. */
private static class Constraints { private Map<String, List<Constraint>> constraintsMap = new HashMap<>(); private static class Holder { private static final Pattern DENY_AFTER_PATTERN = Pattern.compile( "denyAfter\\s+(\\d{4})-(\\d{2})-(\\d{2})"); } public Constraints(List<String> constraintArray) { for (String constraintEntry : constraintArray) { if (constraintEntry == null || constraintEntry.isEmpty()) { continue; } constraintEntry = constraintEntry.trim(); if (debug != null) { debug.println("Constraints: " + constraintEntry); } // Check if constraint is a complete disabling of an // algorithm or has conditions. int space = constraintEntry.indexOf(' '); String algorithm = AlgorithmDecomposer.hashName( ((space > 0 ? constraintEntry.substring(0, space) : constraintEntry). toUpperCase(Locale.ENGLISH))); List<Constraint> constraintList = constraintsMap.getOrDefault(algorithm, new ArrayList<>(1)); // Consider the impact of algorithm aliases. for (String alias : AlgorithmDecomposer.getAliases(algorithm)) { constraintsMap.putIfAbsent(alias, constraintList); } // If there is no whitespace, it is a algorithm name; however, // if there is a whitespace, could be a multi-word EC curve too. if (space <= 0 || CurveDB.lookup(constraintEntry) != null) { constraintList.add(new DisabledConstraint(algorithm)); continue; } String policy = constraintEntry.substring(space + 1); // Convert constraint conditions into Constraint classes Constraint c, lastConstraint = null; // Allow only one jdkCA entry per constraint entry boolean jdkCALimit = false; // Allow only one denyAfter entry per constraint entry boolean denyAfterLimit = false; for (String entry : policy.split("&")) { entry = entry.trim(); Matcher matcher; if (entry.startsWith("keySize")) { if (debug != null) { debug.println("Constraints set to keySize: " + entry); } StringTokenizer tokens = new StringTokenizer(entry); if (!"keySize".equals(tokens.nextToken())) { throw new IllegalArgumentException("Error in " + "security property. Constraint unknown: " + entry); } c = new KeySizeConstraint(algorithm, KeySizeConstraint.Operator.of(tokens.nextToken()), Integer.parseInt(tokens.nextToken())); } else if (entry.equalsIgnoreCase("jdkCA")) { if (debug != null) { debug.println("Constraints set to jdkCA."); } if (jdkCALimit) { throw new IllegalArgumentException("Only one " + "jdkCA entry allowed in property. " + "Constraint: " + constraintEntry); } c = new jdkCAConstraint(algorithm); jdkCALimit = true; } else if (entry.startsWith("denyAfter") && (matcher = Holder.DENY_AFTER_PATTERN.matcher(entry)) .matches()) { if (debug != null) { debug.println("Constraints set to denyAfter"); } if (denyAfterLimit) { throw new IllegalArgumentException("Only one " + "denyAfter entry allowed in property. " + "Constraint: " + constraintEntry); } int year = Integer.parseInt(matcher.group(1)); int month = Integer.parseInt(matcher.group(2)); int day = Integer.parseInt(matcher.group(3)); c = new DenyAfterConstraint(algorithm, year, month, day); denyAfterLimit = true; } else if (entry.startsWith("usage")) { String s[] = (entry.substring(5)).trim().split(" "); c = new UsageConstraint(algorithm, s); if (debug != null) { debug.println("Constraints usage length is " + s.length); } } else { throw new IllegalArgumentException("Error in security" + " property. Constraint unknown: " + entry); } // Link multiple conditions for a single constraint // into a linked list. if (lastConstraint == null) { constraintList.add(c); } else { lastConstraint.nextConstraint = c; } lastConstraint = c; } } } // Get applicable constraints based off the signature algorithm private List<Constraint> getConstraints(String algorithm) { return constraintsMap.get(algorithm); } // Check if KeySizeConstraints permit the specified key public boolean permits(Key key) { List<Constraint> list = getConstraints(key.getAlgorithm()); if (list == null) { return true; } for (Constraint constraint : list) { if (!constraint.permits(key)) { if (debug != null) { debug.println("Constraints: failed key size" + "constraint check " + KeyUtil.getKeySize(key)); } return false; } } return true; } // Check if constraints permit this AlgorithmParameters. public boolean permits(String algorithm, AlgorithmParameters aps) { List<Constraint> list = getConstraints(algorithm); if (list == null) { return true; } for (Constraint constraint : list) { if (!constraint.permits(aps)) { if (debug != null) { debug.println("Constraints: failed algorithm " + "parameters constraint check " + aps); } return false; } } return true; } // Check if constraints permit this cert. public void permits(String algorithm, ConstraintsParameters cp) throws CertPathValidatorException { X509Certificate cert = cp.getCertificate(); if (debug != null) { debug.println("Constraints.permits(): " + cp.toString()); } // Get all signature algorithms to check for constraints Set<String> algorithms = new HashSet<>(); if (algorithm != null) { algorithms.addAll(AlgorithmDecomposer.decomposeOneHash(algorithm)); } // Attempt to add the public key algorithm if cert provided if (cert != null) { algorithms.add(cert.getPublicKey().getAlgorithm()); } if (cp.getKey() != null) { algorithms.add(cp.getKey().getAlgorithm()); } // Check all applicable constraints for (String alg : algorithms) { List<Constraint> list = getConstraints(alg); if (list == null) { continue; } for (Constraint constraint : list) { constraint.permits(cp); } } } }
This abstract Constraint class for algorithm-based checking may contain one or more constraints. If the '&' on the {@Security} property is used, multiple constraints have been grouped together requiring all the constraints to fail for the check to be disallowed. If the class contains multiple constraints, the next constraint is stored in nextConstraint in linked-list fashion.
/** * This abstract Constraint class for algorithm-based checking * may contain one or more constraints. If the '&' on the {@Security} * property is used, multiple constraints have been grouped together * requiring all the constraints to fail for the check to be disallowed. * * If the class contains multiple constraints, the next constraint * is stored in {@code nextConstraint} in linked-list fashion. */
private abstract static class Constraint { String algorithm; Constraint nextConstraint = null; // operator enum Operator { EQ, // "==" NE, // "!=" LT, // "<" LE, // "<=" GT, // ">" GE; // ">=" static Operator of(String s) { switch (s) { case "==": return EQ; case "!=": return NE; case "<": return LT; case "<=": return LE; case ">": return GT; case ">=": return GE; } throw new IllegalArgumentException("Error in security " + "property. " + s + " is not a legal Operator"); } }
Check if an algorithm constraint is permitted with a given key. If the check inside of permit() fails, it must call next() with the same Key parameter passed if multiple constraints need to be checked.
Params:
  • key – Public key
Returns:'true' if constraint is allowed, 'false' if disallowed.
/** * Check if an algorithm constraint is permitted with a given key. * * If the check inside of {@code permit()} fails, it must call * {@code next()} with the same {@code Key} parameter passed if * multiple constraints need to be checked. * * @param key Public key * @return 'true' if constraint is allowed, 'false' if disallowed. */
public boolean permits(Key key) { return true; }
Check if the algorithm constraint permits a given cryptographic parameters.
Params:
  • parameters – the cryptographic parameters
Returns:'true' if the cryptographic parameters is allowed, 'false' ortherwise.
/** * Check if the algorithm constraint permits a given cryptographic * parameters. * * @param parameters the cryptographic parameters * @return 'true' if the cryptographic parameters is allowed, * 'false' ortherwise. */
public boolean permits(AlgorithmParameters parameters) { return true; }
Check if an algorithm constraint is permitted with a given ConstraintsParameters. If the check inside of permits() fails, it must call next() with the same ConstraintsParameters parameter passed if multiple constraints need to be checked.
Params:
  • cp – CertConstraintParameter containing certificate info
Throws:
/** * Check if an algorithm constraint is permitted with a given * ConstraintsParameters. * * If the check inside of {@code permits()} fails, it must call * {@code next()} with the same {@code ConstraintsParameters} * parameter passed if multiple constraints need to be checked. * * @param cp CertConstraintParameter containing certificate info * @throws CertPathValidatorException if constraint disallows. * */
public abstract void permits(ConstraintsParameters cp) throws CertPathValidatorException;
Recursively check if the constraints are allowed. If nextConstraint is non-null, this method will call nextConstraint's permits() to check if the constraint is allowed or denied. If the constraint's permits() is allowed, this method will exit this and any recursive next() calls, returning 'true'. If the constraints called were disallowed, the last constraint will throw CertPathValidatorException.
Params:
  • cp – ConstraintsParameters
Returns:'true' if constraint allows the operation, 'false' if we are at the end of the constraint list or, nextConstraint is null.
/** * Recursively check if the constraints are allowed. * * If {@code nextConstraint} is non-null, this method will * call {@code nextConstraint}'s {@code permits()} to check if the * constraint is allowed or denied. If the constraint's * {@code permits()} is allowed, this method will exit this and any * recursive next() calls, returning 'true'. If the constraints called * were disallowed, the last constraint will throw * {@code CertPathValidatorException}. * * @param cp ConstraintsParameters * @return 'true' if constraint allows the operation, 'false' if * we are at the end of the constraint list or, * {@code nextConstraint} is null. */
boolean next(ConstraintsParameters cp) throws CertPathValidatorException { if (nextConstraint != null) { nextConstraint.permits(cp); return true; } return false; }
Recursively check if this constraint is allowed, If nextConstraint is non-null, this method will call nextConstraint's permit() to check if the constraint is allowed or denied. If the constraint's permit() is allowed, this method will exit this and any recursive next() calls, returning 'true'. If the constraints called were disallowed the check will exit with 'false'.
Params:
  • key – Public key
Returns:'true' if constraint allows the operation, 'false' if the constraint denies the operation.
/** * Recursively check if this constraint is allowed, * * If {@code nextConstraint} is non-null, this method will * call {@code nextConstraint}'s {@code permit()} to check if the * constraint is allowed or denied. If the constraint's * {@code permit()} is allowed, this method will exit this and any * recursive next() calls, returning 'true'. If the constraints * called were disallowed the check will exit with 'false'. * * @param key Public key * @return 'true' if constraint allows the operation, 'false' if * the constraint denies the operation. */
boolean next(Key key) { return nextConstraint != null && nextConstraint.permits(key); } String extendedMsg(ConstraintsParameters cp) { return (cp.getCertificate() == null ? "." : " used with certificate: " + cp.getCertificate().getSubjectX500Principal() + (cp.getVariant() != Validator.VAR_GENERIC ? ". Usage was " + cp.getVariant() : ".")); } } /* * This class contains constraints dealing with the certificate chain * of the certificate. */ private static class jdkCAConstraint extends Constraint { jdkCAConstraint(String algo) { algorithm = algo; } /* * Check if ConstraintsParameters has a trusted match, if it does * call next() for any following constraints. If it does not, exit * as this constraint(s) does not restrict the operation. */ @Override public void permits(ConstraintsParameters cp) throws CertPathValidatorException { if (debug != null) { debug.println("jdkCAConstraints.permits(): " + algorithm); } // Check chain has a trust anchor in cacerts if (cp.isTrustedMatch()) { if (next(cp)) { return; } throw new CertPathValidatorException( "Algorithm constraints check failed on certificate " + "anchor limits. " + algorithm + extendedMsg(cp), null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); } } } /* * This class handles the denyAfter constraint. The date is in the UTC/GMT * timezone. */ private static class DenyAfterConstraint extends Constraint { private Date denyAfterDate; private static final SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, MMM d HH:mm:ss z yyyy"); DenyAfterConstraint(String algo, int year, int month, int day) { Calendar c; algorithm = algo; if (debug != null) { debug.println("DenyAfterConstraint read in as: year " + year + ", month = " + month + ", day = " + day); } c = new Calendar.Builder().setTimeZone(TimeZone.getTimeZone("GMT")) .setDate(year, month - 1, day).build(); if (year > c.getActualMaximum(Calendar.YEAR) || year < c.getActualMinimum(Calendar.YEAR)) { throw new IllegalArgumentException( "Invalid year given in constraint: " + year); } if ((month - 1) > c.getActualMaximum(Calendar.MONTH) || (month - 1) < c.getActualMinimum(Calendar.MONTH)) { throw new IllegalArgumentException( "Invalid month given in constraint: " + month); } if (day > c.getActualMaximum(Calendar.DAY_OF_MONTH) || day < c.getActualMinimum(Calendar.DAY_OF_MONTH)) { throw new IllegalArgumentException( "Invalid Day of Month given in constraint: " + day); } denyAfterDate = c.getTime(); if (debug != null) { debug.println("DenyAfterConstraint date set to: " + dateFormat.format(denyAfterDate)); } } /* * Checking that the provided date is not beyond the constraint date. * The provided date can be the PKIXParameter date if given, * otherwise it is the current date. * * If the constraint disallows, call next() for any following * constraints. Throw an exception if this is the last constraint. */ @Override public void permits(ConstraintsParameters cp) throws CertPathValidatorException { Date currentDate; String errmsg; if (cp.getJARTimestamp() != null) { currentDate = cp.getJARTimestamp().getTimestamp(); errmsg = "JAR Timestamp date: "; } else if (cp.getPKIXParamDate() != null) { currentDate = cp.getPKIXParamDate(); errmsg = "PKIXParameter date: "; } else { currentDate = new Date(); errmsg = "Current date: "; } if (!denyAfterDate.after(currentDate)) { if (next(cp)) { return; } throw new CertPathValidatorException( "denyAfter constraint check failed: " + algorithm + " used with Constraint date: " + dateFormat.format(denyAfterDate) + "; " + errmsg + dateFormat.format(currentDate) + extendedMsg(cp), null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); } } /* * Return result if the constraint's date is beyond the current date * in UTC timezone. */ @Override public boolean permits(Key key) { if (next(key)) { return true; } if (debug != null) { debug.println("DenyAfterConstraints.permits(): " + algorithm); } return denyAfterDate.after(new Date()); } } /* * The usage constraint is for the "usage" keyword. It checks against the * variant value in ConstraintsParameters. */ private static class UsageConstraint extends Constraint { String[] usages; UsageConstraint(String algorithm, String[] usages) { this.algorithm = algorithm; this.usages = usages; } @Override public void permits(ConstraintsParameters cp) throws CertPathValidatorException { for (String usage : usages) { String v = null; if (usage.compareToIgnoreCase("TLSServer") == 0) { v = Validator.VAR_TLS_SERVER; } else if (usage.compareToIgnoreCase("TLSClient") == 0) { v = Validator.VAR_TLS_CLIENT; } else if (usage.compareToIgnoreCase("SignedJAR") == 0) { v = Validator.VAR_PLUGIN_CODE_SIGNING; } if (debug != null) { debug.println("Checking if usage constraint \"" + v + "\" matches \"" + cp.getVariant() + "\""); if (Debug.isVerbose()) { // Because usage checking can come from many places // a stack trace is very helpful. (new Exception()).printStackTrace(debug.getPrintStream()); } } if (cp.getVariant().compareTo(v) == 0) { if (next(cp)) { return; } throw new CertPathValidatorException("Usage constraint " + usage + " check failed: " + algorithm + extendedMsg(cp), null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); } } } } /* * This class contains constraints dealing with the key size * support limits per algorithm. e.g. "keySize <= 1024" */ private static class KeySizeConstraint extends Constraint { private int minSize; // the minimal available key size private int maxSize; // the maximal available key size private int prohibitedSize = -1; // unavailable key sizes public KeySizeConstraint(String algo, Operator operator, int length) { algorithm = algo; switch (operator) { case EQ: // an unavailable key size this.minSize = 0; this.maxSize = Integer.MAX_VALUE; prohibitedSize = length; break; case NE: this.minSize = length; this.maxSize = length; break; case LT: this.minSize = length; this.maxSize = Integer.MAX_VALUE; break; case LE: this.minSize = length + 1; this.maxSize = Integer.MAX_VALUE; break; case GT: this.minSize = 0; this.maxSize = length; break; case GE: this.minSize = 0; this.maxSize = length > 1 ? (length - 1) : 0; break; default: // unlikely to happen this.minSize = Integer.MAX_VALUE; this.maxSize = -1; } } /* * If we are passed a certificate, extract the public key and use it. * * Check if each constraint fails and check if there is a linked * constraint Any permitted constraint will exit the linked list * to allow the operation. */ @Override public void permits(ConstraintsParameters cp) throws CertPathValidatorException { Key key = null; if (cp.getKey() != null) { key = cp.getKey(); } else if (cp.getCertificate() != null) { key = cp.getCertificate().getPublicKey(); } if (key != null && !permitsImpl(key)) { if (nextConstraint != null) { nextConstraint.permits(cp); return; } throw new CertPathValidatorException( "Algorithm constraints check failed on keysize limits. " + algorithm + " " + KeyUtil.getKeySize(key) + "bit key" + extendedMsg(cp), null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); } } // Check if key constraint disable the specified key // Uses old style permit() @Override public boolean permits(Key key) { // If we recursively find a constraint that permits us to use // this key, return true and skip any other constraint checks. if (nextConstraint != null && nextConstraint.permits(key)) { return true; } if (debug != null) { debug.println("KeySizeConstraints.permits(): " + algorithm); } return permitsImpl(key); } @Override public boolean permits(AlgorithmParameters parameters) { String paramAlg = parameters.getAlgorithm(); if (!algorithm.equalsIgnoreCase(parameters.getAlgorithm())) { // Consider the impact of the algorithm aliases. Collection<String> aliases = AlgorithmDecomposer.getAliases(algorithm); if (!aliases.contains(paramAlg)) { return true; } } int keySize = KeyUtil.getKeySize(parameters); if (keySize == 0) { return false; } else if (keySize > 0) { return !((keySize < minSize) || (keySize > maxSize) || (prohibitedSize == keySize)); } // Otherwise, the key size is not accessible or determined. // Conservatively, please don't disable such keys. return true; } private boolean permitsImpl(Key key) { // Verify this constraint is for this public key algorithm if (algorithm.compareToIgnoreCase(key.getAlgorithm()) != 0) { return true; } int size = KeyUtil.getKeySize(key); if (size == 0) { return false; // we don't allow any key of size 0. } else if (size > 0) { return !((size < minSize) || (size > maxSize) || (prohibitedSize == size)); } // Otherwise, the key size is not accessible. Conservatively, // please don't disable such keys. return true; } } /* * This constraint is used for the complete disabling of the algorithm. */ private static class DisabledConstraint extends Constraint { DisabledConstraint(String algo) { algorithm = algo; } @Override public void permits(ConstraintsParameters cp) throws CertPathValidatorException { throw new CertPathValidatorException( "Algorithm constraints check failed on disabled " + "algorithm: " + algorithm + extendedMsg(cp), null, null, -1, BasicReason.ALGORITHM_CONSTRAINED); } @Override public boolean permits(Key key) { return false; } } }