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 }