1 /*
2 * (C) 2014,2015,2019 Jack Lloyd
3 *
4 * Botan is released under the Simplified BSD License (see license.txt)
5 */
6 
7 #ifndef BOTAN_CLI_TLS_HELPERS_H_
8 #define BOTAN_CLI_TLS_HELPERS_H_
9 
10 #include <botan/pkcs8.h>
11 #include <botan/credentials_manager.h>
12 #include <botan/tls_policy.h>
13 #include <botan/x509self.h>
14 #include <botan/data_src.h>
15 #include <memory>
16 #include <fstream>
17 
18 #include "cli_exceptions.h"
19 
20 #if defined(BOTAN_HAS_CERTSTOR_SYSTEM)
21    #include <botan/certstor_system.h>
22 #endif
23 
value_exists(const std::vector<std::string> & vec,const std::string & val)24 inline bool value_exists(const std::vector<std::string>& vec,
25                          const std::string& val)
26    {
27    for(size_t i = 0; i != vec.size(); ++i)
28       {
29       if(vec[i] == val)
30          {
31          return true;
32          }
33       }
34    return false;
35    }
36 
37 class Basic_Credentials_Manager : public Botan::Credentials_Manager
38    {
39    public:
Basic_Credentials_Manager(bool use_system_store,const std::string & ca_path)40       Basic_Credentials_Manager(bool use_system_store,
41                                 const std::string& ca_path)
42          {
43          if(ca_path.empty() == false)
44             {
45             m_certstores.push_back(std::make_shared<Botan::Certificate_Store_In_Memory>(ca_path));
46             }
47 
48 #if defined(BOTAN_HAS_CERTSTOR_SYSTEM)
49          if(use_system_store)
50             {
51             m_certstores.push_back(std::make_shared<Botan::System_Certificate_Store>());
52             }
53 #else
54          BOTAN_UNUSED(use_system_store);
55 #endif
56          }
57 
Basic_Credentials_Manager(Botan::RandomNumberGenerator & rng,const std::string & server_crt,const std::string & server_key)58       Basic_Credentials_Manager(Botan::RandomNumberGenerator& rng,
59                                 const std::string& server_crt,
60                                 const std::string& server_key)
61          {
62          Certificate_Info cert;
63 
64          cert.key.reset(Botan::PKCS8::load_key(server_key, rng));
65 
66          Botan::DataSource_Stream in(server_crt);
67          while(!in.end_of_data())
68             {
69             try
70                {
71                cert.certs.push_back(Botan::X509_Certificate(in));
72                }
73             catch(std::exception&)
74                {
75                }
76             }
77 
78          // TODO: attempt to validate chain ourselves
79 
80          m_creds.push_back(cert);
81          }
82 
83       std::vector<Botan::Certificate_Store*>
trusted_certificate_authorities(const std::string & type,const std::string &)84       trusted_certificate_authorities(const std::string& type,
85                                       const std::string& /*hostname*/) override
86          {
87          std::vector<Botan::Certificate_Store*> v;
88 
89          // don't ask for client certs
90          if(type == "tls-server")
91             {
92             return v;
93             }
94 
95          for(auto const& cs : m_certstores)
96             {
97             v.push_back(cs.get());
98             }
99 
100          return v;
101          }
102 
cert_chain(const std::vector<std::string> & algos,const std::string & type,const std::string & hostname)103       std::vector<Botan::X509_Certificate> cert_chain(
104          const std::vector<std::string>& algos,
105          const std::string& type,
106          const std::string& hostname) override
107          {
108          BOTAN_UNUSED(type);
109 
110          for(auto const& i : m_creds)
111             {
112             if(std::find(algos.begin(), algos.end(), i.key->algo_name()) == algos.end())
113                {
114                continue;
115                }
116 
117             if(hostname != "" && !i.certs[0].matches_dns_name(hostname))
118                {
119                continue;
120                }
121 
122             return i.certs;
123             }
124 
125          return std::vector<Botan::X509_Certificate>();
126          }
127 
private_key_for(const Botan::X509_Certificate & cert,const std::string &,const std::string &)128       Botan::Private_Key* private_key_for(const Botan::X509_Certificate& cert,
129                                           const std::string& /*type*/,
130                                           const std::string& /*context*/) override
131          {
132          for(auto const& i : m_creds)
133             {
134             if(cert == i.certs[0])
135                {
136                return i.key.get();
137                }
138             }
139 
140          return nullptr;
141          }
142 
143    private:
144       struct Certificate_Info
145          {
146          std::vector<Botan::X509_Certificate> certs;
147          std::shared_ptr<Botan::Private_Key> key;
148          };
149 
150       std::vector<Certificate_Info> m_creds;
151       std::vector<std::shared_ptr<Botan::Certificate_Store>> m_certstores;
152    };
153 
154 class TLS_All_Policy final : public Botan::TLS::Policy
155    {
156    public:
allowed_ciphers()157       std::vector<std::string> allowed_ciphers() const override
158          {
159          return std::vector<std::string>
160             {
161             "ChaCha20Poly1305",
162             "AES-256/OCB(12)",
163             "AES-128/OCB(12)",
164             "AES-256/GCM",
165             "AES-128/GCM",
166             "AES-256/CCM",
167             "AES-128/CCM",
168             "AES-256/CCM(8)",
169             "AES-128/CCM(8)",
170             "Camellia-256/GCM",
171             "Camellia-128/GCM",
172             "ARIA-256/GCM",
173             "ARIA-128/GCM",
174             "AES-256",
175             "AES-128",
176             "Camellia-256",
177             "Camellia-128",
178             "SEED"
179             "3DES"
180             };
181          }
182 
allowed_key_exchange_methods()183       std::vector<std::string> allowed_key_exchange_methods() const override
184          {
185          return { "SRP_SHA", "ECDHE_PSK", "DHE_PSK", "PSK", "CECPQ1", "ECDH", "DH", "RSA" };
186          }
187 
allowed_signature_methods()188       std::vector<std::string> allowed_signature_methods() const override
189          {
190          return { "ECDSA", "RSA", "DSA", "IMPLICIT" };
191          }
192 
allow_tls10()193       bool allow_tls10() const override { return true; }
allow_tls11()194       bool allow_tls11() const override { return true; }
allow_tls12()195       bool allow_tls12() const override { return true; }
196    };
197 
load_tls_policy(const std::string policy_type)198 inline std::unique_ptr<Botan::TLS::Policy> load_tls_policy(const std::string policy_type)
199    {
200    std::unique_ptr<Botan::TLS::Policy> policy;
201 
202    if(policy_type == "default" || policy_type == "")
203       {
204       policy.reset(new Botan::TLS::Policy);
205       }
206    else if(policy_type == "suiteb_128")
207       {
208       policy.reset(new Botan::TLS::NSA_Suite_B_128);
209       }
210    else if(policy_type == "suiteb_192" || policy_type == "suiteb")
211       {
212       policy.reset(new Botan::TLS::NSA_Suite_B_192);
213       }
214    else if(policy_type == "strict")
215       {
216       policy.reset(new Botan::TLS::Strict_Policy);
217       }
218    else if(policy_type == "bsi")
219       {
220       policy.reset(new Botan::TLS::BSI_TR_02102_2);
221       }
222    else if(policy_type == "datagram")
223       {
224       policy.reset(new Botan::TLS::Strict_Policy);
225       }
226    else if(policy_type == "all" || policy_type == "everything")
227       {
228       policy.reset(new TLS_All_Policy);
229       }
230    else
231       {
232       // assume it's a file
233       std::ifstream policy_stream(policy_type);
234       if(!policy_stream.good())
235          {
236          throw Botan_CLI::CLI_Usage_Error("Unknown TLS policy: not a file or known short name");
237          }
238       policy.reset(new Botan::TLS::Text_Policy(policy_stream));
239       }
240 
241    return policy;
242    }
243 
244 #endif
245