1 /* 2 * Copyright (c) 2012, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.ssl; 27 28 import java.math.BigInteger; 29 import java.util.*; 30 import java.util.regex.Pattern; 31 import javax.net.ssl.*; 32 import sun.net.util.IPAddressUtil; 33 import sun.security.action.GetPropertyAction; 34 35 /** 36 * A utility class to share the static methods. 37 */ 38 final class Utilities { 39 static final char[] hexDigits = "0123456789ABCDEF".toCharArray(); 40 private static final String indent = " "; 41 private static final Pattern lineBreakPatern = 42 Pattern.compile("\\r\\n|\\n|\\r"); 43 44 /** 45 * Puts {@code hostname} into the {@code serverNames} list. 46 * <P> 47 * If the {@code serverNames} does not look like a legal FQDN, it will 48 * not be put into the returned list. 49 * <P> 50 * Note that the returned list does not allow duplicated name type. 51 * 52 * @return a list of {@link SNIServerName} 53 */ 54 static List<SNIServerName> addToSNIServerNameList( 55 List<SNIServerName> serverNames, String hostname) { 56 57 SNIHostName sniHostName = rawToSNIHostName(hostname); 58 if (sniHostName == null) { 59 return serverNames; 60 } 61 62 int size = serverNames.size(); 63 List<SNIServerName> sniList = (size != 0) ? 64 new ArrayList<>(serverNames) : 65 new ArrayList<>(1); 66 67 boolean reset = false; 68 for (int i = 0; i < size; i++) { 69 SNIServerName serverName = sniList.get(i); 70 if (serverName.getType() == StandardConstants.SNI_HOST_NAME) { 71 sniList.set(i, sniHostName); 72 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { 73 SSLLogger.fine( 74 "the previous server name in SNI (" + serverName + 75 ") was replaced with (" + sniHostName + ")"); 76 } 77 reset = true; 78 break; 79 } 80 } 81 82 if (!reset) { 83 sniList.add(sniHostName); 84 } 85 86 return Collections.<SNIServerName>unmodifiableList(sniList); 87 } 88 89 /** 90 * Converts string hostname to {@code SNIHostName}. 91 * <P> 92 * Note that to check whether a hostname is a valid domain name, we cannot 93 * use the hostname resolved from name services. For virtual hosting, 94 * multiple hostnames may be bound to the same IP address, so the hostname 95 * resolved from name services is not always reliable. 96 * 97 * @param hostname 98 * the raw hostname 99 * @return an instance of {@link SNIHostName}, or null if the hostname does 100 * not look like a FQDN 101 */ 102 private static SNIHostName rawToSNIHostName(String hostname) { 103 SNIHostName sniHostName = null; 104 if (hostname != null && hostname.indexOf('.') > 0 && 105 !hostname.endsWith(".") && 106 !IPAddressUtil.isIPv4LiteralAddress(hostname) && 107 !IPAddressUtil.isIPv6LiteralAddress(hostname)) { 108 109 try { 110 sniHostName = new SNIHostName(hostname); 111 } catch (IllegalArgumentException iae) { 112 // don't bother to handle illegal host_name 113 if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { 114 SSLLogger.fine(hostname + "\" " + 115 "is not a legal HostName for server name indication"); 116 } 117 } 118 } 119 120 return sniHostName; 121 } 122 123 /** 124 * Return the value of the boolean System property propName. 125 * 126 * Note use of privileged action. Do NOT make accessible to applications. 127 */ 128 static boolean getBooleanProperty(String propName, boolean defaultValue) { 129 // if set, require value of either true or false 130 String b = GetPropertyAction.privilegedGetProperty(propName); 131 if (b == null) { 132 return defaultValue; 133 } else if (b.equalsIgnoreCase("false")) { 134 return false; 135 } else if (b.equalsIgnoreCase("true")) { 136 return true; 137 } else { 138 throw new RuntimeException("Value of " + propName 139 + " must either be 'true' or 'false'"); 140 } 141 } 142 143 static String indent(String source) { 144 return Utilities.indent(source, indent); 145 } 146 147 static String indent(String source, String prefix) { 148 StringBuilder builder = new StringBuilder(); 149 if (source == null) { 150 builder.append("\n").append(prefix).append("<blank message>"); 151 } else { 152 String[] lines = lineBreakPatern.split(source); 153 boolean isFirst = true; 154 for (String line : lines) { 155 if (isFirst) { 156 isFirst = false; 157 } else { 158 builder.append("\n"); 159 } 160 builder.append(prefix).append(line); 161 } 162 } 163 164 return builder.toString(); 165 } 166 167 static String toHexString(byte b) { 168 return String.valueOf(hexDigits[(b >> 4) & 0x0F]) + 169 String.valueOf(hexDigits[b & 0x0F]); 170 } 171 172 static String byte16HexString(int id) { 173 return "0x" + 174 hexDigits[(id >> 12) & 0x0F] + hexDigits[(id >> 8) & 0x0F] + 175 hexDigits[(id >> 4) & 0x0F] + hexDigits[id & 0x0F]; 176 } 177 178 static String toHexString(byte[] bytes) { 179 if (bytes == null || bytes.length == 0) { 180 return ""; 181 } 182 183 StringBuilder builder = new StringBuilder(bytes.length * 3); 184 boolean isFirst = true; 185 for (byte b : bytes) { 186 if (isFirst) { 187 isFirst = false; 188 } else { 189 builder.append(' '); 190 } 191 192 builder.append(hexDigits[(b >> 4) & 0x0F]); 193 builder.append(hexDigits[b & 0x0F]); 194 } 195 return builder.toString(); 196 } 197 198 static String toHexString(long lv) { 199 StringBuilder builder = new StringBuilder(128); 200 201 boolean isFirst = true; 202 do { 203 if (isFirst) { 204 isFirst = false; 205 } else { 206 builder.append(' '); 207 } 208 209 builder.append(hexDigits[(int)(lv & 0x0F)]); 210 lv >>>= 4; 211 builder.append(hexDigits[(int)(lv & 0x0F)]); 212 lv >>>= 4; 213 } while (lv != 0); 214 builder.reverse(); 215 216 return builder.toString(); 217 } 218 219 /** 220 * Utility method to convert a BigInteger to a byte array in unsigned 221 * format as needed in the handshake messages. BigInteger uses 222 * 2's complement format, i.e. it prepends an extra zero if the MSB 223 * is set. We remove that. 224 */ 225 static byte[] toByteArray(BigInteger bi) { 226 byte[] b = bi.toByteArray(); 227 if ((b.length > 1) && (b[0] == 0)) { 228 int n = b.length - 1; 229 byte[] newarray = new byte[n]; 230 System.arraycopy(b, 1, newarray, 0, n); 231 b = newarray; 232 } 233 return b; 234 } 235 236 static void reverseBytes(byte[] arr) { 237 int i = 0; 238 int j = arr.length - 1; 239 240 while (i < j) { 241 swap(arr, i, j); 242 i++; 243 j--; 244 } 245 } 246 247 private static void swap(byte[] arr, int i, int j) { 248 byte tmp = arr[i]; 249 arr[i] = arr[j]; 250 arr[j] = tmp; 251 } 252 }