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