1 package org.bouncycastle.tls; 2 3 import java.util.Vector; 4 5 import org.bouncycastle.util.Strings; 6 7 public final class ProtocolVersion 8 { 9 public static final ProtocolVersion SSLv3 = new ProtocolVersion(0x0300, "SSL 3.0"); 10 public static final ProtocolVersion TLSv10 = new ProtocolVersion(0x0301, "TLS 1.0"); 11 public static final ProtocolVersion TLSv11 = new ProtocolVersion(0x0302, "TLS 1.1"); 12 public static final ProtocolVersion TLSv12 = new ProtocolVersion(0x0303, "TLS 1.2"); 13 public static final ProtocolVersion TLSv13 = new ProtocolVersion(0x0304, "TLS 1.3"); 14 public static final ProtocolVersion DTLSv10 = new ProtocolVersion(0xFEFF, "DTLS 1.0"); 15 public static final ProtocolVersion DTLSv12 = new ProtocolVersion(0xFEFD, "DTLS 1.2"); 16 17 static final ProtocolVersion CLIENT_EARLIEST_SUPPORTED_DTLS = DTLSv10; 18 static final ProtocolVersion CLIENT_EARLIEST_SUPPORTED_TLS = SSLv3; 19 static final ProtocolVersion CLIENT_LATEST_SUPPORTED_DTLS = DTLSv12; 20 static final ProtocolVersion CLIENT_LATEST_SUPPORTED_TLS = TLSv13; 21 22 static final ProtocolVersion SERVER_EARLIEST_SUPPORTED_DTLS = DTLSv10; 23 static final ProtocolVersion SERVER_EARLIEST_SUPPORTED_TLS = SSLv3; 24 static final ProtocolVersion SERVER_LATEST_SUPPORTED_DTLS = DTLSv12; 25 static final ProtocolVersion SERVER_LATEST_SUPPORTED_TLS = TLSv13; 26 contains(ProtocolVersion[] versions, ProtocolVersion version)27 public static boolean contains(ProtocolVersion[] versions, ProtocolVersion version) 28 { 29 if (versions != null && version != null) 30 { 31 for (int i = 0; i < versions.length; ++i) 32 { 33 if (version.equals(versions[i])) 34 { 35 return true; 36 } 37 } 38 } 39 return false; 40 } 41 getEarliestDTLS(ProtocolVersion[] versions)42 public static ProtocolVersion getEarliestDTLS(ProtocolVersion[] versions) 43 { 44 ProtocolVersion earliest = null; 45 if (null != versions) 46 { 47 for (int i = 0; i < versions.length; ++i) 48 { 49 ProtocolVersion next = versions[i]; 50 if (null != next && next.isDTLS()) 51 { 52 if (null == earliest || next.getMinorVersion() > earliest.getMinorVersion()) 53 { 54 earliest = next; 55 } 56 } 57 } 58 } 59 return earliest; 60 } 61 getEarliestTLS(ProtocolVersion[] versions)62 public static ProtocolVersion getEarliestTLS(ProtocolVersion[] versions) 63 { 64 ProtocolVersion earliest = null; 65 if (null != versions) 66 { 67 for (int i = 0; i < versions.length; ++i) 68 { 69 ProtocolVersion next = versions[i]; 70 if (null != next && next.isTLS()) 71 { 72 if (null == earliest || next.getMinorVersion() < earliest.getMinorVersion()) 73 { 74 earliest = next; 75 } 76 } 77 } 78 } 79 return earliest; 80 } 81 getLatestDTLS(ProtocolVersion[] versions)82 public static ProtocolVersion getLatestDTLS(ProtocolVersion[] versions) 83 { 84 ProtocolVersion latest = null; 85 if (null != versions) 86 { 87 for (int i = 0; i < versions.length; ++i) 88 { 89 ProtocolVersion next = versions[i]; 90 if (null != next && next.isDTLS()) 91 { 92 if (null == latest || next.getMinorVersion() < latest.getMinorVersion()) 93 { 94 latest = next; 95 } 96 } 97 } 98 } 99 return latest; 100 } 101 getLatestTLS(ProtocolVersion[] versions)102 public static ProtocolVersion getLatestTLS(ProtocolVersion[] versions) 103 { 104 ProtocolVersion latest = null; 105 if (null != versions) 106 { 107 for (int i = 0; i < versions.length; ++i) 108 { 109 ProtocolVersion next = versions[i]; 110 if (null != next && next.isTLS()) 111 { 112 if (null == latest || next.getMinorVersion() > latest.getMinorVersion()) 113 { 114 latest = next; 115 } 116 } 117 } 118 } 119 return latest; 120 } 121 isSupportedDTLSVersionClient(ProtocolVersion version)122 static boolean isSupportedDTLSVersionClient(ProtocolVersion version) 123 { 124 return null != version 125 && version.isEqualOrLaterVersionOf(CLIENT_EARLIEST_SUPPORTED_DTLS) 126 && version.isEqualOrEarlierVersionOf(CLIENT_LATEST_SUPPORTED_DTLS); 127 } 128 isSupportedDTLSVersionServer(ProtocolVersion version)129 static boolean isSupportedDTLSVersionServer(ProtocolVersion version) 130 { 131 return null != version 132 && version.isEqualOrLaterVersionOf(SERVER_EARLIEST_SUPPORTED_DTLS) 133 && version.isEqualOrEarlierVersionOf(SERVER_LATEST_SUPPORTED_DTLS); 134 } 135 isSupportedTLSVersionClient(ProtocolVersion version)136 static boolean isSupportedTLSVersionClient(ProtocolVersion version) 137 { 138 if (null == version) 139 { 140 return false; 141 } 142 143 int fullVersion = version.getFullVersion(); 144 145 return fullVersion >= CLIENT_EARLIEST_SUPPORTED_TLS.getFullVersion() 146 && fullVersion <= CLIENT_LATEST_SUPPORTED_TLS.getFullVersion(); 147 } 148 isSupportedTLSVersionServer(ProtocolVersion version)149 static boolean isSupportedTLSVersionServer(ProtocolVersion version) 150 { 151 if (null == version) 152 { 153 return false; 154 } 155 156 int fullVersion = version.getFullVersion(); 157 158 return fullVersion >= SERVER_EARLIEST_SUPPORTED_TLS.getFullVersion() 159 && fullVersion <= SERVER_LATEST_SUPPORTED_TLS.getFullVersion(); 160 } 161 162 private int version; 163 private String name; 164 ProtocolVersion(int v, String name)165 private ProtocolVersion(int v, String name) 166 { 167 this.version = v & 0xFFFF; 168 this.name = name; 169 } 170 downTo(ProtocolVersion min)171 public ProtocolVersion[] downTo(ProtocolVersion min) 172 { 173 if (!isEqualOrLaterVersionOf(min)) 174 { 175 throw new IllegalArgumentException("'min' must be an equal or earlier version of this one"); 176 } 177 178 Vector result = new Vector(); 179 result.addElement(this); 180 181 ProtocolVersion current = this; 182 while (!current.equals(min)) 183 { 184 current = current.getPreviousVersion(); 185 result.addElement(current); 186 } 187 188 ProtocolVersion[] versions = new ProtocolVersion[result.size()]; 189 for (int i = 0; i < result.size(); ++i) 190 { 191 versions[i] = (ProtocolVersion)result.elementAt(i); 192 } 193 return versions; 194 } 195 getFullVersion()196 public int getFullVersion() 197 { 198 return version; 199 } 200 getMajorVersion()201 public int getMajorVersion() 202 { 203 return version >> 8; 204 } 205 getMinorVersion()206 public int getMinorVersion() 207 { 208 return version & 0xFF; 209 } 210 getName()211 public String getName() 212 { 213 return name; 214 } 215 isDTLS()216 public boolean isDTLS() 217 { 218 return getMajorVersion() == 0xFE; 219 } 220 isSSL()221 public boolean isSSL() 222 { 223 return this == SSLv3; 224 } 225 isTLS()226 public boolean isTLS() 227 { 228 return getMajorVersion() == 0x03; 229 } 230 getEquivalentTLSVersion()231 public ProtocolVersion getEquivalentTLSVersion() 232 { 233 switch (getMajorVersion()) 234 { 235 case 0x03: return this; 236 case 0xFE: 237 switch(getMinorVersion()) 238 { 239 case 0xFF: return TLSv11; 240 case 0xFD: return TLSv12; 241 default: return null; 242 } 243 default: return null; 244 } 245 } 246 getNextVersion()247 public ProtocolVersion getNextVersion() 248 { 249 int major = getMajorVersion(), minor = getMinorVersion(); 250 switch (major) 251 { 252 case 0x03: 253 switch (minor) 254 { 255 case 0xFF: return null; 256 default : return get(major, minor + 1); 257 } 258 case 0xFE: 259 switch(minor) 260 { 261 case 0x00: return null; 262 case 0xFF: return DTLSv12; 263 default : return get(major, minor - 1); 264 } 265 default: return null; 266 } 267 } 268 getPreviousVersion()269 public ProtocolVersion getPreviousVersion() 270 { 271 int major = getMajorVersion(), minor = getMinorVersion(); 272 switch (major) 273 { 274 case 0x03: 275 switch (minor) 276 { 277 case 0x00: return null; 278 default : return get(major, minor - 1); 279 } 280 case 0xFE: 281 switch(minor) 282 { 283 case 0xFF: return null; 284 case 0xFD: return DTLSv10; 285 default : return get(major, minor + 1); 286 } 287 default: return null; 288 } 289 } 290 isEarlierVersionOf(ProtocolVersion version)291 public boolean isEarlierVersionOf(ProtocolVersion version) 292 { 293 if (null == version || getMajorVersion() != version.getMajorVersion()) 294 { 295 return false; 296 } 297 int diffMinorVersion = getMinorVersion() - version.getMinorVersion(); 298 return isDTLS() ? diffMinorVersion > 0 : diffMinorVersion < 0; 299 } 300 isEqualOrEarlierVersionOf(ProtocolVersion version)301 public boolean isEqualOrEarlierVersionOf(ProtocolVersion version) 302 { 303 if (null == version || getMajorVersion() != version.getMajorVersion()) 304 { 305 return false; 306 } 307 int diffMinorVersion = getMinorVersion() - version.getMinorVersion(); 308 return isDTLS() ? diffMinorVersion >= 0 : diffMinorVersion <= 0; 309 } 310 isEqualOrLaterVersionOf(ProtocolVersion version)311 public boolean isEqualOrLaterVersionOf(ProtocolVersion version) 312 { 313 if (null == version || getMajorVersion() != version.getMajorVersion()) 314 { 315 return false; 316 } 317 int diffMinorVersion = getMinorVersion() - version.getMinorVersion(); 318 return isDTLS() ? diffMinorVersion <= 0 : diffMinorVersion >= 0; 319 } 320 isLaterVersionOf(ProtocolVersion version)321 public boolean isLaterVersionOf(ProtocolVersion version) 322 { 323 if (null == version || getMajorVersion() != version.getMajorVersion()) 324 { 325 return false; 326 } 327 int diffMinorVersion = getMinorVersion() - version.getMinorVersion(); 328 return isDTLS() ? diffMinorVersion < 0 : diffMinorVersion > 0; 329 } 330 equals(Object other)331 public boolean equals(Object other) 332 { 333 return this == other || (other instanceof ProtocolVersion && equals((ProtocolVersion)other)); 334 } 335 equals(ProtocolVersion other)336 public boolean equals(ProtocolVersion other) 337 { 338 return other != null && this.version == other.version; 339 } 340 hashCode()341 public int hashCode() 342 { 343 return version; 344 } 345 get(int major, int minor)346 public static ProtocolVersion get(int major, int minor) 347 { 348 switch (major) 349 { 350 case 0x03: 351 { 352 switch (minor) 353 { 354 case 0x00: 355 return SSLv3; 356 case 0x01: 357 return TLSv10; 358 case 0x02: 359 return TLSv11; 360 case 0x03: 361 return TLSv12; 362 case 0x04: 363 return TLSv13; 364 } 365 return getUnknownVersion(major, minor, "TLS"); 366 } 367 case 0xFE: 368 { 369 switch (minor) 370 { 371 case 0xFF: 372 return DTLSv10; 373 case 0xFE: 374 throw new IllegalArgumentException("{0xFE, 0xFE} is a reserved protocol version"); 375 case 0xFD: 376 return DTLSv12; 377 } 378 return getUnknownVersion(major, minor, "DTLS"); 379 } 380 default: 381 { 382 return getUnknownVersion(major, minor, "UNKNOWN"); 383 } 384 } 385 } 386 only()387 public ProtocolVersion[] only() 388 { 389 return new ProtocolVersion[]{ this }; 390 } 391 toString()392 public String toString() 393 { 394 return name; 395 } 396 checkUint8(int versionOctet)397 private static void checkUint8(int versionOctet) 398 { 399 if (!TlsUtils.isValidUint8(versionOctet)) 400 { 401 throw new IllegalArgumentException("'versionOctet' is not a valid octet"); 402 } 403 } 404 getUnknownVersion(int major, int minor, String prefix)405 private static ProtocolVersion getUnknownVersion(int major, int minor, String prefix) 406 { 407 checkUint8(major); 408 checkUint8(minor); 409 410 int v = (major << 8) | minor; 411 String hex = Strings.toUpperCase(Integer.toHexString(0x10000 | v).substring(1)); 412 return new ProtocolVersion(v, prefix + " 0x" + hex); 413 } 414 } 415