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 }