1293 lines · 48.4 KB · Java
RawDownload
/* * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code 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.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 in the LICENSE file that * accompanied this code). * * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.security; import java.security.spec.AlgorithmParameterSpec;import java.util.*;import java.util.concurrent.ConcurrentHashMap;import java.io.*;import java.security.cert.Certificate;import java.security.cert.X509Certificate; import java.nio.ByteBuffer; import java.security.Provider.Service; import javax.crypto.Cipher;import javax.crypto.CipherSpi;import javax.crypto.IllegalBlockSizeException;import javax.crypto.BadPaddingException;import javax.crypto.NoSuchPaddingException; import sun.security.util.Debug;import sun.security.jca.*;import sun.security.jca.GetInstance.Instance; /** * The 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> 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. * * <p> Every implementation of the Java platform is required to support the * following standard <code>Signature</code> algorithms: * <ul> * <li><tt>SHA1withDSA</tt></li> * <li><tt>SHA1withRSA</tt></li> * <li><tt>SHA256withRSA</tt></li> * </ul> * These algorithms are described in the <a href= * "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature"> * Signature section</a> of the * Java Cryptography Architecture Standard Algorithm Name Documentation. * Consult the release documentation for your implementation to see if any * other algorithms are supported. * * @author Benjamin Renaud * */ public abstract class Signature extends SignatureSpi {     private static final Debug debug =                        Debug.getInstance("jca", "Signature");     /*     * 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    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 the Signature section in the <a href=     * "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>     * for information about standard algorithm names.     */    protected Signature(String algorithm) {        this.algorithm = algorithm;    }     // name of the special signature alg    private final static String RSA_SIGNATURE = "NONEwithRSA";     // name of the equivalent cipher alg    private final static String RSA_CIPHER = "RSA/ECB/PKCS1Padding";     // all the services we need to lookup for compatibility with Cipher    private final static List<ServiceId> rsaIds = Arrays.asList(        new ServiceId[] {            new ServiceId("Signature", "NONEwithRSA"),            new ServiceId("Cipher", "RSA/ECB/PKCS1Padding"),            new ServiceId("Cipher", "RSA/ECB"),            new ServiceId("Cipher", "RSA//PKCS1Padding"),            new ServiceId("Cipher", "RSA"),        }    );     /**     * Returns a Signature object that implements the specified signature     * algorithm.     *     * <p> This method traverses the list of registered security Providers,     * starting with the most preferred Provider.     * A new Signature object encapsulating the     * SignatureSpi implementation from the first     * Provider that supports the specified algorithm is returned.     *     * <p> Note that the list of registered providers may be retrieved via     * the {@link Security#getProviders() Security.getProviders()} method.     *     * @param algorithm the standard name of the algorithm requested.     * See the Signature section in the <a href=     * "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>     * for information about standard algorithm names.     *     * @return the new Signature object.     *     * @exception NoSuchAlgorithmException if no Provider supports a     *          Signature implementation for the     *          specified algorithm.     *     * @see Provider     */    public static Signature getInstance(String algorithm)            throws NoSuchAlgorithmException {        List<Service> list;        if (algorithm.equalsIgnoreCase(RSA_SIGNATURE)) {            list = GetInstance.getServices(rsaIds);        } else {            list = GetInstance.getServices("Signature", algorithm);        }        Iterator<Service> t = list.iterator();        if (t.hasNext() == false) {            throw new NoSuchAlgorithmException                (algorithm + " Signature not available");        }        // try services until we find an Spi or a working Signature subclass        NoSuchAlgorithmException failure;        do {            Service s = t.next();            if (isSpi(s)) {                return new Delegate(s, t, algorithm);            } else {                // must be a subclass of Signature, disable dynamic selection                try {                    Instance instance =                        GetInstance.getInstance(s, SignatureSpi.class);                    return getInstance(instance, algorithm);                } catch (NoSuchAlgorithmException e) {                    failure = e;                }            }        } while (t.hasNext());        throw failure;    }     private static Signature getInstance(Instance instance, String algorithm) {        Signature sig;        if (instance.impl instanceof Signature) {            sig = (Signature)instance.impl;        } else {            SignatureSpi spi = (SignatureSpi)instance.impl;            sig = new Delegate(spi, algorithm);        }        sig.provider = instance.provider;        return sig;    }     private final static Map<String,Boolean> signatureInfo;     static {        signatureInfo = new ConcurrentHashMap<String,Boolean>();        Boolean TRUE = Boolean.TRUE;        // pre-initialize with values for our SignatureSpi implementations        signatureInfo.put("sun.security.provider.DSA$RawDSA", TRUE);        signatureInfo.put("sun.security.provider.DSA$SHA1withDSA", TRUE);        signatureInfo.put("sun.security.rsa.RSASignature$MD2withRSA", TRUE);        signatureInfo.put("sun.security.rsa.RSASignature$MD5withRSA", TRUE);        signatureInfo.put("sun.security.rsa.RSASignature$SHA1withRSA", TRUE);        signatureInfo.put("sun.security.rsa.RSASignature$SHA256withRSA", TRUE);        signatureInfo.put("sun.security.rsa.RSASignature$SHA384withRSA", TRUE);        signatureInfo.put("sun.security.rsa.RSASignature$SHA512withRSA", TRUE);        signatureInfo.put("com.sun.net.ssl.internal.ssl.RSASignature", TRUE);        signatureInfo.put("sun.security.pkcs11.P11Signature", TRUE);    }     private static boolean isSpi(Service s) {        if (s.getType().equals("Cipher")) {            // must be a CipherSpi, which we can wrap with the CipherAdapter            return true;        }        String className = s.getClassName();        Boolean result = signatureInfo.get(className);        if (result == null) {            try {                Object instance = s.newInstance(null);                // Signature extends SignatureSpi                // so it is a "real" Spi if it is an                // instance of SignatureSpi but not Signature                boolean r = (instance instanceof SignatureSpi)                                && (instance instanceof Signature == false);                if ((debug != null) && (r == false)) {                    debug.println("Not a SignatureSpi " + className);                    debug.println("Delayed provider selection may not be "                        + "available for algorithm " + s.getAlgorithm());                }                result = Boolean.valueOf(r);                signatureInfo.put(className, result);            } catch (Exception e) {                // something is wrong, assume not an SPI                return false;            }        }        return result.booleanValue();    }     /**     * Returns a Signature object that implements the specified signature     * algorithm.     *     * <p> A new Signature object encapsulating the     * SignatureSpi implementation from the specified provider     * is returned.  The specified provider must be registered     * in the security provider list.     *     * <p> Note that the list of registered providers may be retrieved via     * the {@link Security#getProviders() Security.getProviders()} method.     *     * @param algorithm the name of the algorithm requested.     * See the Signature section in the <a href=     * "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>     * for information about standard algorithm names.     *     * @param provider the name of the provider.     *     * @return the new Signature object.     *     * @exception NoSuchAlgorithmException if a SignatureSpi     *          implementation for the specified algorithm is not     *          available from the specified provider.     *     * @exception NoSuchProviderException if the specified provider is not     *          registered in the security provider list.     *     * @exception IllegalArgumentException if the provider name is null     *          or empty.     *     * @see Provider     */    public static Signature getInstance(String algorithm, String provider)            throws NoSuchAlgorithmException, NoSuchProviderException {        if (algorithm.equalsIgnoreCase(RSA_SIGNATURE)) {            // exception compatibility with existing code            if ((provider == null) || (provider.length() == 0)) {                throw new IllegalArgumentException("missing provider");            }            Provider p = Security.getProvider(provider);            if (p == null) {                throw new NoSuchProviderException                    ("no such provider: " + provider);            }            return getInstanceRSA(p);        }        Instance instance = GetInstance.getInstance                ("Signature", SignatureSpi.class, algorithm, provider);        return getInstance(instance, algorithm);    }     /**     * Returns a Signature object that implements the specified     * signature algorithm.     *     * <p> A new Signature object encapsulating the     * SignatureSpi implementation from the specified Provider     * object is returned.  Note that the specified Provider object     * does not have to be registered in the provider list.     *     * @param algorithm the name of the algorithm requested.     * See the Signature section in the <a href=     * "{@docRoot}/../technotes/guides/security/StandardNames.html#Signature">     * Java Cryptography Architecture Standard Algorithm Name Documentation</a>     * for information about standard algorithm names.     *     * @param provider the provider.     *     * @return the new Signature object.     *     * @exception NoSuchAlgorithmException if a SignatureSpi     *          implementation for the specified algorithm is not available     *          from the specified Provider object.     *     * @exception IllegalArgumentException if the provider is null.     *     * @see Provider     *     * @since 1.4     */    public static Signature getInstance(String algorithm, Provider provider)            throws NoSuchAlgorithmException {        if (algorithm.equalsIgnoreCase(RSA_SIGNATURE)) {            // exception compatibility with existing code            if (provider == null) {                throw new IllegalArgumentException("missing provider");            }            return getInstanceRSA(provider);        }        Instance instance = GetInstance.getInstance                ("Signature", SignatureSpi.class, algorithm, provider);        return getInstance(instance, algorithm);    }     // return an implementation for NONEwithRSA, which is a special case    // because of the Cipher.RSA/ECB/PKCS1Padding compatibility wrapper    private static Signature getInstanceRSA(Provider p)            throws NoSuchAlgorithmException {        // try Signature first        Service s = p.getService("Signature", RSA_SIGNATURE);        if (s != null) {            Instance instance = GetInstance.getInstance(s, SignatureSpi.class);            return getInstance(instance, RSA_SIGNATURE);        }        // check Cipher        try {            Cipher c = Cipher.getInstance(RSA_CIPHER, p);            return new Delegate(new CipherAdapter(c), RSA_SIGNATURE);        } catch (GeneralSecurityException e) {            // throw Signature style exception message to avoid confusion,            // but append Cipher exception as cause            throw new NoSuchAlgorithmException("no such algorithm: "                + RSA_SIGNATURE + " for provider " + p.getName(), e);        }    }     /**     * Returns the provider of this signature object.     *     * @return the provider of this signature object     */    public final Provider getProvider() {        chooseFirstProvider();        return this.provider;    }     void chooseFirstProvider() {        // empty, overridden in Delegate    }     /**     * 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.     * @since 1.3     */    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<String> critSet = cert.getCriticalExtensionOIDs();             if (critSet != null && !critSet.isEmpty()                && critSet.contains("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

Lines 1–500 of 1293.