src/java.base/share/classes/sun/security/ssl/ProtocolVersion.java
changeset 47216 71c04702a3d5
parent 32649 2ee9017c7597
child 50768 68fa3d4026ea
child 56542 56aaa6cb3693
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     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 }