/* * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; import jdk.test.lib.RandomFactory; /* * @test * @bug 8050374 * @key randomness * @summary This test validates signature verification * Signature.verify(byte[], int, int). The test uses RandomFactory to * get random set of clear text data to sign. After the signature * generation, the test tries to verify signature with the above API * and passing in different signature offset (0, 33, 66, 99). * @library /test/lib * @build jdk.test.lib.RandomFactory * @run main Offsets SUN NONEwithDSA * @run main Offsets SUN SHA1withDSA * @run main Offsets SUN SHA224withDSA * @run main Offsets SUN SHA256withDSA */ public class Offsets { private final int size; private final byte[] cleartext; private final PublicKey pubkey; private final Signature signature; private final byte[] signed; private Offsets(Signature signature, PublicKey pubkey, PrivateKey privkey, int size, byte[] cleartext) throws InvalidKeyException, SignatureException { this.pubkey = pubkey; this.signature = signature; this.size = size; this.cleartext = cleartext; signature.initSign(privkey); signature.update(cleartext, 0, size); signed = signature.sign(); } int getDataSize() { return size; } int getSignatureLength() { return signed.length; } byte[] shiftSignData(int offset) { byte[] testSignData = new byte[offset + signed.length]; System.arraycopy(signed, 0, testSignData, offset, signed.length); return testSignData; } boolean verifySignature(byte[] sigData, int sigOffset, int sigLength, int updateOffset, int updateLength) throws InvalidKeyException, SignatureException { signature.initVerify(pubkey); signature.update(cleartext, updateOffset, updateLength); return signature.verify(sigData, sigOffset, sigLength); } static Offsets init(String provider, String algorithm) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException { // fill the cleartext data with random bytes byte[] cleartext = new byte[100]; RandomFactory.getRandom().nextBytes(cleartext); // NONEwith requires input to be of 20 bytes int size = algorithm.contains("NONEwith") ? 20 : 100; // create signature instance Signature signature = Signature.getInstance(algorithm, provider); String keyAlgo; if (algorithm.contains("RSA")) { keyAlgo = "RSA"; } else if (algorithm.contains("ECDSA")) { keyAlgo = "EC"; } else if (algorithm.contains("DSA")) { keyAlgo = "DSA"; } else { throw new RuntimeException("Test doesn't support this signature " + "algorithm: " + algorithm); } KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyAlgo, provider); KeyPair kp = kpg.generateKeyPair(); PublicKey pubkey = kp.getPublic(); PrivateKey privkey = kp.getPrivate(); return new Offsets(signature, pubkey, privkey, size, cleartext); } public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { if (args.length < 2) { throw new RuntimeException("Wrong parameters"); } boolean result = true; try { Offsets test = init(args[0], args[1]); // We are trying 3 different offsets, data size has nothing to do // with signature length for (int chunk = 3; chunk > 0; chunk--) { int signOffset = test.getDataSize() / chunk; System.out.println("Running test with offset " + signOffset); byte[] signData = test.shiftSignData(signOffset); boolean success = test.verifySignature(signData, signOffset, test.getSignatureLength(), 0, test.getDataSize()); if (success) { System.out.println("Successfully verified with offset " + signOffset); } else { System.out.println("Verification failed with offset " + signOffset); result = false; } } // save signature to offset 0 byte[] signData = test.shiftSignData(0); // Negative tests // Test signature offset 0. // Wrong test data will be passed to update, // so signature verification should fail. for (int chunk = 3; chunk > 0; chunk--) { int dataOffset = (test.getDataSize() - 1) / chunk; boolean success; try { success = test.verifySignature(signData, 0, test.getSignatureLength(), dataOffset, (test.getDataSize() - dataOffset)); } catch (SignatureException e) { // Since we are trying different data size, it can throw // SignatureException success = false; } if (!success) { System.out.println("Signature verification failed " + "as expected, with data offset " + dataOffset + " and length " + (test.getDataSize() - dataOffset)); } else { System.out.println("Signature verification " + "should not succeed, with data offset " + dataOffset + " and length " + (test.getDataSize() - dataOffset)); result = false; } } // Tests with manipulating offset and length result &= Offsets.checkFailure(test, signData, -1, test.getSignatureLength()); result &= Offsets.checkFailure(test, signData, 0, test.getSignatureLength() - 1); result &= Offsets.checkFailure(test, signData, test.getSignatureLength() + 1, test.getSignatureLength()); result &= Offsets.checkFailure(test, signData, 0, test.getSignatureLength() + 1); result &= Offsets.checkFailure(test, signData, 0, 0); result &= Offsets.checkFailure(test, signData, 0, -1); result &= Offsets.checkFailure(test, signData, 2147483646, test.getSignatureLength()); result &= Offsets.checkFailure(test, null, 0, test.getSignatureLength()); } catch (NoSuchProviderException nspe) { System.out.println("No such provider: " + nspe); } if (!result) { throw new RuntimeException("Some test cases failed"); } } static boolean checkFailure(Offsets test, byte[] signData, int offset, int length) { boolean success; try { success = test.verifySignature(signData, offset, length, 0, test.getDataSize()); } catch (IllegalArgumentException | SignatureException e) { System.out.println("Expected exception: " + e); success = false; } catch (InvalidKeyException e) { System.out.println("Unexpected exception: " + e); return false; } if (!success) { System.out.println("Signature verification failed as expected, " + "with signature offset " + offset + " and length " + length); return true; } else { System.out.println("Signature verification should not succeed, " + "with signature offset " + offset + " and length " + length); return false; } } }