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 }