1 /* 2 * Copyright (c) 2015, 2017, 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.InvalidKeyException; 25 import java.security.KeyPair; 26 import java.security.KeyPairGenerator; 27 import java.security.NoSuchAlgorithmException; 28 import java.security.NoSuchProviderException; 29 import java.security.PrivateKey; 30 import java.security.PublicKey; 31 import java.security.Signature; 32 import java.security.SignatureException; 33 import jdk.test.lib.RandomFactory; 34 35 /* 36 * @test 37 * @bug 8050374 38 * @key randomness 39 * @summary This test validates signature verification 40 * Signature.verify(byte[], int, int). The test uses RandomFactory to 41 * get random set of clear text data to sign. After the signature 42 * generation, the test tries to verify signature with the above API 43 * and passing in different signature offset (0, 33, 66, 99). 44 * @library /test/lib 45 * @build jdk.test.lib.RandomFactory 46 * @run main Offsets SUN NONEwithDSA 47 * @run main Offsets SUN SHA1withDSA 48 * @run main Offsets SUN SHA224withDSA 49 * @run main Offsets SUN SHA256withDSA 50 */ 51 public class Offsets { 52 53 private final int size; 54 private final byte[] cleartext; 55 private final PublicKey pubkey; 56 private final Signature signature; 57 private final byte[] signed; 58 59 private Offsets(Signature signature, PublicKey pubkey, PrivateKey privkey, 60 int size, byte[] cleartext) throws InvalidKeyException, 61 SignatureException { 62 this.pubkey = pubkey; 63 this.signature = signature; 64 this.size = size; 65 this.cleartext = cleartext; 66 67 signature.initSign(privkey); 68 signature.update(cleartext, 0, size); 69 signed = signature.sign(); 70 } 71 72 int getDataSize() { 73 return size; 74 } 75 76 int getSignatureLength() { 77 return signed.length; 78 } 79 80 byte[] shiftSignData(int offset) { 81 byte[] testSignData = new byte[offset + signed.length]; 82 System.arraycopy(signed, 0, testSignData, offset, 83 signed.length); 84 return testSignData; 85 } 86 87 boolean verifySignature(byte[] sigData, int sigOffset, int sigLength, 88 int updateOffset, int updateLength) 89 throws InvalidKeyException, SignatureException { 90 signature.initVerify(pubkey); 91 signature.update(cleartext, updateOffset, updateLength); 92 return signature.verify(sigData, sigOffset, sigLength); 93 } 94 95 static Offsets init(String provider, String algorithm) 96 throws NoSuchAlgorithmException, NoSuchProviderException, 97 InvalidKeyException, SignatureException { 98 // fill the cleartext data with random bytes 99 byte[] cleartext = new byte[100]; 100 RandomFactory.getRandom().nextBytes(cleartext); 101 102 // NONEwith requires input to be of 20 bytes 103 int size = algorithm.contains("NONEwith") ? 20 : 100; 104 105 // create signature instance 106 Signature signature = Signature.getInstance(algorithm, provider); 107 108 String keyAlgo; 109 if (algorithm.contains("RSA")) { 110 keyAlgo = "RSA"; 111 } else if (algorithm.contains("ECDSA")) { 112 keyAlgo = "EC"; 113 } else if (algorithm.contains("DSA")) { 114 keyAlgo = "DSA"; 115 } else { 116 throw new RuntimeException("Test doesn't support this signature " 117 + "algorithm: " + algorithm); 118 } 119 120 KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyAlgo, provider); 121 KeyPair kp = kpg.generateKeyPair(); 122 PublicKey pubkey = kp.getPublic(); 123 PrivateKey privkey = kp.getPrivate(); 124 125 return new Offsets(signature, pubkey, privkey, size, cleartext); 126 } 127 128 public static void main(String[] args) throws NoSuchAlgorithmException, 129 InvalidKeyException, SignatureException { 130 if (args.length < 2) { 131 throw new RuntimeException("Wrong parameters"); 132 } 133 134 boolean result = true; 135 try { 136 Offsets test = init(args[0], args[1]); 137 138 // We are trying 3 different offsets, data size has nothing to do 139 // with signature length 140 for (int chunk = 3; chunk > 0; chunk--) { 141 int signOffset = test.getDataSize() / chunk; 142 143 System.out.println("Running test with offset " + signOffset); 144 byte[] signData = test.shiftSignData(signOffset); 145 146 boolean success = test.verifySignature(signData, signOffset, 147 test.getSignatureLength(), 0, test.getDataSize()); 148 149 if (success) { 150 System.out.println("Successfully verified with offset " 151 + signOffset); 152 } else { 153 System.out.println("Verification failed with offset " 154 + signOffset); 155 result = false; 156 } 157 } 158 159 // save signature to offset 0 160 byte[] signData = test.shiftSignData(0); 161 162 // Negative tests 163 164 // Test signature offset 0. 165 // Wrong test data will be passed to update, 166 // so signature verification should fail. 167 for (int chunk = 3; chunk > 0; chunk--) { 168 int dataOffset = (test.getDataSize() - 1) / chunk; 169 boolean success; 170 try { 171 success = test.verifySignature(signData, 0, 172 test.getSignatureLength(), dataOffset, 173 (test.getDataSize() - dataOffset)); 174 } catch (SignatureException e) { 175 // Since we are trying different data size, it can throw 176 // SignatureException 177 success = false; 178 } 179 180 if (!success) { 181 System.out.println("Signature verification failed " 182 + "as expected, with data offset " + dataOffset 183 + " and length " 184 + (test.getDataSize() - dataOffset)); 185 } else { 186 System.out.println("Signature verification " 187 + "should not succeed, with data offset " 188 + dataOffset + " and length " 189 + (test.getDataSize() - dataOffset)); 190 result = false; 191 } 192 } 193 194 // Tests with manipulating offset and length 195 result &= Offsets.checkFailure(test, signData, -1, 196 test.getSignatureLength()); 197 198 result &= Offsets.checkFailure(test, signData, 0, 199 test.getSignatureLength() - 1); 200 201 result &= Offsets.checkFailure(test, signData, 202 test.getSignatureLength() + 1, test.getSignatureLength()); 203 204 result &= Offsets.checkFailure(test, signData, 0, 205 test.getSignatureLength() + 1); 206 207 result &= Offsets.checkFailure(test, signData, 0, 0); 208 209 result &= Offsets.checkFailure(test, signData, 0, -1); 210 211 result &= Offsets.checkFailure(test, signData, 212 2147483646, test.getSignatureLength()); 213 214 result &= Offsets.checkFailure(test, null, 0, 215 test.getSignatureLength()); 216 } catch (NoSuchProviderException nspe) { 217 System.out.println("No such provider: " + nspe); 218 } 219 220 if (!result) { 221 throw new RuntimeException("Some test cases failed"); 222 } 223 } 224 225 static boolean checkFailure(Offsets test, byte[] signData, int offset, 226 int length) { 227 boolean success; 228 try { 229 success = test.verifySignature(signData, offset, length, 0, 230 test.getDataSize()); 231 } catch (IllegalArgumentException | SignatureException e) { 232 System.out.println("Expected exception: " + e); 233 success = false; 234 } catch (InvalidKeyException e) { 235 System.out.println("Unexpected exception: " + e); 236 return false; 237 } 238 239 if (!success) { 240 System.out.println("Signature verification failed as expected, " 241 + "with signature offset " + offset + " and length " 242 + length); 243 return true; 244 } else { 245 System.out.println("Signature verification should not succeed, " 246 + "with signature offset " + offset + " and length " 247 + length); 248 return false; 249 } 250 } 251 252 }