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