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+
26+package sun.security.util;
27+
28+import java.security.AlgorithmConstraints;
29+import java.security.CryptoPrimitive;
30+import java.security.AlgorithmParameters;
31+
32+import java.security.Key;
33+import java.security.Security;
34+import java.security.PrivilegedAction;
35+import java.security.AccessController;
36+import java.security.interfaces.ECKey;
37+import java.security.interfaces.RSAKey;
38+import java.security.interfaces.DSAKey;
39+import javax.crypto.SecretKey;
40+import javax.crypto.interfaces.DHKey;
41+
42+import java.util.Locale;
43+import java.util.Set;
44+import java.util.Collections;
45+import java.util.HashSet;
46+import java.util.Map;
47+import java.util.HashMap;
48+import java.util.regex.Pattern;
49+import 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+ */
57+public 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+