1 /* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #include <algorithm>
24 
25 #ifdef _WIN32
26 /* In OpenSSL before 1.1.0, we need this first. */
27 #include <winsock2.h>
28 #endif /* _WIN32 */
29 
30 #include "openssl/ssl.h"      /* SSL_* */
31 #include "openssl/x509_vfy.h" /* X509_* */
32 
33 #include "mysql/components/services/log_builtins.h" /* LogErr */
34 #include "mysqld_error.h"                           /* Error/Warning macros */
35 
36 #include "sql/ssl_acceptor_context_data.h"
37 
38 /* Helpers */
verify_store_cert(SSL_CTX * ctx,SSL * ssl)39 static const char *verify_store_cert(SSL_CTX *ctx, SSL *ssl) {
40   const char *result = nullptr;
41   X509 *cert = SSL_get_certificate(ssl);
42   X509_STORE_CTX *sctx = X509_STORE_CTX_new();
43 
44   if (nullptr != sctx &&
45       0 != X509_STORE_CTX_init(sctx, SSL_CTX_get_cert_store(ctx), cert,
46                                nullptr) &&
47       !X509_verify_cert(sctx)) {
48     result = X509_verify_cert_error_string(X509_STORE_CTX_get_error(sctx));
49   }
50   if (sctx != nullptr) X509_STORE_CTX_free(sctx);
51   return result;
52 }
53 
my_asn1_time_to_string(ASN1_TIME * time,char * buf,int len)54 static char *my_asn1_time_to_string(ASN1_TIME *time, char *buf, int len) {
55   int n_read;
56   char *res = nullptr;
57   BIO *bio = BIO_new(BIO_s_mem());
58 
59   if (bio == nullptr) return nullptr;
60 
61   if (!ASN1_TIME_print(bio, time)) goto end;
62 
63   n_read = BIO_read(bio, buf, len - 1);
64 
65   if (n_read > 0) {
66     buf[n_read] = 0;
67     res = buf;
68   }
69 
70 end:
71   BIO_free(bio);
72   return res;
73 }
74 /* Helpers end */
75 
76 static std::string Ssl_acceptor_context_propert_type_names[] = {
77     "Ssl_accept_renegotiates",
78     "Ssl_accepts",
79     "Ssl_callback_cache_hits",
80     "Ssl_client_connects",
81     "Ssl_connect_renegotiates",
82     "Ssl_ctx_verify_depth",
83     "Ssl_ctx_verify_mode",
84     "Current_tls_ca",
85     "Current_tls_capath",
86     "Current_tls_cert",
87     "Current_tls_cipher",
88     "Current_tls_ciphersuites",
89     "Current_tls_crl",
90     "Current_tls_crlpath",
91     "Current_tls_key",
92     "Current_tls_version",
93     "Ssl_finished_accepts",
94     "Ssl_finished_connects",
95     "Ssl_server_not_after",
96     "Ssl_server_not_before",
97     "Ssl_session_cache_hits",
98     "Ssl_session_cache_misses",
99     "Ssl_session_cache_mode",
100     "Ssl_session_cache_overflows",
101     "Ssl_session_cache_size",
102     "Ssl_session_cache_timeouts",
103     "Ssl_used_session_cache_entries",
104     ""};
105 
Ssl_ctx_property_name(Ssl_acceptor_context_property_type property_type)106 std::string Ssl_ctx_property_name(
107     Ssl_acceptor_context_property_type property_type) {
108   return Ssl_acceptor_context_propert_type_names[static_cast<unsigned int>(
109       property_type)];
110 }
111 
operator ++(Ssl_acceptor_context_property_type & property_type)112 Ssl_acceptor_context_property_type &operator++(
113     Ssl_acceptor_context_property_type &property_type) {
114   property_type = static_cast<Ssl_acceptor_context_property_type>(
115       static_cast<
116           std::underlying_type<Ssl_acceptor_context_property_type>::type>(
117           property_type) +
118       1);
119   return property_type;
120 }
121 
Ssl_acceptor_context_data(std::string channel,bool use_ssl_arg,Ssl_init_callback * callbacks,bool report_ssl_error,enum enum_ssl_init_error * out_error)122 Ssl_acceptor_context_data::Ssl_acceptor_context_data(
123     std::string channel, bool use_ssl_arg, Ssl_init_callback *callbacks,
124     bool report_ssl_error /* = true */,
125     enum enum_ssl_init_error *out_error /* = nullptr */)
126     : channel_(channel), ssl_acceptor_fd_(nullptr), acceptor_(nullptr) {
127   enum enum_ssl_init_error error_num = SSL_INITERR_NOERROR;
128   {
129     callbacks->read_parameters(&current_ca_, &current_capath_,
130                                &current_version_, &current_cert_,
131                                &current_cipher_, &current_ciphersuites_,
132                                &current_key_, &current_crl_, &current_crlpath_);
133   }
134 
135   if (use_ssl_arg) {
136     ssl_acceptor_fd_ = new_VioSSLAcceptorFd(
137         current_key_.c_str(), current_cert_.c_str(), current_ca_.c_str(),
138         current_capath_.c_str(), current_cipher_.c_str(),
139         current_ciphersuites_.c_str(), &error_num, current_crl_.c_str(),
140         current_crlpath_.c_str(),
141         process_tls_version(current_version_.c_str()));
142 
143     if (!ssl_acceptor_fd_ && report_ssl_error) {
144       LogErr(WARNING_LEVEL, ER_WARN_TLS_CHANNEL_INITIALIZATION_ERROR,
145              channel_.c_str());
146       LogErr(WARNING_LEVEL, ER_SSL_LIBRARY_ERROR, sslGetErrString(error_num));
147     }
148 
149     if (ssl_acceptor_fd_) acceptor_ = SSL_new(ssl_acceptor_fd_->ssl_context);
150 
151     if (ssl_acceptor_fd_ && acceptor_) {
152       const char *error =
153           verify_store_cert(ssl_acceptor_fd_->ssl_context, acceptor_);
154 
155       if (error && report_ssl_error)
156         LogErr(WARNING_LEVEL, ER_SSL_SERVER_CERT_VERIFY_FAILED, error);
157     }
158   }
159   if (out_error) *out_error = error_num;
160 }
161 
~Ssl_acceptor_context_data()162 Ssl_acceptor_context_data::~Ssl_acceptor_context_data() {
163   if (acceptor_) SSL_free(acceptor_);
164   if (ssl_acceptor_fd_) free_vio_ssl_acceptor_fd(ssl_acceptor_fd_);
165 }
166 
show_property(Ssl_acceptor_context_property_type property_type) const167 std::string Ssl_acceptor_context_data::show_property(
168     Ssl_acceptor_context_property_type property_type) const {
169   auto c =
170       (ssl_acceptor_fd_ == nullptr) ? nullptr : ssl_acceptor_fd_->ssl_context;
171   auto s = acceptor_;
172   std::string output;
173   switch (property_type) {
174     case Ssl_acceptor_context_property_type::accept_renegotiates: {
175       output +=
176           std::to_string(c == nullptr ? 0 : SSL_CTX_sess_accept_renegotiate(c));
177       break;
178     }
179     case Ssl_acceptor_context_property_type::accepts: {
180       output += std::to_string(c == nullptr ? 0 : SSL_CTX_sess_accept(c));
181       break;
182     }
183     case Ssl_acceptor_context_property_type::callback_cache_hits: {
184       output += std::to_string(c == nullptr ? 0 : SSL_CTX_sess_cb_hits(c));
185       break;
186     }
187     case Ssl_acceptor_context_property_type::client_connects: {
188       output += std::to_string(c == nullptr ? 0 : SSL_CTX_sess_connect(c));
189       break;
190     }
191     case Ssl_acceptor_context_property_type::connect_renegotiates: {
192       output += std::to_string(
193           c == nullptr ? 0 : SSL_CTX_sess_connect_renegotiate(c));
194       break;
195     }
196     case Ssl_acceptor_context_property_type::ctx_verify_depth: {
197       output += std::to_string(c == nullptr ? 0 : SSL_CTX_get_verify_depth(c));
198       break;
199     }
200     case Ssl_acceptor_context_property_type::ctx_verify_mode: {
201       output += std::to_string(c == nullptr ? 0 : SSL_CTX_get_verify_mode(c));
202       break;
203     }
204     case Ssl_acceptor_context_property_type::current_tls_ca: {
205       const char *cert = current_ca();
206       output.assign((cert == nullptr) ? "" : cert);
207       break;
208     }
209     case Ssl_acceptor_context_property_type::current_tls_capath: {
210       const char *cert = current_capath();
211       output.assign((cert == nullptr) ? "" : cert);
212       break;
213     }
214     case Ssl_acceptor_context_property_type::current_tls_cert: {
215       const char *cert = current_cert();
216       output.assign((cert == nullptr) ? "" : cert);
217       break;
218     }
219     case Ssl_acceptor_context_property_type::current_tls_cipher: {
220       const char *cert = current_cipher();
221       output.assign((cert == nullptr) ? "" : cert);
222       break;
223     }
224     case Ssl_acceptor_context_property_type::current_tls_ciphersuites: {
225       const char *cert = current_ciphersuites();
226       output.assign((cert == nullptr) ? "" : cert);
227       break;
228     }
229     case Ssl_acceptor_context_property_type::current_tls_crl: {
230       const char *cert = current_crl();
231       output.assign((cert == nullptr) ? "" : cert);
232       break;
233     }
234     case Ssl_acceptor_context_property_type::current_tls_crlpath: {
235       const char *cert = current_crlpath();
236       output.assign((cert == nullptr) ? "" : cert);
237       break;
238     }
239     case Ssl_acceptor_context_property_type::current_tls_key: {
240       const char *cert = current_key();
241       output.assign((cert == nullptr) ? "" : cert);
242       break;
243     }
244     case Ssl_acceptor_context_property_type::current_tls_version: {
245       const char *cert = current_version();
246       output.assign((cert == nullptr) ? "" : cert);
247       break;
248     }
249     case Ssl_acceptor_context_property_type::finished_accepts: {
250       output += std::to_string(c == nullptr ? 0 : SSL_CTX_sess_accept_good(c));
251       break;
252     }
253     case Ssl_acceptor_context_property_type::finished_connects: {
254       output += std::to_string(c == nullptr ? 0 : SSL_CTX_sess_connect_good(c));
255       break;
256     }
257     case Ssl_acceptor_context_property_type::server_not_after: {
258       if (s != nullptr) {
259         X509 *cert = SSL_get_certificate(s);
260         ASN1_TIME *not_after = X509_get_notAfter(cert);
261         if (not_after != nullptr) {
262           char buffer[1024] = {};
263           (void)my_asn1_time_to_string(not_after, buffer, 1024);
264           output.assign(buffer);
265         }
266       } else
267         output.assign("");
268       break;
269     }
270     case Ssl_acceptor_context_property_type::server_not_before: {
271       if (s != nullptr) {
272         X509 *cert = SSL_get_certificate(s);
273         ASN1_TIME *not_before = X509_get_notBefore(cert);
274         if (not_before != nullptr) {
275           char buffer[1024] = {};
276           (void)my_asn1_time_to_string(not_before, buffer, 1024);
277           output.assign(buffer);
278         }
279       } else
280         output.assign("");
281       break;
282     }
283     case Ssl_acceptor_context_property_type::session_cache_hits: {
284       output += std::to_string(c == nullptr ? 0 : SSL_CTX_sess_hits(c));
285       break;
286     }
287     case Ssl_acceptor_context_property_type::session_cache_misses: {
288       output += std::to_string(c == nullptr ? 0 : SSL_CTX_sess_misses(c));
289       break;
290     }
291     case Ssl_acceptor_context_property_type::session_cache_mode: {
292       if (c == nullptr)
293         output.assign("NONE");
294       else {
295         switch (SSL_CTX_get_session_cache_mode(c)) {
296           case SSL_SESS_CACHE_OFF:
297             output.assign("OFF");
298             break;
299           case SSL_SESS_CACHE_CLIENT:
300             output.assign("CLIENT");
301             break;
302           case SSL_SESS_CACHE_SERVER:
303             output.assign("SERVER");
304             break;
305           case SSL_SESS_CACHE_BOTH:
306             output.assign("BOTH");
307             break;
308           case SSL_SESS_CACHE_NO_AUTO_CLEAR:
309             output.assign("NO_AUTO_CLEAR");
310             break;
311           case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP:
312             output.assign("NO_INTERNAL_LOOKUP");
313             break;
314           default:
315             output.assign("UNKNOWN");
316             break;
317         }
318       }
319       break;
320     }
321     case Ssl_acceptor_context_property_type::session_cache_overflows: {
322       output += std::to_string(c == nullptr ? 0 : SSL_CTX_sess_cache_full(c));
323       break;
324     }
325     case Ssl_acceptor_context_property_type::session_cache_size: {
326       output +=
327           std::to_string(c == nullptr ? 0 : SSL_CTX_sess_get_cache_size(c));
328       break;
329     }
330     case Ssl_acceptor_context_property_type::session_cache_timeouts: {
331       output += std::to_string(c == nullptr ? 0 : SSL_CTX_sess_timeouts(c));
332       break;
333     }
334     case Ssl_acceptor_context_property_type::used_session_cache_entries: {
335       output += std::to_string(c == nullptr ? 0 : SSL_CTX_sess_number(c));
336       break;
337     }
338     case Ssl_acceptor_context_property_type::last:
339       // Fall through
340     default:
341       output.assign("");
342   }
343   return output;
344 }
345