Path: blob/master/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
67766 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.lang.ref.SoftReference;30import java.security.AlgorithmParameters;31import java.security.CryptoPrimitive;32import java.security.Key;33import java.security.cert.CertPathValidatorException;34import java.security.cert.CertPathValidatorException.BasicReason;35import java.security.interfaces.ECKey;36import java.security.interfaces.XECKey;37import java.security.spec.AlgorithmParameterSpec;38import java.security.spec.InvalidParameterSpecException;39import java.security.spec.MGF1ParameterSpec;40import java.security.spec.NamedParameterSpec;41import java.security.spec.PSSParameterSpec;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.concurrent.ConcurrentHashMap;56import java.util.regex.Pattern;57import java.util.regex.Matcher;5859/**60* Algorithm constraints for disabled algorithms property61*62* See the "jdk.certpath.disabledAlgorithms" specification in java.security63* for the syntax of the disabled algorithm string.64*/65public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {66private static final Debug debug = Debug.getInstance("certpath");6768// Disabled algorithm security property for certificate path69public static final String PROPERTY_CERTPATH_DISABLED_ALGS =70"jdk.certpath.disabledAlgorithms";7172// Legacy algorithm security property for certificate path and jar73public static final String PROPERTY_SECURITY_LEGACY_ALGS =74"jdk.security.legacyAlgorithms";7576// Disabled algorithm security property for TLS77public static final String PROPERTY_TLS_DISABLED_ALGS =78"jdk.tls.disabledAlgorithms";7980// Disabled algorithm security property for jar81public static final String PROPERTY_JAR_DISABLED_ALGS =82"jdk.jar.disabledAlgorithms";8384// Property for disabled EC named curves85private static final String PROPERTY_DISABLED_EC_CURVES =86"jdk.disabled.namedCurves";8788private static final Pattern INCLUDE_PATTERN = Pattern.compile("include " +89PROPERTY_DISABLED_EC_CURVES, Pattern.CASE_INSENSITIVE);9091private static class CertPathHolder {92static final DisabledAlgorithmConstraints CONSTRAINTS =93new DisabledAlgorithmConstraints(PROPERTY_CERTPATH_DISABLED_ALGS);94}9596private static class JarHolder {97static final DisabledAlgorithmConstraints CONSTRAINTS =98new DisabledAlgorithmConstraints(PROPERTY_JAR_DISABLED_ALGS);99}100101private final Set<String> disabledAlgorithms;102private final Constraints algorithmConstraints;103private volatile SoftReference<Map<String, Boolean>> cacheRef =104new SoftReference<>(null);105106public static DisabledAlgorithmConstraints certPathConstraints() {107return CertPathHolder.CONSTRAINTS;108}109110public static DisabledAlgorithmConstraints jarConstraints() {111return JarHolder.CONSTRAINTS;112}113114/**115* Initialize algorithm constraints with the specified security property.116*117* @param propertyName the security property name that define the disabled118* algorithm constraints119*/120public DisabledAlgorithmConstraints(String propertyName) {121this(propertyName, new AlgorithmDecomposer());122}123124/**125* Initialize algorithm constraints with the specified security property126* for a specific usage type.127*128* @param propertyName the security property name that define the disabled129* algorithm constraints130* @param decomposer an alternate AlgorithmDecomposer.131*/132public DisabledAlgorithmConstraints(String propertyName,133AlgorithmDecomposer decomposer) {134super(decomposer);135disabledAlgorithms = getAlgorithms(propertyName);136137// Check for alias138for (String s : disabledAlgorithms) {139Matcher matcher = INCLUDE_PATTERN.matcher(s);140if (matcher.matches()) {141disabledAlgorithms.remove(matcher.group());142disabledAlgorithms.addAll(143getAlgorithms(PROPERTY_DISABLED_EC_CURVES));144break;145}146}147algorithmConstraints = new Constraints(propertyName, disabledAlgorithms);148}149150/*151* This only checks if the algorithm has been completely disabled. If152* there are keysize or other limit, this method allow the algorithm.153*/154@Override155public final boolean permits(Set<CryptoPrimitive> primitives,156String algorithm, AlgorithmParameters parameters) {157if (primitives == null || primitives.isEmpty()) {158throw new IllegalArgumentException("The primitives cannot be null" +159" or empty.");160}161if (algorithm == null || algorithm.isEmpty()) {162throw new IllegalArgumentException("No algorithm name specified");163}164165if (!cachedCheckAlgorithm(algorithm)) {166return false;167}168169if (parameters != null) {170return algorithmConstraints.permits(algorithm, parameters);171}172173return true;174}175176/*177* Checks if the key algorithm has been disabled or constraints have been178* placed on the key.179*/180@Override181public final boolean permits(Set<CryptoPrimitive> primitives, Key key) {182return checkConstraints(primitives, "", key, null);183}184185/*186* Checks if the key algorithm has been disabled or if constraints have187* been placed on the key.188*/189@Override190public final boolean permits(Set<CryptoPrimitive> primitives,191String algorithm, Key key, AlgorithmParameters parameters) {192193if (algorithm == null || algorithm.isEmpty()) {194throw new IllegalArgumentException("No algorithm name specified");195}196197return checkConstraints(primitives, algorithm, key, parameters);198}199200public final void permits(String algorithm, AlgorithmParameters ap,201ConstraintsParameters cp) throws CertPathValidatorException {202203permits(algorithm, cp);204if (ap != null) {205permits(ap, cp);206}207}208209private void permits(AlgorithmParameters ap, ConstraintsParameters cp)210throws CertPathValidatorException {211212switch (ap.getAlgorithm().toUpperCase(Locale.ENGLISH)) {213case "RSASSA-PSS":214permitsPSSParams(ap, cp);215break;216default:217// unknown algorithm, just ignore218}219}220221private void permitsPSSParams(AlgorithmParameters ap,222ConstraintsParameters cp) throws CertPathValidatorException {223224try {225PSSParameterSpec pssParams =226ap.getParameterSpec(PSSParameterSpec.class);227String digestAlg = pssParams.getDigestAlgorithm();228permits(digestAlg, cp);229AlgorithmParameterSpec mgfParams = pssParams.getMGFParameters();230if (mgfParams instanceof MGF1ParameterSpec) {231String mgfDigestAlg =232((MGF1ParameterSpec)mgfParams).getDigestAlgorithm();233if (!mgfDigestAlg.equalsIgnoreCase(digestAlg)) {234permits(mgfDigestAlg, cp);235}236}237} catch (InvalidParameterSpecException ipse) {238// ignore239}240}241242public final void permits(String algorithm, ConstraintsParameters cp)243throws CertPathValidatorException {244245// Check if named curves in the key are disabled.246for (Key key : cp.getKeys()) {247for (String curve : getNamedCurveFromKey(key)) {248if (!cachedCheckAlgorithm(curve)) {249throw new CertPathValidatorException(250"Algorithm constraints check failed on disabled " +251"algorithm: " + curve,252null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);253}254}255}256257algorithmConstraints.permits(algorithm, cp);258}259260private static List<String> getNamedCurveFromKey(Key key) {261if (key instanceof ECKey) {262NamedCurve nc = CurveDB.lookup(((ECKey)key).getParams());263return (nc == null ? List.of()264: Arrays.asList(nc.getNameAndAliases()));265} else if (key instanceof XECKey) {266return List.of(267((NamedParameterSpec)((XECKey)key).getParams()).getName());268} else {269return List.of();270}271}272273// Check algorithm constraints with key and algorithm274private boolean checkConstraints(Set<CryptoPrimitive> primitives,275String algorithm, Key key, AlgorithmParameters parameters) {276277if (primitives == null || primitives.isEmpty()) {278throw new IllegalArgumentException("The primitives cannot be null" +279" or empty.");280}281282if (key == null) {283throw new IllegalArgumentException("The key cannot be null");284}285286// check the signature algorithm with parameters287if (algorithm != null && !algorithm.isEmpty()) {288if (!permits(primitives, algorithm, parameters)) {289return false;290}291}292293// check the key algorithm294if (!permits(primitives, key.getAlgorithm(), null)) {295return false;296}297298// If this is an elliptic curve, check if it is disabled299for (String curve : getNamedCurveFromKey(key)) {300if (!permits(primitives, curve, null)) {301return false;302}303}304305// check the key constraints306return algorithmConstraints.permits(key);307}308309310/**311* Key and Certificate Constraints312*313* The complete disabling of an algorithm is not handled by Constraints or314* Constraint classes. That is addressed with315* permit(Set<CryptoPrimitive>, String, AlgorithmParameters)316*317* When passing a Key to permit(), the boolean return values follow the318* same as the interface class AlgorithmConstraints.permit(). This is to319* maintain compatibility:320* 'true' means the operation is allowed.321* 'false' means it failed the constraints and is disallowed.322*323* When passing ConstraintsParameters through permit(), an exception324* will be thrown on a failure to better identify why the operation was325* disallowed.326*/327328private static class Constraints {329private Map<String, List<Constraint>> constraintsMap = new HashMap<>();330331private static class Holder {332private static final Pattern DENY_AFTER_PATTERN = Pattern.compile(333"denyAfter\\s+(\\d{4})-(\\d{2})-(\\d{2})");334}335336public Constraints(String propertyName, Set<String> constraintSet) {337for (String constraintEntry : constraintSet) {338if (constraintEntry == null || constraintEntry.isEmpty()) {339continue;340}341342constraintEntry = constraintEntry.trim();343if (debug != null) {344debug.println("Constraints: " + constraintEntry);345}346347// Check if constraint is a complete disabling of an348// algorithm or has conditions.349int space = constraintEntry.indexOf(' ');350String algorithm = AlgorithmDecomposer.hashName(351((space > 0 ? constraintEntry.substring(0, space) :352constraintEntry)));353List<Constraint> constraintList =354constraintsMap.getOrDefault(355algorithm.toUpperCase(Locale.ENGLISH),356new ArrayList<>(1));357358// Consider the impact of algorithm aliases.359for (String alias : AlgorithmDecomposer.getAliases(algorithm)) {360constraintsMap.putIfAbsent(361alias.toUpperCase(Locale.ENGLISH), constraintList);362}363364// If there is no whitespace, it is a algorithm name; however,365// if there is a whitespace, could be a multi-word EC curve too.366if (space <= 0 || CurveDB.lookup(constraintEntry) != null) {367constraintList.add(new DisabledConstraint(algorithm));368continue;369}370371String policy = constraintEntry.substring(space + 1);372373// Convert constraint conditions into Constraint classes374Constraint c, lastConstraint = null;375// Allow only one jdkCA entry per constraint entry376boolean jdkCALimit = false;377// Allow only one denyAfter entry per constraint entry378boolean denyAfterLimit = false;379380for (String entry : policy.split("&")) {381entry = entry.trim();382383Matcher matcher;384if (entry.startsWith("keySize")) {385if (debug != null) {386debug.println("Constraints set to keySize: " +387entry);388}389StringTokenizer tokens = new StringTokenizer(entry);390if (!"keySize".equals(tokens.nextToken())) {391throw new IllegalArgumentException("Error in " +392"security property. Constraint unknown: " +393entry);394}395c = new KeySizeConstraint(algorithm,396KeySizeConstraint.Operator.of(tokens.nextToken()),397Integer.parseInt(tokens.nextToken()));398399} else if (entry.equalsIgnoreCase("jdkCA")) {400if (debug != null) {401debug.println("Constraints set to jdkCA.");402}403if (jdkCALimit) {404throw new IllegalArgumentException("Only one " +405"jdkCA entry allowed in property. " +406"Constraint: " + constraintEntry);407}408c = new jdkCAConstraint(algorithm);409jdkCALimit = true;410411} else if (entry.startsWith("denyAfter") &&412(matcher = Holder.DENY_AFTER_PATTERN.matcher(entry))413.matches()) {414if (debug != null) {415debug.println("Constraints set to denyAfter");416}417if (denyAfterLimit) {418throw new IllegalArgumentException("Only one " +419"denyAfter entry allowed in property. " +420"Constraint: " + constraintEntry);421}422int year = Integer.parseInt(matcher.group(1));423int month = Integer.parseInt(matcher.group(2));424int day = Integer.parseInt(matcher.group(3));425c = new DenyAfterConstraint(algorithm, year, month,426day);427denyAfterLimit = true;428} else if (entry.startsWith("usage")) {429String s[] = (entry.substring(5)).trim().split(" ");430c = new UsageConstraint(algorithm, s);431if (debug != null) {432debug.println("Constraints usage length is " + s.length);433}434} else {435throw new IllegalArgumentException("Error in security" +436" property. Constraint unknown: " + entry);437}438439// Link multiple conditions for a single constraint440// into a linked list.441if (lastConstraint == null) {442constraintList.add(c);443} else {444lastConstraint.nextConstraint = c;445}446lastConstraint = c;447}448}449}450451// Get applicable constraints based off the algorithm452private List<Constraint> getConstraints(String algorithm) {453return constraintsMap.get(algorithm.toUpperCase(Locale.ENGLISH));454}455456// Check if KeySizeConstraints permit the specified key457public boolean permits(Key key) {458List<Constraint> list = getConstraints(key.getAlgorithm());459if (list == null) {460return true;461}462for (Constraint constraint : list) {463if (!constraint.permits(key)) {464if (debug != null) {465debug.println("Constraints: failed key size" +466"constraint check " + KeyUtil.getKeySize(key));467}468return false;469}470}471return true;472}473474// Check if constraints permit this AlgorithmParameters.475public boolean permits(String algorithm, AlgorithmParameters aps) {476List<Constraint> list = getConstraints(algorithm);477if (list == null) {478return true;479}480481for (Constraint constraint : list) {482if (!constraint.permits(aps)) {483if (debug != null) {484debug.println("Constraints: failed algorithm " +485"parameters constraint check " + aps);486}487488return false;489}490}491492return true;493}494495public void permits(String algorithm, ConstraintsParameters cp)496throws CertPathValidatorException {497498if (debug != null) {499debug.println("Constraints.permits(): " + algorithm + ", "500+ cp.toString());501}502503// Get all signature algorithms to check for constraints504Set<String> algorithms = new HashSet<>();505if (algorithm != null) {506algorithms.addAll(AlgorithmDecomposer.decomposeOneHash(algorithm));507algorithms.add(algorithm);508}509510for (Key key : cp.getKeys()) {511algorithms.add(key.getAlgorithm());512}513514// Check all applicable constraints515for (String alg : algorithms) {516List<Constraint> list = getConstraints(alg);517if (list == null) {518continue;519}520for (Constraint constraint : list) {521constraint.permits(cp);522}523}524}525}526527/**528* This abstract Constraint class for algorithm-based checking529* may contain one or more constraints. If the '&' on the {@Security}530* property is used, multiple constraints have been grouped together531* requiring all the constraints to fail for the check to be disallowed.532*533* If the class contains multiple constraints, the next constraint534* is stored in {@code nextConstraint} in linked-list fashion.535*/536private abstract static class Constraint {537String algorithm;538Constraint nextConstraint = null;539540// operator541enum Operator {542EQ, // "=="543NE, // "!="544LT, // "<"545LE, // "<="546GT, // ">"547GE; // ">="548549static Operator of(String s) {550switch (s) {551case "==":552return EQ;553case "!=":554return NE;555case "<":556return LT;557case "<=":558return LE;559case ">":560return GT;561case ">=":562return GE;563}564565throw new IllegalArgumentException("Error in security " +566"property. " + s + " is not a legal Operator");567}568}569570/**571* Check if an algorithm constraint is permitted with a given key.572*573* If the check inside of {@code permit()} fails, it must call574* {@code next()} with the same {@code Key} parameter passed if575* multiple constraints need to be checked.576*577* @param key Public key578* @return 'true' if constraint is allowed, 'false' if disallowed.579*/580public boolean permits(Key key) {581return true;582}583584/**585* Check if the algorithm constraint permits a given cryptographic586* parameters.587*588* @param parameters the cryptographic parameters589* @return 'true' if the cryptographic parameters is allowed,590* 'false' ortherwise.591*/592public boolean permits(AlgorithmParameters parameters) {593return true;594}595596/**597* Check if an algorithm constraint is permitted with a given598* ConstraintsParameters.599*600* If the check inside of {@code permits()} fails, it must call601* {@code next()} with the same {@code ConstraintsParameters}602* parameter passed if multiple constraints need to be checked.603*604* @param cp ConstraintsParameter containing certificate info605* @throws CertPathValidatorException if constraint disallows.606*607*/608public abstract void permits(ConstraintsParameters cp)609throws CertPathValidatorException;610611/**612* Recursively check if the constraints are allowed.613*614* If {@code nextConstraint} is non-null, this method will615* call {@code nextConstraint}'s {@code permits()} to check if the616* constraint is allowed or denied. If the constraint's617* {@code permits()} is allowed, this method will exit this and any618* recursive next() calls, returning 'true'. If the constraints called619* were disallowed, the last constraint will throw620* {@code CertPathValidatorException}.621*622* @param cp ConstraintsParameters623* @return 'true' if constraint allows the operation, 'false' if624* we are at the end of the constraint list or,625* {@code nextConstraint} is null.626*/627boolean next(ConstraintsParameters cp)628throws CertPathValidatorException {629if (nextConstraint != null) {630nextConstraint.permits(cp);631return true;632}633return false;634}635636/**637* Recursively check if this constraint is allowed,638*639* If {@code nextConstraint} is non-null, this method will640* call {@code nextConstraint}'s {@code permit()} to check if the641* constraint is allowed or denied. If the constraint's642* {@code permit()} is allowed, this method will exit this and any643* recursive next() calls, returning 'true'. If the constraints644* called were disallowed the check will exit with 'false'.645*646* @param key Public key647* @return 'true' if constraint allows the operation, 'false' if648* the constraint denies the operation.649*/650boolean next(Key key) {651return nextConstraint != null && nextConstraint.permits(key);652}653}654655/*656* This class contains constraints dealing with the certificate chain657* of the certificate.658*/659private static class jdkCAConstraint extends Constraint {660jdkCAConstraint(String algo) {661algorithm = algo;662}663664/*665* Check if ConstraintsParameters has a trusted match, if it does666* call next() for any following constraints. If it does not, exit667* as this constraint(s) does not restrict the operation.668*/669@Override670public void permits(ConstraintsParameters cp)671throws CertPathValidatorException {672if (debug != null) {673debug.println("jdkCAConstraints.permits(): " + algorithm);674}675676// Check if any certs chain back to at least one trust anchor in677// cacerts678if (cp.anchorIsJdkCA()) {679if (next(cp)) {680return;681}682throw new CertPathValidatorException(683"Algorithm constraints check failed on certificate " +684"anchor limits. " + algorithm + cp.extendedExceptionMsg(),685null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);686}687}688}689690/*691* This class handles the denyAfter constraint. The date is in the UTC/GMT692* timezone.693*/694private static class DenyAfterConstraint extends Constraint {695private Date denyAfterDate;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: " +729denyAfterDate);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: " +760denyAfterDate + "; params date: " +761currentDate + 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}966967private boolean cachedCheckAlgorithm(String algorithm) {968Map<String, Boolean> cache;969if ((cache = cacheRef.get()) == null) {970synchronized (this) {971if ((cache = cacheRef.get()) == null) {972cache = new ConcurrentHashMap<>();973cacheRef = new SoftReference<>(cache);974}975}976}977Boolean result = cache.get(algorithm);978if (result != null) {979return result;980}981result = checkAlgorithm(disabledAlgorithms, algorithm, decomposer);982cache.put(algorithm, result);983return result;984}985986/*987* This constraint is used for the complete disabling of the algorithm.988*/989private static class DisabledConstraint extends Constraint {990DisabledConstraint(String algo) {991algorithm = algo;992}993994@Override995public void permits(ConstraintsParameters cp)996throws CertPathValidatorException {997throw new CertPathValidatorException(998"Algorithm constraints check failed on disabled " +999"algorithm: " + algorithm + cp.extendedExceptionMsg(),1000null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);1001}10021003@Override1004public boolean permits(Key key) {1005return false;1006}1007}1008}100910101011