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