1 /* 2 * Copyright (c) 2012, 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 javax.net.ssl; 27 28 import java.util.Arrays; 29 30 /** 31 * Instances of this class represent a server name in a Server Name 32 * Indication (SNI) extension. 33 * <P> 34 * The SNI extension is a feature that extends the SSL/TLS protocols to 35 * indicate what server name the client is attempting to connect to during 36 * handshaking. See section 3, "Server Name Indication", of <A 37 * HREF="http://www.ietf.org/rfc/rfc6066.txt">TLS Extensions (RFC 6066)</A>. 38 * <P> 39 * {@code SNIServerName} objects are immutable. Subclasses should not provide 40 * methods that can change the state of an instance once it has been created. 41 * 42 * @see SSLParameters#getServerNames() 43 * @see SSLParameters#setServerNames(List) 44 * 45 * @since 1.8 46 */ 47 public abstract class SNIServerName { 48 49 // the type of the server name 50 private final int type; 51 52 // the encoded value of the server name 53 private final byte[] encoded; 54 55 // the hex digitals 56 private static final char[] HEXES = "0123456789ABCDEF".toCharArray(); 57 58 /** 59 * Creates an {@code SNIServerName} using the specified name type and 60 * encoded value. 61 * <P> 62 * Note that the {@code encoded} byte array is cloned to protect against 63 * subsequent modification. 64 * 65 * @param type 66 * the type of the server name 67 * @param encoded 68 * the encoded value of the server name 69 * 70 * @throws IllegalArgumentException if {@code type} is not in the range 71 * of 0 to 255, inclusive. 72 * @throws NullPointerException if {@code encoded} is null 73 */ SNIServerName(int type, byte[] encoded)74 protected SNIServerName(int type, byte[] encoded) { 75 if (type < 0) { 76 throw new IllegalArgumentException( 77 "Server name type cannot be less than zero"); 78 } else if (type > 255) { 79 throw new IllegalArgumentException( 80 "Server name type cannot be greater than 255"); 81 } 82 this.type = type; 83 84 if (encoded == null) { 85 throw new NullPointerException( 86 "Server name encoded value cannot be null"); 87 } 88 this.encoded = encoded.clone(); 89 } 90 91 92 /** 93 * Returns the name type of this server name. 94 * 95 * @return the name type of this server name 96 */ getType()97 public final int getType() { 98 return type; 99 } 100 101 /** 102 * Returns a copy of the encoded server name value of this server name. 103 * 104 * @return a copy of the encoded server name value of this server name 105 */ getEncoded()106 public final byte[] getEncoded() { 107 return encoded.clone(); 108 } 109 110 /** 111 * Indicates whether some other object is "equal to" this server name. 112 * 113 * @return true if, and only if, {@code other} is of the same class 114 * of this object, and has the same name type and 115 * encoded value as this server name. 116 */ 117 @Override equals(Object other)118 public boolean equals(Object other) { 119 if (this == other) { 120 return true; 121 } 122 123 if (this.getClass() != other.getClass()) { 124 return false; 125 } 126 127 SNIServerName that = (SNIServerName)other; 128 return (this.type == that.type) && 129 Arrays.equals(this.encoded, that.encoded); 130 } 131 132 /** 133 * Returns a hash code value for this server name. 134 * <P> 135 * The hash code value is generated using the name type and encoded 136 * value of this server name. 137 * 138 * @return a hash code value for this server name. 139 */ 140 @Override hashCode()141 public int hashCode() { 142 int result = 17; // 17/31: prime number to decrease collisions 143 result = 31 * result + type; 144 result = 31 * result + Arrays.hashCode(encoded); 145 146 return result; 147 } 148 149 /** 150 * Returns a string representation of this server name, including the server 151 * name type and the encoded server name value in this 152 * {@code SNIServerName} object. 153 * <P> 154 * The exact details of the representation are unspecified and subject 155 * to change, but the following may be regarded as typical: 156 * <pre> 157 * "type={@literal <name type>}, value={@literal <name value>}" 158 * </pre> 159 * <P> 160 * In this class, the format of "{@literal <name type>}" is 161 * "[LITERAL] (INTEGER)", where the optional "LITERAL" is the literal 162 * name, and INTEGER is the integer value of the name type. The format 163 * of "{@literal <name value>}" is "XX:...:XX", where "XX" is the 164 * hexadecimal digit representation of a byte value. For example, a 165 * returned value of an pseudo server name may look like: 166 * <pre> 167 * "type=(31), value=77:77:77:2E:65:78:61:6D:70:6C:65:2E:63:6E" 168 * </pre> 169 * or 170 * <pre> 171 * "type=host_name (0), value=77:77:77:2E:65:78:61:6D:70:6C:65:2E:63:6E" 172 * </pre> 173 * 174 * <P> 175 * Please NOTE that the exact details of the representation are unspecified 176 * and subject to change, and subclasses may override the method with 177 * their own formats. 178 * 179 * @return a string representation of this server name 180 */ 181 @Override toString()182 public String toString() { 183 if (type == StandardConstants.SNI_HOST_NAME) { 184 return "type=host_name (0), value=" + toHexString(encoded); 185 } else { 186 return "type=(" + type + "), value=" + toHexString(encoded); 187 } 188 } 189 190 // convert byte array to hex string toHexString(byte[] bytes)191 private static String toHexString(byte[] bytes) { 192 if (bytes.length == 0) { 193 return "(empty)"; 194 } 195 196 StringBuilder sb = new StringBuilder(bytes.length * 3 - 1); 197 boolean isInitial = true; 198 for (byte b : bytes) { 199 if (isInitial) { 200 isInitial = false; 201 } else { 202 sb.append(':'); 203 } 204 205 int k = b & 0xFF; 206 sb.append(HEXES[k >>> 4]); 207 sb.append(HEXES[k & 0xF]); 208 } 209 210 return sb.toString(); 211 } 212 } 213 214