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 26package sun.security.jca; 27 28import 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 */ 37public 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 // Hardcoded names of providers to use for JAR verification. 83 // MUST NOT be on the bootclasspath and not in signed JAR files. 84 private static final String[] jarVerificationProviders = { 85 "SUN", 86 "SunRsaSign", 87 // Note: when SunEC is in a signed JAR file, it's not signed 88 // by EC algorithms. So it's still safe to be listed here. 89 "SunEC", 90 }; 91 92 // Return Sun provider. 93 // This method should only be called by 94 // sun.security.util.ManifestEntryVerifier and java.security.SecureRandom. 95 public static Provider getSunProvider() { 96 return new sun.security.provider.Sun(); 97 } 98 99 /** 100 * Start JAR verification. This sets a special provider list for 101 * the current thread. You MUST save the return value from this 102 * method and you MUST call stopJarVerification() with that object 103 * once you are done. 104 */ 105 public static Object startJarVerification() { 106 ProviderList currentList = getProviderList(); 107 ProviderList jarList = currentList.getJarList(jarVerificationProviders); 108 if (jarList.getProvider("SUN") == null) { 109 // add backup provider 110 Provider p; 111 try { 112 p = new sun.security.provider.VerificationProvider(); 113 } catch (Exception e) { 114 throw new RuntimeException("Missing provider for jar verification", e); 115 } 116 ProviderList.add(jarList, p); 117 } 118 // return the old thread-local provider list, usually null 119 return beginThreadProviderList(jarList); 120 } 121 122 /** 123 * Stop JAR verification. Call once you have completed JAR verification. 124 */ 125 public static void stopJarVerification(Object obj) { 126 // restore old thread-local provider list 127 endThreadProviderList((ProviderList)obj); 128 } 129 130 /** 131 * Return the current ProviderList. If the thread-local list is set, 132 * it is returned. Otherwise, the system wide list is returned. 133 */ 134 public static ProviderList getProviderList() { 135 ProviderList list = getThreadProviderList(); 136 if (list == null) { 137 list = getSystemProviderList(); 138 } 139 return list; 140 } 141 142 /** 143 * Set the current ProviderList. Affects the thread-local list if set, 144 * otherwise the system wide list. 145 */ 146 public static void setProviderList(ProviderList newList) { 147 if (getThreadProviderList() == null) { 148 setSystemProviderList(newList); 149 } else { 150 changeThreadProviderList(newList); 151 } 152 } 153 154 /** 155 * Get the full provider list with invalid providers (those that 156 * could not be loaded) removed. This is the list we need to 157 * present to applications. 158 */ 159 public static ProviderList getFullProviderList() { 160 ProviderList list; 161 synchronized (Providers.class) { 162 list = getThreadProviderList(); 163 if (list != null) { 164 ProviderList newList = list.removeInvalid(); 165 if (newList != list) { 166 changeThreadProviderList(newList); 167 list = newList; 168 } 169 return list; 170 } 171 } 172 list = getSystemProviderList(); 173 ProviderList newList = list.removeInvalid(); 174 if (newList != list) { 175 setSystemProviderList(newList); 176 list = newList; 177 } 178 return list; 179 } 180 181 private static ProviderList getSystemProviderList() { 182 return providerList; 183 } 184 185 private static void setSystemProviderList(ProviderList list) { 186 providerList = list; 187 } 188 189 public static ProviderList getThreadProviderList() { 190 // avoid accessing the threadlocal if none are currently in use 191 // (first use of ThreadLocal.get() for a Thread allocates a Map) 192 if (threadListsUsed == 0) { 193 return null; 194 } 195 return threadLists.get(); 196 } 197 198 // Change the thread local provider list. Use only if the current thread 199 // is already using a thread local list and you want to change it in place. 200 // In other cases, use the begin/endThreadProviderList() methods. 201 private static void changeThreadProviderList(ProviderList list) { 202 threadLists.set(list); 203 } 204 205 /** 206 * Methods to manipulate the thread local provider list. It is for use by 207 * JAR verification (see above) and the SunJSSE FIPS mode only. 208 * 209 * It should be used as follows: 210 * 211 * ProviderList list = ...; 212 * ProviderList oldList = Providers.beginThreadProviderList(list); 213 * try { 214 * // code that needs thread local provider list 215 * } finally { 216 * Providers.endThreadProviderList(oldList); 217 * } 218 * 219 */ 220 221 public static synchronized ProviderList beginThreadProviderList(ProviderList list) { 222 if (ProviderList.debug != null) { 223 ProviderList.debug.println("ThreadLocal providers: " + list); 224 } 225 ProviderList oldList = threadLists.get(); 226 threadListsUsed++; 227 threadLists.set(list); 228 return oldList; 229 } 230 231 public static synchronized void endThreadProviderList(ProviderList list) { 232 if (list == null) { 233 if (ProviderList.debug != null) { 234 ProviderList.debug.println("Disabling ThreadLocal providers"); 235 } 236 threadLists.remove(); 237 } else { 238 if (ProviderList.debug != null) { 239 ProviderList.debug.println 240 ("Restoring previous ThreadLocal providers: " + list); 241 } 242 threadLists.set(list); 243 } 244 threadListsUsed--; 245 } 246 247} 248