Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
67766 views
1
/*
2
* Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.security.util;
27
28
import sun.security.validator.Validator;
29
30
import java.lang.ref.SoftReference;
31
import java.security.AlgorithmParameters;
32
import java.security.CryptoPrimitive;
33
import java.security.Key;
34
import java.security.cert.CertPathValidatorException;
35
import java.security.cert.CertPathValidatorException.BasicReason;
36
import java.security.interfaces.ECKey;
37
import java.security.interfaces.XECKey;
38
import java.security.spec.AlgorithmParameterSpec;
39
import java.security.spec.InvalidParameterSpecException;
40
import java.security.spec.MGF1ParameterSpec;
41
import java.security.spec.NamedParameterSpec;
42
import java.security.spec.PSSParameterSpec;
43
import java.util.ArrayList;
44
import java.util.Arrays;
45
import java.util.Calendar;
46
import java.util.Date;
47
import java.util.HashMap;
48
import java.util.HashSet;
49
import java.util.List;
50
import java.util.Locale;
51
import java.util.Map;
52
import java.util.Set;
53
import java.util.Collection;
54
import java.util.StringTokenizer;
55
import java.util.TimeZone;
56
import java.util.concurrent.ConcurrentHashMap;
57
import java.util.regex.Pattern;
58
import java.util.regex.Matcher;
59
60
/**
61
* Algorithm constraints for disabled algorithms property
62
*
63
* See the "jdk.certpath.disabledAlgorithms" specification in java.security
64
* for the syntax of the disabled algorithm string.
65
*/
66
public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
67
private static final Debug debug = Debug.getInstance("certpath");
68
69
// Disabled algorithm security property for certificate path
70
public static final String PROPERTY_CERTPATH_DISABLED_ALGS =
71
"jdk.certpath.disabledAlgorithms";
72
73
// Legacy algorithm security property for certificate path and jar
74
public static final String PROPERTY_SECURITY_LEGACY_ALGS =
75
"jdk.security.legacyAlgorithms";
76
77
// Disabled algorithm security property for TLS
78
public static final String PROPERTY_TLS_DISABLED_ALGS =
79
"jdk.tls.disabledAlgorithms";
80
81
// Disabled algorithm security property for jar
82
public static final String PROPERTY_JAR_DISABLED_ALGS =
83
"jdk.jar.disabledAlgorithms";
84
85
// Property for disabled EC named curves
86
private static final String PROPERTY_DISABLED_EC_CURVES =
87
"jdk.disabled.namedCurves";
88
89
private static final Pattern INCLUDE_PATTERN = Pattern.compile("include " +
90
PROPERTY_DISABLED_EC_CURVES, Pattern.CASE_INSENSITIVE);
91
92
private static class CertPathHolder {
93
static final DisabledAlgorithmConstraints CONSTRAINTS =
94
new DisabledAlgorithmConstraints(PROPERTY_CERTPATH_DISABLED_ALGS);
95
}
96
97
private static class JarHolder {
98
static final DisabledAlgorithmConstraints CONSTRAINTS =
99
new DisabledAlgorithmConstraints(PROPERTY_JAR_DISABLED_ALGS);
100
}
101
102
private final Set<String> disabledAlgorithms;
103
private final Constraints algorithmConstraints;
104
private volatile SoftReference<Map<String, Boolean>> cacheRef =
105
new SoftReference<>(null);
106
107
public static DisabledAlgorithmConstraints certPathConstraints() {
108
return CertPathHolder.CONSTRAINTS;
109
}
110
111
public static DisabledAlgorithmConstraints jarConstraints() {
112
return JarHolder.CONSTRAINTS;
113
}
114
115
/**
116
* Initialize algorithm constraints with the specified security property.
117
*
118
* @param propertyName the security property name that define the disabled
119
* algorithm constraints
120
*/
121
public DisabledAlgorithmConstraints(String propertyName) {
122
this(propertyName, new AlgorithmDecomposer());
123
}
124
125
/**
126
* Initialize algorithm constraints with the specified security property
127
* for a specific usage type.
128
*
129
* @param propertyName the security property name that define the disabled
130
* algorithm constraints
131
* @param decomposer an alternate AlgorithmDecomposer.
132
*/
133
public DisabledAlgorithmConstraints(String propertyName,
134
AlgorithmDecomposer decomposer) {
135
super(decomposer);
136
disabledAlgorithms = getAlgorithms(propertyName);
137
138
// Check for alias
139
for (String s : disabledAlgorithms) {
140
Matcher matcher = INCLUDE_PATTERN.matcher(s);
141
if (matcher.matches()) {
142
disabledAlgorithms.remove(matcher.group());
143
disabledAlgorithms.addAll(
144
getAlgorithms(PROPERTY_DISABLED_EC_CURVES));
145
break;
146
}
147
}
148
algorithmConstraints = new Constraints(propertyName, disabledAlgorithms);
149
}
150
151
/*
152
* This only checks if the algorithm has been completely disabled. If
153
* there are keysize or other limit, this method allow the algorithm.
154
*/
155
@Override
156
public final boolean permits(Set<CryptoPrimitive> primitives,
157
String algorithm, AlgorithmParameters parameters) {
158
if (primitives == null || primitives.isEmpty()) {
159
throw new IllegalArgumentException("The primitives cannot be null" +
160
" or empty.");
161
}
162
if (algorithm == null || algorithm.isEmpty()) {
163
throw new IllegalArgumentException("No algorithm name specified");
164
}
165
166
if (!cachedCheckAlgorithm(algorithm)) {
167
return false;
168
}
169
170
if (parameters != null) {
171
return algorithmConstraints.permits(algorithm, parameters);
172
}
173
174
return true;
175
}
176
177
/*
178
* Checks if the key algorithm has been disabled or constraints have been
179
* placed on the key.
180
*/
181
@Override
182
public final boolean permits(Set<CryptoPrimitive> primitives, Key key) {
183
return checkConstraints(primitives, "", key, null);
184
}
185
186
/*
187
* Checks if the key algorithm has been disabled or if constraints have
188
* been placed on the key.
189
*/
190
@Override
191
public final boolean permits(Set<CryptoPrimitive> primitives,
192
String algorithm, Key key, AlgorithmParameters parameters) {
193
194
if (algorithm == null || algorithm.isEmpty()) {
195
throw new IllegalArgumentException("No algorithm name specified");
196
}
197
198
return checkConstraints(primitives, algorithm, key, parameters);
199
}
200
201
public final void permits(String algorithm, AlgorithmParameters ap,
202
ConstraintsParameters cp) throws CertPathValidatorException {
203
204
permits(algorithm, cp);
205
if (ap != null) {
206
permits(ap, cp);
207
}
208
}
209
210
private void permits(AlgorithmParameters ap, ConstraintsParameters cp)
211
throws CertPathValidatorException {
212
213
switch (ap.getAlgorithm().toUpperCase(Locale.ENGLISH)) {
214
case "RSASSA-PSS":
215
permitsPSSParams(ap, cp);
216
break;
217
default:
218
// unknown algorithm, just ignore
219
}
220
}
221
222
private void permitsPSSParams(AlgorithmParameters ap,
223
ConstraintsParameters cp) throws CertPathValidatorException {
224
225
try {
226
PSSParameterSpec pssParams =
227
ap.getParameterSpec(PSSParameterSpec.class);
228
String digestAlg = pssParams.getDigestAlgorithm();
229
permits(digestAlg, cp);
230
AlgorithmParameterSpec mgfParams = pssParams.getMGFParameters();
231
if (mgfParams instanceof MGF1ParameterSpec) {
232
String mgfDigestAlg =
233
((MGF1ParameterSpec)mgfParams).getDigestAlgorithm();
234
if (!mgfDigestAlg.equalsIgnoreCase(digestAlg)) {
235
permits(mgfDigestAlg, cp);
236
}
237
}
238
} catch (InvalidParameterSpecException ipse) {
239
// ignore
240
}
241
}
242
243
public final void permits(String algorithm, ConstraintsParameters cp)
244
throws CertPathValidatorException {
245
246
// Check if named curves in the key are disabled.
247
for (Key key : cp.getKeys()) {
248
for (String curve : getNamedCurveFromKey(key)) {
249
if (!cachedCheckAlgorithm(curve)) {
250
throw new CertPathValidatorException(
251
"Algorithm constraints check failed on disabled " +
252
"algorithm: " + curve,
253
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
254
}
255
}
256
}
257
258
algorithmConstraints.permits(algorithm, cp);
259
}
260
261
private static List<String> getNamedCurveFromKey(Key key) {
262
if (key instanceof ECKey) {
263
NamedCurve nc = CurveDB.lookup(((ECKey)key).getParams());
264
return (nc == null ? List.of()
265
: Arrays.asList(nc.getNameAndAliases()));
266
} else if (key instanceof XECKey) {
267
return List.of(
268
((NamedParameterSpec)((XECKey)key).getParams()).getName());
269
} else {
270
return List.of();
271
}
272
}
273
274
// Check algorithm constraints with key and algorithm
275
private boolean checkConstraints(Set<CryptoPrimitive> primitives,
276
String algorithm, Key key, AlgorithmParameters parameters) {
277
278
if (primitives == null || primitives.isEmpty()) {
279
throw new IllegalArgumentException("The primitives cannot be null" +
280
" or empty.");
281
}
282
283
if (key == null) {
284
throw new IllegalArgumentException("The key cannot be null");
285
}
286
287
// check the signature algorithm with parameters
288
if (algorithm != null && !algorithm.isEmpty()) {
289
if (!permits(primitives, algorithm, parameters)) {
290
return false;
291
}
292
}
293
294
// check the key algorithm
295
if (!permits(primitives, key.getAlgorithm(), null)) {
296
return false;
297
}
298
299
// If this is an elliptic curve, check if it is disabled
300
for (String curve : getNamedCurveFromKey(key)) {
301
if (!permits(primitives, curve, null)) {
302
return false;
303
}
304
}
305
306
// check the key constraints
307
return algorithmConstraints.permits(key);
308
}
309
310
311
/**
312
* Key and Certificate Constraints
313
*
314
* The complete disabling of an algorithm is not handled by Constraints or
315
* Constraint classes. That is addressed with
316
* permit(Set<CryptoPrimitive>, String, AlgorithmParameters)
317
*
318
* When passing a Key to permit(), the boolean return values follow the
319
* same as the interface class AlgorithmConstraints.permit(). This is to
320
* maintain compatibility:
321
* 'true' means the operation is allowed.
322
* 'false' means it failed the constraints and is disallowed.
323
*
324
* When passing ConstraintsParameters through permit(), an exception
325
* will be thrown on a failure to better identify why the operation was
326
* disallowed.
327
*/
328
329
private static class Constraints {
330
private Map<String, List<Constraint>> constraintsMap = new HashMap<>();
331
332
private static class Holder {
333
private static final Pattern DENY_AFTER_PATTERN = Pattern.compile(
334
"denyAfter\\s+(\\d{4})-(\\d{2})-(\\d{2})");
335
}
336
337
public Constraints(String propertyName, Set<String> constraintSet) {
338
for (String constraintEntry : constraintSet) {
339
if (constraintEntry == null || constraintEntry.isEmpty()) {
340
continue;
341
}
342
343
constraintEntry = constraintEntry.trim();
344
if (debug != null) {
345
debug.println("Constraints: " + constraintEntry);
346
}
347
348
// Check if constraint is a complete disabling of an
349
// algorithm or has conditions.
350
int space = constraintEntry.indexOf(' ');
351
String algorithm = AlgorithmDecomposer.hashName(
352
((space > 0 ? constraintEntry.substring(0, space) :
353
constraintEntry)));
354
List<Constraint> constraintList =
355
constraintsMap.getOrDefault(
356
algorithm.toUpperCase(Locale.ENGLISH),
357
new ArrayList<>(1));
358
359
// Consider the impact of algorithm aliases.
360
for (String alias : AlgorithmDecomposer.getAliases(algorithm)) {
361
constraintsMap.putIfAbsent(
362
alias.toUpperCase(Locale.ENGLISH), constraintList);
363
}
364
365
// If there is no whitespace, it is a algorithm name; however,
366
// if there is a whitespace, could be a multi-word EC curve too.
367
if (space <= 0 || CurveDB.lookup(constraintEntry) != null) {
368
constraintList.add(new DisabledConstraint(algorithm));
369
continue;
370
}
371
372
String policy = constraintEntry.substring(space + 1);
373
374
// Convert constraint conditions into Constraint classes
375
Constraint c, lastConstraint = null;
376
// Allow only one jdkCA entry per constraint entry
377
boolean jdkCALimit = false;
378
// Allow only one denyAfter entry per constraint entry
379
boolean denyAfterLimit = false;
380
381
for (String entry : policy.split("&")) {
382
entry = entry.trim();
383
384
Matcher matcher;
385
if (entry.startsWith("keySize")) {
386
if (debug != null) {
387
debug.println("Constraints set to keySize: " +
388
entry);
389
}
390
StringTokenizer tokens = new StringTokenizer(entry);
391
if (!"keySize".equals(tokens.nextToken())) {
392
throw new IllegalArgumentException("Error in " +
393
"security property. Constraint unknown: " +
394
entry);
395
}
396
c = new KeySizeConstraint(algorithm,
397
KeySizeConstraint.Operator.of(tokens.nextToken()),
398
Integer.parseInt(tokens.nextToken()));
399
400
} else if (entry.equalsIgnoreCase("jdkCA")) {
401
if (debug != null) {
402
debug.println("Constraints set to jdkCA.");
403
}
404
if (jdkCALimit) {
405
throw new IllegalArgumentException("Only one " +
406
"jdkCA entry allowed in property. " +
407
"Constraint: " + constraintEntry);
408
}
409
c = new jdkCAConstraint(algorithm);
410
jdkCALimit = true;
411
412
} else if (entry.startsWith("denyAfter") &&
413
(matcher = Holder.DENY_AFTER_PATTERN.matcher(entry))
414
.matches()) {
415
if (debug != null) {
416
debug.println("Constraints set to denyAfter");
417
}
418
if (denyAfterLimit) {
419
throw new IllegalArgumentException("Only one " +
420
"denyAfter entry allowed in property. " +
421
"Constraint: " + constraintEntry);
422
}
423
int year = Integer.parseInt(matcher.group(1));
424
int month = Integer.parseInt(matcher.group(2));
425
int day = Integer.parseInt(matcher.group(3));
426
c = new DenyAfterConstraint(algorithm, year, month,
427
day);
428
denyAfterLimit = true;
429
} else if (entry.startsWith("usage")) {
430
String s[] = (entry.substring(5)).trim().split(" ");
431
c = new UsageConstraint(algorithm, s);
432
if (debug != null) {
433
debug.println("Constraints usage length is " + s.length);
434
}
435
} else {
436
throw new IllegalArgumentException("Error in security" +
437
" property. Constraint unknown: " + entry);
438
}
439
440
// Link multiple conditions for a single constraint
441
// into a linked list.
442
if (lastConstraint == null) {
443
constraintList.add(c);
444
} else {
445
lastConstraint.nextConstraint = c;
446
}
447
lastConstraint = c;
448
}
449
}
450
}
451
452
// Get applicable constraints based off the algorithm
453
private List<Constraint> getConstraints(String algorithm) {
454
return constraintsMap.get(algorithm.toUpperCase(Locale.ENGLISH));
455
}
456
457
// Check if KeySizeConstraints permit the specified key
458
public boolean permits(Key key) {
459
List<Constraint> list = getConstraints(key.getAlgorithm());
460
if (list == null) {
461
return true;
462
}
463
for (Constraint constraint : list) {
464
if (!constraint.permits(key)) {
465
if (debug != null) {
466
debug.println("Constraints: failed key size" +
467
"constraint check " + KeyUtil.getKeySize(key));
468
}
469
return false;
470
}
471
}
472
return true;
473
}
474
475
// Check if constraints permit this AlgorithmParameters.
476
public boolean permits(String algorithm, AlgorithmParameters aps) {
477
List<Constraint> list = getConstraints(algorithm);
478
if (list == null) {
479
return true;
480
}
481
482
for (Constraint constraint : list) {
483
if (!constraint.permits(aps)) {
484
if (debug != null) {
485
debug.println("Constraints: failed algorithm " +
486
"parameters constraint check " + aps);
487
}
488
489
return false;
490
}
491
}
492
493
return true;
494
}
495
496
public void permits(String algorithm, ConstraintsParameters cp)
497
throws CertPathValidatorException {
498
499
if (debug != null) {
500
debug.println("Constraints.permits(): " + algorithm + ", "
501
+ cp.toString());
502
}
503
504
// Get all signature algorithms to check for constraints
505
Set<String> algorithms = new HashSet<>();
506
if (algorithm != null) {
507
algorithms.addAll(AlgorithmDecomposer.decomposeOneHash(algorithm));
508
algorithms.add(algorithm);
509
}
510
511
for (Key key : cp.getKeys()) {
512
algorithms.add(key.getAlgorithm());
513
}
514
515
// Check all applicable constraints
516
for (String alg : algorithms) {
517
List<Constraint> list = getConstraints(alg);
518
if (list == null) {
519
continue;
520
}
521
for (Constraint constraint : list) {
522
constraint.permits(cp);
523
}
524
}
525
}
526
}
527
528
/**
529
* This abstract Constraint class for algorithm-based checking
530
* may contain one or more constraints. If the '&' on the {@Security}
531
* property is used, multiple constraints have been grouped together
532
* requiring all the constraints to fail for the check to be disallowed.
533
*
534
* If the class contains multiple constraints, the next constraint
535
* is stored in {@code nextConstraint} in linked-list fashion.
536
*/
537
private abstract static class Constraint {
538
String algorithm;
539
Constraint nextConstraint = null;
540
541
// operator
542
enum Operator {
543
EQ, // "=="
544
NE, // "!="
545
LT, // "<"
546
LE, // "<="
547
GT, // ">"
548
GE; // ">="
549
550
static Operator of(String s) {
551
switch (s) {
552
case "==":
553
return EQ;
554
case "!=":
555
return NE;
556
case "<":
557
return LT;
558
case "<=":
559
return LE;
560
case ">":
561
return GT;
562
case ">=":
563
return GE;
564
}
565
566
throw new IllegalArgumentException("Error in security " +
567
"property. " + s + " is not a legal Operator");
568
}
569
}
570
571
/**
572
* Check if an algorithm constraint is permitted with a given key.
573
*
574
* If the check inside of {@code permit()} fails, it must call
575
* {@code next()} with the same {@code Key} parameter passed if
576
* multiple constraints need to be checked.
577
*
578
* @param key Public key
579
* @return 'true' if constraint is allowed, 'false' if disallowed.
580
*/
581
public boolean permits(Key key) {
582
return true;
583
}
584
585
/**
586
* Check if the algorithm constraint permits a given cryptographic
587
* parameters.
588
*
589
* @param parameters the cryptographic parameters
590
* @return 'true' if the cryptographic parameters is allowed,
591
* 'false' ortherwise.
592
*/
593
public boolean permits(AlgorithmParameters parameters) {
594
return true;
595
}
596
597
/**
598
* Check if an algorithm constraint is permitted with a given
599
* ConstraintsParameters.
600
*
601
* If the check inside of {@code permits()} fails, it must call
602
* {@code next()} with the same {@code ConstraintsParameters}
603
* parameter passed if multiple constraints need to be checked.
604
*
605
* @param cp ConstraintsParameter containing certificate info
606
* @throws CertPathValidatorException if constraint disallows.
607
*
608
*/
609
public abstract void permits(ConstraintsParameters cp)
610
throws CertPathValidatorException;
611
612
/**
613
* Recursively check if the constraints are allowed.
614
*
615
* If {@code nextConstraint} is non-null, this method will
616
* call {@code nextConstraint}'s {@code permits()} to check if the
617
* constraint is allowed or denied. If the constraint's
618
* {@code permits()} is allowed, this method will exit this and any
619
* recursive next() calls, returning 'true'. If the constraints called
620
* were disallowed, the last constraint will throw
621
* {@code CertPathValidatorException}.
622
*
623
* @param cp ConstraintsParameters
624
* @return 'true' if constraint allows the operation, 'false' if
625
* we are at the end of the constraint list or,
626
* {@code nextConstraint} is null.
627
*/
628
boolean next(ConstraintsParameters cp)
629
throws CertPathValidatorException {
630
if (nextConstraint != null) {
631
nextConstraint.permits(cp);
632
return true;
633
}
634
return false;
635
}
636
637
/**
638
* Recursively check if this constraint is allowed,
639
*
640
* If {@code nextConstraint} is non-null, this method will
641
* call {@code nextConstraint}'s {@code permit()} to check if the
642
* constraint is allowed or denied. If the constraint's
643
* {@code permit()} is allowed, this method will exit this and any
644
* recursive next() calls, returning 'true'. If the constraints
645
* called were disallowed the check will exit with 'false'.
646
*
647
* @param key Public key
648
* @return 'true' if constraint allows the operation, 'false' if
649
* the constraint denies the operation.
650
*/
651
boolean next(Key key) {
652
return nextConstraint != null && nextConstraint.permits(key);
653
}
654
}
655
656
/*
657
* This class contains constraints dealing with the certificate chain
658
* of the certificate.
659
*/
660
private static class jdkCAConstraint extends Constraint {
661
jdkCAConstraint(String algo) {
662
algorithm = algo;
663
}
664
665
/*
666
* Check if ConstraintsParameters has a trusted match, if it does
667
* call next() for any following constraints. If it does not, exit
668
* as this constraint(s) does not restrict the operation.
669
*/
670
@Override
671
public void permits(ConstraintsParameters cp)
672
throws CertPathValidatorException {
673
if (debug != null) {
674
debug.println("jdkCAConstraints.permits(): " + algorithm);
675
}
676
677
// Check if any certs chain back to at least one trust anchor in
678
// cacerts
679
if (cp.anchorIsJdkCA()) {
680
if (next(cp)) {
681
return;
682
}
683
throw new CertPathValidatorException(
684
"Algorithm constraints check failed on certificate " +
685
"anchor limits. " + algorithm + cp.extendedExceptionMsg(),
686
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
687
}
688
}
689
}
690
691
/*
692
* This class handles the denyAfter constraint. The date is in the UTC/GMT
693
* timezone.
694
*/
695
private static class DenyAfterConstraint extends Constraint {
696
private Date denyAfterDate;
697
698
DenyAfterConstraint(String algo, int year, int month, int day) {
699
Calendar c;
700
701
algorithm = algo;
702
703
if (debug != null) {
704
debug.println("DenyAfterConstraint read in as: year " +
705
year + ", month = " + month + ", day = " + day);
706
}
707
708
c = new Calendar.Builder().setTimeZone(TimeZone.getTimeZone("GMT"))
709
.setDate(year, month - 1, day).build();
710
711
if (year > c.getActualMaximum(Calendar.YEAR) ||
712
year < c.getActualMinimum(Calendar.YEAR)) {
713
throw new IllegalArgumentException(
714
"Invalid year given in constraint: " + year);
715
}
716
if ((month - 1) > c.getActualMaximum(Calendar.MONTH) ||
717
(month - 1) < c.getActualMinimum(Calendar.MONTH)) {
718
throw new IllegalArgumentException(
719
"Invalid month given in constraint: " + month);
720
}
721
if (day > c.getActualMaximum(Calendar.DAY_OF_MONTH) ||
722
day < c.getActualMinimum(Calendar.DAY_OF_MONTH)) {
723
throw new IllegalArgumentException(
724
"Invalid Day of Month given in constraint: " + day);
725
}
726
727
denyAfterDate = c.getTime();
728
if (debug != null) {
729
debug.println("DenyAfterConstraint date set to: " +
730
denyAfterDate);
731
}
732
}
733
734
/*
735
* Checking that the provided date is not beyond the constraint date.
736
* The provided date can be the PKIXParameter date if given,
737
* otherwise it is the current date.
738
*
739
* If the constraint disallows, call next() for any following
740
* constraints. Throw an exception if this is the last constraint.
741
*/
742
@Override
743
public void permits(ConstraintsParameters cp)
744
throws CertPathValidatorException {
745
Date currentDate;
746
String errmsg;
747
748
if (cp.getDate() != null) {
749
currentDate = cp.getDate();
750
} else {
751
currentDate = new Date();
752
}
753
754
if (!denyAfterDate.after(currentDate)) {
755
if (next(cp)) {
756
return;
757
}
758
throw new CertPathValidatorException(
759
"denyAfter constraint check failed: " + algorithm +
760
" used with Constraint date: " +
761
denyAfterDate + "; params date: " +
762
currentDate + cp.extendedExceptionMsg(),
763
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
764
}
765
}
766
767
/*
768
* Return result if the constraint's date is beyond the current date
769
* in UTC timezone.
770
*/
771
@Override
772
public boolean permits(Key key) {
773
if (next(key)) {
774
return true;
775
}
776
if (debug != null) {
777
debug.println("DenyAfterConstraints.permits(): " + algorithm);
778
}
779
780
return denyAfterDate.after(new Date());
781
}
782
}
783
784
/*
785
* The usage constraint is for the "usage" keyword. It checks against the
786
* variant value in ConstraintsParameters.
787
*/
788
private static class UsageConstraint extends Constraint {
789
String[] usages;
790
791
UsageConstraint(String algorithm, String[] usages) {
792
this.algorithm = algorithm;
793
this.usages = usages;
794
}
795
796
@Override
797
public void permits(ConstraintsParameters cp)
798
throws CertPathValidatorException {
799
String variant = cp.getVariant();
800
for (String usage : usages) {
801
802
boolean match = false;
803
switch (usage.toLowerCase()) {
804
case "tlsserver":
805
match = variant.equals(Validator.VAR_TLS_SERVER);
806
break;
807
case "tlsclient":
808
match = variant.equals(Validator.VAR_TLS_CLIENT);
809
break;
810
case "signedjar":
811
match =
812
variant.equals(Validator.VAR_PLUGIN_CODE_SIGNING) ||
813
variant.equals(Validator.VAR_CODE_SIGNING) ||
814
variant.equals(Validator.VAR_TSA_SERVER);
815
break;
816
}
817
818
if (debug != null) {
819
debug.println("Checking if usage constraint \"" + usage +
820
"\" matches \"" + cp.getVariant() + "\"");
821
if (Debug.isVerbose()) {
822
// Because usage checking can come from many places
823
// a stack trace is very helpful.
824
(new Exception()).printStackTrace(debug.getPrintStream());
825
}
826
}
827
if (match) {
828
if (next(cp)) {
829
return;
830
}
831
throw new CertPathValidatorException("Usage constraint " +
832
usage + " check failed: " + algorithm +
833
cp.extendedExceptionMsg(),
834
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
835
}
836
}
837
}
838
}
839
840
/*
841
* This class contains constraints dealing with the key size
842
* support limits per algorithm. e.g. "keySize <= 1024"
843
*/
844
private static class KeySizeConstraint extends Constraint {
845
846
private int minSize; // the minimal available key size
847
private int maxSize; // the maximal available key size
848
private int prohibitedSize = -1; // unavailable key sizes
849
850
public KeySizeConstraint(String algo, Operator operator, int length) {
851
algorithm = algo;
852
switch (operator) {
853
case EQ: // an unavailable key size
854
this.minSize = 0;
855
this.maxSize = Integer.MAX_VALUE;
856
prohibitedSize = length;
857
break;
858
case NE:
859
this.minSize = length;
860
this.maxSize = length;
861
break;
862
case LT:
863
this.minSize = length;
864
this.maxSize = Integer.MAX_VALUE;
865
break;
866
case LE:
867
this.minSize = length + 1;
868
this.maxSize = Integer.MAX_VALUE;
869
break;
870
case GT:
871
this.minSize = 0;
872
this.maxSize = length;
873
break;
874
case GE:
875
this.minSize = 0;
876
this.maxSize = length > 1 ? (length - 1) : 0;
877
break;
878
default:
879
// unlikely to happen
880
this.minSize = Integer.MAX_VALUE;
881
this.maxSize = -1;
882
}
883
}
884
885
/*
886
* For each key, check if each constraint fails and check if there is
887
* a linked constraint. Any permitted constraint will exit the linked
888
* list to allow the operation.
889
*/
890
@Override
891
public void permits(ConstraintsParameters cp)
892
throws CertPathValidatorException {
893
for (Key key : cp.getKeys()) {
894
if (!permitsImpl(key)) {
895
if (nextConstraint != null) {
896
nextConstraint.permits(cp);
897
continue;
898
}
899
throw new CertPathValidatorException(
900
"Algorithm constraints check failed on keysize limits: " +
901
algorithm + " " + KeyUtil.getKeySize(key) + " bit key" +
902
cp.extendedExceptionMsg(),
903
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
904
}
905
}
906
}
907
908
909
// Check if key constraint disable the specified key
910
// Uses old style permit()
911
@Override
912
public boolean permits(Key key) {
913
// If we recursively find a constraint that permits us to use
914
// this key, return true and skip any other constraint checks.
915
if (nextConstraint != null && nextConstraint.permits(key)) {
916
return true;
917
}
918
if (debug != null) {
919
debug.println("KeySizeConstraints.permits(): " + algorithm);
920
}
921
922
return permitsImpl(key);
923
}
924
925
@Override
926
public boolean permits(AlgorithmParameters parameters) {
927
String paramAlg = parameters.getAlgorithm();
928
if (!algorithm.equalsIgnoreCase(parameters.getAlgorithm())) {
929
// Consider the impact of the algorithm aliases.
930
Collection<String> aliases =
931
AlgorithmDecomposer.getAliases(algorithm);
932
if (!aliases.contains(paramAlg)) {
933
return true;
934
}
935
}
936
937
int keySize = KeyUtil.getKeySize(parameters);
938
if (keySize == 0) {
939
return false;
940
} else if (keySize > 0) {
941
return !((keySize < minSize) || (keySize > maxSize) ||
942
(prohibitedSize == keySize));
943
} // Otherwise, the key size is not accessible or determined.
944
// Conservatively, please don't disable such keys.
945
946
return true;
947
}
948
949
private boolean permitsImpl(Key key) {
950
// Verify this constraint is for this public key algorithm
951
if (algorithm.compareToIgnoreCase(key.getAlgorithm()) != 0) {
952
return true;
953
}
954
955
int size = KeyUtil.getKeySize(key);
956
if (size == 0) {
957
return false; // we don't allow any key of size 0.
958
} else if (size > 0) {
959
return !((size < minSize) || (size > maxSize) ||
960
(prohibitedSize == size));
961
} // Otherwise, the key size is not accessible. Conservatively,
962
// please don't disable such keys.
963
964
return true;
965
}
966
}
967
968
private boolean cachedCheckAlgorithm(String algorithm) {
969
Map<String, Boolean> cache;
970
if ((cache = cacheRef.get()) == null) {
971
synchronized (this) {
972
if ((cache = cacheRef.get()) == null) {
973
cache = new ConcurrentHashMap<>();
974
cacheRef = new SoftReference<>(cache);
975
}
976
}
977
}
978
Boolean result = cache.get(algorithm);
979
if (result != null) {
980
return result;
981
}
982
result = checkAlgorithm(disabledAlgorithms, algorithm, decomposer);
983
cache.put(algorithm, result);
984
return result;
985
}
986
987
/*
988
* This constraint is used for the complete disabling of the algorithm.
989
*/
990
private static class DisabledConstraint extends Constraint {
991
DisabledConstraint(String algo) {
992
algorithm = algo;
993
}
994
995
@Override
996
public void permits(ConstraintsParameters cp)
997
throws CertPathValidatorException {
998
throw new CertPathValidatorException(
999
"Algorithm constraints check failed on disabled " +
1000
"algorithm: " + algorithm + cp.extendedExceptionMsg(),
1001
null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
1002
}
1003
1004
@Override
1005
public boolean permits(Key key) {
1006
return false;
1007
}
1008
}
1009
}
1010
1011