1 /* Signature.java --- Signature Class 2 Copyright (C) 1999, 2002, 2003, 2004 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package java.security; 40 41 import gnu.java.lang.CPStringBuilder; 42 43 import gnu.java.security.Engine; 44 45 import java.lang.reflect.InvocationTargetException; 46 import java.nio.ByteBuffer; 47 import java.security.cert.Certificate; 48 import java.security.cert.X509Certificate; 49 import java.security.spec.AlgorithmParameterSpec; 50 51 /** 52 * <code>Signature</code> is used to provide an interface to digital signature 53 * algorithms. Digital signatures provide authentication and data integrity of 54 * digital data. 55 * 56 * <p>The GNU provider provides the NIST standard DSA which uses DSA and SHA-1. 57 * It can be specified by SHA/DSA, SHA-1/DSA or its OID. If the RSA signature 58 * algorithm is provided then it could be MD2/RSA. MD5/RSA, or SHA-1/RSA. The 59 * algorithm must be specified because there is no default.</p> 60 * 61 * <p>Signature provides implementation-independent algorithms which are 62 * requested by the user through the <code>getInstance()<?code> methods. It can 63 * be requested by specifying just the algorithm name or by specifying both the 64 * algorithm name and provider name.</p> 65 * 66 * <p>The three phases of using <code>Signature</code> are:</p> 67 * 68 * <ol> 69 * <li>Initializing: 70 * <ul> 71 * <li>It must be initialized with a private key for signing.</li> 72 * <li>It must be initialized with a public key for verifying.</li> 73 * </li> 74 * 75 * <li>Updating: 76 * <p>Update the bytes for signing or verifying with calls to update.</p> 77 * </li> 78 * 79 * <li>Signing or Verify the signature on the currently stored bytes by 80 * calling sign or verify.</li> 81 * </ol> 82 * 83 * @author Mark Benvenuto (ivymccough@worldnet.att.net) 84 */ 85 public abstract class Signature extends SignatureSpi 86 { 87 /** Service name for signatures. */ 88 private static final String SIGNATURE = "Signature"; 89 90 /** 91 * Possible state value which signifies that this instance has not yet been 92 * initialized. 93 */ 94 protected static final int UNINITIALIZED = 0; 95 96 /** 97 * Possible state value which signifies that this instance has been 98 * initialized for signing purposes. 99 */ 100 protected static final int SIGN = 2; 101 102 /** 103 * Possible state value which signifies that this instance has been 104 * initialized for verification purposes. 105 */ 106 protected static final int VERIFY = 3; 107 108 /** Current sate of this instance. */ 109 protected int state = UNINITIALIZED; 110 111 private String algorithm; 112 Provider provider; 113 114 // Constructor. 115 // ------------------------------------------------------------------------ 116 117 /** 118 * Constructs a new <code>Signature</code> instance for a designated digital 119 * signature algorithm. 120 * 121 * @param algorithm 122 * the algorithm to use. 123 */ Signature(String algorithm)124 protected Signature(String algorithm) 125 { 126 this.algorithm = algorithm; 127 state = UNINITIALIZED; 128 } 129 130 /** 131 * Returns an instance of <code>Signature</code> representing the specified 132 * signature. 133 * 134 * @param algorithm the algorithm to use. 135 * @return a new instance repesenting the desired algorithm. 136 * @throws NoSuchAlgorithmException if the algorithm is not implemented by any 137 * provider. 138 * @throws IllegalArgumentException if <code>algorithm</code> is 139 * <code>null</code> or is an empty string. 140 */ getInstance(String algorithm)141 public static Signature getInstance(String algorithm) 142 throws NoSuchAlgorithmException 143 { 144 Provider[] p = Security.getProviders(); 145 NoSuchAlgorithmException lastException = null; 146 for (int i = 0; i < p.length; i++) 147 try 148 { 149 return getInstance(algorithm, p[i]); 150 } 151 catch (NoSuchAlgorithmException x) 152 { 153 lastException = x; 154 } 155 if (lastException != null) 156 throw lastException; 157 throw new NoSuchAlgorithmException(algorithm); 158 } 159 160 /** 161 * Returns an instance of <code>Signature</code> representing the specified 162 * signature from the named provider. 163 * 164 * @param algorithm the algorithm to use. 165 * @param provider the name of the provider to use. 166 * @return a new instance repesenting the desired algorithm. 167 * @throws NoSuchProviderException if the named provider was not found. 168 * @throws NoSuchAlgorithmException if the algorithm is not implemented by the 169 * named provider. 170 * @throws IllegalArgumentException if either <code>algorithm</code> or 171 * <code>provider</code> is <code>null</code> or empty. 172 */ getInstance(String algorithm, String provider)173 public static Signature getInstance(String algorithm, String provider) 174 throws NoSuchAlgorithmException, NoSuchProviderException 175 { 176 if (provider == null) 177 throw new IllegalArgumentException("provider MUST NOT be null"); 178 provider = provider.trim(); 179 if (provider.length() == 0) 180 throw new IllegalArgumentException("provider MUST NOT be empty"); 181 Provider p = Security.getProvider(provider); 182 if (p == null) 183 throw new NoSuchProviderException(provider); 184 return getInstance(algorithm, p); 185 } 186 187 /** 188 * Returns an instance of <code>Signature</code> representing the specified 189 * signature from the specified {@link Provider}. 190 * 191 * @param algorithm the algorithm to use. 192 * @param provider the {@link Provider} to use. 193 * @return a new instance repesenting the desired algorithm. 194 * @throws NoSuchAlgorithmException if the algorithm is not implemented by the 195 * {@link Provider}. 196 * @throws IllegalArgumentException if either <code>algorithm</code> or 197 * <code>provider</code> is <code>null</code>, or if 198 * <code>algorithm</code> is an empty string. 199 */ getInstance(String algorithm, Provider provider)200 public static Signature getInstance(String algorithm, Provider provider) 201 throws NoSuchAlgorithmException 202 { 203 CPStringBuilder sb = new CPStringBuilder("Signature algorithm [") 204 .append(algorithm).append("] from provider[") 205 .append(provider).append("] "); 206 Object o; 207 try 208 { 209 o = Engine.getInstance(SIGNATURE, algorithm, provider); 210 } 211 catch (InvocationTargetException x) 212 { 213 Throwable cause = x.getCause(); 214 if (cause instanceof NoSuchAlgorithmException) 215 throw (NoSuchAlgorithmException) cause; 216 if (cause == null) 217 cause = x; 218 sb.append("could not be created"); 219 NoSuchAlgorithmException y = new NoSuchAlgorithmException(sb.toString()); 220 y.initCause(cause); 221 throw y; 222 } 223 Signature result; 224 if (o instanceof SignatureSpi) 225 result = new DummySignature((SignatureSpi) o, algorithm); 226 else if (o instanceof Signature) 227 { 228 result = (Signature) o; 229 result.algorithm = algorithm; 230 } 231 else 232 { 233 sb.append("is of an unexpected Type: ").append(o.getClass().getName()); 234 throw new NoSuchAlgorithmException(sb.toString()); 235 } 236 result.provider = provider; 237 return result; 238 } 239 240 /** 241 * Returns the {@link Provider} of this instance. 242 * 243 * @return the {@link Provider} of this instance. 244 */ getProvider()245 public final Provider getProvider() 246 { 247 return provider; 248 } 249 250 /** 251 * Initializes this instance with the public key for verification purposes. 252 * 253 * @param publicKey 254 * the public key to verify with. 255 * @throws InvalidKeyException 256 * if the key is invalid. 257 */ initVerify(PublicKey publicKey)258 public final void initVerify(PublicKey publicKey) throws InvalidKeyException 259 { 260 state = VERIFY; 261 engineInitVerify(publicKey); 262 } 263 264 /** 265 * Verify a signature with a designated {@link Certificate}. This is a FIPS 266 * 140-1 compatible method since it verifies a signature with a certificate. 267 * 268 * <p>If the {@link Certificate} is an X.509 one, has a <i>KeyUsage</i> 269 * parameter and that parameter indicates this key is not to be used for 270 * signing then an exception is thrown.</p> 271 * 272 * @param certificate 273 * a {@link Certificate} containing a public key to verify with. 274 * @throws InvalidKeyException if the key is invalid. 275 */ initVerify(Certificate certificate)276 public final void initVerify(Certificate certificate) 277 throws InvalidKeyException 278 { 279 state = VERIFY; 280 if (certificate.getType().equals("X509")) 281 { 282 X509Certificate cert = (X509Certificate) certificate; 283 boolean[]array = cert.getKeyUsage(); 284 if (array != null && array[0] == false) 285 throw new InvalidKeyException( 286 "KeyUsage of this Certificate indicates it cannot be used for digital signing"); 287 } 288 this.initVerify(certificate.getPublicKey()); 289 } 290 291 /** 292 * Initializes this class with the private key for signing purposes. 293 * 294 * @param privateKey 295 * the private key to sign with. 296 * @throws InvalidKeyException 297 * if the key is invalid. 298 */ initSign(PrivateKey privateKey)299 public final void initSign(PrivateKey privateKey) throws InvalidKeyException 300 { 301 state = SIGN; 302 engineInitSign(privateKey); 303 } 304 305 /** 306 * Initializes this class with the private key and source of randomness for 307 * signing purposes. 308 * 309 * @param privateKey 310 * the private key to sign with. 311 * @param random 312 * the {@link SecureRandom} to use. 313 * @throws InvalidKeyException 314 * if the key is invalid. 315 */ initSign(PrivateKey privateKey, SecureRandom random)316 public final void initSign(PrivateKey privateKey, SecureRandom random) 317 throws InvalidKeyException 318 { 319 state = SIGN; 320 engineInitSign(privateKey, random); 321 } 322 323 /** 324 * Returns the signature bytes of all the data fed to this instance. The 325 * format of the output depends on the underlying signature algorithm. 326 * 327 * @return the signature bytes. 328 * @throws SignatureException 329 * if the engine is not properly initialized. 330 */ sign()331 public final byte[] sign() throws SignatureException 332 { 333 if (state == SIGN) 334 return engineSign(); 335 else 336 throw new SignatureException(); 337 } 338 339 /** 340 * Generates signature bytes of all the data fed to this instance and stores 341 * it in the designated array. The format of the result depends on the 342 * underlying signature algorithm. 343 * 344 * <p>After calling this method, the instance is reset to its initial state 345 * and can then be used to generate additional signatures.</p> 346 * 347 * <p><b>IMPLEMENTATION NOTE:</b> Neither this method nor the GNU provider 348 * will return partial digests. If <code>len</code> is less than the 349 * signature length, this method will throw a {@link SignatureException}. If 350 * it is greater than or equal then it is ignored.</p> 351 * 352 * @param outbuf 353 * array of bytes of where to store the resulting signature bytes. 354 * @param offset 355 * the offset to start at in the array. 356 * @param len 357 * the number of the bytes to use in the array. 358 * @return the real number of bytes used. 359 * @throws SignatureException 360 * if the engine is not properly initialized. 361 * @since 1.2 362 */ sign(byte[] outbuf, int offset, int len)363 public final int sign(byte[] outbuf, int offset, int len) 364 throws SignatureException 365 { 366 if (state == SIGN) 367 return engineSign(outbuf, offset, len); 368 else 369 throw new SignatureException(); 370 } 371 372 /** 373 * Verifies a designated signature. 374 * 375 * @param signature 376 * the signature bytes to verify. 377 * @return <code>true</code> if verified, <code>false</code> otherwise. 378 * @throws SignatureException 379 * if the engine is not properly initialized or the signature does 380 * not check. 381 */ verify(byte[]signature)382 public final boolean verify(byte[]signature) throws SignatureException 383 { 384 if (state == VERIFY) 385 return engineVerify(signature); 386 else 387 throw new SignatureException(); 388 } 389 390 /** 391 * Verifies a designated signature. 392 * 393 * @param signature 394 * the signature bytes to verify. 395 * @param offset 396 * the offset to start at in the array. 397 * @param length 398 * the number of the bytes to use from the array. 399 * @return <code>true</code> if verified, <code>false</code> otherwise. 400 * @throws IllegalArgumentException 401 * if the <code>signature</code> byte array is <code>null</code>, 402 * or the <code>offset</code> or <code>length</code> is less 403 * than <code>0</code>, or the sum of the <code>offset</code> 404 * and <code>length</code> is greater than the length of the 405 * <code>signature</code> byte array. 406 * @throws SignatureException 407 * if the engine is not properly initialized or the signature does 408 * not check. 409 */ verify(byte[] signature, int offset, int length)410 public final boolean verify(byte[] signature, int offset, int length) 411 throws SignatureException 412 { 413 if (state != VERIFY) 414 throw new SignatureException("illegal state"); 415 416 if (signature == null) 417 throw new IllegalArgumentException("signature is null"); 418 if (offset < 0) 419 throw new IllegalArgumentException("offset is less than 0"); 420 if (length < 0) 421 throw new IllegalArgumentException("length is less than 0"); 422 if (offset + length < signature.length) 423 throw new IllegalArgumentException("range is out of bounds"); 424 425 return engineVerify(signature, offset, length); 426 } 427 428 /** 429 * Updates the data to be signed or verified with the specified byte. 430 * 431 * @param b 432 * the byte to update with. 433 * @throws SignatureException 434 * if the engine is not properly initialized. 435 */ update(byte b)436 public final void update(byte b) throws SignatureException 437 { 438 if (state != UNINITIALIZED) 439 engineUpdate(b); 440 else 441 throw new SignatureException(); 442 } 443 444 /** 445 * Updates the data to be signed or verified with the specified bytes. 446 * 447 * @param data 448 * the array of bytes to use. 449 * @throws SignatureException 450 * if the engine is not properly initialized. 451 */ update(byte[]data)452 public final void update(byte[]data) throws SignatureException 453 { 454 if (state != UNINITIALIZED) 455 engineUpdate(data, 0, data.length); 456 else 457 throw new SignatureException(); 458 } 459 460 /** 461 * Updates the data to be signed or verified with the specified bytes. 462 * 463 * @param data 464 * an array of bytes to use. 465 * @param off 466 * the offset to start at in the array. 467 * @param len 468 * the number of bytes to use from the array. 469 * @throws SignatureException 470 * if the engine is not properly initialized. 471 */ update(byte[]data, int off, int len)472 public final void update(byte[]data, int off, int len) 473 throws SignatureException 474 { 475 if (state != UNINITIALIZED) 476 engineUpdate(data, off, len); 477 else 478 throw new SignatureException(); 479 } 480 481 /** 482 * Update this signature with the {@link java.nio.Buffer#remaining()} 483 * bytes of the input buffer. 484 * 485 * @param input The input buffer. 486 * @throws SignatureException If this instance was not properly 487 * initialized. 488 */ update(ByteBuffer input)489 public final void update(ByteBuffer input) throws SignatureException 490 { 491 if (state != UNINITIALIZED) 492 engineUpdate(input); 493 else 494 throw new SignatureException("not initialized"); 495 } 496 497 /** 498 * Returns the name of the algorithm currently used. The names of algorithms 499 * are usually SHA/DSA or SHA/RSA. 500 * 501 * @return name of algorithm. 502 */ getAlgorithm()503 public final String getAlgorithm() 504 { 505 return algorithm; 506 } 507 508 /** 509 * Returns a rstring representation of this instance. 510 * 511 * @return a rstring representation of this instance. 512 */ toString()513 public String toString() 514 { 515 return (algorithm + " Signature"); 516 } 517 518 /** 519 * Sets the specified algorithm parameter to the specified value. 520 * 521 * @param param 522 * the parameter name. 523 * @param value 524 * the parameter value. 525 * @throws InvalidParameterException 526 * if the parameter is invalid, the parameter is already set and 527 * can not be changed, a security exception occured, etc. 528 * @deprecated use the other setParameter 529 */ setParameter(String param, Object value)530 public final void setParameter(String param, Object value) 531 throws InvalidParameterException 532 { 533 engineSetParameter(param, value); 534 } 535 536 /** 537 * Sets the signature engine with the specified {@link AlgorithmParameterSpec}. 538 * 539 * <p>By default, and unless overriden by the concrete SPI, this method always 540 * throws an {@link UnsupportedOperationException}.</p> 541 * 542 * @param params 543 * the parameters to use for intializing this instance. 544 * @throws InvalidParameterException 545 * if the parameter is invalid, the parameter is already set and 546 * cannot be changed, a security exception occured, etc. 547 */ setParameter(AlgorithmParameterSpec params)548 public final void setParameter(AlgorithmParameterSpec params) 549 throws InvalidAlgorithmParameterException 550 { 551 engineSetParameter(params); 552 } 553 554 /** 555 * Return the parameters of the algorithm used in this instance as an 556 * {@link AlgorithmParameters}. 557 * 558 * @return the parameters used with this instance, or <code>null</code> if 559 * this instance does not use any parameters. 560 */ getParameters()561 public final AlgorithmParameters getParameters() 562 { 563 return engineGetParameters(); 564 } 565 566 /** 567 * Returns the value for the specified algorithm parameter. 568 * 569 * @param param 570 * the parameter name. 571 * @return the parameter value. 572 * @throws InvalidParameterException 573 * if the parameter is invalid. 574 * @deprecated use the other getParameter 575 */ getParameter(String param)576 public final Object getParameter(String param) 577 throws InvalidParameterException 578 { 579 return engineGetParameter(param); 580 } 581 582 /** 583 * Returns a clone of this instance. 584 * 585 * @return a clone of this instace. 586 * @throws CloneNotSupportedException 587 * if the implementation does not support cloning. 588 */ clone()589 public Object clone() throws CloneNotSupportedException 590 { 591 return super.clone(); 592 } 593 } 594