1 /** 2 * Hooks for application level policies on TLS connections 3 * 4 * Copyright: 5 * (C) 2004-2006,2013 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.policy; 12 13 import botan.constants; 14 static if (BOTAN_HAS_TLS): 15 16 import botan.tls.version_; 17 import botan.tls.ciphersuite; 18 import botan.cert.x509.x509cert; 19 import botan.pubkey.algo.dl_group; 20 import botan.tls.ciphersuite; 21 import botan.tls.magic; 22 import botan.tls.exceptn; 23 import memutils.dictionarylist; 24 import std.datetime; 25 import std.algorithm : uniq, sort; 26 import std.array : array, Appender; 27 import std.conv : to; 28 import botan.utils.types; 29 30 /** 31 * TLSPolicy Base Class 32 * Inherit and overload as desired to suit local policy concerns 33 */ 34 class TLSPolicy 35 { 36 public: 37 38 /** 39 * Returns a list of ciphers we are willing to negotiate, in 40 * order of preference. 41 */ 42 Vector!string allowedCiphers() const 43 { 44 return Vector!string([ 45 "ChaCha20Poly1305", 46 "AES-256/GCM", 47 "AES-128/GCM", 48 "AES-256/CCM", 49 "AES-128/CCM", 50 "AES-256/CCM-8", 51 "AES-128/CCM-8", 52 "Camellia-256/GCM", 53 "Camellia-128/GCM", 54 "AES-256", 55 "AES-128", 56 "Camellia-256", 57 "Camellia-128", 58 "SEED" 59 "3DES", 60 "RC4", 61 ]); 62 } 63 64 /** 65 * Returns a list of hash algorithms we are willing to use for 66 * signatures, in order of preference. 67 */ 68 Vector!string allowedSignatureHashes() const 69 { 70 return Vector!string([ 71 "SHA-512", 72 "SHA-384", 73 "SHA-256", 74 "SHA-224", 75 "SHA-1", 76 "MD5", 77 ]); 78 } 79 80 81 /** 82 * Returns a list of MAC algorithms we are willing to use. 83 */ 84 Vector!string allowedMacs() const 85 { 86 return Vector!string([ 87 "AEAD", 88 "SHA-384", 89 "SHA-256", 90 "SHA-1", 91 "MD5", 92 ]); 93 } 94 95 /** 96 * Returns a list of key exchange algorithms we are willing to 97 * use, in order of preference. Allowed values: DH, empty string 98 * (representing RSA using server certificate key) 99 */ 100 Vector!string allowedKeyExchangeMethods() const 101 { 102 return Vector!string([ 103 //"SRP_SHA", 104 //"ECDHE_PSK", 105 //"DHE_PSK", 106 //"PSK", 107 "ECDH", 108 "DH", 109 "RSA", 110 ]); 111 } 112 113 /** 114 * Returns a list of signature algorithms we are willing to 115 * use, in order of preference. Allowed values RSA and DSA. 116 */ 117 Vector!string allowedSignatureMethods() const 118 { 119 return Vector!string([ 120 "ECDSA", 121 "RSA", 122 "DSA", 123 //"" 124 ]); 125 } 126 127 /** 128 * Return list of ECC curves we are willing to use in order of preference 129 */ 130 Vector!string allowedEccCurves() const 131 { 132 return Vector!string([ 133 "brainpool512r1", 134 "brainpool384r1", 135 "brainpool256r1", 136 "secp521r1", 137 "secp384r1", 138 "secp256r1", 139 "secp256k1", 140 "secp224r1", 141 "secp224k1", 142 "secp192r1", 143 "secp192k1", 144 "secp160r2", 145 "secp160r1", 146 "secp160k1", 147 ]); 148 } 149 150 /** 151 * Returns a list of compression algorithms we are willing to use, 152 * in order of preference. Allowed values any value of 153 * Compression_Method. 154 * 155 * @note Compression is not currently supported 156 */ 157 Vector!ubyte compression() const 158 { 159 return Vector!ubyte([NO_COMPRESSION]); 160 } 161 162 163 /** 164 * Choose an elliptic curve to use 165 */ 166 string chooseCurve(in Vector!string curve_names) const 167 { 168 const Vector!string our_curves = allowedEccCurves(); 169 for (size_t i = 0; i != our_curves.length; ++i) 170 if (valueExists(curve_names, our_curves[i])) 171 return our_curves[i]; 172 173 return ""; // no shared curve 174 } 175 176 /** 177 * Attempt to negotiate the use of the heartbeat extension 178 */ 179 bool negotiateHeartbeatSupport() const 180 { 181 return false; 182 } 183 184 /** 185 * Allow renegotiation even if the counterparty doesn't 186 * support the secure renegotiation extension. 187 * 188 * Notes: 189 * Changing this to true exposes you to injected plaintext attacks. 190 * Read RFC 5746 for background. 191 */ 192 bool allowInsecureRenegotiation() const { return false; } 193 194 /** 195 * The protocol dictates that the first 32 bits of the random 196 * field are the current time in seconds. However this allows 197 * client fingerprinting attacks. Set to false to disable, in 198 * which case random bytes will be used instead. 199 */ 200 bool includeTimeInHelloRandom() const { return true; } 201 202 /** 203 * Allow servers to initiate a new handshake 204 */ 205 bool allowServerInitiatedRenegotiation() const 206 { 207 return true; 208 } 209 210 /** 211 * Return the group to use for ephemeral Diffie-Hellman key agreement 212 */ 213 DLGroup dhGroup() const 214 { 215 return DLGroup("modp/ietf/2048"); 216 } 217 218 /** 219 * Return the minimum DH group size we're willing to use 220 */ 221 size_t minimumDhGroupSize() const 222 { 223 return 1024; 224 } 225 226 /** 227 * If this function returns false, unknown SRP/PSK identifiers 228 * will be rejected with an unknown_psk_identifier alert as soon 229 * as the non-existence is identified. Otherwise, a false 230 * identifier value will be used and the protocol allowed to 231 * proceed, causing the handshake to eventually fail without 232 * revealing that the username does not exist on this system. 233 */ 234 bool hideUnknownUsers() const { return false; } 235 236 /** 237 * Return the allowed lifetime of a session ticket. If 0, session 238 * tickets do not expire until the session ticket key rolls over. 239 * Expired session tickets cannot be used to resume a session. 240 */ 241 Duration sessionTicketLifetime() const 242 { 243 return 24.hours; // 1 day 244 } 245 246 /** 247 * Returns: true if and only if we are willing to accept this version 248 * Default accepts only TLS, so if you want to enable DTLS override 249 * in your application. 250 */ 251 bool acceptableProtocolVersion(TLSProtocolVersion _version) const 252 { 253 if (_version.isDatagramProtocol()) 254 return (_version >= TLSProtocolVersion.DTLS_V12); 255 256 return (_version >= TLSProtocolVersion.TLS_V10); 257 } 258 /** 259 * Returns the more recent protocol version we are willing to 260 * use, for either TLS or DTLS depending on datagram param. 261 * Shouldn't ever need to override this unless you want to allow 262 * a user to disable use of TLS v1.2 (which is *not recommended*) 263 */ 264 TLSProtocolVersion latestSupportedVersion(bool datagram) const 265 { 266 if (datagram) 267 return TLSProtocolVersion.latestDtlsVersion(); 268 else 269 return TLSProtocolVersion.latestTlsVersion(); 270 } 271 272 /** 273 * When offering this version, should we send a fallback SCSV? 274 * Default returns true iff version is the latest version the 275 * policy allows, exists to allow override in case of interop problems. 276 */ 277 bool sendFallbackSCSV(in TLSProtocolVersion _version) const 278 { 279 return _version == latestSupportedVersion(_version.isDatagramProtocol()); 280 } 281 282 /** 283 * Allows policy to reject any ciphersuites which are undesirable 284 * for whatever reason without having to reimplement ciphersuite_list 285 */ 286 bool acceptableCiphersuite(in TLSCiphersuite) const 287 { 288 return true; 289 } 290 291 /** 292 * Returns: true if servers should choose the ciphersuite matching 293 * their highest preference, rather than the clients. 294 * Has no effect on client side. 295 */ 296 bool serverUsesOwnCiphersuitePreferences() const { return true; } 297 298 /** 299 * Return allowed ciphersuites, in order of preference 300 */ 301 Vector!ushort ciphersuiteList(TLSProtocolVersion _version, bool have_srp) const 302 { 303 Vector!string ciphers = allowedCiphers(); 304 Vector!string macs = allowedMacs(); 305 Vector!string kex = allowedKeyExchangeMethods(); 306 Vector!string sigs = allowedSignatureMethods(); 307 308 CiphersuitePreferenceOrdering order = CiphersuitePreferenceOrdering(ciphers, macs, kex, sigs); 309 310 Vector!(TLSCiphersuite) ciphersuites; 311 ciphersuites.reserve(64); 312 auto cipher_suites = TLSCiphersuite.allKnownCiphersuites(); 313 foreach (const ref TLSCiphersuite suite; cipher_suites) 314 { 315 if (!acceptableCiphersuite(suite)) 316 continue; 317 318 if (!have_srp && suite.kexAlgo() == "SRP_SHA") 319 continue; 320 321 if (_version.isDatagramProtocol() && suite.cipherAlgo() == "RC4") 322 continue; 323 324 if (!_version.supportsAeadModes() && suite.macAlgo() == "AEAD") 325 continue; 326 327 if (!valueExists(kex, suite.kexAlgo())) 328 continue; // unsupported key exchange 329 330 if (!valueExists(ciphers, suite.cipherAlgo())) 331 continue; // unsupported cipher 332 333 if (!valueExists(macs, suite.macAlgo())) 334 continue; // unsupported MAC algo 335 336 if (!valueExists(sigs, suite.sigAlgo())) 337 { 338 // allow if it's an empty sig algo and we want to use PSK 339 if (suite.sigAlgo() != "" || !suite.pskCiphersuite()) 340 continue; 341 } 342 343 // OK, allow it: 344 ciphersuites ~= suite; 345 } 346 347 if (ciphersuites.length == 0) 348 throw new LogicError("TLSPolicy does not allow any available cipher suite"); 349 Vector!ushort ciphersuite_codes; 350 auto ciphersuites_ordered = ciphersuites[].uniq.array.sort!((a,b){ return order.compare(a, b); }).array.to!(TLSCiphersuite[]); 351 foreach (TLSCiphersuite i; ciphersuites_ordered) 352 ciphersuite_codes.pushBack(i.ciphersuiteCode()); 353 return ciphersuite_codes; 354 } 355 356 ~this() {} 357 } 358 359 /** 360 * NSA Suite B 128-bit security level (see @rfc 6460) 361 */ 362 class NSASuiteB128 : TLSPolicy 363 { 364 public: 365 override Vector!string allowedCiphers() const 366 { return Vector!string(["AES-128/GCM"]); } 367 368 override Vector!string allowedSignatureHashes() const 369 { return Vector!string(["SHA-256"]); } 370 371 override Vector!string allowedMacs() const 372 { return Vector!string(["AEAD"]); } 373 374 override Vector!string allowedKeyExchangeMethods() const 375 { return Vector!string(["ECDH"]); } 376 377 override Vector!string allowedSignatureMethods() const 378 { return Vector!string(["ECDSA"]); } 379 380 override Vector!string allowedEccCurves() const 381 { return Vector!string(["secp256r1"]); } 382 383 override bool acceptableProtocolVersion(TLSProtocolVersion _version) const 384 { return _version == TLSProtocolVersion.TLS_V12; } 385 } 386 387 /** 388 * TLSPolicy for DTLS. We require DTLS v1.2 and an AEAD mode 389 */ 390 class DatagramPolicy : TLSPolicy 391 { 392 public: 393 override Vector!string allowedMacs() const 394 { return Vector!string(["AEAD"]); } 395 396 override bool acceptableProtocolVersion(TLSProtocolVersion _version) const 397 { return _version == TLSProtocolVersion.DTLS_V12; } 398 } 399 400 401 private: 402 403 struct CiphersuitePreferenceOrdering 404 { 405 public: 406 this(ref Vector!string ciphers, ref Vector!string macs, ref Vector!string kex, ref Vector!string sigs) 407 { 408 m_ciphers = ciphers.dup(); 409 m_macs = macs.dup(); 410 m_kex = kex.dup(); 411 m_sigs = sigs.dup(); 412 } 413 414 bool compare(U : TLSCiphersuite)(in TLSCiphersuite a, auto ref U b) const 415 { 416 if (a.kexAlgo() != b.kexAlgo()) 417 { 418 for (size_t i = 0; i != m_kex.length; ++i) 419 { 420 if (a.kexAlgo() == m_kex[i]) 421 return true; 422 if (b.kexAlgo() == m_kex[i]) 423 return false; 424 } 425 } 426 427 if (a.cipherAlgo() != b.cipherAlgo()) 428 { 429 for (size_t i = 0; i != m_ciphers.length; ++i) 430 { 431 if (a.cipherAlgo() == m_ciphers[i]) 432 return true; 433 if (b.cipherAlgo() == m_ciphers[i]) 434 return false; 435 } 436 } 437 438 if (a.cipherKeylen() != b.cipherKeylen()) 439 { 440 if (a.cipherKeylen() < b.cipherKeylen()) 441 return false; 442 if (a.cipherKeylen() > b.cipherKeylen()) 443 return true; 444 } 445 446 if (a.sigAlgo() != b.sigAlgo()) 447 { 448 for (size_t i = 0; i != m_sigs.length; ++i) 449 { 450 if (a.sigAlgo() == m_sigs[i]) 451 return true; 452 if (b.sigAlgo() == m_sigs[i]) 453 return false; 454 } 455 } 456 457 if (a.macAlgo() != b.macAlgo()) 458 { 459 for (size_t i = 0; i != m_macs.length; ++i) 460 { 461 if (a.macAlgo() == m_macs[i]) 462 return true; 463 if (b.macAlgo() == m_macs[i]) 464 return false; 465 } 466 } 467 468 return false; // equal (?!?) 469 } 470 private: 471 Vector!string m_ciphers, m_macs, m_kex, m_sigs; 472 }