Botan 3.13.0
Crypto and TLS for C&
tls_text_policy.cpp
Go to the documentation of this file.
1/*
2* Text-Based TLS Policy
3* (C) 2016,2017 Jack Lloyd
4* 2017 Harry Reimann, Rohde & Schwarz Cybersecurity
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/tls_policy.h>
10
11#include <botan/assert.h>
12#include <botan/exceptn.h>
13#include <botan/tls_signature_scheme.h>
14#include <botan/internal/fmt.h>
15#include <botan/internal/parsing.h>
16#include <optional>
17#include <sstream>
18
19namespace Botan::TLS {
20
22 return get_bool("allow_ssl_key_log_file", Policy::allow_ssl_key_log_file());
23}
24
25std::vector<std::string> Text_Policy::allowed_ciphers() const {
26 return get_list("ciphers", Policy::allowed_ciphers());
27}
28
29std::vector<std::string> Text_Policy::allowed_signature_hashes() const {
30 return get_list("signature_hashes", Policy::allowed_signature_hashes());
31}
32
33std::vector<std::string> Text_Policy::allowed_macs() const {
34 return get_list("macs", Policy::allowed_macs());
35}
36
37std::vector<std::string> Text_Policy::allowed_key_exchange_methods() const {
38 return get_list("key_exchange_methods", Policy::allowed_key_exchange_methods());
39}
40
41std::vector<std::string> Text_Policy::allowed_signature_methods() const {
42 return get_list("signature_methods", Policy::allowed_signature_methods());
43}
44
45std::vector<Signature_Scheme> Text_Policy::allowed_signature_schemes() const {
46 const auto sig_schemes_str = get_str("signature_schemes", "");
47 return (sig_schemes_str.empty()) ? Policy::allowed_signature_schemes() : read_sig_scheme_list(sig_schemes_str);
48}
49
50std::vector<Signature_Scheme> Text_Policy::acceptable_signature_schemes() const {
51 const auto sig_schemes_str = get_str("acceptable_signature_schemes", "");
52 return (sig_schemes_str.empty()) ? Policy::acceptable_signature_schemes() : read_sig_scheme_list(sig_schemes_str);
53}
54
56 return get_bool("use_ecc_point_compression", Policy::use_ecc_point_compression());
57}
58
60 return get_bool("allow_tls12", Policy::allow_tls12());
61}
62
64 return get_bool("allow_tls13", Policy::allow_tls13());
65}
66
68 return get_bool("allow_dtls12", Policy::allow_dtls12());
69}
70
72 return get_bool("allow_insecure_renegotiation", Policy::allow_insecure_renegotiation());
73}
74
76 return get_bool("include_time_in_hello_random", Policy::include_time_in_hello_random());
77}
78
80 return get_bool("require_client_certificate_authentication", Policy::require_client_certificate_authentication());
81}
82
84 return get_bool("allow_client_initiated_renegotiation", Policy::allow_client_initiated_renegotiation());
85}
86
87std::vector<Certificate_Type> Text_Policy::accepted_client_certificate_types() const {
88 const auto cert_types = get_str("accepted_client_certificate_types");
89 return (cert_types.empty()) ? Policy::accepted_client_certificate_types() : read_cert_type_list(cert_types);
90}
91
92std::vector<Certificate_Type> Text_Policy::accepted_server_certificate_types() const {
93 const auto cert_types = get_str("accepted_server_certificate_types");
94 return (cert_types.empty()) ? Policy::accepted_server_certificate_types() : read_cert_type_list(cert_types);
95}
96
98 return get_bool("allow_server_initiated_renegotiation", Policy::allow_server_initiated_renegotiation());
99}
100
102 return get_bool("server_uses_own_ciphersuite_preferences", Policy::server_uses_own_ciphersuite_preferences());
103}
104
106 return get_bool("negotiate_encrypt_then_mac", Policy::negotiate_encrypt_then_mac());
107}
108
110 return get_bool("require_extended_master_secret", Policy::require_extended_master_secret());
111}
112
113std::optional<uint16_t> Text_Policy::record_size_limit() const {
114 const auto limit = get_len("record_size_limit", 0);
115 // RFC 8449 4.
116 // TLS 1.3 uses a limit of 2^14+1 octets.
117 BOTAN_ARG_CHECK(limit <= 16385, "record size limit too large");
118 return (limit > 0) ? std::make_optional(static_cast<uint16_t>(limit)) : std::nullopt;
119}
120
121size_t Text_Policy::record_padding_bytes(size_t plaintext_bytes) const {
122 // Text policies can express the simplest padding scheme only: pad
123 // records to a fixed minimum size.
124 const auto minimum_record_size = get_len("minimum_record_size", 0);
125 return (plaintext_bytes < minimum_record_size) ? minimum_record_size - plaintext_bytes : 0;
126}
127
129 return get_bool("support_cert_status_message", Policy::support_cert_status_message());
130}
131
132std::vector<Group_Params> Text_Policy::key_exchange_groups() const {
133 std::string group_str = get_str("key_exchange_groups");
134
135 if(group_str.empty()) {
136 // fall back to previously used name
137 group_str = get_str("groups");
138 }
139
140 if(group_str.empty()) {
142 }
143
144 return read_group_list(group_str);
145}
146
147std::vector<Group_Params> Text_Policy::key_exchange_groups_to_offer() const {
148 const std::string group_str = get_str("key_exchange_groups_to_offer", "notset");
149
150 if(group_str.empty() || group_str == "notset") {
151 // policy was not set, fall back to default behaviour
153 }
154
155 if(group_str == "none") {
156 return {};
157 }
158
159 return read_group_list(group_str);
160}
161
163 return get_len("minimum_ecdh_group_size", Policy::minimum_ecdh_group_size());
164}
165
167 return get_len("minimum_ecdsa_group_size", Policy::minimum_ecdsa_group_size());
168}
169
171 return get_len("minimum_dh_group_size", Policy::minimum_dh_group_size());
172}
173
175 return get_len("minimum_rsa_bits", Policy::minimum_rsa_bits());
176}
177
179 return get_len("minimum_signature_strength", Policy::minimum_signature_strength());
180}
181
183 return get_len("dtls_default_mtu", Policy::dtls_default_mtu());
184}
185
187 return get_len("dtls_initial_timeout", Policy::dtls_initial_timeout());
188}
189
191 return get_len("dtls_maximum_timeout", Policy::dtls_maximum_timeout());
192}
193
195 const std::string v = get_str("dtls_maximum_hello_verify_requests");
196
197 if(v.empty()) {
199 }
200
201 if(v == "none") {
202 return std::nullopt;
203 }
204
205 return to_u32bit(v);
206}
207
209 return get_bool("require_cert_revocation_info", Policy::require_cert_revocation_info());
210}
211
213 return get_bool("hide_unknown_users", Policy::hide_unknown_users());
214}
215
217 return get_len("maximum_session_tickets_per_client_hello", Policy::maximum_session_tickets_per_client_hello());
218}
219
220std::chrono::seconds Text_Policy::session_ticket_lifetime() const {
221 return get_duration("session_ticket_lifetime", Policy::session_ticket_lifetime());
222}
223
225 return get_bool("reuse_session_tickets", Policy::reuse_session_tickets());
226}
227
229 return get_len("new_session_tickets_upon_handshake_success", Policy::new_session_tickets_upon_handshake_success());
230}
231
232std::vector<uint16_t> Text_Policy::srtp_profiles() const {
233 std::vector<uint16_t> r;
234 for(const auto& p : get_list("srtp_profiles", std::vector<std::string>())) {
235 if(const auto srtp = parse_u16(p)) {
236 r.push_back(srtp.value());
237 } else {
238 throw Invalid_Argument(fmt("Failed to parse input '{}' as a SRTP profile id", p));
239 }
240 }
241 return r;
242}
243
245 return get_bool("tls_13_middlebox_compatibility_mode", Policy::tls_13_middlebox_compatibility_mode());
246}
247
249 return get_bool("hash_hello_random", Policy::hash_hello_random());
250}
251
252void Text_Policy::set(const std::string& key, const std::string& value) {
253 m_kv[key] = value;
254}
255
256Text_Policy::Text_Policy(std::string_view s) {
257 std::istringstream iss{std::string(s)}; // FIXME C++23 avoid copy
258 m_kv = read_cfg(iss);
259}
260
261Text_Policy::Text_Policy(std::istream& in) : m_kv(read_cfg(in)) {}
262
263std::vector<std::string> Text_Policy::get_list(const std::string& key, const std::vector<std::string>& def) const {
264 const std::string v = get_str(key);
265
266 if(v.empty()) {
267 return def;
268 }
269
270 return split_on(v, ' ');
271}
272
273std::vector<Group_Params> Text_Policy::read_group_list(std::string_view group_str) const {
274 std::vector<Group_Params> groups;
275 for(const auto& group_name : split_on(group_str, ' ')) {
276 Group_Params group_id = Group_Params::from_string(group_name).value_or(Group_Params::NONE);
277
278 if(!group_id.is_available()) {
279 continue;
280 }
281
282 if(group_id == Group_Params::NONE) {
283 try {
284 size_t consumed = 0;
285 const unsigned long ll_id = std::stoul(group_name, &consumed, 0);
286 if(consumed != group_name.size()) {
287 continue; // some other cruft
288 }
289
290 const uint16_t id = static_cast<uint16_t>(ll_id);
291
292 if(id != ll_id) {
293 continue; // integer too large
294 }
295
296 group_id = static_cast<Group_Params>(id);
297 } catch(...) {
298 continue;
299 }
300 }
301
302 if(group_id != Group_Params::NONE) {
303 groups.push_back(group_id);
304 }
305 }
306
307 return groups;
308}
309
310std::vector<Certificate_Type> Text_Policy::read_cert_type_list(const std::string& cert_type_names) const {
311 std::vector<Certificate_Type> cert_types;
312 for(const std::string& cert_type_name : split_on(cert_type_names, ' ')) {
313 cert_types.push_back(certificate_type_from_string(cert_type_name));
314 }
315
316 return cert_types;
317}
318
319std::vector<Signature_Scheme> Text_Policy::read_sig_scheme_list(std::string_view sig_scheme_str) const {
320 std::vector<Signature_Scheme> sig_schemes;
321 for(const auto& sig_scheme_name : split_on(sig_scheme_str, ' ')) {
322 sig_schemes.push_back(Signature_Scheme::from_string(sig_scheme_name));
323 }
324 return sig_schemes;
325}
326
327size_t Text_Policy::get_len(const std::string& key, size_t def) const {
328 const std::string v = get_str(key);
329
330 if(v.empty()) {
331 return def;
332 }
333
334 return to_u32bit(v);
335}
336
337std::chrono::seconds Text_Policy::get_duration(const std::string& key, std::chrono::seconds def) const {
338 using rep_t = std::chrono::seconds::rep;
339 constexpr rep_t max_seconds = std::chrono::seconds::max().count();
340 constexpr auto max_sizet = std::numeric_limits<size_t>::max();
341 using ull = unsigned long long;
342
343 // The concrete type of `rep` is not specified exactly. Let's play it extra safe...
344 // e.g. on 32-bit platforms size_t is 32 bits but rep_t is "at least 35 bits"
345
346 // at least zero and certainly fitting into rep_t
347 const rep_t positive_default = std::max(def.count(), rep_t(0));
348 // at least zero but capped to whatever size_t can handle
349 const size_t positive_capped_default = static_cast<size_t>(std::min<ull>(positive_default, max_sizet));
350 // at least zero but capped to whatever rep_t can handle
351 const rep_t result = static_cast<rep_t>(std::min<ull>(get_len(key, positive_capped_default), max_seconds));
352
353 return std::chrono::seconds(result);
354}
355
356bool Text_Policy::get_bool(const std::string& key, bool def) const {
357 const std::string v = get_str(key);
358
359 if(v.empty()) {
360 return def;
361 }
362
363 if(v == "true" || v == "True") {
364 return true;
365 } else if(v == "false" || v == "False") {
366 return false;
367 } else {
368 throw Decoding_Error("Invalid boolean '" + v + "'");
369 }
370}
371
372std::string Text_Policy::get_str(const std::string& key, const std::string& def) const {
373 auto i = m_kv.find(key);
374 if(i == m_kv.end()) {
375 return def;
376 }
377
378 return i->second;
379}
380
381bool Text_Policy::set_value(const std::string& key, std::string_view val, bool overwrite) {
382 auto i = m_kv.find(key);
383
384 if(overwrite == false && i != m_kv.end()) {
385 return false;
386 }
387
388 m_kv.insert(i, std::make_pair(key, val));
389 return true;
390}
391
392} // namespace Botan::TLS
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
static std::optional< Group_Params > from_string(std::string_view group_name)
virtual bool include_time_in_hello_random() const
virtual size_t dtls_maximum_timeout() const
virtual size_t minimum_ecdh_group_size() const
virtual size_t dtls_default_mtu() const
virtual bool allow_tls12() const
virtual std::vector< Signature_Scheme > allowed_signature_schemes() const
virtual bool reuse_session_tickets() const
virtual std::vector< Certificate_Type > accepted_server_certificate_types() const
virtual std::vector< Certificate_Type > accepted_client_certificate_types() const
virtual bool require_client_certificate_authentication() const
virtual std::vector< Group_Params > key_exchange_groups() const
virtual size_t new_session_tickets_upon_handshake_success() const
virtual std::vector< Group_Params > key_exchange_groups_to_offer() const
virtual size_t minimum_rsa_bits() const
virtual std::optional< size_t > dtls_maximum_hello_verify_requests() const
virtual bool tls_13_middlebox_compatibility_mode() const
virtual bool allow_client_initiated_renegotiation() const
virtual bool allow_ssl_key_log_file() const
virtual bool require_cert_revocation_info() const
virtual bool negotiate_encrypt_then_mac() const
virtual bool require_extended_master_secret() const
virtual bool server_uses_own_ciphersuite_preferences() const
virtual bool support_cert_status_message() const
virtual std::vector< std::string > allowed_macs() const
virtual bool hide_unknown_users() const
virtual bool hash_hello_random() const
virtual bool allow_tls13() const
virtual std::vector< std::string > allowed_key_exchange_methods() const
virtual size_t dtls_initial_timeout() const
virtual size_t maximum_session_tickets_per_client_hello() const
virtual std::vector< Signature_Scheme > acceptable_signature_schemes() const
virtual bool use_ecc_point_compression() const
virtual bool allow_dtls12() const
virtual size_t minimum_dh_group_size() const
virtual bool allow_insecure_renegotiation() const
virtual std::vector< std::string > allowed_ciphers() const
virtual std::chrono::seconds session_ticket_lifetime() const
virtual size_t minimum_signature_strength() const
virtual std::vector< std::string > allowed_signature_methods() const
virtual size_t minimum_ecdsa_group_size() const
virtual std::vector< std::string > allowed_signature_hashes() const
virtual bool allow_server_initiated_renegotiation() const
static Signature_Scheme from_string(std::string_view str)
size_t dtls_initial_timeout() const override
bool allow_dtls12() const override
bool server_uses_own_ciphersuite_preferences() const override
bool hash_hello_random() const override
std::chrono::seconds session_ticket_lifetime() const override
size_t record_padding_bytes(size_t plaintext_bytes) const override
std::optional< uint16_t > record_size_limit() const override
bool allow_ssl_key_log_file() const override
bool include_time_in_hello_random() const override
bool allow_client_initiated_renegotiation() const override
std::string get_str(const std::string &key, const std::string &def="") const
bool support_cert_status_message() const override
std::vector< std::string > allowed_signature_methods() const override
std::vector< Group_Params > key_exchange_groups() const override
bool require_cert_revocation_info() const override
std::vector< std::string > allowed_key_exchange_methods() const override
size_t minimum_ecdsa_group_size() const override
bool set_value(const std::string &key, std::string_view val, bool overwrite)
bool allow_tls13() const override
size_t maximum_session_tickets_per_client_hello() const override
std::vector< Certificate_Type > accepted_server_certificate_types() const override
std::vector< Group_Params > key_exchange_groups_to_offer() const override
std::chrono::seconds get_duration(const std::string &key, std::chrono::seconds def) const
size_t new_session_tickets_upon_handshake_success() const override
bool require_extended_master_secret() const override
std::vector< std::string > allowed_signature_hashes() const override
std::vector< uint16_t > srtp_profiles() const override
bool hide_unknown_users() const override
std::vector< std::string > allowed_ciphers() const override
Text_Policy(std::string_view s)
size_t minimum_ecdh_group_size() const override
void set(const std::string &key, const std::string &value)
bool allow_server_initiated_renegotiation() const override
bool get_bool(const std::string &key, bool def) const
size_t minimum_signature_strength() const override
std::vector< Certificate_Type > accepted_client_certificate_types() const override
bool negotiate_encrypt_then_mac() const override
std::optional< size_t > dtls_maximum_hello_verify_requests() const override
bool require_client_certificate_authentication() const override
bool tls_13_middlebox_compatibility_mode() const override
std::vector< Signature_Scheme > acceptable_signature_schemes() const override
size_t dtls_maximum_timeout() const override
bool reuse_session_tickets() const override
size_t get_len(const std::string &key, size_t def) const
bool allow_insecure_renegotiation() const override
bool allow_tls12() const override
std::vector< Signature_Scheme > allowed_signature_schemes() const override
bool use_ecc_point_compression() const override
std::vector< Certificate_Type > read_cert_type_list(const std::string &cert_type_str) const
std::vector< Signature_Scheme > read_sig_scheme_list(std::string_view sig_scheme_str) const
size_t dtls_default_mtu() const override
std::vector< Group_Params > read_group_list(std::string_view group_str) const
size_t minimum_rsa_bits() const override
std::vector< std::string > allowed_macs() const override
size_t minimum_dh_group_size() const override
std::vector< std::string > get_list(const std::string &key, const std::vector< std::string > &def) const
Certificate_Type certificate_type_from_string(const std::string &type_str)
std::map< std::string, std::string > read_cfg(std::istream &is)
Definition read_cfg.cpp:35
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
std::vector< std::string > split_on(std::string_view str, char delim)
Definition parsing.cpp:141
std::optional< uint16_t > parse_u16(std::string_view input, bool require_canonical)
Definition parsing.cpp:60
uint32_t to_u32bit(std::string_view input)
Definition parsing.cpp:76