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