1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
|
/*
* Hooks for application level policies on TLS connections
* (C) 2004-2006,2013 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#ifndef BOTAN_TLS_POLICY_H__
#define BOTAN_TLS_POLICY_H__
#include <botan/tls_version.h>
#include <botan/tls_ciphersuite.h>
#include <botan/x509cert.h>
#include <botan/dl_group.h>
#include <vector>
#include <sstream>
namespace Botan {
namespace TLS {
/**
* TLS Policy Base Class
* Inherit and overload as desired to suit local policy concerns
*/
class BOTAN_DLL Policy
{
public:
/**
* Returns a list of ciphers we are willing to negotiate, in
* order of preference.
*/
virtual std::vector<std::string> allowed_ciphers() const;
/**
* Returns a list of hash algorithms we are willing to use for
* signatures, in order of preference.
*/
virtual std::vector<std::string> allowed_signature_hashes() const;
/**
* Returns a list of MAC algorithms we are willing to use.
*/
virtual std::vector<std::string> allowed_macs() const;
/**
* Returns a list of key exchange algorithms we are willing to
* use, in order of preference. Allowed values: DH, empty string
* (representing RSA using server certificate key)
*/
virtual std::vector<std::string> allowed_key_exchange_methods() const;
/**
* Returns a list of signature algorithms we are willing to
* use, in order of preference. Allowed values RSA and DSA.
*/
virtual std::vector<std::string> allowed_signature_methods() const;
bool allowed_signature_method(const std::string& sig_method) const;
/**
* Return list of ECC curves we are willing to use in order of preference
*/
virtual std::vector<std::string> allowed_ecc_curves() const;
/**
* Returns a list of compression algorithms we are willing to use,
* in order of preference. Allowed values any value of
* Compression_Method.
*
* @note Compression is not currently supported
*/
virtual std::vector<byte> compression() const;
/**
* Choose an elliptic curve to use
*/
virtual std::string choose_curve(const std::vector<std::string>& curve_names) const;
/**
* Allow renegotiation even if the counterparty doesn't
* support the secure renegotiation extension.
*
* @warning Changing this to true exposes you to injected
* plaintext attacks. Read RFC 5746 for background.
*/
virtual bool allow_insecure_renegotiation() const;
/**
* The protocol dictates that the first 32 bits of the random
* field are the current time in seconds. However this allows
* client fingerprinting attacks. Set to false to disable, in
* which case random bytes will be used instead.
*/
virtual bool include_time_in_hello_random() const;
/**
* Allow servers to initiate a new handshake
*/
virtual bool allow_server_initiated_renegotiation() const;
virtual std::string dh_group() const;
/**
* Return the minimum DH group size we're willing to use
*/
virtual size_t minimum_dh_group_size() const;
/**
* If this function returns false, unknown SRP/PSK identifiers
* will be rejected with an unknown_psk_identifier alert as soon
* as the non-existence is identified. Otherwise, a false
* identifier value will be used and the protocol allowed to
* proceed, causing the handshake to eventually fail without
* revealing that the username does not exist on this system.
*/
virtual bool hide_unknown_users() const;
/**
* Return the allowed lifetime of a session ticket. If 0, session
* tickets do not expire until the session ticket key rolls over.
* Expired session tickets cannot be used to resume a session.
*/
virtual u32bit session_ticket_lifetime() const;
/**
* If this returns a non-empty vector, and DTLS is negotiated,
* then we will also attempt to negotiate the SRTP extension from
* RFC 5764 using the returned values as the profile ids.
*/
virtual std::vector<u16bit> srtp_profiles() const;
/**
* @return true if and only if we are willing to accept this version
* Default accepts TLS v1.0 and later or DTLS v1.2 or later.
*/
virtual bool acceptable_protocol_version(Protocol_Version version) const;
/**
* Returns the more recent protocol version we are willing to
* use, for either TLS or DTLS depending on datagram param.
* Shouldn't ever need to override this unless you want to allow
* a user to disable use of TLS v1.2 (which is *not recommended*)
*/
virtual Protocol_Version latest_supported_version(bool datagram) const;
/**
* When offering this version, should we send a fallback SCSV?
* Default returns true iff version is not the latest version the
* policy allows, exists to allow override in case of interop problems.
*/
virtual bool send_fallback_scsv(Protocol_Version version) const;
/**
* Allows policy to reject any ciphersuites which are undesirable
* for whatever reason without having to reimplement ciphersuite_list
*/
virtual bool acceptable_ciphersuite(const Ciphersuite& suite) const;
/**
* @return true if servers should choose the ciphersuite matching
* their highest preference, rather than the clients.
* Has no effect on client side.
*/
virtual bool server_uses_own_ciphersuite_preferences() const;
/**
* Return allowed ciphersuites, in order of preference
*/
virtual std::vector<u16bit> ciphersuite_list(Protocol_Version version,
bool have_srp) const;
virtual size_t dtls_default_mtu() const;
virtual size_t dtls_initial_timeout() const;
virtual size_t dtls_maximum_timeout() const;
virtual void print(std::ostream& o) const;
virtual ~Policy() {}
};
/**
* NSA Suite B 128-bit security level (see @rfc 6460)
*/
class BOTAN_DLL NSA_Suite_B_128 : public Policy
{
public:
std::vector<std::string> allowed_ciphers() const override
{ return std::vector<std::string>({"AES-128/GCM"}); }
std::vector<std::string> allowed_signature_hashes() const override
{ return std::vector<std::string>({"SHA-256"}); }
std::vector<std::string> allowed_macs() const override
{ return std::vector<std::string>({"AEAD"}); }
std::vector<std::string> allowed_key_exchange_methods() const override
{ return std::vector<std::string>({"ECDH"}); }
std::vector<std::string> allowed_signature_methods() const override
{ return std::vector<std::string>({"ECDSA"}); }
std::vector<std::string> allowed_ecc_curves() const override
{ return std::vector<std::string>({"secp256r1"}); }
bool acceptable_protocol_version(Protocol_Version version) const override
{ return version == Protocol_Version::TLS_V12; }
};
/**
* Policy for DTLS. We require DTLS v1.2 and an AEAD mode
*/
class BOTAN_DLL Datagram_Policy : public Policy
{
public:
std::vector<std::string> allowed_macs() const override
{ return std::vector<std::string>({"AEAD"}); }
bool acceptable_protocol_version(Protocol_Version version) const override
{ return version == Protocol_Version::DTLS_V12; }
};
/*
* This policy requires a secure version of TLS and disables all insecure
* algorithms. It is compatible with other botan TLSes (including those using the
* default policy) and with many other recent implementations. It is a great idea
* to use if you control both sides of the protocol and don't have to worry
* about ancient and/or bizarre TLS implementations.
*/
class BOTAN_DLL Strict_Policy : public Policy
{
public:
std::vector<std::string> allowed_ciphers() const override;
std::vector<std::string> allowed_signature_hashes() const override;
std::vector<std::string> allowed_macs() const override;
std::vector<std::string> allowed_key_exchange_methods() const override;
bool acceptable_protocol_version(Protocol_Version version) const override;
};
class BOTAN_DLL Text_Policy : public Policy
{
public:
std::vector<std::string> allowed_ciphers() const override
{ return get_list("ciphers", Policy::allowed_ciphers()); }
std::vector<std::string> allowed_signature_hashes() const override
{ return get_list("signature_hashes", Policy::allowed_signature_hashes()); }
std::vector<std::string> allowed_macs() const override
{ return get_list("macs", Policy::allowed_macs()); }
std::vector<std::string> allowed_key_exchange_methods() const override
{ return get_list("key_exchange_methods", Policy::allowed_key_exchange_methods()); }
std::vector<std::string> allowed_signature_methods() const override
{ return get_list("signature_methods", Policy::allowed_signature_methods()); }
std::vector<std::string> allowed_ecc_curves() const override
{ return get_list("ecc_curves", Policy::allowed_ecc_curves()); }
bool allow_insecure_renegotiation() const override
{ return get_bool("allow_insecure_renegotiation", Policy::allow_insecure_renegotiation()); }
bool include_time_in_hello_random() const override
{ return get_bool("include_time_in_hello_random", Policy::include_time_in_hello_random()); }
bool allow_server_initiated_renegotiation() const override
{ return get_bool("allow_server_initiated_renegotiation", Policy::allow_server_initiated_renegotiation()); }
bool server_uses_own_ciphersuite_preferences() const override
{ return get_bool("server_uses_own_ciphersuite_preferences", Policy::server_uses_own_ciphersuite_preferences()); }
std::string dh_group() const override
{ return get_str("dh_group", Policy::dh_group()); }
size_t minimum_dh_group_size() const override
{ return get_len("minimum_dh_group_size", Policy::minimum_dh_group_size()); }
bool hide_unknown_users() const override
{ return get_bool("hide_unknown_users", Policy::hide_unknown_users()); }
u32bit session_ticket_lifetime() const override
{ return get_len("session_ticket_lifetime", Policy::session_ticket_lifetime()); }
bool send_fallback_scsv(Protocol_Version version) const override
{ return get_bool("send_fallback_scsv", false) ? Policy::send_fallback_scsv(version) : false; }
std::vector<u16bit> srtp_profiles() const override
{
std::vector<u16bit> r;
for(auto&& p : get_list("srtp_profiles", std::vector<std::string>()))
{
r.push_back(to_u32bit(p));
}
return r;
}
void set(const std::string& k, const std::string& v) { m_kv[k] = v; }
explicit Text_Policy(const std::string& s)
{
std::istringstream iss(s);
m_kv = read_cfg(iss);
}
explicit Text_Policy(std::istream& in) : m_kv(read_cfg(in))
{}
private:
std::vector<std::string> get_list(const std::string& key,
const std::vector<std::string>& def) const
{
const std::string v = get_str(key);
if(v.empty())
return def;
return split_on(v, ' ');
}
size_t get_len(const std::string& key, size_t def) const
{
const std::string v = get_str(key);
if(v.empty())
return def;
return to_u32bit(v);
}
bool get_bool(const std::string& key, bool def) const
{
const std::string v = get_str(key);
if(v.empty())
return def;
if(v == "true" || v == "True")
return true;
else if(v == "false" || v == "False")
return false;
else
throw Exception("Invalid boolean '" + v + "'");
}
std::string get_str(const std::string& key, const std::string& def = "") const
{
auto i = m_kv.find(key);
if(i == m_kv.end())
return def;
return i->second;
}
std::map<std::string, std::string> m_kv;
};
}
}
#endif
|