home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / security / Security.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  18.8 KB  |  651 lines

  1. /*
  2.  * @(#)Security.java    1.69 98/03/18
  3.  *
  4.  * Copyright 1996-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.security;
  16.  
  17. import java.lang.reflect.*;
  18. import java.util.*;
  19. import java.io.*;
  20.  
  21. /**
  22.  * <p>This class centralizes all security properties and common security
  23.  * methods. One of its primary uses is to manage providers.
  24.  *
  25.  * @author Benjamin Renaud
  26.  * @version 1.69, 98/03/18
  27.  */
  28.  
  29. public final class Security {
  30.  
  31.     /* Are we debugging? -- for developers */
  32.     static final boolean debug = false;
  33.  
  34.     /* Are we displaying errors? -- for users */
  35.     static final boolean error = true;
  36.  
  37.     /* The java.security properties */
  38.     private static Properties props; 
  39.  
  40.     /* A vector of providers, in order of priority */
  41.     private static Vector providers;
  42.  
  43.     // Where we cache provider properties
  44.     private static Hashtable providerPropertiesCache;
  45.  
  46.     // An element in the cache
  47.     static class ProviderProperty {
  48.     String property;
  49.     Provider provider;
  50.     }
  51.  
  52.     static {
  53.     try {
  54.         // beginPrivileged here because there are multiple
  55.         // things in initialize that might require privs.
  56.         // (the FileInputStream call and the File.exists call,
  57.         // the securityPropFile call, etc)
  58.         java.security.AccessController.beginPrivileged();
  59.         initialize();
  60.     } finally {
  61.         java.security.AccessController.endPrivileged();
  62.     }
  63.     }
  64.     
  65.     private static void initialize() {
  66.     props = new Properties();
  67.     providers = new Vector();
  68.     providerPropertiesCache = new Hashtable();
  69.  
  70.     File propFile = securityPropFile("java.security");
  71.     if (!propFile.exists()) {
  72.         System.err.println
  73.         ("security properties not found. using defaults.");
  74.         initializeStatic();
  75.     } else {
  76.         try {
  77.         FileInputStream fis = new FileInputStream(propFile);
  78.         InputStream is = new BufferedInputStream(fis);
  79.         props.load(is);
  80.         is.close();
  81.         } catch (IOException e) {
  82.         error("could not load security properties file from " +
  83.               propFile + ". using defaults.");
  84.         initializeStatic();
  85.         }
  86.     }
  87.     loadProviders();
  88.     }
  89.  
  90.     /* 
  91.      * Initialize to default values, if <java.home>/lib/java.security
  92.      * is not found.
  93.      */
  94.     private static void initializeStatic() {
  95.     props.put("security.provider.1", "sun.security.provider.Sun");
  96.     }
  97.  
  98.     /**
  99.      * Don't let anyone instantiate this. 
  100.      */
  101.     private Security() {
  102.     }
  103.  
  104.     /**
  105.      * Loops through provider declarations, which are expected to be
  106.      * of the form:
  107.      *
  108.      * security.provider.1=sun.security.provider.Sun
  109.      * security.provider.2=sun.security.jsafe.Jsafe
  110.      * etc.
  111.      *
  112.      * The order determines the default search order when looking for 
  113.      * an algorithm.
  114.      */
  115.     private static void loadProviders() {
  116.  
  117.     int i = 1;
  118.  
  119.     while(true) {
  120.  
  121.         String name = props.getProperty("security.provider." + i++);
  122.         if (name == null) {
  123.         break;
  124.  
  125.         } else {
  126.         Provider prov = Provider.loadProvider(name);
  127.         if (prov != null) {
  128.             /* This must manipulate the datastructure
  129.                directly, because going through addProviders
  130.                causes a security check to happen, which
  131.                sometimes will cause the security
  132.                initialization to fail with bad
  133.                consequences. */
  134.             providers.addElement(prov);
  135.         }
  136.         }
  137.     }
  138.     }
  139.  
  140.     static File securityPropFile(String filename) {
  141.     // maybe check for a system property which will specify where to
  142.     // look. Someday.
  143.     String sep = File.separator;
  144.     return new File(System.getProperty("java.home") + sep + "lib" + sep + 
  145.             "security" + sep + filename);
  146.     }
  147.  
  148.     /**
  149.      * Looks up providers, and returns the property (and its associated
  150.      * provider) mapping the key, if any.
  151.      * The order in which the providers are looked up is the
  152.      * provider-preference order, as specificed in the security
  153.      * properties file.
  154.      */
  155.     static ProviderProperty getProviderProperty(String key) {
  156.     String propName=null;
  157.  
  158.     ProviderProperty entry
  159.         = (ProviderProperty)providerPropertiesCache.get(key);
  160.     if (entry != null) {
  161.         return entry;
  162.     }
  163.  
  164.     for (int i = 0; i < providers.size(); i++) {
  165.  
  166.         Provider prov = (Provider)providers.elementAt(i);        
  167.         String prop = prov.getProperty(key);
  168.  
  169.         if (prop == null) {
  170.         // Is there a match if we do a case-insensitive property name
  171.         // comparison? Let's try ...
  172.         for (Enumeration e = prov.keys();
  173.              e.hasMoreElements() && prop==null; ) {
  174.             propName = (String)e.nextElement();
  175.             if (key.equalsIgnoreCase(propName)) {
  176.             prop = prov.getProperty(propName);
  177.             }
  178.         }
  179.         }
  180.  
  181.         if (prop != null) {
  182.         ProviderProperty newEntry = new ProviderProperty();
  183.         newEntry.property = prop;
  184.         newEntry.provider = prov;
  185.         providerPropertiesCache.put(key, newEntry);
  186.         if (propName != null) {
  187.             // Store the property value in the cache under the exact
  188.             // property name, as specified by the provider
  189.             providerPropertiesCache.put(propName, newEntry);
  190.         }
  191.         return newEntry;
  192.         }
  193.     }
  194.  
  195.     return entry;
  196.     }
  197.  
  198.     /**
  199.      * We always map names to standard names
  200.      */
  201.     static String getStandardName(String alias, String engineType) {
  202.     ProviderProperty entry = getProviderProperty("Alg.Alias." + engineType
  203.                              + "." + alias);
  204.     if (entry != null) {
  205.         return entry.property;
  206.     } else {
  207.         return null;
  208.     }
  209.     }
  210.  
  211.     /** 
  212.      * Gets a specified property for an algorithm. The algorithm name
  213.      * should be a standard name. See Appendix A in the <a href=
  214.      * "../guide/security/CryptoSpec.html#AppA">
  215.      * Java Cryptography Architecture API Specification & Reference </a> 
  216.      * for information about standard algorithm names.
  217.      * One possible use is by specialized algorithm parsers, which may map 
  218.      * classes to algorithms which they understand (much like Key parsers 
  219.      * do).
  220.      *
  221.      * @param algName the algorithm name.
  222.      *
  223.      * @param propName the name of the property to get.
  224.      * 
  225.      * @return the value of the specified property.  
  226.      */
  227.     public static String getAlgorithmProperty(String algName,
  228.                           String propName) {
  229.     ProviderProperty entry = getProviderProperty("Alg." + propName
  230.                              + "." + algName);
  231.     if (entry != null) {
  232.         return entry.property;
  233.     } else {
  234.         return null;
  235.     }
  236.     }
  237.  
  238.     /** 
  239.      * Given an algorithm name, returns the name of PublicKey class
  240.      * capable of handling keys for that algorithm. The algorithm name
  241.      * should be a standard name. See Appendix A in the <a href=
  242.      * "../guide/security/CryptoSpec.html#AppA">
  243.      * Java Cryptography Architecture API Specification & Reference </a> 
  244.      * for information about standard algorithm names.
  245.      *
  246.      * @param algName the standard algorithm name for which to get
  247.      * a public key class name.
  248.      */
  249.     static String getPublicKeyClassName(String algName, String format) {
  250.  
  251.     String stdName = getStandardName(algName, "Key");
  252.  
  253.     if (stdName == null) {
  254.         stdName = algName;
  255.     }
  256.  
  257.     String formatAndAlg = "PublicKey." + format + "." + stdName;
  258.     ProviderProperty entry = getProviderProperty(formatAndAlg);
  259.     if (entry != null) {
  260.         return entry.property;
  261.     } else {
  262.         return null;
  263.     }
  264.     }
  265.  
  266.  
  267.     /**
  268.      * Given an algorithm name, returns the name of PrivateKey class
  269.      * capable of handling keys for that algorithm. The algorithm name
  270.      * should be a standard name. See Appendix A in the <a href=
  271.      * "../guide/security/CryptoSpec.html#AppA">
  272.      * Java Cryptography Architecture API Specification & Reference </a> 
  273.      * for information about standard algorithm names.
  274.      */
  275.     static String getPrivateKeyClassName(String algName, String format) {
  276.  
  277.     String stdName = getStandardName(algName, "Key");
  278.  
  279.     if (stdName == null) {
  280.         stdName = algName;
  281.     }
  282.  
  283.     ProviderProperty entry = getProviderProperty("PrivateKey." + format
  284.                              + "." + stdName);
  285.     if (entry != null) {
  286.         return entry.property;
  287.     } else {
  288.         return null;
  289.     }
  290.     }
  291.  
  292.     static ProviderProperty getEngineClassName(String algName,
  293.                            String engineType)
  294.     throws NoSuchAlgorithmException {
  295.     /* First get the standard name */
  296.     String stdName = getStandardName(algName, engineType);    
  297.     if (stdName == null) {
  298.         stdName = algName;
  299.     }
  300.  
  301.     ProviderProperty entry = getProviderProperty(engineType
  302.                              + "." + stdName);
  303.     if (entry == null) {
  304.         throw new NoSuchAlgorithmException("algorithm " + algName
  305.                            + " not available.");
  306.     }
  307.  
  308.     return entry;
  309.     }
  310.  
  311.     /**
  312.      * Given an algorithm name, returns the name of Signature class
  313.      * capable of handling keys for that algorithm. The algorithm name
  314.      * should be a standard name. See Appendix A in the <a href=
  315.      * "../guide/security/CryptoSpec.html#AppA">
  316.      * Java Cryptography Architecture API Specification & Reference </a> 
  317.      * for information about standard algorithm names.
  318.      */
  319.     private static ProviderProperty getEngineClassName(String algName,
  320.                                String provider, 
  321.                                String engineType) 
  322.     throws NoSuchAlgorithmException, NoSuchProviderException {
  323.  
  324.     if (provider == null) {
  325.         return getEngineClassName(algName, engineType);
  326.     }
  327.  
  328.     /* First get the standard name */
  329.     String stdName = getStandardName(algName, engineType);
  330.     if (stdName == null) {
  331.         stdName = algName;
  332.     }
  333.  
  334.     Provider prov = getProvider(provider);
  335.     if (prov == null) {
  336.         throw new NoSuchProviderException("no such provider: " + provider);
  337.     }
  338.     
  339.     String key = engineType + "." + stdName;
  340.     String className = prov.getProperty(key);
  341.     if (className == null) {
  342.         // Is there a match if we do a case-insensitive property name
  343.         // comparison? Let's try ...
  344.         for (Enumeration e = prov.keys();
  345.          e.hasMoreElements() && className==null; ) {
  346.         String propName = (String)e.nextElement();
  347.         if (key.equalsIgnoreCase(propName)) {
  348.             className = prov.getProperty(propName);
  349.         }
  350.         }
  351.     }
  352.     if (className == null) {
  353.         throw new NoSuchAlgorithmException("no such algorithm: " + algName
  354.                            + " for provider " + provider);
  355.     }
  356.     
  357.     ProviderProperty entry = new ProviderProperty();
  358.     entry.property = className;
  359.     entry.provider = prov;
  360.  
  361.     return entry;
  362.     }
  363.  
  364.     /**
  365.      * Adds a new provider, at a specified position. The position is
  366.      * the preference order in which providers are searched for
  367.      * requested algorithms. Note that it is not guaranteed that this
  368.      * preference will be respected. The position is 1-based, that is,
  369.      * 1 is most preferred, followed by 2, and so on. Sometimes it
  370.      * will be legal to add a provider, but only in the last position,
  371.      * in which case the <code>position</code> argument will be ignored. 
  372.      * 
  373.      * <p>If the given provider is installed at the requested position,
  374.      * the provider that used to be at that position, and all providers
  375.      * with a position greater than <code>position</code>, are shifted up
  376.      * one position (towards the end of the list of installed providers).
  377.      * 
  378.      * <p>A provider cannot be added if it is already installed.
  379.      *
  380.      * @param provider the provider to be added.
  381.      *
  382.      * @param position the preference position that the caller would
  383.      * like for this provider.
  384.      *
  385.      * @return the actual preference position in which the provider was 
  386.      * added, or -1 if the provider was not added because it is
  387.      * already installed.
  388.      *
  389.      * @see #getProvider
  390.      * @see #removeProvider 
  391.      */
  392.     public static int insertProviderAt(Provider provider, int position) {
  393.  
  394.     check("Security.insertProvider."+provider.getName());
  395.  
  396.     /* First check if the provider is already installed */
  397.     Provider already = getProvider(provider.getName());
  398.     if (already != null) {
  399.         return -1;
  400.     }    
  401.         
  402.     int size = providers.size();
  403.     if (position > size || position <= 0) {
  404.         position = size+1;
  405.     }
  406.  
  407.     providers.insertElementAt(provider, position-1);
  408.  
  409.     // empty provider-property cache
  410.     providerPropertiesCache.clear();
  411.     
  412.     return position;
  413.     }
  414.  
  415.     /**
  416.      * Adds a provider to the next position available.
  417.      *
  418.      * @param provider the provider to be added.
  419.      *
  420.      * @return the preference position in which the provider was 
  421.      * added, or -1 if the provider was not added because it is
  422.      * already installed.
  423.      * 
  424.      * @see #getProvider
  425.      * @see #removeProvider
  426.      */
  427.     public static int addProvider(Provider provider) {
  428.     
  429.     return insertProviderAt(provider, providers.size() + 1);
  430.     }
  431.  
  432.     /**
  433.      * Removes the provider with the specified name.
  434.      *
  435.      * <p>When the specified provider is removed, all providers located
  436.      * at a position greater than where the specified provider was are shifted
  437.      * down one position (towards the head of the list of installed providers).
  438.      *
  439.      * <p>This method returns silently if the provider is not installed.
  440.      *
  441.      * @param name the name of the provider to remove.
  442.      *
  443.      * @see #getProvider
  444.      * @see #addProvider
  445.      */
  446.     public static void removeProvider(String name) {
  447.  
  448.     check("Security.removeProvider."+name);
  449.     
  450.     Provider provider = getProvider(name);
  451.  
  452.     if (provider != null) {
  453.         providers.removeElement(provider);
  454.     }
  455.     }
  456.  
  457.     
  458.     /**
  459.      * Returns all providers currently installed.
  460.      * 
  461.      * @return an array of all providers currently installed.
  462.      */
  463.     public static Provider[] getProviders() {
  464.     Provider[] result = new Provider[providers.size()];
  465.     providers.copyInto(result);
  466.     return result;
  467.     }
  468.  
  469.     /**
  470.      * Returns the provider installed with the specified name, if
  471.      * any. Returns null if no provider with the speicified name is
  472.      * installed.
  473.      * 
  474.      * @param name the name of the provider to get.
  475.      * 
  476.      * @return the provider of the specified name.
  477.      *
  478.      * @see #removeProvider
  479.      * @see #addProvider
  480.      */
  481.     public static Provider getProvider(String name) {
  482.     Enumeration enum = providers.elements();
  483.     while (enum.hasMoreElements()) {
  484.         Provider prov = (Provider)enum.nextElement();
  485.         if (prov.getName().equals(name)) {
  486.         return prov;
  487.         }
  488.     }
  489.     return null;
  490.     }
  491.  
  492.     private static boolean checkSuperclass(Class subclass, Class superclass) {
  493.     while(!subclass.equals(superclass)) {
  494.         subclass = subclass.getSuperclass();
  495.         if (subclass == null) {
  496.         return false;
  497.         }
  498.     }
  499.     return true;
  500.     }
  501.  
  502.     /*
  503.      * Returns an array of objects: the first object in the array is
  504.      * an instance of an implementation of the requested algorithm
  505.      * and type, and the second object in the array identifies the provider
  506.      * of that implementation.
  507.      * The <code>provider</code> argument can be null, in which case all
  508.      * configured providers will be searched in order of preference.
  509.      */
  510.     static Object[] getImpl(String algorithm, String type, String provider)
  511.     throws NoSuchAlgorithmException, NoSuchProviderException {    
  512.  
  513.     ProviderProperty classImpl = getEngineClassName(algorithm, provider,
  514.                             type);
  515.     String className = classImpl.property;
  516.  
  517.     try {
  518.  
  519.         Class typeClass = Class.forName("java.security." + type + "Spi");
  520.         Class cl = Class.forName(className);
  521.  
  522.         if (checkSuperclass(cl, typeClass)) {
  523.         Object obj = cl.newInstance();
  524.         return new Object[] { obj, classImpl.provider };
  525.         } else {
  526.         throw new NoSuchAlgorithmException("class configured for " + 
  527.                            type + ": " + className + 
  528.                            " not a " + type);
  529.         }
  530.     } catch (ClassNotFoundException e) {
  531.         throw new NoSuchAlgorithmException("class configured for " + 
  532.                            type + "(provider: " + 
  533.                            provider + ")" + 
  534.                            "cannot be found.\n" + 
  535.                            e.getMessage());
  536.     } catch (InstantiationException e) {
  537.         throw new NoSuchAlgorithmException("class " + className + 
  538.                            " configured for " + type +
  539.                            "(provider: " + provider + 
  540.                            ") cannot be instantiated.\n" + 
  541.                            e.getMessage());
  542.     } catch (IllegalAccessException e) {
  543.         throw new NoSuchAlgorithmException("class " + className + 
  544.                            " configured for " + type +
  545.                            "(provider: " + provider +
  546.                            ") cannot be accessed.\n" + 
  547.                            e.getMessage());
  548.     } catch (SecurityException e) {
  549.         throw new NoSuchAlgorithmException("class " + className + 
  550.                            " configured for " + type +
  551.                            "(provider: " + provider +
  552.                            ") cannot be accessed.\n" + 
  553.                            e.getMessage());
  554.     }
  555.     }
  556.  
  557.     /**
  558.      * Gets a security property.
  559.      *
  560.      * <p> If a security manager exists, its <code>checkPermission</code>
  561.      * method is called with the
  562.      * <code>java.security.SecurityPermission("Security.getProperty."+key)
  563.      * </code> permission. This may result in a security exception.
  564.      *
  565.      * @param key the key of the property being retrieved.
  566.      *
  567.      * @return the value of the security property corresponding to key.
  568.      *
  569.      * @exception java.lang.SecurityException if a security manager exists and
  570.      * the calling thread does not have permission to retrieve the specified
  571.      * security property.
  572.      */
  573.     public static String getProperty(String key) {
  574.     SecurityManager sm = System.getSecurityManager();
  575.     if (sm != null) {
  576.         sm.checkPermission(new SecurityPermission("Security.getProperty."+
  577.                               key));
  578.     }
  579.     return props.getProperty(key);
  580.     }
  581.  
  582.     /**
  583.      * Sets a security property.
  584.      *
  585.      * <p> If a security manager exists, its <code>checkPermission</code>
  586.      * method is called with the
  587.      * <code>java.security.SecurityPermission("Security.setProperty."+key)
  588.      * </code> permission. This may result in a security exception.
  589.      *
  590.      * @param key the name of the property to be set.
  591.      *
  592.      * @param datum the value of the property to be set.
  593.      *
  594.      * @exception java.lang.SecurityException if a security manager exists and
  595.      * the calling thread does not have permission to set the specified
  596.      * security property.
  597.      */
  598.     public static void setProperty(String key, String datum) {
  599.     check("Security.setProperty."+key);
  600.     props.put(key, datum);
  601.     }
  602.  
  603.     private static void check(String directive) {
  604.     
  605.     SecurityManager security = System.getSecurityManager();
  606.     if (security != null) {
  607.         security.checkSecurityAccess(directive);
  608.     }
  609.     }
  610.     
  611.     /**
  612.      * Print an error message that may be significant to a user.
  613.      */
  614.     static void error(String msg) {
  615.     if (debug) {
  616.         System.err.println(msg);
  617.     }
  618.     }
  619.  
  620.     /**
  621.      * Print an error message that may be significant to a user.
  622.      */
  623.     static void error(String msg, Throwable t) {
  624.     error(msg);
  625.     if (debug) {
  626.         t.printStackTrace();
  627.     }
  628.     }
  629.     
  630.     /**
  631.      * Print an debugging message that may be significant to a developer.
  632.      */
  633.     static void debug(String msg) {
  634.     if (debug) {
  635.         System.err.println(msg);
  636.     }
  637.     }
  638.  
  639.     /**
  640.      * Print an debugging message that may be significant to a developer.
  641.      */
  642.     static void debug(String msg, Throwable t) {
  643.     if (debug) {
  644.         t.printStackTrace();
  645.         System.err.println(msg);
  646.     }
  647.     }
  648. }
  649.     
  650.  
  651.