1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.  Oracle designates this
9  * particular file as subject to the "Classpath" exception as provided
10  * by Oracle in the LICENSE file that accompanied this code.
11  *
12  * This code is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * version 2 for more details (a copy is included in the LICENSE file that
16  * accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License version
19  * 2 along with this work; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23  * or visit www.oracle.com if you need additional information or have any
24  * questions.
25  */
26 
27 package sun.security.jca;
28 
29 import java.security.Provider;
30 
31 /**
32  * Collection of methods to get and set provider list. Also includes
33  * special code for the provider list during JAR verification.
34  *
35  * @author  Andreas Sterbenz
36  * @since   1.5
37  */
38 public class Providers {
39 
40     private static final ThreadLocal<ProviderList> threadLists =
41         new InheritableThreadLocal<>();
42 
43     // number of threads currently using thread-local provider lists
44     // tracked to allow an optimization if == 0
45     private static volatile int threadListsUsed;
46 
47     // current system-wide provider list
48     // Note volatile immutable object, so no synchronization needed.
49     private static volatile ProviderList providerList;
50 
51     static {
52         // set providerList to empty list first in case initialization somehow
53         // triggers a getInstance() call (although that should not happen)
54         providerList = ProviderList.EMPTY;
55         providerList = ProviderList.fromSecurityProperties();
56 
57         // removeInvalid is specified to try initializing all configured providers
58         // and removing those that aren't instantiable. This has the side effect
59         // of eagerly initializing all providers.
60         final int numConfiguredProviders = providerList.size();
61         providerList = providerList.removeInvalid();
62         if (numConfiguredProviders != providerList.size()) {
63             throw new AssertionError("Unable to configure default providers");
64         }
65     }
66 
Providers()67     private Providers() {
68         // empty
69     }
70 
71     // we need special handling to resolve circularities when loading
72     // signed JAR files during startup. The code below is part of that.
73 
74     // Basically, before we load data from a signed JAR file, we parse
75     // the PKCS#7 file and verify the signature. We need a
76     // CertificateFactory, Signatures, etc. to do that. We have to make
77     // sure that we do not try to load the implementation from the JAR
78     // file we are just verifying.
79     //
80     // To avoid that, we use different provider settings during JAR
81     // verification.  However, we do not want those provider settings to
82     // interfere with other parts of the system. Therefore, we make them local
83     // to the Thread executing the JAR verification code.
84     //
85     // The code here is used by sun.security.util.SignatureFileVerifier.
86     // See there for details.
87 
88     private static final String BACKUP_PROVIDER_CLASSNAME =
89         "sun.security.provider.VerificationProvider";
90 
91     // Hardcoded classnames of providers to use for JAR verification.
92     // MUST NOT be on the bootclasspath and not in signed JAR files.
93     private static final String[] jarVerificationProviders = {
94         // BEGIN Android-changed
95         /*
96         "sun.security.provider.Sun",
97         "sun.security.rsa.SunRsaSign",
98         // Note: SunEC *is* in a signed JAR file, but it's not signed
99         // by EC itself. So it's still safe to be listed here.
100         "sun.security.ec.SunEC",
101         */
102         "com.android.org.conscrypt.OpenSSLProvider",
103         "com.android.org.bouncycastle.jce.provider.BouncyCastleProvider",
104         "com.android.org.conscrypt.JSSEProvider",
105         // END Android-changed
106         BACKUP_PROVIDER_CLASSNAME,
107     };
108 
109     // Return to Sun provider or its backup.
110     // This method should only be called by
111     // sun.security.util.ManifestEntryVerifier and java.security.SecureRandom.
getSunProvider()112     public static Provider getSunProvider() {
113         try {
114             Class<?> clazz = Class.forName(jarVerificationProviders[0]);
115             return (Provider)clazz.newInstance();
116         } catch (Exception e) {
117             try {
118                 Class<?> clazz = Class.forName(BACKUP_PROVIDER_CLASSNAME);
119                 return (Provider)clazz.newInstance();
120             } catch (Exception ee) {
121                 throw new RuntimeException("Sun provider not found", e);
122             }
123         }
124     }
125 
126     /**
127      * Start JAR verification. This sets a special provider list for
128      * the current thread. You MUST save the return value from this
129      * method and you MUST call stopJarVerification() with that object
130      * once you are done.
131      */
startJarVerification()132     public static Object startJarVerification() {
133         ProviderList currentList = getProviderList();
134         ProviderList jarList = currentList.getJarList(jarVerificationProviders);
135         // return the old thread-local provider list, usually null
136         return beginThreadProviderList(jarList);
137     }
138 
139     /**
140      * Stop JAR verification. Call once you have completed JAR verification.
141      */
stopJarVerification(Object obj)142     public static void stopJarVerification(Object obj) {
143         // restore old thread-local provider list
144         endThreadProviderList((ProviderList)obj);
145     }
146 
147     /**
148      * Return the current ProviderList. If the thread-local list is set,
149      * it is returned. Otherwise, the system wide list is returned.
150      */
getProviderList()151     public static ProviderList getProviderList() {
152         ProviderList list = getThreadProviderList();
153         if (list == null) {
154             list = getSystemProviderList();
155         }
156         return list;
157     }
158 
159     /**
160      * Set the current ProviderList. Affects the thread-local list if set,
161      * otherwise the system wide list.
162      */
setProviderList(ProviderList newList)163     public static void setProviderList(ProviderList newList) {
164         if (getThreadProviderList() == null) {
165             setSystemProviderList(newList);
166         } else {
167             changeThreadProviderList(newList);
168         }
169     }
170 
171     /**
172      * Get the full provider list with invalid providers (those that
173      * could not be loaded) removed. This is the list we need to
174      * present to applications.
175      */
getFullProviderList()176     public static ProviderList getFullProviderList() {
177         ProviderList list;
178         synchronized (Providers.class) {
179             list = getThreadProviderList();
180             if (list != null) {
181                 ProviderList newList = list.removeInvalid();
182                 if (newList != list) {
183                     changeThreadProviderList(newList);
184                     list = newList;
185                 }
186                 return list;
187             }
188         }
189         list = getSystemProviderList();
190         ProviderList newList = list.removeInvalid();
191         if (newList != list) {
192             setSystemProviderList(newList);
193             list = newList;
194         }
195         return list;
196     }
197 
getSystemProviderList()198     private static ProviderList getSystemProviderList() {
199         return providerList;
200     }
201 
setSystemProviderList(ProviderList list)202     private static void setSystemProviderList(ProviderList list) {
203         providerList = list;
204     }
205 
getThreadProviderList()206     public static ProviderList getThreadProviderList() {
207         // avoid accessing the threadlocal if none are currently in use
208         // (first use of ThreadLocal.get() for a Thread allocates a Map)
209         if (threadListsUsed == 0) {
210             return null;
211         }
212         return threadLists.get();
213     }
214 
215     // Change the thread local provider list. Use only if the current thread
216     // is already using a thread local list and you want to change it in place.
217     // In other cases, use the begin/endThreadProviderList() methods.
changeThreadProviderList(ProviderList list)218     private static void changeThreadProviderList(ProviderList list) {
219         threadLists.set(list);
220     }
221 
222     /**
223      * Methods to manipulate the thread local provider list. It is for use by
224      * JAR verification (see above) and the SunJSSE FIPS mode only.
225      *
226      * It should be used as follows:
227      *
228      *   ProviderList list = ...;
229      *   ProviderList oldList = Providers.beginThreadProviderList(list);
230      *   try {
231      *     // code that needs thread local provider list
232      *   } finally {
233      *     Providers.endThreadProviderList(oldList);
234      *   }
235      *
236      */
237 
beginThreadProviderList(ProviderList list)238     public static synchronized ProviderList beginThreadProviderList(ProviderList list) {
239         if (ProviderList.debug != null) {
240             ProviderList.debug.println("ThreadLocal providers: " + list);
241         }
242         ProviderList oldList = threadLists.get();
243         threadListsUsed++;
244         threadLists.set(list);
245         return oldList;
246     }
247 
endThreadProviderList(ProviderList list)248     public static synchronized void endThreadProviderList(ProviderList list) {
249         if (list == null) {
250             if (ProviderList.debug != null) {
251                 ProviderList.debug.println("Disabling ThreadLocal providers");
252             }
253             threadLists.remove();
254         } else {
255             if (ProviderList.debug != null) {
256                 ProviderList.debug.println
257                     ("Restoring previous ThreadLocal providers: " + list);
258             }
259             threadLists.set(list);
260         }
261         threadListsUsed--;
262     }
263 
264 }
265