--- a/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java Thu May 26 13:18:32 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java Thu May 26 13:33:27 2016 -0700
@@ -31,11 +31,15 @@
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertPathValidatorException.BasicReason;
import java.security.cert.X509Certificate;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.TimeZone;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
@@ -226,6 +230,8 @@
private Map<String, Set<Constraint>> constraintsMap = new HashMap<>();
private static final Pattern keySizePattern = Pattern.compile(
"keySize\\s*(<=|<|==|!=|>|>=)\\s*(\\d+)");
+ private static final Pattern denyAfterPattern = Pattern.compile(
+ "denyAfter\\s+(\\d{4})-(\\d{2})-(\\d{2})");
public Constraints(String[] constraintArray) {
for (String constraintEntry : constraintArray) {
@@ -259,6 +265,8 @@
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();
@@ -284,6 +292,22 @@
}
c = new jdkCAConstraint(algorithm);
jdkCALimit = true;
+
+ } else if(matcher.usePattern(denyAfterPattern).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 {
throw new IllegalArgumentException("Error in security" +
" property. Constraint unknown: " + entry);
@@ -360,7 +384,15 @@
}
}
- // Abstract class for algorithm constraint checking
+ /**
+ * 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;
@@ -396,22 +428,79 @@
}
/**
- * Check if an algorithm constraint permit this key to be used.
+ * 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 constraints do not match
+ * @return 'true' if constraint is allowed, 'false' if disallowed.
*/
public boolean permits(Key key) {
return true;
}
/**
- * Check if an algorithm constraint is permit this certificate to
- * be used.
- * @param cp CertificateParameter containing certificate and state info
- * @return true if constraints do not match
+ * Check if an algorithm constraint is permitted with a given
+ * CertConstraintParameters.
+ *
+ * If the check inside of {@code permits()} fails, it must call
+ * {@code next()} with the same {@code CertConstraintParameters}
+ * parameter passed if multiple constraints need to be checked.
+ *
+ * @param cp CertConstraintParameter containing certificate info
+ * @throws CertPathValidatorException if constraint disallows.
+ *
*/
public abstract void permits(CertConstraintParameters cp)
throws CertPathValidatorException;
+
+ /**
+ * 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 CertConstraintParameters
+ * @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(CertConstraintParameters cp)
+ throws CertPathValidatorException {
+ if (nextConstraint != null) {
+ nextConstraint.permits(cp);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 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) {
+ if (nextConstraint != null && nextConstraint.permits(key)) {
+ return true;
+ }
+ return false;
+ }
}
/*
@@ -424,9 +513,9 @@
}
/*
- * 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.
+ * Check if CertConstraintParameters 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.
*/
public void permits(CertConstraintParameters cp)
throws CertPathValidatorException {
@@ -434,10 +523,9 @@
debug.println("jdkCAConstraints.permits(): " + algorithm);
}
- // Return false if the chain has a trust anchor in cacerts
+ // Check chain has a trust anchor in cacerts
if (cp.isTrustedMatch()) {
- if (nextConstraint != null) {
- nextConstraint.permits(cp);
+ if (next(cp)) {
return;
}
throw new CertPathValidatorException(
@@ -448,6 +536,99 @@
}
}
+ /*
+ * 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(CertConstraintParameters cp)
+ throws CertPathValidatorException {
+ Date currentDate;
+
+ if (cp.getPKIXParamDate() != null) {
+ currentDate = cp.getPKIXParamDate();
+ } else {
+ currentDate = new Date();
+ }
+
+ if (!denyAfterDate.after(currentDate)) {
+ if (next(cp)) {
+ return;
+ }
+ throw new CertPathValidatorException(
+ "denyAfter constraint check failed. " +
+ "Constraint date: " +
+ dateFormat.format(denyAfterDate) +
+ "; Cert date: " +
+ dateFormat.format(currentDate),
+ null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+ }
+ }
+
+ /*
+ * Return result if the constraint's date is beyond the current date
+ * in UTC timezone.
+ */
+ public boolean permits(Key key) {
+ if (next(key)) {
+ return true;
+ }
+ if (debug != null) {
+ debug.println("DenyAfterConstraints.permits(): " + algorithm);
+ }
+
+ return denyAfterDate.after(new Date());
+ }
+ }
/*
* This class contains constraints dealing with the key size