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