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

randombit / botan / 5607864191

18 Jul 2023 11:59AM UTC coverage: 91.706% (-0.03%) from 91.736%
5607864191

push

github

randombit
Merge GH #3622 Extend Credentials_Manager to support TLS 1.3 PSK

78332 of 85416 relevant lines covered (91.71%)

12320969.22 hits per line

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

86.6
/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/pkcs8.h>
14
#include <botan/tls_policy.h>
15
#include <botan/x509self.h>
16
#include <fstream>
17
#include <memory>
18

19
#include "cli_exceptions.h"
20

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

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

34
class Basic_Credentials_Manager : public Botan::Credentials_Manager {
35
   protected:
36
      void load_credentials(const std::string& crt, const std::string& key) {
39✔
37
         Certificate_Info cert;
39✔
38

39
         Botan::DataSource_Stream key_in(key);
39✔
40
         cert.key = Botan::PKCS8::load_key(key_in);
78✔
41

42
         Botan::DataSource_Stream in(crt);
39✔
43
         while(!in.end_of_data()) {
117✔
44
            try {
78✔
45
               cert.certs.push_back(Botan::X509_Certificate(in));
117✔
46
            } catch(std::exception&) {}
39✔
47
         }
48

49
         // TODO: attempt to validate chain ourselves
50

51
         m_creds.push_back(cert);
39✔
52
      }
39✔
53

54
   public:
55
      Basic_Credentials_Manager(bool use_system_store,
40✔
56
                                std::string ca_path,
57
                                std::optional<std::string> client_crt = std::nullopt,
58
                                std::optional<std::string> client_key = std::nullopt,
59
                                std::optional<Botan::secure_vector<uint8_t>> psk = std::nullopt,
60
                                std::optional<std::string> psk_identity = std::nullopt) :
40✔
61
            m_psk(std::move(psk)), m_psk_identity(std::move(psk_identity)) {
42✔
62
         if(ca_path.empty() == false) {
40✔
63
            m_certstores.push_back(std::make_shared<Botan::Certificate_Store_In_Memory>(ca_path));
4✔
64
         }
65

66
         BOTAN_ARG_CHECK(client_crt.has_value() == client_key.has_value(),
40✔
67
                         "either provide both client certificate and key or neither");
68

69
         if(client_crt.has_value() && client_key.has_value()) {
40✔
70
            load_credentials(client_crt.value(), client_key.value());
×
71
         }
72

73
#if defined(BOTAN_HAS_CERTSTOR_SYSTEM)
74
         if(use_system_store) {
40✔
75
            m_certstores.push_back(std::make_shared<Botan::System_Certificate_Store>());
40✔
76
         }
77
#else
78
         BOTAN_UNUSED(use_system_store);
79
#endif
80
      }
40✔
81

82
      Basic_Credentials_Manager(const std::string& server_crt,
39✔
83
                                const std::string& server_key,
84
                                std::optional<Botan::secure_vector<uint8_t>> psk = std::nullopt,
85
                                std::optional<std::string> psk_identity = std::nullopt) :
39✔
86
            m_psk(std::move(psk)), m_psk_identity(std::move(psk_identity)) {
41✔
87
         load_credentials(server_crt, server_key);
39✔
88
      }
39✔
89

90
      std::vector<Botan::Certificate_Store*> trusted_certificate_authorities(const std::string& type,
87✔
91
                                                                             const std::string& /*hostname*/) override {
92
         std::vector<Botan::Certificate_Store*> v;
87✔
93

94
         // don't ask for client certs
95
         if(type == "tls-server") {
87✔
96
            return v;
97
         }
98

99
         for(const auto& cs : m_certstores) {
81✔
100
            v.push_back(cs.get());
42✔
101
         }
102

103
         return v;
104
      }
×
105

106
      std::vector<Botan::X509_Certificate> find_cert_chain(
112✔
107
         const std::vector<std::string>& algos,
108
         const std::vector<Botan::AlgorithmIdentifier>& cert_signature_schemes,
109
         const std::vector<Botan::X509_DN>& acceptable_cas,
110
         const std::string& type,
111
         const std::string& hostname) override {
112
         BOTAN_UNUSED(cert_signature_schemes);
112✔
113

114
         if(type == "tls-client") {
112✔
115
            for(const auto& dn : acceptable_cas) {
×
116
               for(const auto& cred : m_creds) {
×
117
                  if(dn == cred.certs[0].issuer_dn())
×
118
                     return cred.certs;
×
119
               }
120
            }
121
         } else if(type == "tls-server") {
112✔
122
            for(const auto& i : m_creds) {
176✔
123
               if(std::find(algos.begin(), algos.end(), i.key->algo_name()) == algos.end()) {
112✔
124
                  continue;
64✔
125
               }
126

127
               if(hostname != "" && !i.certs[0].matches_dns_name(hostname)) {
48✔
128
                  continue;
×
129
               }
130

131
               return i.certs;
48✔
132
            }
133
         }
134

135
         return {};
64✔
136
      }
137

138
      std::shared_ptr<Botan::Private_Key> private_key_for(const Botan::X509_Certificate& cert,
47✔
139
                                                          const std::string& /*type*/,
140
                                                          const std::string& /*context*/) override {
141
         for(const auto& i : m_creds) {
47✔
142
            if(cert == i.certs[0]) {
47✔
143
               return i.key;
47✔
144
            }
145
         }
146

147
         return nullptr;
×
148
      }
149

150
      std::string psk_identity(const std::string& type,
1✔
151
                               const std::string& context,
152
                               const std::string& identity_hint) override {
153
         return (m_psk_identity && (type == "tls-client" || type == "tls-server"))
1✔
154
                   ? m_psk_identity.value()
2✔
155
                   : Botan::Credentials_Manager::psk_identity(type, context, identity_hint);
×
156
      }
157

158
      std::vector<Botan::TLS::ExternalPSK> find_preshared_keys(
2✔
159
         std::string_view host,
160
         Botan::TLS::Connection_Side peer_type,
161
         const std::vector<std::string>& ids = {},
162
         const std::optional<std::string>& prf = std::nullopt) override {
163
         if(!m_psk.has_value() || !m_psk_identity.has_value()) {
2✔
164
            return Botan::Credentials_Manager::find_preshared_keys(host, peer_type, ids, prf);
×
165
         }
166

167
         std::vector<Botan::TLS::ExternalPSK> psks;
2✔
168

169
         const bool prf_matches = !prf.has_value() || m_psk_prf == prf.value();
2✔
170
         const bool id_matches = ids.empty() || std::find(ids.begin(), ids.end(), m_psk_identity.value()) != ids.end();
2✔
171

172
         if(prf_matches && id_matches) {
2✔
173
            psks.emplace_back(m_psk_identity.value(), m_psk_prf, m_psk.value());
2✔
174
         }
175

176
         return psks;
2✔
177
      }
2✔
178

179
   private:
180
      struct Certificate_Info {
78✔
181
            std::vector<Botan::X509_Certificate> certs;
182
            std::shared_ptr<Botan::Private_Key> key;
183
      };
184

185
      std::vector<Certificate_Info> m_creds;
186
      std::vector<std::shared_ptr<Botan::Certificate_Store>> m_certstores;
187
      std::optional<Botan::secure_vector<uint8_t>> m_psk;
188
      std::optional<std::string> m_psk_identity;
189
      std::string m_psk_prf;
190
};
191

192
class TLS_All_Policy final : public Botan::TLS::Policy {
2✔
193
   public:
194
      std::vector<std::string> allowed_ciphers() const override {
90✔
195
         return std::vector<std::string>{"ChaCha20Poly1305",
90✔
196
                                         "AES-256/OCB(12)",
197
                                         "AES-128/OCB(12)",
198
                                         "AES-256/GCM",
199
                                         "AES-128/GCM",
200
                                         "AES-256/CCM",
201
                                         "AES-128/CCM",
202
                                         "AES-256/CCM(8)",
203
                                         "AES-128/CCM(8)",
204
                                         "Camellia-256/GCM",
205
                                         "Camellia-128/GCM",
206
                                         "ARIA-256/GCM",
207
                                         "ARIA-128/GCM",
208
                                         "AES-256",
209
                                         "AES-128",
210
                                         "Camellia-256",
211
                                         "Camellia-128",
212
                                         "SEED",
213
                                         "3DES"};
1,800✔
214
      }
215

216
      std::vector<std::string> allowed_key_exchange_methods() const override {
1✔
217
         return {"ECDHE_PSK", "DHE_PSK", "PSK", "ECDH", "DH", "RSA"};
7✔
218
      }
219

220
      std::vector<std::string> allowed_signature_methods() const override {
1✔
221
         return {"ECDSA", "RSA", "DSA", "IMPLICIT"};
5✔
222
      }
223

224
      bool allow_tls12() const override { return true; }
1✔
225
};
226

227
inline std::shared_ptr<Botan::TLS::Policy> load_tls_policy(const std::string policy_type) {
12✔
228
   if(policy_type == "default" || policy_type == "") {
12✔
229
      return std::make_shared<Botan::TLS::Policy>();
3✔
230
   } else if(policy_type == "suiteb_128") {
9✔
231
      return std::make_shared<Botan::TLS::NSA_Suite_B_128>();
1✔
232
   } else if(policy_type == "suiteb_192" || policy_type == "suiteb") {
8✔
233
      return std::make_shared<Botan::TLS::NSA_Suite_B_192>();
1✔
234
   } else if(policy_type == "strict") {
7✔
235
      return std::make_shared<Botan::TLS::Strict_Policy>();
1✔
236
   } else if(policy_type == "bsi") {
6✔
237
      return std::make_shared<Botan::TLS::BSI_TR_02102_2>();
×
238
   } else if(policy_type == "datagram") {
6✔
239
      return std::make_shared<Botan::TLS::Strict_Policy>();
×
240
   } else if(policy_type == "all" || policy_type == "everything") {
6✔
241
      return std::make_shared<TLS_All_Policy>();
1✔
242
   }
243

244
   // if something we don't recognize, assume it's a file
245
   std::ifstream policy_stream(policy_type);
5✔
246
   if(!policy_stream.good()) {
5✔
247
      throw Botan_CLI::CLI_Usage_Error("Unknown TLS policy: not a file or known short name");
×
248
   }
249
   return std::make_shared<Botan::TLS::Text_Policy>(policy_stream);
5✔
250
}
5✔
251

252
#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