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