1 /** @file
2
3 @section license License
4
5 Licensed to the Apache Software Foundation (ASF) under one
6 or more contributor license agreements. See the NOTICE file
7 distributed with this work for additional information
8 regarding copyright ownership. The ASF licenses this file
9 to you under the Apache License, Version 2.0 (the
10 "License"); you may not use this file except in compliance
11 with the License. You may obtain a copy of the License at
12
13 http://www.apache.org/licenses/LICENSE-2.0
14
15 Unless required by applicable law or agreed to in writing, software
16 distributed under the License is distributed on an "AS IS" BASIS,
17 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 See the License for the specific language governing permissions and
19 limitations under the License.
20 */
21
22 #include "tscore/ink_config.h"
23 #include "records/I_RecHttp.h"
24 #include "tscore/ink_platform.h"
25 #include "tscore/Filenames.h"
26 #include "tscore/X509HostnameValidator.h"
27
28 #include "P_Net.h"
29 #include "P_SSLClientUtils.h"
30 #include "YamlSNIConfig.h"
31 #include "SSLDiags.h"
32
33 #include <openssl/err.h>
34 #include <openssl/pem.h>
35
36 int
verify_callback(int signature_ok,X509_STORE_CTX * ctx)37 verify_callback(int signature_ok, X509_STORE_CTX *ctx)
38 {
39 X509 *cert;
40 int depth;
41 int err;
42 SSL *ssl;
43
44 SSLDebug("Entered verify cb");
45
46 /*
47 * Retrieve the pointer to the SSL of the connection currently treated
48 * and the application specific data stored into the SSL object.
49 */
50 ssl = static_cast<SSL *>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
51 SSLNetVConnection *netvc = SSLNetVCAccess(ssl);
52
53 // No enforcing, go away
54 if (netvc == nullptr) {
55 // No netvc, very bad. Go away. Things are not good.
56 SSLDebug("WARN, Netvc gone by in verify_callback");
57 return false;
58 } else if (netvc->options.verifyServerPolicy == YamlSNIConfig::Policy::DISABLED) {
59 return true; // Tell them that all is well
60 }
61
62 depth = X509_STORE_CTX_get_error_depth(ctx);
63 cert = X509_STORE_CTX_get_current_cert(ctx);
64 err = X509_STORE_CTX_get_error(ctx);
65
66 bool enforce_mode = (netvc->options.verifyServerPolicy == YamlSNIConfig::Policy::ENFORCED);
67 bool check_sig =
68 static_cast<uint8_t>(netvc->options.verifyServerProperties) & static_cast<uint8_t>(YamlSNIConfig::Property::SIGNATURE_MASK);
69
70 if (check_sig) {
71 if (!signature_ok) {
72 SSLDebug("verify error:num=%d:%s:depth=%d", err, X509_verify_cert_error_string(err), depth);
73 const char *sni_name;
74 char buff[INET6_ADDRSTRLEN];
75 ats_ip_ntop(netvc->get_remote_addr(), buff, INET6_ADDRSTRLEN);
76 if (netvc->options.sni_servername) {
77 sni_name = netvc->options.sni_servername.get();
78 } else {
79 sni_name = buff;
80 }
81 Warning("Core server certificate verification failed for (%s). Action=%s Error=%s server=%s(%s) depth=%d", sni_name,
82 enforce_mode ? "Terminate" : "Continue", X509_verify_cert_error_string(err), netvc->options.ssl_servername.get(),
83 buff, depth);
84 // If not enforcing ignore the error, just log warning
85 return enforce_mode ? signature_ok : 1;
86 }
87 }
88 // Don't check names and other things unless this is the terminal cert
89 if (depth != 0) {
90 // Not server cert....
91 return signature_ok;
92 }
93
94 bool check_name =
95 static_cast<uint8_t>(netvc->options.verifyServerProperties) & static_cast<uint8_t>(YamlSNIConfig::Property::NAME_MASK);
96 if (check_name) {
97 char *matched_name = nullptr;
98 unsigned char *sni_name;
99 char buff[INET6_ADDRSTRLEN];
100 if (netvc->options.sni_servername) {
101 sni_name = reinterpret_cast<unsigned char *>(netvc->options.sni_servername.get());
102 } else {
103 sni_name = reinterpret_cast<unsigned char *>(buff);
104 ats_ip_ntop(netvc->get_remote_addr(), buff, INET6_ADDRSTRLEN);
105 }
106 if (validate_hostname(cert, sni_name, false, &matched_name)) {
107 SSLDebug("Hostname %s verified OK, matched %s", netvc->options.sni_servername.get(), matched_name);
108 ats_free(matched_name);
109 } else { // Name validation failed
110 // Get the server address if we did't already compute it
111 if (netvc->options.sni_servername) {
112 ats_ip_ntop(netvc->get_remote_addr(), buff, INET6_ADDRSTRLEN);
113 }
114 // If we got here the verification failed
115 Warning("SNI (%s) not in certificate. Action=%s server=%s(%s)", sni_name, enforce_mode ? "Terminate" : "Continue",
116 netvc->options.ssl_servername.get(), buff);
117 return !enforce_mode;
118 }
119 }
120 // If the previous configured checks passed, give the hook a try
121 netvc->set_verify_cert(ctx);
122 netvc->callHooks(TS_EVENT_SSL_VERIFY_SERVER);
123 netvc->set_verify_cert(nullptr);
124 if (netvc->getSSLHandShakeComplete()) { // hook moved the handshake state to terminal
125 unsigned char *sni_name;
126 char buff[INET6_ADDRSTRLEN];
127 if (netvc->options.sni_servername) {
128 sni_name = reinterpret_cast<unsigned char *>(netvc->options.sni_servername.get());
129 } else {
130 sni_name = reinterpret_cast<unsigned char *>(buff);
131 ats_ip_ntop(netvc->get_remote_addr(), buff, INET6_ADDRSTRLEN);
132 }
133 Warning("TS_EVENT_SSL_VERIFY_SERVER plugin failed the origin certificate check for %s. Action=%s SNI=%s",
134 netvc->options.ssl_servername.get(), enforce_mode ? "Terminate" : "Continue", sni_name);
135 return !enforce_mode;
136 }
137 // Made it this far. All is good
138 return true;
139 }
140
141 static int
ssl_client_cert_callback(SSL * ssl,void *)142 ssl_client_cert_callback(SSL *ssl, void * /*arg*/)
143 {
144 SSLNetVConnection *netvc = SSLNetVCAccess(ssl);
145 SSL_CTX *ctx = SSL_get_SSL_CTX(ssl);
146 if (ctx) {
147 // Do not need to free either the cert or the ssl_ctx
148 // both are internal pointers
149 X509 *cert = SSL_CTX_get0_certificate(ctx);
150 netvc->set_sent_cert(cert != nullptr ? 2 : 1);
151 }
152 return 1;
153 }
154
155 SSL_CTX *
SSLInitClientContext(const SSLConfigParams * params)156 SSLInitClientContext(const SSLConfigParams *params)
157 {
158 const SSL_METHOD *meth = nullptr;
159 SSL_CTX *client_ctx = nullptr;
160
161 // Note that we do not call RAND_seed() explicitly here, we depend on OpenSSL
162 // to do the seeding of the PRNG for us. This is the case for all platforms that
163 // has /dev/urandom for example.
164
165 meth = SSLv23_client_method();
166 client_ctx = SSL_CTX_new(meth);
167
168 if (!client_ctx) {
169 SSLError("cannot create new client context");
170 ::exit(1);
171 }
172
173 SSL_CTX_set_options(client_ctx, params->ssl_client_ctx_options);
174 if (params->client_cipherSuite != nullptr) {
175 if (!SSL_CTX_set_cipher_list(client_ctx, params->client_cipherSuite)) {
176 SSLError("invalid client cipher suite in %s", ts::filename::RECORDS);
177 goto fail;
178 }
179 }
180
181 #if TS_USE_TLS_SET_CIPHERSUITES
182 if (params->client_tls13_cipher_suites != nullptr) {
183 if (!SSL_CTX_set_ciphersuites(client_ctx, params->client_tls13_cipher_suites)) {
184 SSLError("invalid tls client cipher suites in %s", ts::filename::RECORDS);
185 goto fail;
186 }
187 }
188 #endif
189
190 #if defined(SSL_CTX_set1_groups_list) || defined(SSL_CTX_set1_curves_list)
191 if (params->client_groups_list != nullptr) {
192 #ifdef SSL_CTX_set1_groups_list
193 if (!SSL_CTX_set1_groups_list(client_ctx, params->client_groups_list)) {
194 #else
195 if (!SSL_CTX_set1_curves_list(client_ctx, params->client_groups_list)) {
196 #endif
197 SSLError("invalid groups list for client in %s", ts::filename::RECORDS);
198 goto fail;
199 }
200 }
201 #endif
202
203 SSL_CTX_set_verify_depth(client_ctx, params->client_verify_depth);
204 if (SSLConfigParams::init_ssl_ctx_cb) {
205 SSLConfigParams::init_ssl_ctx_cb(client_ctx, false);
206 }
207
208 SSL_CTX_set_cert_cb(client_ctx, ssl_client_cert_callback, nullptr);
209
210 return client_ctx;
211
212 fail:
213 SSLReleaseContext(client_ctx);
214 ::exit(1);
215 }
216
217 SSL_CTX *
218 SSLCreateClientContext(const struct SSLConfigParams *params, const char *ca_bundle_path, const char *ca_bundle_file,
219 const char *cert_path, const char *key_path)
220 {
221 std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)> ctx(nullptr, &SSL_CTX_free);
222
223 if (nullptr == params || nullptr == cert_path) {
224 return nullptr;
225 }
226
227 ctx.reset(SSLInitClientContext(params));
228
229 if (!ctx) {
230 return nullptr;
231 }
232
233 if (!SSL_CTX_use_certificate_chain_file(ctx.get(), cert_path)) {
234 SSLError("SSLCreateClientContext(): failed to load client certificate.");
235 return nullptr;
236 }
237
238 if (!key_path || key_path[0] == '\0') {
239 key_path = cert_path;
240 }
241
242 if (!SSL_CTX_use_PrivateKey_file(ctx.get(), key_path, SSL_FILETYPE_PEM)) {
243 SSLError("SSLCreateClientContext(): failed to load client private key.");
244 return nullptr;
245 }
246
247 if (!SSL_CTX_check_private_key(ctx.get())) {
248 SSLError("SSLCreateClientContext(): client private key does not match client certificate.");
249 return nullptr;
250 }
251
252 if (ca_bundle_file || ca_bundle_path) {
253 if (!SSL_CTX_load_verify_locations(ctx.get(), ca_bundle_file, ca_bundle_path)) {
254 SSLError("SSLCreateClientContext(): Invalid client CA cert file/CA path.");
255 return nullptr;
256 }
257 } else if (!SSL_CTX_set_default_verify_paths(ctx.get())) {
258 SSLError("SSLCreateClientContext(): failed to set the default verify paths.");
259 return nullptr;
260 }
261 return ctx.release();
262 }
263