--- a/src/java.base/share/classes/sun/security/ssl/ProtocolVersion.java Fri May 11 14:55:56 2018 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/ProtocolVersion.java Fri May 11 15:53:12 2018 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,33 +25,41 @@
package sun.security.ssl;
-import java.util.*;
import java.security.CryptoPrimitive;
-import sun.security.ssl.CipherSuite.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
/**
- * Type safe enum for an SSL/TLS protocol version. Instances are obtained
- * using the static factory methods or by referencing the static members
- * in this class. Member variables are final and can be accessed without
- * accessor methods.
- *
- * There is only ever one instance per supported protocol version, this
- * means == can be used for comparision instead of equals() if desired.
- *
- * Checks for a particular version number should generally take this form:
- *
- * <pre>{@code
- * if (protocolVersion.v >= ProtocolVersion.TLS10) {
- * // TLS 1.0 code goes here
- * } else {
- * // SSL 3.0 code here
- * }
- * }</pre>
+ * Enum for an SSL/TLS/DTLS protocol version.
*
* @author Andreas Sterbenz
* @since 1.4.1
*/
-public final class ProtocolVersion implements Comparable<ProtocolVersion> {
+enum ProtocolVersion {
+// TLS13 (0x0304, "TLSv1.3", false),
+ TLS13 (SSLConfiguration.tls13VN, "TLSv1.3", false),
+ TLS12 (0x0303, "TLSv1.2", false),
+ TLS11 (0x0302, "TLSv1.1", false),
+ TLS10 (0x0301, "TLSv1", false),
+ SSL30 (0x0300, "SSLv3", false),
+ SSL20Hello (0x0002, "SSLv2Hello", false),
+
+ DTLS13 (0xFEFC, "DTLSv1.3", true),
+ DTLS12 (0xFEFD, "DTLSv1.2", true),
+ DTLS10 (0xFEFF, "DTLSv1.0", true),
+
+ // Dummy protocol version value for invalid SSLSession
+ NONE (-1, "NONE", false);
+
+
+ final int id;
+ final String name;
+ final boolean isDTLS;
+ final byte major;
+ final byte minor;
+ final boolean isAvailable;
// The limit of maximum protocol version
static final int LIMIT_MAX_VALUE = 0xFFFF;
@@ -59,257 +67,336 @@
// The limit of minimum protocol version
static final int LIMIT_MIN_VALUE = 0x0000;
- // Dummy protocol version value for invalid SSLSession
- static final ProtocolVersion NONE = new ProtocolVersion(-1, "NONE");
+ // (D)TLS ProtocolVersion array for TLS 1.0 and previous versions.
+ static final ProtocolVersion[] PROTOCOLS_TO_10 = new ProtocolVersion[] {
+ TLS10, SSL30
+ };
- // If enabled, send/accept SSLv2 hello messages
- static final ProtocolVersion SSL20Hello =
- new ProtocolVersion(0x0002, "SSLv2Hello");
+ // (D)TLS ProtocolVersion array for TLS 1.1/DTLS 1.0 and previous versions.
+ static final ProtocolVersion[] PROTOCOLS_TO_11 = new ProtocolVersion[] {
+ TLS11, TLS10, SSL30, DTLS10
+ };
- // SSL 3.0
- static final ProtocolVersion SSL30 = new ProtocolVersion(0x0300, "SSLv3");
+ // (D)TLS ProtocolVersion array for (D)TLS 1.2 and previous versions.
+ static final ProtocolVersion[] PROTOCOLS_TO_12 = new ProtocolVersion[] {
+ TLS12, TLS11, TLS10, SSL30, DTLS12, DTLS10
+ };
- // TLS 1.0
- static final ProtocolVersion TLS10 = new ProtocolVersion(0x0301, "TLSv1");
+ // (D)TLS ProtocolVersion array for (D)TLS 1.3 and previous versions.
+ static final ProtocolVersion[] PROTOCOLS_TO_13 = new ProtocolVersion[] {
+ TLS13, TLS12, TLS11, TLS10, SSL30, DTLS13, DTLS12, DTLS10
+ };
- // TLS 1.1
- static final ProtocolVersion TLS11 = new ProtocolVersion(0x0302, "TLSv1.1");
+ // No protocol version specified.
+ static final ProtocolVersion[] PROTOCOLS_OF_NONE = new ProtocolVersion[] {
+ NONE
+ };
- // TLS 1.2
- static final ProtocolVersion TLS12 = new ProtocolVersion(0x0303, "TLSv1.2");
+ // (D)TLS ProtocolVersion array for (D)TLS 1.3.
+ static final ProtocolVersion[] PROTOCOLS_OF_30 = new ProtocolVersion[] {
+ SSL30
+ };
- // DTLS 1.0
- // {254, 255}, the version value of DTLS 1.0.
- static final ProtocolVersion DTLS10 =
- new ProtocolVersion(0xFEFF, "DTLSv1.0");
+ // (D)TLS ProtocolVersion array for TLS 1.1/DTSL 1.0.
+ static final ProtocolVersion[] PROTOCOLS_OF_11 = new ProtocolVersion[] {
+ TLS11, DTLS10
+ };
+
+ // (D)TLS ProtocolVersion array for (D)TLS 1.2.
+ static final ProtocolVersion[] PROTOCOLS_OF_12 = new ProtocolVersion[] {
+ TLS12, DTLS12
+ };
- // No DTLS 1.1, that version number was skipped in order to harmonize
- // version numbers with TLS.
+ // (D)TLS ProtocolVersion array for (D)TLS 1.3.
+ static final ProtocolVersion[] PROTOCOLS_OF_13 = new ProtocolVersion[] {
+ TLS13, DTLS13
+ };
- // DTLS 1.2
- // {254, 253}, the version value of DTLS 1.2.
- static final ProtocolVersion DTLS12 =
- new ProtocolVersion(0xFEFD, "DTLSv1.2");
+ // (D)TLS ProtocolVersion array for TSL 1.0/1.1 and DTLS 1.0.
+ static final ProtocolVersion[] PROTOCOLS_10_11 = new ProtocolVersion[] {
+ TLS11, TLS10, DTLS10
+ };
- private static final boolean FIPS = SunJSSE.isFIPS();
-
- // minimum version we implement (SSL 3.0)
- static final ProtocolVersion MIN = FIPS ? TLS10 : SSL30;
+ // (D)TLS ProtocolVersion array for TSL 1.1/1.2 and DTLS 1.0/1.2.
+ static final ProtocolVersion[] PROTOCOLS_11_12 = new ProtocolVersion[] {
+ TLS12, TLS11, DTLS12, DTLS10
+ };
- // maximum version we implement (TLS 1.2)
- static final ProtocolVersion MAX = TLS12;
+ // (D)TLS ProtocolVersion array for TSL 1.2/1.3 and DTLS 1.2/1.3.
+ static final ProtocolVersion[] PROTOCOLS_12_13 = new ProtocolVersion[] {
+ TLS13, TLS12, DTLS13, DTLS12
+ };
- // SSL/TLS ProtocolVersion to use by default (TLS 1.2)
- static final ProtocolVersion DEFAULT_TLS = TLS12;
+ // (D)TLS ProtocolVersion array for TSL 1.0/1.1/1.2 and DTLS 1.0/1.2.
+ static final ProtocolVersion[] PROTOCOLS_10_12 = new ProtocolVersion[] {
+ TLS12, TLS11, TLS10, DTLS12, DTLS10
+ };
- // DTLS ProtocolVersion to use by default (TLS 1.2)
- static final ProtocolVersion DEFAULT_DTLS = DTLS12;
+ // Empty ProtocolVersion array
+ static final ProtocolVersion[] PROTOCOLS_EMPTY = new ProtocolVersion[0];
- // Default version for hello messages (SSLv2Hello)
- static final ProtocolVersion DEFAULT_HELLO = FIPS ? TLS10 : SSL30;
+ private ProtocolVersion(int id, String name, boolean isDTLS) {
+ this.id = id;
+ this.name = name;
+ this.isDTLS = isDTLS;
+ this.major = (byte)((id >>> 8) & 0xFF);
+ this.minor = (byte)(id & 0xFF);
- // Available protocols
- //
- // Including all supported protocols except the disabled ones.
- static final Set<ProtocolVersion> availableProtocols;
+ this.isAvailable = SSLAlgorithmConstraints.DEFAULT_SSL_ONLY.permits(
+ EnumSet.<CryptoPrimitive>of(CryptoPrimitive.KEY_AGREEMENT),
+ name, null);
+ }
- // version in 16 bit MSB format as it appears in records and
- // messages, i.e. 0x0301 for TLS 1.0
- public final int v;
+ /**
+ * Return a ProtocolVersion with the specified major and minor
+ * version numbers.
+ */
+ static ProtocolVersion valueOf(byte major, byte minor) {
+ for (ProtocolVersion pv : ProtocolVersion.values()) {
+ if ((pv.major == major) && (pv.minor == minor)) {
+ return pv;
+ }
+ }
- // major and minor version
- public final byte major, minor;
-
- // name used in JSSE (e.g. TLSv1 for TLS 1.0)
- final String name;
+ return null;
+ }
- // Initialize the available protocols.
- static {
- Set<ProtocolVersion> protocols = new HashSet<>(7);
+ /**
+ * Return a ProtocolVersion with the specified version number.
+ */
+ static ProtocolVersion valueOf(int id) {
+ for (ProtocolVersion pv : ProtocolVersion.values()) {
+ if (pv.id == id) {
+ return pv;
+ }
+ }
- ProtocolVersion[] pvs = new ProtocolVersion[] {
- SSL20Hello, SSL30, TLS10, TLS11, TLS12, DTLS10, DTLS12};
- EnumSet<CryptoPrimitive> cryptoPrimitives =
- EnumSet.<CryptoPrimitive>of(CryptoPrimitive.KEY_AGREEMENT);
- for (ProtocolVersion p : pvs) {
- if (SSLAlgorithmConstraints.DEFAULT_SSL_ONLY.permits(
- cryptoPrimitives, p.name, null)) {
- protocols.add(p);
+ return null;
+ }
+
+ /**
+ * Return name of a (D)TLS protocol specified by major and
+ * minor version numbers.
+ */
+ static String nameOf(byte major, byte minor) {
+ for (ProtocolVersion pv : ProtocolVersion.values()) {
+ if ((pv.major == major) && (pv.minor == minor)) {
+ return pv.name;
}
}
- availableProtocols =
- Collections.<ProtocolVersion>unmodifiableSet(protocols);
+ return "(D)TLS-" + major + "." + minor;
+ }
+
+ /**
+ * Return name of a (D)TLS protocol specified by a protocol number.
+ */
+ static String nameOf(int id) {
+ return nameOf((byte)((id >>> 8) & 0xFF), (byte)(id & 0xFF));
+ }
+
+ /**
+ * Return a ProtocolVersion for the given (D)TLS protocol name.
+ */
+ static ProtocolVersion nameOf(String name) {
+ for (ProtocolVersion pv : ProtocolVersion.values()) {
+ if (pv.name.equals(name)) {
+ return pv;
+ }
+ }
+
+ return null;
}
- // private
- private ProtocolVersion(int v, String name) {
- this.v = v;
- this.name = name;
- major = (byte)(v >>> 8);
- minor = (byte)(v & 0xFF);
+ /**
+ * Return true if the specific (D)TLS protocol is negotiable.
+ */
+ static boolean isNegotiable(
+ byte major, byte minor, boolean isDTLS, boolean allowSSL20Hello) {
+
+ int v = ((major & 0xFF) << 8) | (minor & 0xFF);
+ if (isDTLS) {
+ return v <= DTLS10.id;
+ } else {
+ if (v < SSL30.id) {
+ if (!allowSSL20Hello || (v != SSL20Hello.id)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Get names of a list of ProtocolVersion objects.
+ */
+ static String[] toStringArray(List<ProtocolVersion> protocolVersions) {
+ if ((protocolVersions != null) && !protocolVersions.isEmpty()) {
+ String[] protocolNames = new String[protocolVersions.size()];
+ int i = 0;
+ for (ProtocolVersion pv : protocolVersions) {
+ protocolNames[i++] = pv.name;
+ }
+
+ return protocolNames;
+ }
+
+ return new String[0];
}
- // private
- private static ProtocolVersion valueOf(int v) {
- if (v == SSL30.v) {
- return SSL30;
- } else if (v == TLS10.v) {
- return TLS10;
- } else if (v == TLS11.v) {
- return TLS11;
- } else if (v == TLS12.v) {
- return TLS12;
- } else if (v == SSL20Hello.v) {
- return SSL20Hello;
- } else if (v == DTLS10.v) {
- return DTLS10;
- } else if (v == DTLS12.v) {
- return DTLS12;
+ /**
+ * Get names of a list of protocol version identifiers.
+ */
+ static String[] toStringArray(int[] protocolVersions) {
+ if ((protocolVersions != null) && protocolVersions.length != 0) {
+ String[] protocolNames = new String[protocolVersions.length];
+ int i = 0;
+ for (int pv : protocolVersions) {
+ protocolNames[i++] = ProtocolVersion.nameOf(pv);
+ }
+
+ return protocolNames;
+ }
+
+ return new String[0];
+ }
+
+ /**
+ * Get a list of ProtocolVersion objects of an array protocol
+ * version names.
+ */
+ static List<ProtocolVersion> namesOf(String[] protocolNames) {
+ if (protocolNames == null || protocolNames.length == 0) {
+ return Collections.emptyList();
+ }
+
+ if ((protocolNames != null) && (protocolNames.length != 0)) {
+ List<ProtocolVersion> pvs = new ArrayList<>(protocolNames.length);
+ for (String pn : protocolNames) {
+ ProtocolVersion pv = ProtocolVersion.nameOf(pn);
+ if (pv == null) {
+ throw new IllegalArgumentException(
+ "Unsupported protocol" + pn);
+ }
+
+ pvs.add(pv);
+ }
+
+ return Collections.unmodifiableList(pvs);
+ }
+
+ return Collections.<ProtocolVersion>emptyList();
+ }
+
+ /**
+ * Return true if the specific protocol version name is
+ * of (D)TLS 1.2 or newer version.
+ */
+ static boolean useTLS12PlusSpec(String name) {
+ ProtocolVersion pv = ProtocolVersion.nameOf(name);
+ if (pv != null && pv != NONE) {
+ return pv.isDTLS ? (pv.id <= DTLS12.id) : (pv.id >= TLS12.id);
+ }
+
+ return false;
+ }
+
+ /**
+ * Compares this object with the specified ProtocolVersion.
+ *
+ * @see java.lang.Comparable
+ */
+ int compare(ProtocolVersion that) {
+ if (this == that) {
+ return 0;
+ }
+
+ if (this == ProtocolVersion.NONE) {
+ return -1;
+ } else if (that == ProtocolVersion.NONE) {
+ return 1;
+ }
+
+ if (isDTLS) {
+ return that.id - this.id;
} else {
- int major = (v >>> 8) & 0xFF;
- int minor = v & 0xFF;
- return new ProtocolVersion(v, "Unknown-" + major + "." + minor);
+ return this.id - that.id;
}
}
/**
- * Return a ProtocolVersion with the specified major and minor version
- * numbers. Never throws exceptions.
+ * Return true if this ProtocolVersion object is of (D)TLS 1.3 or
+ * newer version.
*/
- public static ProtocolVersion valueOf(int major, int minor) {
- return valueOf(((major & 0xFF) << 8) | (minor & 0xFF));
+ boolean useTLS13PlusSpec() {
+ return isDTLS ? (this.id <= DTLS13.id) : (this.id >= TLS13.id);
}
/**
- * Return a ProtocolVersion for the given name.
- *
- * @exception IllegalArgumentException if name is null or does not
- * identify a supported protocol
+ * Return true if this ProtocolVersion object is of (D)TLS 1.2 or
+ * newer version.
*/
- static ProtocolVersion valueOf(String name) {
- if (name == null) {
- throw new IllegalArgumentException("Protocol cannot be null");
- }
-
- if (FIPS && (name.equals(SSL30.name) || name.equals(SSL20Hello.name))) {
- throw new IllegalArgumentException(
- "Only TLS 1.0 or later allowed in FIPS mode");
- }
-
- if (name.equals(SSL30.name)) {
- return SSL30;
- } else if (name.equals(TLS10.name)) {
- return TLS10;
- } else if (name.equals(TLS11.name)) {
- return TLS11;
- } else if (name.equals(TLS12.name)) {
- return TLS12;
- } else if (name.equals(SSL20Hello.name)) {
- return SSL20Hello;
- } else if (name.equals(DTLS10.name)) {
- return DTLS10;
- } else if (name.equals(DTLS12.name)) {
- return DTLS12;
- } else {
- throw new IllegalArgumentException(name);
- }
- }
-
- @Override
- public String toString() {
- return name;
+ boolean useTLS12PlusSpec() {
+ return isDTLS ? (this.id <= DTLS12.id) : (this.id >= TLS12.id);
}
/**
- * Compares this object with the specified object for order.
+ * Return true if this ProtocolVersion object is of
+ * TLS 1.1/DTLS 1.0 or newer version.
*/
- @Override
- public int compareTo(ProtocolVersion protocolVersion) {
- if (maybeDTLSProtocol()) {
- if (!protocolVersion.maybeDTLSProtocol()) {
- throw new IllegalArgumentException("Not DTLS protocol");
- }
+ boolean useTLS11PlusSpec() {
+ return isDTLS ? true : (this.id >= TLS11.id);
+ }
- return protocolVersion.v - this.v;
- } else {
- if (protocolVersion.maybeDTLSProtocol()) {
- throw new IllegalArgumentException("Not TLS protocol");
- }
-
- return this.v - protocolVersion.v;
- }
+ /**
+ * Return true if this ProtocolVersion object is of TLS 1.0 or
+ * newer version.
+ */
+ boolean useTLS10PlusSpec() {
+ return isDTLS ? true : (this.id >= TLS10.id);
}
/**
- * Returns true if a ProtocolVersion represents a DTLS protocol.
+ * Return true if this ProtocolVersion object is of TLS 1.0 or
+ * newer version.
*/
- boolean isDTLSProtocol() {
- return this.v == DTLS12.v || this.v == DTLS10.v;
+ static boolean useTLS10PlusSpec(int id, boolean isDTLS) {
+ return isDTLS ? true : (id >= TLS10.id);
+ }
+
+ /**
+ * Return true if this ProtocolVersion object is of TLS 1.3 or
+ * newer version.
+ */
+ static boolean useTLS13PlusSpec(int id, boolean isDTLS) {
+ return isDTLS ? (id <= DTLS13.id) : (id >= TLS13.id);
}
/**
- * Returns true if a ProtocolVersion may represent a DTLS protocol.
+ * Select the lower of that suggested protocol version and
+ * the highest of the listed protocol versions.
+ *
+ * @param listedVersions the listed protocol version
+ * @param suggestedVersion the suggested protocol version
*/
- boolean maybeDTLSProtocol() {
- return (this.major & 0x80) != 0;
- }
-
- boolean useTLS12PlusSpec() {
- return maybeDTLSProtocol() ? (this.v <= DTLS12.v) : (this.v >= TLS12.v);
- }
-
- boolean useTLS11PlusSpec() {
- return maybeDTLSProtocol() ? true : (this.v >= TLS11.v);
- }
-
- boolean useTLS10PlusSpec() {
- return maybeDTLSProtocol() ? true : (this.v >= TLS10.v);
- }
-
- boolean obsoletes(CipherSuite suite) {
- ProtocolVersion proto = this;
- if (proto.isDTLSProtocol()) {
- // DTLS bans stream ciphers.
- if (suite.cipher.cipherType == CipherType.STREAM_CIPHER) {
- return true;
- }
-
- proto = mapToTLSProtocol(this);
- }
-
- return (proto.v >= suite.obsoleted);
- }
-
- boolean supports(CipherSuite suite) {
- ProtocolVersion proto = this;
- if (proto.isDTLSProtocol()) {
- // DTLS bans stream ciphers.
- if (suite.cipher.cipherType == CipherType.STREAM_CIPHER) {
- return false;
- }
-
- proto = mapToTLSProtocol(this);
- }
-
- return (proto.v >= suite.supported);
- }
-
- // Map a specified protocol to the corresponding TLS version.
- //
- // DTLS 1.2 -> TLS 1.2
- // DTLS 1.0 -> TLS 1.1
- private static ProtocolVersion mapToTLSProtocol(
- ProtocolVersion protocolVersion) {
-
- if (protocolVersion.isDTLSProtocol()) {
- if (protocolVersion.v == DTLS10.v) {
- protocolVersion = TLS11;
- } else { // DTLS12
- protocolVersion = TLS12;
+ static ProtocolVersion selectedFrom(
+ List<ProtocolVersion> listedVersions, int suggestedVersion) {
+ ProtocolVersion selectedVersion = ProtocolVersion.NONE;
+ for (ProtocolVersion pv : listedVersions) {
+ if (pv.id == suggestedVersion) {
+ return pv;
+ } else if (pv.isDTLS) {
+ if (pv.id > suggestedVersion && pv.id < selectedVersion.id) {
+ selectedVersion = pv;
+ }
+ } else {
+ if (pv.id < suggestedVersion && pv.id > selectedVersion.id) {
+ selectedVersion = pv;
+ }
}
}
- return protocolVersion;
+ return selectedVersion;
}
}