Path: blob/master/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
41159 views
/*1* Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.util;2627import sun.security.validator.Validator;2829import java.security.AlgorithmParameters;30import java.security.CryptoPrimitive;31import java.security.Key;32import java.security.cert.CertPathValidatorException;33import java.security.cert.CertPathValidatorException.BasicReason;34import java.security.interfaces.ECKey;35import java.security.interfaces.XECKey;36import java.security.spec.AlgorithmParameterSpec;37import java.security.spec.InvalidParameterSpecException;38import java.security.spec.MGF1ParameterSpec;39import java.security.spec.NamedParameterSpec;40import java.security.spec.PSSParameterSpec;41import java.text.SimpleDateFormat;42import java.util.ArrayList;43import java.util.Arrays;44import java.util.Calendar;45import java.util.Date;46import java.util.HashMap;47import java.util.HashSet;48import java.util.List;49import java.util.Locale;50import java.util.Map;51import java.util.Set;52import java.util.Collection;53import java.util.StringTokenizer;54import java.util.TimeZone;55import java.util.regex.Pattern;56import java.util.regex.Matcher;5758/**59* Algorithm constraints for disabled algorithms property60*61* See the "jdk.certpath.disabledAlgorithms" specification in java.security62* for the syntax of the disabled algorithm string.63*/64public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {65private static final Debug debug = Debug.getInstance("certpath");6667// Disabled algorithm security property for certificate path68public static final String PROPERTY_CERTPATH_DISABLED_ALGS =69"jdk.certpath.disabledAlgorithms";7071// Legacy algorithm security property for certificate path and jar72public static final String PROPERTY_SECURITY_LEGACY_ALGS =73"jdk.security.legacyAlgorithms";7475// Disabled algorithm security property for TLS76public static final String PROPERTY_TLS_DISABLED_ALGS =77"jdk.tls.disabledAlgorithms";7879// Disabled algorithm security property for jar80public static final String PROPERTY_JAR_DISABLED_ALGS =81"jdk.jar.disabledAlgorithms";8283// Property for disabled EC named curves84private static final String PROPERTY_DISABLED_EC_CURVES =85"jdk.disabled.namedCurves";8687private static class CertPathHolder {88static final DisabledAlgorithmConstraints CONSTRAINTS =89new DisabledAlgorithmConstraints(PROPERTY_CERTPATH_DISABLED_ALGS);90}9192private static class JarHolder {93static final DisabledAlgorithmConstraints CONSTRAINTS =94new DisabledAlgorithmConstraints(PROPERTY_JAR_DISABLED_ALGS);95}9697private final List<String> disabledAlgorithms;98private final Constraints algorithmConstraints;99100public static DisabledAlgorithmConstraints certPathConstraints() {101return CertPathHolder.CONSTRAINTS;102}103104public static DisabledAlgorithmConstraints jarConstraints() {105return JarHolder.CONSTRAINTS;106}107108/**109* Initialize algorithm constraints with the specified security property.110*111* @param propertyName the security property name that define the disabled112* algorithm constraints113*/114public DisabledAlgorithmConstraints(String propertyName) {115this(propertyName, new AlgorithmDecomposer());116}117118/**119* Initialize algorithm constraints with the specified security property120* for a specific usage type.121*122* @param propertyName the security property name that define the disabled123* algorithm constraints124* @param decomposer an alternate AlgorithmDecomposer.125*/126public DisabledAlgorithmConstraints(String propertyName,127AlgorithmDecomposer decomposer) {128super(decomposer);129disabledAlgorithms = getAlgorithms(propertyName);130131// Check for alias132int ecindex = -1, i = 0;133for (String s : disabledAlgorithms) {134if (s.regionMatches(true, 0,"include ", 0, 8)) {135if (s.regionMatches(true, 8, PROPERTY_DISABLED_EC_CURVES, 0,136PROPERTY_DISABLED_EC_CURVES.length())) {137ecindex = i;138break;139}140}141i++;142}143if (ecindex > -1) {144disabledAlgorithms.remove(ecindex);145disabledAlgorithms.addAll(ecindex,146getAlgorithms(PROPERTY_DISABLED_EC_CURVES));147}148algorithmConstraints = new Constraints(propertyName, disabledAlgorithms);149}150151/*152* This only checks if the algorithm has been completely disabled. If153* there are keysize or other limit, this method allow the algorithm.154*/155@Override156public final boolean permits(Set<CryptoPrimitive> primitives,157String algorithm, AlgorithmParameters parameters) {158if (primitives == null || primitives.isEmpty()) {159throw new IllegalArgumentException("The primitives cannot be null" +160" or empty.");161}162163if (!checkAlgorithm(disabledAlgorithms, algorithm, decomposer)) {164return false;165}166167if (parameters != null) {168return algorithmConstraints.permits(algorithm, parameters);169}170171return true;172}173174/*175* Checks if the key algorithm has been disabled or constraints have been176* placed on the key.177*/178@Override179public final boolean permits(Set<CryptoPrimitive> primitives, Key key) {180return checkConstraints(primitives, "", key, null);181}182183/*184* Checks if the key algorithm has been disabled or if constraints have185* been placed on the key.186*/187@Override188public final boolean permits(Set<CryptoPrimitive> primitives,189String algorithm, Key key, AlgorithmParameters parameters) {190191if (algorithm == null || algorithm.isEmpty()) {192throw new IllegalArgumentException("No algorithm name specified");193}194195return checkConstraints(primitives, algorithm, key, parameters);196}197198public final void permits(String algorithm, AlgorithmParameters ap,199ConstraintsParameters cp) throws CertPathValidatorException {200201permits(algorithm, cp);202if (ap != null) {203permits(ap, cp);204}205}206207private void permits(AlgorithmParameters ap, ConstraintsParameters cp)208throws CertPathValidatorException {209210switch (ap.getAlgorithm().toUpperCase(Locale.ENGLISH)) {211case "RSASSA-PSS":212permitsPSSParams(ap, cp);213break;214default:215// unknown algorithm, just ignore216}217}218219private void permitsPSSParams(AlgorithmParameters ap,220ConstraintsParameters cp) throws CertPathValidatorException {221222try {223PSSParameterSpec pssParams =224ap.getParameterSpec(PSSParameterSpec.class);225String digestAlg = pssParams.getDigestAlgorithm();226permits(digestAlg, cp);227AlgorithmParameterSpec mgfParams = pssParams.getMGFParameters();228if (mgfParams instanceof MGF1ParameterSpec) {229String mgfDigestAlg =230((MGF1ParameterSpec)mgfParams).getDigestAlgorithm();231if (!mgfDigestAlg.equalsIgnoreCase(digestAlg)) {232permits(mgfDigestAlg, cp);233}234}235} catch (InvalidParameterSpecException ipse) {236// ignore237}238}239240public final void permits(String algorithm, ConstraintsParameters cp)241throws CertPathValidatorException {242243// Check if named curves in the key are disabled.244for (Key key : cp.getKeys()) {245for (String curve : getNamedCurveFromKey(key)) {246if (!checkAlgorithm(disabledAlgorithms, curve, decomposer)) {247throw new CertPathValidatorException(248"Algorithm constraints check failed on disabled " +249"algorithm: " + curve,250null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);251}252}253}254255algorithmConstraints.permits(algorithm, cp);256}257258private static List<String> getNamedCurveFromKey(Key key) {259if (key instanceof ECKey) {260NamedCurve nc = CurveDB.lookup(((ECKey)key).getParams());261return (nc == null ? List.of()262: Arrays.asList(nc.getNameAndAliases()));263} else if (key instanceof XECKey) {264return List.of(265((NamedParameterSpec)((XECKey)key).getParams()).getName());266} else {267return List.of();268}269}270271// Check algorithm constraints with key and algorithm272private boolean checkConstraints(Set<CryptoPrimitive> primitives,273String algorithm, Key key, AlgorithmParameters parameters) {274275if (primitives == null || primitives.isEmpty()) {276throw new IllegalArgumentException("The primitives cannot be null" +277" or empty.");278}279280if (key == null) {281throw new IllegalArgumentException("The key cannot be null");282}283284// check the signature algorithm with parameters285if (algorithm != null && !algorithm.isEmpty()) {286if (!permits(primitives, algorithm, parameters)) {287return false;288}289}290291// check the key algorithm292if (!permits(primitives, key.getAlgorithm(), null)) {293return false;294}295296// If this is an elliptic curve, check if it is disabled297for (String curve : getNamedCurveFromKey(key)) {298if (!permits(primitives, curve, null)) {299return false;300}301}302303// check the key constraints304return algorithmConstraints.permits(key);305}306307308/**309* Key and Certificate Constraints310*311* The complete disabling of an algorithm is not handled by Constraints or312* Constraint classes. That is addressed with313* permit(Set<CryptoPrimitive>, String, AlgorithmParameters)314*315* When passing a Key to permit(), the boolean return values follow the316* same as the interface class AlgorithmConstraints.permit(). This is to317* maintain compatibility:318* 'true' means the operation is allowed.319* 'false' means it failed the constraints and is disallowed.320*321* When passing ConstraintsParameters through permit(), an exception322* will be thrown on a failure to better identify why the operation was323* disallowed.324*/325326private static class Constraints {327private Map<String, List<Constraint>> constraintsMap = new HashMap<>();328329private static class Holder {330private static final Pattern DENY_AFTER_PATTERN = Pattern.compile(331"denyAfter\\s+(\\d{4})-(\\d{2})-(\\d{2})");332}333334public Constraints(String propertyName, List<String> constraintArray) {335for (String constraintEntry : constraintArray) {336if (constraintEntry == null || constraintEntry.isEmpty()) {337continue;338}339340constraintEntry = constraintEntry.trim();341if (debug != null) {342debug.println("Constraints: " + constraintEntry);343}344345// Check if constraint is a complete disabling of an346// algorithm or has conditions.347int space = constraintEntry.indexOf(' ');348String algorithm = AlgorithmDecomposer.hashName(349((space > 0 ? constraintEntry.substring(0, space) :350constraintEntry)));351List<Constraint> constraintList =352constraintsMap.getOrDefault(353algorithm.toUpperCase(Locale.ENGLISH),354new ArrayList<>(1));355356// Consider the impact of algorithm aliases.357for (String alias : AlgorithmDecomposer.getAliases(algorithm)) {358constraintsMap.putIfAbsent(359alias.toUpperCase(Locale.ENGLISH), constraintList);360}361362// If there is no whitespace, it is a algorithm name; however,363// if there is a whitespace, could be a multi-word EC curve too.364if (space <= 0 || CurveDB.lookup(constraintEntry) != null) {365constraintList.add(new DisabledConstraint(algorithm));366continue;367}368369String policy = constraintEntry.substring(space + 1);370371// Convert constraint conditions into Constraint classes372Constraint c, lastConstraint = null;373// Allow only one jdkCA entry per constraint entry374boolean jdkCALimit = false;375// Allow only one denyAfter entry per constraint entry376boolean denyAfterLimit = false;377378for (String entry : policy.split("&")) {379entry = entry.trim();380381Matcher matcher;382if (entry.startsWith("keySize")) {383if (debug != null) {384debug.println("Constraints set to keySize: " +385entry);386}387StringTokenizer tokens = new StringTokenizer(entry);388if (!"keySize".equals(tokens.nextToken())) {389throw new IllegalArgumentException("Error in " +390"security property. Constraint unknown: " +391entry);392}393c = new KeySizeConstraint(algorithm,394KeySizeConstraint.Operator.of(tokens.nextToken()),395Integer.parseInt(tokens.nextToken()));396397} else if (entry.equalsIgnoreCase("jdkCA")) {398if (debug != null) {399debug.println("Constraints set to jdkCA.");400}401if (jdkCALimit) {402throw new IllegalArgumentException("Only one " +403"jdkCA entry allowed in property. " +404"Constraint: " + constraintEntry);405}406c = new jdkCAConstraint(algorithm);407jdkCALimit = true;408409} else if (entry.startsWith("denyAfter") &&410(matcher = Holder.DENY_AFTER_PATTERN.matcher(entry))411.matches()) {412if (debug != null) {413debug.println("Constraints set to denyAfter");414}415if (denyAfterLimit) {416throw new IllegalArgumentException("Only one " +417"denyAfter entry allowed in property. " +418"Constraint: " + constraintEntry);419}420int year = Integer.parseInt(matcher.group(1));421int month = Integer.parseInt(matcher.group(2));422int day = Integer.parseInt(matcher.group(3));423c = new DenyAfterConstraint(algorithm, year, month,424day);425denyAfterLimit = true;426} else if (entry.startsWith("usage")) {427String s[] = (entry.substring(5)).trim().split(" ");428c = new UsageConstraint(algorithm, s);429if (debug != null) {430debug.println("Constraints usage length is " + s.length);431}432} else {433throw new IllegalArgumentException("Error in security" +434" property. Constraint unknown: " + entry);435}436437// Link multiple conditions for a single constraint438// into a linked list.439if (lastConstraint == null) {440constraintList.add(c);441} else {442lastConstraint.nextConstraint = c;443}444lastConstraint = c;445}446}447}448449// Get applicable constraints based off the algorithm450private List<Constraint> getConstraints(String algorithm) {451return constraintsMap.get(algorithm.toUpperCase(Locale.ENGLISH));452}453454// Check if KeySizeConstraints permit the specified key455public boolean permits(Key key) {456List<Constraint> list = getConstraints(key.getAlgorithm());457if (list == null) {458return true;459}460for (Constraint constraint : list) {461if (!constraint.permits(key)) {462if (debug != null) {463debug.println("Constraints: failed key size" +464"constraint check " + KeyUtil.getKeySize(key));465}466return false;467}468}469return true;470}471472// Check if constraints permit this AlgorithmParameters.473public boolean permits(String algorithm, AlgorithmParameters aps) {474List<Constraint> list = getConstraints(algorithm);475if (list == null) {476return true;477}478479for (Constraint constraint : list) {480if (!constraint.permits(aps)) {481if (debug != null) {482debug.println("Constraints: failed algorithm " +483"parameters constraint check " + aps);484}485486return false;487}488}489490return true;491}492493public void permits(String algorithm, ConstraintsParameters cp)494throws CertPathValidatorException {495496if (debug != null) {497debug.println("Constraints.permits(): " + algorithm + ", "498+ cp.toString());499}500501// Get all signature algorithms to check for constraints502Set<String> algorithms = new HashSet<>();503if (algorithm != null) {504algorithms.addAll(AlgorithmDecomposer.decomposeOneHash(algorithm));505algorithms.add(algorithm);506}507508for (Key key : cp.getKeys()) {509algorithms.add(key.getAlgorithm());510}511512// Check all applicable constraints513for (String alg : algorithms) {514List<Constraint> list = getConstraints(alg);515if (list == null) {516continue;517}518for (Constraint constraint : list) {519constraint.permits(cp);520}521}522}523}524525/**526* This abstract Constraint class for algorithm-based checking527* may contain one or more constraints. If the '&' on the {@Security}528* property is used, multiple constraints have been grouped together529* requiring all the constraints to fail for the check to be disallowed.530*531* If the class contains multiple constraints, the next constraint532* is stored in {@code nextConstraint} in linked-list fashion.533*/534private abstract static class Constraint {535String algorithm;536Constraint nextConstraint = null;537538// operator539enum Operator {540EQ, // "=="541NE, // "!="542LT, // "<"543LE, // "<="544GT, // ">"545GE; // ">="546547static Operator of(String s) {548switch (s) {549case "==":550return EQ;551case "!=":552return NE;553case "<":554return LT;555case "<=":556return LE;557case ">":558return GT;559case ">=":560return GE;561}562563throw new IllegalArgumentException("Error in security " +564"property. " + s + " is not a legal Operator");565}566}567568/**569* Check if an algorithm constraint is permitted with a given key.570*571* If the check inside of {@code permit()} fails, it must call572* {@code next()} with the same {@code Key} parameter passed if573* multiple constraints need to be checked.574*575* @param key Public key576* @return 'true' if constraint is allowed, 'false' if disallowed.577*/578public boolean permits(Key key) {579return true;580}581582/**583* Check if the algorithm constraint permits a given cryptographic584* parameters.585*586* @param parameters the cryptographic parameters587* @return 'true' if the cryptographic parameters is allowed,588* 'false' ortherwise.589*/590public boolean permits(AlgorithmParameters parameters) {591return true;592}593594/**595* Check if an algorithm constraint is permitted with a given596* ConstraintsParameters.597*598* If the check inside of {@code permits()} fails, it must call599* {@code next()} with the same {@code ConstraintsParameters}600* parameter passed if multiple constraints need to be checked.601*602* @param cp ConstraintsParameter containing certificate info603* @throws CertPathValidatorException if constraint disallows.604*605*/606public abstract void permits(ConstraintsParameters cp)607throws CertPathValidatorException;608609/**610* Recursively check if the constraints are allowed.611*612* If {@code nextConstraint} is non-null, this method will613* call {@code nextConstraint}'s {@code permits()} to check if the614* constraint is allowed or denied. If the constraint's615* {@code permits()} is allowed, this method will exit this and any616* recursive next() calls, returning 'true'. If the constraints called617* were disallowed, the last constraint will throw618* {@code CertPathValidatorException}.619*620* @param cp ConstraintsParameters621* @return 'true' if constraint allows the operation, 'false' if622* we are at the end of the constraint list or,623* {@code nextConstraint} is null.624*/625boolean next(ConstraintsParameters cp)626throws CertPathValidatorException {627if (nextConstraint != null) {628nextConstraint.permits(cp);629return true;630}631return false;632}633634/**635* Recursively check if this constraint is allowed,636*637* If {@code nextConstraint} is non-null, this method will638* call {@code nextConstraint}'s {@code permit()} to check if the639* constraint is allowed or denied. If the constraint's640* {@code permit()} is allowed, this method will exit this and any641* recursive next() calls, returning 'true'. If the constraints642* called were disallowed the check will exit with 'false'.643*644* @param key Public key645* @return 'true' if constraint allows the operation, 'false' if646* the constraint denies the operation.647*/648boolean next(Key key) {649return nextConstraint != null && nextConstraint.permits(key);650}651}652653/*654* This class contains constraints dealing with the certificate chain655* of the certificate.656*/657private static class jdkCAConstraint extends Constraint {658jdkCAConstraint(String algo) {659algorithm = algo;660}661662/*663* Check if ConstraintsParameters has a trusted match, if it does664* call next() for any following constraints. If it does not, exit665* as this constraint(s) does not restrict the operation.666*/667@Override668public void permits(ConstraintsParameters cp)669throws CertPathValidatorException {670if (debug != null) {671debug.println("jdkCAConstraints.permits(): " + algorithm);672}673674// Check if any certs chain back to at least one trust anchor in675// cacerts676if (cp.anchorIsJdkCA()) {677if (next(cp)) {678return;679}680throw new CertPathValidatorException(681"Algorithm constraints check failed on certificate " +682"anchor limits. " + algorithm + cp.extendedExceptionMsg(),683null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);684}685}686}687688/*689* This class handles the denyAfter constraint. The date is in the UTC/GMT690* timezone.691*/692private static class DenyAfterConstraint extends Constraint {693private Date denyAfterDate;694private static final SimpleDateFormat dateFormat =695new SimpleDateFormat("EEE, MMM d HH:mm:ss z yyyy");696697DenyAfterConstraint(String algo, int year, int month, int day) {698Calendar c;699700algorithm = algo;701702if (debug != null) {703debug.println("DenyAfterConstraint read in as: year " +704year + ", month = " + month + ", day = " + day);705}706707c = new Calendar.Builder().setTimeZone(TimeZone.getTimeZone("GMT"))708.setDate(year, month - 1, day).build();709710if (year > c.getActualMaximum(Calendar.YEAR) ||711year < c.getActualMinimum(Calendar.YEAR)) {712throw new IllegalArgumentException(713"Invalid year given in constraint: " + year);714}715if ((month - 1) > c.getActualMaximum(Calendar.MONTH) ||716(month - 1) < c.getActualMinimum(Calendar.MONTH)) {717throw new IllegalArgumentException(718"Invalid month given in constraint: " + month);719}720if (day > c.getActualMaximum(Calendar.DAY_OF_MONTH) ||721day < c.getActualMinimum(Calendar.DAY_OF_MONTH)) {722throw new IllegalArgumentException(723"Invalid Day of Month given in constraint: " + day);724}725726denyAfterDate = c.getTime();727if (debug != null) {728debug.println("DenyAfterConstraint date set to: " +729dateFormat.format(denyAfterDate));730}731}732733/*734* Checking that the provided date is not beyond the constraint date.735* The provided date can be the PKIXParameter date if given,736* otherwise it is the current date.737*738* If the constraint disallows, call next() for any following739* constraints. Throw an exception if this is the last constraint.740*/741@Override742public void permits(ConstraintsParameters cp)743throws CertPathValidatorException {744Date currentDate;745String errmsg;746747if (cp.getDate() != null) {748currentDate = cp.getDate();749} else {750currentDate = new Date();751}752753if (!denyAfterDate.after(currentDate)) {754if (next(cp)) {755return;756}757throw new CertPathValidatorException(758"denyAfter constraint check failed: " + algorithm +759" used with Constraint date: " +760dateFormat.format(denyAfterDate) + "; params date: " +761dateFormat.format(currentDate) + cp.extendedExceptionMsg(),762null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);763}764}765766/*767* Return result if the constraint's date is beyond the current date768* in UTC timezone.769*/770@Override771public boolean permits(Key key) {772if (next(key)) {773return true;774}775if (debug != null) {776debug.println("DenyAfterConstraints.permits(): " + algorithm);777}778779return denyAfterDate.after(new Date());780}781}782783/*784* The usage constraint is for the "usage" keyword. It checks against the785* variant value in ConstraintsParameters.786*/787private static class UsageConstraint extends Constraint {788String[] usages;789790UsageConstraint(String algorithm, String[] usages) {791this.algorithm = algorithm;792this.usages = usages;793}794795@Override796public void permits(ConstraintsParameters cp)797throws CertPathValidatorException {798String variant = cp.getVariant();799for (String usage : usages) {800801boolean match = false;802switch (usage.toLowerCase()) {803case "tlsserver":804match = variant.equals(Validator.VAR_TLS_SERVER);805break;806case "tlsclient":807match = variant.equals(Validator.VAR_TLS_CLIENT);808break;809case "signedjar":810match =811variant.equals(Validator.VAR_PLUGIN_CODE_SIGNING) ||812variant.equals(Validator.VAR_CODE_SIGNING) ||813variant.equals(Validator.VAR_TSA_SERVER);814break;815}816817if (debug != null) {818debug.println("Checking if usage constraint \"" + usage +819"\" matches \"" + cp.getVariant() + "\"");820if (Debug.isVerbose()) {821// Because usage checking can come from many places822// a stack trace is very helpful.823(new Exception()).printStackTrace(debug.getPrintStream());824}825}826if (match) {827if (next(cp)) {828return;829}830throw new CertPathValidatorException("Usage constraint " +831usage + " check failed: " + algorithm +832cp.extendedExceptionMsg(),833null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);834}835}836}837}838839/*840* This class contains constraints dealing with the key size841* support limits per algorithm. e.g. "keySize <= 1024"842*/843private static class KeySizeConstraint extends Constraint {844845private int minSize; // the minimal available key size846private int maxSize; // the maximal available key size847private int prohibitedSize = -1; // unavailable key sizes848849public KeySizeConstraint(String algo, Operator operator, int length) {850algorithm = algo;851switch (operator) {852case EQ: // an unavailable key size853this.minSize = 0;854this.maxSize = Integer.MAX_VALUE;855prohibitedSize = length;856break;857case NE:858this.minSize = length;859this.maxSize = length;860break;861case LT:862this.minSize = length;863this.maxSize = Integer.MAX_VALUE;864break;865case LE:866this.minSize = length + 1;867this.maxSize = Integer.MAX_VALUE;868break;869case GT:870this.minSize = 0;871this.maxSize = length;872break;873case GE:874this.minSize = 0;875this.maxSize = length > 1 ? (length - 1) : 0;876break;877default:878// unlikely to happen879this.minSize = Integer.MAX_VALUE;880this.maxSize = -1;881}882}883884/*885* For each key, check if each constraint fails and check if there is886* a linked constraint. Any permitted constraint will exit the linked887* list to allow the operation.888*/889@Override890public void permits(ConstraintsParameters cp)891throws CertPathValidatorException {892for (Key key : cp.getKeys()) {893if (!permitsImpl(key)) {894if (nextConstraint != null) {895nextConstraint.permits(cp);896continue;897}898throw new CertPathValidatorException(899"Algorithm constraints check failed on keysize limits: " +900algorithm + " " + KeyUtil.getKeySize(key) + " bit key" +901cp.extendedExceptionMsg(),902null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);903}904}905}906907908// Check if key constraint disable the specified key909// Uses old style permit()910@Override911public boolean permits(Key key) {912// If we recursively find a constraint that permits us to use913// this key, return true and skip any other constraint checks.914if (nextConstraint != null && nextConstraint.permits(key)) {915return true;916}917if (debug != null) {918debug.println("KeySizeConstraints.permits(): " + algorithm);919}920921return permitsImpl(key);922}923924@Override925public boolean permits(AlgorithmParameters parameters) {926String paramAlg = parameters.getAlgorithm();927if (!algorithm.equalsIgnoreCase(parameters.getAlgorithm())) {928// Consider the impact of the algorithm aliases.929Collection<String> aliases =930AlgorithmDecomposer.getAliases(algorithm);931if (!aliases.contains(paramAlg)) {932return true;933}934}935936int keySize = KeyUtil.getKeySize(parameters);937if (keySize == 0) {938return false;939} else if (keySize > 0) {940return !((keySize < minSize) || (keySize > maxSize) ||941(prohibitedSize == keySize));942} // Otherwise, the key size is not accessible or determined.943// Conservatively, please don't disable such keys.944945return true;946}947948private boolean permitsImpl(Key key) {949// Verify this constraint is for this public key algorithm950if (algorithm.compareToIgnoreCase(key.getAlgorithm()) != 0) {951return true;952}953954int size = KeyUtil.getKeySize(key);955if (size == 0) {956return false; // we don't allow any key of size 0.957} else if (size > 0) {958return !((size < minSize) || (size > maxSize) ||959(prohibitedSize == size));960} // Otherwise, the key size is not accessible. Conservatively,961// please don't disable such keys.962963return true;964}965}966967/*968* This constraint is used for the complete disabling of the algorithm.969*/970private static class DisabledConstraint extends Constraint {971DisabledConstraint(String algo) {972algorithm = algo;973}974975@Override976public void permits(ConstraintsParameters cp)977throws CertPathValidatorException {978throw new CertPathValidatorException(979"Algorithm constraints check failed on disabled " +980"algorithm: " + algorithm + cp.extendedExceptionMsg(),981null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);982}983984@Override985public boolean permits(Key key) {986return false;987}988}989}990991992