1 /*
2    BAREOS® - Backup Archiving REcovery Open Sourced
3 
4    Copyright (C) 2005-2010 Free Software Foundation Europe e.V.
5    Copyright (C) 2014-2020 Bareos GmbH & Co. KG
6 
7    This program is Free Software; you can redistribute it and/or
8    modify it under the terms of version three of the GNU Affero General Public
9    License as published by the Free Software Foundation and included
10    in the file LICENSE.
11 
12    This program is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15    Affero General Public License for more details.
16 
17    You should have received a copy of the GNU Affero General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20    02110-1301, USA.
21 */
22 /*
23  * tls_openssl.c TLS support functions when using OPENSSL backend.
24  *
25  * Author: Landon Fuller <landonf@threerings.net>
26  */
27 
28 #include <assert.h>
29 #include "include/bareos.h"
30 #include "include/make_unique.h"
31 #include "lib/bpoll.h"
32 #include "lib/crypto_openssl.h"
33 
34 #if defined(HAVE_TLS) && defined(HAVE_OPENSSL)
35 
36 #  include <openssl/asn1.h>
37 #  include <openssl/asn1t.h>
38 #  include <openssl/err.h>
39 #  include <openssl/ssl.h>
40 #  include <openssl/x509v3.h>
41 
42 #  include "lib/bsock.h"
43 #  include "lib/tls_openssl.h"
44 #  include "lib/tls_openssl_private.h"
45 #  include "lib/bstringlist.h"
46 #  include "lib/ascii_control_characters.h"
47 #  include "include/jcr.h"
48 
49 #  include "parse_conf.h"
50 
TlsOpenSsl()51 TlsOpenSsl::TlsOpenSsl() : d_(std::make_unique<TlsOpenSslPrivate>()) {}
52 
53 TlsOpenSsl::~TlsOpenSsl() = default;
54 
init()55 bool TlsOpenSsl::init() { return d_->init(); }
56 
SetTlsPskClientContext(const PskCredentials & credentials)57 void TlsOpenSsl::SetTlsPskClientContext(const PskCredentials& credentials)
58 {
59   if (!d_->openssl_ctx_) {
60     Dmsg0(50, "Could not set TLS_PSK CLIENT context (no SSL_CTX)\n");
61   } else {
62     BStringList ident(credentials.get_identity(),
63                       AsciiControlCharacters::RecordSeparator());
64     Dmsg1(50, "Preparing TLS_PSK CLIENT context for identity %s\n",
65           ident.JoinReadable().c_str());
66     d_->ClientContextInsertCredentials(credentials);
67     SSL_CTX_set_psk_client_callback(d_->openssl_ctx_,
68                                     TlsOpenSslPrivate::psk_client_cb);
69   }
70 }
71 
SetTlsPskServerContext(ConfigurationParser * config)72 void TlsOpenSsl::SetTlsPskServerContext(ConfigurationParser* config)
73 {
74   if (!d_->openssl_ctx_) {
75     Dmsg0(50, "Could not prepare TLS_PSK SERVER callback (no SSL_CTX)\n");
76   } else if (!config) {
77     Dmsg0(50, "Could not prepare TLS_PSK SERVER callback (no config)\n");
78   } else {
79     Dmsg0(50, "Preparing TLS_PSK SERVER callback\n");
80     SSL_CTX_set_ex_data(
81         d_->openssl_ctx_,
82         TlsOpenSslPrivate::SslCtxExDataIndex::kConfigurationParserPtr,
83         (void*)config);
84 
85     SSL_CTX_set_psk_server_callback(d_->openssl_ctx_,
86                                     TlsOpenSslPrivate::psk_server_cb);
87   }
88 }
89 
TlsCipherGetName() const90 std::string TlsOpenSsl::TlsCipherGetName() const
91 {
92   if (d_->openssl_) {
93     const SSL_CIPHER* cipher = SSL_get_current_cipher(d_->openssl_);
94     const char* protocol_name = SSL_get_cipher_version(d_->openssl_);
95     if (cipher) {
96       return std::string(SSL_CIPHER_get_name(cipher)) + " " + protocol_name;
97     }
98   }
99   return std::string();
100 }
101 
TlsLogConninfo(JobControlRecord * jcr,const char * host,int port,const char * who) const102 void TlsOpenSsl::TlsLogConninfo(JobControlRecord* jcr,
103                                 const char* host,
104                                 int port,
105                                 const char* who) const
106 {
107   if (!d_->openssl_) {
108     Qmsg(jcr, M_INFO, 0, _("No openssl to %s at %s:%d established\n"), who,
109          host, port);
110   } else {
111     std::string cipher_name = TlsCipherGetName();
112     Qmsg(jcr, M_INFO, 0, _("Connected %s at %s:%d, encryption: %s\n"), who,
113          host, port, cipher_name.empty() ? "Unknown" : cipher_name.c_str());
114   }
115 }
116 
117 /*
118  * Verifies a list of common names against the certificate commonName
119  * attribute.
120  *
121  * Returns: true on success
122  *          false on failure
123  */
TlsPostconnectVerifyCn(JobControlRecord * jcr,const std::vector<std::string> & verify_list)124 bool TlsOpenSsl::TlsPostconnectVerifyCn(
125     JobControlRecord* jcr,
126     const std::vector<std::string>& verify_list)
127 {
128   X509* cert;
129   X509_NAME* subject;
130   bool auth_success = false;
131 
132   if (!(cert = SSL_get_peer_certificate(d_->openssl_))) {
133     Qmsg0(jcr, M_ERROR, 0, _("Peer failed to present a TLS certificate\n"));
134     return false;
135   }
136 
137   if ((subject = X509_get_subject_name(cert)) != NULL) {
138     char data[256]; /* nullterminated by X509_NAME_get_text_by_NID */
139     if (X509_NAME_get_text_by_NID(subject, NID_commonName, data, sizeof(data))
140         > 0) {
141       std::string cn;
142       for (const std::string& cn : verify_list) {
143         std::string d(data);
144         Dmsg2(120, "comparing CNs: cert-cn=%s, allowed-cn=%s\n", data,
145               cn.c_str());
146         if (d.compare(cn) == 0) { auth_success = true; }
147       }
148     }
149   }
150 
151   X509_free(cert);
152   return auth_success;
153 }
154 
155 /*
156  * Verifies a peer's hostname against the subjectAltName and commonName
157  * attributes.
158  *
159  * Returns: true on success
160  *          false on failure
161  */
TlsPostconnectVerifyHost(JobControlRecord * jcr,const char * host)162 bool TlsOpenSsl::TlsPostconnectVerifyHost(JobControlRecord* jcr,
163                                           const char* host)
164 {
165   int i, j;
166   int extensions;
167   int cnLastPos = -1;
168   X509* cert;
169   X509_NAME* subject;
170   X509_NAME_ENTRY* neCN;
171   ASN1_STRING* asn1CN;
172   bool auth_success = false;
173 
174   if (!(cert = SSL_get_peer_certificate(d_->openssl_))) {
175     Qmsg1(jcr, M_ERROR, 0, _("Peer %s failed to present a TLS certificate\n"),
176           host);
177     return false;
178   }
179 
180   /*
181    * Check subjectAltName extensions first
182    */
183   if ((extensions = X509_get_ext_count(cert)) > 0) {
184     for (i = 0; i < extensions; i++) {
185       X509_EXTENSION* ext;
186       const char* extname;
187 
188       ext = X509_get_ext(cert, i);
189       extname = OBJ_nid2sn(OBJ_obj2nid(X509_EXTENSION_get_object(ext)));
190 
191       if (bstrcmp(extname, "subjectAltName")) {
192 #  if (OPENSSL_VERSION_NUMBER >= 0x10000000L)
193         const X509V3_EXT_METHOD* method;
194 #  else
195         X509V3_EXT_METHOD* method;
196 #  endif
197         STACK_OF(CONF_VALUE) * val;
198         CONF_VALUE* nval;
199         void* extstr = NULL;
200 #  if (OPENSSL_VERSION_NUMBER >= 0x0090800FL)
201         const unsigned char* ext_value_data;
202 #  else
203         unsigned char* ext_value_data;
204 #  endif
205 
206         if (!(method = X509V3_EXT_get(ext))) { break; }
207 
208         ext_value_data = X509_EXTENSION_get_data(ext)->data;
209 
210 #  if (OPENSSL_VERSION_NUMBER > 0x00907000L)
211         if (method->it) {
212           extstr = ASN1_item_d2i(NULL, &ext_value_data,
213                                  X509_EXTENSION_get_data(ext)->length,
214                                  ASN1_ITEM_ptr(method->it));
215         } else {
216           /*
217            * Old style ASN1
218            * Decode ASN1 item in data
219            */
220           extstr = method->d2i(NULL, &ext_value_data,
221                                X509_EXTENSION_get_data(ext)->length);
222         }
223 
224 #  else
225         extstr = method->d2i(NULL, &ext_value_data, ext->value->length);
226 #  endif
227 
228         /*
229          * Iterate through to find the dNSName field(s)
230          */
231         val = method->i2v(method, extstr, NULL);
232 
233         for (j = 0; j < sk_CONF_VALUE_num(val); j++) {
234           nval = sk_CONF_VALUE_value(val, j);
235           if (bstrcmp(nval->name, "DNS")) {
236             if (Bstrcasecmp(nval->value, host)) {
237               auth_success = true;
238               goto success;
239             }
240           }
241         }
242       }
243     }
244   }
245 
246   /*
247    * Try verifying against the subject name
248    */
249   if (!auth_success) {
250     if ((subject = X509_get_subject_name(cert)) != NULL) {
251       /*
252        * Loop through all CNs
253        */
254       for (;;) {
255         cnLastPos
256             = X509_NAME_get_index_by_NID(subject, NID_commonName, cnLastPos);
257         if (cnLastPos == -1) { break; }
258         neCN = X509_NAME_get_entry(subject, cnLastPos);
259         asn1CN = X509_NAME_ENTRY_get_data(neCN);
260         if (Bstrcasecmp((const char*)asn1CN->data, host)) {
261           auth_success = true;
262           break;
263         }
264       }
265     }
266   }
267 
268 success:
269   X509_free(cert);
270 
271   return auth_success;
272 }
273 
TlsBsockConnect(BareosSocket * bsock)274 bool TlsOpenSsl::TlsBsockConnect(BareosSocket* bsock)
275 {
276   return d_->OpensslBsockSessionStart(bsock, false);
277 }
278 
TlsBsockAccept(BareosSocket * bsock)279 bool TlsOpenSsl::TlsBsockAccept(BareosSocket* bsock)
280 {
281   return d_->OpensslBsockSessionStart(bsock, true);
282 }
283 
TlsBsockShutdown(BareosSocket * bsock)284 void TlsOpenSsl::TlsBsockShutdown(BareosSocket* bsock)
285 {
286   /*
287    * SSL_shutdown must be called twice to fully complete the process -
288    * The first time to initiate the shutdown handshake, and the second to
289    * receive the peer's reply.
290    *
291    * In addition, if the underlying socket is blocking, SSL_shutdown()
292    * will not return until the current stage of the shutdown process has
293    * completed or an error has occurred. By setting the socket blocking
294    * we can avoid the ugly for()/switch()/select() loop.
295    */
296 
297   if (!d_->openssl_) { return; }
298 
299   /* Set socket blocking for shutdown */
300   bsock->SetBlocking();
301 
302   btimer_t* tid = StartBsockTimer(bsock, 60 * 2);
303 
304   int err_shutdown = SSL_shutdown(d_->openssl_);
305 
306   StopBsockTimer(tid);
307 
308   if (err_shutdown == 0) {
309     /* Complete the shutdown with the second call */
310     tid = StartBsockTimer(bsock, 2);
311     err_shutdown = SSL_shutdown(d_->openssl_);
312     StopBsockTimer(tid);
313   }
314 
315   int ssl_error = SSL_get_error(d_->openssl_, err_shutdown);
316 
317   /*
318    * There may be more errors on the thread-local error-queue.
319    * As we just shutdown our context and looked at the errors that we were
320    * interested in we clear the queue so nobody else gets to read an error
321    * that may have occured here.
322    */
323   ERR_clear_error();  // empties the current thread's openssl error queue
324 
325   SSL_free(d_->openssl_);
326   d_->openssl_ = nullptr;
327 
328 
329   JobControlRecord* jcr = bsock->get_jcr();
330 
331   if (jcr && jcr->is_passive_client_connection_probing) { return; }
332 
333   std::string message{_("TLS shutdown failure.")};
334 
335   switch (ssl_error) {
336     case SSL_ERROR_NONE:
337       break;
338     case SSL_ERROR_ZERO_RETURN:
339       /* TLS connection was shut down on us via a TLS protocol-level closure
340        */
341       OpensslPostErrors(jcr, M_ERROR, message.c_str());
342       break;
343     default:
344       /* Socket Error Occurred */
345       OpensslPostErrors(jcr, M_ERROR, message.c_str());
346       break;
347   }
348 }
349 
TlsBsockWriten(BareosSocket * bsock,char * ptr,int32_t nbytes)350 int TlsOpenSsl::TlsBsockWriten(BareosSocket* bsock, char* ptr, int32_t nbytes)
351 {
352   return d_->OpensslBsockReadwrite(bsock, ptr, nbytes, true);
353 }
354 
TlsBsockReadn(BareosSocket * bsock,char * ptr,int32_t nbytes)355 int TlsOpenSsl::TlsBsockReadn(BareosSocket* bsock, char* ptr, int32_t nbytes)
356 {
357   return d_->OpensslBsockReadwrite(bsock, ptr, nbytes, false);
358 }
359 
360 #endif /* HAVE_TLS  && HAVE_OPENSSL */
361