1 /*
   2  * Copyright (c) 2015, 2017, 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.util.Arrays;
  32 
  33 /*
  34  * @test
  35  * @bug 8050374
  36  * @key intermittent
  37  * @summary Verify a chain of signed objects
  38  */
  39 public class Chain {
  40 
  41     static enum KeyAlg {
  42         RSA("RSA"),
  43         DSA("DSA"),
  44         EC("EC");
  45 
  46         final String name;
  47 
  48         KeyAlg(String alg) {
  49             this.name = alg;
  50         }
  51     }
  52 
  53     static enum Provider {
  54         Default("default"),
  55         SunRsaSign("SunRsaSign"),
  56         Sun("SUN"),
  57         SunEC("SunEC"),
  58         SunJSSE("SunJSSE"),
  59         SunMSCAPI("SunMSCAPI");
  60 
  61         final String name;
  62 
  63         Provider(String name) {
  64             this.name = name;
  65         }
  66     }
  67 
  68     static enum SigAlg {
  69         MD2withRSA("MD2withRSA"),
  70         MD5withRSA("md5withRSA"),
  71 
  72         SHA1withDSA("SHA1withDSA"),
  73         SHA224withDSA("SHA224withDSA"),
  74         SHA256withDSA("SHA256withDSA"),
  75 
  76         SHA1withRSA("Sha1withrSA"),
  77         SHA224withRSA("SHA224withRSA"),
  78         SHA256withRSA("SHA256withRSA"),
  79         SHA384withRSA("SHA384withRSA"),
  80         SHA512withRSA("SHA512withRSA"),
  81 
  82         SHA1withECDSA("SHA1withECDSA"),
  83         SHA256withECDSA("SHA256withECDSA"),
  84         SHA224withECDSA("SHA224withECDSA"),
  85         SHA384withECDSA("SHA384withECDSA"),
  86         SHA512withECDSA("SHA512withECDSA"),
  87 
  88         MD5andSHA1withRSA("MD5andSHA1withRSA");
  89 
  90         final String name;
  91 
  92         SigAlg(String name) {
  93             this.name = name;
  94         }
  95     }
  96 
  97     static class Test {
  98         final Provider provider;
  99         final KeyAlg keyAlg;
 100         final SigAlg sigAlg;
 101 
 102         Test(SigAlg sigAlg, KeyAlg keyAlg, Provider privider) {
 103             this.provider = privider;
 104             this.keyAlg = keyAlg;
 105             this.sigAlg = sigAlg;
 106         }
 107     }
 108 
 109     private static final Test[] tests = {
 110         new Test(SigAlg.SHA1withDSA, KeyAlg.DSA, Provider.Default),
 111         new Test(SigAlg.MD2withRSA, KeyAlg.RSA, Provider.Default),
 112         new Test(SigAlg.MD5withRSA, KeyAlg.RSA, Provider.Default),
 113         new Test(SigAlg.SHA1withRSA, KeyAlg.RSA, Provider.Default),
 114         new Test(SigAlg.SHA1withDSA, KeyAlg.DSA, Provider.Sun),
 115         new Test(SigAlg.SHA224withDSA, KeyAlg.DSA, Provider.Sun),
 116         new Test(SigAlg.SHA256withDSA, KeyAlg.DSA, Provider.Sun),
 117     };
 118 
 119     private static final String str = "to-be-signed";
 120     private static final int N = 3;
 121 
 122     public static void main(String argv[]) {
 123         boolean result = Arrays.stream(tests).allMatch((test) -> runTest(test));
 124         if(result) {
 125             System.out.println("All tests passed");
 126         } else {
 127             throw new RuntimeException("Some tests failed");
 128         }
 129     }
 130 
 131     static boolean runTest(Test test) {
 132         System.out.format("Test: provider = %s, signature algorithm = %s, "
 133                 + "key algorithm = %s\n",
 134                 test.provider, test.sigAlg, test.keyAlg);
 135         try {
 136             // Generate all private/public key pairs
 137             PrivateKey[] privKeys = new PrivateKey[N];
 138             PublicKey[] pubKeys = new PublicKey[N];
 139             PublicKey[] anotherPubKeys = new PublicKey[N];
 140             Signature signature;
 141             KeyPairGenerator kpg;
 142             if (test.provider != Provider.Default) {
 143                 signature = Signature.getInstance(test.sigAlg.name,
 144                         test.provider.name);
 145                 kpg = KeyPairGenerator.getInstance(
 146                     test.keyAlg.name, test.provider.name);
 147             } else {
 148                 signature = Signature.getInstance(test.sigAlg.name);
 149                 kpg = KeyPairGenerator.getInstance(test.keyAlg.name);
 150             }
 151             for (int j=0; j < N; j++) {
 152                 KeyPair kp = kpg.genKeyPair();
 153                 KeyPair anotherKp = kpg.genKeyPair();
 154                 privKeys[j] = kp.getPrivate();
 155                 pubKeys[j] = kp.getPublic();
 156                 anotherPubKeys[j] = anotherKp.getPublic();
 157 
 158                 if (Arrays.equals(pubKeys[j].getEncoded(),
 159                         anotherPubKeys[j].getEncoded())) {
 160                     System.out.println("Failed: it should not get "
 161                             + "the same pair of public key");
 162                     return false;
 163                 }
 164             }
 165 
 166             // Create a chain of signed objects
 167             SignedObject[] objects = new SignedObject[N];
 168             objects[0] = new SignedObject(str, privKeys[0], signature);
 169             for (int j = 1; j < N; j++) {
 170                 objects[j] = new SignedObject(objects[j - 1], privKeys[j],
 171                         signature);
 172             }
 173 
 174             // Verify the chain
 175             int n = objects.length - 1;
 176             SignedObject object = objects[n];
 177             do {
 178                 if (!object.verify(pubKeys[n], signature)) {
 179                     System.out.println("Failed: verification failed, n = " + n);
 180                     return false;
 181                 }
 182 
 183                 if (object.verify(anotherPubKeys[n], signature)) {
 184                     System.out.println("Failed: verification should not "
 185                             + "succeed with wrong public key, n = " + n);
 186                     return false;
 187                 }
 188 
 189                 object = (SignedObject) object.getObject();
 190                 n--;
 191             } while (n > 0);
 192 
 193             System.out.println("signed data: " + object.getObject());
 194             if (!str.equals(object.getObject())) {
 195                 System.out.println("Failed: signed data is not equal to "
 196                         + "original one");
 197                 return false;
 198             }
 199 
 200             System.out.println("Test passed");
 201             return true;
 202         } catch (NoSuchProviderException nspe) {
 203             if (test.provider == Provider.SunMSCAPI
 204                     && !System.getProperty("os.name").startsWith("Windows")) {
 205                 System.out.println("SunMSCAPI is available only on Windows: "
 206                         + nspe);
 207                 return true;
 208             }
 209             System.out.println("Unexpected exception: " + nspe);
 210             return false;
 211         } catch (Exception e) {
 212             System.out.println("Unexpected exception: " + e);
 213             e.printStackTrace(System.out);
 214             return false;
 215         }
 216     }
 217 }
 218