Signature.java 18.9 KB
Newer Older
Tom Tromey committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/* Signature.java --- Signature Class
   Copyright (C) 1999, 2002, 2003, 2004  Free Software Foundation, Inc.

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */


package java.security;

41 42
import gnu.java.lang.CPStringBuilder;

Tom Tromey committed
43 44
import gnu.java.security.Engine;

45 46
import java.lang.reflect.InvocationTargetException;
import java.nio.ByteBuffer;
Tom Tromey committed
47 48 49 50 51
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;

/**
52 53 54
 * <code>Signature</code> is used to provide an interface to digital signature
 * algorithms. Digital signatures provide authentication and data integrity of
 * digital data.
55
 *
56 57 58 59
 * <p>The GNU provider provides the NIST standard DSA which uses DSA and SHA-1.
 * It can be specified by SHA/DSA, SHA-1/DSA or its OID. If the RSA signature
 * algorithm is provided then it could be MD2/RSA. MD5/RSA, or SHA-1/RSA. The
 * algorithm must be specified because there is no default.</p>
60
 *
61 62 63 64
 * <p>Signature provides implementation-independent algorithms which are
 * requested by the user through the <code>getInstance()<?code> methods. It can
 * be requested by specifying just the algorithm name or by specifying both the
 * algorithm name and provider name.</p>
65
 *
66
 * <p>The three phases of using <code>Signature</code> are:</p>
67
 *
Tom Tromey committed
68
 * <ol>
69
 *   <li>Initializing:
Tom Tromey committed
70
 *     <ul>
71 72 73
 *       <li>It must be initialized with a private key for signing.</li>
 *       <li>It must be initialized with a public key for verifying.</li>
 *   </li>
74
 *
75 76 77
 *   <li>Updating:
 *   <p>Update the bytes for signing or verifying with calls to update.</p>
 *   </li>
78
 *
79 80 81
 *   <li>Signing or Verify the signature on the currently stored bytes by
 *   calling sign or verify.</li>
 * </ol>
Tom Tromey committed
82 83 84 85 86 87 88 89 90
 *
 * @author Mark Benvenuto  (ivymccough@worldnet.att.net)
 */
public abstract class Signature extends SignatureSpi
{
  /** Service name for signatures. */
  private static final String SIGNATURE = "Signature";

  /**
91 92
   * Possible state value which signifies that this instance has not yet been
   * initialized.
Tom Tromey committed
93 94 95 96
   */
  protected static final int UNINITIALIZED = 0;

  /**
97 98
   * Possible state value which signifies that this instance has been
   * initialized for signing purposes.
Tom Tromey committed
99 100 101 102
   */
  protected static final int SIGN = 2;

  /**
103 104
   * Possible state value which signifies that this instance has been
   * initialized for verification purposes.
Tom Tromey committed
105 106 107
   */
  protected static final int VERIFY = 3;

108
  /** Current sate of this instance. */
Tom Tromey committed
109 110 111 112 113
  protected int state = UNINITIALIZED;

  private String algorithm;
  Provider provider;

114 115 116
  // Constructor.
  // ------------------------------------------------------------------------

Tom Tromey committed
117
  /**
118 119
   * Constructs a new <code>Signature</code> instance for a designated digital
   * signature algorithm.
120
   *
121 122
   * @param algorithm
   *          the algorithm to use.
Tom Tromey committed
123 124 125 126 127 128 129 130
   */
  protected Signature(String algorithm)
  {
    this.algorithm = algorithm;
    state = UNINITIALIZED;
  }

  /**
131 132
   * Returns an instance of <code>Signature</code> representing the specified
   * signature.
133
   *
134
   * @param algorithm the algorithm to use.
135
   * @return a new instance repesenting the desired algorithm.
136 137 138 139
   * @throws NoSuchAlgorithmException if the algorithm is not implemented by any
   *           provider.
   * @throws IllegalArgumentException if <code>algorithm</code> is
   *           <code>null</code> or is an empty string.
Tom Tromey committed
140 141
   */
  public static Signature getInstance(String algorithm)
142
      throws NoSuchAlgorithmException
Tom Tromey committed
143 144
  {
    Provider[] p = Security.getProviders();
145
    NoSuchAlgorithmException lastException = null;
Tom Tromey committed
146
    for (int i = 0; i < p.length; i++)
147 148 149 150 151 152 153 154 155 156
      try
        {
          return getInstance(algorithm, p[i]);
        }
      catch (NoSuchAlgorithmException x)
        {
          lastException = x;
        }
    if (lastException != null)
      throw lastException;
Tom Tromey committed
157 158 159 160
    throw new NoSuchAlgorithmException(algorithm);
  }

  /**
161 162
   * Returns an instance of <code>Signature</code> representing the specified
   * signature from the named provider.
163
   *
164 165
   * @param algorithm the algorithm to use.
   * @param provider the name of the provider to use.
166
   * @return a new instance repesenting the desired algorithm.
167 168 169 170 171
   * @throws NoSuchProviderException if the named provider was not found.
   * @throws NoSuchAlgorithmException if the algorithm is not implemented by the
   *           named provider.
   * @throws IllegalArgumentException if either <code>algorithm</code> or
   *           <code>provider</code> is <code>null</code> or empty.
Tom Tromey committed
172 173
   */
  public static Signature getInstance(String algorithm, String provider)
174
      throws NoSuchAlgorithmException, NoSuchProviderException
Tom Tromey committed
175
  {
176 177 178 179 180
    if (provider == null)
      throw new IllegalArgumentException("provider MUST NOT be null");
    provider = provider.trim();
    if (provider.length() == 0)
      throw new IllegalArgumentException("provider MUST NOT be empty");
Tom Tromey committed
181 182 183 184 185 186 187
    Provider p = Security.getProvider(provider);
    if (p == null)
      throw new NoSuchProviderException(provider);
    return getInstance(algorithm, p);
  }

  /**
188 189
   * Returns an instance of <code>Signature</code> representing the specified
   * signature from the specified {@link Provider}.
190
   *
191 192
   * @param algorithm the algorithm to use.
   * @param provider the {@link Provider} to use.
193
   * @return a new instance repesenting the desired algorithm.
194 195 196 197 198
   * @throws NoSuchAlgorithmException if the algorithm is not implemented by the
   *           {@link Provider}.
   * @throws IllegalArgumentException if either <code>algorithm</code> or
   *           <code>provider</code> is <code>null</code>, or if
   *           <code>algorithm</code> is an empty string.
Tom Tromey committed
199 200 201 202
   */
  public static Signature getInstance(String algorithm, Provider provider)
    throws NoSuchAlgorithmException
  {
203
    CPStringBuilder sb = new CPStringBuilder("Signature algorithm [")
204 205 206
        .append(algorithm).append("] from provider[")
        .append(provider).append("] ");
    Object o;
Tom Tromey committed
207 208 209 210
    try
      {
        o = Engine.getInstance(SIGNATURE, algorithm, provider);
      }
211
    catch (InvocationTargetException x)
Tom Tromey committed
212
      {
213 214 215 216 217 218 219 220 221
        Throwable cause = x.getCause();
        if (cause instanceof NoSuchAlgorithmException)
          throw (NoSuchAlgorithmException) cause;
        if (cause == null)
          cause = x;
        sb.append("could not be created");
        NoSuchAlgorithmException y = new NoSuchAlgorithmException(sb.toString());
        y.initCause(cause);
        throw y;
Tom Tromey committed
222
      }
223
    Signature result;
Tom Tromey committed
224
    if (o instanceof SignatureSpi)
225
      result = new DummySignature((SignatureSpi) o, algorithm);
Tom Tromey committed
226 227 228 229 230 231 232
    else if (o instanceof Signature)
      {
        result = (Signature) o;
        result.algorithm = algorithm;
      }
    else
      {
233 234
        sb.append("is of an unexpected Type: ").append(o.getClass().getName());
        throw new NoSuchAlgorithmException(sb.toString());
Tom Tromey committed
235 236 237 238 239 240
      }
    result.provider = provider;
    return result;
  }

  /**
241
   * Returns the {@link Provider} of this instance.
242
   *
243
   * @return the {@link Provider} of this instance.
Tom Tromey committed
244 245 246 247 248 249 250
   */
  public final Provider getProvider()
  {
    return provider;
  }

  /**
251
   * Initializes this instance with the public key for verification purposes.
252
   *
253 254 255 256
   * @param publicKey
   *          the public key to verify with.
   * @throws InvalidKeyException
   *           if the key is invalid.
Tom Tromey committed
257 258 259 260 261 262 263 264
   */
  public final void initVerify(PublicKey publicKey) throws InvalidKeyException
  {
    state = VERIFY;
    engineInitVerify(publicKey);
  }

  /**
265 266
   * Verify a signature with a designated {@link Certificate}. This is a FIPS
   * 140-1 compatible method since it verifies a signature with a certificate.
267
   *
268 269 270
   * <p>If the {@link Certificate} is an X.509 one, has a <i>KeyUsage</i>
   * parameter and that parameter indicates this key is not to be used for
   * signing then an exception is thrown.</p>
271
   *
272 273 274
   * @param certificate
   *          a {@link Certificate} containing a public key to verify with.
   * @throws InvalidKeyException if the key is invalid.
Tom Tromey committed
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
   */
  public final void initVerify(Certificate certificate)
    throws InvalidKeyException
  {
    state = VERIFY;
    if (certificate.getType().equals("X509"))
      {
        X509Certificate cert = (X509Certificate) certificate;
        boolean[]array = cert.getKeyUsage();
        if (array != null && array[0] == false)
          throw new InvalidKeyException(
              "KeyUsage of this Certificate indicates it cannot be used for digital signing");
      }
    this.initVerify(certificate.getPublicKey());
  }

  /**
292
   * Initializes this class with the private key for signing purposes.
293
   *
294 295 296 297
   * @param privateKey
   *          the private key to sign with.
   * @throws InvalidKeyException
   *           if the key is invalid.
Tom Tromey committed
298 299 300 301 302 303 304 305
   */
  public final void initSign(PrivateKey privateKey) throws InvalidKeyException
  {
    state = SIGN;
    engineInitSign(privateKey);
  }

  /**
306 307
   * Initializes this class with the private key and source of randomness for
   * signing purposes.
308
   *
309 310 311 312 313 314
   * @param privateKey
   *          the private key to sign with.
   * @param random
   *          the {@link SecureRandom} to use.
   * @throws InvalidKeyException
   *           if the key is invalid.
Tom Tromey committed
315 316 317 318 319 320 321 322 323
   */
  public final void initSign(PrivateKey privateKey, SecureRandom random)
    throws InvalidKeyException
  {
    state = SIGN;
    engineInitSign(privateKey, random);
  }

  /**
324 325
   * Returns the signature bytes of all the data fed to this instance. The
   * format of the output depends on the underlying signature algorithm.
326
   *
327 328 329
   * @return the signature bytes.
   * @throws SignatureException
   *           if the engine is not properly initialized.
Tom Tromey committed
330 331 332 333 334 335 336 337 338 339
   */
  public final byte[] sign() throws SignatureException
  {
    if (state == SIGN)
      return engineSign();
    else
      throw new SignatureException();
  }

  /**
340 341 342
   * Generates signature bytes of all the data fed to this instance and stores
   * it in the designated array. The format of the result depends on the
   * underlying signature algorithm.
343
   *
344 345
   * <p>After calling this method, the instance is reset to its initial state
   * and can then be used to generate additional signatures.</p>
346
   *
347 348 349 350
   * <p><b>IMPLEMENTATION NOTE:</b> Neither this method nor the GNU provider
   * will return partial digests. If <code>len</code> is less than the
   * signature length, this method will throw a {@link SignatureException}. If
   * it is greater than or equal then it is ignored.</p>
351
   *
352 353 354 355 356 357 358 359 360
   * @param outbuf
   *          array of bytes of where to store the resulting signature bytes.
   * @param offset
   *          the offset to start at in the array.
   * @param len
   *          the number of the bytes to use in the array.
   * @return the real number of bytes used.
   * @throws SignatureException
   *           if the engine is not properly initialized.
Tom Tromey committed
361 362 363 364 365 366 367 368 369 370 371 372
   * @since 1.2
   */
  public final int sign(byte[] outbuf, int offset, int len)
    throws SignatureException
  {
    if (state == SIGN)
      return engineSign(outbuf, offset, len);
    else
      throw new SignatureException();
  }

  /**
373
   * Verifies a designated signature.
374
   *
375 376 377 378 379 380
   * @param signature
   *          the signature bytes to verify.
   * @return <code>true</code> if verified, <code>false</code> otherwise.
   * @throws SignatureException
   *           if the engine is not properly initialized or the signature does
   *           not check.
Tom Tromey committed
381 382 383 384 385 386 387 388 389 390
   */
  public final boolean verify(byte[]signature) throws SignatureException
  {
    if (state == VERIFY)
      return engineVerify(signature);
    else
      throw new SignatureException();
  }

  /**
391
   * Verifies a designated signature.
392
   *
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
   * @param signature
   *          the signature bytes to verify.
   * @param offset
   *          the offset to start at in the array.
   * @param length
   *          the number of the bytes to use from the array.
   * @return <code>true</code> if verified, <code>false</code> otherwise.
   * @throws IllegalArgumentException
   *           if the <code>signature</code> byte array is <code>null</code>,
   *           or the <code>offset</code> or <code>length</code> is less
   *           than <code>0</code>, or the sum of the <code>offset</code>
   *           and <code>length</code> is greater than the length of the
   *           <code>signature</code> byte array.
   * @throws SignatureException
   *           if the engine is not properly initialized or the signature does
   *           not check.
Tom Tromey committed
409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
   */
  public final boolean verify(byte[] signature, int offset, int length)
    throws SignatureException
  {
    if (state != VERIFY)
      throw new SignatureException("illegal state");

    if (signature == null)
      throw new IllegalArgumentException("signature is null");
    if (offset < 0)
      throw new IllegalArgumentException("offset is less than 0");
    if (length < 0)
      throw new IllegalArgumentException("length is less than 0");
    if (offset + length < signature.length)
      throw new IllegalArgumentException("range is out of bounds");

    return engineVerify(signature, offset, length);
  }

  /**
429
   * Updates the data to be signed or verified with the specified byte.
430
   *
431 432 433 434
   * @param b
   *          the byte to update with.
   * @throws SignatureException
   *           if the engine is not properly initialized.
Tom Tromey committed
435 436 437 438 439 440 441 442 443 444
   */
  public final void update(byte b) throws SignatureException
  {
    if (state != UNINITIALIZED)
      engineUpdate(b);
    else
      throw new SignatureException();
  }

  /**
445
   * Updates the data to be signed or verified with the specified bytes.
446
   *
447 448 449 450
   * @param data
   *          the array of bytes to use.
   * @throws SignatureException
   *           if the engine is not properly initialized.
Tom Tromey committed
451 452 453 454 455 456 457 458 459 460
   */
  public final void update(byte[]data) throws SignatureException
  {
    if (state != UNINITIALIZED)
      engineUpdate(data, 0, data.length);
    else
      throw new SignatureException();
  }

  /**
461
   * Updates the data to be signed or verified with the specified bytes.
462
   *
463 464 465 466 467 468 469 470
   * @param data
   *          an array of bytes to use.
   * @param off
   *          the offset to start at in the array.
   * @param len
   *          the number of bytes to use from the array.
   * @throws SignatureException
   *           if the engine is not properly initialized.
Tom Tromey committed
471 472 473 474 475 476 477 478 479
   */
  public final void update(byte[]data, int off, int len)
    throws SignatureException
  {
    if (state != UNINITIALIZED)
      engineUpdate(data, off, len);
    else
      throw new SignatureException();
  }
480

481 482 483
  /**
   * Update this signature with the {@link java.nio.Buffer#remaining()}
   * bytes of the input buffer.
484
   *
485 486 487 488 489 490 491 492 493 494 495
   * @param input The input buffer.
   * @throws SignatureException If this instance was not properly
   *  initialized.
   */
  public final void update(ByteBuffer input) throws SignatureException
  {
    if (state != UNINITIALIZED)
      engineUpdate(input);
    else
      throw new SignatureException("not initialized");
  }
Tom Tromey committed
496 497

  /**
498 499
   * Returns the name of the algorithm currently used. The names of algorithms
   * are usually SHA/DSA or SHA/RSA.
500
   *
501
   * @return name of algorithm.
Tom Tromey committed
502 503 504 505 506 507 508
   */
  public final String getAlgorithm()
  {
    return algorithm;
  }

  /**
509
   * Returns a rstring representation of this instance.
510
   *
511
   * @return a rstring representation of this instance.
Tom Tromey committed
512 513 514 515 516 517 518
   */
  public String toString()
  {
    return (algorithm + " Signature");
  }

  /**
519
   * Sets the specified algorithm parameter to the specified value.
520
   *
521 522 523 524 525 526 527 528
   * @param param
   *          the parameter name.
   * @param value
   *          the parameter value.
   * @throws InvalidParameterException
   *           if the parameter is invalid, the parameter is already set and
   *           can not be changed, a security exception occured, etc.
   * @deprecated use the other setParameter
Tom Tromey committed
529 530 531 532 533 534 535 536
   */
  public final void setParameter(String param, Object value)
    throws InvalidParameterException
  {
    engineSetParameter(param, value);
  }

  /**
537
   * Sets the signature engine with the specified {@link AlgorithmParameterSpec}.
538
   *
539 540
   * <p>By default, and unless overriden by the concrete SPI, this method always
   * throws an {@link UnsupportedOperationException}.</p>
541
   *
542 543 544 545 546
   * @param params
   *          the parameters to use for intializing this instance.
   * @throws InvalidParameterException
   *           if the parameter is invalid, the parameter is already set and
   *           cannot be changed, a security exception occured, etc.
Tom Tromey committed
547 548 549 550 551 552 553 554
   */
  public final void setParameter(AlgorithmParameterSpec params)
    throws InvalidAlgorithmParameterException
  {
    engineSetParameter(params);
  }

  /**
555 556
   * Return the parameters of the algorithm used in this instance as an
   * {@link AlgorithmParameters}.
557
   *
558 559
   * @return the parameters used with this instance, or <code>null</code> if
   *         this instance does not use any parameters.
Tom Tromey committed
560 561 562 563 564 565 566
   */
  public final AlgorithmParameters getParameters()
  {
    return engineGetParameters();
  }

  /**
567
   * Returns the value for the specified algorithm parameter.
568
   *
569 570 571 572 573 574
   * @param param
   *          the parameter name.
   * @return the parameter value.
   * @throws InvalidParameterException
   *           if the parameter is invalid.
   * @deprecated use the other getParameter
Tom Tromey committed
575 576 577 578 579 580 581 582
   */
  public final Object getParameter(String param)
    throws InvalidParameterException
  {
    return engineGetParameter(param);
  }

  /**
583
   * Returns a clone of this instance.
584
   *
585 586 587
   * @return a clone of this instace.
   * @throws CloneNotSupportedException
   *           if the implementation does not support cloning.
Tom Tromey committed
588 589 590 591 592 593
   */
  public Object clone() throws CloneNotSupportedException
  {
    return super.clone();
  }
}