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 }