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