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