support.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9/* DEBUG: section 83 SSL accelerator support */
10
11#include "squid.h"
12
13/* MS Visual Studio Projects are monolithic, so we need the following
14 * #if to exclude the SSL code from compile process when not needed.
15 */
16#if USE_OPENSSL
17
18#include "acl/FilledChecklist.h"
19#include "anyp/PortCfg.h"
20#include "anyp/Uri.h"
21#include "fatal.h"
22#include "fd.h"
23#include "fde.h"
24#include "globals.h"
25#include "ipc/MemMap.h"
26#include "security/CertError.h"
29#include "security/Session.h"
30#include "SquidConfig.h"
31#include "ssl/bio.h"
32#include "ssl/Config.h"
33#include "ssl/ErrorDetail.h"
34#include "ssl/gadgets.h"
35#include "ssl/support.h"
36
37#include <cerrno>
38
39// TODO: Move ssl_ex_index_* global variables from global.cc here.
41
43
44const EVP_MD *Ssl::DefaultSignHash = nullptr;
45
46std::vector<const char *> Ssl::BumpModeStr = {
47 "none",
48 "client-first",
49 "server-first",
50 "peek",
51 "stare",
52 "bump",
53 "splice",
54 "terminate"
55 /*,"err"*/
56};
57
63int
64Ssl::AskPasswordCb(char *buf, int size, int /* rwflag */, void *userdata)
65{
66 FILE *in;
67 int len = 0;
68 char cmdline[1024];
69
70 snprintf(cmdline, sizeof(cmdline), "\"%s\" \"%s\"", ::Config.Program.ssl_password, (const char *)userdata);
71 in = popen(cmdline, "r");
72
73 if (fgets(buf, size, in))
74
75 len = strlen(buf);
76
77 while (len > 0 && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
78 --len;
79
80 buf[len] = '\0';
81
82 pclose(in);
83
84 return len;
85}
86
88static void
89ssl_ask_password(SSL_CTX * context, const char * prompt)
90{
92 SSL_CTX_set_default_passwd_cb(context, Ssl::AskPasswordCb);
93 SSL_CTX_set_default_passwd_cb_userdata(context, (void *)prompt);
94 }
95}
96
97#if HAVE_LIBSSL_SSL_CTX_SET_TMP_RSA_CALLBACK
98static RSA *
99ssl_temp_rsa_cb(SSL *, int, int keylen)
100{
101 static RSA *rsa_512 = nullptr;
102 static RSA *rsa_1024 = nullptr;
103 static BIGNUM *e = nullptr;
104 RSA *rsa = nullptr;
105 int newkey = 0;
106
107 if (!e) {
108 e = BN_new();
109 if (!e || !BN_set_word(e, RSA_F4)) {
110 debugs(83, DBG_IMPORTANT, "ERROR: ssl_temp_rsa_cb: Failed to set exponent for key " << keylen);
111 BN_free(e);
112 e = nullptr;
113 return nullptr;
114 }
115 }
116
117 switch (keylen) {
118
119 case 512:
120
121 if (!rsa_512) {
122 rsa_512 = RSA_new();
123 if (rsa_512 && RSA_generate_key_ex(rsa_512, 512, e, nullptr)) {
124 newkey = 1;
125 } else {
126 RSA_free(rsa_512);
127 rsa_512 = nullptr;
128 }
129 }
130
131 rsa = rsa_512;
132 break;
133
134 case 1024:
135
136 if (!rsa_1024) {
137 rsa_1024 = RSA_new();
138 if (rsa_1024 && RSA_generate_key_ex(rsa_1024, 1024, e, nullptr)) {
139 newkey = 1;
140 } else {
141 RSA_free(rsa_1024);
142 rsa_1024 = nullptr;
143 }
144 }
145
146 rsa = rsa_1024;
147 break;
148
149 default:
150 debugs(83, DBG_IMPORTANT, "ERROR: ssl_temp_rsa_cb: Unexpected key length " << keylen);
151 return nullptr;
152 }
153
154 if (rsa == NULL) {
155 debugs(83, DBG_IMPORTANT, "ERROR: ssl_temp_rsa_cb: Failed to generate key " << keylen);
156 return nullptr;
157 }
158
159 if (newkey) {
160 if (Debug::Enabled(83, 5))
161 PEM_write_RSAPrivateKey(debug_log, rsa, nullptr, nullptr, 0, nullptr, nullptr);
162
163 debugs(83, DBG_IMPORTANT, "Generated ephemeral RSA key of length " << keylen);
164 }
165
166 return rsa;
167}
168#endif
169
170void
172{
173#if HAVE_LIBSSL_SSL_CTX_SET_TMP_RSA_CALLBACK
174 debugs(83, 9, "Setting RSA key generation callback.");
175 SSL_CTX_set_tmp_rsa_callback(ctx.get(), ssl_temp_rsa_cb);
176#else
177 (void)ctx;
178#endif
179}
180
181int Ssl::asn1timeToString(ASN1_TIME *tm, char *buf, int len)
182{
183 BIO *bio;
184 int write = 0;
185 bio = BIO_new(BIO_s_mem());
186 if (bio) {
187 if (ASN1_TIME_print(bio, tm))
188 write = BIO_read(bio, buf, len-1);
189 BIO_free(bio);
190 }
191 buf[write]='\0';
192 return write;
193}
194
195int Ssl::matchX509CommonNames(X509 *peer_cert, void *check_data, int (*check_func)(void *check_data, ASN1_STRING *cn_data))
196{
197 assert(peer_cert);
198
199 X509_NAME *name = X509_get_subject_name(peer_cert);
200
201 for (int i = X509_NAME_get_index_by_NID(name, NID_commonName, -1); i >= 0; i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) {
202
203 ASN1_STRING *cn_data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i));
204
205 if ( (*check_func)(check_data, cn_data) == 0)
206 return 1;
207 }
208
209 STACK_OF(GENERAL_NAME) * altnames;
210 altnames = (STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i(peer_cert, NID_subject_alt_name, nullptr, nullptr);
211
212 if (altnames) {
213 int numalts = sk_GENERAL_NAME_num(altnames);
214 for (int i = 0; i < numalts; ++i) {
215 const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);
216 if (check->type != GEN_DNS) {
217 continue;
218 }
219 ASN1_STRING *cn_data = check->d.dNSName;
220
221 if ( (*check_func)(check_data, cn_data) == 0) {
222 sk_GENERAL_NAME_pop_free(altnames, GENERAL_NAME_free);
223 return 1;
224 }
225 }
226 sk_GENERAL_NAME_pop_free(altnames, GENERAL_NAME_free);
227 }
228 return 0;
229}
230
231static int check_domain( void *check_data, ASN1_STRING *cn_data)
232{
233 char cn[1024];
234 const char *server = (const char *)check_data;
235
236 if (cn_data->length == 0)
237 return 1; // zero length cn, ignore
238
239 if (cn_data->length > (int)sizeof(cn) - 1)
240 return 1; //if does not fit our buffer just ignore
241
242 char *s = reinterpret_cast<char*>(cn_data->data);
243 char *d = cn;
244 for (int i = 0; i < cn_data->length; ++i, ++d, ++s) {
245 if (*s == '\0')
246 return 1; // always a domain mismatch. contains 0x00
247 *d = *s;
248 }
249 cn[cn_data->length] = '\0';
250 debugs(83, 4, "Verifying server domain " << server << " to certificate name/subjectAltName " << cn);
251 return matchDomainName(server, (cn[0] == '*' ? cn + 1 : cn), mdnRejectSubsubDomains);
252}
253
254bool Ssl::checkX509ServerValidity(X509 *cert, const char *server)
255{
256 return matchX509CommonNames(cert, (void *)server, check_domain);
257}
258
261static int
262ssl_verify_cb(int ok, X509_STORE_CTX * ctx)
263{
264 // preserve original ctx->error before SSL_ calls can overwrite it
265 Security::ErrorCode error_no = ok ? SSL_ERROR_NONE : X509_STORE_CTX_get_error(ctx);
266
267 SSL *ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
268 SSL_CTX *sslctx = SSL_get_SSL_CTX(ssl);
269 SBuf *server = (SBuf *)SSL_get_ex_data(ssl, ssl_ex_index_server);
270 void *dont_verify_domain = SSL_CTX_get_ex_data(sslctx, ssl_ctx_ex_index_dont_verify_domain);
271 ACLChecklist *check = (ACLChecklist*)SSL_get_ex_data(ssl, ssl_ex_index_cert_error_check);
272 X509 *peeked_cert = (X509 *)SSL_get_ex_data(ssl, ssl_ex_index_ssl_peeked_cert);
273 Security::CertPointer peer_cert;
275
276 // detect infinite loops
277 uint32_t *validationCounter = static_cast<uint32_t *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_validation_counter));
278 if (!validationCounter) {
279 validationCounter = new uint32_t(1);
280 SSL_set_ex_data(ssl, ssl_ex_index_ssl_validation_counter, validationCounter);
281 } else {
282 // overflows allowed if SQUID_CERT_VALIDATION_ITERATION_MAX >= UINT32_MAX
283 (*validationCounter)++;
284 }
285
286 if ((*validationCounter) >= SQUID_CERT_VALIDATION_ITERATION_MAX) {
287 ok = 0; // or the validation loop will never stop
289 debugs(83, 2, "SQUID_X509_V_ERR_INFINITE_VALIDATION: " <<
290 *validationCounter << " iterations while checking " << *peer_cert);
291 }
292
293 if (ok) {
294 debugs(83, 5, "SSL Certificate signature OK: " << *peer_cert);
295
296 // Check for domain mismatch only if the current certificate is the peer certificate.
297 if (!dont_verify_domain && server && peer_cert.get() == X509_STORE_CTX_get_current_cert(ctx)) {
298 if (!Ssl::checkX509ServerValidity(peer_cert.get(), server->c_str())) {
299 debugs(83, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " << *peer_cert << " does not match domainname " << server);
300 ok = 0;
302 }
303 }
304 }
305
306 if (ok && peeked_cert) {
307 // Check whether the already peeked certificate matches the new one.
308 if (X509_cmp(peer_cert.get(), peeked_cert) != 0) {
309 debugs(83, 2, "SQUID_X509_V_ERR_CERT_CHANGE: Certificate " << *peer_cert << " does not match peeked certificate");
310 ok = 0;
312 }
313 }
314
315 if (!ok && error_no == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) {
316 if (const auto params = Ssl::VerifyCallbackParameters::Find(*ssl)) {
317 if (params->callerHandlesMissingCertificates) {
318 debugs(83, 3, "hiding X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY");
319 params->hidMissingIssuer = true;
320 ok = 1;
321 }
322 }
323 }
324
325 if (!ok) {
326 Security::CertPointer broken_cert;
327 broken_cert.resetAndLock(X509_STORE_CTX_get_current_cert(ctx));
328 if (!broken_cert)
329 broken_cert = peer_cert;
330
331 Security::CertErrors *errs = static_cast<Security::CertErrors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors));
332 const int depth = X509_STORE_CTX_get_error_depth(ctx);
333 if (!errs) {
334 errs = new Security::CertErrors(Security::CertError(error_no, broken_cert, depth));
335 if (!SSL_set_ex_data(ssl, ssl_ex_index_ssl_errors, (void *)errs)) {
336 debugs(83, 2, "Failed to set ssl error_no in ssl_verify_cb: Certificate " << *peer_cert);
337 delete errs;
338 errs = nullptr;
339 }
340 } else // remember another error number
341 errs->push_back_unique(Security::CertError(error_no, broken_cert, depth));
342
343 if (const auto description = Ssl::GetErrorDescr(error_no))
344 debugs(83, 5, *description << ": " << *peer_cert);
345 else
346 debugs(83, DBG_IMPORTANT, "ERROR: SSL unknown certificate error " << error_no << " in " << *peer_cert);
347
348 // Check if the certificate error can be bypassed.
349 // Infinity validation loop errors can not bypassed.
350 if (error_no != SQUID_X509_V_ERR_INFINITE_VALIDATION) {
351 if (check) {
352 ACLFilledChecklist *filledCheck = Filled(check);
353 const auto savedErrors = filledCheck->sslErrors;
354 const auto sslErrors = std::make_unique<Security::CertErrors>(Security::CertError(error_no, broken_cert));
355 filledCheck->sslErrors = sslErrors.get();
356 filledCheck->serverCert = peer_cert;
357 if (check->fastCheck().allowed()) {
358 debugs(83, 3, "bypassing SSL error " << error_no << " in " << *peer_cert);
359 ok = 1;
360 } else {
361 debugs(83, 5, "confirming SSL error " << error_no);
362 }
363 filledCheck->sslErrors = savedErrors;
364 filledCheck->serverCert.reset();
365 }
366 // If the certificate validator is used then we need to allow all errors and
367 // pass them to certificate validator for more processing
368 else if (Ssl::TheConfig.ssl_crt_validator) {
369 ok = 1;
370 }
371 }
372 }
373
374 if (Ssl::TheConfig.ssl_crt_validator) {
375 // Check if we have stored certificates chain. Store if not.
376 if (!SSL_get_ex_data(ssl, ssl_ex_index_ssl_cert_chain)) {
377 STACK_OF(X509) *certStack = X509_STORE_CTX_get1_chain(ctx);
378 if (certStack && !SSL_set_ex_data(ssl, ssl_ex_index_ssl_cert_chain, certStack))
379 sk_X509_pop_free(certStack, X509_free);
380 }
381 }
382
383 if (!ok && !SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail) ) {
384
385 // Find the broken certificate. It may be intermediate.
386 Security::CertPointer broken_cert(peer_cert); // reasonable default if search fails
387 // Our SQUID_X509_V_ERR_DOMAIN_MISMATCH implies peer_cert is at fault.
388 if (error_no != SQUID_X509_V_ERR_DOMAIN_MISMATCH) {
389 if (auto *last_used_cert = X509_STORE_CTX_get_current_cert(ctx))
390 broken_cert.resetAndLock(last_used_cert);
391 }
392
393 std::unique_ptr<Security::ErrorDetail::Pointer> edp(new Security::ErrorDetail::Pointer(
394 new Security::ErrorDetail(error_no, peer_cert, broken_cert)));
395 if (SSL_set_ex_data(ssl, ssl_ex_index_ssl_error_detail, edp.get()))
396 edp.release();
397 else
398 debugs(83, 2, "failed to store a " << *peer_cert << " error detail: " << *edp);
399 }
400
401 return ok;
402}
403
404void
406{
407 int mode;
408
409 // assume each flag is exclusive; flags creator must check this assumption
410 if (flags & SSL_FLAG_DONT_VERIFY_PEER) {
411 debugs(83, DBG_IMPORTANT, "SECURITY WARNING: Peer certificates are not verified for validity!");
412 debugs(83, DBG_IMPORTANT, "WARNING: UPGRADE: The DONT_VERIFY_PEER flag is deprecated. Remove the clientca= option to disable client certificates.");
413 mode = SSL_VERIFY_NONE;
414 }
415 else if (flags & SSL_FLAG_DELAYED_AUTH) {
416 debugs(83, DBG_PARSE_NOTE(3), "not requesting client certificates until ACL processing requires one");
417 mode = SSL_VERIFY_NONE;
418 }
419 else if (flags & SSL_FLAG_CONDITIONAL_AUTH) {
420 debugs(83, DBG_PARSE_NOTE(3), "will request the client certificate but ignore its absence");
421 mode = SSL_VERIFY_PEER;
422 }
423 else {
424 debugs(83, DBG_PARSE_NOTE(3), "Requiring client certificates.");
425 mode = SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
426 }
427
428 SSL_CTX_set_verify(ctx.get(), mode, (mode != SSL_VERIFY_NONE) ? ssl_verify_cb : nullptr);
429}
430
431void
433{
434 debugs(83, DBG_PARSE_NOTE(3), "Not requiring any client certificates");
435 SSL_CTX_set_verify(ctx.get(),SSL_VERIFY_NONE,nullptr);
436}
437
438static int VerifyCtxCertificates(X509_STORE_CTX *ctx, STACK_OF(X509) *extraCerts);
439
440bool
442{
443 const auto peerCertificatesChain = SSL_get_peer_cert_chain(&sconn);
444
445 // TODO: Replace debugs/return false with returning ErrorDetail::Pointer.
446 // Using Security::ErrorDetail terminology, errors in _this_ function are
447 // "non-validation errors", but VerifyCtxCertificates() errors may be
448 // "certificate validation errors". Callers detail SQUID_TLS_ERR_CONNECT.
449 // Some details should be created right here. Others extracted from OpenSSL.
450 // Why not throw? Most of the reasons detailed in the following commit apply
451 // here as well: https://github.com/measurement-factory/squid/commit/e862d33
452
453 if (!peerCertificatesChain || sk_X509_num(peerCertificatesChain) == 0) {
454 debugs(83, 2, "no server certificates");
455 return false;
456 }
457
458 const auto verificationStore = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(&sconn));
459 if (!verificationStore) {
460 debugs(83, 2, "no certificate store");
461 return false;
462 }
463
464 const X509_STORE_CTX_Pointer storeCtx(X509_STORE_CTX_new());
465 if (!storeCtx) {
466 debugs(83, 2, "cannot create X509_STORE_CTX; likely OOM");
467 return false;
468 }
469
470 const auto peerCert = sk_X509_value(peerCertificatesChain, 0);
471 if (!X509_STORE_CTX_init(storeCtx.get(), verificationStore, peerCert, peerCertificatesChain)) {
472 debugs(83, 2, "cannot initialize X509_STORE_CTX");
473 return false;
474 }
475
476#if defined(SSL_CERT_FLAG_SUITEB_128_LOS)
477 // overwrite context Suite B (RFC 5759) flags with connection non-defaults
478 // SSL_set_cert_flags() return type is long, but its implementation actually
479 // returns an unsigned long flags value expected by X509_STORE_CTX_set_flags
480 const unsigned long certFlags = SSL_set_cert_flags(&sconn, 0);
481 if (const auto suiteBflags = certFlags & SSL_CERT_FLAG_SUITEB_128_LOS)
482 X509_STORE_CTX_set_flags(storeCtx.get(), suiteBflags);
483#endif
484
485 if (!X509_STORE_CTX_set_ex_data(storeCtx.get(), SSL_get_ex_data_X509_STORE_CTX_idx(), &sconn)) {
486 debugs(83, 2, "cannot attach SSL object to X509_STORE_CTX");
487 return false;
488 }
489
490 // If we ever add DANE support to Squid, we will supply DANE details here:
491 // X509_STORE_CTX_set0_dane(storeCtx.get(), SSL_get0_dane(&sconn));
492
493 // tell OpenSSL we are verifying a server certificate
494 if (!X509_STORE_CTX_set_default(storeCtx.get(), "ssl_server")) {
495 debugs(83, 2, "cannot set default verification method to ssl_server");
496 return false;
497 }
498
499 // overwrite context "verification parameters" with connection non-defaults
500 const auto param = X509_STORE_CTX_get0_param(storeCtx.get());
501 if (!param) {
502 debugs(83, 2, "no context verification parameters");
503 return false;
504 }
505#if defined(HAVE_X509_VERIFY_PARAM_SET_AUTH_LEVEL)
506 X509_VERIFY_PARAM_set_auth_level(param, SSL_get_security_level(&sconn));
507#endif
508 if (!X509_VERIFY_PARAM_set1(param, SSL_get0_param(&sconn))) {
509 debugs(83, 2, "cannot overwrite context verification parameters");
510 return false;
511 }
512
513 // copy any connection "verify_callback function" to the validation context
514 // (\ref OpenSSL_vcb_disambiguation)
515 if (const auto cb = SSL_get_verify_callback(&sconn))
516 X509_STORE_CTX_set_verify_cb(storeCtx.get(), cb);
517
518 // verify the server certificate chain in the prepared validation context
519 if (VerifyCtxCertificates(storeCtx.get(), extraCerts.get()) <= 0) {
520 // see also: ssl_verify_cb() details errors via ssl_ex_index_ssl_errors
521 const auto verifyResult = X509_STORE_CTX_get_error(storeCtx.get());
522 debugs(83, 3, "verification failure: " << verifyResult << ' ' << X509_verify_cert_error_string(verifyResult));
523 return false;
524 }
525
526 debugs(83, 7, "success");
527 return true;
528}
529
530/* Ssl::VerifyCallbackParameters */
531
534{
535 return static_cast<VerifyCallbackParameters*>(SSL_get_ex_data(&sconn, ssl_ex_index_verify_callback_parameters));
536}
537
540{
541 Must(!Find(sconn));
542 const auto parameters = new VerifyCallbackParameters();
543 if (!SSL_set_ex_data(&sconn, ssl_ex_index_verify_callback_parameters, parameters)) {
544 delete parameters;
545 throw TextException("SSL_set_ex_data() failed; likely OOM", Here());
546 }
547 return parameters;
548}
549
552{
553 const auto parameters = Find(sconn);
554 Must(parameters);
555 return *parameters;
556}
557
558// "dup" function for SSL_get_ex_new_index("cert_err_check")
559#if OPENSSL_VERSION_MAJOR >= 3
560static int
561ssl_dupAclChecklist(CRYPTO_EX_DATA *, const CRYPTO_EX_DATA *, void **,
562 int, long, void *)
563#elif SQUID_USE_CONST_CRYPTO_EX_DATA_DUP
564static int
565ssl_dupAclChecklist(CRYPTO_EX_DATA *, const CRYPTO_EX_DATA *, void *,
566 int, long, void *)
567#else
568static int
569ssl_dupAclChecklist(CRYPTO_EX_DATA *, CRYPTO_EX_DATA *, void *,
570 int, long, void *)
571#endif
572{
573 // We do not support duplication of ACLCheckLists.
574 // If duplication is needed, we can count copies with cbdata.
575 assert(false);
576 return 0;
577}
578
579// "free" function for SSL_get_ex_new_index("cert_err_check")
580static void
581ssl_freeAclChecklist(void *, void *ptr, CRYPTO_EX_DATA *,
582 int, long, void *)
583{
584 delete static_cast<ACLChecklist *>(ptr); // may be NULL
585}
586
587// "free" function for SSL_get_ex_new_index("ssl_error_detail")
588static void
589ssl_free_ErrorDetail(void *, void *ptr, CRYPTO_EX_DATA *,
590 int, long, void *)
591{
592 const auto errDetail = static_cast<Security::ErrorDetail::Pointer*>(ptr);
593 delete errDetail;
594}
595
596static void
597ssl_free_SslErrors(void *, void *ptr, CRYPTO_EX_DATA *,
598 int, long, void *)
599{
600 Security::CertErrors *errs = static_cast <Security::CertErrors*>(ptr);
601 delete errs;
602}
603
604// "free" function for SSL_get_ex_new_index("ssl_ex_index_ssl_validation_counter")
605static void
606ssl_free_int(void *, void *ptr, CRYPTO_EX_DATA *,
607 int, long, void *)
608{
609 uint32_t *counter = static_cast <uint32_t *>(ptr);
610 delete counter;
611}
612
616static void
617ssl_free_CertChain(void *, void *ptr, CRYPTO_EX_DATA *,
618 int, long, void *)
619{
620 STACK_OF(X509) *certsChain = static_cast <STACK_OF(X509) *>(ptr);
621 sk_X509_pop_free(certsChain,X509_free);
622}
623
624// "free" function for X509 certificates
625static void
626ssl_free_X509(void *, void *ptr, CRYPTO_EX_DATA *,
627 int, long, void *)
628{
629 X509 *cert = static_cast <X509 *>(ptr);
630 X509_free(cert);
631}
632
633// "free" function for SBuf
634static void
635ssl_free_SBuf(void *, void *ptr, CRYPTO_EX_DATA *,
636 int, long, void *)
637{
638 SBuf *buf = static_cast <SBuf *>(ptr);
639 delete buf;
640}
641
643static void
644ssl_free_VerifyCallbackParameters(void *, void *ptr, CRYPTO_EX_DATA *,
645 int, long, void *)
646{
647 delete static_cast<Ssl::VerifyCallbackParameters*>(ptr);
648}
649
650void
652{
653 static bool initialized = false;
654 if (initialized)
655 return;
656 initialized = true;
657
659
660 if (::Config.SSL.ssl_engine) {
661#if OPENSSL_VERSION_MAJOR < 3
662 debugs(83, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: Support for ssl_engine is deprecated " <<
663 "in Squids built with OpenSSL 1.x (like this Squid). " <<
664 "It is removed in Squids built with OpenSSL 3.0 or newer.");
665#if !defined(OPENSSL_NO_ENGINE)
666 ENGINE_load_builtin_engines();
667 ENGINE *e;
668 if (!(e = ENGINE_by_id(::Config.SSL.ssl_engine)))
669 fatalf("Unable to find SSL engine '%s'\n", ::Config.SSL.ssl_engine);
670
671 if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
672 const auto ssl_error = ERR_get_error();
673 fatalf("Failed to initialise SSL engine: %s\n", Security::ErrorString(ssl_error));
674 }
675#else /* OPENSSL_NO_ENGINE */
676 throw TextException("Cannot use ssl_engine in Squid built with OpenSSL configured to disable SSL engine support", Here());
677#endif
678
679#else /* OPENSSL_VERSION_MAJOR */
680 throw TextException("Cannot use ssl_engine in Squid built with OpenSSL 3.0 or newer", Here());
681#endif
682 }
683
685 Ssl::DefaultSignHash = EVP_get_digestbyname(defName);
687 fatalf("Sign hash '%s' is not supported\n", defName);
688
689 ssl_ex_index_server = SSL_get_ex_new_index(0, (void *) "server", nullptr, nullptr, ssl_free_SBuf);
690 ssl_ctx_ex_index_dont_verify_domain = SSL_CTX_get_ex_new_index(0, (void *) "dont_verify_domain", nullptr, nullptr, nullptr);
691 ssl_ex_index_cert_error_check = SSL_get_ex_new_index(0, (void *) "cert_error_check", nullptr, &ssl_dupAclChecklist, &ssl_freeAclChecklist);
692 ssl_ex_index_ssl_error_detail = SSL_get_ex_new_index(0, (void *) "ssl_error_detail", nullptr, nullptr, &ssl_free_ErrorDetail);
693 ssl_ex_index_ssl_peeked_cert = SSL_get_ex_new_index(0, (void *) "ssl_peeked_cert", nullptr, nullptr, &ssl_free_X509);
694 ssl_ex_index_ssl_errors = SSL_get_ex_new_index(0, (void *) "ssl_errors", nullptr, nullptr, &ssl_free_SslErrors);
695 ssl_ex_index_ssl_cert_chain = SSL_get_ex_new_index(0, (void *) "ssl_cert_chain", nullptr, nullptr, &ssl_free_CertChain);
696 ssl_ex_index_ssl_validation_counter = SSL_get_ex_new_index(0, (void *) "ssl_validation_counter", nullptr, nullptr, &ssl_free_int);
697 ssl_ex_index_verify_callback_parameters = SSL_get_ex_new_index(0, (void *) "verify_callback_parameters", nullptr, nullptr, &ssl_free_VerifyCallbackParameters);
698}
699
700bool
702{
703 if (!ctx)
704 return false;
705
706 return true;
707}
708
709bool
711{
712 if (!ctx)
713 return false;
714
715 if (!peer.sslCipher.isEmpty()) {
716 debugs(83, 5, "Using chiper suite " << peer.sslCipher << ".");
717
718 const char *cipher = peer.sslCipher.c_str();
719 if (!SSL_CTX_set_cipher_list(ctx.get(), cipher)) {
720 const auto ssl_error = ERR_get_error();
721 fatalf("Failed to set SSL cipher suite '%s': %s\n",
722 cipher, Security::ErrorString(ssl_error));
723 }
724 }
725
726 if (!peer.certs.empty()) {
727 // TODO: support loading multiple cert/key pairs
728 auto &keys = peer.certs.front();
729 if (!keys.certFile.isEmpty()) {
730 debugs(83, 2, "loading client certificate from " << keys.certFile);
731
732 const char *certfile = keys.certFile.c_str();
733 if (!SSL_CTX_use_certificate_chain_file(ctx.get(), certfile)) {
734 const auto ssl_error = ERR_get_error();
735 fatalf("Failed to acquire SSL certificate '%s': %s\n",
736 certfile, Security::ErrorString(ssl_error));
737 }
738
739 debugs(83, 2, "loading private key from " << keys.privateKeyFile);
740 const char *keyfile = keys.privateKeyFile.c_str();
741 ssl_ask_password(ctx.get(), keyfile);
742
743 if (!SSL_CTX_use_PrivateKey_file(ctx.get(), keyfile, SSL_FILETYPE_PEM)) {
744 const auto ssl_error = ERR_get_error();
745 fatalf("Failed to acquire SSL private key '%s': %s\n",
746 keyfile, Security::ErrorString(ssl_error));
747 }
748
749 debugs(83, 5, "Comparing private and public SSL keys.");
750
751 if (!SSL_CTX_check_private_key(ctx.get())) {
752 const auto ssl_error = ERR_get_error();
753 fatalf("SSL private key '%s' does not match public key '%s': %s\n",
754 certfile, keyfile, Security::ErrorString(ssl_error));
755 }
756 }
757 }
758
760
762
763 return true;
764}
765
767static const char *
768ssl_get_attribute(X509_NAME * name, const char *attribute_name)
769{
770 static char buffer[1024];
771 buffer[0] = '\0';
772
773 if (strcmp(attribute_name, "DN") == 0) {
774 X509_NAME_oneline(name, buffer, sizeof(buffer));
775 } else {
776 int nid = OBJ_txt2nid(const_cast<char *>(attribute_name));
777 if (nid == 0) {
778 debugs(83, DBG_IMPORTANT, "WARNING: Unknown SSL attribute name '" << attribute_name << "'");
779 return nullptr;
780 }
781 X509_NAME_get_text_by_NID(name, nid, buffer, sizeof(buffer));
782 }
783
784 return *buffer ? buffer : nullptr;
785}
786
788const char *
789Ssl::GetX509UserAttribute(X509 * cert, const char *attribute_name)
790{
791 X509_NAME *name;
792 const char *ret;
793
794 if (!cert)
795 return nullptr;
796
797 name = X509_get_subject_name(cert);
798
799 ret = ssl_get_attribute(name, attribute_name);
800
801 return ret;
802}
803
804const char *
805Ssl::GetX509Fingerprint(X509 * cert, const char *)
806{
807 static char buf[1024];
808 if (!cert)
809 return nullptr;
810
811 unsigned int n;
812 unsigned char md[EVP_MAX_MD_SIZE];
813 if (!X509_digest(cert, EVP_sha1(), md, &n))
814 return nullptr;
815
816 assert(3 * n + 1 < sizeof(buf));
817
818 char *s = buf;
819 for (unsigned int i=0; i < n; ++i, s += 3) {
820 const char term = (i + 1 < n) ? ':' : '\0';
821 snprintf(s, 4, "%02X%c", md[i], term);
822 }
823
824 return buf;
825}
826
827SBuf
828Ssl::GetX509PEM(X509 * cert)
829{
830 assert(cert);
831
832 Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
833 PEM_write_bio_X509(bio.get(), cert);
834
835 char *ptr;
836 const auto len = BIO_get_mem_data(bio.get(), &ptr);
837 return SBuf(ptr, len);
838}
839
841const char *
842Ssl::GetX509CAAttribute(X509 * cert, const char *attribute_name)
843{
844
845 X509_NAME *name;
846 const char *ret;
847
848 if (!cert)
849 return nullptr;
850
851 name = X509_get_issuer_name(cert);
852
853 ret = ssl_get_attribute(name, attribute_name);
854
855 return ret;
856}
857
858const char *sslGetUserAttribute(SSL *ssl, const char *attribute_name)
859{
860 if (!ssl)
861 return nullptr;
862
863 X509 *cert = SSL_get_peer_certificate(ssl);
864
865 const char *attr = Ssl::GetX509UserAttribute(cert, attribute_name);
866
867 X509_free(cert);
868 return attr;
869}
870
871const char *sslGetCAAttribute(SSL *ssl, const char *attribute_name)
872{
873 if (!ssl)
874 return nullptr;
875
876 X509 *cert = SSL_get_peer_certificate(ssl);
877
878 const char *attr = Ssl::GetX509CAAttribute(cert, attribute_name);
879
880 X509_free(cert);
881 return attr;
882}
883
884const char *
886{
887 return sslGetUserAttribute(ssl, "emailAddress");
888}
889
890SBuf
892{
893 assert(ssl);
894
895 if (const auto cert = SSL_get_peer_certificate(ssl))
896 return Ssl::GetX509PEM(cert);
897
898 return SBuf();
899}
900
901SBuf
903{
904 assert(ssl);
905
906 auto chain = SSL_get_peer_cert_chain(ssl);
907
908 if (!chain)
909 return sslGetUserCertificatePEM(ssl);
910
911 Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
912
913 for (int i = 0; i < sk_X509_num(chain); ++i) {
914 X509 *cert = sk_X509_value(chain, i);
915 PEM_write_bio_X509(bio.get(), cert);
916 }
917
918 char *ptr;
919 const auto len = BIO_get_mem_data(bio.get(), &ptr);
920 return SBuf(ptr, len);
921}
922
925Ssl::createSSLContext(Security::CertPointer & x509, Security::PrivateKeyPointer & pkey, Security::ServerOptions &options)
926{
928
929 if (!SSL_CTX_use_certificate(ctx.get(), x509.get()))
931
932 if (!SSL_CTX_use_PrivateKey(ctx.get(), pkey.get()))
934
935 if (!options.updateContextConfig(ctx))
937
938 return ctx;
939}
940
943{
945 Security::PrivateKeyPointer pkey;
946 if (!readCertAndPrivateKeyFromMemory(cert, pkey, data) || !cert || !pkey)
948
949 Security::ContextPointer ctx(createSSLContext(cert, pkey, options));
950 if (ctx && trusted)
952 return ctx;
953}
954
957{
959 Security::PrivateKeyPointer pkey;
960 if (!generateSslCertificate(cert, pkey, properties) || !cert || !pkey)
962
963 Security::ContextPointer ctx(createSSLContext(cert, pkey, options));
964 if (ctx && trusted)
966 return ctx;
967}
968
969void
971{
972 assert(ctx);
973 // Add signing certificate to the certificates chain
974 X509 *signingCert = options.signingCa.cert.get();
975 if (SSL_CTX_add_extra_chain_cert(ctx.get(), signingCert)) {
976 // increase the certificate lock
977 X509_up_ref(signingCert);
978 } else {
979 const auto ssl_error = ERR_get_error();
980 debugs(33, DBG_IMPORTANT, "WARNING: can not add signing certificate to SSL context chain: " << Security::ErrorString(ssl_error));
981 }
982
983 for (auto cert : options.signingCa.chain) {
984 if (SSL_CTX_add_extra_chain_cert(ctx.get(), cert.get())) {
985 // increase the certificate lock
986 X509_up_ref(cert.get());
987 } else {
988 const auto error = ERR_get_error();
989 debugs(83, DBG_IMPORTANT, "WARNING: can not add certificate to SSL dynamic context chain: " << Security::ErrorString(error));
990 }
991 }
992}
993
994void
996{
997 if (ctx && signAlgorithm == Ssl::algSignTrusted)
999}
1000
1001bool
1003{
1005 Security::PrivateKeyPointer pkey;
1006 if (!generateSslCertificate(cert, pkey, properties))
1007 return false;
1008
1009 if (!cert)
1010 return false;
1011
1012 if (!pkey)
1013 return false;
1014
1015 if (!SSL_use_certificate(ssl, cert.get()))
1016 return false;
1017
1018 if (!SSL_use_PrivateKey(ssl, pkey.get()))
1019 return false;
1020
1021 return true;
1022}
1023
1024bool
1026{
1028 Security::PrivateKeyPointer pkey;
1029 if (!readCertAndPrivateKeyFromMemory(cert, pkey, data))
1030 return false;
1031
1032 if (!cert || !pkey)
1033 return false;
1034
1035 if (!SSL_use_certificate(ssl, cert.get()))
1036 return false;
1037
1038 if (!SSL_use_PrivateKey(ssl, pkey.get()))
1039 return false;
1040
1041 return true;
1042}
1043
1044bool
1046{
1047#if HAVE_SSL_CTX_GET0_CERTIFICATE
1048 X509 * cert = SSL_CTX_get0_certificate(ctx.get());
1049#elif SQUID_USE_SSLGETCERTIFICATE_HACK
1050 // SSL_get_certificate is buggy in openssl versions 1.0.1d and 1.0.1e
1051 // Try to retrieve certificate directly from Security::ContextPointer object
1052 X509 ***pCert = (X509 ***)ctx->cert;
1053 X509 * cert = pCert && *pCert ? **pCert : NULL;
1054#elif SQUID_SSLGETCERTIFICATE_BUGGY
1055 X509 * cert = nullptr;
1056 assert(0);
1057#else
1058 // Temporary ssl for getting X509 certificate from SSL_CTX.
1060 X509 * cert = SSL_get_certificate(ssl.get());
1061#endif
1062 if (!cert)
1063 return false;
1064 const auto time_notBefore = X509_getm_notBefore(cert);
1065 const auto time_notAfter = X509_getm_notAfter(cert);
1066 return (X509_cmp_current_time(time_notBefore) < 0 && X509_cmp_current_time(time_notAfter) > 0);
1067}
1068
1069void
1070Ssl::setClientSNI(SSL *ssl, const char *fqdn)
1071{
1072 const Ip::Address test(fqdn);
1073 if (!test.isAnyAddr())
1074 return; // raw IP is inappropriate for SNI
1075
1076 //The SSL_CTRL_SET_TLSEXT_HOSTNAME is a openssl macro which indicates
1077 // if the TLS servername extension (SNI) is enabled in openssl library.
1078#if defined(SSL_CTRL_SET_TLSEXT_HOSTNAME)
1079 if (!SSL_set_tlsext_host_name(ssl, fqdn)) {
1080 const auto ssl_error = ERR_get_error();
1081 debugs(83, 3, "WARNING: unable to set TLS servername extension (SNI): " <<
1082 Security::ErrorString(ssl_error) << "\n");
1083 }
1084#else
1085 debugs(83, 7, "no support for TLS servername extension (SNI)");
1086#endif
1087}
1088
1089const char *
1091{
1092 AUTHORITY_INFO_ACCESS *info;
1093 if (!cert)
1094 return nullptr;
1095 info = static_cast<AUTHORITY_INFO_ACCESS *>(X509_get_ext_d2i(cert, NID_info_access, nullptr, nullptr));
1096 if (!info)
1097 return nullptr;
1098
1099 static char uri[MAX_URL];
1100 uri[0] = '\0';
1101
1102 for (int i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++) {
1103 ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(info, i);
1104 if (OBJ_obj2nid(ad->method) == NID_ad_ca_issuers) {
1105 if (ad->location->type == GEN_URI) {
1106 xstrncpy(uri,
1107 reinterpret_cast<const char *>(
1108 ASN1_STRING_get0_data(ad->location->d.uniformResourceIdentifier)
1109 ),
1110 sizeof(uri));
1111 }
1112 break;
1113 }
1114 }
1115 AUTHORITY_INFO_ACCESS_free(info);
1116 return uri[0] != '\0' ? uri : nullptr;
1117}
1118
1119bool
1120Ssl::loadCerts(const char *certsFile, Ssl::CertsIndexedList &list)
1121{
1122 const BIO_Pointer in(BIO_new_file(certsFile, "r"));
1123 if (!in) {
1124 debugs(83, DBG_IMPORTANT, "ERROR: Failed to open '" << certsFile << "' to load certificates");
1125 return false;
1126 }
1127
1128 while (auto aCert = ReadOptionalCertificate(in)) {
1129 const auto name = Security::SubjectName(*aCert);
1130 list.insert(std::pair<SBuf, X509 *>(name, aCert.release()));
1131 }
1132 debugs(83, 4, "Loaded " << list.size() << " certificates from file: '" << certsFile << "'");
1133 return true;
1134}
1135
1138static X509 *
1140{
1141 const auto name = Security::IssuerName(*cert);
1142 if (name.isEmpty())
1143 return nullptr;
1144
1145 const auto ret = list.equal_range(name);
1146 for (Ssl::CertsIndexedList::iterator it = ret.first; it != ret.second; ++it) {
1147 X509 *issuer = it->second;
1148 if (Security::IssuedBy(*cert, *issuer)) {
1149 return issuer;
1150 }
1151 }
1152 return nullptr;
1153}
1154
1156static X509 *
1157sk_x509_findIssuer(const STACK_OF(X509) *sk, X509 *cert)
1158{
1159 if (!sk)
1160 return nullptr;
1161
1162 const auto certCount = sk_X509_num(sk);
1163 for (int i = 0; i < certCount; ++i) {
1164 const auto issuer = sk_X509_value(sk, i);
1165 if (Security::IssuedBy(*cert, *issuer))
1166 return issuer;
1167 }
1168 return nullptr;
1169}
1170
1173static X509 *
1174findIssuerInCaDb(X509 *cert, const Security::ContextPointer &connContext)
1175{
1176 if (!connContext)
1177 return nullptr;
1178
1179 X509_STORE_CTX *storeCtx = X509_STORE_CTX_new();
1180 if (!storeCtx) {
1181 debugs(83, DBG_IMPORTANT, "ERROR: Failed to allocate STORE_CTX object");
1182 return nullptr;
1183 }
1184
1185 X509 *issuer = nullptr;
1186 X509_STORE *store = SSL_CTX_get_cert_store(connContext.get());
1187 if (X509_STORE_CTX_init(storeCtx, store, nullptr, nullptr)) {
1188 const auto ret = X509_STORE_CTX_get1_issuer(&issuer, storeCtx, cert);
1189 if (ret > 0) {
1190 assert(issuer);
1191 debugs(83, 5, "found " << *issuer);
1192 } else {
1193 debugs(83, ret < 0 ? 2 : 3, "not found or failure: " << ret);
1194 assert(!issuer);
1195 }
1196 } else {
1197 const auto ssl_error = ERR_get_error();
1198 debugs(83, DBG_IMPORTANT, "ERROR: Failed to initialize STORE_CTX object: " << Security::ErrorString(ssl_error));
1199 }
1200
1201 X509_STORE_CTX_free(storeCtx);
1202
1203 return issuer;
1204}
1205
1207Ssl::findIssuerCertificate(X509 *cert, const STACK_OF(X509) *serverCertificates, const Security::ContextPointer &context)
1208{
1209 Must(cert);
1210
1211 // check certificate chain, if any
1212 if (const auto issuer = serverCertificates ? sk_x509_findIssuer(serverCertificates, cert) : nullptr) {
1213 X509_up_ref(issuer);
1214 return Security::CertPointer(issuer);
1215 }
1216
1217 // check untrusted certificates
1218 if (const auto issuer = findCertIssuerFast(SquidUntrustedCerts, cert)) {
1219 X509_up_ref(issuer);
1220 return Security::CertPointer(issuer);
1221 }
1222
1223 // check trusted CA certificates
1224 if (const auto issuer = findIssuerInCaDb(cert, context)) {
1225 // no X509_up_ref(issuer) because findIssuerInCaDb() ups reference count
1226 return Security::CertPointer(issuer);
1227 }
1228
1229 return Security::CertPointer(nullptr);
1230}
1231
1232bool
1233Ssl::missingChainCertificatesUrls(std::queue<SBuf> &URIs, const STACK_OF(X509) &serverCertificates, const Security::ContextPointer &context)
1234{
1235 for (int i = 0; i < sk_X509_num(&serverCertificates); ++i) {
1236 const auto cert = sk_X509_value(&serverCertificates, i);
1237
1238 if (findIssuerCertificate(cert, &serverCertificates, context))
1239 continue;
1240
1241 if (const auto issuerUri = findIssuerUri(cert)) {
1242 URIs.push(SBuf(issuerUri));
1243 } else {
1244 debugs(83, 3, "Issuer certificate for " <<
1245 *cert <<
1246 " is missing and its URI is not provided");
1247 }
1248 }
1249
1250 debugs(83, (URIs.empty() ? 3 : 5), "found: " << URIs.size());
1251 return !URIs.empty();
1252}
1253
1255static void
1256completeIssuers(X509_STORE_CTX *ctx, STACK_OF(X509) &untrustedCerts)
1257{
1258 debugs(83, 2, "completing " << sk_X509_num(&untrustedCerts) <<
1259 " OpenSSL untrusted certs using " << SquidUntrustedCerts.size() <<
1260 " configured untrusted certificates");
1261
1262 const X509_VERIFY_PARAM *param = X509_STORE_CTX_get0_param(ctx);
1263 int depth = X509_VERIFY_PARAM_get_depth(param);
1264 Security::CertPointer current;
1266 int i = 0;
1267 for (i = 0; current && (i < depth); ++i) {
1268 if (Security::SelfSigned(*current)) {
1269 // either ctx->cert is itself self-signed or untrustedCerts
1270 // already contain the self-signed current certificate
1271 break;
1272 }
1273
1274 // untrustedCerts is short, not worth indexing
1275 const Security::ContextPointer nullCtx;
1276 auto issuer = Ssl::findIssuerCertificate(current.get(), &untrustedCerts, nullCtx);
1277 current = issuer;
1278 if (issuer)
1279 sk_X509_push(&untrustedCerts, issuer.release());
1280 }
1281
1282 if (i >= depth)
1283 debugs(83, 2, "exceeded the maximum certificate chain length: " << depth);
1284}
1285
1289static int
1290VerifyCtxCertificates(X509_STORE_CTX *ctx, STACK_OF(X509) *extraCerts)
1291{
1292 // OpenSSL already maintains ctx->untrusted but we cannot modify
1293 // internal OpenSSL list directly. We have to give OpenSSL our own
1294 // list, but it must include certificates on the OpenSSL ctx->untrusted
1295 STACK_OF(X509) *oldUntrusted = X509_STORE_CTX_get0_untrusted(ctx);
1296 // X509_chain_up_ref() increments cert references _and_ dupes the stack
1297 Ssl::X509_STACK_Pointer untrustedCerts(oldUntrusted ? X509_chain_up_ref(oldUntrusted) : sk_X509_new_null());
1298
1299 if (extraCerts) {
1300 for (int i = 0; i < sk_X509_num(extraCerts); ++i) {
1301 const auto cert = sk_X509_value(extraCerts, i);
1302 X509_up_ref(cert);
1303 sk_X509_push(untrustedCerts.get(), cert);
1304 }
1305 }
1306
1307 // If the local untrusted certificates internal database is used
1308 // run completeIssuers to add missing certificates if possible.
1309 if (SquidUntrustedCerts.size() > 0)
1310 completeIssuers(ctx, *untrustedCerts);
1311
1312 X509_STORE_CTX_set0_untrusted(ctx, untrustedCerts.get()); // No locking/unlocking, just sets ctx->untrusted
1313 int ret = X509_verify_cert(ctx);
1314 X509_STORE_CTX_set0_untrusted(ctx, oldUntrusted); // Set back the old untrusted list
1315 return ret;
1316}
1317
1333
1337static int
1338untrustedToStoreCtx_cb(X509_STORE_CTX *ctx, void *)
1339{
1340 debugs(83, 4, "Try to use pre-downloaded intermediate certificates");
1341 return VerifyCtxCertificates(ctx, nullptr);
1342}
1343
1344void
1345Ssl::useSquidUntrusted(SSL_CTX *sslContext)
1346{
1347 SSL_CTX_set_cert_verify_callback(sslContext, untrustedToStoreCtx_cb, nullptr);
1348}
1349
1350bool
1352{
1353 return Ssl::loadCerts(path, SquidUntrustedCerts);
1354}
1355
1356void
1358{
1359 if (SquidUntrustedCerts.size()) {
1360 for (Ssl::CertsIndexedList::iterator it = SquidUntrustedCerts.begin(); it != SquidUntrustedCerts.end(); ++it) {
1361 X509_free(it->second);
1362 }
1363 SquidUntrustedCerts.clear();
1364 }
1365}
1366
1367bool Ssl::generateUntrustedCert(Security::CertPointer &untrustedCert, Security::PrivateKeyPointer &untrustedPkey, Security::CertPointer const &cert, Security::PrivateKeyPointer const & pkey)
1368{
1369 // Generate the self-signed certificate, using a hard-coded subject prefix
1370 Ssl::CertificateProperties certProperties;
1371 if (const char *cn = CommonHostName(cert.get())) {
1372 certProperties.commonName = "Not trusted by \"";
1373 certProperties.commonName += cn;
1374 certProperties.commonName += "\"";
1375 } else if (const char *org = getOrganization(cert.get())) {
1376 certProperties.commonName = "Not trusted by \"";
1377 certProperties.commonName += org;
1378 certProperties.commonName += "\"";
1379 } else
1380 certProperties.commonName = "Not trusted";
1381 certProperties.setCommonName = true;
1382 // O, OU, and other CA subject fields will be mimicked
1383 // Expiration date and other common properties will be mimicked
1384 certProperties.signAlgorithm = Ssl::algSignSelf;
1385 certProperties.signWithPkey.resetAndLock(pkey.get());
1386 certProperties.mimicCert.resetAndLock(cert.get());
1387 return Ssl::generateSslCertificate(untrustedCert, untrustedPkey, certProperties);
1388}
1389
1391{
1392 bool origSignatureAsKey = false;
1393 if (certProperties.mimicCert) {
1394 if (auto *sig = Ssl::X509_get_signature(certProperties.mimicCert)) {
1395 origSignatureAsKey = true;
1396 key.append((const char *)sig->data, sig->length);
1397 }
1398 }
1399
1400 if (!origSignatureAsKey || certProperties.setCommonName) {
1401 // Use common name instead
1402 key.append(certProperties.commonName.c_str());
1403 }
1404 key.append(certProperties.setCommonName ? '1' : '0');
1405 key.append(certProperties.setValidAfter ? '1' : '0');
1406 key.append(certProperties.setValidBefore ? '1' : '0');
1407 key.append(certProperties.signAlgorithm != Ssl:: algSignEnd ? certSignAlgorithm(certProperties.signAlgorithm) : "-");
1408 key.append(certProperties.signHash ? EVP_MD_name(certProperties.signHash) : "-");
1409
1410 if (certProperties.mimicCert) {
1411 Ssl::BIO_Pointer bio(BIO_new_SBuf(&key));
1412 ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509), bio.get(), (ASN1_VALUE *)certProperties.mimicCert.get());
1413 }
1414}
1415
1416static int
1418{
1419 BIO_set_init(bio, 0);
1420 BIO_set_data(bio, nullptr);
1421 return 1;
1422}
1423
1424static int
1426{
1427 if (!bio)
1428 return 0;
1429 return 1;
1430}
1431
1432static int
1433bio_sbuf_write(BIO* bio, const char* data, int len)
1434{
1435 SBuf *buf = static_cast<SBuf *>(BIO_get_data(bio));
1436 // TODO: Convert exceptions into BIO errors
1437 buf->append(data, len);
1438 return len;
1439}
1440
1441static int
1442bio_sbuf_puts(BIO *bio, const char *data)
1443{
1444 // TODO: use bio_sbuf_write() instead
1445 SBuf *buf = static_cast<SBuf *>(BIO_get_data(bio));
1446 size_t oldLen = buf->length();
1447 buf->append(data);
1448 return buf->length() - oldLen;
1449}
1450
1451static long
1452bio_sbuf_ctrl(BIO *bio, int cmd, long /* num */, void *)
1453{
1454 SBuf *buf = static_cast<SBuf *>(BIO_get_data(bio));
1455 switch (cmd) {
1456 case BIO_CTRL_RESET:
1457 // TODO: Convert exceptions into BIO errors
1458 buf->clear();
1459 return 1;
1460 case BIO_CTRL_FLUSH:
1461 return 1;
1462 default:
1463 return 0;
1464 }
1465}
1466
1468{
1469#if HAVE_LIBCRYPTO_BIO_METH_NEW
1470 static BIO_METHOD *BioSBufMethods = nullptr;
1471 if (!BioSBufMethods) {
1472 BioSBufMethods = BIO_meth_new(BIO_TYPE_MEM, "Squid-SBuf");
1473 BIO_meth_set_write(BioSBufMethods, bio_sbuf_write);
1474 BIO_meth_set_read(BioSBufMethods, nullptr);
1475 BIO_meth_set_puts(BioSBufMethods, bio_sbuf_puts);
1476 BIO_meth_set_gets(BioSBufMethods, nullptr);
1477 BIO_meth_set_ctrl(BioSBufMethods, bio_sbuf_ctrl);
1478 BIO_meth_set_create(BioSBufMethods, bio_sbuf_create);
1479 BIO_meth_set_destroy(BioSBufMethods, bio_sbuf_destroy);
1480 }
1481#else
1482 static BIO_METHOD *BioSBufMethods = new BIO_METHOD({
1483 BIO_TYPE_MEM,
1484 "Squid SBuf",
1486 nullptr,
1488 nullptr,
1492 NULL
1493 });
1494#endif
1495 BIO *bio = BIO_new(BioSBufMethods);
1496 Must(bio);
1497 BIO_set_data(bio, buf);
1498 BIO_set_init(bio, 1);
1499 return bio;
1500}
1501
1502#endif /* USE_OPENSSL */
1503
ACLFilledChecklist * Filled(ACLChecklist *checklist)
convenience and safety wrapper for dynamic_cast<ACLFilledChecklist*>
#define Here()
source code location of the caller
Definition: Here.h:15
int size
Definition: ModDevPoll.cc:75
class SquidConfig Config
Definition: SquidConfig.cc:12
#define Must(condition)
Definition: TextException.h:75
int matchDomainName(const char *h, const char *d, MatchDomainNameFlags flags)
Definition: Uri.cc:820
@ mdnRejectSubsubDomains
Definition: Uri.h:231
static char * keys[]
Definition: WinSvc.cc:84
void error(char *format,...)
#define assert(EX)
Definition: assert.h:17
static char server[MAXLINE]
Acl::Answer const & fastCheck()
Definition: Checklist.cc:332
Security::CertPointer serverCert
CbcPointer< Security::CertErrors > sslErrors
bool allowed() const
Definition: Acl.h:156
bool push_back_unique(C const &element)
Definition: CbDataList.h:87
static bool Enabled(const int section, const int level)
whether debugging the given section and the given level produces output
Definition: Stream.h:75
bool isAnyAddr() const
Definition: Address.cc:170
Definition: SBuf.h:94
const char * c_str()
Definition: SBuf.cc:516
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:415
bool isEmpty() const
Definition: SBuf.h:431
SBuf & append(const SBuf &S)
Definition: SBuf.cc:185
void clear()
Definition: SBuf.cc:175
Security::CertPointer cert
public X.509 certificate from certFile
Definition: KeyData.h:31
Security::CertList chain
any certificates which must be chained from cert
Definition: KeyData.h:35
void reset()
Forget the raw pointer - unlock if any value was set. Become a nil pointer.
T * get() const
Returns raw and possibly nullptr pointer.
TLS squid.conf settings for a remote server peer.
Definition: PeerOptions.h:26
std::list< Security::KeyData > certs
details from the cert= and file= config parameters
Definition: PeerOptions.h:105
TLS squid.conf settings for a listening port.
Definition: ServerOptions.h:26
Security::ContextPointer createBlankContext() const override
generate an unset security context object
bool updateContextConfig(Security::ContextPointer &)
update the given TLS security context using squid.conf settings
Security::KeyData signingCa
x509 certificate and key for signing generated certificates
Definition: ServerOptions.h:87
char * ssl_password
Definition: SquidConfig.h:211
struct SquidConfig::@99 Program
char * certSignHash
Definition: SquidConfig.h:491
struct SquidConfig::@114 SSL
char * ssl_engine
Definition: SquidConfig.h:488
Security::PrivateKeyPointer signWithPkey
The key of the signing certificate.
Definition: gadgets.h:234
bool setCommonName
Replace the CN field of the mimicking subject with the given.
Definition: gadgets.h:237
bool setValidAfter
Do not mimic "Not Valid After" field.
Definition: gadgets.h:235
CertSignAlgorithm signAlgorithm
The signing algorithm to use.
Definition: gadgets.h:239
bool setValidBefore
Do not mimic "Not Valid Before" field.
Definition: gadgets.h:236
Security::CertPointer mimicCert
Certificate to mimic.
Definition: gadgets.h:232
const EVP_MD * signHash
The signing hash to use.
Definition: gadgets.h:240
std::string commonName
A CN to use for the generated certificate.
Definition: gadgets.h:238
static VerifyCallbackParameters & At(Security::Connection &)
Definition: support.cc:551
static VerifyCallbackParameters * New(Security::Connection &)
Definition: support.cc:539
static VerifyCallbackParameters * Find(Security::Connection &)
Definition: support.cc:533
an std::runtime_error with thrower location info
Definition: TextException.h:21
#define DBG_PARSE_NOTE(x)
Definition: Stream.h:42
#define DBG_IMPORTANT
Definition: Stream.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
#define debug_log
change-avoidance macro; new code should call DebugStream() instead
Definition: Stream.h:183
#define MAX_URL
Definition: defines.h:78
static int port
Definition: ldap_backend.cc:70
void fatalf(const char *fmt,...)
Definition: fatal.cc:68
int ssl_ex_index_server
int ssl_ex_index_ssl_peeked_cert
int ssl_ex_index_ssl_error_detail
int ssl_ctx_ex_index_dont_verify_domain
int ssl_ex_index_ssl_errors
int ssl_ex_index_ssl_validation_counter
int ssl_ex_index_ssl_cert_chain
int ssl_ex_index_cert_error_check
void useSquidUntrusted(SSL_CTX *sslContext)
Definition: support.cc:1345
GETX509ATTRIBUTE GetX509UserAttribute
Definition: support.h:109
Security::ContextPointer GenerateSslContext(CertificateProperties const &, Security::ServerOptions &, bool trusted)
Definition: support.cc:956
GETX509PEM GetX509PEM
Definition: support.h:115
std::vector< const char * > BumpModeStr
Definition: support.cc:46
SBuf sslGetUserCertificatePEM(SSL *ssl)
Definition: support.cc:891
bool configureSSL(SSL *ssl, CertificateProperties const &properties, AnyP::PortCfg &port)
Definition: support.cc:1002
bool generateUntrustedCert(Security::CertPointer &untrustedCert, Security::PrivateKeyPointer &untrustedPkey, Security::CertPointer const &cert, Security::PrivateKeyPointer const &pkey)
Definition: support.cc:1367
void chainCertificatesToSSLContext(Security::ContextPointer &, Security::ServerOptions &)
Definition: support.cc:970
void InRamCertificateDbKey(const Ssl::CertificateProperties &certProperties, SBuf &key)
Definition: support.cc:1390
GETX509ATTRIBUTE GetX509CAAttribute
Definition: support.h:112
const char * sslGetUserAttribute(SSL *ssl, const char *attribute_name)
Definition: support.cc:858
BIO * BIO_new_SBuf(SBuf *buf)
Definition: support.cc:1467
Security::ContextPointer createSSLContext(Security::CertPointer &x509, Security::PrivateKeyPointer &pkey, Security::ServerOptions &)
Create SSL context and apply ssl certificate and private key to it.
Definition: support.cc:925
bool verifySslCertificate(const Security::ContextPointer &, CertificateProperties const &)
Definition: support.cc:1045
bool checkX509ServerValidity(X509 *cert, const char *server)
Definition: support.cc:254
bool configureSSLUsingPkeyAndCertFromMemory(SSL *ssl, const char *data, AnyP::PortCfg &port)
Definition: support.cc:1025
bool loadCerts(const char *certsFile, Ssl::CertsIndexedList &list)
Definition: support.cc:1120
int asn1timeToString(ASN1_TIME *tm, char *buf, int len)
Definition: support.cc:181
const char * sslGetCAAttribute(SSL *ssl, const char *attribute_name)
Definition: support.cc:871
Security::ContextPointer GenerateSslContextUsingPkeyAndCertFromMemory(const char *data, Security::ServerOptions &, bool trusted)
Definition: support.cc:942
GETX509ATTRIBUTE GetX509Fingerprint
Definition: support.h:118
SBuf sslGetUserCertificateChainPEM(SSL *ssl)
Definition: support.cc:902
void configureUnconfiguredSslContext(Security::ContextPointer &, Ssl::CertSignAlgorithm signAlgorithm, AnyP::PortCfg &)
Definition: support.cc:995
void setClientSNI(SSL *ssl, const char *fqdn)
Definition: support.cc:1070
const char * getOrganization(X509 *x509)
Definition: gadgets.cc:974
bool loadSquidUntrusted(const char *path)
Definition: support.cc:1351
const char * CommonHostName(X509 *x509)
Definition: gadgets.cc:969
const char * sslGetUserEmail(SSL *ssl)
Definition: support.cc:885
void unloadSquidUntrusted()
Definition: support.cc:1357
int matchX509CommonNames(X509 *peer_cert, void *check_data, int(*check_func)(void *check_data, ASN1_STRING *cn_data))
Definition: support.cc:195
static void ssl_free_CertChain(void *, void *ptr, CRYPTO_EX_DATA *, int, long, void *)
Definition: support.cc:617
static void ssl_ask_password(SSL_CTX *context, const char *prompt)
Definition: support.cc:89
static const char * ssl_get_attribute(X509_NAME *name, const char *attribute_name)
Definition: support.cc:768
bool generateSslCertificate(Security::CertPointer &cert, Security::PrivateKeyPointer &pkey, CertificateProperties const &properties)
Definition: gadgets.cc:711
CertSignAlgorithm
Definition: gadgets.h:166
bool readCertAndPrivateKeyFromMemory(Security::CertPointer &cert, Security::PrivateKeyPointer &pkey, char const *bufferToRead)
Definition: gadgets.cc:145
const char * certSignAlgorithm(int sg)
Definition: gadgets.h:179
@ algSignEnd
Definition: gadgets.h:166
@ algSignTrusted
Definition: gadgets.h:166
@ algSignSelf
Definition: gadgets.h:166
SBuf IssuerName(Certificate &)
The Issuer field of the given certificate (if found) or an empty SBuf.
Definition: Certificate.cc:28
std::shared_ptr< SSL_CTX > ContextPointer
Definition: Context.h:29
SSL Connection
Definition: Session.h:45
int ErrorCode
Squid-defined error code (<0), an error code returned by X.509 API, or zero.
Definition: forward.h:132
Security::SessionPointer NewSessionObject(const Security::ContextPointer &)
Definition: Session.cc:90
std::shared_ptr< SSL > SessionPointer
Definition: Session.h:49
CbDataList< Security::CertError > CertErrors
Holds a list of X.509 certificate errors.
Definition: forward.h:74
Security::LockingPointer< X509, X509_free_cpp, HardFun< int, X509 *, X509_up_ref > > CertPointer
Definition: forward.h:86
long ParsedPortFlags
Definition: forward.h:202
bool SelfSigned(Certificate &c)
Whether the given certificate is self-signed.
Definition: Certificate.h:34
SBuf SubjectName(Certificate &)
The SubjectName field of the given certificate (if found) or an empty SBuf.
Definition: Certificate.cc:68
bool IssuedBy(Certificate &cert, Certificate &issuer)
Definition: Certificate.cc:108
const char * ErrorString(const LibErrorCode code)
converts numeric LibErrorCode into a human-friendlier string
Definition: forward.h:150
void DisablePeerVerification(Security::ContextPointer &)
Definition: support.cc:432
bool InitClientContext(Security::ContextPointer &, Security::PeerOptions &, Security::ParsedPortFlags)
initialize a TLS client context with OpenSSL specific settings
Definition: support.cc:710
std::unique_ptr< BIO, HardFun< void, BIO *, &BIO_vfree > > BIO_Pointer
Definition: gadgets.h:54
bool VerifyConnCertificates(Security::Connection &, const Ssl::X509_STACK_Pointer &extraCerts)
Definition: support.cc:441
std::unique_ptr< X509_STORE_CTX, HardFun< void, X509_STORE_CTX *, &X509_STORE_CTX_free > > X509_STORE_CTX_Pointer
Definition: gadgets.h:77
Security::CertPointer findIssuerCertificate(X509 *cert, const STACK_OF(X509) *serverCertificates, const Security::ContextPointer &context)
Definition: support.cc:1207
bool missingChainCertificatesUrls(std::queue< SBuf > &URIs, const STACK_OF(X509) &serverCertificates, const Security::ContextPointer &context)
Definition: support.cc:1233
Config TheConfig
Definition: Config.cc:12
Security::CertPointer ReadOptionalCertificate(const BIO_Pointer &)
Definition: gadgets.cc:733
const ASN1_BIT_STRING * X509_get_signature(const Security::CertPointer &)
Definition: gadgets.cc:1005
void Initialize()
Definition: support.cc:651
std::optional< SBuf > GetErrorDescr(Security::ErrorCode)
Definition: ErrorDetail.cc:159
const EVP_MD * DefaultSignHash
Definition: support.cc:44
int AskPasswordCb(char *buf, int size, int rwflag, void *userdata)
Definition: support.cc:64
void MaybeSetupRsaCallback(Security::ContextPointer &)
if required, setup callback for generating ephemeral RSA keys
Definition: support.cc:171
const char * findIssuerUri(X509 *cert)
finds certificate issuer URI in the Authority Info Access extension
Definition: support.cc:1090
std::unique_ptr< STACK_OF(X509), sk_X509_free_wrapper > X509_STACK_Pointer
Definition: gadgets.h:50
std::multimap< SBuf, X509 * > CertsIndexedList
certificates indexed by issuer name
Definition: support.h:144
void ConfigurePeerVerification(Security::ContextPointer &, const Security::ParsedPortFlags)
set the certificate verify callback for a context
Definition: support.cc:405
bool InitServerContext(Security::ContextPointer &, AnyP::PortCfg &)
initialize a TLS server context with OpenSSL specific settings
Definition: support.cc:701
int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param)
Definition: openssl.h:292
void * BIO_get_data(BIO *table)
Definition: openssl.h:62
#define X509_getm_notAfter
Definition: openssl.h:247
void SQUID_OPENSSL_init_ssl(void)
Definition: openssl.h:308
#define X509_getm_notBefore
Definition: openssl.h:248
X509_VERIFY_PARAM * SSL_get0_param(SSL *ssl)
Definition: openssl.h:300
#define X509_STORE_CTX_set0_untrusted
Definition: openssl.h:246
void BIO_set_init(BIO *table, int init)
Definition: openssl.h:74
STACK_OF(X509) *X509_STORE_CTX_get0_untrusted(X509_STORE_CTX *ctx)
Definition: openssl.h:237
X509 * X509_STORE_CTX_get0_cert(X509_STORE_CTX *ctx)
Definition: openssl.h:230
const unsigned char * ASN1_STRING_get0_data(const ASN1_STRING *x)
Definition: openssl.h:54
void BIO_set_data(BIO *table, void *data)
Definition: openssl.h:68
#define SSL_FLAG_CONDITIONAL_AUTH
Definition: forward.h:58
#define SSL_FLAG_DONT_VERIFY_PEER
Definition: forward.h:53
@ SQUID_X509_V_ERR_INFINITE_VALIDATION
Definition: forward.h:235
@ SQUID_X509_V_ERR_DOMAIN_MISMATCH
Definition: forward.h:234
@ SQUID_X509_V_ERR_CERT_CHANGE
Definition: forward.h:233
#define SSL_FLAG_DELAYED_AUTH
Definition: forward.h:52
#define SQUID_SSL_SIGN_HASH_IF_NONE
Definition: gadgets.h:43
#define SQUID_CERT_VALIDATION_ITERATION_MAX
Definition: support.h:45
static void ssl_free_ErrorDetail(void *, void *ptr, CRYPTO_EX_DATA *, int, long, void *)
Definition: support.cc:589
static void ssl_free_X509(void *, void *ptr, CRYPTO_EX_DATA *, int, long, void *)
Definition: support.cc:626
static int bio_sbuf_puts(BIO *bio, const char *data)
Definition: support.cc:1442
static void ssl_free_SBuf(void *, void *ptr, CRYPTO_EX_DATA *, int, long, void *)
Definition: support.cc:635
static int bio_sbuf_destroy(BIO *bio)
Definition: support.cc:1425
static void completeIssuers(X509_STORE_CTX *ctx, STACK_OF(X509) &untrustedCerts)
add missing issuer certificates to untrustedCerts
Definition: support.cc:1256
static void ssl_free_int(void *, void *ptr, CRYPTO_EX_DATA *, int, long, void *)
Definition: support.cc:606
static X509 * findIssuerInCaDb(X509 *cert, const Security::ContextPointer &connContext)
Definition: support.cc:1174
static int check_domain(void *check_data, ASN1_STRING *cn_data)
Definition: support.cc:231
static int ssl_dupAclChecklist(CRYPTO_EX_DATA *, CRYPTO_EX_DATA *, void *, int, long, void *)
Definition: support.cc:569
static int ssl_verify_cb(int ok, X509_STORE_CTX *ctx)
Definition: support.cc:262
static int ssl_ex_index_verify_callback_parameters
Definition: support.cc:40
static int untrustedToStoreCtx_cb(X509_STORE_CTX *ctx, void *)
Definition: support.cc:1338
static void ssl_freeAclChecklist(void *, void *ptr, CRYPTO_EX_DATA *, int, long, void *)
Definition: support.cc:581
static int bio_sbuf_write(BIO *bio, const char *data, int len)
Definition: support.cc:1433
static void ssl_free_SslErrors(void *, void *ptr, CRYPTO_EX_DATA *, int, long, void *)
Definition: support.cc:597
static X509 * findCertIssuerFast(Ssl::CertsIndexedList &list, X509 *cert)
Definition: support.cc:1139
static int VerifyCtxCertificates(X509_STORE_CTX *ctx, STACK_OF(X509) *extraCerts)
Definition: support.cc:1290
static int bio_sbuf_create(BIO *bio)
Definition: support.cc:1417
static Ssl::CertsIndexedList SquidUntrustedCerts
Definition: support.cc:42
static long bio_sbuf_ctrl(BIO *bio, int cmd, long, void *)
Definition: support.cc:1452
static X509 * sk_x509_findIssuer(const STACK_OF(X509) *sk, X509 *cert)
slowly find the issuer certificate of a given cert using linear search
Definition: support.cc:1157
static void ssl_free_VerifyCallbackParameters(void *, void *ptr, CRYPTO_EX_DATA *, int, long, void *)
"free" function for the ssl_ex_index_verify_callback_parameters entry
Definition: support.cc:644
#define NULL
Definition: types.h:145
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors