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