History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/util/DisabledAlgorithmConstraints.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/security/util/DisabledAlgorithmConstraints.java+486−0
@@ -0,0 +1,486 @@
1/*
2 * Copyright (c) 2010, 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
26package sun.security.util;
27
28import java.security.AlgorithmConstraints;
29import java.security.CryptoPrimitive;
30import java.security.AlgorithmParameters;
31
32import java.security.Key;
33import java.security.Security;
34import java.security.PrivilegedAction;
35import java.security.AccessController;
36import java.security.interfaces.ECKey;
37import java.security.interfaces.RSAKey;
38import java.security.interfaces.DSAKey;
39import javax.crypto.SecretKey;
40import javax.crypto.interfaces.DHKey;
41
42import java.util.Locale;
43import java.util.Set;
44import java.util.Collections;
45import java.util.HashSet;
46import java.util.Map;
47import java.util.HashMap;
48import java.util.regex.Pattern;
49import java.util.regex.Matcher;
50
51/**
52 * Algorithm constraints for disabled algorithms property
53 *
54 * See the "jdk.certpath.disabledAlgorithms" specification in java.security
55 * for the syntax of the disabled algorithm string.
56 */
57public class DisabledAlgorithmConstraints implements AlgorithmConstraints {
58
59 // the known security property, jdk.certpath.disabledAlgorithms
60 public final static String PROPERTY_CERTPATH_DISABLED_ALGS =
61 "jdk.certpath.disabledAlgorithms";
62
63 // the known security property, jdk.tls.disabledAlgorithms
64 public final static String PROPERTY_TLS_DISABLED_ALGS =
65 "jdk.tls.disabledAlgorithms";
66
67 private static Map<String, String[]> disabledAlgorithmsMap =
68 Collections.synchronizedMap(new HashMap<String, String[]>());
69 private static Map<String, KeySizeConstraints> keySizeConstraintsMap =
70 Collections.synchronizedMap(new HashMap<String, KeySizeConstraints>());
71
72 private String[] disabledAlgorithms;
73 private KeySizeConstraints keySizeConstraints;
74
75 /**
76 * Initialize algorithm constraints with the specified security property.
77 *
78 * @param propertyName the security property name that define the disabled
79 * algorithm constraints
80 */
81 public DisabledAlgorithmConstraints(String propertyName) {
82 synchronized (disabledAlgorithmsMap) {
83 if(!disabledAlgorithmsMap.containsKey(propertyName)) {
84 loadDisabledAlgorithmsMap(propertyName);
85 }
86
87 disabledAlgorithms = disabledAlgorithmsMap.get(propertyName);
88 keySizeConstraints = keySizeConstraintsMap.get(propertyName);
89 }
90 }
91
92 @Override
93 final public boolean permits(Set<CryptoPrimitive> primitives,
94 String algorithm, AlgorithmParameters parameters) {
95
96 if (algorithm == null || algorithm.length() == 0) {
97 throw new IllegalArgumentException("No algorithm name specified");
98 }
99
100 if (primitives == null || primitives.isEmpty()) {
101 throw new IllegalArgumentException(
102 "No cryptographic primitive specified");
103 }
104
105 Set<String> elements = null;
106 for (String disabled : disabledAlgorithms) {
107 if (disabled == null || disabled.isEmpty()) {
108 continue;
109 }
110
111 // check the full name
112 if (disabled.equalsIgnoreCase(algorithm)) {
113 return false;
114 }
115
116 // decompose the algorithm into sub-elements
117 if (elements == null) {
118 elements = decomposes(algorithm);
119 }
120
121 // check the items of the algorithm
122 for (String element : elements) {
123 if (disabled.equalsIgnoreCase(element)) {
124 return false;
125 }
126 }
127 }
128
129 return true;
130 }
131
132 @Override
133 final public boolean permits(Set<CryptoPrimitive> primitives, Key key) {
134 return checkConstraints(primitives, "", key, null);
135 }
136
137 @Override
138 final public boolean permits(Set<CryptoPrimitive> primitives,
139 String algorithm, Key key, AlgorithmParameters parameters) {
140
141 if (algorithm == null || algorithm.length() == 0) {
142 throw new IllegalArgumentException("No algorithm name specified");
143 }
144
145 return checkConstraints(primitives, algorithm, key, parameters);
146 }
147
148 /**
149 * Decompose the standard algorithm name into sub-elements.
150 * <p>
151 * For example, we need to decompose "SHA1WithRSA" into "SHA1" and "RSA"
152 * so that we can check the "SHA1" and "RSA" algorithm constraints
153 * separately.
154 * <p>
155 * Please override the method if need to support more name pattern.
156 */
157 protected Set<String> decomposes(String algorithm) {
158 if (algorithm == null || algorithm.length() == 0) {
159 return new HashSet<String>();
160 }
161
162 // algorithm/mode/padding
163 Pattern transPattern = Pattern.compile("/");
164 String[] transTockens = transPattern.split(algorithm);
165
166 Set<String> elements = new HashSet<String>();
167 for (String transTocken : transTockens) {
168 if (transTocken == null || transTocken.length() == 0) {
169 continue;
170 }
171
172 // PBEWith<digest>And<encryption>
173 // PBEWith<prf>And<encryption>
174 // OAEPWith<digest>And<mgf>Padding
175 // <digest>with<encryption>
176 // <digest>with<encryption>and<mgf>
177 Pattern pattern =
178 Pattern.compile("with|and", Pattern.CASE_INSENSITIVE);
179 String[] tokens = pattern.split(transTocken);
180
181 for (String token : tokens) {
182 if (token == null || token.length() == 0) {
183 continue;
184 }
185
186 elements.add(token);
187 }
188 }
189
190 // In Java standard algorithm name specification, for different
191 // purpose, the SHA-1 and SHA-2 algorithm names are different. For
192 // example, for MessageDigest, the standard name is "SHA-256", while
193 // for Signature, the digest algorithm component is "SHA256" for
194 // signature algorithm "SHA256withRSA". So we need to check both
195 // "SHA-256" and "SHA256" to make the right constraint checking.
196
197 // handle special name: SHA-1 and SHA1
198 if (elements.contains("SHA1") && !elements.contains("SHA-1")) {
199 elements.add("SHA-1");
200 }
201 if (elements.contains("SHA-1") && !elements.contains("SHA1")) {
202 elements.add("SHA1");
203 }
204
205 // handle special name: SHA-224 and SHA224
206 if (elements.contains("SHA224") && !elements.contains("SHA-224")) {
207 elements.add("SHA-224");
208 }
209 if (elements.contains("SHA-224") && !elements.contains("SHA224")) {
210 elements.add("SHA224");
211 }
212
213 // handle special name: SHA-256 and SHA256
214 if (elements.contains("SHA256") && !elements.contains("SHA-256")) {
215 elements.add("SHA-256");
216 }
217 if (elements.contains("SHA-256") && !elements.contains("SHA256")) {
218 elements.add("SHA256");
219 }
220
221 // handle special name: SHA-384 and SHA384
222 if (elements.contains("SHA384") && !elements.contains("SHA-384")) {
223 elements.add("SHA-384");
224 }
225 if (elements.contains("SHA-384") && !elements.contains("SHA384")) {
226 elements.add("SHA384");
227 }
228
229 // handle special name: SHA-512 and SHA512
230 if (elements.contains("SHA512") && !elements.contains("SHA-512")) {
231 elements.add("SHA-512");
232 }
233 if (elements.contains("SHA-512") && !elements.contains("SHA512")) {
234 elements.add("SHA512");
235 }
236
237 return elements;
238 }
239
240 // Check algorithm constraints
241 private boolean checkConstraints(Set<CryptoPrimitive> primitives,
242 String algorithm, Key key, AlgorithmParameters parameters) {
243
244 // check the key parameter, it cannot be null.
245 if (key == null) {
246 throw new IllegalArgumentException("The key cannot be null");
247 }
248
249 // check the target algorithm
250 if (algorithm != null && algorithm.length() != 0) {
251 if (!permits(primitives, algorithm, parameters)) {
252 return false;
253 }
254 }
255
256 // check the key algorithm
257 if (!permits(primitives, key.getAlgorithm(), null)) {
258 return false;
259 }
260
261 // check the key constraints
262 if (keySizeConstraints.disables(key)) {
263 return false;
264 }
265
266 return true;
267 }
268
269 // Get disabled algorithm constraints from the specified security property.
270 private static void loadDisabledAlgorithmsMap(
271 final String propertyName) {
272
273 String property = AccessController.doPrivileged(
274 new PrivilegedAction<String>() {
275 public String run() {
276 return Security.getProperty(propertyName);
277 }
278 });
279
280 String[] algorithmsInProperty = null;
281
282 if (property != null && !property.isEmpty()) {
283
284 // remove double quote marks from beginning/end of the property
285 if (property.charAt(0) == '"' &&
286 property.charAt(property.length() - 1) == '"') {
287 property = property.substring(1, property.length() - 1);
288 }
289
290 algorithmsInProperty = property.split(",");
291 for (int i = 0; i < algorithmsInProperty.length; i++) {
292 algorithmsInProperty[i] = algorithmsInProperty[i].trim();
293 }
294 }
295
296 // map the disabled algorithms
297 if (algorithmsInProperty == null) {
298 algorithmsInProperty = new String[0];
299 }
300 disabledAlgorithmsMap.put(propertyName, algorithmsInProperty);
301
302 // map the key constraints
303 KeySizeConstraints keySizeConstraints =
304 new KeySizeConstraints(algorithmsInProperty);
305 keySizeConstraintsMap.put(propertyName, keySizeConstraints);
306 }
307
308 /**
309 * key constraints
310 */
311 private static class KeySizeConstraints {
312 private static final Pattern pattern = Pattern.compile(
313 "(\\S+)\\s+keySize\\s*(<=|<|==|!=|>|>=)\\s*(\\d+)");
314
315 private Map<String, Set<KeySizeConstraint>> constraintsMap =
316 Collections.synchronizedMap(
317 new HashMap<String, Set<KeySizeConstraint>>());
318
319 public KeySizeConstraints(String[] restrictions) {
320 for (String restriction : restrictions) {
321 if (restriction == null || restriction.isEmpty()) {
322 continue;
323 }
324
325 Matcher matcher = pattern.matcher(restriction);
326 if (matcher.matches()) {
327 String algorithm = matcher.group(1);
328
329 KeySizeConstraint.Operator operator =
330 KeySizeConstraint.Operator.of(matcher.group(2));
331 int length = Integer.parseInt(matcher.group(3));
332
333 algorithm = algorithm.toLowerCase(Locale.ENGLISH);
334
335 synchronized (constraintsMap) {
336 if (!constraintsMap.containsKey(algorithm)) {
337 constraintsMap.put(algorithm,
338 new HashSet<KeySizeConstraint>());
339 }
340
341 Set<KeySizeConstraint> constraintSet =
342 constraintsMap.get(algorithm);
343 KeySizeConstraint constraint =
344 new KeySizeConstraint(operator, length);
345 constraintSet.add(constraint);
346 }
347 }
348 }
349 }
350
351 // Does this KeySizeConstraints disable the specified key?
352 public boolean disables(Key key) {
353 String algorithm = key.getAlgorithm().toLowerCase(Locale.ENGLISH);
354 synchronized (constraintsMap) {
355 if (constraintsMap.containsKey(algorithm)) {
356 Set<KeySizeConstraint> constraintSet =
357 constraintsMap.get(algorithm);
358 for (KeySizeConstraint constraint : constraintSet) {
359 if (constraint.disables(key)) {
360 return true;
361 }
362 }
363 }
364 }
365
366 return false;
367 }
368 }
369
370 /**
371 * Key size constraint.
372 *
373 * e.g. "keysize <= 1024"
374 */
375 private static class KeySizeConstraint {
376 // operator
377 static enum Operator {
378 EQ, // "=="
379 NE, // "!="
380 LT, // "<"
381 LE, // "<="
382 GT, // ">"
383 GE; // ">="
384
385 static Operator of(String s) {
386 switch (s) {
387 case "==":
388 return EQ;
389 case "!=":
390 return NE;
391 case "<":
392 return LT;
393 case "<=":
394 return LE;
395 case ">":
396 return GT;
397 case ">=":
398 return GE;
399 }
400
401 throw new IllegalArgumentException(
402 s + " is not a legal Operator");
403 }
404 }
405
406 private int minSize; // the minimal available key size
407 private int maxSize; // the maximal available key size
408 private int prohibitedSize = -1; // unavailable key sizes
409
410 public KeySizeConstraint(Operator operator, int length) {
411 switch (operator) {
412 case EQ: // an unavailable key size
413 this.minSize = 0;
414 this.maxSize = Integer.MAX_VALUE;
415 prohibitedSize = length;
416 break;
417 case NE:
418 this.minSize = length;
419 this.maxSize = length;
420 break;
421 case LT:
422 this.minSize = length;
423 this.maxSize = Integer.MAX_VALUE;
424 break;
425 case LE:
426 this.minSize = length + 1;
427 this.maxSize = Integer.MAX_VALUE;
428 break;
429 case GT:
430 this.minSize = 0;
431 this.maxSize = length;
432 break;
433 case GE:
434 this.minSize = 0;
435 this.maxSize = length > 1 ? (length - 1) : 0;
436 break;
437 default:
438 // unlikely to happen
439 this.minSize = Integer.MAX_VALUE;
440 this.maxSize = -1;
441 }
442 }
443
444 // Does this key constraint disable the specified key?
445 public boolean disables(Key key) {
446 int size = -1;
447
448 // it is a SecretKey
449 if (key instanceof SecretKey) {
450 SecretKey sk = (SecretKey)key;
451 if (sk.getFormat().equals("RAW") && sk.getEncoded() != null) {
452 size = sk.getEncoded().length * 8;
453
454 }
455 }
456
457 // it is an asymmetric key
458 if (key instanceof RSAKey) {
459 RSAKey pubk = (RSAKey)key;
460 size = pubk.getModulus().bitLength();
461 } else if (key instanceof ECKey) {
462 ECKey pubk = (ECKey)key;
463 size = pubk.getParams().getOrder().bitLength();
464 } else if (key instanceof DSAKey) {
465 DSAKey pubk = (DSAKey)key;
466 size = pubk.getParams().getP().bitLength();
467 } else if (key instanceof DHKey) {
468 DHKey pubk = (DHKey)key;
469 size = pubk.getParams().getP().bitLength();
470 } // else, it is not a key we know.
471
472 if (size == 0) {
473 return true; // we don't allow any key of size 0.
474 }
475
476 if (size >= 0) {
477 return ((size < minSize) || (size > maxSize) ||
478 (prohibitedSize == size));
479 }
480
481 return false;
482 }
483 }
484
485}
486