1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.security; 19 20import java.nio.ByteBuffer; 21import java.security.cert.Certificate; 22import java.security.cert.X509Certificate; 23import java.security.spec.AlgorithmParameterSpec; 24import java.util.ArrayList; 25import java.util.Iterator; 26import java.util.Set; 27import org.apache.harmony.security.fortress.Engine; 28import org.apache.harmony.security.fortress.Engine.SpiAndProvider; 29 30/** 31 * {@code Signature} is an engine class which is capable of creating and 32 * verifying digital signatures, using different algorithms that have been 33 * registered with the {@link Security} class. 34 * 35 * @see SignatureSpi 36 */ 37public abstract class Signature extends SignatureSpi { 38 39 // The service name. 40 private static final String SERVICE = "Signature"; 41 42 // Used to access common engine functionality 43 private static final Engine ENGINE = new Engine(SERVICE); 44 45 // The provider 46 Provider provider; 47 48 // The algorithm. 49 final String algorithm; 50 51 /** 52 * Constant that indicates that this {@code Signature} instance has not yet 53 * been initialized. 54 */ 55 protected static final int UNINITIALIZED = 0; 56 57 /** 58 * Constant that indicates that this {@code Signature} instance has been 59 * initialized for signing. 60 */ 61 protected static final int SIGN = 2; 62 63 /** 64 * Constant that indicates that this {@code Signature} instance has been 65 * initialized for verification. 66 */ 67 protected static final int VERIFY = 3; 68 69 /** 70 * Represents the current state of this {@code Signature}. The three 71 * possible states are {@link #UNINITIALIZED}, {@link #SIGN} or 72 * {@link #VERIFY}. 73 */ 74 protected int state = UNINITIALIZED; 75 76 /** 77 * Constructs a new instance of {@code Signature} with the name of 78 * the algorithm to use. 79 * 80 * @param algorithm 81 * the name of algorithm to use. 82 */ 83 protected Signature(String algorithm) { 84 this.algorithm = algorithm; 85 } 86 87 /** 88 * Returns a new instance of {@code Signature} that utilizes the specified 89 * algorithm. 90 * 91 * @param algorithm 92 * the name of the algorithm to use. 93 * @return a new instance of {@code Signature} that utilizes the specified 94 * algorithm. 95 * @throws NoSuchAlgorithmException 96 * if the specified algorithm is not available. 97 * @throws NullPointerException 98 * if {@code algorithm} is {@code null}. 99 */ 100 public static Signature getInstance(String algorithm) 101 throws NoSuchAlgorithmException { 102 if (algorithm == null) { 103 throw new NullPointerException("algorithm == null"); 104 } 105 return getSignature(algorithm, null); 106 } 107 108 /** 109 * Returns a new instance of {@code Signature} that utilizes the specified 110 * algorithm from the specified provider. 111 * 112 * @param algorithm 113 * the name of the algorithm to use. 114 * @param provider 115 * the name of the provider. 116 * @return a new instance of {@code Signature} that utilizes the specified 117 * algorithm from the specified provider. 118 * @throws NoSuchAlgorithmException 119 * if the specified algorithm is not available. 120 * @throws NoSuchProviderException 121 * if the specified provider is not available. 122 * @throws NullPointerException 123 * if {@code algorithm} is {@code null}. 124 * @throws IllegalArgumentException if {@code provider == null || provider.isEmpty()} 125 */ 126 public static Signature getInstance(String algorithm, String provider) 127 throws NoSuchAlgorithmException, NoSuchProviderException { 128 if (algorithm == null) { 129 throw new NullPointerException("algorithm == null"); 130 } 131 if (provider == null || provider.isEmpty()) { 132 throw new IllegalArgumentException(); 133 } 134 Provider p = Security.getProvider(provider); 135 if (p == null) { 136 throw new NoSuchProviderException(provider); 137 } 138 return getSignature(algorithm, p); 139 } 140 141 /** 142 * Returns a new instance of {@code Signature} that utilizes the specified 143 * algorithm from the specified provider. The {@code provider} supplied 144 * does not have to be registered. 145 * 146 * @param algorithm 147 * the name of the algorithm to use. 148 * @param provider 149 * the security provider. 150 * @return a new instance of {@code Signature} that utilizes the specified 151 * algorithm from the specified provider. 152 * @throws NoSuchAlgorithmException 153 * if the specified algorithm is not available. 154 * @throws NullPointerException 155 * if {@code algorithm} is {@code null}. 156 * @throws IllegalArgumentException if {@code provider == null} 157 */ 158 public static Signature getInstance(String algorithm, Provider provider) 159 throws NoSuchAlgorithmException { 160 if (algorithm == null) { 161 throw new NullPointerException("algorithm == null"); 162 } 163 if (provider == null) { 164 throw new IllegalArgumentException("provider == null"); 165 } 166 return getSignature(algorithm, provider); 167 } 168 169 private static Signature getSignature(String algorithm, Provider provider) 170 throws NoSuchAlgorithmException { 171 if (algorithm == null || algorithm.isEmpty()) { 172 throw new NoSuchAlgorithmException("Unknown algorithm: " + algorithm); 173 } 174 175 SpiAndProvider spiAndProvider = tryAlgorithm(null, provider, algorithm); 176 if (spiAndProvider == null) { 177 if (provider == null) { 178 throw new NoSuchAlgorithmException("No provider found for " + algorithm); 179 } else { 180 throw new NoSuchAlgorithmException("Provider " + provider.getName() 181 + " does not provide " + algorithm); 182 } 183 } 184 if (spiAndProvider.spi instanceof Signature) { 185 return (Signature) spiAndProvider.spi; 186 } 187 return new SignatureImpl(algorithm, provider); 188 } 189 190 private static Engine.SpiAndProvider tryAlgorithm(Key key, Provider provider, String algorithm) { 191 if (provider != null) { 192 Provider.Service service = provider.getService(SERVICE, algorithm); 193 if (service == null) { 194 return null; 195 } 196 return tryAlgorithmWithProvider(key, service); 197 } 198 ArrayList<Provider.Service> services = ENGINE.getServices(algorithm); 199 if (services == null) { 200 return null; 201 } 202 for (Provider.Service service : services) { 203 Engine.SpiAndProvider sap = tryAlgorithmWithProvider(key, service); 204 if (sap != null) { 205 return sap; 206 } 207 } 208 return null; 209 } 210 211 private static Engine.SpiAndProvider tryAlgorithmWithProvider(Key key, Provider.Service service) { 212 try { 213 if (key != null && !service.supportsParameter(key)) { 214 return null; 215 } 216 217 Engine.SpiAndProvider sap = ENGINE.getInstance(service, null); 218 if (sap.spi == null || sap.provider == null) { 219 return null; 220 } 221 if (!(sap.spi instanceof SignatureSpi)) { 222 return null; 223 } 224 return sap; 225 } catch (NoSuchAlgorithmException ignored) { 226 } 227 return null; 228 } 229 230 /** 231 * Returns the provider associated with this {@code Signature}. 232 * 233 * @return the provider associated with this {@code Signature}. 234 */ 235 public final Provider getProvider() { 236 ensureProviderChosen(); 237 return provider; 238 } 239 240 /** 241 * This makes sure the provider is chosen since Signature is abstract and 242 * getProvider is final but we need to support late binding. 243 */ 244 void ensureProviderChosen() { 245 } 246 247 /** 248 * Returns the name of the algorithm of this {@code Signature}. 249 * 250 * @return the name of the algorithm of this {@code Signature}. 251 */ 252 public final String getAlgorithm() { 253 return algorithm; 254 } 255 256 /** 257 * Initializes this {@code Signature} instance for signature verification, 258 * using the public key of the identity whose signature is going to be 259 * verified. 260 * 261 * @param publicKey 262 * the public key. 263 * @throws InvalidKeyException 264 * if {@code publicKey} is not valid. 265 */ 266 public final void initVerify(PublicKey publicKey) 267 throws InvalidKeyException { 268 engineInitVerify(publicKey); 269 state = VERIFY; 270 } 271 272 /** 273 * Initializes this {@code Signature} instance for signature verification, 274 * using the certificate of the identity whose signature is going to be 275 * verified. 276 * <p> 277 * If the given certificate is an instance of {@link X509Certificate} and 278 * has a key usage parameter that indicates, that this certificate is not to 279 * be used for signing, an {@code InvalidKeyException} is thrown. 280 * 281 * @param certificate 282 * the certificate used to verify a signature. 283 * @throws InvalidKeyException 284 * if the publicKey in the certificate is not valid or not to be 285 * used for signing. 286 */ 287 public final void initVerify(Certificate certificate) 288 throws InvalidKeyException { 289 if (certificate instanceof X509Certificate) { 290 Set<String> ce = ((X509Certificate) certificate).getCriticalExtensionOIDs(); 291 boolean critical = false; 292 if (ce != null && !ce.isEmpty()) { 293 for (Iterator<String> i = ce.iterator(); i.hasNext();) { 294 if ("2.5.29.15".equals(i.next())) { 295 //KeyUsage OID = 2.5.29.15 296 critical = true; 297 break; 298 } 299 } 300 if (critical) { 301 boolean[] keyUsage = ((X509Certificate) certificate) 302 .getKeyUsage(); 303 // As specified in RFC 3280 - 304 // Internet X.509 Public Key Infrastructure 305 // Certificate and Certificate Revocation List (CRL) Profile. 306 // (http://www.ietf.org/rfc/rfc3280.txt) 307 // 308 // KeyUsage ::= BIT STRING { digitalSignature (0), <skipped> } 309 if ((keyUsage != null) && (!keyUsage[0])) { // digitalSignature 310 throw new InvalidKeyException("The public key in the certificate cannot be used for digital signature purposes"); 311 } 312 } 313 } 314 } 315 engineInitVerify(certificate.getPublicKey()); 316 state = VERIFY; 317 } 318 319 /** 320 * Initializes this {@code Signature} instance for signing, using the 321 * private key of the identity whose signature is going to be generated. 322 * 323 * @param privateKey 324 * the private key. 325 * @throws InvalidKeyException 326 * if {@code privateKey} is not valid. 327 */ 328 public final void initSign(PrivateKey privateKey) 329 throws InvalidKeyException { 330 engineInitSign(privateKey); 331 state = SIGN; 332 } 333 334 /** 335 * Initializes this {@code Signature} instance for signing, using the 336 * private key of the identity whose signature is going to be generated and 337 * the specified source of randomness. 338 * 339 * @param privateKey 340 * the private key. 341 * @param random 342 * the {@code SecureRandom} to use. 343 * @throws InvalidKeyException 344 * if {@code privateKey} is not valid. 345 */ 346 public final void initSign(PrivateKey privateKey, SecureRandom random) 347 throws InvalidKeyException { 348 engineInitSign(privateKey, random); 349 state = SIGN; 350 } 351 352 /** 353 * Generates and returns the signature of all updated data. 354 * <p> 355 * This {@code Signature} instance is reset to the state of its last 356 * initialization for signing and thus can be used for another signature 357 * from the same identity. 358 * 359 * @return the signature of all updated data. 360 * @throws SignatureException 361 * if this {@code Signature} instance is not initialized 362 * properly. 363 */ 364 public final byte[] sign() throws SignatureException { 365 if (state != SIGN) { 366 throw new SignatureException("Signature object is not initialized properly"); 367 } 368 return engineSign(); 369 } 370 371 /** 372 * Generates and stores the signature of all updated data in the provided 373 * {@code byte[]} at the specified position with the specified length. 374 * <p> 375 * This {@code Signature} instance is reset to the state of its last 376 * initialization for signing and thus can be used for another signature 377 * from the same identity. 378 * 379 * @param outbuf 380 * the buffer to store the signature. 381 * @param offset 382 * the index of the first byte in {@code outbuf} to store. 383 * @param len 384 * the number of bytes allocated for the signature. 385 * @return the number of bytes stored in {@code outbuf}. 386 * @throws SignatureException 387 * if this {@code Signature} instance is not initialized 388 * properly. 389 * @throws IllegalArgumentException 390 * if {@code offset} or {@code len} are not valid in respect to 391 * {@code outbuf}. 392 */ 393 public final int sign(byte[] outbuf, int offset, int len) 394 throws SignatureException { 395 if (outbuf == null || offset < 0 || len < 0 || 396 offset + len > outbuf.length) { 397 throw new IllegalArgumentException(); 398 } 399 if (state != SIGN) { 400 throw new SignatureException("Signature object is not initialized properly"); 401 } 402 return engineSign(outbuf, offset, len); 403 } 404 405 /** 406 * Indicates whether the given {@code signature} can be verified using the 407 * public key or a certificate of the signer. 408 * <p> 409 * This {@code Signature} instance is reset to the state of its last 410 * initialization for verifying and thus can be used to verify another 411 * signature of the same signer. 412 * 413 * @param signature 414 * the signature to verify. 415 * @return {@code true} if the signature was verified, {@code false} 416 * otherwise. 417 * @throws SignatureException 418 * if this {@code Signature} instance is not initialized 419 * properly. 420 */ 421 public final boolean verify(byte[] signature) throws SignatureException { 422 if (state != VERIFY) { 423 throw new SignatureException("Signature object is not initialized properly"); 424 } 425 return engineVerify(signature); 426 } 427 428 /** 429 * Indicates whether the given {@code signature} starting at index {@code 430 * offset} with {@code length} bytes can be verified using the public key or 431 * a certificate of the signer. 432 * <p> 433 * This {@code Signature} instance is reset to the state of its last 434 * initialization for verifying and thus can be used to verify another 435 * signature of the same signer. 436 * 437 * @param signature 438 * the {@code byte[]} containing the signature to verify. 439 * @param offset 440 * the start index in {@code signature} of the signature. 441 * @param length 442 * the number of bytes allocated for the signature. 443 * @return {@code true} if the signature was verified, {@code false} 444 * otherwise. 445 * @throws SignatureException 446 * if this {@code Signature} instance is not initialized 447 * properly. 448 * @throws IllegalArgumentException 449 * if {@code offset} or {@code length} are not valid in respect 450 * to {@code signature}. 451 */ 452 public final boolean verify(byte[] signature, int offset, int length) 453 throws SignatureException { 454 if (state != VERIFY) { 455 throw new SignatureException("Signature object is not initialized properly"); 456 } 457 if (signature == null || offset < 0 || length < 0 || 458 offset + length > signature.length) { 459 throw new IllegalArgumentException(); 460 } 461 return engineVerify(signature, offset, length); 462 } 463 464 /** 465 * Updates the data to be verified or to be signed, using the specified 466 * {@code byte}. 467 * 468 * @param b 469 * the byte to update with. 470 * @throws SignatureException 471 * if this {@code Signature} instance is not initialized 472 * properly. 473 */ 474 public final void update(byte b) throws SignatureException { 475 if (state == UNINITIALIZED) { 476 throw new SignatureException("Signature object is not initialized properly"); 477 } 478 engineUpdate(b); 479 } 480 481 /** 482 * Updates the data to be verified or to be signed, using the specified 483 * {@code byte[]}. 484 * 485 * @param data 486 * the byte array to update with. 487 * @throws SignatureException 488 * if this {@code Signature} instance is not initialized 489 * properly. 490 */ 491 public final void update(byte[] data) throws SignatureException { 492 if (state == UNINITIALIZED) { 493 throw new SignatureException("Signature object is not initialized properly"); 494 } 495 engineUpdate(data, 0, data.length); 496 } 497 498 /** 499 * Updates the data to be verified or to be signed, using the given {@code 500 * byte[]}, starting form the specified index for the specified length. 501 * 502 * @param data 503 * the byte array to update with. 504 * @param off 505 * the start index in {@code data} of the data. 506 * @param len 507 * the number of bytes to use. 508 * @throws SignatureException 509 * if this {@code Signature} instance is not initialized 510 * properly. 511 */ 512 public final void update(byte[] data, int off, int len) 513 throws SignatureException { 514 if (state == UNINITIALIZED) { 515 throw new SignatureException("Signature object is not initialized properly"); 516 } 517 if (data == null || off < 0 || len < 0 || 518 off + len > data.length) { 519 throw new IllegalArgumentException(); 520 } 521 engineUpdate(data, off, len); 522 } 523 524 /** 525 * Updates the data to be verified or to be signed, using the specified 526 * {@code ByteBuffer}. 527 * 528 * @param data 529 * the {@code ByteBuffer} to update with. 530 * @throws SignatureException 531 * if this {@code Signature} instance is not initialized 532 * properly. 533 */ 534 public final void update(ByteBuffer data) throws SignatureException { 535 if (state == UNINITIALIZED) { 536 throw new SignatureException("Signature object is not initialized properly"); 537 } 538 engineUpdate(data); 539 } 540 541 /** 542 * Returns a string containing a concise, human-readable description of this 543 * {@code Signature} including its algorithm and its state. 544 * 545 * @return a printable representation for this {@code Signature}. 546 */ 547 @Override 548 public String toString() { 549 return "SIGNATURE " + algorithm + " state: " + stateToString(state); 550 } 551 552 // Convert state to string 553 private String stateToString(int state) { 554 switch (state) { 555 case UNINITIALIZED: 556 return "UNINITIALIZED"; 557 case SIGN: 558 return "SIGN"; 559 case VERIFY: 560 return "VERIFY"; 561 default: 562 return ""; 563 } 564 } 565 566 /** 567 * Sets the specified parameter to the given value. 568 * 569 * @param param 570 * the name of the parameter. 571 * @param value 572 * the parameter value. 573 * @throws InvalidParameterException 574 * if the parameter is invalid, already set or is not allowed to 575 * be changed. 576 * @deprecated Use {@link #setParameter(AlgorithmParameterSpec)} instead. 577 */ 578 @Deprecated 579 public final void setParameter(String param, Object value) 580 throws InvalidParameterException { 581 engineSetParameter(param, value); 582 } 583 584 /** 585 * Sets the specified {@code AlgorithmParameterSpec}. 586 * 587 * @param params 588 * the parameter to set. 589 * @throws InvalidAlgorithmParameterException 590 * if the parameter is invalid, already set or is not allowed to 591 * be changed. 592 */ 593 public final void setParameter(AlgorithmParameterSpec params) 594 throws InvalidAlgorithmParameterException { 595 engineSetParameter(params); 596 } 597 598 /** 599 * Returns the {@code AlgorithmParameters} of this {@link Signature} 600 * instance. 601 * 602 * @return the {@code AlgorithmParameters} of this {@link Signature} 603 * instance, maybe {@code null}. 604 */ 605 public final AlgorithmParameters getParameters() { 606 return engineGetParameters(); 607 } 608 609 /** 610 * Returns the value of the parameter with the specified name. 611 * 612 * @param param 613 * the name of the requested parameter value 614 * @return the value of the parameter with the specified name, maybe {@code 615 * null}. 616 * @throws InvalidParameterException 617 * if {@code param} is not a valid parameter for this {@code 618 * Signature} or an other error occurs. 619 * @deprecated There is no generally accepted parameter naming convention. 620 */ 621 @Deprecated 622 public final Object getParameter(String param) 623 throws InvalidParameterException { 624 return engineGetParameter(param); 625 } 626 627 /** 628 * Internal Signature implementation 629 */ 630 private static class SignatureImpl extends Signature { 631 632 /** 633 * Lock held while the SPI is initializing. 634 */ 635 private final Object initLock = new Object(); 636 637 // The provider specified when creating this instance. 638 private final Provider specifiedProvider; 639 640 private SignatureSpi spiImpl; 641 642 public SignatureImpl(String algorithm, Provider provider) { 643 super(algorithm); 644 this.specifiedProvider = provider; 645 } 646 647 private SignatureImpl(String algorithm, Provider provider, SignatureSpi spi) { 648 this(algorithm, provider); 649 spiImpl = spi; 650 } 651 652 @Override 653 void ensureProviderChosen() { 654 getSpi(null); 655 } 656 657 @Override 658 protected byte[] engineSign() throws SignatureException { 659 return getSpi().engineSign(); 660 } 661 662 @Override 663 protected void engineUpdate(byte arg0) throws SignatureException { 664 getSpi().engineUpdate(arg0); 665 } 666 667 @Override 668 protected boolean engineVerify(byte[] arg0) throws SignatureException { 669 return getSpi().engineVerify(arg0); 670 } 671 672 @Override 673 protected void engineUpdate(byte[] arg0, int arg1, int arg2) throws SignatureException { 674 getSpi().engineUpdate(arg0, arg1, arg2); 675 } 676 677 @Override 678 protected void engineInitSign(PrivateKey arg0) throws InvalidKeyException { 679 getSpi(arg0).engineInitSign(arg0); 680 } 681 682 @Override 683 protected void engineInitVerify(PublicKey arg0) throws InvalidKeyException { 684 getSpi(arg0).engineInitVerify(arg0); 685 } 686 687 @Override 688 protected Object engineGetParameter(String arg0) throws InvalidParameterException { 689 return getSpi().engineGetParameter(arg0); 690 } 691 692 @Override 693 protected void engineSetParameter(String arg0, Object arg1) 694 throws InvalidParameterException { 695 getSpi().engineSetParameter(arg0, arg1); 696 } 697 698 @Override 699 protected void engineSetParameter(AlgorithmParameterSpec arg0) 700 throws InvalidAlgorithmParameterException { 701 getSpi().engineSetParameter(arg0); 702 } 703 704 @Override 705 public Object clone() throws CloneNotSupportedException { 706 SignatureSpi spi = spiImpl != null ? (SignatureSpi) spiImpl.clone() : null; 707 return new SignatureImpl(getAlgorithm(), getProvider(), spi); 708 } 709 710 /** 711 * Makes sure a CipherSpi that matches this type is selected. 712 */ 713 private SignatureSpi getSpi(Key key) { 714 synchronized (initLock) { 715 if (spiImpl != null && key == null) { 716 return spiImpl; 717 } 718 719 final Engine.SpiAndProvider sap = tryAlgorithm(key, specifiedProvider, algorithm); 720 if (sap == null) { 721 throw new ProviderException("No provider for " + getAlgorithm()); 722 } 723 724 spiImpl = (SignatureSpi) sap.spi; 725 provider = sap.provider; 726 727 return spiImpl; 728 } 729 } 730 731 /** 732 * Convenience call when the Key is not available. 733 */ 734 private SignatureSpi getSpi() { 735 return getSpi(null); 736 } 737 } 738} 739