1 /*
   2  * Copyright (c) 2017, 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.io.ByteArrayInputStream;
  25 import java.io.IOException;
  26 import java.net.SocketTimeoutException;
  27 import java.security.KeyFactory;
  28 import java.security.KeyStore;
  29 import java.security.NoSuchAlgorithmException;
  30 import java.security.PrivateKey;
  31 import java.security.cert.Certificate;
  32 import java.security.cert.CertificateFactory;
  33 import java.security.spec.InvalidKeySpecException;
  34 import java.security.spec.PKCS8EncodedKeySpec;
  35 
  36 import javax.net.ssl.KeyManagerFactory;
  37 import javax.net.ssl.SSLContext;
  38 import javax.net.ssl.SSLHandshakeException;
  39 import javax.net.ssl.TrustManagerFactory;
  40 
  41 /*
  42  * Utilities for testing.
  43  */
  44 public class Utils {
  45 
  46     /* ***** Properties ***** */
  47     public static final String PROP_PORT = "test.port";
  48     public static final String PROP_PROTOCOL = "test.protocol";
  49     public static final String PROP_CIPHER_SUITE = "test.cipher.suite";
  50     public static final String PROP_CLIENT_AUTH = "test.client.auth";
  51     public static final String PROP_SERVER_JDK = "test.server.jdk";
  52     public static final String PROP_CLIENT_JDK = "test.client.jdk";
  53     public static final String PROP_SERVER_NAME = "test.server.name";
  54     public static final String PROP_APP_PROTOCOLS
  55             = "test.app.protocols";
  56     public static final String PROP_NEGO_APP_PROTOCOL
  57             = "test.negotiated.app.protocol";
  58     public static final String PROP_SUPPORTS_SNI_ON_SERVER
  59             = "test.supports.sni.on.server";
  60     public static final String PROP_SUPPORTS_SNI_ON_CLIENT
  61             = "test.supports.sni.on.client";
  62     public static final String PROP_SUPPORTS_ALPN_ON_SERVER
  63             = "test.supports.alpn.on.server";
  64     public static final String PROP_SUPPORTS_ALPN_ON_CLIENT
  65             = "test.supports.alpn.on.client";
  66     public static final String PROP_NEGATIVE_CASE_ON_SERVER
  67             = "test.negative.case.on.server";
  68     public static final String PROP_NEGATIVE_CASE_ON_CLIENT
  69             = "test.negative.case.on.client";
  70 
  71     public static final int TIMEOUT = 10000;
  72     public static final char[] PASSWORD = "testpass".toCharArray();
  73 
  74     public static final String TEST_LOG = "test.html";
  75     public static final String PORT_LOG = "port";
  76 
  77     public static final String HTTP_2 = "h2";
  78     public static final String HTTP_1_1 = "http/1.1";
  79 
  80     public static final String PARAM_DELIMITER = ";";
  81     public static final String VALUE_DELIMITER = ",";
  82 
  83     /*
  84      * Creates SSL context with the specified certificate.
  85      */
  86     public static SSLContext createSSLContext(Cert... certs) throws Exception {
  87         KeyStore trustStore = KeyStore.getInstance("JKS");
  88         trustStore.load(null, null);
  89         for (int i = 0; i < certs.length; i++) {
  90             trustStore.setCertificateEntry("trust-" + certs[i].name(),
  91                     createCert(certs[i]));
  92         }
  93         TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
  94         tmf.init(trustStore);
  95 
  96         KeyStore keyStore = KeyStore.getInstance("JKS");
  97         keyStore.load(null, null);
  98         for (int i = 0; i < certs.length; i++) {
  99             PrivateKey privKey = createKey(certs[i]);
 100             keyStore.setKeyEntry("cert-" + certs[i].name(), privKey, PASSWORD,
 101                     new Certificate[] { createCert(certs[i]) });
 102         }
 103         KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
 104         kmf.init(keyStore, PASSWORD);
 105 
 106         SSLContext context = SSLContext.getInstance("TLS");
 107         context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
 108         return context;
 109     }
 110 
 111     private static Certificate createCert(Cert cert) throws IOException {
 112         try {
 113             CertificateFactory certFactory
 114                     = CertificateFactory.getInstance("X.509");
 115             return certFactory.generateCertificate(
 116                     new ByteArrayInputStream(cert.certMaterials.getBytes()));
 117         } catch (Exception e) {
 118             throw new RuntimeException("Create key failed: " + cert, e);
 119         }
 120     }
 121 
 122     private static PrivateKey createKey(Cert cert)
 123             throws NoSuchAlgorithmException, InvalidKeySpecException {
 124         PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(
 125                 hexToBytes(cert.privKeyMaterials));
 126         KeyFactory keyFactory = KeyFactory.getInstance(
 127                 cert.keyAlgorithm.name);
 128         PrivateKey privKey = keyFactory.generatePrivate(privKeySpec);
 129         return privKey;
 130     }
 131 
 132     public static byte[] hexToBytes(String hex) {
 133         if (hex == null) {
 134             return null;
 135         }
 136 
 137         int length = hex.length();
 138         if (length % 2 != 0) {
 139             throw new IllegalArgumentException("Hex format is wrong.");
 140         }
 141 
 142         byte[] bytes = new byte[length / 2];
 143         for (int i = 0; i < length; i += 2) {
 144             bytes[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
 145                     + Character.digit(hex.charAt(i + 1), 16));
 146         }
 147         return bytes;
 148     }
 149 
 150     public static String join(String delimiter, String... values) {
 151         StringBuilder result = new StringBuilder();
 152         if (values != null && values.length > 0) {
 153             for (int i = 0; i < values.length - 1; i++) {
 154                 result.append(values[i]).append(delimiter);
 155             }
 156             result.append(values[values.length - 1]);
 157         }
 158         return result.toString();
 159     }
 160 
 161     public static String[] split(String str, String delimiter) {
 162         return str == null ? new String[0] : str.split(delimiter);
 163     }
 164 
 165     public static String boolToStr(boolean bool) {
 166         return bool ? "Y" : "N";
 167     }
 168 
 169     public static boolean getBoolProperty(String prop) {
 170         return Boolean.valueOf(System.getProperty(prop));
 171     }
 172 
 173     public static Status handleException(Exception exception,
 174             boolean negativeCase) {
 175         Status status;
 176         if ((exception instanceof SSLHandshakeException
 177                 || exception instanceof IllegalArgumentException)
 178                 && negativeCase) {
 179             System.out.println("Expected exception: " + exception);
 180             status = Status.EXPECTED_FAIL;
 181         } else if (exception instanceof SocketTimeoutException) {
 182             status = Status.TIMEOUT;
 183         } else {
 184             exception.printStackTrace(System.out);
 185             status = Status.FAIL;
 186         }
 187         return status;
 188     }
 189 
 190     /* The HTML-related constants and methods. */
 191 
 192     private static final String STYLE
 193             = "style=\"font-family: Courier New; "
 194             + "font-size: 12px; "
 195             + "white-space: pre-wrap\"";
 196 
 197     private static final String TABLE_STYLE
 198             = "#test { font-family: \"Courier New\"; font-size: 12px; border-collapse: collapse; }\n"
 199             + "#test td { border: 1px solid #ddd; padding: 4px; }\n"
 200             + "#test tr:nth-child(odd) { background-color: #f2f2f2; }";
 201 
 202     public static String row(Object... values) {
 203         StringBuilder row = new StringBuilder();
 204         row.append(startTr());
 205         for (Object value : values) {
 206             row.append(startTd());
 207             row.append(value);
 208             row.append(endTd());
 209         }
 210         row.append(endTr());
 211         return row.toString();
 212     }
 213 
 214     public static String startHtml() {
 215         return startTag("html");
 216     }
 217 
 218     public static String endHtml() {
 219         return endTag("html");
 220     }
 221 
 222     public static String startPre() {
 223         return startTag("pre " + STYLE);
 224     }
 225 
 226     public static String endPre() {
 227         return endTag("pre");
 228     }
 229 
 230     public static String anchorName(String name, String text) {
 231         return "<a name=" + name + ">" + text + "</a>";
 232     }
 233 
 234     public static String anchorLink(String file, String anchorName,
 235             String text) {
 236         return "<a href=" + file + "#" + anchorName + ">" + text + "</a>";
 237     }
 238 
 239     public static String tableStyle() {
 240         return startTag("style") + TABLE_STYLE  +endTag("style");
 241     }
 242 
 243     public static String startTable() {
 244         return startTag("table id=\"test\"");
 245     }
 246 
 247     public static String endTable() {
 248         return endTag("table");
 249     }
 250 
 251     private static String startTr() {
 252         return startTag("tr");
 253     }
 254 
 255     private static String endTr() {
 256         return endTag("tr");
 257     }
 258 
 259     private static String startTd() {
 260         return startTag("td");
 261     }
 262 
 263     private static String endTd() {
 264         return endTag("td");
 265     }
 266 
 267     private static String startTag(String tag) {
 268         return "<" + tag + ">";
 269     }
 270 
 271     private static String endTag(String tag) {
 272         return "</" + tag + ">";
 273     }
 274 }