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(¤t_ca_, ¤t_capath_,
130 ¤t_version_, ¤t_cert_,
131 ¤t_cipher_, ¤t_ciphersuites_,
132 ¤t_key_, ¤t_crl_, ¤t_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