Kea 2.7.6
botan_tls.cc
Go to the documentation of this file.
1// Copyright (C) 2021-2024 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#ifdef WITH_BOTAN
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// Kea session manager.
186using KeaSessionManager = Botan::TLS::Session_Manager_Noop;
187
188// Allowed signature methods which prefers RSA.
189const std::vector<std::string>
190KeaPolicy::AllowedSignatureMethodsRSA = { "RSA", "DSA", "ECDSA" };
191
192// Allowed signature methods which prefers ECDSA.
193const std::vector<std::string>
194KeaPolicy::AllowedSignatureMethodsECDSA = { "ECDSA", "RSA", "DSA" };
195
196// Class of Botan TLS context implementations.
197class TlsContextImpl {
198public:
199 // Constructor.
200 TlsContextImpl() : cred_mgr_(), rng_(), sess_mgr_(), policy_() {
201 }
202
203 // Destructor.
204 virtual ~TlsContextImpl() {
205 }
206
207 // Get the peer certificate requirement mode.
208 virtual bool getCertRequired() const {
209 return (cred_mgr_.getUseStores());
210 }
211
212 // Set the peer certificate requirement mode.
213 //
214 // With Botan this means to provide or not the CA certificate stores.
215 virtual void setCertRequired(bool cert_required) {
216 cred_mgr_.setUseStores(cert_required);
217 }
218
219 // Load the trust anchor aka certificate authority (path).
220 virtual void loadCaPath(const std::string& ca_path) {
221 try {
222 cred_mgr_.setStorePath(ca_path);
223 } catch (const std::exception& ex) {
224 isc_throw(LibraryError, ex.what());
225 }
226 }
227
228 // Load the trust anchor aka certificate authority (file).
229 virtual void loadCaFile(const std::string& ca_file) {
230 try {
231 cred_mgr_.setStoreFile(ca_file);
232 } catch (const std::exception& ex) {
233 isc_throw(LibraryError, ex.what());
234 }
235 }
236
238 virtual void loadCertFile(const std::string& cert_file) {
239 try {
240 cred_mgr_.setCertChain(cert_file);
241 } catch (const std::exception& ex) {
242 isc_throw(LibraryError, ex.what());
243 }
244 }
245
249 virtual void loadKeyFile(const std::string& key_file) {
250 try {
251 bool is_rsa = true;
252 cred_mgr_.setPrivateKey(key_file, rng_, is_rsa);
253 policy_.setPrefRSA(is_rsa);
254 } catch (const std::exception& ex) {
255 isc_throw(LibraryError, ex.what());
256 }
257 }
258
259 // Build the context if not yet done.
260 virtual void build() {
261 if (context_) {
262 return;
263 }
264 context_.reset(new Botan::TLS::Context(cred_mgr_,
265 rng_,
266 sess_mgr_,
267 policy_));
268 }
269
270 virtual Botan::TLS::Context& get() {
271 return (*context_);
272 }
273
274 // Credentials Manager.
275 KeaCredentialsManager cred_mgr_;
276
277 // Random Number Generator.
278 Botan::AutoSeeded_RNG rng_;
279
280 // Session Manager.
281 KeaSessionManager sess_mgr_;
282
283 KeaPolicy policy_;
284
285 std::unique_ptr<Botan::TLS::Context> context_;
286};
287
288TlsContext::~TlsContext() {
289}
290
291TlsContext::TlsContext(TlsRole role)
292 : TlsContextBase(role), impl_(new TlsContextImpl()) {
293}
294
295Botan::TLS::Context&
296TlsContext::getContext() {
297 impl_->build();
298 return (impl_->get());
299}
300
301void
302TlsContext::setCertRequired(bool cert_required) {
303 if (!cert_required && (getRole() == TlsRole::CLIENT)) {
305 "'cert-required' parameter must be true for a TLS client");
306 }
307 impl_->setCertRequired(cert_required);
308}
309
310bool
311TlsContext::getCertRequired() const {
312 return (impl_->getCertRequired());
313}
314
315void
316TlsContext::loadCaFile(const std::string& ca_file) {
317 impl_->loadCaFile(ca_file);
318}
319
320void
321TlsContext::loadCaPath(const std::string& ca_path) {
322 impl_->loadCaPath(ca_path);
323}
324
325void
326TlsContext::loadCertFile(const std::string& cert_file) {
327 impl_->loadCertFile(cert_file);
328}
329
330void
331TlsContext::loadKeyFile(const std::string& key_file) {
332 impl_->loadKeyFile(key_file);
333}
334
335} // namespace asiolink
336} // namespace isc
337
338#endif // WITH_BOTAN
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
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.