1 /*
  2  * Copyright (c) 2015, 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.util.*;
 27 import jdk.test.lib.SigTestUtil;
 28 import static jdk.test.lib.SigTestUtil.SignatureType;
 29 
 30 /*
 31  * @test
 32  * @bug 8050374 8181048 8146293
 33  * @summary Verify a chain of signed objects
 34  * @library /test/lib
 35  * @build jdk.test.lib.SigTestUtil
 36  * @run main Chain
 37  */
 38 public class Chain {
 39 
 40     static enum KeyAlg {
 41         RSA("RSA"),
 42         DSA("DSA"),
 43         EC("EC");
 44 
 45         final String name;
 46 
 47         KeyAlg(String alg) {
 48             this.name = alg;
 49         }
 50     }
 51 
 52     static enum Provider {
 53         Default("default"),
 54         SunRsaSign("SunRsaSign"),
 55         Sun("SUN"),
 56         SunEC("SunEC"),
 57         SunJSSE("SunJSSE"),
 58         SunMSCAPI("SunMSCAPI");
 59 
 60         final String name;
 61 
 62         Provider(String name) {
 63             this.name = name;
 64         }
 65     }
 66 
 67     static enum SigAlg {
 68         MD2withRSA("MD2withRSA"),
 69         MD5withRSA("md5withRSA"),
 70 
 71         SHA1withDSA("SHA1withDSA"),
 72         SHA224withDSA("SHA224withDSA"),
 73         SHA256withDSA("SHA256withDSA"),
 74         SHA384withDSA("SHA384withDSA"),
 75         SHA512withDSA("SHA512withDSA"),
 76 
 77         SHA3_224withDSA("SHA3-224withDSA"),
 78         SHA3_256withDSA("SHA3-256withDSA"),
 79         SHA3_384withDSA("SHA3-384withDSA"),
 80         SHA3_512withDSA("SHA3-512withDSA"),
 81 
 82         SHA1withRSA("Sha1withrSA"),
 83         SHA224withRSA("SHA224withRSA"),
 84         SHA256withRSA("SHA256withRSA"),
 85         SHA384withRSA("SHA384withRSA"),
 86         SHA512withRSA("SHA512withRSA"),
 87         SHA512_224withRSA("SHA512/224withRSA"),
 88         SHA512_256withRSA("SHA512/256withRSA"),
 89         SHA3_224withRSA("SHA3-224withRSA"),
 90         SHA3_256withRSA("SHA3-256withRSA"),
 91         SHA3_384withRSA("SHA3-384withRSA"),
 92         SHA3_512withRSA("SHA3-512withRSA"),
 93 
 94         SHA1withECDSA("SHA1withECDSA"),
 95         SHA224withECDSA("SHA224withECDSA"),
 96         SHA256withECDSA("SHA256withECDSA"),
 97         SHA384withECDSA("SHA384withECDSA"),
 98         SHA512withECDSA("SHA512withECDSA"),
 99         SHA3_224withECDSA("SHA3-224withECDSA"),
100         SHA3_256withECDSA("SHA3-256withECDSA"),
101         SHA3_384withECDSA("SHA3-384withECDSA"),
102         SHA3_512withECDSA("SHA3-512withECDSA"),
103 
104         MD5andSHA1withRSA("MD5andSHA1withRSA"),
105 
106         RSASSA_PSS("RSASSA-PSS");
107 
108         final String name;
109 
110         SigAlg(String name) {
111             this.name = name;
112         }
113     }
114 
115     static class Test {
116         final Provider provider;
117         final KeyAlg keyAlg;
118         final SigAlg sigAlg;
119         final int keySize;
120         final AlgorithmParameterSpec sigParams;
121 
122         Test(SigAlg sigAlg, KeyAlg keyAlg, Provider provider) {
123             this(sigAlg, keyAlg, provider, -1, null);
124         }
125 
126         Test(SigAlg sigAlg, KeyAlg keyAlg, Provider provider, int keySize) {
127             this(sigAlg, keyAlg, provider, keySize, null);
128         }
129 
130         Test(SigAlg sigAlg, KeyAlg keyAlg, Provider provider, int keySize,
131                 AlgorithmParameterSpec sigParams) {
132             this.provider = provider;
133             this.keyAlg = keyAlg;
134             this.sigAlg = sigAlg;
135             this.keySize = keySize;
136             this.sigParams = sigParams;
137         }
138 
139         private static String formatParams(AlgorithmParameterSpec aps) {
140             if (aps == null) return "null";
141             if (aps instanceof PSSParameterSpec) {
142                 PSSParameterSpec p = (PSSParameterSpec) aps;
143                 return String.format("PSSParameterSpec (%s, %s, %s, %s)",
144                     p.getDigestAlgorithm(), formatParams(p.getMGFParameters()),
145                     p.getSaltLength(), p.getTrailerField());
146             } else if (aps instanceof MGF1ParameterSpec) {
147                 return "MGF1" +
148                     ((MGF1ParameterSpec)aps).getDigestAlgorithm();
149             } else {
150                 return aps.toString();
151             }
152         }
153 
154         public String toString() {
155             return String.format("Test: provider = %s, signature alg = %s, "
156                 + " w/ %s, key alg = %s", provider, sigAlg,
157                 formatParams(sigParams), keyAlg);
158         }
159     }
160 
161     private static final Test[] tests = {
162         new Test(SigAlg.SHA1withDSA, KeyAlg.DSA, Provider.Default, 1024),
163         new Test(SigAlg.MD2withRSA, KeyAlg.RSA, Provider.Default),
164         new Test(SigAlg.MD5withRSA, KeyAlg.RSA, Provider.Default),
165         new Test(SigAlg.SHA3_224withRSA, KeyAlg.RSA, Provider.Default),
166         new Test(SigAlg.SHA3_256withRSA, KeyAlg.RSA, Provider.Default),
167         new Test(SigAlg.SHA3_384withRSA, KeyAlg.RSA, Provider.Default),
168         new Test(SigAlg.SHA3_512withRSA, KeyAlg.RSA, Provider.Default),
169         new Test(SigAlg.SHA1withDSA, KeyAlg.DSA, Provider.Sun, 1024),
170         new Test(SigAlg.SHA224withDSA, KeyAlg.DSA, Provider.Sun, 2048),
171         new Test(SigAlg.SHA256withDSA, KeyAlg.DSA, Provider.Sun, 2048),
172     };
173 
174     private static final String str = "to-be-signed";
175     private static final int N = 3;
176 
177     public static void main(String argv[]) {
178         boolean result = Arrays.stream(tests).allMatch((test) -> runTest(test));
179         result &= runTestPSS(2048);
180         if (result) {
181             System.out.println("All tests passed");
182         } else {
183             throw new RuntimeException("Some tests failed");
184         }
185     }
186 
187     private static boolean runTestPSS(int keysize) {
188         boolean result = true;
189         SigAlg pss = SigAlg.RSASSA_PSS;
190         Iterator<String> mdAlgs = SigTestUtil.getDigestAlgorithms
191             (SignatureType.RSASSA_PSS, keysize).iterator();
192         while (mdAlgs.hasNext()) {
193             result &= runTest(new Test(pss, KeyAlg.RSA, Provider.SunRsaSign,
194                 keysize, SigTestUtil.generateDefaultParameter
195                     (SignatureType.RSASSA_PSS, mdAlgs.next())));
196         }
197         return result;
198     }
199 
200     static boolean runTest(Test test) {
201         System.out.println(test);
202         try {
203             // Generate all private/public key pairs
204             PrivateKey[] privKeys = new PrivateKey[N];
205             PublicKey[] pubKeys = new PublicKey[N];
206             PublicKey[] anotherPubKeys = new PublicKey[N];
207             Signature signature;
208             KeyPairGenerator kpg;
209             if (test.provider != Provider.Default) {
210                 signature = Signature.getInstance(test.sigAlg.name,
211                         test.provider.name);
212                 // try using the same provider first, if not, fallback
213                 // to the first available impl
214                 try {
215                     kpg = KeyPairGenerator.getInstance(
216                         test.keyAlg.name, test.provider.name);
217                 } catch (NoSuchAlgorithmException nsae) {
218                     kpg = KeyPairGenerator.getInstance(
219                         test.keyAlg.name);
220                 }
221             } else {
222                 signature = Signature.getInstance(test.sigAlg.name);
223                 kpg = KeyPairGenerator.getInstance(test.keyAlg.name);
224             }
225             if (test.sigParams != null) {
226                 signature.setParameter(test.sigParams);
227             }
228 
229             for (int j=0; j < N; j++) {
230                 if (test.keySize != -1) {
231                     kpg.initialize(test.keySize);
232                 }
233                 KeyPair kp = kpg.genKeyPair();
234                 KeyPair anotherKp = kpg.genKeyPair();
235                 privKeys[j] = kp.getPrivate();
236                 pubKeys[j] = kp.getPublic();
237                 anotherPubKeys[j] = anotherKp.getPublic();
238 
239                 if (Arrays.equals(pubKeys[j].getEncoded(),
240                         anotherPubKeys[j].getEncoded())) {
241                     System.out.println("Failed: it should not get "
242                             + "the same pair of public key");
243                     return false;
244                 }
245             }
246 
247             // Create a chain of signed objects
248             SignedObject[] objects = new SignedObject[N];
249             objects[0] = new SignedObject(str, privKeys[0], signature);
250             for (int j = 1; j < N; j++) {
251                 objects[j] = new SignedObject(objects[j - 1], privKeys[j],
252                         signature);
253             }
254 
255             // Verify the chain
256             int n = objects.length - 1;
257             SignedObject object = objects[n];
258             do {
259                 if (!object.verify(pubKeys[n], signature)) {
260                     System.out.println("Failed: verification failed, n = " + n);
261                     return false;
262                 }
263                 if (object.verify(anotherPubKeys[n], signature)) {
264                     System.out.println("Failed: verification should not "
265                             + "succeed with wrong public key, n = " + n);
266                     return false;
267                 }
268 
269                 object = (SignedObject) object.getObject();
270                 n--;
271             } while (n > 0);
272 
273             System.out.println("signed data: " + object.getObject());
274             if (!str.equals(object.getObject())) {
275                 System.out.println("Failed: signed data is not equal to "
276                         + "original one");
277                 return false;
278             }
279 
280             System.out.println("Test passed");
281             return true;
282         } catch (NoSuchProviderException nspe) {
283             if (test.provider == Provider.SunMSCAPI
284                     && !System.getProperty("os.name").startsWith("Windows")) {
285                 System.out.println("SunMSCAPI is available only on Windows: "
286                         + nspe);
287                 return true;
288             }
289             System.out.println("Unexpected exception: " + nspe);
290             return false;
291         } catch (Exception e) {
292             System.out.println("Unexpected exception: " + e);
293             e.printStackTrace(System.out);
294             return false;
295         }
296     }
297 }
298