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