jdk/src/share/classes/sun/jkernel/BundleCheck.java
changeset 8249 c3d31a2ce7c6
parent 8248 09e47b898040
parent 8219 4a1c655bfb69
child 8250 a36beda9b9de
equal deleted inserted replaced
8248:09e47b898040 8249:c3d31a2ce7c6
     1 /*
       
     2  * Copyright (c) 2008, 2009, 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  *
       
    28  * The Java Kernel Bundle security check.
       
    29  *
       
    30  * This class is responsible for detail of creating, storing, dispensing, and
       
    31  * updating bundle security checks and security checks for all the files
       
    32  * extracted from a bundle. Security checks are cryptographic
       
    33  * hashcodes that make it impractical to counterfeit a file. The security
       
    34  * check algorithm is defined by peer class StandaloneMessageDigest. The
       
    35  * cryptographic
       
    36  * hashcodes are held in instances of this class as byte arrays and externally
       
    37  * as hexidecimal string values for Bundle name Property keys. The properties
       
    38  * are a resource in the Java Kernel core JRE rt.jar and accessed after a
       
    39  * real or simulated bundle download by peer classes DownloadManager and
       
    40  * Bundle. Build-time deployment class SplitJRE uses this class to create file
       
    41  * security checks directly and via a special execution of DownloadManager.
       
    42  * The main method of this class can be used to create a
       
    43  * new set of security codes and updated properties for a given JRE path
       
    44  * and set of bundle names (CWD assume to contain bundle files as <name>.zip).
       
    45  *
       
    46  * This is a Sun internal class defined by the Sun implementation and
       
    47  * intended for JRE/JDK release deployment.
       
    48  *
       
    49  * @see sun.jkernel.DownloadManager
       
    50  * @see sun.jkernel.Bundle
       
    51  * @see sun.jkernel.StandaloneSHA
       
    52  * @see sun.jkernel.ByteArrayToFromHexDigits
       
    53  * See also deploy/src/kernel/share/classes/sun/kernel/SplitJRE.java
       
    54  */
       
    55 
       
    56 package sun.jkernel;
       
    57 
       
    58 import java.io.File;
       
    59 import java.io.InputStream;
       
    60 import java.io.OutputStream;
       
    61 import java.io.BufferedInputStream;
       
    62 import java.io.BufferedOutputStream;
       
    63 import java.io.FileInputStream;
       
    64 import java.io.FileOutputStream;
       
    65 import java.io.IOException;
       
    66 import java.util.Properties;
       
    67 
       
    68 
       
    69 public class BundleCheck {
       
    70 
       
    71     /* File buffer size */
       
    72 
       
    73     private static final int DIGEST_STREAM_BUFFER_SIZE = 2048;
       
    74 
       
    75     /* The bundle filename suffix */
       
    76 
       
    77     private static final String BUNDLE_SUFFIX = ".zip";
       
    78 
       
    79     /* Mutable static state. */
       
    80 
       
    81     /* Properties (Bundle name/check hex String pairs) for a set of Bundles.
       
    82        Guarded by this class' object. */
       
    83 
       
    84     private static volatile Properties properties;
       
    85 
       
    86     /* Mutable instance state. */
       
    87 
       
    88     /**
       
    89      * The bytes of the check value. Guarded by the bundle Mutex (in
       
    90      * sun.jkernel.DownloadManager) or the fact that sun.kernel.SplitJRE
       
    91      * and/or DownloadManager with "-download all" runs a single thread.
       
    92      */
       
    93 
       
    94     private byte[] checkBytes;
       
    95 
       
    96     /* Prevent instantiation by default constructor */
       
    97 
       
    98     private BundleCheck(){}
       
    99 
       
   100     /**
       
   101      * Store the bundle check values as properties to the path specified.
       
   102      * Only invoked by SplitJRE.
       
   103      */
       
   104 
       
   105     public static void storeProperties(String fullPath)  {
       
   106 
       
   107         try {
       
   108             File f = new File(fullPath);
       
   109             f.getParentFile().mkdirs();
       
   110             OutputStream out = new FileOutputStream(f);
       
   111             properties.store(out, null);
       
   112             out.close();
       
   113         } catch (Exception e) {
       
   114             throw new RuntimeException(
       
   115                 "BundleCheck: storing properties threw: " + e);
       
   116         }
       
   117     }
       
   118 
       
   119     /**
       
   120      * Fetch the check value properties as a DownloadManager resource.
       
   121      */
       
   122 
       
   123     private static void loadProperties()  {
       
   124         properties = new Properties();
       
   125         try {
       
   126             InputStream in = new BufferedInputStream(
       
   127                 DownloadManager.class.getResourceAsStream(
       
   128                 DownloadManager.CHECK_VALUES_FILE));
       
   129             if (in == null)
       
   130                 throw new RuntimeException("BundleCheck: unable to locate " +
       
   131                     DownloadManager.CHECK_VALUES_FILE + " as resource");
       
   132             properties.load(in);
       
   133             in.close();
       
   134         } catch (Exception e) {
       
   135             throw new RuntimeException("BundleCheck: loadProperties threw " +
       
   136                 e);
       
   137         }
       
   138     }
       
   139 
       
   140     /* Get the check value Properties object */
       
   141 
       
   142     private synchronized static Properties getProperties() {
       
   143         if (properties == null) {
       
   144             // If this fails it means addProperty has been used inappropriately
       
   145             loadProperties();
       
   146         }
       
   147         return properties;
       
   148     }
       
   149 
       
   150     /* Reset the properties with an empty Properties object */
       
   151 
       
   152     public static void resetProperties() {
       
   153         properties = null;
       
   154     }
       
   155 
       
   156     /* The BundleCheck expressed as a String */
       
   157 
       
   158     public String toString() {
       
   159         return ByteArrayToFromHexDigits.bytesToHexString(checkBytes);
       
   160     }
       
   161 
       
   162     /* Add the given BundleCheck as a property to bundleCheckvalueProperties */
       
   163 
       
   164     private void addProperty(String name) {
       
   165         // When first called by SplitJRE just start with empty object
       
   166         // rather than allowing a load to happen, as it does at install time.
       
   167         if (properties == null) {
       
   168            properties = new Properties();
       
   169         }
       
   170         getProperties().put(name, toString());
       
   171     }
       
   172 
       
   173     /* private ctor for creating/initializing a BundleCheck */
       
   174 
       
   175     private BundleCheck(byte[] checkBytes) {
       
   176         this.checkBytes = checkBytes;
       
   177     }
       
   178 
       
   179     /* private ctor for creating a BundleCheck with a given name and known
       
   180        Property value. */
       
   181 
       
   182     private BundleCheck(String name) {
       
   183         String hexString = getProperties().getProperty(name);
       
   184         if  (hexString == null) {
       
   185             throw new RuntimeException(
       
   186                 "BundleCheck: no check property for bundle: " + name);
       
   187         }
       
   188         this.checkBytes = ByteArrayToFromHexDigits.hexStringToBytes(hexString);
       
   189     }
       
   190 
       
   191     /* Make a BundleCheck from the contents of the given file or a Bundle
       
   192        name. Save the new object's value as a property if saveProperty is
       
   193        true. Behavior is only defined for name or file being null, but not
       
   194        both, and for saveProperty to be true only when both name and file
       
   195        are not null.
       
   196        Any IO or other exception implies an unexpected and fatal internal
       
   197        error and results in a RuntimeException.  */
       
   198 
       
   199     private static BundleCheck getInstance(String name,
       
   200         File file, boolean saveProperty) {
       
   201         if (file == null ) {
       
   202             return new BundleCheck(name);
       
   203 
       
   204         } else {
       
   205             StandaloneMessageDigest checkDigest = null;
       
   206             try {
       
   207                 FileInputStream checkFileStream = new FileInputStream(file);
       
   208                 checkDigest = StandaloneMessageDigest.getInstance("SHA-1");
       
   209 
       
   210                 // Compute a check code across all of the file bytes.
       
   211                 // NOTE that every time a bundle is created, even from
       
   212                 // the "same bits", it may be different wrt to the security
       
   213                 // code because of slight variations build to build. For
       
   214                 // example, the JVM build normally contains an
       
   215                 // auto-incrementing build number, built archives might have
       
   216                 // timestamps, etc.
       
   217 
       
   218                 int readCount;
       
   219                 byte[] messageStreamBuff =
       
   220                     new byte[DIGEST_STREAM_BUFFER_SIZE];
       
   221                 do {
       
   222                     readCount = checkFileStream.read(messageStreamBuff);
       
   223                     if (readCount > 0) {
       
   224                         checkDigest.update(messageStreamBuff,0,readCount);
       
   225                     }
       
   226                 } while (readCount != -1);
       
   227                 checkFileStream.close();
       
   228 
       
   229             } catch (Exception e) {
       
   230                 throw new RuntimeException(
       
   231                     "BundleCheck.addProperty() caught: " + e);
       
   232             }
       
   233             BundleCheck bc = new BundleCheck(checkDigest.digest());
       
   234             if (saveProperty) {
       
   235                 bc.addProperty(name);
       
   236             }
       
   237             return bc;
       
   238         }
       
   239     }
       
   240 
       
   241     /* Create a BundleCheck from the given file */
       
   242 
       
   243     public static BundleCheck getInstance(File file) {
       
   244         return getInstance(null, file, false);
       
   245     }
       
   246 
       
   247     /* Create a BundleCheck from the given bundle name */
       
   248 
       
   249     static BundleCheck getInstance(String name) {
       
   250         return getInstance(name, null, false);
       
   251     }
       
   252 
       
   253     /* Create a BundleCheck from the given bundle name and file and
       
   254        use it to make and save a security check Property value. */
       
   255 
       
   256     public static void addProperty(String name,  File file) {
       
   257         getInstance(name, file, true);
       
   258     }
       
   259 
       
   260     /* Create a bundlecheck from the given bundle name and file and
       
   261        add a Property value for it. */
       
   262 
       
   263     static void add(String name, File file) {
       
   264         getInstance(name, file, true).addProperty(name);
       
   265     }
       
   266 
       
   267     /* Compare two BundkCheck instances for equal check values */
       
   268 
       
   269     boolean equals(BundleCheck b) {
       
   270         if ((checkBytes == null) || (b.checkBytes == null)) {
       
   271             return false;
       
   272         }
       
   273         if (checkBytes.length != b.checkBytes.length) {
       
   274             return false;
       
   275         }
       
   276         for (int i = 0; i < checkBytes.length; i++) {
       
   277             if (checkBytes[i] != b.checkBytes[i]) {
       
   278                 if (DownloadManager.debug) {
       
   279                     System.out.println(
       
   280                         "BundleCheck.equals mismatch between this: " +
       
   281                         toString() + " and param: " + b.toString());
       
   282                 }
       
   283                 return false;
       
   284             }
       
   285          }
       
   286          return true;
       
   287     }
       
   288 
       
   289     /* After SplitJRE is used to restructure the JRE into a "core JRE" and
       
   290        a set of Java Kernel "bundles", if extra compression is available
       
   291        the bundles are extracted and rearchived with zero compression by
       
   292        deploy build make steps. The newly compressed bundle names are then
       
   293        passed to this main with the path of the kernel core JRE to have new
       
   294        bundle security check values computed and the corresponding properties
       
   295        updated in rt.jar. If extra compression isn't available then this main is
       
   296        never used and the default jar/zip bundle compression and security
       
   297        codes created by SplitJRE are left in place and ready to use. */
       
   298 
       
   299     public static void main(String[] args) {
       
   300         if (args.length < 2) {
       
   301             System.err.println("Usage: java BundleCheck <jre path> " +
       
   302                 "<bundle 1 name> ... <bundle N name>");
       
   303             return;
       
   304         }
       
   305 
       
   306         // Make a security check code for each bundle file
       
   307         for (int arg = 1; arg < args.length; arg++) {
       
   308             BundleCheck.addProperty(args[arg],
       
   309                 new File(args[arg] + BUNDLE_SUFFIX));
       
   310         }
       
   311 
       
   312         // Store the new check code properties below the current directory
       
   313         BundleCheck.storeProperties(DownloadManager.CHECK_VALUES_DIR);
       
   314 
       
   315         // Now swap the new properties file into the core rt.jar
       
   316         try {
       
   317             int status = Runtime.getRuntime().exec(
       
   318                 "jar uf " + args[0] + "\\lib\\rt.jar " +
       
   319                 DownloadManager.CHECK_VALUES_DIR).waitFor();
       
   320             if (status != 0) {
       
   321                 System.err.println(
       
   322                     "BundleCheck: exec of jar uf gave nonzero status");
       
   323                 return;
       
   324             }
       
   325         } catch (Exception e) {
       
   326             System.err.println("BundleCheck: exec of jar uf threw: " + e);
       
   327             return;
       
   328         }
       
   329     } // main
       
   330 }