1 /*
   2  * Copyright (c) 1999, 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 
  26 package javax.crypto;
  27 
  28 import java.security.AlgorithmParameters;
  29 import java.security.Provider;
  30 import java.security.Key;
  31 import java.security.Security;
  32 import java.security.NoSuchAlgorithmException;
  33 import java.security.NoSuchProviderException;
  34 import java.security.InvalidKeyException;
  35 import java.security.InvalidAlgorithmParameterException;
  36 import java.security.spec.AlgorithmParameterSpec;
  37 
  38 import sun.security.jca.GetInstance.Instance;
  39 
  40 /**
  41  * This class provides the functionality of an exemption mechanism, examples
  42  * of which are <i>key recovery</i>, <i>key weakening</i>, and
  43  * <i>key escrow</i>.
  44  *
  45  * <p>Applications or applets that use an exemption mechanism may be granted
  46  * stronger encryption capabilities than those which don't.
  47  *
  48  * @since 1.4
  49  */
  50 
  51 public class ExemptionMechanism {
  52 
  53     // The provider
  54     private Provider provider;
  55 
  56     // The provider implementation (delegate)
  57     private ExemptionMechanismSpi exmechSpi;
  58 
  59     // The name of the exemption mechanism.
  60     private String mechanism;
  61 
  62     // Flag which indicates whether this ExemptionMechanism
  63     // result is generated successfully.
  64     private boolean done = false;
  65 
  66     // State information
  67     private boolean initialized = false;
  68 
  69     // Store away the key at init() time for later comparison.
  70     private Key keyStored = null;
  71 
  72     /**
  73      * Creates a ExemptionMechanism object.
  74      *
  75      * @param exmechSpi the delegate
  76      * @param provider the provider
  77      * @param mechanism the exemption mechanism
  78      */
  79     protected ExemptionMechanism(ExemptionMechanismSpi exmechSpi,
  80                                  Provider provider,
  81                                  String mechanism) {
  82         this.exmechSpi = exmechSpi;
  83         this.provider = provider;
  84         this.mechanism = mechanism;
  85     }
  86 
  87     /**
  88      * Returns the exemption mechanism name of this
  89      * <code>ExemptionMechanism</code> object.
  90      *
  91      * <p>This is the same name that was specified in one of the
  92      * <code>getInstance</code> calls that created this
  93      * <code>ExemptionMechanism</code> object.
  94      *
  95      * @return the exemption mechanism name of this
  96      * <code>ExemptionMechanism</code> object.
  97      */
  98     public final String getName() {
  99         return this.mechanism;
 100     }
 101 
 102     /**
 103      * Returns an <code>ExemptionMechanism</code> object that implements the
 104      * specified exemption mechanism algorithm.
 105      *
 106      * <p> This method traverses the list of registered security Providers,
 107      * starting with the most preferred Provider.
 108      * A new ExemptionMechanism object encapsulating the
 109      * ExemptionMechanismSpi implementation from the first
 110      * Provider that supports the specified algorithm is returned.
 111      *
 112      * <p> Note that the list of registered providers may be retrieved via
 113      * the {@link Security#getProviders() Security.getProviders()} method.
 114      *
 115      * @implNote
 116      * The JDK Reference Implementation additionally uses the
 117      * {@code jdk.security.provider.preferred} property to determine
 118      * the preferred provider order for the specified algorithm. This
 119      * may be different than the order of providers returned by
 120      * {@link Security#getProviders() Security.getProviders()}.
 121      *
 122      * @param algorithm the standard name of the requested exemption
 123      * mechanism.
 124      * See the ExemptionMechanism section in the
 125      * <a href=
 126      *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Exemption">
 127      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
 128      * for information about standard exemption mechanism names.
 129      *
 130      * @return the new <code>ExemptionMechanism</code> object.
 131      *
 132      * @exception NullPointerException if <code>algorithm</code>
 133      *          is null.
 134      *
 135      * @exception NoSuchAlgorithmException if no Provider supports an
 136      *          ExemptionMechanismSpi implementation for the
 137      *          specified algorithm.
 138      *
 139      * @see java.security.Provider
 140      */
 141     public static final ExemptionMechanism getInstance(String algorithm)
 142             throws NoSuchAlgorithmException {
 143         Instance instance = JceSecurity.getInstance("ExemptionMechanism",
 144                 ExemptionMechanismSpi.class, algorithm);
 145         return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl,
 146                 instance.provider, algorithm);
 147     }
 148 
 149 
 150     /**
 151      * Returns an <code>ExemptionMechanism</code> object that implements the
 152      * specified exemption mechanism algorithm.
 153      *
 154      * <p> A new ExemptionMechanism object encapsulating the
 155      * ExemptionMechanismSpi implementation from the specified provider
 156      * is returned.  The specified provider must be registered
 157      * in the security provider list.
 158      *
 159      * <p> Note that the list of registered providers may be retrieved via
 160      * the {@link Security#getProviders() Security.getProviders()} method.
 161 
 162      * @param algorithm the standard name of the requested exemption mechanism.
 163      * See the ExemptionMechanism section in the
 164      * <a href=
 165      *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Exemption">
 166      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
 167      * for information about standard exemption mechanism names.
 168      *
 169      * @param provider the name of the provider.
 170      *
 171      * @return the new <code>ExemptionMechanism</code> object.
 172      *
 173      * @exception NullPointerException if <code>algorithm</code>
 174      *          is null.
 175      *
 176      * @exception NoSuchAlgorithmException if an ExemptionMechanismSpi
 177      *          implementation for the specified algorithm is not
 178      *          available from the specified provider.
 179      *
 180      * @exception NoSuchProviderException if the specified provider is not
 181      *          registered in the security provider list.
 182      *
 183      * @exception IllegalArgumentException if the <code>provider</code>
 184      *          is null or empty.
 185      *
 186      * @see java.security.Provider
 187      */
 188     public static final ExemptionMechanism getInstance(String algorithm,
 189             String provider) throws NoSuchAlgorithmException,
 190             NoSuchProviderException {
 191         Instance instance = JceSecurity.getInstance("ExemptionMechanism",
 192                 ExemptionMechanismSpi.class, algorithm, provider);
 193         return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl,
 194                 instance.provider, algorithm);
 195     }
 196 
 197     /**
 198      * Returns an <code>ExemptionMechanism</code> object that implements the
 199      * specified exemption mechanism algorithm.
 200      *
 201      * <p> A new ExemptionMechanism object encapsulating the
 202      * ExemptionMechanismSpi implementation from the specified Provider
 203      * object is returned.  Note that the specified Provider object
 204      * does not have to be registered in the provider list.
 205      *
 206      * @param algorithm the standard name of the requested exemption mechanism.
 207      * See the ExemptionMechanism section in the
 208      * <a href=
 209      *   "{@docRoot}/../technotes/guides/security/StandardNames.html#Exemption">
 210      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
 211      * for information about standard exemption mechanism names.
 212      *
 213      * @param provider the provider.
 214      *
 215      * @return the new <code>ExemptionMechanism</code> object.
 216      *
 217      * @exception NullPointerException if <code>algorithm</code>
 218      *          is null.
 219      *
 220      * @exception NoSuchAlgorithmException if an ExemptionMechanismSpi
 221      *          implementation for the specified algorithm is not available
 222      *          from the specified Provider object.
 223      *
 224      * @exception IllegalArgumentException if the <code>provider</code>
 225      *          is null.
 226      *
 227      * @see java.security.Provider
 228      */
 229     public static final ExemptionMechanism getInstance(String algorithm,
 230             Provider provider) throws NoSuchAlgorithmException {
 231         Instance instance = JceSecurity.getInstance("ExemptionMechanism",
 232                 ExemptionMechanismSpi.class, algorithm, provider);
 233         return new ExemptionMechanism((ExemptionMechanismSpi)instance.impl,
 234                 instance.provider, algorithm);
 235     }
 236 
 237     /**
 238      * Returns the provider of this <code>ExemptionMechanism</code> object.
 239      *
 240      * @return the provider of this <code>ExemptionMechanism</code> object.
 241      */
 242     public final Provider getProvider() {
 243         return this.provider;
 244     }
 245 
 246     /**
 247      * Returns whether the result blob has been generated successfully by this
 248      * exemption mechanism.
 249      *
 250      * <p>The method also makes sure that the key passed in is the same as
 251      * the one this exemption mechanism used in initializing and generating
 252      * phases.
 253      *
 254      * @param key the key the crypto is going to use.
 255      *
 256      * @return whether the result blob of the same key has been generated
 257      * successfully by this exemption mechanism; false if <code>key</code>
 258      * is null.
 259      *
 260      * @exception ExemptionMechanismException if problem(s) encountered
 261      * while determining whether the result blob has been generated successfully
 262      * by this exemption mechanism object.
 263      */
 264     public final boolean isCryptoAllowed(Key key)
 265             throws ExemptionMechanismException {
 266         boolean ret = false;
 267         if (done && (key != null)) {
 268             // Check if the key passed in is the same as the one
 269             // this exemption mechanism used.
 270             ret = keyStored.equals(key);
 271         }
 272         return ret;
 273      }
 274 
 275     /**
 276      * Returns the length in bytes that an output buffer would need to be in
 277      * order to hold the result of the next
 278      * {@link #genExemptionBlob(byte[]) genExemptionBlob}
 279      * operation, given the input length <code>inputLen</code> (in bytes).
 280      *
 281      * <p>The actual output length of the next
 282      * {@link #genExemptionBlob(byte[]) genExemptionBlob}
 283      * call may be smaller than the length returned by this method.
 284      *
 285      * @param inputLen the input length (in bytes)
 286      *
 287      * @return the required output buffer size (in bytes)
 288      *
 289      * @exception IllegalStateException if this exemption mechanism is in a
 290      * wrong state (e.g., has not yet been initialized)
 291      */
 292     public final int getOutputSize(int inputLen) throws IllegalStateException {
 293         if (!initialized) {
 294             throw new IllegalStateException(
 295                 "ExemptionMechanism not initialized");
 296         }
 297         if (inputLen < 0) {
 298             throw new IllegalArgumentException(
 299                 "Input size must be equal to " + "or greater than zero");
 300         }
 301         return exmechSpi.engineGetOutputSize(inputLen);
 302     }
 303 
 304     /**
 305      * Initializes this exemption mechanism with a key.
 306      *
 307      * <p>If this exemption mechanism requires any algorithm parameters
 308      * that cannot be derived from the given <code>key</code>, the
 309      * underlying exemption mechanism implementation is supposed to
 310      * generate the required parameters itself (using provider-specific
 311      * default values); in the case that algorithm parameters must be
 312      * specified by the caller, an <code>InvalidKeyException</code> is raised.
 313      *
 314      * @param key the key for this exemption mechanism
 315      *
 316      * @exception InvalidKeyException if the given key is inappropriate for
 317      * this exemption mechanism.
 318      * @exception ExemptionMechanismException if problem(s) encountered in the
 319      * process of initializing.
 320      */
 321     public final void init(Key key)
 322             throws InvalidKeyException, ExemptionMechanismException {
 323         done = false;
 324         initialized = false;
 325 
 326         keyStored = key;
 327         exmechSpi.engineInit(key);
 328         initialized = true;
 329     }
 330 
 331     /**
 332      * Initializes this exemption mechanism with a key and a set of algorithm
 333      * parameters.
 334      *
 335      * <p>If this exemption mechanism requires any algorithm parameters
 336      * and <code>params</code> is null, the underlying exemption
 337      * mechanism implementation is supposed to generate the required
 338      * parameters itself (using provider-specific default values); in the case
 339      * that algorithm parameters must be specified by the caller, an
 340      * <code>InvalidAlgorithmParameterException</code> is raised.
 341      *
 342      * @param key the key for this exemption mechanism
 343      * @param params the algorithm parameters
 344      *
 345      * @exception InvalidKeyException if the given key is inappropriate for
 346      * this exemption mechanism.
 347      * @exception InvalidAlgorithmParameterException if the given algorithm
 348      * parameters are inappropriate for this exemption mechanism.
 349      * @exception ExemptionMechanismException if problem(s) encountered in the
 350      * process of initializing.
 351      */
 352     public final void init(Key key, AlgorithmParameterSpec params)
 353             throws InvalidKeyException, InvalidAlgorithmParameterException,
 354             ExemptionMechanismException {
 355         done = false;
 356         initialized = false;
 357 
 358         keyStored = key;
 359         exmechSpi.engineInit(key, params);
 360         initialized = true;
 361     }
 362 
 363     /**
 364      * Initializes this exemption mechanism with a key and a set of algorithm
 365      * parameters.
 366      *
 367      * <p>If this exemption mechanism requires any algorithm parameters
 368      * and <code>params</code> is null, the underlying exemption mechanism
 369      * implementation is supposed to generate the required parameters itself
 370      * (using provider-specific default values); in the case that algorithm
 371      * parameters must be specified by the caller, an
 372      * <code>InvalidAlgorithmParameterException</code> is raised.
 373      *
 374      * @param key the key for this exemption mechanism
 375      * @param params the algorithm parameters
 376      *
 377      * @exception InvalidKeyException if the given key is inappropriate for
 378      * this exemption mechanism.
 379      * @exception InvalidAlgorithmParameterException if the given algorithm
 380      * parameters are inappropriate for this exemption mechanism.
 381      * @exception ExemptionMechanismException if problem(s) encountered in the
 382      * process of initializing.
 383      */
 384     public final void init(Key key, AlgorithmParameters params)
 385             throws InvalidKeyException, InvalidAlgorithmParameterException,
 386             ExemptionMechanismException {
 387         done = false;
 388         initialized = false;
 389 
 390         keyStored = key;
 391         exmechSpi.engineInit(key, params);
 392         initialized = true;
 393     }
 394 
 395     /**
 396      * Generates the exemption mechanism key blob.
 397      *
 398      * @return the new buffer with the result key blob.
 399      *
 400      * @exception IllegalStateException if this exemption mechanism is in
 401      * a wrong state (e.g., has not been initialized).
 402      * @exception ExemptionMechanismException if problem(s) encountered in the
 403      * process of generating.
 404      */
 405     public final byte[] genExemptionBlob() throws IllegalStateException,
 406             ExemptionMechanismException {
 407         if (!initialized) {
 408             throw new IllegalStateException(
 409                 "ExemptionMechanism not initialized");
 410         }
 411         byte[] blob = exmechSpi.engineGenExemptionBlob();
 412         done = true;
 413         return blob;
 414     }
 415 
 416     /**
 417      * Generates the exemption mechanism key blob, and stores the result in
 418      * the <code>output</code> buffer.
 419      *
 420      * <p>If the <code>output</code> buffer is too small to hold the result,
 421      * a <code>ShortBufferException</code> is thrown. In this case, repeat this
 422      * call with a larger output buffer. Use
 423      * {@link #getOutputSize(int) getOutputSize} to determine how big
 424      * the output buffer should be.
 425      *
 426      * @param output the buffer for the result
 427      *
 428      * @return the number of bytes stored in <code>output</code>
 429      *
 430      * @exception IllegalStateException if this exemption mechanism is in
 431      * a wrong state (e.g., has not been initialized).
 432      * @exception ShortBufferException if the given output buffer is too small
 433      * to hold the result.
 434      * @exception ExemptionMechanismException if problem(s) encountered in the
 435      * process of generating.
 436      */
 437     public final int genExemptionBlob(byte[] output)
 438             throws IllegalStateException, ShortBufferException,
 439             ExemptionMechanismException {
 440         if (!initialized) {
 441             throw new IllegalStateException
 442             ("ExemptionMechanism not initialized");
 443         }
 444         int n = exmechSpi.engineGenExemptionBlob(output, 0);
 445         done = true;
 446         return n;
 447     }
 448 
 449     /**
 450      * Generates the exemption mechanism key blob, and stores the result in
 451      * the <code>output</code> buffer, starting at <code>outputOffset</code>
 452      * inclusive.
 453      *
 454      * <p>If the <code>output</code> buffer is too small to hold the result,
 455      * a <code>ShortBufferException</code> is thrown. In this case, repeat this
 456      * call with a larger output buffer. Use
 457      * {@link #getOutputSize(int) getOutputSize} to determine how big
 458      * the output buffer should be.
 459      *
 460      * @param output the buffer for the result
 461      * @param outputOffset the offset in <code>output</code> where the result
 462      * is stored
 463      *
 464      * @return the number of bytes stored in <code>output</code>
 465      *
 466      * @exception IllegalStateException if this exemption mechanism is in
 467      * a wrong state (e.g., has not been initialized).
 468      * @exception ShortBufferException if the given output buffer is too small
 469      * to hold the result.
 470      * @exception ExemptionMechanismException if problem(s) encountered in the
 471      * process of generating.
 472      */
 473     public final int genExemptionBlob(byte[] output, int outputOffset)
 474             throws IllegalStateException, ShortBufferException,
 475             ExemptionMechanismException {
 476         if (!initialized) {
 477             throw new IllegalStateException
 478             ("ExemptionMechanism not initialized");
 479         }
 480         int n = exmechSpi.engineGenExemptionBlob(output, outputOffset);
 481         done = true;
 482         return n;
 483     }
 484 
 485     /**
 486      * Ensures that the key stored away by this ExemptionMechanism
 487      * object will be wiped out when there are no more references to it.
 488      */
 489     protected void finalize() {
 490         keyStored = null;
 491         // Are there anything else we could do?
 492     }
 493 }