• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 5867182258

15 Aug 2023 01:12PM UTC coverage: 91.69%. Remained the same
5867182258

Pull #3570

github

web-flow
Merge 6740857b8 into fc4b4271f
Pull Request #3570: KMAC, 2nd: added keccak-fips as standalone; added KMAC-256

78663 of 85792 relevant lines covered (91.69%)

12338227.17 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.74
/src/cli/tls_helpers.h
1
/*
2
* (C) 2014,2015,2019 Jack Lloyd
3
*     2023           René Meusel, Rohde & Schwarz Cybersecurity
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#ifndef BOTAN_CLI_TLS_HELPERS_H_
9
#define BOTAN_CLI_TLS_HELPERS_H_
10

11
#include <botan/credentials_manager.h>
12
#include <botan/data_src.h>
13
#include <botan/hex.h>
14
#include <botan/pkcs8.h>
15
#include <botan/tls_policy.h>
16
#include <botan/x509self.h>
17
#include <fstream>
18
#include <memory>
19

20
#include "cli_exceptions.h"
21

22
#if defined(BOTAN_HAS_CERTSTOR_SYSTEM)
23
   #include <botan/certstor_system.h>
24
#endif
25

26
inline bool value_exists(const std::vector<std::string>& vec, const std::string& val) {
27
   for(size_t i = 0; i != vec.size(); ++i) {
28
      if(vec[i] == val) {
29
         return true;
30
      }
31
   }
32
   return false;
33
}
34

35
inline std::string maybe_hex_encode(std::string_view v) {
4✔
36
   auto is_printable_char = [](uint8_t c) { return c >= 32 && c < 127; };
8✔
37
   if(!std::all_of(v.begin(), v.end(), is_printable_char)) {
4✔
38
      return Botan::hex_encode(std::span<const uint8_t>(reinterpret_cast<const uint8_t*>(v.data()), v.size()));
×
39
   }
40
   return std::string(v);
4✔
41
}
42

43
class Basic_Credentials_Manager : public Botan::Credentials_Manager {
44
   protected:
45
      void load_credentials(const std::string& crt, const std::string& key) {
39✔
46
         Certificate_Info cert;
39✔
47

48
         Botan::DataSource_Stream key_in(key);
39✔
49
         cert.key = Botan::PKCS8::load_key(key_in);
78✔
50

51
         Botan::DataSource_Stream in(crt);
39✔
52
         while(!in.end_of_data()) {
117✔
53
            try {
78✔
54
               cert.certs.push_back(Botan::X509_Certificate(in));
117✔
55
            } catch(std::exception&) {}
39✔
56
         }
57

58
         // TODO: attempt to validate chain ourselves
59

60
         m_creds.push_back(cert);
39✔
61
      }
39✔
62

63
   public:
64
      Basic_Credentials_Manager(bool use_system_store,
41✔
65
                                const std::string& ca_path,
66
                                std::optional<std::string> client_crt = std::nullopt,
67
                                std::optional<std::string> client_key = std::nullopt,
68
                                std::optional<Botan::secure_vector<uint8_t>> psk = std::nullopt,
69
                                std::optional<std::string> psk_identity = std::nullopt,
70
                                const std::optional<std::string>& psk_prf = std::nullopt) :
41✔
71
            m_psk(std::move(psk)),
41✔
72
            m_psk_identity(std::move(psk_identity)),
41✔
73

74
            // RFC 8446 4.2.11
75
            //    the Hash algorithm MUST be set when the PSK is established or
76
            //    default to SHA-256 if no such algorithm is defined.
77
            m_psk_prf(psk_prf.value_or("SHA-256")) {
82✔
78
         if(ca_path.empty() == false) {
41✔
79
            m_certstores.push_back(std::make_shared<Botan::Certificate_Store_In_Memory>(ca_path));
5✔
80
         }
81

82
         BOTAN_ARG_CHECK(client_crt.has_value() == client_key.has_value(),
41✔
83
                         "either provide both client certificate and key or neither");
84

85
         if(client_crt.has_value() && client_key.has_value()) {
41✔
86
            load_credentials(client_crt.value(), client_key.value());
×
87
         }
88

89
#if defined(BOTAN_HAS_CERTSTOR_SYSTEM)
90
         if(use_system_store) {
41✔
91
            m_certstores.push_back(std::make_shared<Botan::System_Certificate_Store>());
41✔
92
         }
93
#else
94
         BOTAN_UNUSED(use_system_store);
95
#endif
96
      }
41✔
97

98
      Basic_Credentials_Manager(const std::string& server_crt,
39✔
99
                                const std::string& server_key,
100
                                std::optional<Botan::secure_vector<uint8_t>> psk = std::nullopt,
101
                                std::optional<std::string> psk_identity = std::nullopt,
102
                                const std::optional<std::string>& psk_prf = std::nullopt) :
39✔
103
            m_psk(std::move(psk)),
39✔
104
            m_psk_identity(std::move(psk_identity)),
78✔
105

106
            // RFC 8446 4.2.11
107
            //    the Hash algorithm MUST be set when the PSK is established or
108
            //    default to SHA-256 if no such algorithm is defined.
109
            m_psk_prf(psk_prf.value_or("SHA-256")) {
78✔
110
         load_credentials(server_crt, server_key);
39✔
111
      }
39✔
112

113
      std::vector<Botan::Certificate_Store*> trusted_certificate_authorities(const std::string& type,
87✔
114
                                                                             const std::string& /*hostname*/) override {
115
         std::vector<Botan::Certificate_Store*> v;
87✔
116

117
         // don't ask for client certs
118
         if(type == "tls-server") {
87✔
119
            return v;
120
         }
121

122
         for(const auto& cs : m_certstores) {
81✔
123
            v.push_back(cs.get());
42✔
124
         }
125

126
         return v;
127
      }
×
128

129
      std::vector<Botan::X509_Certificate> find_cert_chain(
112✔
130
         const std::vector<std::string>& algos,
131
         const std::vector<Botan::AlgorithmIdentifier>& cert_signature_schemes,
132
         const std::vector<Botan::X509_DN>& acceptable_cas,
133
         const std::string& type,
134
         const std::string& hostname) override {
135
         BOTAN_UNUSED(cert_signature_schemes);
112✔
136

137
         if(type == "tls-client") {
112✔
138
            for(const auto& dn : acceptable_cas) {
×
139
               for(const auto& cred : m_creds) {
×
140
                  if(dn == cred.certs[0].issuer_dn()) {
×
141
                     return cred.certs;
×
142
                  }
143
               }
144
            }
145
         } else if(type == "tls-server") {
112✔
146
            for(const auto& i : m_creds) {
176✔
147
               if(std::find(algos.begin(), algos.end(), i.key->algo_name()) == algos.end()) {
112✔
148
                  continue;
64✔
149
               }
150

151
               if(!hostname.empty() && !i.certs[0].matches_dns_name(hostname)) {
48✔
152
                  continue;
×
153
               }
154

155
               return i.certs;
48✔
156
            }
157
         }
158

159
         return {};
64✔
160
      }
161

162
      std::shared_ptr<Botan::Private_Key> private_key_for(const Botan::X509_Certificate& cert,
47✔
163
                                                          const std::string& /*type*/,
164
                                                          const std::string& /*context*/) override {
165
         for(const auto& i : m_creds) {
47✔
166
            if(cert == i.certs[0]) {
47✔
167
               return i.key;
47✔
168
            }
169
         }
170

171
         return nullptr;
×
172
      }
173

174
      std::string psk_identity(const std::string& type,
1✔
175
                               const std::string& context,
176
                               const std::string& identity_hint) override {
177
         return (m_psk_identity && (type == "tls-client" || type == "tls-server"))
1✔
178
                   ? m_psk_identity.value()
2✔
179
                   : Botan::Credentials_Manager::psk_identity(type, context, identity_hint);
×
180
      }
181

182
      std::vector<Botan::TLS::ExternalPSK> find_preshared_keys(
24✔
183
         std::string_view host,
184
         Botan::TLS::Connection_Side peer_type,
185
         const std::vector<std::string>& ids = {},
186
         const std::optional<std::string>& prf = std::nullopt) override {
187
         if(!m_psk.has_value() || !m_psk_identity.has_value()) {
24✔
188
            return Botan::Credentials_Manager::find_preshared_keys(host, peer_type, ids, prf);
20✔
189
         }
190

191
         std::vector<Botan::TLS::ExternalPSK> psks;
4✔
192

193
         const bool prf_matches = !prf.has_value() || m_psk_prf == prf.value();
4✔
194
         const bool id_matches = ids.empty() || std::find(ids.begin(), ids.end(), m_psk_identity.value()) != ids.end();
4✔
195

196
         if(prf_matches && id_matches) {
4✔
197
            psks.emplace_back(m_psk_identity.value(), m_psk_prf, m_psk.value());
4✔
198
         }
199

200
         return psks;
4✔
201
      }
4✔
202

203
   private:
204
      struct Certificate_Info {
78✔
205
            std::vector<Botan::X509_Certificate> certs;
206
            std::shared_ptr<Botan::Private_Key> key;
207
      };
208

209
      std::vector<Certificate_Info> m_creds;
210
      std::vector<std::shared_ptr<Botan::Certificate_Store>> m_certstores;
211
      std::optional<Botan::secure_vector<uint8_t>> m_psk;
212
      std::optional<std::string> m_psk_identity;
213
      std::string m_psk_prf;
214
};
215

216
class TLS_All_Policy final : public Botan::TLS::Policy {
2✔
217
   public:
218
      std::vector<std::string> allowed_ciphers() const override {
90✔
219
         return std::vector<std::string>{"ChaCha20Poly1305",
90✔
220
                                         "AES-256/OCB(12)",
221
                                         "AES-128/OCB(12)",
222
                                         "AES-256/GCM",
223
                                         "AES-128/GCM",
224
                                         "AES-256/CCM",
225
                                         "AES-128/CCM",
226
                                         "AES-256/CCM(8)",
227
                                         "AES-128/CCM(8)",
228
                                         "Camellia-256/GCM",
229
                                         "Camellia-128/GCM",
230
                                         "ARIA-256/GCM",
231
                                         "ARIA-128/GCM",
232
                                         "AES-256",
233
                                         "AES-128",
234
                                         "Camellia-256",
235
                                         "Camellia-128",
236
                                         "SEED",
237
                                         "3DES"};
1,800✔
238
      }
239

240
      std::vector<std::string> allowed_key_exchange_methods() const override {
1✔
241
         return {"ECDHE_PSK", "DHE_PSK", "PSK", "ECDH", "DH", "RSA"};
7✔
242
      }
243

244
      std::vector<std::string> allowed_signature_methods() const override {
1✔
245
         return {"ECDSA", "RSA", "DSA", "IMPLICIT"};
5✔
246
      }
247

248
      bool allow_tls12() const override { return true; }
1✔
249
};
250

251
inline std::shared_ptr<Botan::TLS::Policy> load_tls_policy(const std::string& policy_type) {
13✔
252
   if(policy_type == "default" || policy_type.empty()) {
13✔
253
      return std::make_shared<Botan::TLS::Policy>();
3✔
254
   } else if(policy_type == "suiteb_128") {
10✔
255
      return std::make_shared<Botan::TLS::NSA_Suite_B_128>();
1✔
256
   } else if(policy_type == "suiteb_192" || policy_type == "suiteb") {
9✔
257
      return std::make_shared<Botan::TLS::NSA_Suite_B_192>();
1✔
258
   } else if(policy_type == "strict") {
8✔
259
      return std::make_shared<Botan::TLS::Strict_Policy>();
1✔
260
   } else if(policy_type == "bsi") {
7✔
261
      return std::make_shared<Botan::TLS::BSI_TR_02102_2>();
×
262
   } else if(policy_type == "datagram") {
7✔
263
      return std::make_shared<Botan::TLS::Strict_Policy>();
×
264
   } else if(policy_type == "all" || policy_type == "everything") {
7✔
265
      return std::make_shared<TLS_All_Policy>();
1✔
266
   }
267

268
   // if something we don't recognize, assume it's a file
269
   std::ifstream policy_stream(policy_type);
6✔
270
   if(!policy_stream.good()) {
6✔
271
      throw Botan_CLI::CLI_Usage_Error("Unknown TLS policy: not a file or known short name");
×
272
   }
273
   return std::make_shared<Botan::TLS::Text_Policy>(policy_stream);
6✔
274
}
6✔
275

276
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc