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