jdk/src/java.base/share/classes/javax/crypto/JceSecurity.java.template
changeset 42365 5e640c2994d6
parent 40565 3ac0ba151e70
equal deleted inserted replaced
42364:c5a725b3d358 42365:5e640c2994d6
       
     1 /*
       
     2  * Copyright (c) 1997, 2016, 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 /*
       
    27  * README README README README README README README README README
       
    28  *
       
    29  * This file is the template for generating the JceSecurity.java source
       
    30  * file.
       
    31  *
       
    32  * In the current jdk builds, this file is first preprocessed to replace
       
    33  * @@JCE_DEFAULT_POLICY@ [sic] with "limited" or "unlimited" which is
       
    34  * determined by the $(UNLIMTED_CRYPTO) make variable.  This variable is
       
    35  * set by top-level configure script, using either
       
    36  * --disable-unlimited-crypto or --enable-unlimited-crypto [default].
       
    37  *
       
    38  * Since this file is a generated source, incremental changes to
       
    39  * this file require regenerating the source.  Compilation options:
       
    40  *
       
    41  *     (fewer dependencies/"faster" ones first)
       
    42  *
       
    43  * 1.  make JDK_FILTER=javax/crypto java.base-gensrc-only java.base-java-only
       
    44  * 2.  make java.base-gensrc-only java.base-java-only
       
    45  * 3.  make java.base-gensrc-only java.base-only
       
    46  * 4.  make java.base-only
       
    47  * 5.  make
       
    48  */
       
    49 
       
    50 package javax.crypto;
       
    51 
       
    52 import java.util.*;
       
    53 import java.io.*;
       
    54 import java.net.URL;
       
    55 import java.nio.file.*;
       
    56 import java.security.*;
       
    57 
       
    58 import java.security.Provider.Service;
       
    59 
       
    60 import sun.security.jca.*;
       
    61 import sun.security.jca.GetInstance.Instance;
       
    62 import sun.security.util.Debug;
       
    63 
       
    64 /**
       
    65  * This class instantiates implementations of JCE engine classes from
       
    66  * providers registered with the java.security.Security object.
       
    67  *
       
    68  * @author Jan Luehe
       
    69  * @author Sharon Liu
       
    70  * @since 1.4
       
    71  */
       
    72 
       
    73 final class JceSecurity {
       
    74   
       
    75   	
       
    76     private static final Debug debug = Debug.getInstance("jca");
       
    77 
       
    78     static final SecureRandom RANDOM = new SecureRandom();
       
    79 
       
    80     // The defaultPolicy and exemptPolicy will be set up
       
    81     // in the static initializer.
       
    82     private static CryptoPermissions defaultPolicy = null;
       
    83     private static CryptoPermissions exemptPolicy = null;
       
    84 
       
    85     // Map<Provider,?> of the providers we already have verified
       
    86     // value == PROVIDER_VERIFIED is successfully verified
       
    87     // value is failure cause Exception in error case
       
    88     private static final Map<Provider, Object> verificationResults =
       
    89             new IdentityHashMap<>();
       
    90 
       
    91     // Map<Provider,?> of the providers currently being verified
       
    92     private static final Map<Provider, Object> verifyingProviders =
       
    93             new IdentityHashMap<>();
       
    94 
       
    95     private static final boolean isRestricted;
       
    96 
       
    97     /*
       
    98      * Don't let anyone instantiate this.
       
    99      */
       
   100     private JceSecurity() {
       
   101     }
       
   102 
       
   103     static {
       
   104         try {
       
   105             AccessController.doPrivileged(
       
   106                 new PrivilegedExceptionAction<> () {
       
   107                     @Override
       
   108                     public Void run() throws Exception {
       
   109                         setupJurisdictionPolicies();
       
   110                         return null;
       
   111                     }
       
   112                 }
       
   113             );
       
   114 
       
   115             isRestricted = defaultPolicy.implies(
       
   116                 CryptoAllPermission.INSTANCE) ? false : true;
       
   117         } catch (Exception e) {
       
   118             throw new SecurityException(
       
   119                     "Can not initialize cryptographic mechanism", e);
       
   120         }
       
   121     }
       
   122 
       
   123     static Instance getInstance(String type, Class<?> clazz, String algorithm,
       
   124             String provider) throws NoSuchAlgorithmException,
       
   125             NoSuchProviderException {
       
   126         Service s = GetInstance.getService(type, algorithm, provider);
       
   127         Exception ve = getVerificationResult(s.getProvider());
       
   128         if (ve != null) {
       
   129             String msg = "JCE cannot authenticate the provider " + provider;
       
   130             throw (NoSuchProviderException)
       
   131                                 new NoSuchProviderException(msg).initCause(ve);
       
   132         }
       
   133         return GetInstance.getInstance(s, clazz);
       
   134     }
       
   135 
       
   136     static Instance getInstance(String type, Class<?> clazz, String algorithm,
       
   137             Provider provider) throws NoSuchAlgorithmException {
       
   138         Service s = GetInstance.getService(type, algorithm, provider);
       
   139         Exception ve = JceSecurity.getVerificationResult(provider);
       
   140         if (ve != null) {
       
   141             String msg = "JCE cannot authenticate the provider "
       
   142                 + provider.getName();
       
   143             throw new SecurityException(msg, ve);
       
   144         }
       
   145         return GetInstance.getInstance(s, clazz);
       
   146     }
       
   147 
       
   148     static Instance getInstance(String type, Class<?> clazz, String algorithm)
       
   149             throws NoSuchAlgorithmException {
       
   150         List<Service> services = GetInstance.getServices(type, algorithm);
       
   151         NoSuchAlgorithmException failure = null;
       
   152         for (Service s : services) {
       
   153             if (canUseProvider(s.getProvider()) == false) {
       
   154                 // allow only signed providers
       
   155                 continue;
       
   156             }
       
   157             try {
       
   158                 Instance instance = GetInstance.getInstance(s, clazz);
       
   159                 return instance;
       
   160             } catch (NoSuchAlgorithmException e) {
       
   161                 failure = e;
       
   162             }
       
   163         }
       
   164         throw new NoSuchAlgorithmException("Algorithm " + algorithm
       
   165                 + " not available", failure);
       
   166     }
       
   167 
       
   168     /**
       
   169      * Verify if the JAR at URL codeBase is a signed exempt application
       
   170      * JAR file and returns the permissions bundled with the JAR.
       
   171      *
       
   172      * @throws Exception on error
       
   173      */
       
   174     static CryptoPermissions verifyExemptJar(URL codeBase) throws Exception {
       
   175         ProviderVerifier pv = new ProviderVerifier(codeBase, true);
       
   176         pv.verify();
       
   177         return pv.getPermissions();
       
   178     }
       
   179 
       
   180     /**
       
   181      * Verify if the JAR at URL codeBase is a signed provider JAR file.
       
   182      *
       
   183      * @throws Exception on error
       
   184      */
       
   185     static void verifyProvider(URL codeBase, Provider p) throws Exception {
       
   186         // Verify the provider JAR file and all
       
   187         // supporting JAR files if there are any.
       
   188         ProviderVerifier pv = new ProviderVerifier(codeBase, p, false);
       
   189         pv.verify();
       
   190     }
       
   191 
       
   192     private static final Object PROVIDER_VERIFIED = Boolean.TRUE;
       
   193 
       
   194     /*
       
   195      * Verify that the provider JAR files are signed properly, which
       
   196      * means the signer's certificate can be traced back to a
       
   197      * JCE trusted CA.
       
   198      * Return null if ok, failure Exception if verification failed.
       
   199      */
       
   200     static synchronized Exception getVerificationResult(Provider p) {
       
   201         Object o = verificationResults.get(p);
       
   202         if (o == PROVIDER_VERIFIED) {
       
   203             return null;
       
   204         } else if (o != null) {
       
   205             return (Exception)o;
       
   206         }
       
   207         if (verifyingProviders.get(p) != null) {
       
   208             // this method is static synchronized, must be recursion
       
   209             // return failure now but do not save the result
       
   210             return new NoSuchProviderException("Recursion during verification");
       
   211         }
       
   212         try {
       
   213             verifyingProviders.put(p, Boolean.FALSE);
       
   214             URL providerURL = getCodeBase(p.getClass());
       
   215             verifyProvider(providerURL, p);
       
   216             // Verified ok, cache result
       
   217             verificationResults.put(p, PROVIDER_VERIFIED);
       
   218             return null;
       
   219         } catch (Exception e) {
       
   220             verificationResults.put(p, e);
       
   221             return e;
       
   222         } finally {
       
   223             verifyingProviders.remove(p);
       
   224         }
       
   225     }
       
   226 
       
   227     // return whether this provider is properly signed and can be used by JCE
       
   228     static boolean canUseProvider(Provider p) {
       
   229         return getVerificationResult(p) == null;
       
   230     }
       
   231 
       
   232     // dummy object to represent null
       
   233     private static final URL NULL_URL;
       
   234 
       
   235     static {
       
   236         try {
       
   237             NULL_URL = new URL("http://null.oracle.com/");
       
   238         } catch (Exception e) {
       
   239             throw new RuntimeException(e);
       
   240         }
       
   241     }
       
   242 
       
   243     // reference to a Map we use as a cache for codebases
       
   244     private static final Map<Class<?>, URL> codeBaseCacheRef =
       
   245             new WeakHashMap<>();
       
   246 
       
   247     /*
       
   248      * Returns the CodeBase for the given class.
       
   249      */
       
   250     static URL getCodeBase(final Class<?> clazz) {
       
   251         synchronized (codeBaseCacheRef) {
       
   252             URL url = codeBaseCacheRef.get(clazz);
       
   253             if (url == null) {
       
   254                 url = AccessController.doPrivileged(
       
   255                     new PrivilegedAction<>() {
       
   256                         @Override
       
   257                         public URL run() {
       
   258                             ProtectionDomain pd = clazz.getProtectionDomain();
       
   259                             if (pd != null) {
       
   260                                 CodeSource cs = pd.getCodeSource();
       
   261                                 if (cs != null) {
       
   262                                     return cs.getLocation();
       
   263                                 }
       
   264                             }
       
   265                             return NULL_URL;
       
   266                         }
       
   267                     });
       
   268                 codeBaseCacheRef.put(clazz, url);
       
   269             }
       
   270             return (url == NULL_URL) ? null : url;
       
   271         }
       
   272     }
       
   273 
       
   274     // This is called from within an doPrivileged block.
       
   275     private static void setupJurisdictionPolicies() throws Exception {
       
   276 
       
   277         // Sanity check the crypto.policy Security property.  Single
       
   278         // directory entry, no pseudo-directories (".", "..", leading/trailing
       
   279         // path separators). normalize()/getParent() will help later.
       
   280         String cryptoPolicyProperty = Security.getProperty("crypto.policy");
       
   281 
       
   282         /*
       
   283          * In case no property is present, rather than fail catastrophically,
       
   284          * we at least try for a "sane" value, which is what we were
       
   285          * built with.  We first preprocess this file to plug in that
       
   286          * value, then compile the result gensrc.
       
   287          *
       
   288          * Log the warning first.
       
   289          */
       
   290         if (cryptoPolicyProperty == null) {
       
   291             cryptoPolicyProperty = "@@JCE_DEFAULT_POLICY@@";
       
   292             if (debug != null) {
       
   293                 debug.println(
       
   294                     "Security Property 'crypto.policy' not found: "
       
   295                     + "using '" + cryptoPolicyProperty + "' as fallback");
       
   296             }
       
   297         }
       
   298 
       
   299         Path cpPath = Paths.get(cryptoPolicyProperty);
       
   300 
       
   301         if ((cpPath.getNameCount() != 1) ||
       
   302                 (cpPath.compareTo(cpPath.getFileName()) != 0)) {
       
   303             throw new SecurityException(
       
   304                 "Invalid policy directory name format: " +
       
   305                 cryptoPolicyProperty);
       
   306         }
       
   307 
       
   308         // Prepend java.home to get the full path.  normalize() in
       
   309         // case an extra "." or ".." snuck in somehow.
       
   310         String javaHomeProperty = System.getProperty("java.home");
       
   311         Path javaHomePolicyPath = Paths.get(javaHomeProperty, "conf",
       
   312                 "security", "policy").normalize();
       
   313         Path cryptoPolicyPath = Paths.get(javaHomeProperty, "conf", "security",
       
   314                 "policy", cryptoPolicyProperty).normalize();
       
   315 
       
   316         if (cryptoPolicyPath.getParent().compareTo(javaHomePolicyPath) != 0) {
       
   317             throw new SecurityException(
       
   318                 "Invalid cryptographic jurisdiction policy directory path: " +
       
   319                 cryptoPolicyProperty);
       
   320         }
       
   321 
       
   322         if (!Files.isDirectory(cryptoPolicyPath)
       
   323                 || !Files.isReadable(cryptoPolicyPath)) {
       
   324             throw new SecurityException(
       
   325                 "Can't read cryptographic policy directory: " +
       
   326                 cryptoPolicyProperty);
       
   327         }
       
   328 
       
   329         try (DirectoryStream<Path> stream = Files.newDirectoryStream(
       
   330                 cryptoPolicyPath, "{default,exempt}_*.policy")) {
       
   331             for (Path entry : stream) {
       
   332                 try (InputStream is = new BufferedInputStream(
       
   333                         Files.newInputStream(entry))) {
       
   334                     String filename = entry.getFileName().toString();
       
   335 
       
   336                     CryptoPermissions tmpPerms = new CryptoPermissions();
       
   337                     tmpPerms.load(is);
       
   338 
       
   339                     if (filename.startsWith("default_")) {
       
   340                         // Did we find a default perms?
       
   341                         defaultPolicy = ((defaultPolicy == null) ? tmpPerms :
       
   342                                 defaultPolicy.getMinimum(tmpPerms));
       
   343                     } else if (filename.startsWith("exempt_")) {
       
   344                         // Did we find a exempt perms?
       
   345                         exemptPolicy = ((exemptPolicy == null) ? tmpPerms :
       
   346                                 exemptPolicy.getMinimum(tmpPerms));
       
   347                     } else {
       
   348                         // This should never happen.  newDirectoryStream
       
   349                         // should only throw return "{default,exempt}_*.policy"
       
   350                         throw new SecurityException(
       
   351                             "Unexpected jurisdiction policy files in : " +
       
   352                             cryptoPolicyProperty);
       
   353                     }
       
   354                 } catch (Exception e) {
       
   355                     throw new SecurityException(
       
   356                         "Couldn't parse jurisdiction policy files in: " +
       
   357                         cryptoPolicyProperty);
       
   358                 }
       
   359             }
       
   360         } catch (DirectoryIteratorException ex) {
       
   361             // I/O error encountered during the iteration,
       
   362             // the cause is an IOException
       
   363             throw new SecurityException(
       
   364                 "Couldn't iterate through the jurisdiction policy files: " +
       
   365                 cryptoPolicyProperty);
       
   366         }
       
   367 
       
   368         // Must have a default policy
       
   369         if ((defaultPolicy == null) || defaultPolicy.isEmpty()) {
       
   370             throw new SecurityException(
       
   371                 "Missing mandatory jurisdiction policy files: " +
       
   372                 cryptoPolicyProperty);
       
   373         }
       
   374 
       
   375         // If there was an empty exempt policy file, ignore it.
       
   376         if ((exemptPolicy != null) && exemptPolicy.isEmpty()) {
       
   377             exemptPolicy = null;
       
   378         }
       
   379     }
       
   380 
       
   381     static CryptoPermissions getDefaultPolicy() {
       
   382         return defaultPolicy;
       
   383     }
       
   384 
       
   385     static CryptoPermissions getExemptPolicy() {
       
   386         return exemptPolicy;
       
   387     }
       
   388 
       
   389     static boolean isRestricted() {
       
   390         return isRestricted;
       
   391     }
       
   392 }