1/*
2 * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.security.rsa;
27
28import java.io.IOException;
29import java.nio.ByteBuffer;
30
31import java.security.*;
32import java.security.interfaces.*;
33
34import sun.security.util.*;
35import sun.security.x509.AlgorithmId;
36
37/**
38 * PKCS#1 RSA signatures with the various message digest algorithms.
39 * This file contains an abstract base class with all the logic plus
40 * a nested static class for each of the message digest algorithms
41 * (see end of the file). We support MD2, MD5, SHA-1, SHA-224, SHA-256,
42 * SHA-384, and SHA-512.
43 *
44 * @since   1.5
45 * @author  Andreas Sterbenz
46 */
47public abstract class RSASignature extends SignatureSpi {
48
49    // we sign an ASN.1 SEQUENCE of AlgorithmId and digest
50    // it has the form 30:xx:30:xx:[digestOID]:05:00:04:xx:[digest]
51    // this means the encoded length is (8 + digestOID.length + digest.length)
52    private static final int baseLength = 8;
53
54    // object identifier for the message digest algorithm used
55    private final ObjectIdentifier digestOID;
56
57    // length of the encoded signature blob
58    private final int encodedLength;
59
60    // message digest implementation we use
61    private final MessageDigest md;
62    // flag indicating whether the digest is reset
63    private boolean digestReset;
64
65    // private key, if initialized for signing
66    private RSAPrivateKey privateKey;
67    // public key, if initialized for verifying
68    private RSAPublicKey publicKey;
69
70    // padding to use, set when the initSign/initVerify is called
71    private RSAPadding padding;
72
73    /**
74     * Construct a new RSASignature. Used by subclasses.
75     */
76    RSASignature(String algorithm, ObjectIdentifier digestOID, int oidLength) {
77        this.digestOID = digestOID;
78        try {
79            md = MessageDigest.getInstance(algorithm);
80        } catch (NoSuchAlgorithmException e) {
81            throw new ProviderException(e);
82        }
83        digestReset = true;
84        encodedLength = baseLength + oidLength + md.getDigestLength();
85    }
86
87    // initialize for verification. See JCA doc
88    protected void engineInitVerify(PublicKey publicKey)
89            throws InvalidKeyException {
90        RSAPublicKey rsaKey = (RSAPublicKey)RSAKeyFactory.toRSAKey(publicKey);
91        this.privateKey = null;
92        this.publicKey = rsaKey;
93        initCommon(rsaKey, null);
94    }
95
96    // initialize for signing. See JCA doc
97    protected void engineInitSign(PrivateKey privateKey)
98            throws InvalidKeyException {
99        engineInitSign(privateKey, null);
100    }
101
102    // initialize for signing. See JCA doc
103    protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
104            throws InvalidKeyException {
105        RSAPrivateKey rsaKey =
106            (RSAPrivateKey)RSAKeyFactory.toRSAKey(privateKey);
107        this.privateKey = rsaKey;
108        this.publicKey = null;
109        initCommon(rsaKey, random);
110    }
111
112    /**
113     * Init code common to sign and verify.
114     */
115    private void initCommon(RSAKey rsaKey, SecureRandom random)
116            throws InvalidKeyException {
117        resetDigest();
118        int keySize = RSACore.getByteLength(rsaKey);
119        try {
120            padding = RSAPadding.getInstance
121                (RSAPadding.PAD_BLOCKTYPE_1, keySize, random);
122        } catch (InvalidAlgorithmParameterException iape) {
123            throw new InvalidKeyException(iape.getMessage());
124        }
125        int maxDataSize = padding.getMaxDataSize();
126        if (encodedLength > maxDataSize) {
127            throw new InvalidKeyException
128                ("Key is too short for this signature algorithm");
129        }
130    }
131
132    /**
133     * Reset the message digest if it is not already reset.
134     */
135    private void resetDigest() {
136        if (digestReset == false) {
137            md.reset();
138            digestReset = true;
139        }
140    }
141
142    /**
143     * Return the message digest value.
144     */
145    private byte[] getDigestValue() {
146        digestReset = true;
147        return md.digest();
148    }
149
150    // update the signature with the plaintext data. See JCA doc
151    protected void engineUpdate(byte b) throws SignatureException {
152        md.update(b);
153        digestReset = false;
154    }
155
156    // update the signature with the plaintext data. See JCA doc
157    protected void engineUpdate(byte[] b, int off, int len)
158            throws SignatureException {
159        md.update(b, off, len);
160        digestReset = false;
161    }
162
163    // update the signature with the plaintext data. See JCA doc
164    protected void engineUpdate(ByteBuffer b) {
165        md.update(b);
166        digestReset = false;
167    }
168
169    // sign the data and return the signature. See JCA doc
170    protected byte[] engineSign() throws SignatureException {
171        byte[] digest = getDigestValue();
172        try {
173            byte[] encoded = encodeSignature(digestOID, digest);
174            byte[] padded = padding.pad(encoded);
175            byte[] encrypted = RSACore.rsa(padded, privateKey, true);
176            return encrypted;
177        } catch (GeneralSecurityException e) {
178            throw new SignatureException("Could not sign data", e);
179        } catch (IOException e) {
180            throw new SignatureException("Could not encode data", e);
181        }
182    }
183
184    // verify the data and return the result. See JCA doc
185    // should be reset to the state after engineInitVerify call.
186    protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
187        try {
188            if (sigBytes.length != RSACore.getByteLength(publicKey)) {
189                throw new SignatureException("Signature length not correct: got " +
190                    sigBytes.length + " but was expecting " +
191                    RSACore.getByteLength(publicKey));
192            }
193            byte[] digest = getDigestValue();
194            byte[] decrypted = RSACore.rsa(sigBytes, publicKey);
195            byte[] unpadded = padding.unpad(decrypted);
196            byte[] decodedDigest = decodeSignature(digestOID, unpadded);
197            return MessageDigest.isEqual(digest, decodedDigest);
198        } catch (javax.crypto.BadPaddingException e) {
199            // occurs if the app has used the wrong RSA public key
200            // or if sigBytes is invalid
201            // return false rather than propagating the exception for
202            // compatibility/ease of use
203            return false;
204        } catch (IOException e) {
205            throw new SignatureException("Signature encoding error", e);
206        } finally {
207            resetDigest();
208        }
209    }
210
211    /**
212     * Encode the digest, return the to-be-signed data.
213     * Also used by the PKCS#11 provider.
214     */
215    public static byte[] encodeSignature(ObjectIdentifier oid, byte[] digest)
216            throws IOException {
217        DerOutputStream out = new DerOutputStream();
218        new AlgorithmId(oid).encode(out);
219        out.putOctetString(digest);
220        DerValue result =
221            new DerValue(DerValue.tag_Sequence, out.toByteArray());
222        return result.toByteArray();
223    }
224
225    /**
226     * Decode the signature data. Verify that the object identifier matches
227     * and return the message digest.
228     */
229    public static byte[] decodeSignature(ObjectIdentifier oid, byte[] sig)
230            throws IOException {
231        // Enforce strict DER checking for signatures
232        DerInputStream in = new DerInputStream(sig, 0, sig.length, false);
233        DerValue[] values = in.getSequence(2);
234        if ((values.length != 2) || (in.available() != 0)) {
235            throw new IOException("SEQUENCE length error");
236        }
237        AlgorithmId algId = AlgorithmId.parse(values[0]);
238        if (algId.getOID().equals(oid) == false) {
239            throw new IOException("ObjectIdentifier mismatch: "
240                + algId.getOID());
241        }
242        if (algId.getEncodedParams() != null) {
243            throw new IOException("Unexpected AlgorithmId parameters");
244        }
245        byte[] digest = values[1].getOctetString();
246        return digest;
247    }
248
249    // set parameter, not supported. See JCA doc
250    @Deprecated
251    protected void engineSetParameter(String param, Object value)
252            throws InvalidParameterException {
253        throw new UnsupportedOperationException("setParameter() not supported");
254    }
255
256    // get parameter, not supported. See JCA doc
257    @Deprecated
258    protected Object engineGetParameter(String param)
259            throws InvalidParameterException {
260        throw new UnsupportedOperationException("getParameter() not supported");
261    }
262
263    // Nested class for MD2withRSA signatures
264    public static final class MD2withRSA extends RSASignature {
265        public MD2withRSA() {
266            super("MD2", AlgorithmId.MD2_oid, 10);
267        }
268    }
269
270    // Nested class for MD5withRSA signatures
271    public static final class MD5withRSA extends RSASignature {
272        public MD5withRSA() {
273            super("MD5", AlgorithmId.MD5_oid, 10);
274        }
275    }
276
277    // Nested class for SHA1withRSA signatures
278    public static final class SHA1withRSA extends RSASignature {
279        public SHA1withRSA() {
280            super("SHA-1", AlgorithmId.SHA_oid, 7);
281        }
282    }
283
284    // Nested class for SHA224withRSA signatures
285    public static final class SHA224withRSA extends RSASignature {
286        public SHA224withRSA() {
287            super("SHA-224", AlgorithmId.SHA224_oid, 11);
288        }
289    }
290
291    // Nested class for SHA256withRSA signatures
292    public static final class SHA256withRSA extends RSASignature {
293        public SHA256withRSA() {
294            super("SHA-256", AlgorithmId.SHA256_oid, 11);
295        }
296    }
297
298    // Nested class for SHA384withRSA signatures
299    public static final class SHA384withRSA extends RSASignature {
300        public SHA384withRSA() {
301            super("SHA-384", AlgorithmId.SHA384_oid, 11);
302        }
303    }
304
305    // Nested class for SHA512withRSA signatures
306    public static final class SHA512withRSA extends RSASignature {
307        public SHA512withRSA() {
308            super("SHA-512", AlgorithmId.SHA512_oid, 11);
309        }
310    }
311
312}
313