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