1 /**
2 * TLS Protocol Version Management
3 * 
4 * Copyright:
5 * (C) 2012 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.tls.version_;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_TLS):
15 
16 import botan.utils.get_byte;
17 import botan.tls.exceptn;
18 import botan.tls.alert;
19 import botan.utils.parsing;
20 import botan.utils.types;
21 import std.conv : to;
22 
23 /**
24 * TLS Protocol Version
25 */
26 struct TLSProtocolVersion
27 {
28 public:
29     alias ushort VersionCode;
30     enum : VersionCode {
31         TLS_V10             = 0x0301,
32         TLS_V11             = 0x0302,
33         TLS_V12             = 0x0303,
34 
35         DTLS_V10            = 0xFEFF,
36         DTLS_V12            = 0xFEFD
37     }
38 
39     static TLSProtocolVersion latestTlsVersion()
40     {
41         return TLSProtocolVersion(TLS_V12);
42     }
43 
44     static TLSProtocolVersion latestDtlsVersion()
45     {
46         return TLSProtocolVersion(DTLS_V12);
47     }
48 
49     /**
50     * Params:
51     *  named_version = a specific named version of the protocol
52     */
53     this(VersionCode named_version)
54     {
55         m_version = cast(ushort) named_version;
56     }
57 
58     /**
59     * Params:
60     *  major = the major version
61     *  minor = the minor version
62     */
63     this(ubyte major, ubyte minor)
64     {
65         m_version = (cast(ushort)(major) << 8) | minor; 
66     }
67 
68     /**
69     * Returns: true if this is a valid protocol version
70     */
71     bool valid() const { return (m_version != 0); }
72 
73     /**
74     * Returns: true if this is a protocol version we know about
75     */
76     bool knownVersion() const
77     {
78         return (m_version == TLSProtocolVersion.TLS_V10 ||
79                 m_version == TLSProtocolVersion.TLS_V11 ||
80                 m_version == TLSProtocolVersion.TLS_V12 ||
81                 m_version == TLSProtocolVersion.DTLS_V10 ||
82                 m_version == TLSProtocolVersion.DTLS_V12);
83     }
84 
85     /**
86     * Returns: major version of the protocol version
87     */
88     ubyte majorVersion() const { return get_byte(0, m_version); }
89 
90     /**
91     * Returns: minor version of the protocol version
92     */
93     ubyte minorVersion() const { return get_byte(1, m_version); }
94 
95     /**
96     * Returns: human-readable description of this version
97     */
98     string toString() const
99     {
100         const ubyte maj = majorVersion();
101         const ubyte min = minorVersion();
102                 
103         if (maj == 3 && min >= 1) // TLS v1.x
104             return "TLS v1." ~ to!string(min-1);
105         
106         if (maj == 254) // DTLS 1.x
107             return "DTLS v1." ~ to!string(255 - min);
108         
109         // Some very new or very old protocol (or bogus data)
110         return "Unknown " ~ to!string(maj) ~ "." ~ to!string(min);
111     }
112 
113     /**
114     * Returns: true iff this is a DTLS version
115     */
116     bool isDatagramProtocol() const
117     {
118         return majorVersion() == 254;
119     }
120 
121     /**
122     * Returns: true if this version supports negotiable signature algorithms
123     */
124     bool supportsNegotiableSignatureAlgorithms() const
125     {
126         return (m_version == TLSProtocolVersion.TLS_V12 ||
127                 m_version == TLSProtocolVersion.DTLS_V12);
128     }
129 
130     /**
131     * Returns: true if this version uses explicit IVs for block ciphers
132     */
133     bool supportsExplicitCbcIvs() const
134     {
135         return (m_version == TLSProtocolVersion.TLS_V11 ||
136                 m_version == TLSProtocolVersion.TLS_V12 ||
137                 m_version == TLSProtocolVersion.DTLS_V10 ||
138                 m_version == TLSProtocolVersion.DTLS_V12);
139     }
140 
141     /**
142     * Returns: true if this version uses a ciphersuite specific PRF
143     */
144     bool supportsCiphersuiteSpecificPrf() const
145     {
146         return (m_version == TLSProtocolVersion.TLS_V12 ||
147                 m_version == TLSProtocolVersion.DTLS_V12);
148     }
149 
150     bool supportsAeadModes() const
151     {
152         return (m_version == TLSProtocolVersion.TLS_V12 ||
153                 m_version == TLSProtocolVersion.DTLS_V12);
154     }
155 
156     /**
157     * Returns: if this version is equal to other
158     */
159     bool opEquals(in TLSProtocolVersion other) const
160     {
161         return (m_version == other.m_version);
162     }
163     
164     /**
165     * Returns: if this version is not equal to other
166     */
167     int opCmp(in TLSProtocolVersion other) const
168     {
169         if (m_version == other.m_version) return 0;
170         else if (isGreaterThan(other)) return 1;
171         else return -1;
172     }
173 
174     /**
175     * Returns: if this version is equal to other
176     */
177     bool opEquals(in ushort other) const
178     {
179         return (m_version == other);
180     }
181     
182     /**
183     * Returns: if this version is not equal to other
184     */
185     int opCmp(in ushort other) const
186     {
187         if (m_version == other) return 0;
188         else if (isGreaterThan(TLSProtocolVersion(other))) return 1;
189         else return -1;
190     }
191 
192     /**
193     * Returns: if this version is later than other
194     */
195     bool isGreaterThan(in TLSProtocolVersion other) const
196     {
197         if (this.isDatagramProtocol() != other.isDatagramProtocol())
198             throw new TLSException(TLSAlert.PROTOCOL_VERSION,
199                                    "Version comparing " ~ toString() ~ " with " ~ other.toString());
200         
201         if (this.isDatagramProtocol())
202             return m_version < other.m_version; // goes backwards
203         
204         return m_version > other.m_version;
205     }
206 private:
207     ushort m_version;
208 }