1 /*
2  * Copyright (c) 2002, 2018, 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.security.CryptoPrimitive;
29 import java.util.ArrayList;
30 import java.util.Collections;
31 import java.util.EnumSet;
32 import java.util.List;
33 
34 /**
35  * Enum for an SSL/TLS/DTLS protocol version.
36  *
37  * @author  Andreas Sterbenz
38  * @since   1.4.1
39  */
40 enum ProtocolVersion {
41     TLS13           (0x0304,    "TLSv1.3",      false),
42     TLS12           (0x0303,    "TLSv1.2",      false),
43     TLS11           (0x0302,    "TLSv1.1",      false),
44     TLS10           (0x0301,    "TLSv1",        false),
45     SSL30           (0x0300,    "SSLv3",        false),
46     SSL20Hello      (0x0002,    "SSLv2Hello",   false),
47 
48     DTLS12          (0xFEFD,    "DTLSv1.2",     true),
49     DTLS10          (0xFEFF,    "DTLSv1.0",     true),
50 
51     // Dummy protocol version value for invalid SSLSession
52     NONE            (-1,        "NONE",         false);
53 
54 
55     final int id;
56     final String name;
57     final boolean isDTLS;
58     final byte major;
59     final byte minor;
60     final boolean isAvailable;
61 
62     // The limit of maximum protocol version
63     static final int LIMIT_MAX_VALUE = 0xFFFF;
64 
65     // The limit of minimum protocol version
66     static final int LIMIT_MIN_VALUE = 0x0000;
67 
68     // (D)TLS ProtocolVersion array for TLS 1.0 and previous versions.
69     static final ProtocolVersion[] PROTOCOLS_TO_10 = new ProtocolVersion[] {
70             TLS10, SSL30
71         };
72 
73     // (D)TLS ProtocolVersion array for TLS 1.1/DTLS 1.0 and previous versions.
74     static final ProtocolVersion[] PROTOCOLS_TO_11 = new ProtocolVersion[] {
75             TLS11, TLS10, SSL30, DTLS10
76         };
77 
78     // (D)TLS ProtocolVersion array for (D)TLS 1.2 and previous versions.
79     static final ProtocolVersion[] PROTOCOLS_TO_12 = new ProtocolVersion[] {
80             TLS12, TLS11, TLS10, SSL30, DTLS12, DTLS10
81     };
82 
83     // (D)TLS ProtocolVersion array for (D)TLS 1.3 and previous versions.
84     static final ProtocolVersion[] PROTOCOLS_TO_13 = new ProtocolVersion[] {
85             TLS13, TLS12, TLS11, TLS10, SSL30, DTLS12, DTLS10
86         };
87 
88     // No protocol version specified.
89     static final ProtocolVersion[] PROTOCOLS_OF_NONE = new ProtocolVersion[] {
90             NONE
91         };
92 
93     // (D)TLS ProtocolVersion array for SSL 3.0.
94     static final ProtocolVersion[] PROTOCOLS_OF_30 = new ProtocolVersion[] {
95             SSL30
96         };
97 
98     // (D)TLS ProtocolVersion array for TLS 1.1/DTSL 1.0.
99     static final ProtocolVersion[] PROTOCOLS_OF_11 = new ProtocolVersion[] {
100             TLS11, DTLS10
101         };
102 
103     // (D)TLS ProtocolVersion array for (D)TLS 1.2.
104     static final ProtocolVersion[] PROTOCOLS_OF_12 = new ProtocolVersion[] {
105             TLS12, DTLS12
106         };
107 
108     // (D)TLS ProtocolVersion array for (D)TLS 1.3.
109     static final ProtocolVersion[] PROTOCOLS_OF_13 = new ProtocolVersion[] {
110             TLS13
111         };
112 
113     // (D)TLS ProtocolVersion array for TSL 1.0/1.1 and DTLS 1.0.
114     static final ProtocolVersion[] PROTOCOLS_10_11 = new ProtocolVersion[] {
115             TLS11, TLS10, DTLS10
116         };
117 
118     // (D)TLS ProtocolVersion array for TSL 1.1/1.2 and DTLS 1.0/1.2.
119     static final ProtocolVersion[] PROTOCOLS_11_12 = new ProtocolVersion[] {
120             TLS12, TLS11, DTLS12, DTLS10
121         };
122 
123     // (D)TLS ProtocolVersion array for TSL 1.2/1.3 and DTLS 1.2/1.3.
124     static final ProtocolVersion[] PROTOCOLS_12_13 = new ProtocolVersion[] {
125             TLS13, TLS12, DTLS12
126         };
127 
128     // (D)TLS ProtocolVersion array for TSL 1.0/1.1/1.2 and DTLS 1.0/1.2.
129     static final ProtocolVersion[] PROTOCOLS_10_12 = new ProtocolVersion[] {
130             TLS12, TLS11, TLS10, DTLS12, DTLS10
131         };
132 
133     // TLS ProtocolVersion array for TLS 1.2 and previous versions.
134     static final ProtocolVersion[] PROTOCOLS_TO_TLS12 = new ProtocolVersion[] {
135             TLS12, TLS11, TLS10, SSL30
136     };
137 
138     // TLS ProtocolVersion array for TLS 1.1 and previous versions.
139     static final ProtocolVersion[] PROTOCOLS_TO_TLS11 = new ProtocolVersion[] {
140             TLS11, TLS10, SSL30
141     };
142 
143     // TLS ProtocolVersion array for TLS 1.0 and previous versions.
144     static final ProtocolVersion[] PROTOCOLS_TO_TLS10 = new ProtocolVersion[] {
145             TLS10, SSL30
146     };
147 
148     // Empty ProtocolVersion array
149     static final ProtocolVersion[] PROTOCOLS_EMPTY = new ProtocolVersion[0];
150 
ProtocolVersion(int id, String name, boolean isDTLS)151     private ProtocolVersion(int id, String name, boolean isDTLS) {
152         this.id = id;
153         this.name = name;
154         this.isDTLS = isDTLS;
155         this.major = (byte)((id >>> 8) & 0xFF);
156         this.minor = (byte)(id & 0xFF);
157 
158         this.isAvailable = SSLAlgorithmConstraints.DEFAULT_SSL_ONLY.permits(
159                 EnumSet.<CryptoPrimitive>of(CryptoPrimitive.KEY_AGREEMENT),
160                 name, null);
161     }
162 
163     /**
164      * Return a ProtocolVersion with the specified major and minor
165      * version numbers.
166      */
valueOf(byte major, byte minor)167     static ProtocolVersion valueOf(byte major, byte minor) {
168         for (ProtocolVersion pv : ProtocolVersion.values()) {
169             if ((pv.major == major) && (pv.minor == minor)) {
170                 return pv;
171             }
172         }
173 
174         return null;
175     }
176 
177     /**
178      * Return a ProtocolVersion with the specified version number.
179      */
valueOf(int id)180     static ProtocolVersion valueOf(int id) {
181         for (ProtocolVersion pv : ProtocolVersion.values()) {
182             if (pv.id == id) {
183                 return pv;
184             }
185         }
186 
187         return null;
188     }
189 
190     /**
191      * Return name of a (D)TLS protocol specified by major and
192      * minor version numbers.
193      */
nameOf(byte major, byte minor)194     static String nameOf(byte major, byte minor) {
195         for (ProtocolVersion pv : ProtocolVersion.values()) {
196             if ((pv.major == major) && (pv.minor == minor)) {
197                 return pv.name;
198             }
199         }
200 
201         return "(D)TLS-" + major + "." + minor;
202     }
203 
204     /**
205      * Return name of a (D)TLS protocol specified by a protocol number.
206      */
nameOf(int id)207     static String nameOf(int id) {
208         return nameOf((byte)((id >>> 8) & 0xFF), (byte)(id & 0xFF));
209     }
210 
211     /**
212      * Return a ProtocolVersion for the given (D)TLS protocol name.
213      */
nameOf(String name)214     static ProtocolVersion nameOf(String name) {
215         for (ProtocolVersion pv : ProtocolVersion.values()) {
216             if (pv.name.equals(name)) {
217                 return pv;
218             }
219         }
220 
221         return null;
222     }
223 
224     /**
225      * Return true if the specific (D)TLS protocol is negotiable.
226      *
227      * Used to filter out SSLv2Hello and protocol numbers less than the
228      * minimal supported protocol versions.
229      */
isNegotiable( byte major, byte minor, boolean isDTLS, boolean allowSSL20Hello)230     static boolean isNegotiable(
231             byte major, byte minor, boolean isDTLS, boolean allowSSL20Hello) {
232         int v = ((major & 0xFF) << 8) | (minor & 0xFF);
233         if (isDTLS) {
234             return v <= DTLS10.id;
235         } else {
236             if (v < SSL30.id) {
237                if (!allowSSL20Hello || (v != SSL20Hello.id)) {
238                    return false;
239                }
240             }
241             return true;
242         }
243     }
244 
245     /**
246      * Get names of a list of ProtocolVersion objects.
247      */
toStringArray(List<ProtocolVersion> protocolVersions)248     static String[] toStringArray(List<ProtocolVersion> protocolVersions) {
249         if ((protocolVersions != null) && !protocolVersions.isEmpty()) {
250             String[] protocolNames = new String[protocolVersions.size()];
251             int i = 0;
252             for (ProtocolVersion pv : protocolVersions) {
253                 protocolNames[i++] = pv.name;
254             }
255 
256             return protocolNames;
257         }
258 
259         return new String[0];
260     }
261 
262     /**
263      * Get names of a list of protocol version identifiers.
264      */
toStringArray(int[] protocolVersions)265     static String[] toStringArray(int[] protocolVersions) {
266         if ((protocolVersions != null) && protocolVersions.length != 0) {
267             String[] protocolNames = new String[protocolVersions.length];
268             int i = 0;
269             for (int pv : protocolVersions) {
270                 protocolNames[i++] = ProtocolVersion.nameOf(pv);
271             }
272 
273             return protocolNames;
274         }
275 
276         return new String[0];
277     }
278 
279     /**
280      * Get a list of ProtocolVersion objects of an array protocol
281      * version names.
282      */
namesOf(String[] protocolNames)283     static List<ProtocolVersion> namesOf(String[] protocolNames) {
284         if (protocolNames == null || protocolNames.length == 0) {
285             return Collections.<ProtocolVersion>emptyList();
286         }
287 
288         List<ProtocolVersion> pvs = new ArrayList<>(protocolNames.length);
289         for (String pn : protocolNames) {
290             ProtocolVersion pv = ProtocolVersion.nameOf(pn);
291             if (pv == null) {
292                 throw new IllegalArgumentException(
293                         "Unsupported protocol" + pn);
294             }
295 
296             pvs.add(pv);
297         }
298 
299         return Collections.unmodifiableList(pvs);
300     }
301 
302     /**
303      * Return true if the specific protocol version name is
304      * of (D)TLS 1.2 or newer version.
305      */
useTLS12PlusSpec(String name)306     static boolean useTLS12PlusSpec(String name) {
307         ProtocolVersion pv = ProtocolVersion.nameOf(name);
308         if (pv != null && pv != NONE) {
309             return pv.isDTLS ? (pv.id <= DTLS12.id) : (pv.id >= TLS12.id);
310         }
311 
312         return false;
313     }
314 
315     /**
316      * Compares this object with the specified ProtocolVersion.
317      *
318      * @see java.lang.Comparable
319      */
compare(ProtocolVersion that)320     int compare(ProtocolVersion that) {
321         if (this == that) {
322             return 0;
323         }
324 
325         if (this == ProtocolVersion.NONE) {
326             return -1;
327         } else if (that == ProtocolVersion.NONE) {
328             return 1;
329         }
330 
331         if (isDTLS) {
332             return that.id - this.id;
333         } else {
334             return this.id - that.id;
335         }
336     }
337 
338     /**
339      * Return true if this ProtocolVersion object is of (D)TLS 1.3 or
340      * newer version.
341      */
useTLS13PlusSpec()342     boolean useTLS13PlusSpec() {
343         return isDTLS ? (this.id < DTLS12.id) : (this.id >= TLS13.id);
344     }
345 
346     /**
347      * Return true if this ProtocolVersion object is of (D)TLS 1.2 or
348      * newer version.
349      */
useTLS12PlusSpec()350     boolean useTLS12PlusSpec() {
351         return isDTLS ? (this.id <= DTLS12.id) : (this.id >= TLS12.id);
352     }
353 
354     /**
355      * Return true if this ProtocolVersion object is of
356      * TLS 1.1/DTLS 1.0 or newer version.
357      */
useTLS11PlusSpec()358     boolean useTLS11PlusSpec() {
359         return isDTLS ? true : (this.id >= TLS11.id);
360     }
361 
362     /**
363      * Return true if this ProtocolVersion object is of TLS 1.0 or
364      * newer version.
365      */
useTLS10PlusSpec()366     boolean useTLS10PlusSpec() {
367         return isDTLS ? true : (this.id >= TLS10.id);
368     }
369 
370     /**
371      * Return true if this ProtocolVersion object is of TLS 1.0 or
372      * newer version.
373      */
useTLS10PlusSpec(int id, boolean isDTLS)374     static boolean useTLS10PlusSpec(int id, boolean isDTLS) {
375         return isDTLS ? true : (id >= TLS10.id);
376     }
377 
378     /**
379      * Return true if this ProtocolVersion object is of (D)TLS 1.3 or
380      * newer version.
381      */
useTLS13PlusSpec(int id, boolean isDTLS)382     static boolean useTLS13PlusSpec(int id, boolean isDTLS) {
383         return isDTLS ? (id < DTLS12.id) : (id >= TLS13.id);
384     }
385 
386     /**
387      * Select the lower of that suggested protocol version and
388      * the highest of the listed protocol versions.
389      *
390      * @param listedVersions    the listed protocol version
391      * @param suggestedVersion  the suggested protocol version
392      */
selectedFrom( List<ProtocolVersion> listedVersions, int suggestedVersion)393     static ProtocolVersion selectedFrom(
394             List<ProtocolVersion> listedVersions, int suggestedVersion) {
395         ProtocolVersion selectedVersion = ProtocolVersion.NONE;
396         for (ProtocolVersion pv : listedVersions) {
397             if (pv.id == suggestedVersion) {
398                 return pv;
399             } else if (pv.isDTLS) {
400                 if (pv.id > suggestedVersion && pv.id < selectedVersion.id) {
401                     selectedVersion = pv;
402                 }
403             } else {
404                 if (pv.id < suggestedVersion && pv.id > selectedVersion.id) {
405                     selectedVersion = pv;
406                 }
407             }
408         }
409 
410         return selectedVersion;
411     }
412 }
413