1 /*
   2  * Copyright (c) 2013, 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 jdk.test.lib.process.OutputAnalyzer;
  25 import jdk.test.lib.process.ProcessTools;
  26 
  27 import java.util.ArrayList;
  28 import java.util.Arrays;
  29 import java.util.List;
  30 
  31 /**
  32  * Base class.
  33  */
  34 public abstract class Test {
  35 
  36     static final String TEST_SOURCES = System.getProperty("test.src", ".");
  37     static final String TEST_CLASSES = System.getProperty("test.classes");
  38     static final String FS = System.getProperty("file.separator");
  39     static final String JAVA_HOME = System.getProperty("java.home");
  40     static final String KEYTOOL = JAVA_HOME + FS + "bin" + FS + "keytool";
  41     static final String JARSIGNER = JAVA_HOME + FS + "bin" + FS + "jarsigner";
  42     static final String UNSIGNED_JARFILE = "unsigned.jar";
  43     static final String SIGNED_JARFILE = "signed.jar";
  44     static final String UPDATED_SIGNED_JARFILE = "updated_signed.jar";
  45     static final String FIRST_FILE = "first.txt";
  46     static final String SECOND_FILE = "second.txt";
  47     static final String PASSWORD = "password";
  48     static final String FIRST_KEY_KEYSTORE = "first_key.jks";
  49     static final String KEYSTORE = "keystore.jks";
  50     static final String FIRST_KEY_ALIAS = "first";
  51     static final String SECOND_KEY_ALIAS = "second";
  52     static final String KEY_ALG = "RSA";
  53     static final String KEY_ALIAS = "alias";
  54     static final String CERT_REQUEST_FILENAME = "test.req";
  55     static final String CERT_FILENAME = "test.crt";
  56     static final String CA_KEY_ALIAS = "ca";
  57     static final String CA2_KEY_ALIAS = "ca2";
  58     static final int KEY_SIZE = 2048;
  59     static final int TIMEOUT = 6 * 60 * 1000;   // in millis
  60     static final int VALIDITY = 365;
  61 
  62     static final String WARNING = "Warning:";
  63     static final String WARNING_OR_ERROR = "(Warning|Error):";
  64 
  65     static final String CHAIN_NOT_VALIDATED_VERIFYING_WARNING
  66             = "This jar contains entries "
  67             + "whose certificate chain is invalid.";
  68 
  69     static final String ALIAS_NOT_IN_STORE_VERIFYING_WARNING
  70             = "This jar contains signed entries "
  71             + "that are not signed by alias in this keystore.";
  72 
  73     static final String BAD_EXTENDED_KEY_USAGE_SIGNING_WARNING
  74             = "The signer certificate's ExtendedKeyUsage extension "
  75             + "doesn't allow code signing.";
  76 
  77     static final String BAD_EXTENDED_KEY_USAGE_VERIFYING_WARNING
  78             = "This jar contains entries whose signer certificate's "
  79             + "ExtendedKeyUsage extension doesn't allow code signing.";
  80 
  81     static final String BAD_KEY_USAGE_SIGNING_WARNING
  82             = "The signer certificate's KeyUsage extension "
  83             + "doesn't allow code signing.";
  84 
  85     static final String BAD_KEY_USAGE_VERIFYING_WARNING
  86             = "This jar contains entries whose signer certificate's KeyUsage "
  87             + "extension doesn't allow code signing.";
  88 
  89     static final String BAD_NETSCAPE_CERT_TYPE_SIGNING_WARNING
  90             = "The signer certificate's NetscapeCertType extension "
  91             + "doesn't allow code signing.";
  92 
  93     static final String BAD_NETSCAPE_CERT_TYPE_VERIFYING_WARNING
  94             = "This jar contains entries "
  95             + "whose signer certificate's NetscapeCertType extension "
  96             + "doesn't allow code signing.";
  97 
  98     static final String CHAIN_NOT_VALIDATED_SIGNING_WARNING
  99             = "The signer's certificate chain is invalid.";
 100 
 101     static final String HAS_EXPIRING_CERT_SIGNING_WARNING
 102             = "The signer certificate will expire within six months.";
 103 
 104     static final String HAS_EXPIRING_CERT_VERIFYING_WARNING
 105             = "This jar contains entries "
 106             + "whose signer certificate will expire within six months.";
 107 
 108     static final String HAS_EXPIRED_CERT_SIGNING_WARNING
 109             = "The signer certificate has expired.";
 110 
 111     static final String HAS_EXPIRED_CERT_VERIFYING_WARNING
 112             = "This jar contains entries whose signer certificate has expired.";
 113 
 114     static final String HAS_UNSIGNED_ENTRY_VERIFYING_WARNING
 115             = "This jar contains unsigned entries "
 116             + "which have not been integrity-checked.";
 117 
 118     static final String NOT_SIGNED_BY_ALIAS_VERIFYING_WARNING
 119             = "This jar contains signed entries "
 120             + "which are not signed by the specified alias(es).";
 121 
 122     static final String NO_TIMESTAMP_SIGNING_WARN_TEMPLATE
 123             = "No -tsa or -tsacert is provided "
 124             + "and this jar is not timestamped. "
 125             + "Without a timestamp, users may not be able to validate this jar "
 126             + "after the signer certificate's expiration date "
 127             + "(%1$tY-%1$tm-%1$td).";
 128 
 129     static final String NO_TIMESTAMP_VERIFYING_WARN_TEMPLATE
 130             = "This jar contains signatures that do not include a timestamp. "
 131             + "Without a timestamp, users may not be able to validate this jar "
 132             + "after any of the signer certificates expire "
 133             + "(as early as %1$tY-%1$tm-%1$td).";
 134 
 135     static final String NOT_YET_VALID_CERT_SIGNING_WARNING
 136             = "The signer certificate is not yet valid.";
 137 
 138     static final String NOT_YET_VALID_CERT_VERIFYING_WARNING
 139             = "This jar contains entries "
 140             + "whose signer certificate is not yet valid.";
 141 
 142     static final String JAR_SIGNED = "jar signed.";
 143 
 144     static final String JAR_VERIFIED = "jar verified.";
 145 
 146     static final String JAR_VERIFIED_WITH_SIGNER_ERRORS
 147             = "jar verified, with signer errors.";
 148 
 149     static final int CHAIN_NOT_VALIDATED_EXIT_CODE = 4;
 150     static final int HAS_EXPIRED_CERT_EXIT_CODE = 4;
 151     static final int BAD_KEY_USAGE_EXIT_CODE = 8;
 152     static final int BAD_EXTENDED_KEY_USAGE_EXIT_CODE = 8;
 153     static final int BAD_NETSCAPE_CERT_TYPE_EXIT_CODE = 8;
 154     static final int HAS_UNSIGNED_ENTRY_EXIT_CODE = 16;
 155     static final int ALIAS_NOT_IN_STORE_EXIT_CODE = 32;
 156     static final int NOT_SIGNED_BY_ALIAS_EXIT_CODE = 32;
 157 
 158     protected void createAlias(String alias, String ... options)
 159             throws Throwable {
 160         List<String> cmd = new ArrayList<>();
 161         cmd.addAll(List.of(
 162                 "-genkeypair",
 163                 "-alias", alias,
 164                 "-keyalg", KEY_ALG,
 165                 "-keysize", Integer.toString(KEY_SIZE),
 166                 "-keystore", KEYSTORE,
 167                 "-storepass", PASSWORD,
 168                 "-keypass", PASSWORD,
 169                 "-dname", "CN=" + alias));
 170         cmd.addAll(Arrays.asList(options));
 171 
 172         keytool(cmd.toArray(new String[cmd.size()]))
 173                 .shouldHaveExitValue(0);
 174     }
 175 
 176     protected void issueCert(String alias, String ... options)
 177             throws Throwable {
 178         keytool("-certreq",
 179                 "-alias", alias,
 180                 "-keystore", KEYSTORE,
 181                 "-storepass", PASSWORD,
 182                 "-keypass", PASSWORD,
 183                 "-file", alias + ".req")
 184                     .shouldHaveExitValue(0);
 185 
 186         List<String> cmd = new ArrayList<>();
 187         cmd.addAll(List.of(
 188                 "-gencert",
 189                 "-alias", CA_KEY_ALIAS,
 190                 "-infile", alias + ".req",
 191                 "-outfile", alias + ".cert",
 192                 "-keystore", KEYSTORE,
 193                 "-storepass", PASSWORD,
 194                 "-keypass", PASSWORD,
 195                 "-file", alias + ".req"));
 196         cmd.addAll(Arrays.asList(options));
 197 
 198         keytool(cmd.toArray(new String[cmd.size()]))
 199                 .shouldHaveExitValue(0);
 200 
 201         keytool("-importcert",
 202                 "-alias", alias,
 203                 "-keystore", KEYSTORE,
 204                 "-storepass", PASSWORD,
 205                 "-keypass", PASSWORD,
 206                 "-file", alias + ".cert")
 207                     .shouldHaveExitValue(0);
 208     }
 209 
 210     protected void checkVerifying(OutputAnalyzer analyzer, int expectedExitCode,
 211             String... warnings) {
 212         analyzer.shouldHaveExitValue(expectedExitCode);
 213         int count = 0;
 214         for (String warning : warnings) {
 215             if (warning.startsWith("!")) {
 216                 analyzer.shouldNotContain(warning.substring(1));
 217             } else {
 218                 count++;
 219                 analyzer.shouldContain(warning);
 220             }
 221         }
 222         if (count > 0) {
 223             analyzer.shouldMatch(WARNING_OR_ERROR);
 224         }
 225         if (expectedExitCode == 0) {
 226             analyzer.shouldContain(JAR_VERIFIED);
 227         } else {
 228             analyzer.shouldContain(JAR_VERIFIED_WITH_SIGNER_ERRORS);
 229         }
 230     }
 231 
 232     protected void checkSigning(OutputAnalyzer analyzer, String... warnings) {
 233         analyzer.shouldHaveExitValue(0);
 234         int count = 0;
 235         for (String warning : warnings) {
 236             if (warning.startsWith("!")) {
 237                 analyzer.shouldNotContain(warning.substring(1));
 238             } else {
 239                 count++;
 240                 analyzer.shouldContain(warning);
 241             }
 242         }
 243         if (count > 0) {
 244             analyzer.shouldMatch(WARNING_OR_ERROR);
 245         }
 246         analyzer.shouldContain(JAR_SIGNED);
 247     }
 248 
 249     protected OutputAnalyzer keytool(String... cmd) throws Throwable {
 250         return tool(KEYTOOL, cmd);
 251     }
 252 
 253     protected OutputAnalyzer jarsigner(String... cmd) throws Throwable {
 254         return tool(JARSIGNER, cmd);
 255     }
 256 
 257     private OutputAnalyzer tool(String tool, String... args) throws Throwable {
 258         List<String> cmd = new ArrayList<>();
 259         cmd.add(tool);
 260         cmd.add("-J-Duser.language=en");
 261         cmd.add("-J-Duser.country=US");
 262         cmd.addAll(Arrays.asList(args));
 263         return ProcessTools.executeCommand(cmd.toArray(new String[cmd.size()]));
 264     }
 265 }