Repository navigation
Expand file tree
/
Copy pathtls_options.cpp
More file actions
152 lines (125 loc) · 3.91 KB
/
Copy pathtls_options.cpp
File metadata and controls
152 lines (125 loc) · 3.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#include "tls_options.h"
#include <algorithm>
#include <cctype>
namespace {
std::string uppercase(const std::string& value) {
std::string result(value);
std::transform(result.begin(), result.end(), result.begin(),
[](unsigned char character) {
return static_cast<char>(std::toupper(character));
});
return result;
}
bool set_tls_option(MYSQL* mysql, enum mysql_option option, const void* value,
std::string* error) {
if (mysql_options(mysql, option, value) == 0)
return true;
if (error)
*error = mysql_error(mysql);
return false;
}
const char* optional_value(const std::string& value) {
return value.empty() ? nullptr : value.c_str();
}
bool has_tls_material(const TLSOptions& options) {
return !options.ca_file.empty() || !options.ca_path.empty() ||
!options.certificate_file.empty() || !options.key_file.empty() ||
!options.cipher.empty() || !options.version.empty();
}
} // namespace
bool parse_tls_mode(const std::string& value, TLSMode* result) {
if (!result)
return false;
const std::string normalized = uppercase(value);
if (normalized == "DISABLED") {
*result = TLSMode::DISABLED;
} else if (normalized == "PREFERRED") {
*result = TLSMode::PREFERRED;
} else if (normalized == "REQUIRED") {
*result = TLSMode::REQUIRED;
} else {
return false;
}
return true;
}
bool parse_tls_boolean(const std::string& value, bool* result) {
if (!result)
return false;
const std::string normalized = uppercase(value);
if (normalized == "0" || normalized == "FALSE") {
*result = false;
} else if (normalized == "1" || normalized == "TRUE") {
*result = true;
} else {
return false;
}
return true;
}
bool tls_options_valid(const TLSOptions& options, std::string* error) {
if (options.mode != TLSMode::DISABLED) {
if (error)
error->clear();
return true;
}
if (options.verify_server_certificate) {
if (error)
*error = "TLS certificate verification cannot be enabled when TLS is disabled";
return false;
}
if (has_tls_material(options)) {
if (error)
*error = "TLS material cannot be configured when TLS is disabled";
return false;
}
if (error)
error->clear();
return true;
}
bool apply_tls_options(MYSQL* mysql, const TLSOptions& options, std::string* error) {
if (!mysql) {
if (error)
*error = "MYSQL handle is null";
return false;
}
if (!tls_options_valid(options, error))
return false;
const my_bool enforce = options.mode == TLSMode::DISABLED ? 0 : 1;
const my_bool verify = options.mode == TLSMode::DISABLED
? 0
: (options.verify_server_certificate ? 1 : 0);
if (!set_tls_option(mysql, MYSQL_OPT_SSL_ENFORCE, &enforce, error) ||
!set_tls_option(mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &verify, error) ||
!set_tls_option(mysql, MYSQL_OPT_SSL_CA, optional_value(options.ca_file), error) ||
!set_tls_option(mysql, MYSQL_OPT_SSL_CAPATH, optional_value(options.ca_path), error) ||
!set_tls_option(mysql, MYSQL_OPT_SSL_CERT, optional_value(options.certificate_file), error) ||
!set_tls_option(mysql, MYSQL_OPT_SSL_KEY, optional_value(options.key_file), error) ||
!set_tls_option(mysql, MYSQL_OPT_SSL_CIPHER, optional_value(options.cipher), error) ||
!set_tls_option(mysql, MYSQL_OPT_TLS_VERSION, optional_value(options.version), error)) {
return false;
}
if (error)
error->clear();
return true;
}
bool verify_tls_connection(MYSQL* mysql, const TLSOptions& options, std::string* error) {
if (options.mode != TLSMode::REQUIRED ||
(mysql && mysql_get_ssl_cipher(mysql) != nullptr)) {
if (error)
error->clear();
return true;
}
if (error)
*error = "TLS is required but no TLS cipher was negotiated";
return false;
}
const char* tls_mode_name(TLSMode mode) {
switch (mode) {
case TLSMode::DISABLED:
return "DISABLED";
case TLSMode::PREFERRED:
return "PREFERRED";
case TLSMode::REQUIRED:
return "REQUIRED";
}
return "UNKNOWN";
}