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