Kea 2.7.0
botan_boost_tls.cc
Go to the documentation of this file.
1// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
10
11#if defined(WITH_BOTAN) && defined(WITH_BOTAN_BOOST)
12
14#include <asiolink/crypto_tls.h>
15
16#include <botan/auto_rng.h>
17#include <botan/certstor_flatfile.h>
18#include <botan/data_src.h>
19#include <botan/pem.h>
20#include <botan/pkcs8.h>
21
22using namespace isc::cryptolink;
23
24namespace isc {
25namespace asiolink {
26
27// Classes of Kea certificate stores.
28using KeaCertificateStorePath = Botan::Certificate_Store_In_Memory;
29using KeaCertificateStoreFile = Botan::Flatfile_Certificate_Store;
30
31// Class of Kea credential managers.
32class KeaCredentialsManager : public Botan::Credentials_Manager {
33public:
34 // Constructor.
35 KeaCredentialsManager() : store_(), use_stores_(true), certs_(), key_() {
36 }
37
38 // Destructor.
39 virtual ~KeaCredentialsManager() {
40 }
41
42 // CA certificate stores.
43 // nullptr means do not require or check peer certificate.
44 std::vector<Botan::Certificate_Store*>
45 trusted_certificate_authorities(const std::string&,
46 const std::string&) override {
47 std::vector<Botan::Certificate_Store*> result;
48 if (use_stores_ && store_) {
49 result.push_back(store_.get());
50 }
51 return (result);
52 }
53
54 // Certificate chain.
55 std::vector<Botan::X509_Certificate>
56 cert_chain(const std::vector<std::string>&,
57 const std::string&,
58 const std::string&) override {
59 return (certs_);
60 }
61
62 // Private key.
63 Botan::Private_Key*
64 private_key_for(const Botan::X509_Certificate&,
65 const std::string&,
66 const std::string&) override {
67 return (key_.get());
68 }
69
70 // Set the store from a path.
71 void setStorePath(const std::string& path) {
72 store_.reset(new KeaCertificateStorePath(path));
73 }
74
75 // Set the store from a file.
76 void setStoreFile(const std::string& file) {
77 store_.reset(new KeaCertificateStoreFile(file));
78 }
79
80 // Get the use of CA certificate stores flag.
81 bool getUseStores() const {
82 return (use_stores_);
83 }
84
85 // Set the use of CA certificate stores flag.
86 void setUseStores(bool use_stores) {
87 use_stores_ = use_stores;
88 }
89
90 // Set the certificate chain.
91 void setCertChain(const std::string& file) {
92 Botan::DataSource_Stream source(file);
93 certs_.clear();
94 while (!source.end_of_data()) {
95 std::string label;
96 std::vector<uint8_t> cert;
97 try {
98 cert = unlock(Botan::PEM_Code::decode(source, label));
99 if ((label != "CERTIFICATE") &&
100 (label != "X509 CERTIFICATE") &&
101 (label != "TRUSTED CERTIFICATE")) {
102 isc_throw(LibraryError, "Expected a certificate, got '"
103 << label << "'");
104 }
105 certs_.push_back(Botan::X509_Certificate(cert));
106 } catch (const std::exception& ex) {
107 if (certs_.empty()) {
108 throw;
109 }
110 // Got one certificate so skipping garbage.
111 continue;
112 }
113 }
114 if (certs_.empty()) {
115 isc_throw(LibraryError, "Found no certificate?");
116 }
117 }
118
119 // Set the private key.
120 void setPrivateKey(const std::string& file,
121 Botan::RandomNumberGenerator& rng,
122 bool& is_rsa) {
123 key_.reset(Botan::PKCS8::load_key(file, rng));
124 if (!key_) {
126 "Botan::PKCS8::load_key failed but not threw?");
127 }
128 is_rsa = (key_->algo_name() == "RSA");
129 }
130
131 // Pointer to the CA certificate store.
132 std::unique_ptr<Botan::Certificate_Store> store_;
133
134 // Use the CA certificate store flag.
135 bool use_stores_;
136
137 // The certificate chain.
138 std::vector<Botan::X509_Certificate> certs_;
139
140 // Pointer to the private key.
141 std::unique_ptr<Botan::Private_Key> key_;
142};
143
144// Class of Kea policy.
145// Use Strict_Policy?
146class KeaPolicy : public Botan::TLS::Default_Policy {
147public:
148 // Constructor.
149 KeaPolicy() : prefer_rsa_(true) {
150 }
151
152 // Destructor.
153 virtual ~KeaPolicy() {
154 }
155
156 // Allowed signature methods in preference order.
157 std::vector<std::string> allowed_signature_methods() const override {
158 if (prefer_rsa_) {
159 return (AllowedSignatureMethodsRSA);
160 } else {
161 return (AllowedSignatureMethodsECDSA);
162 }
163 }
164
165 // Disable OSCP.
166 bool require_cert_revocation_info() const override {
167 return false;
168 }
169
170 // Set the RSA preferred flag.
171 void setPrefRSA(bool prefer_rsa) {
172 prefer_rsa_ = prefer_rsa;
173 }
174
175 // Prefer RSA preferred flag.
176 bool prefer_rsa_;
177
178 // Allowed signature methods which prefers RSA.
179 static const std::vector<std::string> AllowedSignatureMethodsRSA;
180
181 // Allowed signature methods which prefers ECDSA.
182 static const std::vector<std::string> AllowedSignatureMethodsECDSA;
183};
184
185
186// Kea session manager.
187using KeaSessionManager = Botan::TLS::Session_Manager_Noop;
188
189// Allowed signature methods which prefers RSA.
190const std::vector<std::string>
191KeaPolicy::AllowedSignatureMethodsRSA = { "RSA", "DSA", "ECDSA" };
192
193// Allowed signature methods which prefers ECDSA.
194const std::vector<std::string>
195KeaPolicy::AllowedSignatureMethodsECDSA = { "ECDSA", "RSA", "DSA" };
196
197// Class of Botan TLS context implementations.
198class TlsContextImpl {
199public:
200 // Constructor.
201 TlsContextImpl() : cred_mgr_(), rng_(), sess_mgr_(), policy_() {
202 }
203
204 // Destructor.
205 virtual ~TlsContextImpl() {
206 }
207
208 // Get the peer certificate requirement mode.
209 virtual bool getCertRequired() const {
210 return (cred_mgr_.getUseStores());
211 }
212
213 // Set the peer certificate requirement mode.
214 //
215 // With Botan this means to provide or not the CA certificate stores.
216 virtual void setCertRequired(bool cert_required) {
217 cred_mgr_.setUseStores(cert_required);
218 }
219
220 // Load the trust anchor aka certificate authority (path).
221 virtual void loadCaPath(const std::string& ca_path) {
222 try {
223 cred_mgr_.setStorePath(ca_path);
224 } catch (const std::exception& ex) {
226 }
227 }
228
229 // Load the trust anchor aka certificate authority (file).
230 virtual void loadCaFile(const std::string& ca_file) {
231 try {
232 cred_mgr_.setStoreFile(ca_file);
233 } catch (const std::exception& ex) {
235 }
236 }
237
239 virtual void loadCertFile(const std::string& cert_file) {
240 try {
241 cred_mgr_.setCertChain(cert_file);
242 } catch (const std::exception& ex) {
244 }
245 }
246
250 virtual void loadKeyFile(const std::string& key_file) {
251 try {
252 bool is_rsa = true;
253 cred_mgr_.setPrivateKey(key_file, rng_, is_rsa);
254 policy_.setPrefRSA(is_rsa);
255 } catch (const std::exception& ex) {
257 }
258 }
259
260 // Build the context if not yet done.
261 virtual void build() {
262 if (context_) {
263 return;
264 }
265 context_.reset(new Botan::TLS::Context(cred_mgr_,
266 rng_,
267 sess_mgr_,
268 policy_));
269 }
270
271 virtual Botan::TLS::Context& get() {
272 return (*context_);
273 }
274
275 // Credentials Manager.
276 KeaCredentialsManager cred_mgr_;
277
278 // Random Number Generator.
279 Botan::AutoSeeded_RNG rng_;
280
281 // Session Manager.
282 KeaSessionManager sess_mgr_;
283
284 KeaPolicy policy_;
285
286 std::unique_ptr<Botan::TLS::Context> context_;
287};
288
289TlsContext::~TlsContext() {
290}
291
292TlsContext::TlsContext(TlsRole role)
293 : TlsContextBase(role), impl_(new TlsContextImpl()) {
294}
295
296Botan::TLS::Context&
297TlsContext::getContext() {
298 impl_->build();
299 return (impl_->get());
300}
301
302void
303TlsContext::setCertRequired(bool cert_required) {
304 if (!cert_required && (getRole() == TlsRole::CLIENT)) {
306 "'cert-required' parameter must be true for a TLS client");
307 }
308 impl_->setCertRequired(cert_required);
309}
310
311bool
312TlsContext::getCertRequired() const {
313 return (impl_->getCertRequired());
314}
315
316void
317TlsContext::loadCaFile(const std::string& ca_file) {
318 impl_->loadCaFile(ca_file);
319}
320
321void
322TlsContext::loadCaPath(const std::string& ca_path) {
323 impl_->loadCaPath(ca_path);
324}
325
326void
327TlsContext::loadCertFile(const std::string& cert_file) {
328 impl_->loadCertFile(cert_file);
329}
330
331void
332TlsContext::loadKeyFile(const std::string& key_file) {
333 impl_->loadKeyFile(key_file);
334}
335
336} // namespace asiolink
337} // namespace isc
338
339#endif // WITH_BOTAN && WITH_BOTAN_BOOST
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown when an unexpected error condition occurs.
TLS API.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Defines the logger used by the top-level component of kea-lfc.