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