1 /* 2 * Copyright (c) 2002, 2015, 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.util.*; 29 import java.security.CryptoPrimitive; 30 import sun.security.ssl.CipherSuite.*; 31 32 /** 33 * Type safe enum for an SSL/TLS protocol version. Instances are obtained 34 * using the static factory methods or by referencing the static members 35 * in this class. Member variables are final and can be accessed without 36 * accessor methods. 37 * 38 * There is only ever one instance per supported protocol version, this 39 * means == can be used for comparision instead of equals() if desired. 40 * 41 * Checks for a particular version number should generally take this form: 42 * 43 * <pre>{@code 44 * if (protocolVersion.v >= ProtocolVersion.TLS10) { 45 * // TLS 1.0 code goes here 46 * } else { 47 * // SSL 3.0 code here 48 * } 49 * }</pre> 50 * 51 * @author Andreas Sterbenz 52 * @since 1.4.1 53 */ 54 public final class ProtocolVersion implements Comparable<ProtocolVersion> { 55 56 // The limit of maximum protocol version 57 static final int LIMIT_MAX_VALUE = 0xFFFF; 58 59 // The limit of minimum protocol version 60 static final int LIMIT_MIN_VALUE = 0x0000; 61 62 // Dummy protocol version value for invalid SSLSession 63 static final ProtocolVersion NONE = new ProtocolVersion(-1, "NONE"); 64 65 // If enabled, send/accept SSLv2 hello messages 66 static final ProtocolVersion SSL20Hello = 67 new ProtocolVersion(0x0002, "SSLv2Hello"); 68 69 // SSL 3.0 70 static final ProtocolVersion SSL30 = new ProtocolVersion(0x0300, "SSLv3"); 71 72 // TLS 1.0 73 static final ProtocolVersion TLS10 = new ProtocolVersion(0x0301, "TLSv1"); 74 75 // TLS 1.1 76 static final ProtocolVersion TLS11 = new ProtocolVersion(0x0302, "TLSv1.1"); 77 78 // TLS 1.2 79 static final ProtocolVersion TLS12 = new ProtocolVersion(0x0303, "TLSv1.2"); 80 81 // DTLS 1.0 82 // {254, 255}, the version value of DTLS 1.0. 83 static final ProtocolVersion DTLS10 = 84 new ProtocolVersion(0xFEFF, "DTLSv1.0"); 85 86 // No DTLS 1.1, that version number was skipped in order to harmonize 87 // version numbers with TLS. 88 89 // DTLS 1.2 90 // {254, 253}, the version value of DTLS 1.2. 91 static final ProtocolVersion DTLS12 = 92 new ProtocolVersion(0xFEFD, "DTLSv1.2"); 93 94 private static final boolean FIPS = SunJSSE.isFIPS(); 95 96 // minimum version we implement (SSL 3.0) 97 static final ProtocolVersion MIN = FIPS ? TLS10 : SSL30; 98 99 // maximum version we implement (TLS 1.2) 100 static final ProtocolVersion MAX = TLS12; 101 102 // SSL/TLS ProtocolVersion to use by default (TLS 1.2) 103 static final ProtocolVersion DEFAULT_TLS = TLS12; 104 105 // DTLS ProtocolVersion to use by default (TLS 1.2) 106 static final ProtocolVersion DEFAULT_DTLS = DTLS12; 107 108 // Default version for hello messages (SSLv2Hello) 109 static final ProtocolVersion DEFAULT_HELLO = FIPS ? TLS10 : SSL30; 110 111 // Available protocols 112 // 113 // Including all supported protocols except the disabled ones. 114 static final Set<ProtocolVersion> availableProtocols; 115 116 // version in 16 bit MSB format as it appears in records and 117 // messages, i.e. 0x0301 for TLS 1.0 118 public final int v; 119 120 // major and minor version 121 public final byte major, minor; 122 123 // name used in JSSE (e.g. TLSv1 for TLS 1.0) 124 final String name; 125 126 // Initialize the available protocols. 127 static { 128 Set<ProtocolVersion> protocols = new HashSet<>(7); 129 130 ProtocolVersion[] pvs = new ProtocolVersion[] { 131 SSL20Hello, SSL30, TLS10, TLS11, TLS12, DTLS10, DTLS12}; 132 EnumSet<CryptoPrimitive> cryptoPrimitives = 133 EnumSet.<CryptoPrimitive>of(CryptoPrimitive.KEY_AGREEMENT); 134 for (ProtocolVersion p : pvs) { 135 if (SSLAlgorithmConstraints.DEFAULT_SSL_ONLY.permits( 136 cryptoPrimitives, p.name, null)) { 137 protocols.add(p); 138 } 139 } 140 141 availableProtocols = 142 Collections.<ProtocolVersion>unmodifiableSet(protocols); 143 } 144 145 // private 146 private ProtocolVersion(int v, String name) { 147 this.v = v; 148 this.name = name; 149 major = (byte)(v >>> 8); 150 minor = (byte)(v & 0xFF); 151 } 152 153 // private 154 private static ProtocolVersion valueOf(int v) { 155 if (v == SSL30.v) { 156 return SSL30; 157 } else if (v == TLS10.v) { 158 return TLS10; 159 } else if (v == TLS11.v) { 160 return TLS11; 161 } else if (v == TLS12.v) { 162 return TLS12; 163 } else if (v == SSL20Hello.v) { 164 return SSL20Hello; 165 } else if (v == DTLS10.v) { 166 return DTLS10; 167 } else if (v == DTLS12.v) { 168 return DTLS12; 169 } else { 170 int major = (v >>> 8) & 0xFF; 171 int minor = v & 0xFF; 172 return new ProtocolVersion(v, "Unknown-" + major + "." + minor); 173 } 174 } 175 176 /** 177 * Return a ProtocolVersion with the specified major and minor version 178 * numbers. Never throws exceptions. 179 */ 180 public static ProtocolVersion valueOf(int major, int minor) { 181 return valueOf(((major & 0xFF) << 8) | (minor & 0xFF)); 182 } 183 184 /** 185 * Return a ProtocolVersion for the given name. 186 * 187 * @exception IllegalArgumentException if name is null or does not 188 * identify a supported protocol 189 */ 190 static ProtocolVersion valueOf(String name) { 191 if (name == null) { 192 throw new IllegalArgumentException("Protocol cannot be null"); 193 } 194 195 if (FIPS && (name.equals(SSL30.name) || name.equals(SSL20Hello.name))) { 196 throw new IllegalArgumentException( 197 "Only TLS 1.0 or later allowed in FIPS mode"); 198 } 199 200 if (name.equals(SSL30.name)) { 201 return SSL30; 202 } else if (name.equals(TLS10.name)) { 203 return TLS10; 204 } else if (name.equals(TLS11.name)) { 205 return TLS11; 206 } else if (name.equals(TLS12.name)) { 207 return TLS12; 208 } else if (name.equals(SSL20Hello.name)) { 209 return SSL20Hello; 210 } else if (name.equals(DTLS10.name)) { 211 return DTLS10; 212 } else if (name.equals(DTLS12.name)) { 213 return DTLS12; 214 } else { 215 throw new IllegalArgumentException(name); 216 } 217 } 218 219 @Override 220 public String toString() { 221 return name; 222 } 223 224 /** 225 * Compares this object with the specified object for order. 226 */ 227 @Override 228 public int compareTo(ProtocolVersion protocolVersion) { 229 if (maybeDTLSProtocol()) { 230 if (!protocolVersion.maybeDTLSProtocol()) { 231 throw new IllegalArgumentException("Not DTLS protocol"); 232 } 233 234 return protocolVersion.v - this.v; 235 } else { 236 if (protocolVersion.maybeDTLSProtocol()) { 237 throw new IllegalArgumentException("Not TLS protocol"); 238 } 239 240 return this.v - protocolVersion.v; 241 } 242 } 243 244 /** 245 * Returns true if a ProtocolVersion represents a DTLS protocol. 246 */ 247 boolean isDTLSProtocol() { 248 return this.v == DTLS12.v || this.v == DTLS10.v; 249 } 250 251 /** 252 * Returns true if a ProtocolVersion may represent a DTLS protocol. 253 */ 254 boolean maybeDTLSProtocol() { 255 return (this.major & 0x80) != 0; 256 } 257 258 boolean useTLS12PlusSpec() { 259 return maybeDTLSProtocol() ? (this.v <= DTLS12.v) : (this.v >= TLS12.v); 260 } 261 262 boolean useTLS11PlusSpec() { 263 return maybeDTLSProtocol() ? true : (this.v >= TLS11.v); 264 } 265 266 boolean useTLS10PlusSpec() { 267 return maybeDTLSProtocol() ? true : (this.v >= TLS10.v); 268 } 269 270 boolean obsoletes(CipherSuite suite) { 271 ProtocolVersion proto = this; 272 if (proto.isDTLSProtocol()) { 273 // DTLS bans stream ciphers. 274 if (suite.cipher.cipherType == CipherType.STREAM_CIPHER) { 275 return true; 276 } 277 278 proto = mapToTLSProtocol(this); 279 } 280 281 return (proto.v >= suite.obsoleted); 282 } 283 284 boolean supports(CipherSuite suite) { 285 ProtocolVersion proto = this; 286 if (proto.isDTLSProtocol()) { 287 // DTLS bans stream ciphers. 288 if (suite.cipher.cipherType == CipherType.STREAM_CIPHER) { 289 return false; 290 } 291 292 proto = mapToTLSProtocol(this); 293 } 294 295 return (proto.v >= suite.supported); 296 } 297 298 // Map a specified protocol to the corresponding TLS version. 299 // 300 // DTLS 1.2 -> TLS 1.2 301 // DTLS 1.0 -> TLS 1.1 302 private static ProtocolVersion mapToTLSProtocol( 303 ProtocolVersion protocolVersion) { 304 305 if (protocolVersion.isDTLSProtocol()) { 306 if (protocolVersion.v == DTLS10.v) { 307 protocolVersion = TLS11; 308 } else { // DTLS12 309 protocolVersion = TLS12; 310 } 311 } 312 313 return protocolVersion; 314 } 315 }