1 /*
2  * Copyright (c) 2015, 2018, 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.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 import java.security.*;
25 import java.security.spec.*;
26 import jdk.test.lib.RandomFactory;
27 
28 /*
29  * @test
30  * @bug 8050374 8181048 8146293
31  * @key randomness
32  * @summary This test validates signature verification
33  *          Signature.verify(byte[], int, int). The test uses RandomFactory to
34  *          get random set of clear text data to sign. After the signature
35  *          generation, the test tries to verify signature with the above API
36  *          and passing in different signature offset (0, 33, 66, 99).
37  * @library /test/lib
38  * @build jdk.test.lib.RandomFactory
39  * @run main Offsets SUN NONEwithDSA
40  * @run main Offsets SUN SHA1withDSA
41  * @run main Offsets SUN SHA224withDSA
42  * @run main Offsets SUN SHA256withDSA
43  * @run main Offsets SunRsaSign SHA224withRSA
44  * @run main Offsets SunRsaSign SHA256withRSA
45  * @run main Offsets SunRsaSign SHA384withRSA
46  * @run main Offsets SunRsaSign SHA512withRSA
47  * @run main Offsets SunRsaSign SHA512/224withRSA
48  * @run main Offsets SunRsaSign SHA512/256withRSA
49  */
50 public class Offsets {
51 
52     private final int size;
53     private final byte[] cleartext;
54     private final PublicKey pubkey;
55     private final Signature signature;
56     private final byte[] signed;
57 
Offsets(Signature signature, PublicKey pubkey, PrivateKey privkey, int size, byte[] cleartext)58     private Offsets(Signature signature, PublicKey pubkey, PrivateKey privkey,
59             int size, byte[] cleartext) throws InvalidKeyException,
60                 SignatureException {
61         System.out.println("Testing signature " + signature.getAlgorithm());
62         this.pubkey = pubkey;
63         this.signature = signature;
64         this.size = size;
65         this.cleartext = cleartext;
66 
67         String sigAlg = signature.getAlgorithm();
68         signature.initSign(privkey);
69         signature.update(cleartext, 0, size);
70         signed = signature.sign();
71     }
72 
getDataSize()73     int getDataSize() {
74         return size;
75     }
76 
getSignatureLength()77     int getSignatureLength() {
78         return signed.length;
79     }
80 
shiftSignData(int offset)81     byte[] shiftSignData(int offset) {
82         byte[] testSignData = new byte[offset + signed.length];
83         System.arraycopy(signed, 0, testSignData, offset,
84                 signed.length);
85         return testSignData;
86     }
87 
verifySignature(byte[] sigData, int sigOffset, int sigLength, int updateOffset, int updateLength)88     boolean verifySignature(byte[] sigData, int sigOffset, int sigLength,
89             int updateOffset, int updateLength)
90             throws InvalidKeyException, SignatureException {
91         signature.initVerify(pubkey);
92         signature.update(cleartext, updateOffset, updateLength);
93         return signature.verify(sigData, sigOffset, sigLength);
94     }
95 
init(String provider, String algorithm)96     static Offsets init(String provider, String algorithm)
97             throws NoSuchAlgorithmException, NoSuchProviderException,
98             InvalidKeyException, SignatureException {
99         // fill the cleartext data with random bytes
100         byte[] cleartext = new byte[100];
101         RandomFactory.getRandom().nextBytes(cleartext);
102 
103         // NONEwith requires input to be of 20 bytes
104         int size = algorithm.contains("NONEwith") ? 20 : 100;
105 
106         // create signature instance
107         Signature signature = Signature.getInstance(algorithm, provider);
108 
109         String keyAlgo;
110         int keySize = 2048;
111         if (algorithm.contains("RSA")) {
112             keyAlgo = "RSA";
113         } else if (algorithm.contains("ECDSA")) {
114             keyAlgo = "EC";
115             keySize = 256;
116         } else if (algorithm.contains("DSA")) {
117             keyAlgo = "DSA";
118             if (algorithm.startsWith("SHAwith") ||
119                     algorithm.startsWith("SHA1with")) {
120                 keySize = 1024;
121             }
122         } else {
123             throw new RuntimeException("Test doesn't support this signature "
124                     + "algorithm: " + algorithm);
125         }
126         KeyPairGenerator kpg = null;
127         // first try matching provider, fallback to most preferred if none available
128         try {
129             kpg = KeyPairGenerator.getInstance(keyAlgo, provider);
130         } catch (NoSuchAlgorithmException nsae) {
131             kpg = KeyPairGenerator.getInstance(keyAlgo);
132         }
133         kpg.initialize(keySize);
134         KeyPair kp = kpg.generateKeyPair();
135         PublicKey pubkey = kp.getPublic();
136         PrivateKey privkey = kp.getPrivate();
137 
138         return new Offsets(signature, pubkey, privkey, size, cleartext);
139     }
140 
main(String[] args)141     public static void main(String[] args) throws NoSuchAlgorithmException,
142             InvalidKeyException, SignatureException {
143         if (args.length < 2) {
144             throw new RuntimeException("Wrong parameters");
145         }
146 
147         boolean result = true;
148         try {
149             Offsets test = init(args[0], args[1]);
150 
151             // We are trying 3 different offsets, data size has nothing to do
152             // with signature length
153             for (int chunk = 3; chunk > 0; chunk--) {
154                 int signOffset = test.getDataSize() / chunk;
155 
156                 System.out.println("Running test with offset " + signOffset);
157                 byte[] signData = test.shiftSignData(signOffset);
158 
159                 boolean success = test.verifySignature(signData, signOffset,
160                         test.getSignatureLength(), 0, test.getDataSize());
161 
162                 if (success) {
163                     System.out.println("Successfully verified with offset "
164                             + signOffset);
165                 } else {
166                     System.out.println("Verification failed with offset "
167                             + signOffset);
168                     result = false;
169                 }
170             }
171 
172             // save signature to offset 0
173             byte[] signData = test.shiftSignData(0);
174 
175             // Negative tests
176 
177             // Test signature offset 0.
178             // Wrong test data will be passed to update,
179             // so signature verification should fail.
180             for (int chunk = 3; chunk > 0; chunk--) {
181                 int dataOffset = (test.getDataSize() - 1) / chunk;
182                 boolean success;
183                 try {
184                     success = test.verifySignature(signData, 0,
185                             test.getSignatureLength(), dataOffset,
186                             (test.getDataSize() - dataOffset));
187                 } catch (SignatureException e) {
188                     // Since we are trying different data size, it can throw
189                     // SignatureException
190                     success = false;
191                 }
192 
193                 if (!success) {
194                     System.out.println("Signature verification failed "
195                             + "as expected, with data offset " + dataOffset
196                             + " and length "
197                             + (test.getDataSize() - dataOffset));
198                 } else {
199                     System.out.println("Signature verification "
200                             + "should not succeed, with data offset "
201                             + dataOffset + " and length "
202                             + (test.getDataSize() - dataOffset));
203                     result = false;
204                 }
205             }
206 
207             // Tests with manipulating offset and length
208             result &= Offsets.checkFailure(test, signData, -1,
209                     test.getSignatureLength());
210 
211             result &= Offsets.checkFailure(test, signData, 0,
212                     test.getSignatureLength() - 1);
213 
214             result &= Offsets.checkFailure(test, signData,
215                     test.getSignatureLength() + 1, test.getSignatureLength());
216 
217             result &= Offsets.checkFailure(test, signData, 0,
218                     test.getSignatureLength() + 1);
219 
220             result &= Offsets.checkFailure(test, signData, 0, 0);
221 
222             result &= Offsets.checkFailure(test, signData, 0, -1);
223 
224             result &= Offsets.checkFailure(test, signData,
225                     2147483646, test.getSignatureLength());
226 
227             result &= Offsets.checkFailure(test, null, 0,
228                     test.getSignatureLength());
229         } catch (NoSuchProviderException nspe) {
230             System.out.println("No such provider: " + nspe);
231         }
232 
233         if (!result) {
234             throw new RuntimeException("Some test cases failed");
235         }
236     }
237 
checkFailure(Offsets test, byte[] signData, int offset, int length)238     static boolean checkFailure(Offsets test, byte[] signData, int offset,
239             int length) {
240         boolean success;
241         try {
242             success = test.verifySignature(signData, offset, length, 0,
243                     test.getDataSize());
244         } catch (IllegalArgumentException | SignatureException e) {
245             System.out.println("Expected exception: " + e);
246             success = false;
247         } catch (InvalidKeyException e) {
248             System.out.println("Unexpected exception: " + e);
249             return false;
250         }
251 
252         if (!success) {
253             System.out.println("Signature verification failed as expected, "
254                     + "with signature offset " + offset + " and length "
255                     + length);
256             return true;
257         } else {
258             System.out.println("Signature verification should not succeed, "
259                     + "with signature offset " + offset + " and length "
260                     + length);
261             return false;
262         }
263     }
264 
265 }
266