1 /* 2 * Copyright (c) 2019, 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 jdk.testlibrary.Convert; 25 26 import java.security.*; 27 import java.security.spec.*; 28 import java.math.*; 29 import java.util.*; 30 31 /* 32 * @test 33 * @bug 8147502 34 * @summary Test that digests are properly truncated before the signature 35 * is applied. The digest should be truncated to the bit length of the 36 * group order. 37 * @library /lib/testlibrary 38 * @build jdk.testlibrary.Convert 39 * @run main SignatureDigestTruncate 40 */ 41 public class SignatureDigestTruncate { 42 43 /* 44 * A SecureRandom that produces nextBytes in a way that causes the nonce 45 * to be set to the value supplied to the constructor. This class 46 * is specific to the way that the native ECDSA implementation in 47 * SunEC produces nonces from random input. It may not work for all 48 * test cases, and it will need to be updated when the behavior of 49 * SunEC changes. 50 */ 51 private static class FixedRandom extends SecureRandom { 52 53 private final byte[] val; 54 FixedRandom(byte[] val)55 public FixedRandom(byte[] val) { 56 // SunEC adds one to the value returned, so subtract one here in 57 // order to get back to the correct value. 58 BigInteger biVal = new BigInteger(1, val); 59 biVal = biVal.subtract(BigInteger.ONE); 60 byte[] temp = biVal.toByteArray(); 61 this.val = new byte[val.length]; 62 int inStartPos = Math.max(0, temp.length - val.length); 63 int outStartPos = Math.max(0, val.length - temp.length); 64 System.arraycopy(temp, inStartPos, this.val, outStartPos, 65 temp.length - inStartPos); 66 } 67 68 @Override nextBytes(byte[] bytes)69 public void nextBytes(byte[] bytes) { 70 // SunEC samples (n + 1) * 2 bytes, but only n*2 bytes are used by 71 // the native implementation. So the value must be offset slightly. 72 Arrays.fill(bytes, (byte) 0); 73 int copyLength = Math.min(val.length, bytes.length - 2); 74 System.arraycopy(val, 0, bytes, bytes.length - copyLength - 2, 75 copyLength); 76 } 77 } 78 assertEquals(byte[] expected, byte[] actual, String name)79 private static void assertEquals(byte[] expected, byte[] actual, 80 String name) { 81 if (!Arrays.equals(actual, expected)) { 82 System.out.println("expect: " 83 + Convert.byteArrayToHexString(expected)); 84 System.out.println("actual: " 85 + Convert.byteArrayToHexString(actual)); 86 throw new RuntimeException("Incorrect " + name + " value"); 87 } 88 } 89 runTest(String alg, String curveName, String privateKeyStr, String msgStr, String kStr, String sigStr)90 private static void runTest(String alg, String curveName, 91 String privateKeyStr, String msgStr, String kStr, String sigStr) 92 throws Exception { 93 94 System.out.println("Testing " + alg + " with " + curveName); 95 96 byte[] privateKey = Convert.hexStringToByteArray(privateKeyStr); 97 byte[] msg = Convert.hexStringToByteArray(msgStr); 98 byte[] k = Convert.hexStringToByteArray(kStr); 99 byte[] expectedSig = Convert.hexStringToByteArray(sigStr); 100 101 AlgorithmParameters params = 102 AlgorithmParameters.getInstance("EC", "SunEC"); 103 params.init(new ECGenParameterSpec(curveName)); 104 ECParameterSpec ecParams = 105 params.getParameterSpec(ECParameterSpec.class); 106 107 KeyFactory kf = KeyFactory.getInstance("EC", "SunEC"); 108 BigInteger s = new BigInteger(1, privateKey); 109 ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(s, ecParams); 110 PrivateKey privKey = kf.generatePrivate(privKeySpec); 111 112 Signature sig = Signature.getInstance(alg, "SunEC"); 113 sig.initSign(privKey, new FixedRandom(k)); 114 sig.update(msg); 115 byte[] computedSig = sig.sign(); 116 assertEquals(expectedSig, computedSig, "signature"); 117 } 118 main(String[] args)119 public static void main(String[] args) throws Exception { 120 runTest("SHA384withECDSA", "sect283r1", 121 "abcdef10234567", "010203040506070809", 122 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d" + 123 "1e1f20212223", 124 "304c022401d7544b5d3935216bd45e2f8042537e1e0296a11e0eb9666619" + 125 "9281b40942abccd5358a0224035de8a314d3e6c2a97614daebf5fb131354" + 126 "0eec3f9a3272068aa10922ccae87d255c84c"); 127 } 128 } 129