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 * @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 if (algorithm.contains("RSA")) { 109 keyAlgo = "RSA"; 110 } else if (algorithm.contains("ECDSA")) { 111 keyAlgo = "EC"; 112 } else if (algorithm.contains("DSA")) { 113 keyAlgo = "DSA"; 114 } else { 115 throw new RuntimeException("Test doesn't support this signature " 116 + "algorithm: " + algorithm); 117 } 118 119 KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyAlgo, provider); 120 KeyPair kp = kpg.generateKeyPair(); 121 PublicKey pubkey = kp.getPublic(); 122 PrivateKey privkey = kp.getPrivate(); 123 124 return new Offsets(signature, pubkey, privkey, size, cleartext); 125 } 126 127 public static void main(String[] args) throws NoSuchAlgorithmException, 128 InvalidKeyException, SignatureException { 129 if (args.length < 2) { 130 throw new RuntimeException("Wrong parameters"); 131 } 132 133 boolean result = true; 134 try { 135 Offsets test = init(args[0], args[1]); 136 137 // We are trying 3 different offsets, data size has nothing to do 138 // with signature length 139 for (int chunk = 3; chunk > 0; chunk--) { 140 int signOffset = test.getDataSize() / chunk; 141 142 System.out.println("Running test with offset " + signOffset); 143 byte[] signData = test.shiftSignData(signOffset); 144 145 boolean success = test.verifySignature(signData, signOffset, 146 test.getSignatureLength(), 0, test.getDataSize()); 147 148 if (success) { 149 System.out.println("Successfully verified with offset " 150 + signOffset); 151 } else { 152 System.out.println("Verification failed with offset " 153 + signOffset); 154 result = false; 155 } 156 } 157 158 // save signature to offset 0 159 byte[] signData = test.shiftSignData(0); 160 161 // Negative tests 162 163 // Test signature offset 0. 164 // Wrong test data will be passed to update, 165 // so signature verification should fail. 166 for (int chunk = 3; chunk > 0; chunk--) { 167 int dataOffset = (test.getDataSize() - 1) / chunk; 168 boolean success; 169 try { 170 success = test.verifySignature(signData, 0, 171 test.getSignatureLength(), dataOffset, 172 (test.getDataSize() - dataOffset)); 173 } catch (SignatureException e) { 174 // Since we are trying different data size, it can throw 175 // SignatureException 176 success = false; 177 } 178 179 if (!success) { 180 System.out.println("Signature verification failed " 181 + "as expected, with data offset " + dataOffset 182 + " and length " 183 + (test.getDataSize() - dataOffset)); 184 } else { 185 System.out.println("Signature verification " 186 + "should not succeed, with data offset " 187 + dataOffset + " and length " 188 + (test.getDataSize() - dataOffset)); 189 result = false; 190 } 191 } 192 193 // Tests with manipulating offset and length 194 result &= Offsets.checkFailure(test, signData, -1, 195 test.getSignatureLength()); 196 197 result &= Offsets.checkFailure(test, signData, 0, 198 test.getSignatureLength() - 1); 199 200 result &= Offsets.checkFailure(test, signData, 201 test.getSignatureLength() + 1, test.getSignatureLength()); 202 203 result &= Offsets.checkFailure(test, signData, 0, 204 test.getSignatureLength() + 1); 205 206 result &= Offsets.checkFailure(test, signData, 0, 0); 207 208 result &= Offsets.checkFailure(test, signData, 0, -1); 209 210 result &= Offsets.checkFailure(test, signData, 211 2147483646, test.getSignatureLength()); 212 213 result &= Offsets.checkFailure(test, null, 0, 214 test.getSignatureLength()); 215 } catch (NoSuchProviderException nspe) { 216 System.out.println("No such provider: " + nspe); 217 } 218 219 if (!result) { 220 throw new RuntimeException("Some test cases failed"); 221 } 222 } 223 224 static boolean checkFailure(Offsets test, byte[] signData, int offset, 225 int length) { 226 boolean success; 227 try { 228 success = test.verifySignature(signData, offset, length, 0, 229 test.getDataSize()); 230 } catch (IllegalArgumentException | SignatureException e) { 231 System.out.println("Expected exception: " + e); 232 success = false; 233 } catch (InvalidKeyException e) { 234 System.out.println("Unexpected exception: " + e); 235 return false; 236 } 237 238 if (!success) { 239 System.out.println("Signature verification failed as expected, " 240 + "with signature offset " + offset + " and length " 241 + length); 242 return true; 243 } else { 244 System.out.println("Signature verification should not succeed, " 245 + "with signature offset " + offset + " and length " 246 + length); 247 return false; 248 } 249 } 250 251 }