Home | History | Annotate | Download | only in jca
      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