23 * questions. |
23 * questions. |
24 */ |
24 */ |
25 |
25 |
26 package sun.security.util; |
26 package sun.security.util; |
27 |
27 |
28 import java.security.AlgorithmConstraints; |
|
29 import java.security.CryptoPrimitive; |
28 import java.security.CryptoPrimitive; |
30 import java.security.AlgorithmParameters; |
29 import java.security.AlgorithmParameters; |
31 |
|
32 import java.security.Key; |
30 import java.security.Key; |
33 import java.security.Security; |
|
34 import java.security.PrivilegedAction; |
|
35 import java.security.AccessController; |
|
36 |
|
37 import java.util.Locale; |
31 import java.util.Locale; |
38 import java.util.Set; |
32 import java.util.Set; |
39 import java.util.Collections; |
33 import java.util.Collections; |
40 import java.util.HashSet; |
34 import java.util.HashSet; |
41 import java.util.Map; |
35 import java.util.Map; |
47 * Algorithm constraints for disabled algorithms property |
41 * Algorithm constraints for disabled algorithms property |
48 * |
42 * |
49 * See the "jdk.certpath.disabledAlgorithms" specification in java.security |
43 * See the "jdk.certpath.disabledAlgorithms" specification in java.security |
50 * for the syntax of the disabled algorithm string. |
44 * for the syntax of the disabled algorithm string. |
51 */ |
45 */ |
52 public class DisabledAlgorithmConstraints implements AlgorithmConstraints { |
46 public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints { |
53 |
47 |
54 // the known security property, jdk.certpath.disabledAlgorithms |
48 // the known security property, jdk.certpath.disabledAlgorithms |
55 public final static String PROPERTY_CERTPATH_DISABLED_ALGS = |
49 public final static String PROPERTY_CERTPATH_DISABLED_ALGS = |
56 "jdk.certpath.disabledAlgorithms"; |
50 "jdk.certpath.disabledAlgorithms"; |
57 |
51 |
62 private final static Map<String, String[]> disabledAlgorithmsMap = |
56 private final static Map<String, String[]> disabledAlgorithmsMap = |
63 new HashMap<>(); |
57 new HashMap<>(); |
64 private final static Map<String, KeySizeConstraints> keySizeConstraintsMap = |
58 private final static Map<String, KeySizeConstraints> keySizeConstraintsMap = |
65 new HashMap<>(); |
59 new HashMap<>(); |
66 |
60 |
67 private String[] disabledAlgorithms; |
61 private final String[] disabledAlgorithms; |
68 private KeySizeConstraints keySizeConstraints; |
62 private final KeySizeConstraints keySizeConstraints; |
69 |
63 |
70 /** |
64 /** |
71 * Initialize algorithm constraints with the specified security property. |
65 * Initialize algorithm constraints with the specified security property. |
72 * |
66 * |
73 * @param propertyName the security property name that define the disabled |
67 * @param propertyName the security property name that define the disabled |
74 * algorithm constraints |
68 * algorithm constraints |
75 */ |
69 */ |
76 public DisabledAlgorithmConstraints(String propertyName) { |
70 public DisabledAlgorithmConstraints(String propertyName) { |
77 // Both disabledAlgorithmsMap and keySizeConstraintsMap are |
71 this(propertyName, new AlgorithmDecomposer()); |
78 // synchronized with the lock of disabledAlgorithmsMap. |
72 } |
79 synchronized (disabledAlgorithmsMap) { |
73 |
80 if(!disabledAlgorithmsMap.containsKey(propertyName)) { |
74 public DisabledAlgorithmConstraints(String propertyName, |
81 loadDisabledAlgorithmsMap(propertyName); |
75 AlgorithmDecomposer decomposer) { |
82 } |
76 super(decomposer); |
83 |
77 disabledAlgorithms = getAlgorithms(disabledAlgorithmsMap, propertyName); |
84 disabledAlgorithms = disabledAlgorithmsMap.get(propertyName); |
78 keySizeConstraints = getKeySizeConstraints(disabledAlgorithms, |
85 keySizeConstraints = keySizeConstraintsMap.get(propertyName); |
79 propertyName); |
86 } |
|
87 } |
80 } |
88 |
81 |
89 @Override |
82 @Override |
90 final public boolean permits(Set<CryptoPrimitive> primitives, |
83 final public boolean permits(Set<CryptoPrimitive> primitives, |
91 String algorithm, AlgorithmParameters parameters) { |
84 String algorithm, AlgorithmParameters parameters) { |
92 |
85 |
93 if (algorithm == null || algorithm.length() == 0) { |
|
94 throw new IllegalArgumentException("No algorithm name specified"); |
|
95 } |
|
96 |
|
97 if (primitives == null || primitives.isEmpty()) { |
86 if (primitives == null || primitives.isEmpty()) { |
98 throw new IllegalArgumentException( |
87 throw new IllegalArgumentException( |
99 "No cryptographic primitive specified"); |
88 "No cryptographic primitive specified"); |
100 } |
89 } |
101 |
90 |
102 Set<String> elements = null; |
91 return checkAlgorithm(disabledAlgorithms, algorithm, decomposer); |
103 for (String disabled : disabledAlgorithms) { |
|
104 if (disabled == null || disabled.isEmpty()) { |
|
105 continue; |
|
106 } |
|
107 |
|
108 // check the full name |
|
109 if (disabled.equalsIgnoreCase(algorithm)) { |
|
110 return false; |
|
111 } |
|
112 |
|
113 // decompose the algorithm into sub-elements |
|
114 if (elements == null) { |
|
115 elements = decomposes(algorithm); |
|
116 } |
|
117 |
|
118 // check the items of the algorithm |
|
119 for (String element : elements) { |
|
120 if (disabled.equalsIgnoreCase(element)) { |
|
121 return false; |
|
122 } |
|
123 } |
|
124 } |
|
125 |
|
126 return true; |
|
127 } |
92 } |
128 |
93 |
129 @Override |
94 @Override |
130 final public boolean permits(Set<CryptoPrimitive> primitives, Key key) { |
95 final public boolean permits(Set<CryptoPrimitive> primitives, Key key) { |
131 return checkConstraints(primitives, "", key, null); |
96 return checkConstraints(primitives, "", key, null); |
138 if (algorithm == null || algorithm.length() == 0) { |
103 if (algorithm == null || algorithm.length() == 0) { |
139 throw new IllegalArgumentException("No algorithm name specified"); |
104 throw new IllegalArgumentException("No algorithm name specified"); |
140 } |
105 } |
141 |
106 |
142 return checkConstraints(primitives, algorithm, key, parameters); |
107 return checkConstraints(primitives, algorithm, key, parameters); |
143 } |
|
144 |
|
145 /** |
|
146 * Decompose the standard algorithm name into sub-elements. |
|
147 * <p> |
|
148 * For example, we need to decompose "SHA1WithRSA" into "SHA1" and "RSA" |
|
149 * so that we can check the "SHA1" and "RSA" algorithm constraints |
|
150 * separately. |
|
151 * <p> |
|
152 * Please override the method if need to support more name pattern. |
|
153 */ |
|
154 protected Set<String> decomposes(String algorithm) { |
|
155 if (algorithm == null || algorithm.length() == 0) { |
|
156 return new HashSet<String>(); |
|
157 } |
|
158 |
|
159 // algorithm/mode/padding |
|
160 Pattern transPattern = Pattern.compile("/"); |
|
161 String[] transTockens = transPattern.split(algorithm); |
|
162 |
|
163 Set<String> elements = new HashSet<String>(); |
|
164 for (String transTocken : transTockens) { |
|
165 if (transTocken == null || transTocken.length() == 0) { |
|
166 continue; |
|
167 } |
|
168 |
|
169 // PBEWith<digest>And<encryption> |
|
170 // PBEWith<prf>And<encryption> |
|
171 // OAEPWith<digest>And<mgf>Padding |
|
172 // <digest>with<encryption> |
|
173 // <digest>with<encryption>and<mgf> |
|
174 // <digest>with<encryption>in<format> |
|
175 Pattern pattern = |
|
176 Pattern.compile("with|and|in", Pattern.CASE_INSENSITIVE); |
|
177 String[] tokens = pattern.split(transTocken); |
|
178 |
|
179 for (String token : tokens) { |
|
180 if (token == null || token.length() == 0) { |
|
181 continue; |
|
182 } |
|
183 |
|
184 elements.add(token); |
|
185 } |
|
186 } |
|
187 |
|
188 // In Java standard algorithm name specification, for different |
|
189 // purpose, the SHA-1 and SHA-2 algorithm names are different. For |
|
190 // example, for MessageDigest, the standard name is "SHA-256", while |
|
191 // for Signature, the digest algorithm component is "SHA256" for |
|
192 // signature algorithm "SHA256withRSA". So we need to check both |
|
193 // "SHA-256" and "SHA256" to make the right constraint checking. |
|
194 |
|
195 // handle special name: SHA-1 and SHA1 |
|
196 if (elements.contains("SHA1") && !elements.contains("SHA-1")) { |
|
197 elements.add("SHA-1"); |
|
198 } |
|
199 if (elements.contains("SHA-1") && !elements.contains("SHA1")) { |
|
200 elements.add("SHA1"); |
|
201 } |
|
202 |
|
203 // handle special name: SHA-224 and SHA224 |
|
204 if (elements.contains("SHA224") && !elements.contains("SHA-224")) { |
|
205 elements.add("SHA-224"); |
|
206 } |
|
207 if (elements.contains("SHA-224") && !elements.contains("SHA224")) { |
|
208 elements.add("SHA224"); |
|
209 } |
|
210 |
|
211 // handle special name: SHA-256 and SHA256 |
|
212 if (elements.contains("SHA256") && !elements.contains("SHA-256")) { |
|
213 elements.add("SHA-256"); |
|
214 } |
|
215 if (elements.contains("SHA-256") && !elements.contains("SHA256")) { |
|
216 elements.add("SHA256"); |
|
217 } |
|
218 |
|
219 // handle special name: SHA-384 and SHA384 |
|
220 if (elements.contains("SHA384") && !elements.contains("SHA-384")) { |
|
221 elements.add("SHA-384"); |
|
222 } |
|
223 if (elements.contains("SHA-384") && !elements.contains("SHA384")) { |
|
224 elements.add("SHA384"); |
|
225 } |
|
226 |
|
227 // handle special name: SHA-512 and SHA512 |
|
228 if (elements.contains("SHA512") && !elements.contains("SHA-512")) { |
|
229 elements.add("SHA-512"); |
|
230 } |
|
231 if (elements.contains("SHA-512") && !elements.contains("SHA512")) { |
|
232 elements.add("SHA512"); |
|
233 } |
|
234 |
|
235 return elements; |
|
236 } |
108 } |
237 |
109 |
238 // Check algorithm constraints |
110 // Check algorithm constraints |
239 private boolean checkConstraints(Set<CryptoPrimitive> primitives, |
111 private boolean checkConstraints(Set<CryptoPrimitive> primitives, |
240 String algorithm, Key key, AlgorithmParameters parameters) { |
112 String algorithm, Key key, AlgorithmParameters parameters) { |
262 } |
134 } |
263 |
135 |
264 return true; |
136 return true; |
265 } |
137 } |
266 |
138 |
267 // Get disabled algorithm constraints from the specified security property. |
139 private static KeySizeConstraints getKeySizeConstraints( |
268 private static void loadDisabledAlgorithmsMap( |
140 String[] disabledAlgorithms, String propertyName) { |
269 final String propertyName) { |
141 synchronized (keySizeConstraintsMap) { |
270 |
142 if(!keySizeConstraintsMap.containsKey(propertyName)) { |
271 String property = AccessController.doPrivileged( |
143 // map the key constraints |
272 new PrivilegedAction<String>() { |
144 KeySizeConstraints keySizeConstraints = |
273 public String run() { |
145 new KeySizeConstraints(disabledAlgorithms); |
274 return Security.getProperty(propertyName); |
146 keySizeConstraintsMap.put(propertyName, keySizeConstraints); |
275 } |
147 } |
276 }); |
148 |
277 |
149 return keySizeConstraintsMap.get(propertyName); |
278 String[] algorithmsInProperty = null; |
150 } |
279 |
|
280 if (property != null && !property.isEmpty()) { |
|
281 |
|
282 // remove double quote marks from beginning/end of the property |
|
283 if (property.charAt(0) == '"' && |
|
284 property.charAt(property.length() - 1) == '"') { |
|
285 property = property.substring(1, property.length() - 1); |
|
286 } |
|
287 |
|
288 algorithmsInProperty = property.split(","); |
|
289 for (int i = 0; i < algorithmsInProperty.length; i++) { |
|
290 algorithmsInProperty[i] = algorithmsInProperty[i].trim(); |
|
291 } |
|
292 } |
|
293 |
|
294 // map the disabled algorithms |
|
295 if (algorithmsInProperty == null) { |
|
296 algorithmsInProperty = new String[0]; |
|
297 } |
|
298 disabledAlgorithmsMap.put(propertyName, algorithmsInProperty); |
|
299 |
|
300 // map the key constraints |
|
301 KeySizeConstraints keySizeConstraints = |
|
302 new KeySizeConstraints(algorithmsInProperty); |
|
303 keySizeConstraintsMap.put(propertyName, keySizeConstraints); |
|
304 } |
151 } |
305 |
152 |
306 /** |
153 /** |
307 * key constraints |
154 * key constraints |
308 */ |
155 */ |