/* * @(#)Signature.java 1.93 06/10/10 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program 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 version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. * */ package java.security; import java.security.spec.AlgorithmParameterSpec; import java.util.*; import java.io.*; import java.security.cert.Certificate; import java.security.cert.X509Certificate; /** * This Signature class is used to provide applications the functionality * of a digital signature algorithm. Digital signatures are used for * authentication and integrity assurance of digital data. * * <p> The signature algorithm can be, among others, the NIST standard * DSA, using DSA and SHA-1. The DSA algorithm using the * SHA-1 message digest algorithm can be specified as <tt>SHA1withDSA</tt>. * In the case of RSA, there are multiple choices for the message digest * algorithm, so the signing algorithm could be specified as, for example, * <tt>MD2withRSA</tt>, <tt>MD5withRSA</tt>, or <tt>SHA1withRSA</tt>. * The algorithm name must be specified, as there is no default. * * <p>Like other algorithm-based classes in Java Security, Signature * provides implementation-independent algorithms, whereby a caller * (application code) requests a particular signature algorithm * and is handed back a properly initialized Signature object. It is * also possible, if desired, to request a particular algorithm from a * particular provider. See the <code>getInstance </code> methods. * * <p>Thus, there are two ways to request a Signature algorithm object: by * specifying either just an algorithm name, or both an algorithm name * and a package provider. <ul> * * <li>If just an algorithm name is specified, the system will * determine if there is an implementation of the algorithm requested * available in the environment, and if there is more than one, if * there is a preferred one.<p> * * <li>If both an algorithm name and a package provider are specified, * the system will determine if there is an implementation of the * algorithm in the package requested, and throw an exception if there * is not. * * </ul> * * <p>A Signature object can be used to generate and verify digital * signatures. * * <p>There are three phases to the use of a Signature object for * either signing data or verifying a signature:<ol> * * <li>Initialization, with either * * <ul> * * <li>a public key, which initializes the signature for * verification (see {@link #initVerify(PublicKey) initVerify}), or * * <li>a private key (and optionally a Secure Random Number Generator), * which initializes the signature for signing * (see {@link #initSign(PrivateKey)} * and {@link #initSign(PrivateKey, SecureRandom)}). * * </ul><p> * * <li>Updating<p> * * <p>Depending on the type of initialization, this will update the * bytes to be signed or verified. See the * {@link #update(byte) update} methods.<p> * * <li>Signing or Verifying a signature on all updated bytes. See the * {@link #sign() sign} methods and the {@link #verify(byte[]) verify} * method. * * </ol> * * <p>Note that this class is abstract and extends from * <code>SignatureSpi</code> for historical reasons. * Application developers should only take notice of the methods defined in * this <code>Signature</code> class; all the methods in * the superclass are intended for cryptographic service providers who wish to * supply their own implementations of digital signature algorithms. * * @author Benjamin Renaud * * @version 1.86, 05/03/00 */ public abstract class Signature extends SignatureSpi { /* Are we in debugging mode? */ private static final boolean debug = false; /* * The algorithm for this signature object. * This value is used to map an OID to the particular algorithm. * The mapping is done in AlgorithmObject.algOID(String algorithm) */ private String algorithm; // The provider private Provider provider; /** * Possible {@link #state} value, signifying that * this signature object has not yet been initialized. */ protected final static int UNINITIALIZED = 0; /** * Possible {@link #state} value, signifying that * this signature object has been initialized for signing. */ protected final static int SIGN = 2; /** * Possible {@link #state} value, signifying that * this signature object has been initialized for verification. */ protected final static int VERIFY = 3; /** * Current state of this signature object. */ protected int state = UNINITIALIZED; /** * Creates a Signature object for the specified algorithm. * * @param algorithm the standard string name of the algorithm. * See Appendix A in the <a href= * "../../../guide/security/CryptoSpec.html#AppA"> * Java Cryptography Architecture API Specification & Reference </a> * for information about standard algorithm names. */ protected Signature(String algorithm) { this.algorithm = algorithm; } /** * Generates a Signature object that implements the specified digest * algorithm. If the default provider package * provides an implementation of the requested digest algorithm, * an instance of Signature containing that implementation is returned. * If the algorithm is not available in the default * package, other packages are searched. * * @param algorithm the standard name of the algorithm requested. * See Appendix A in the <a href= * "../../../guide/security/CryptoSpec.html#AppA"> * Java Cryptography Architecture API Specification & Reference </a> * for information about standard algorithm names. * * @return the new Signature object. * * @exception NoSuchAlgorithmException if the algorithm is * not available in the environment. */ public static Signature getInstance(String algorithm) throws NoSuchAlgorithmException { try { Object[] objs = Security.getImpl(algorithm, "Signature", (String)null); if (objs[0] instanceof Signature) { Signature sig = (Signature)objs[0]; sig.provider = (Provider)objs[1]; return sig; } else { Signature delegate = new Delegate((SignatureSpi)objs[0], algorithm); delegate.provider = (Provider)objs[1]; return delegate; } } catch(NoSuchProviderException e) { throw new NoSuchAlgorithmException(algorithm + " not found"); } } /** * Generates a Signature object implementing the specified * algorithm, as supplied from the specified provider, if such an * algorithm is available from the provider. * * @param algorithm the name of the algorithm requested. * See Appendix A in the <a href= * "../../../guide/security/CryptoSpec.html#AppA"> * Java Cryptography Architecture API Specification & Reference </a> * for information about standard algorithm names. * * @param provider the name of the provider. * * @return the new Signature object. * * @exception NoSuchAlgorithmException if the algorithm is * not available in the package supplied by the requested * provider. * * @exception NoSuchProviderException if the provider is not * available in the environment. * * @exception IllegalArgumentException if the provider name is null * or empty. * * @see Provider */ public static Signature getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { if (provider == null || provider.length() == 0) throw new IllegalArgumentException("missing provider"); Object[] objs = Security.getImpl(algorithm, "Signature", provider); if (objs[0] instanceof Signature) { Signature sig = (Signature)objs[0]; sig.provider = (Provider)objs[1]; return sig; } else { Signature delegate = new Delegate((SignatureSpi)objs[0], algorithm); delegate.provider = (Provider)objs[1]; return delegate; } } /** * Generates a Signature object implementing the specified * algorithm, as supplied from the specified provider, if such an * algorithm is available from the provider. Note: the * <code>provider</code> doesn't have to be registered. * * @param algorithm the name of the algorithm requested. * See Appendix A in the <a href= * "../../../guide/security/CryptoSpec.html#AppA"> * Java Cryptography Architecture API Specification & Reference </a> * for information about standard algorithm names. * * @param provider the provider. * * @return the new Signature object. * * @exception NoSuchAlgorithmException if the algorithm is * not available in the package supplied by the requested * provider. * * @exception IllegalArgumentException if the <code>provider</code> is * null. * * @see Provider * * @since 1.4 */ public static Signature getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { if (provider == null) throw new IllegalArgumentException("missing provider"); Object[] objs = Security.getImpl(algorithm, "Signature", provider); if (objs[0] instanceof Signature) { Signature sig = (Signature)objs[0]; sig.provider = (Provider)objs[1]; return sig; } else { Signature delegate = new Delegate((SignatureSpi)objs[0], algorithm); delegate.provider = (Provider)objs[1]; return delegate; } } /** * Returns the provider of this signature object. * * @return the provider of this signature object */ public final Provider getProvider() { return this.provider; } /** * Initializes this object for verification. If this method is called * again with a different argument, it negates the effect * of this call. * * @param publicKey the public key of the identity whose signature is * going to be verified. * * @exception InvalidKeyException if the key is invalid. */ public final void initVerify(PublicKey publicKey) throws InvalidKeyException { engineInitVerify(publicKey); state = VERIFY; } /** * Initializes this object for verification, using the public key from * the given certificate. * <p>If the certificate is of type X.509 and has a <i>key usage</i> * extension field marked as critical, and the value of the <i>key usage</i> * extension field implies that the public key in * the certificate and its corresponding private key are not * supposed to be used for digital signatures, an <code>InvalidKeyException</code> * is thrown. * * @param certificate the certificate of the identity whose signature is * going to be verified. * * @exception InvalidKeyException if the public key in the certificate * is not encoded properly or does not include required parameter * information or cannot be used for digital signature purposes. */ public final void initVerify(Certificate certificate) throws InvalidKeyException { // If the certificate is of type X509Certificate, // we should check whether it has a Key Usage // extension marked as critical. if (certificate instanceof java.security.cert.X509Certificate) { // Check whether the cert has a key usage extension // marked as a critical extension. // The OID for KeyUsage extension is 2.5.29.15. X509Certificate cert = (X509Certificate)certificate; Set critSet = cert.getCriticalExtensionOIDs(); if (critSet != null && !critSet.isEmpty() && critSet.contains(new String("2.5.29.15"))) { boolean[] keyUsageInfo = cert.getKeyUsage(); // keyUsageInfo[0] is for digitalSignature. if ((keyUsageInfo != null) && (keyUsageInfo[0] == false)) throw new InvalidKeyException("Wrong key usage"); } } PublicKey publicKey = certificate.getPublicKey(); engineInitVerify(publicKey); state = VERIFY; } /** * Initialize this object for signing. If this method is called * again with a different argument, it negates the effect * of this call. * * @param privateKey the private key of the identity whose signature * is going to be generated. * * @exception InvalidKeyException if the key is invalid. */ public final void initSign(PrivateKey privateKey) throws InvalidKeyException { engineInitSign(privateKey); state = SIGN; } /** * Initialize this object for signing. If this method is called * again with a different argument, it negates the effect * of this call. * * @param privateKey the private key of the identity whose signature * is going to be generated. * * @param random the source of randomness for this signature. * * @exception InvalidKeyException if the key is invalid. */ public final void initSign(PrivateKey privateKey, SecureRandom random) throws InvalidKeyException { engineInitSign(privateKey, random); state = SIGN; } /** * Returns the signature bytes of all the data updated. * The format of the signature depends on the underlying * signature scheme. * * <p>A call to this method resets this signature object to the state * it was in when previously initialized for signing via a * call to <code>initSign(PrivateKey)</code>. That is, the object is * reset and available to generate another signature from the same * signer, if desired, via new calls to <code>update</code> and * <code>sign</code>. * * @return the signature bytes of the signing operation's result. * * @exception SignatureException if this signature object is not * initialized properly. */ public final byte[] sign() throws SignatureException { if (state == SIGN) { return engineSign(); } throw new SignatureException("object not initialized for " + "signing"); } /** * Finishes the signature operation and stores the resulting signature * bytes in the provided buffer <code>outbuf</code>, starting at * <code>offset</code>. * The format of the signature depends on the underlying * signature scheme. * * <p>This signature object is reset to its initial state (the state it * was in after a call to one of the <code>initSign</code> methods) and * can be reused to generate further signatures with the same private key. * * @param outbuf buffer for the signature result. * * @param offset offset into <code>outbuf</code> where the signature is * stored. * * @param len number of bytes within <code>outbuf</code> allotted for the * signature. * * @return the number of bytes placed into <code>outbuf</code>. * * @exception SignatureException if an error occurs or <code>len</code> * is less than the actual signature length. * * @since 1.2 */ public final int sign(byte[] outbuf, int offset, int len) throws SignatureException { if (outbuf == null) { throw new IllegalArgumentException("No output buffer given"); } if (outbuf.length - offset < len) { throw new IllegalArgumentException ("Output buffer too small for specified offset and length"); } if (state != SIGN) { throw new SignatureException("object not initialized for " + "signing"); } return engineSign(outbuf, offset, len); } /** * Verifies the passed-in signature. * * <p>A call to this method resets this signature object to the state * it was in when previously initialized for verification via a * call to <code>initVerify(PublicKey)</code>. That is, the object is * reset and available to verify another signature from the identity * whose public key was specified in the call to <code>initVerify</code>. * * @param signature the signature bytes to be verified. * * @return true if the signature was verified, false if not. * * @exception SignatureException if this signature object is not * initialized properly, or the passed-in signature is improperly * encoded or of the wrong type, etc. */ public final boolean verify(byte[] signature) throws SignatureException { if (state == VERIFY) { return engineVerify(signature); } throw new SignatureException("object not initialized for " + "verification"); } /** * Verifies the passed-in signature in the specified array * of bytes, starting at the specified offset. * * <p>A call to this method resets this signature object to the state * it was in when previously initialized for verification via a * call to <code>initVerify(PublicKey)</code>. That is, the object is * reset and available to verify another signature from the identity * whose public key was specified in the call to <code>initVerify</code>. * * * @param signature the signature bytes to be verified. * @param offset the offset to start from in the array of bytes. * @param length the number of bytes to use, starting at offset. * * @return true if the signature was verified, false if not. * * @exception SignatureException if this signature object is not * initialized properly, or the passed-in signature is improperly * encoded or of the wrong type, etc. * @exception IllegalArgumentException if the <code>signature</code> * byte array is null, or the <code>offset</code> or <code>length</code> * is less than 0, or the sum of the <code>offset</code> and * <code>length</code> is greater than the length of the * <code>signature</code> byte array. */ public final boolean verify(byte[] signature, int offset, int length) throws SignatureException { if (state == VERIFY) { if ((signature == null) || (offset < 0) || (length < 0) || (offset + length > signature.length)) { throw new IllegalArgumentException("Bad arguments"); } return engineVerify(signature, offset, length); } throw new SignatureException("object not initialized for " + "verification"); } /** * Updates the data to be signed or verified by a byte. * * @param b the byte to use for the update. * * @exception SignatureException if this signature object is not * initialized properly. */ public final void update(byte b) throws SignatureException { if (state == VERIFY || state == SIGN) { engineUpdate(b); } else { throw new SignatureException("object not initialized for " + "signature or verification"); } } /** * Updates the data to be signed or verified, using the specified * array of bytes. * * @param data the byte array to use for the update. * * @exception SignatureException if this signature object is not * initialized properly. */ public final void update(byte[] data) throws SignatureException { update(data, 0, data.length); } /** * Updates the data to be signed or verified, using the specified * array of bytes, starting at the specified offset. * * @param data the array of bytes. * @param off the offset to start from in the array of bytes. * @param len the number of bytes to use, starting at offset. * * @exception SignatureException if this signature object is not * initialized properly. */ public final void update(byte[] data, int off, int len) throws SignatureException { if (state == SIGN || state == VERIFY) { engineUpdate(data, off, len); } else { throw new SignatureException("object not initialized for " + "signature or verification"); } } /** * Returns the name of the algorithm for this signature object. * * @return the name of the algorithm for this signature object. */ public final String getAlgorithm() { return this.algorithm; } /** * Returns a string representation of this signature object, * providing information that includes the state of the object * and the name of the algorithm used. * * @return a string representation of this signature object. */ public String toString() { String initState = ""; switch (state) { case UNINITIALIZED: initState = "<not initialized>"; break; case VERIFY: initState = "<initialized for verifying>"; break; case SIGN: initState = "<initialized for signing>"; break; } return "Signature object: " + getAlgorithm() + initState; } /** * Sets the specified algorithm parameter to the specified value. * This method supplies a general-purpose mechanism through * which it is possible to set the various parameters of this object. * A parameter may be any settable parameter for the algorithm, such as * a parameter size, or a source of random bits for signature generation * (if appropriate), or an indication of whether or not to perform * a specific but optional computation. A uniform algorithm-specific * naming scheme for each parameter is desirable but left unspecified * at this time. * * param param the string identifier of the parameter. * param value the parameter value. * * exception InvalidParameterException if <code>param</code> is an * invalid parameter for this signature algorithm engine, * the parameter is already set * and cannot be set again, a security exception occurs, and so on. * * @see #getParameter * * @deprecated Use * {@link #setParameter(java.security.spec.AlgorithmParameterSpec) * setParameter}. * public final void setParameter(String param, Object value) throws InvalidParameterException { engineSetParameter(param, value); } */ /** * Initializes this signature engine with the specified parameter set. * * @param params the parameters * * @exception InvalidAlgorithmParameterException if the given parameters * are inappropriate for this signature engine * * @see #getParameters */ public final void setParameter(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { engineSetParameter(params); } /** * Returns the parameters used with this signature object. * * <p>The returned parameters may be the same that were used to initialize * this signature, or may contain a combination of default and randomly * generated parameter values used by the underlying signature * implementation if this signature requires algorithm parameters but * was not initialized with any. * * @return the parameters used with this signature, or null if this * signature does not use any parameters. * * @see #setParameter(AlgorithmParameterSpec) */ public final AlgorithmParameters getParameters() { return engineGetParameters(); } /** * Gets the value of the specified algorithm parameter. This method * supplies a general-purpose mechanism through which it is possible to * get the various parameters of this object. A parameter may be any * settable parameter for the algorithm, such as a parameter size, or * a source of random bits for signature generation (if appropriate), * or an indication of whether or not to perform a specific but optional * computation. A uniform algorithm-specific naming scheme for each * parameter is desirable but left unspecified at this time. * * param param the string name of the parameter. * * return the object that represents the parameter value, or null if * there is none. * * exception InvalidParameterException if <code>param</code> is an invalid * parameter for this engine, or another exception occurs while * trying to get this parameter. * * @see #setParameter(String, Object) * * @deprecated * public final Object getParameter(String param) throws InvalidParameterException { return engineGetParameter(param); } */ /** * Returns a clone if the implementation is cloneable. * * @return a clone if the implementation is cloneable. * * @exception CloneNotSupportedException if this is called * on an implementation that does not support <code>Cloneable</code>. */ public Object clone() throws CloneNotSupportedException { if (this instanceof Cloneable) { return super.clone(); } else { throw new CloneNotSupportedException(); } } // private debugging method. private static void debug(String statement) { if (debug) { System.err.println(statement); } } // private debugging method. private static void debug(Exception e) { if (debug) { e.printStackTrace(); } } /* * The following class allows providers to extend from SignatureSpi * rather than from Signature. It represents a Signature with an * encapsulated, provider-supplied SPI object (of type SignatureSpi). * If the provider implementation is an instance of SignatureSpi, the * getInstance() methods above return an instance of this class, with * the SPI object encapsulated. * * Note: All SPI methods from the original Signature class have been * moved up the hierarchy into a new class (SignatureSpi), which has * been interposed in the hierarchy between the API (Signature) * and its original parent (Object). */ static class Delegate extends Signature { // The provider implementation (delegate) private SignatureSpi sigSpi; // constructor public Delegate(SignatureSpi sigSpi, String algorithm) { super(algorithm); this.sigSpi = sigSpi; } /* * Returns a clone if the delegate is cloneable. * * @return a clone if the delegate is cloneable. * * @exception CloneNotSupportedException if this is called on a * delegate that does not support <code>Cloneable</code>. */ public Object clone() throws CloneNotSupportedException { if (sigSpi instanceof Cloneable) { SignatureSpi sigSpiClone = (SignatureSpi)sigSpi.clone(); // Because 'algorithm' and 'provider' are private // members of our supertype, we must perform a cast to // access them. Signature that = new Delegate(sigSpiClone, ((Signature)this).algorithm); that.provider = ((Signature)this).provider; return that; } else { throw new CloneNotSupportedException(); } } protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { sigSpi.engineInitVerify(publicKey); } protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { sigSpi.engineInitSign(privateKey); } protected void engineInitSign(PrivateKey privateKey, SecureRandom sr) throws InvalidKeyException { sigSpi.engineInitSign(privateKey, sr); } protected void engineUpdate(byte b) throws SignatureException { sigSpi.engineUpdate(b); } protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { sigSpi.engineUpdate(b, off, len); } protected byte[] engineSign() throws SignatureException { return sigSpi.engineSign(); } protected int engineSign(byte[] outbuf, int offset, int len) throws SignatureException { return sigSpi.engineSign(outbuf, offset, len); } protected boolean engineVerify(byte[] sigBytes) throws SignatureException { return sigSpi.engineVerify(sigBytes); } protected boolean engineVerify(byte[] sigBytes, int offset, int length) throws SignatureException { return sigSpi.engineVerify(sigBytes, offset, length); } /* Note: The definition of this call depends on java.security.engineSetParameter, which is deprecated. protected void engineSetParameter(String param, Object value) throws InvalidParameterException { sigSpi.engineSetParameter(param, value); } */ protected void engineSetParameter(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { sigSpi.engineSetParameter(params); } /* Note: The definition of this call depends on java.security.engineGetParameter, which is deprecated. protected Object engineGetParameter(String param) throws InvalidParameterException { return sigSpi.engineGetParameter(param); } */ protected AlgorithmParameters engineGetParameters() { return sigSpi.engineGetParameters(); } } }