1 /*
2  * Copyright (c) 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 import java.security.KeyPair;
24 import java.security.KeyPairGenerator;
25 import java.security.PrivateKey;
26 import java.security.PublicKey;
27 import java.security.SecureRandom;
28 import java.security.Signature;
29 import java.security.spec.EdDSAParameterSpec;
30 import java.util.Arrays;
31 import jdk.test.lib.Convert;
32 
33 /*
34  * @test
35  * @bug 8209632
36  * @summary Test EdDSAParameterSpec.
37  * @library /test/lib
38  * @build jdk.test.lib.Convert
39  * @run main EdDSAParamSpec
40  */
41 public class EdDSAParamSpec {
42 
43     private static final String EDDSA = "EdDSA";
44     private static final String ED25519 = "Ed25519";
45     private static final String ED448 = "Ed448";
46     private static final String PROVIDER = "SunEC";
47     private static final byte[] MSG = "TEST".getBytes();
48     private static final SecureRandom RND = new SecureRandom(new byte[]{0x1});
49 
main(String[] args)50     public static void main(String[] args) throws Exception {
51 
52         testParam(PROVIDER, EDDSA);
53         testParam(PROVIDER, ED25519);
54         testParam(PROVIDER, ED448);
55     }
56 
57     /**
58      * Test Signature.
59      */
testParam(String provider, String name)60     private static void testParam(String provider, String name)
61             throws Exception {
62 
63         KeyPair kp = genKeyPair(provider, name);
64         Signature sig = Signature.getInstance(name, provider);
65         EdDSAParameterSpec initParam
66                 = new EdDSAParameterSpec(true, "testContext".getBytes());
67         sig.setParameter(initParam);
68         byte[] origSign = sign(sig, kp.getPrivate(), MSG);
69         for (boolean preHash : new boolean[]{true, false}) {
70             System.out.printf("Testing signature for name: %s,"
71                     + " algorithm spec: (prehash:%s)%n", name, preHash);
72             verifyPublic(sig, kp.getPublic(), MSG,
73                     new EdDSAParameterSpec(preHash), initParam, origSign);
74             // Test Case with Context size combined.
75             // As per rfc8032, value of context is maximum of 255 octet
76             byte[] maxCtx = new byte[255];
77             RND.nextBytes(maxCtx);
78             for (byte[] context : new byte[][]{"others".getBytes(), maxCtx}) {
79                 System.out.printf("Testing signature for name: %s,"
80                         + " algorithm spec: (prehash:%s, context:%s)%n",
81                         name, preHash, Convert.byteArrayToHexString(context));
82                 EdDSAParameterSpec params
83                         = new EdDSAParameterSpec(preHash, context);
84                 verifyPublic(sig, kp.getPublic(), MSG, params, initParam,
85                         origSign);
86             }
87         }
88         System.out.println("Passed.");
89     }
90 
genKeyPair(String provider, String name)91     private static KeyPair genKeyPair(String provider, String name)
92             throws Exception {
93 
94         KeyPairGenerator kpg = KeyPairGenerator.getInstance(name, provider);
95         return kpg.generateKeyPair();
96     }
97 
sign(Signature sig, PrivateKey priKey, byte[] msg)98     private static byte[] sign(Signature sig, PrivateKey priKey, byte[] msg)
99             throws Exception {
100 
101         sig.initSign(priKey);
102         sig.update(msg);
103         return sig.sign();
104     }
105 
verify(Signature sig, PublicKey pubKey, byte[] msg, byte[] sign)106     private static boolean verify(Signature sig, PublicKey pubKey, byte[] msg,
107             byte[] sign) throws Exception {
108 
109         sig.initVerify(pubKey);
110         sig.update(msg);
111         return sig.verify(sign);
112     }
113 
verifyPublic(Signature sig, PublicKey pubKey, byte[] msg, EdDSAParameterSpec params, EdDSAParameterSpec initParam, byte[] origSign)114     private static void verifyPublic(Signature sig, PublicKey pubKey,
115             byte[] msg, EdDSAParameterSpec params, EdDSAParameterSpec initParam,
116             byte[] origSign) throws Exception {
117 
118         sig.setParameter(params);
119         if (verify(sig, pubKey, msg, origSign)) {
120             byte[] context = params.getContext().isPresent()
121                     ? params.getContext().get() : null;
122             byte[] initContext = initParam.getContext().isPresent()
123                     ? initParam.getContext().get() : null;
124             boolean preHash = params.isPrehash();
125             boolean initPreHash = initParam.isPrehash();
126             // The signature should not get verified other than same parameter
127             // which is set through the signature instance.
128             if (!(equals(context, initContext) && equals(preHash, initPreHash))) {
129                 throw new RuntimeException(String.format("Signature verification"
130                         + " success with different param context(actual:%s, "
131                         + "expected:%s), Prehash(actual:%s, expected:%s)",
132                         Convert.byteArrayToHexString(context),
133                         Convert.byteArrayToHexString(initContext),
134                         preHash, initPreHash));
135             } else {
136                 System.out.println("Atleast a case matched");
137             }
138         }
139     }
140 
equals(Object actual, Object expected)141     private static boolean equals(Object actual, Object expected) {
142 
143         if (actual == expected) {
144             return true;
145         }
146         if (actual == null || expected == null) {
147             return false;
148         }
149         boolean equals = actual.equals(expected);
150         if (!equals) {
151             throw new RuntimeException(String.format("Actual: %s, Expected: %s",
152                     actual, expected));
153         }
154         return equals;
155     }
156 
equals(byte[] actual, byte[] expected)157     private static boolean equals(byte[] actual, byte[] expected) {
158 
159         if (actual == expected) {
160             return true;
161         }
162         if (actual == null || expected == null) {
163             return false;
164         }
165         boolean equals = Arrays.equals(actual, expected);
166         if (!equals) {
167             throw new RuntimeException(String.format("Actual array: %s, "
168                     + "Expected array:%s", Convert.byteArrayToHexString(actual),
169                     Convert.byteArrayToHexString(expected)));
170         }
171         return equals;
172     }
173 
174 }
175