1 /*
2 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
3 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
4 *
5 *
6 *
7 *
8 *
9 *
10 *
11 *
12 *
13 *
14 *
15 *
16 *
17 *
18 *
19 *
20 *
21 *
22 *
23 *
24 */
25
26 package java.security;
27
28 import java.lang.reflect.*;
29 import java.util.*;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.io.*;
32 import java.net.URL;
33 import sun.security.util.Debug;
34 import sun.security.util.PropertyExpander;
35
36 import sun.security.jca.*;
37
38 /**
39 * <p>This class centralizes all security properties and common security
40 * methods. One of its primary uses is to manage providers.
41 *
42 * <p>The default values of security properties are read from an
43 * implementation-specific location, which is typically the properties file
44 * {@code lib/security/java.security} in the Java installation directory.
45 *
46 * @author Benjamin Renaud
47 */
48
49 public final class Security {
50
51 /* Are we debugging? -- for developers */
52 private static final Debug sdebug =
53 Debug.getInstance("properties");
54
55 /* The java.security properties */
56 private static Properties props;
57
58 // An element in the cache
59 private static class ProviderProperty {
60 String className;
61 Provider provider;
62 }
63
64 static {
65 // doPrivileged here because there are multiple
66 // things in initialize that might require privs.
67 // (the FileInputStream call and the File.exists call,
68 // the securityPropFile call, etc)
69 AccessController.doPrivileged(new PrivilegedAction<Void>() {
70 public Void run() {
71 initialize();
72 return null;
73 }
74 });
75 }
76
77 private static void initialize() {
78 props = new Properties();
79 boolean loadedProps = false;
80 boolean overrideAll = false;
81
82 // first load the system properties file
83 // to determine the value of security.overridePropertiesFile
84 File propFile = securityPropFile("java.security");
85 if (propFile.exists()) {
86 InputStream is = null;
87 try {
88 FileInputStream fis = new FileInputStream(propFile);
89 is = new BufferedInputStream(fis);
90 props.load(is);
91 loadedProps = true;
92
93 if (sdebug != null) {
94 sdebug.println("reading security properties file: " +
95 propFile);
96 }
97 } catch (IOException e) {
98 if (sdebug != null) {
99 sdebug.println("unable to load security properties from " +
100 propFile);
101 e.printStackTrace();
102 }
103 } finally {
104 if (is != null) {
105 try {
106 is.close();
107 } catch (IOException ioe) {
108 if (sdebug != null) {
109 sdebug.println("unable to close input stream");
110 }
111 }
112 }
113 }
114 }
115
116 if ("true".equalsIgnoreCase(props.getProperty
117 ("security.overridePropertiesFile"))) {
118
119 String extraPropFile = System.getProperty
120 ("java.security.properties");
121 if (extraPropFile != null && extraPropFile.startsWith("=")) {
122 overrideAll = true;
123 extraPropFile = extraPropFile.substring(1);
124 }
125
126 if (overrideAll) {
127 props = new Properties();
128 if (sdebug != null) {
129 sdebug.println
130 ("overriding other security properties files!");
131 }
132 }
133
134 // now load the user-specified file so its values
135 // will win if they conflict with the earlier values
136 if (extraPropFile != null) {
137 BufferedInputStream bis = null;
138 try {
139 URL propURL;
140
141 extraPropFile = PropertyExpander.expand(extraPropFile);
142 propFile = new File(extraPropFile);
143 if (propFile.exists()) {
144 propURL = new URL
145 ("file:" + propFile.getCanonicalPath());
146 } else {
147 propURL = new URL(extraPropFile);
148 }
149 bis = new BufferedInputStream(propURL.openStream());
150 props.load(bis);
151 loadedProps = true;
152
153 if (sdebug != null) {
154 sdebug.println("reading security properties file: " +
155 propURL);
156 if (overrideAll) {
157 sdebug.println
158 ("overriding other security properties files!");
159 }
160 }
161 } catch (Exception e) {
162 if (sdebug != null) {
163 sdebug.println
164 ("unable to load security properties from " +
165 extraPropFile);
166 e.printStackTrace();
167 }
168 } finally {
169 if (bis != null) {
170 try {
171 bis.close();
172 } catch (IOException ioe) {
173 if (sdebug != null) {
174 sdebug.println("unable to close input stream");
175 }
176 }
177 }
178 }
179 }
180 }
181
182 if (!loadedProps) {
183 initializeStatic();
184 if (sdebug != null) {
185 sdebug.println("unable to load security properties " +
186 "-- using defaults");
187 }
188 }
189
190 }
191
192 /*
193 * Initialize to default values, if <java.home>/lib/java.security
194 * is not found.
195 */
196 private static void initializeStatic() {
197 props.put("security.provider.1", "sun.security.provider.Sun");
198 props.put("security.provider.2", "sun.security.rsa.SunRsaSign");
199 props.put("security.provider.3", "com.sun.net.ssl.internal.ssl.Provider");
200 props.put("security.provider.4", "com.sun.crypto.provider.SunJCE");
201 props.put("security.provider.5", "sun.security.jgss.SunProvider");
202 props.put("security.provider.6", "com.sun.security.sasl.Provider");
203 }
204
205 /**
206 * Don't let anyone instantiate this.
207 */
208 private Security() {
209 }
210
211 private static File securityPropFile(String filename) {
212 // maybe check for a system property which will specify where to
213 // look. Someday.
214 String sep = File.separator;
215 return new File(System.getProperty("java.home") + sep + "lib" + sep +
216 "security" + sep + filename);
217 }
218
219 /**
220 * Looks up providers, and returns the property (and its associated
221 * provider) mapping the key, if any.
222 * The order in which the providers are looked up is the
223 * provider-preference order, as specificed in the security
224 * properties file.
225 */
226 private static ProviderProperty getProviderProperty(String key) {
227 ProviderProperty entry = null;
228
229 List<Provider> providers = Providers.getProviderList().providers();
230 for (int i = 0; i < providers.size(); i++) {
231
232 String matchKey = null;
233 Provider prov = providers.get(i);
234 String prop = prov.getProperty(key);
235
236 if (prop == null) {
237 // Is there a match if we do a case-insensitive property name
238 // comparison? Let's try ...
239 for (Enumeration<Object> e = prov.keys();
240 e.hasMoreElements() && prop == null; ) {
241 matchKey = (String)e.nextElement();
242 if (key.equalsIgnoreCase(matchKey)) {
243 prop = prov.getProperty(matchKey);
244 break;
245 }
246 }
247 }
248
249 if (prop != null) {
250 ProviderProperty newEntry = new ProviderProperty();
251 newEntry.className = prop;
252 newEntry.provider = prov;
253 return newEntry;
254 }
255 }
256
257 return entry;
258 }
259
260 /**
261 * Returns the property (if any) mapping the key for the given provider.
262 */
263 private static String getProviderProperty(String key, Provider provider) {
264 String prop = provider.getProperty(key);
265 if (prop == null) {
266 // Is there a match if we do a case-insensitive property name
267 // comparison? Let's try ...
268 for (Enumeration<Object> e = provider.keys();
269 e.hasMoreElements() && prop == null; ) {
270 String matchKey = (String)e.nextElement();
271 if (key.equalsIgnoreCase(matchKey)) {
272 prop = provider.getProperty(matchKey);
273 break;
274 }
275 }
276 }
277 return prop;
278 }
279
280 /**
281 * Gets a specified property for an algorithm. The algorithm name
282 * should be a standard name. See the <a href=
283 * "{@docRoot}/../technotes/guides/security/StandardNames.html">
284 * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
285 * for information about standard algorithm names.
286 *
287 * One possible use is by specialized algorithm parsers, which may map
288 * classes to algorithms which they understand (much like Key parsers
289 * do).
290 *
291 * @param algName the algorithm name.
292 *
293 * @param propName the name of the property to get.
294 *
295 * @return the value of the specified property.
296 *
297 * @deprecated This method used to return the value of a proprietary
298 * property in the master file of the "SUN" Cryptographic Service
299 * Provider in order to determine how to parse algorithm-specific
300 * parameters. Use the new provider-based and algorithm-independent
301 * {@code AlgorithmParameters} and {@code KeyFactory} engine
302 * classes (introduced in the J2SE version 1.2 platform) instead.
303 */
304 @Deprecated
305 public static String getAlgorithmProperty(String algName,
306 String propName) {
307 ProviderProperty entry = getProviderProperty("Alg." + propName
308 + "." + algName);
309 if (entry != null) {
310 return entry.className;
311 } else {
312 return null;
313 }
314 }
315
316 /**
317 * Adds a new provider, at a specified position. The position is
318 * the preference order in which providers are searched for
319 * requested algorithms. The position is 1-based, that is,
320 * 1 is most preferred, followed by 2, and so on.
321 *
322 * <p>If the given provider is installed at the requested position,
323 * the provider that used to be at that position, and all providers
324 * with a position greater than {@code position}, are shifted up
325 * one position (towards the end of the list of installed providers).
326 *
327 * <p>A provider cannot be added if it is already installed.
328 *
329 * <p>If there is a security manager, the
330 * {@link java.lang.SecurityManager#checkSecurityAccess} method is called
331 * with the {@code "insertProvider"} permission target name to see if
332 * it's ok to add a new provider. If this permission check is denied,
333 * {@code checkSecurityAccess} is called again with the
334 * {@code "insertProvider."+provider.getName()} permission target name. If
335 * both checks are denied, a {@code SecurityException} is thrown.
336 *
337 * @param provider the provider to be added.
338 *
339 * @param position the preference position that the caller would
340 * like for this provider.
341 *
342 * @return the actual preference position in which the provider was
343 * added, or -1 if the provider was not added because it is
344 * already installed.
345 *
346 * @throws NullPointerException if provider is null
347 * @throws SecurityException
348 * if a security manager exists and its {@link
349 * java.lang.SecurityManager#checkSecurityAccess} method
350 * denies access to add a new provider
351 *
352 * @see #getProvider
353 * @see #removeProvider
354 * @see java.security.SecurityPermission
355 */
356 public static synchronized int insertProviderAt(Provider provider,
357 int position) {
358 String providerName = provider.getName();
359 checkInsertProvider(providerName);
360 ProviderList list = Providers.getFullProviderList();
361 ProviderList newList = ProviderList.insertAt(list, provider, position - 1);
362 if (list == newList) {
363 return -1;
364 }
365 Providers.setProviderList(newList);
366 return newList.getIndex(providerName) + 1;
367 }
368
369 /**
370 * Adds a provider to the next position available.
371 *
372 * <p>If there is a security manager, the
373 * {@link java.lang.SecurityManager#checkSecurityAccess} method is called
374 * with the {@code "insertProvider"} permission target name to see if
375 * it's ok to add a new provider. If this permission check is denied,
376 * {@code checkSecurityAccess} is called again with the
377 * {@code "insertProvider."+provider.getName()} permission target name. If
378 * both checks are denied, a {@code SecurityException} is thrown.
379 *
380 * @param provider the provider to be added.
381 *
382 * @return the preference position in which the provider was
383 * added, or -1 if the provider was not added because it is
384 * already installed.
385 *
386 * @throws NullPointerException if provider is null
387 * @throws SecurityException
388 * if a security manager exists and its {@link
389 * java.lang.SecurityManager#checkSecurityAccess} method
390 * denies access to add a new provider
391 *
392 * @see #getProvider
393 * @see #removeProvider
394 * @see java.security.SecurityPermission
395 */
396 public static int addProvider(Provider provider) {
397 /*
398 * We can't assign a position here because the statically
399 * registered providers may not have been installed yet.
400 * insertProviderAt() will fix that value after it has
401 * loaded the static providers.
402 */
403 return insertProviderAt(provider, 0);
404 }
405
406 /**
407 * Removes the provider with the specified name.
408 *
409 * <p>When the specified provider is removed, all providers located
410 * at a position greater than where the specified provider was are shifted
411 * down one position (towards the head of the list of installed
412 * providers).
413 *
414 * <p>This method returns silently if the provider is not installed or
415 * if name is null.
416 *
417 * <p>First, if there is a security manager, its
418 * {@code checkSecurityAccess}
419 * method is called with the string {@code "removeProvider."+name}
420 * to see if it's ok to remove the provider.
421 * If the default implementation of {@code checkSecurityAccess}
422 * is used (i.e., that method is not overriden), then this will result in
423 * a call to the security manager's {@code checkPermission} method
424 * with a {@code SecurityPermission("removeProvider."+name)}
425 * permission.
426 *
427 * @param name the name of the provider to remove.
428 *
429 * @throws SecurityException
430 * if a security manager exists and its {@link
431 * java.lang.SecurityManager#checkSecurityAccess} method
432 * denies
433 * access to remove the provider
434 *
435 * @see #getProvider
436 * @see #addProvider
437 */
438 public static synchronized void removeProvider(String name) {
439 check("removeProvider." + name);
440 ProviderList list = Providers.getFullProviderList();
441 ProviderList newList = ProviderList.remove(list, name);
442 Providers.setProviderList(newList);
443 }
444
445 /**
446 * Returns an array containing all the installed providers. The order of
447 * the providers in the array is their preference order.
448 *
449 * @return an array of all the installed providers.
450 */
451 public static Provider[] getProviders() {
452 return Providers.getFullProviderList().toArray();
453 }
454
455 /**
456 * Returns the provider installed with the specified name, if
457 * any. Returns null if no provider with the specified name is
458 * installed or if name is null.
459 *
460 * @param name the name of the provider to get.
461 *
462 * @return the provider of the specified name.
463 *
464 * @see #removeProvider
465 * @see #addProvider
466 */
467 public static Provider getProvider(String name) {
468 return Providers.getProviderList().getProvider(name);
469 }
470
471 /**
472 * Returns an array containing all installed providers that satisfy the
473 * specified selection criterion, or null if no such providers have been
474 * installed. The returned providers are ordered
475 * according to their
476 * {@linkplain #insertProviderAt(java.security.Provider, int) preference order}.
477 *
478 * <p> A cryptographic service is always associated with a particular
479 * algorithm or type. For example, a digital signature service is
480 * always associated with a particular algorithm (e.g., DSA),
481 * and a CertificateFactory service is always associated with
482 * a particular certificate type (e.g., X.509).
483 *
484 * <p>The selection criterion must be specified in one of the following two
485 * formats:
486 * <ul>
487 * <li> <i>{@literal <crypto_service>.<algorithm_or_type>}</i>
488 * <p> The cryptographic service name must not contain any dots.
489 * <p> A
490 * provider satisfies the specified selection criterion iff the provider
491 * implements the
492 * specified algorithm or type for the specified cryptographic service.
493 * <p> For example, "CertificateFactory.X.509"
494 * would be satisfied by any provider that supplied
495 * a CertificateFactory implementation for X.509 certificates.
496 * <li> <i>{@literal <crypto_service>.<algorithm_or_type>
497 * <attribute_name>:<attribute_value>}</i>
498 * <p> The cryptographic service name must not contain any dots. There
499 * must be one or more space characters between the
500 * <i>{@literal <algorithm_or_type>}</i> and the
501 * <i>{@literal <attribute_name>}</i>.
502 * <p> A provider satisfies this selection criterion iff the
503 * provider implements the specified algorithm or type for the specified
504 * cryptographic service and its implementation meets the
505 * constraint expressed by the specified attribute name/value pair.
506 * <p> For example, "Signature.SHA1withDSA KeySize:1024" would be
507 * satisfied by any provider that implemented
508 * the SHA1withDSA signature algorithm with a keysize of 1024 (or larger).
509 *
510 * </ul>
511 *
512 * <p> See the <a href=
513 * "{@docRoot}/../technotes/guides/security/StandardNames.html">
514 * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
515 * for information about standard cryptographic service names, standard
516 * algorithm names and standard attribute names.
517 *
518 * @param filter the criterion for selecting
519 * providers. The filter is case-insensitive.
520 *
521 * @return all the installed providers that satisfy the selection
522 * criterion, or null if no such providers have been installed.
523 *
524 * @throws InvalidParameterException
525 * if the filter is not in the required format
526 * @throws NullPointerException if filter is null
527 *
528 * @see #getProviders(java.util.Map)
529 * @since 1.3
530 */
531 public static Provider[] getProviders(String filter) {
532 String key = null;
533 String value = null;
534 int index = filter.indexOf(':');
535
536 if (index == -1) {
537 key = filter;
538 value = "";
539 } else {
540 key = filter.substring(0, index);
541 value = filter.substring(index + 1);
542 }
543
544 Hashtable<String, String> hashtableFilter = new Hashtable<>(1);
545 hashtableFilter.put(key, value);
546
547 return (getProviders(hashtableFilter));
548 }
549
550 /**
551 * Returns an array containing all installed providers that satisfy the
552 * specified* selection criteria, or null if no such providers have been
553 * installed. The returned providers are ordered
554 * according to their
555 * {@linkplain #insertProviderAt(java.security.Provider, int)
556 * preference order}.
557 *
558 * <p>The selection criteria are represented by a map.
559 * Each map entry represents a selection criterion.
560 * A provider is selected iff it satisfies all selection
561 * criteria. The key for any entry in such a map must be in one of the
562 * following two formats:
563 * <ul>
564 * <li> <i>{@literal <crypto_service>.<algorithm_or_type>}</i>
565 * <p> The cryptographic service name must not contain any dots.
566 * <p> The value associated with the key must be an empty string.
567 * <p> A provider
568 * satisfies this selection criterion iff the provider implements the
569 * specified algorithm or type for the specified cryptographic service.
570 * <li> <i>{@literal <crypto_service>}.
571 * {@literal <algorithm_or_type> <attribute_name>}</i>
572 * <p> The cryptographic service name must not contain any dots. There
573 * must be one or more space characters between the
574 * <i>{@literal <algorithm_or_type>}</i>
575 * and the <i>{@literal <attribute_name>}</i>.
576 * <p> The value associated with the key must be a non-empty string.
577 * A provider satisfies this selection criterion iff the
578 * provider implements the specified algorithm or type for the specified
579 * cryptographic service and its implementation meets the
580 * constraint expressed by the specified attribute name/value pair.
581 * </ul>
582 *
583 * <p> See the <a href=
584 * "../../../technotes/guides/security/StandardNames.html">
585 * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
586 * for information about standard cryptographic service names, standard
587 * algorithm names and standard attribute names.
588 *
589 * @param filter the criteria for selecting
590 * providers. The filter is case-insensitive.
591 *
592 * @return all the installed providers that satisfy the selection
593 * criteria, or null if no such providers have been installed.
594 *
595 * @throws InvalidParameterException
596 * if the filter is not in the required format
597 * @throws NullPointerException if filter is null
598 *
599 * @see #getProviders(java.lang.String)
600 * @since 1.3
601 */
602 public static Provider[] getProviders(Map<String,String> filter) {
603 // Get all installed providers first.
604 // Then only return those providers who satisfy the selection criteria.
605 Provider[] allProviders = Security.getProviders();
606 Set<String> keySet = filter.keySet();
607 LinkedHashSet<Provider> candidates = new LinkedHashSet<>(5);
608
609 // Returns all installed providers
610 // if the selection criteria is null.
611 if ((keySet == null) || (allProviders == null)) {
612 return allProviders;
613 }
614
615 boolean firstSearch = true;
616
617 // For each selection criterion, remove providers
618 // which don't satisfy the criterion from the candidate set.
619 for (Iterator<String> ite = keySet.iterator(); ite.hasNext(); ) {
620 String key = ite.next();
621 String value = filter.get(key);
622
623 LinkedHashSet<Provider> newCandidates = getAllQualifyingCandidates(key, value,
624 allProviders);
625 if (firstSearch) {
626 candidates = newCandidates;
627 firstSearch = false;
628 }
629
630 if ((newCandidates != null) && !newCandidates.isEmpty()) {
631 // For each provider in the candidates set, if it
632 // isn't in the newCandidate set, we should remove
633 // it from the candidate set.
634 for (Iterator<Provider> cansIte = candidates.iterator();
635 cansIte.hasNext(); ) {
636 Provider prov = cansIte.next();
637 if (!newCandidates.contains(prov)) {
638 cansIte.remove();
639 }
640 }
641 } else {
642 candidates = null;
643 break;
644 }
645 }
646
647 if ((candidates == null) || (candidates.isEmpty()))
648 return null;
649
650 Object[] candidatesArray = candidates.toArray();
651 Provider[] result = new Provider[candidatesArray.length];
652
653 for (int i = 0; i < result.length; i++) {
654 result[i] = (Provider)candidatesArray[i];
655 }
656
657 return result;
658 }
659
660 // Map containing cached Spi Class objects of the specified type
661 private static final Map<String, Class<?>> spiMap =
662 new ConcurrentHashMap<>();
663
664 /**
665 * Return the Class object for the given engine type
666 * (e.g. "MessageDigest"). Works for Spis in the java.security package
667 * only.
668 */
669 private static Class<?> getSpiClass(String type) {
670 Class<?> clazz = spiMap.get(type);
671 if (clazz != null) {
672 return clazz;
673 }
674 try {
675 clazz = Class.forName("java.security." + type + "Spi");
676 spiMap.put(type, clazz);
677 return clazz;
678 } catch (ClassNotFoundException e) {
679 throw new AssertionError("Spi class not found", e);
680 }
681 }
682
683 /*
684 * Returns an array of objects: the first object in the array is
685 * an instance of an implementation of the requested algorithm
686 * and type, and the second object in the array identifies the provider
687 * of that implementation.
688 * The {@code provider} argument can be null, in which case all
689 * configured providers will be searched in order of preference.
690 */
691 static Object[] getImpl(String algorithm, String type, String provider)
692 throws NoSuchAlgorithmException, NoSuchProviderException {
693 if (provider == null) {
694 return GetInstance.getInstance
695 (type, getSpiClass(type), algorithm).toArray();
696 } else {
697 return GetInstance.getInstance
698 (type, getSpiClass(type), algorithm, provider).toArray();
699 }
700 }
701
702 static Object[] getImpl(String algorithm, String type, String provider,
703 Object params) throws NoSuchAlgorithmException,
704 NoSuchProviderException, InvalidAlgorithmParameterException {
705 if (provider == null) {
706 return GetInstance.getInstance
707 (type, getSpiClass(type), algorithm, params).toArray();
708 } else {
709 return GetInstance.getInstance
710 (type, getSpiClass(type), algorithm, params, provider).toArray();
711 }
712 }
713
714 /*
715 * Returns an array of objects: the first object in the array is
716 * an instance of an implementation of the requested algorithm
717 * and type, and the second object in the array identifies the provider
718 * of that implementation.
719 * The {@code provider} argument cannot be null.
720 */
721 static Object[] getImpl(String algorithm, String type, Provider provider)
722 throws NoSuchAlgorithmException {
723 return GetInstance.getInstance
724 (type, getSpiClass(type), algorithm, provider).toArray();
725 }
726
727 static Object[] getImpl(String algorithm, String type, Provider provider,
728 Object params) throws NoSuchAlgorithmException,
729 InvalidAlgorithmParameterException {
730 return GetInstance.getInstance
731 (type, getSpiClass(type), algorithm, params, provider).toArray();
732 }
733
734 /**
735 * Gets a security property value.
736 *
737 * <p>First, if there is a security manager, its
738 * {@code checkPermission} method is called with a
739 * {@code java.security.SecurityPermission("getProperty."+key)}
740 * permission to see if it's ok to retrieve the specified
741 * security property value..
742 *
743 * @param key the key of the property being retrieved.
744 *
745 * @return the value of the security property corresponding to key.
746 *
747 * @throws SecurityException
748 * if a security manager exists and its {@link
749 * java.lang.SecurityManager#checkPermission} method
750 * denies
751 * access to retrieve the specified security property value
752 * @throws NullPointerException is key is null
753 *
754 * @see #setProperty
755 * @see java.security.SecurityPermission
756 */
757 public static String getProperty(String key) {
758 SecurityManager sm = System.getSecurityManager();
759 if (sm != null) {
760 sm.checkPermission(new SecurityPermission("getProperty."+
761 key));
762 }
763 String name = props.getProperty(key);
764 if (name != null)
765 name = name.trim(); // could be a class name with trailing ws
766 return name;
767 }
768
769 /**
770 * Sets a security property value.
771 *
772 * <p>First, if there is a security manager, its
773 * {@code checkPermission} method is called with a
774 * {@code java.security.SecurityPermission("setProperty."+key)}
775 * permission to see if it's ok to set the specified
776 * security property value.
777 *
778 * @param key the name of the property to be set.
779 *
780 * @param datum the value of the property to be set.
781 *
782 * @throws SecurityException
783 * if a security manager exists and its {@link
784 * java.lang.SecurityManager#checkPermission} method
785 * denies access to set the specified security property value
786 * @throws NullPointerException if key or datum is null
787 *
788 * @see #getProperty
789 * @see java.security.SecurityPermission
790 */
791 public static void setProperty(String key, String datum) {
792 check("setProperty."+key);
793 props.put(key, datum);
794 invalidateSMCache(key); /* See below. */
795 }
796
797 /*
798 * Implementation detail: If the property we just set in
799 * setProperty() was either "package.access" or
800 * "package.definition", we need to signal to the SecurityManager
801 * class that the value has just changed, and that it should
802 * invalidate it's local cache values.
803 *
804 * Rather than create a new API entry for this function,
805 * we use reflection to set a private variable.
806 */
807 private static void invalidateSMCache(String key) {
808
809 final boolean pa = key.equals("package.access");
810 final boolean pd = key.equals("package.definition");
811
812 if (pa || pd) {
813 AccessController.doPrivileged(new PrivilegedAction<Void>() {
814 public Void run() {
815 try {
816 /* Get the class via the bootstrap class loader. */
817 Class<?> cl = Class.forName(
818 "java.lang.SecurityManager", false, null);
819 Field f = null;
820 boolean accessible = false;
821
822 if (pa) {
823 f = cl.getDeclaredField("packageAccessValid");
824 accessible = f.isAccessible();
825 f.setAccessible(true);
826 } else {
827 f = cl.getDeclaredField("packageDefinitionValid");
828 accessible = f.isAccessible();
829 f.setAccessible(true);
830 }
831 f.setBoolean(f, false);
832 f.setAccessible(accessible);
833 }
834 catch (Exception e1) {
835 /* If we couldn't get the class, it hasn't
836 * been loaded yet. If there is no such
837 * field, we shouldn't try to set it. There
838 * shouldn't be a security execption, as we
839 * are loaded by boot class loader, and we
840 * are inside a doPrivileged() here.
841 *
842 * NOOP: don't do anything...
843 */
844 }
845 return null;
846 } /* run */
847 }); /* PrivilegedAction */
848 } /* if */
849 }
850
851 private static void check(String directive) {
852 SecurityManager security = System.getSecurityManager();
853 if (security != null) {
854 security.checkSecurityAccess(directive);
855 }
856 }
857
858 private static void checkInsertProvider(String name) {
859 SecurityManager security = System.getSecurityManager();
860 if (security != null) {
861 try {
862 security.checkSecurityAccess("insertProvider");
863 } catch (SecurityException se1) {
864 try {
865 security.checkSecurityAccess("insertProvider." + name);
866 } catch (SecurityException se2) {
867 // throw first exception, but add second to suppressed
868 se1.addSuppressed(se2);
869 throw se1;
870 }
871 }
872 }
873 }
874
875 /*
876 * Returns all providers who satisfy the specified
877 * criterion.
878 */
879 private static LinkedHashSet<Provider> getAllQualifyingCandidates(
880 String filterKey,
881 String filterValue,
882 Provider[] allProviders) {
883 String[] filterComponents = getFilterComponents(filterKey,
884 filterValue);
885
886 // The first component is the service name.
887 // The second is the algorithm name.
888 // If the third isn't null, that is the attrinute name.
889 String serviceName = filterComponents[0];
890 String algName = filterComponents[1];
891 String attrName = filterComponents[2];
892
893 return getProvidersNotUsingCache(serviceName, algName, attrName,
894 filterValue, allProviders);
895 }
896
897 private static LinkedHashSet<Provider> getProvidersNotUsingCache(
898 String serviceName,
899 String algName,
900 String attrName,
901 String filterValue,
902 Provider[] allProviders) {
903 LinkedHashSet<Provider> candidates = new LinkedHashSet<>(5);
904 for (int i = 0; i < allProviders.length; i++) {
905 if (isCriterionSatisfied(allProviders[i], serviceName,
906 algName,
907 attrName, filterValue)) {
908 candidates.add(allProviders[i]);
909 }
910 }
911 return candidates;
912 }
913
914 /*
915 * Returns true if the given provider satisfies
916 * the selection criterion key:value.
917 */
918 private static boolean isCriterionSatisfied(Provider prov,
919 String serviceName,
920 String algName,
921 String attrName,
922 String filterValue) {
923 String key = serviceName + '.' + algName;
924
925 if (attrName != null) {
926 key += ' ' + attrName;
927 }
928 // Check whether the provider has a property
929 // whose key is the same as the given key.
930 String propValue = getProviderProperty(key, prov);
931
932 if (propValue == null) {
933 // Check whether we have an alias instead
934 // of a standard name in the key.
935 String standardName = getProviderProperty("Alg.Alias." +
936 serviceName + "." +
937 algName,
938 prov);
939 if (standardName != null) {
940 key = serviceName + "." + standardName;
941
942 if (attrName != null) {
943 key += ' ' + attrName;
944 }
945
946 propValue = getProviderProperty(key, prov);
947 }
948
949 if (propValue == null) {
950 // The provider doesn't have the given
951 // key in its property list.
952 return false;
953 }
954 }
955
956 // If the key is in the format of:
957 // <crypto_service>.<algorithm_or_type>,
958 // there is no need to check the value.
959
960 if (attrName == null) {
961 return true;
962 }
963
964 // If we get here, the key must be in the
965 // format of <crypto_service>.<algorithm_or_provider> <attribute_name>.
966 if (isStandardAttr(attrName)) {
967 return isConstraintSatisfied(attrName, filterValue, propValue);
968 } else {
969 return filterValue.equalsIgnoreCase(propValue);
970 }
971 }
972
973 /*
974 * Returns true if the attribute is a standard attribute;
975 * otherwise, returns false.
976 */
977 private static boolean isStandardAttr(String attribute) {
978 // For now, we just have two standard attributes:
979 // KeySize and ImplementedIn.
980 if (attribute.equalsIgnoreCase("KeySize"))
981 return true;
982
983 if (attribute.equalsIgnoreCase("ImplementedIn"))
984 return true;
985
986 return false;
987 }
988
989 /*
990 * Returns true if the requested attribute value is supported;
991 * otherwise, returns false.
992 */
993 private static boolean isConstraintSatisfied(String attribute,
994 String value,
995 String prop) {
996 // For KeySize, prop is the max key size the
997 // provider supports for a specific <crypto_service>.<algorithm>.
998 if (attribute.equalsIgnoreCase("KeySize")) {
999 int requestedSize = Integer.parseInt(value);
1000 int maxSize = Integer.parseInt(prop);
1001 if (requestedSize <= maxSize) {
1002 return true;
1003 } else {
1004 return false;
1005 }
1006 }
1007
1008 // For Type, prop is the type of the implementation
1009 // for a specific <crypto service>.<algorithm>.
1010 if (attribute.equalsIgnoreCase("ImplementedIn")) {
1011 return value.equalsIgnoreCase(prop);
1012 }
1013
1014 return false;
1015 }
1016
1017 static String[] getFilterComponents(String filterKey, String filterValue) {
1018 int algIndex = filterKey.indexOf('.');
1019
1020 if (algIndex < 0) {
1021 // There must be a dot in the filter, and the dot
1022 // shouldn't be at the beginning of this string.
1023 throw new InvalidParameterException("Invalid filter");
1024 }
1025
1026 String serviceName = filterKey.substring(0, algIndex);
1027 String algName = null;
1028 String attrName = null;
1029
1030 if (filterValue.length() == 0) {
1031 // The filterValue is an empty string. So the filterKey
1032 // should be in the format of <crypto_service>.<algorithm_or_type>.
1033 algName = filterKey.substring(algIndex + 1).trim();
1034 if (algName.length() == 0) {
1035 // There must be a algorithm or type name.
1036 throw new InvalidParameterException("Invalid filter");
1037 }
1038 } else {
1039 // The filterValue is a non-empty string. So the filterKey must be
1040 // in the format of
1041 // <crypto_service>.<algorithm_or_type> <attribute_name>
1042 int attrIndex = filterKey.indexOf(' ');
1043
1044 if (attrIndex == -1) {
1045 // There is no attribute name in the filter.
1046 throw new InvalidParameterException("Invalid filter");
1047 } else {
1048 attrName = filterKey.substring(attrIndex + 1).trim();
1049 if (attrName.length() == 0) {
1050 // There is no attribute name in the filter.
1051 throw new InvalidParameterException("Invalid filter");
1052 }
1053 }
1054
1055 // There must be an algorithm name in the filter.
1056 if ((attrIndex < algIndex) ||
1057 (algIndex == attrIndex - 1)) {
1058 throw new InvalidParameterException("Invalid filter");
1059 } else {
1060 algName = filterKey.substring(algIndex + 1, attrIndex);
1061 }
1062 }
1063
1064 String[] result = new String[3];
1065 result[0] = serviceName;
1066 result[1] = algName;
1067 result[2] = attrName;
1068
1069 return result;
1070 }
1071
1072 /**
1073 * Returns a Set of Strings containing the names of all available
1074 * algorithms or types for the specified Java cryptographic service
1075 * (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore). Returns
1076 * an empty Set if there is no provider that supports the
1077 * specified service or if serviceName is null. For a complete list
1078 * of Java cryptographic services, please see the
1079 * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">Java
1080 * Cryptography Architecture API Specification & Reference</a>.
1081 * Note: the returned set is immutable.
1082 *
1083 * @param serviceName the name of the Java cryptographic
1084 * service (e.g., Signature, MessageDigest, Cipher, Mac, KeyStore).
1085 * Note: this parameter is case-insensitive.
1086 *
1087 * @return a Set of Strings containing the names of all available
1088 * algorithms or types for the specified Java cryptographic service
1089 * or an empty set if no provider supports the specified service.
1090 *
1091 * @since 1.4
1092 **/
1093 public static Set<String> getAlgorithms(String serviceName) {
1094
1095 if ((serviceName == null) || (serviceName.length() == 0) ||
1096 (serviceName.endsWith("."))) {
1097 return Collections.emptySet();
1098 }
1099
1100 HashSet<String> result = new HashSet<>();
1101 Provider[] providers = Security.getProviders();
1102
1103 for (int i = 0; i < providers.length; i++) {
1104 // Check the keys for each provider.
1105 for (Enumeration<Object> e = providers[i].keys();
1106 e.hasMoreElements(); ) {
1107 String currentKey =
1108 ((String)e.nextElement()).toUpperCase(Locale.ENGLISH);
1109 if (currentKey.startsWith(
1110 serviceName.toUpperCase(Locale.ENGLISH))) {
1111 // We should skip the currentKey if it contains a
1112 // whitespace. The reason is: such an entry in the
1113 // provider property contains attributes for the
1114 // implementation of an algorithm. We are only interested
1115 // in entries which lead to the implementation
1116 // classes.
1117 if (currentKey.indexOf(" ") < 0) {
1118 result.add(currentKey.substring(
1119 serviceName.length() + 1));
1120 }
1121 }
1122 }
1123 }
1124 return Collections.unmodifiableSet(result);
1125 }
1126 }
1127