]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ssl/support.cc
Simplify appending SBuf to String (#2108)
[thirdparty/squid.git] / src / ssl / support.cc
CommitLineData
f484cdf5 1/*
1f7b830e 2 * Copyright (C) 1996-2025 The Squid Software Foundation and contributors
f484cdf5 3 *
bbc27441
AJ
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.
f484cdf5 7 */
8
bbc27441
AJ
9/* DEBUG: section 83 SSL accelerator support */
10
582c2af2 11#include "squid.h"
454e8283 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 */
cb4f4424 16#if USE_OPENSSL
454e8283 17
c0941a6a 18#include "acl/FilledChecklist.h"
22b2a7a0 19#include "anyp/Host.h"
86660d64 20#include "anyp/PortCfg.h"
c8ab5ec6 21#include "anyp/Uri.h"
ed6e9fb9 22#include "fatal.h"
b3a8ae1b 23#include "fd.h"
582c2af2
FC
24#include "fde.h"
25#include "globals.h"
22b2a7a0 26#include "ip/Address.h"
86c63190 27#include "ipc/MemMap.h"
92e3827b 28#include "security/CertError.h"
907831e6 29#include "security/Certificate.h"
83b053a0 30#include "security/ErrorDetail.h"
8d15a0c1 31#include "security/Session.h"
4d5904f7 32#include "SquidConfig.h"
b3a8ae1b 33#include "ssl/bio.h"
2cef0ca6 34#include "ssl/Config.h"
4d16918e 35#include "ssl/ErrorDetail.h"
95d2589c 36#include "ssl/gadgets.h"
602d9612 37#include "ssl/support.h"
f484cdf5 38
1a30fdf5 39#include <cerrno>
21d845b1 40
55369ae6 41// TODO: Move ssl_ex_index_* global variables from global.cc here.
800967af 42static int ssl_ex_index_verify_callback_parameters = -1;
55369ae6 43
aee3523a 44const EVP_MD *Ssl::DefaultSignHash = nullptr;
3c26b00a 45
ba6fffba 46std::vector<const char *> Ssl::BumpModeStr = {
caf3666d
AR
47 "none",
48 "client-first",
49 "server-first",
5d65362c
CT
50 "peek",
51 "stare",
52 "bump",
7f4e9b73 53 "splice",
ba6fffba
EB
54 "terminate"
55 /*,"err"*/
caf3666d
AR
56};
57
22b2a7a0
TW
58namespace Ssl {
59
60/// GeneralNameMatcher for matching a single AnyP::Host given at construction time
61class OneNameMatcher: public GeneralNameMatcher
62{
63public:
64 explicit OneNameMatcher(const AnyP::Host &needle): needle_(needle) {}
65
66protected:
67 /* GeneralNameMatcher API */
68 bool matchDomainName(const Dns::DomainName &) const override;
69 bool matchIp(const Ip::Address &) const override;
70
71 AnyP::Host needle_; ///< a name we are looking for
72};
73
9e779e40
EB
74static CertsIndexedList &
75SquidUntrustedCerts()
76{
77 static auto untrustedCerts = new CertsIndexedList();
78 return *untrustedCerts;
79}
80
22b2a7a0
TW
81} // namespace Ssl
82
83bool
84Ssl::GeneralNameMatcher::match(const GeneralName &name) const
85{
86 if (const auto domain = name.domainName())
87 return matchDomainName(*domain);
88 if (const auto ip = name.ip())
89 return matchIp(*ip);
90 Assure(!"unreachable code: the above `if` statements must cover all name variants");
91 return false;
92}
93
94bool
95Ssl::OneNameMatcher::matchDomainName(const Dns::DomainName &rawName) const {
96 // TODO: Add debugs() stream manipulator to safely (i.e. without breaking
97 // cache.log message framing) dump raw input that may contain new lines. Use
98 // here and in similar contexts where we report such raw input.
99 debugs(83, 5, "needle=" << needle_ << " domain=" << rawName);
100 if (needle_.ip()) {
101 // for example, a 127.0.0.1 IP needle does not match DNS:127.0.0.1 SAN
102 debugs(83, 7, "needle is an IP; mismatch");
103 return false;
104 }
105
106 Assure(needle_.domainName());
107 auto domainNeedle = *needle_.domainName();
108
109 auto name = rawName;
110 if (name.length() > 0 && name[0] == '*')
111 name.consume(1);
112
113 return ::matchDomainName(domainNeedle.c_str(), name.c_str(), mdnRejectSubsubDomains) == 0;
114}
115
116bool
117Ssl::OneNameMatcher::matchIp(const Ip::Address &ip) const {
118 debugs(83, 5, "needle=" << needle_ << " ip=" << ip);
119 if (const auto needleIp = needle_.ip())
120 return (*needleIp == ip);
121 debugs(83, 7, "needle is not an IP; mismatch");
122 return false;
123}
124
63be0a78 125/**
126 \defgroup ServerProtocolSSLInternal Server-Side SSL Internals
127 \ingroup ServerProtocolSSLAPI
128 */
129
51e09c08 130int
8b082ed9 131Ssl::AskPasswordCb(char *buf, int size, int /* rwflag */, void *userdata)
307b83b7 132{
133 FILE *in;
134 int len = 0;
135 char cmdline[1024];
136
51e09c08 137 snprintf(cmdline, sizeof(cmdline), "\"%s\" \"%s\"", ::Config.Program.ssl_password, (const char *)userdata);
307b83b7 138 in = popen(cmdline, "r");
139
140 if (fgets(buf, size, in))
141
142 len = strlen(buf);
143
144 while (len > 0 && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
5e263176 145 --len;
307b83b7 146
147 buf[len] = '\0';
148
149 pclose(in);
150
151 return len;
152}
153
63be0a78 154/// \ingroup ServerProtocolSSLInternal
307b83b7 155static void
156ssl_ask_password(SSL_CTX * context, const char * prompt)
157{
158 if (Config.Program.ssl_password) {
51e09c08 159 SSL_CTX_set_default_passwd_cb(context, Ssl::AskPasswordCb);
307b83b7 160 SSL_CTX_set_default_passwd_cb_userdata(context, (void *)prompt);
161 }
162}
163
17e98f24 164#if HAVE_LIBSSL_SSL_CTX_SET_TMP_RSA_CALLBACK
f484cdf5 165static RSA *
8b082ed9 166ssl_temp_rsa_cb(SSL *, int, int keylen)
f484cdf5 167{
24b30fdc
EQ
168 static RSA *rsa_512 = nullptr;
169 static RSA *rsa_1024 = nullptr;
170 static BIGNUM *e = nullptr;
171 RSA *rsa = nullptr;
e01f02ed 172 int newkey = 0;
f484cdf5 173
24b30fdc
EQ
174 if (!e) {
175 e = BN_new();
176 if (!e || !BN_set_word(e, RSA_F4)) {
d816f28d 177 debugs(83, DBG_IMPORTANT, "ERROR: ssl_temp_rsa_cb: Failed to set exponent for key " << keylen);
24b30fdc
EQ
178 BN_free(e);
179 e = nullptr;
180 return nullptr;
181 }
182 }
183
e01f02ed 184 switch (keylen) {
185
186 case 512:
187
188 if (!rsa_512) {
24b30fdc
EQ
189 rsa_512 = RSA_new();
190 if (rsa_512 && RSA_generate_key_ex(rsa_512, 512, e, nullptr)) {
191 newkey = 1;
192 } else {
193 RSA_free(rsa_512);
194 rsa_512 = nullptr;
195 }
e01f02ed 196 }
197
198 rsa = rsa_512;
199 break;
200
201 case 1024:
202
203 if (!rsa_1024) {
24b30fdc
EQ
204 rsa_1024 = RSA_new();
205 if (rsa_1024 && RSA_generate_key_ex(rsa_1024, 1024, e, nullptr)) {
206 newkey = 1;
207 } else {
208 RSA_free(rsa_1024);
209 rsa_1024 = nullptr;
210 }
e01f02ed 211 }
212
213 rsa = rsa_1024;
214 break;
215
216 default:
d816f28d 217 debugs(83, DBG_IMPORTANT, "ERROR: ssl_temp_rsa_cb: Unexpected key length " << keylen);
a1b1756c 218 return nullptr;
e01f02ed 219 }
220
221 if (rsa == NULL) {
d816f28d 222 debugs(83, DBG_IMPORTANT, "ERROR: ssl_temp_rsa_cb: Failed to generate key " << keylen);
a1b1756c 223 return nullptr;
e01f02ed 224 }
225
226 if (newkey) {
014adac1 227 if (Debug::Enabled(83, 5))
016c612a 228 PEM_write_RSAPrivateKey(DebugStream(), rsa, nullptr, nullptr, 0, nullptr, nullptr);
e01f02ed 229
e0236918 230 debugs(83, DBG_IMPORTANT, "Generated ephemeral RSA key of length " << keylen);
e01f02ed 231 }
62e76326 232
f484cdf5 233 return rsa;
234}
b7afb10f
CT
235#endif
236
cf487124
AJ
237void
238Ssl::MaybeSetupRsaCallback(Security::ContextPointer &ctx)
b7afb10f 239{
17e98f24 240#if HAVE_LIBSSL_SSL_CTX_SET_TMP_RSA_CALLBACK
b7afb10f
CT
241 debugs(83, 9, "Setting RSA key generation callback.");
242 SSL_CTX_set_tmp_rsa_callback(ctx.get(), ssl_temp_rsa_cb);
8b082ed9
FC
243#else
244 (void)ctx;
b7afb10f
CT
245#endif
246}
f484cdf5 247
4d16918e
CT
248int Ssl::asn1timeToString(ASN1_TIME *tm, char *buf, int len)
249{
250 BIO *bio;
251 int write = 0;
252 bio = BIO_new(BIO_s_mem());
253 if (bio) {
e34763f4
A
254 if (ASN1_TIME_print(bio, tm))
255 write = BIO_read(bio, buf, len-1);
256 BIO_free(bio);
4d16918e
CT
257 }
258 buf[write]='\0';
259 return write;
260}
261
22b2a7a0
TW
262static std::optional<AnyP::Host>
263ParseSubjectAltName(const GENERAL_NAME &san)
4d16918e 264{
22b2a7a0
TW
265 switch(san.type) {
266 case GEN_DNS: {
267 Assure(san.d.dNSName);
268 // GEN_DNS is an IA5STRING. IA5STRING is a subset of ASCII that does not
269 // need to be converted to UTF-8 (or some such) before we parse it.
270 const auto buffer = Ssl::AsnToSBuf(*san.d.dNSName);
271 return AnyP::Host::ParseWildDomainName(buffer);
272 }
4d16918e 273
22b2a7a0
TW
274 case GEN_IPADD: {
275 // san.d.iPAddress is OpenSSL ASN1_OCTET_STRING
276 Assure(san.d.iPAddress);
e34763f4 277
22b2a7a0 278 // RFC 5280 section 4.2.1.6 signals IPv4/IPv6 address family using data length
4d16918e 279
22b2a7a0
TW
280 if (san.d.iPAddress->length == 4) {
281 struct in_addr addr;
282 static_assert(sizeof(addr.s_addr) == 4);
283 memcpy(&addr.s_addr, san.d.iPAddress->data, sizeof(addr.s_addr));
284 const Ip::Address ip(addr);
285 return AnyP::Host::ParseIp(ip);
286 }
4d16918e 287
22b2a7a0
TW
288 if (san.d.iPAddress->length == 16) {
289 struct in6_addr addr;
290 static_assert(sizeof(addr.s6_addr) == 16);
291 memcpy(&addr.s6_addr, san.d.iPAddress->data, sizeof(addr.s6_addr));
292 const Ip::Address ip(addr);
293 return AnyP::Host::ParseIp(ip);
294 }
4d16918e 295
22b2a7a0
TW
296 debugs(83, 3, "unexpected length of an IP address SAN: " << san.d.iPAddress->length);
297 return std::nullopt;
298 }
e34763f4 299
22b2a7a0
TW
300 default:
301 debugs(83, 3, "unsupported SAN kind: " << san.type);
302 return std::nullopt;
4d16918e 303 }
4d16918e
CT
304}
305
22b2a7a0
TW
306bool
307Ssl::HasMatchingSubjectName(X509 &cert, const GeneralNameMatcher &matcher)
4d16918e 308{
22b2a7a0
TW
309 const auto name = X509_get_subject_name(&cert);
310 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)) {
311 debugs(83, 7, "checking CN at " << i);
312 if (const auto cn = ParseCommonNameAt(*name, i)) {
313 if (matcher.match(*cn))
314 return true;
315 }
316 }
abbd7825 317
22b2a7a0
TW
318 const Ssl::GENERAL_NAME_STACK_Pointer sans(static_cast<STACK_OF(GENERAL_NAME)*>(
319 X509_get_ext_d2i(&cert, NID_subject_alt_name, nullptr, nullptr)));
320 if (sans) {
321 const auto sanCount = sk_GENERAL_NAME_num(sans.get());
322 for (int i = 0; i < sanCount; ++i) {
323 debugs(83, 7, "checking SAN at " << i);
324 const auto rawSan = sk_GENERAL_NAME_value(sans.get(), i);
325 Assure(rawSan);
326 if (const auto san = ParseSubjectAltName(*rawSan)) {
327 if (matcher.match(*san))
328 return true;
329 }
330 }
0f7f4cfc 331 }
22b2a7a0
TW
332
333 debugs(83, 7, "no matches");
334 return false;
4d16918e
CT
335}
336
22b2a7a0
TW
337bool
338Ssl::HasSubjectName(X509 &cert, const AnyP::Host &host)
8eb0a7ee 339{
22b2a7a0 340 return HasMatchingSubjectName(cert, OneNameMatcher(host));
8eb0a7ee
CT
341}
342
800967af
CT
343/// adjusts OpenSSL validation results for each verified certificate in ctx
344/// OpenSSL "verify_callback function" (\ref OpenSSL_vcb_disambiguation)
f484cdf5 345static int
346ssl_verify_cb(int ok, X509_STORE_CTX * ctx)
347{
7698a79c 348 // preserve original ctx->error before SSL_ calls can overwrite it
2a268a06 349 Security::ErrorCode error_no = ok ? SSL_ERROR_NONE : X509_STORE_CTX_get_error(ctx);
7698a79c 350
a7ad6e4e 351 SSL *ssl = (SSL *)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
0476ec45 352 SSL_CTX *sslctx = SSL_get_SSL_CTX(ssl);
68920ad8 353 SBuf *server = (SBuf *)SSL_get_ex_data(ssl, ssl_ex_index_server);
a7ad6e4e 354 void *dont_verify_domain = SSL_CTX_get_ex_data(sslctx, ssl_ctx_ex_index_dont_verify_domain);
815eaa44 355 ACLChecklist *check = (ACLChecklist*)SSL_get_ex_data(ssl, ssl_ex_index_cert_error_check);
e7bcc25f 356 X509 *peeked_cert = (X509 *)SSL_get_ex_data(ssl, ssl_ex_index_ssl_peeked_cert);
92e3827b 357 Security::CertPointer peer_cert;
2a268a06 358 peer_cert.resetAndLock(X509_STORE_CTX_get0_cert(ctx));
f484cdf5 359
0ad3ff51
CT
360 // detect infinite loops
361 uint32_t *validationCounter = static_cast<uint32_t *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_validation_counter));
362 if (!validationCounter) {
363 validationCounter = new uint32_t(1);
364 SSL_set_ex_data(ssl, ssl_ex_index_ssl_validation_counter, validationCounter);
365 } else {
366 // overflows allowed if SQUID_CERT_VALIDATION_ITERATION_MAX >= UINT32_MAX
367 (*validationCounter)++;
368 }
369
370 if ((*validationCounter) >= SQUID_CERT_VALIDATION_ITERATION_MAX) {
371 ok = 0; // or the validation loop will never stop
372 error_no = SQUID_X509_V_ERR_INFINITE_VALIDATION;
373 debugs(83, 2, "SQUID_X509_V_ERR_INFINITE_VALIDATION: " <<
907831e6 374 *validationCounter << " iterations while checking " << *peer_cert);
0ad3ff51
CT
375 }
376
a7ad6e4e 377 if (ok) {
907831e6 378 debugs(83, 5, "SSL Certificate signature OK: " << *peer_cert);
62e76326 379
4747ea4c 380 // Check for domain mismatch only if the current certificate is the peer certificate.
92e3827b 381 if (!dont_verify_domain && server && peer_cert.get() == X509_STORE_CTX_get_current_cert(ctx)) {
22b2a7a0
TW
382 // XXX: This code does not know where the server name came from. The
383 // name may be valid but not compatible with requirements assumed or
384 // enforced by the AnyP::Host::ParseSimpleDomainName() call below.
385 // TODO: Store AnyP::Host (or equivalent) in ssl_ex_index_server.
386 if (const auto host = Ssl::ParseAsSimpleDomainNameOrIp(*server)) {
387 if (Ssl::HasSubjectName(*peer_cert, *host)) {
388 debugs(83, 5, "certificate subject matches " << *host);
389 } else {
390 debugs(83, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Certificate " << *peer_cert << " does not match domainname " << *host);
391 ok = 0;
392 error_no = SQUID_X509_V_ERR_DOMAIN_MISMATCH;
393 }
394 } else {
395 debugs(83, 2, "SQUID_X509_V_ERR_DOMAIN_MISMATCH: Cannot check whether certificate " << *peer_cert << " subject matches malformed domainname " << *server);
62e76326 396 ok = 0;
4d16918e 397 error_no = SQUID_X509_V_ERR_DOMAIN_MISMATCH;
62e76326 398 }
399 }
7698a79c 400 }
0db46e4f 401
e7bcc25f 402 if (ok && peeked_cert) {
7a957a93 403 // Check whether the already peeked certificate matches the new one.
92e3827b 404 if (X509_cmp(peer_cert.get(), peeked_cert) != 0) {
907831e6 405 debugs(83, 2, "SQUID_X509_V_ERR_CERT_CHANGE: Certificate " << *peer_cert << " does not match peeked certificate");
e7bcc25f
CT
406 ok = 0;
407 error_no = SQUID_X509_V_ERR_CERT_CHANGE;
408 }
409 }
410
800967af
CT
411 if (!ok && error_no == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) {
412 if (const auto params = Ssl::VerifyCallbackParameters::Find(*ssl)) {
413 if (params->callerHandlesMissingCertificates) {
414 debugs(83, 3, "hiding X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY");
415 params->hidMissingIssuer = true;
416 ok = 1;
417 }
418 }
419 }
420
7698a79c 421 if (!ok) {
92e3827b
AJ
422 Security::CertPointer broken_cert;
423 broken_cert.resetAndLock(X509_STORE_CTX_get_current_cert(ctx));
62a7607e
CT
424 if (!broken_cert)
425 broken_cert = peer_cert;
426
92e3827b 427 Security::CertErrors *errs = static_cast<Security::CertErrors *>(SSL_get_ex_data(ssl, ssl_ex_index_ssl_errors));
e36bc333 428 const int depth = X509_STORE_CTX_get_error_depth(ctx);
7a957a93 429 if (!errs) {
92e3827b 430 errs = new Security::CertErrors(Security::CertError(error_no, broken_cert, depth));
7a957a93 431 if (!SSL_set_ex_data(ssl, ssl_ex_index_ssl_errors, (void *)errs)) {
907831e6 432 debugs(83, 2, "Failed to set ssl error_no in ssl_verify_cb: Certificate " << *peer_cert);
7a957a93 433 delete errs;
aee3523a 434 errs = nullptr;
fb2178bb 435 }
87f237a9 436 } else // remember another error number
92e3827b 437 errs->push_back_unique(Security::CertError(error_no, broken_cert, depth));
fb2178bb 438
4e143970
FC
439 if (const auto description = Ssl::GetErrorDescr(error_no))
440 debugs(83, 5, *description << ": " << *peer_cert);
cf09bec7 441 else
907831e6 442 debugs(83, DBG_IMPORTANT, "ERROR: SSL unknown certificate error " << error_no << " in " << *peer_cert);
7698a79c 443
0ad3ff51
CT
444 // Check if the certificate error can be bypassed.
445 // Infinity validation loop errors can not bypassed.
446 if (error_no != SQUID_X509_V_ERR_INFINITE_VALIDATION) {
447 if (check) {
448 ACLFilledChecklist *filledCheck = Filled(check);
757a738c 449 const auto savedErrors = filledCheck->sslErrors;
27a1c6de
AR
450 const auto sslErrors = std::make_unique<Security::CertErrors>(Security::CertError(error_no, broken_cert));
451 filledCheck->sslErrors = sslErrors.get();
92e3827b 452 filledCheck->serverCert = peer_cert;
06bf5384 453 if (check->fastCheck().allowed()) {
907831e6 454 debugs(83, 3, "bypassing SSL error " << error_no << " in " << *peer_cert);
0ad3ff51
CT
455 ok = 1;
456 } else {
457 debugs(83, 5, "confirming SSL error " << error_no);
458 }
757a738c 459 filledCheck->sslErrors = savedErrors;
58a5291c 460 filledCheck->serverCert.reset();
7698a79c 461 }
0ad3ff51 462 // If the certificate validator is used then we need to allow all errors and
2f8abb64 463 // pass them to certificate validator for more processing
0ad3ff51 464 else if (Ssl::TheConfig.ssl_crt_validator) {
7698a79c 465 ok = 1;
7698a79c 466 }
815eaa44 467 }
a7ad6e4e 468 }
62e76326 469
081be7eb
CT
470 if (Ssl::TheConfig.ssl_crt_validator) {
471 // Check if we have stored certificates chain. Store if not.
472 if (!SSL_get_ex_data(ssl, ssl_ex_index_ssl_cert_chain)) {
473 STACK_OF(X509) *certStack = X509_STORE_CTX_get1_chain(ctx);
474 if (certStack && !SSL_set_ex_data(ssl, ssl_ex_index_ssl_cert_chain, certStack))
475 sk_X509_pop_free(certStack, X509_free);
476 }
477 }
478
7698a79c 479 if (!ok && !SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail) ) {
f622c461
MF
480
481 // Find the broken certificate. It may be intermediate.
92e3827b 482 Security::CertPointer broken_cert(peer_cert); // reasonable default if search fails
f622c461
MF
483 // Our SQUID_X509_V_ERR_DOMAIN_MISMATCH implies peer_cert is at fault.
484 if (error_no != SQUID_X509_V_ERR_DOMAIN_MISMATCH) {
92e3827b
AJ
485 if (auto *last_used_cert = X509_STORE_CTX_get_current_cert(ctx))
486 broken_cert.resetAndLock(last_used_cert);
f622c461
MF
487 }
488
83b053a0
CT
489 std::unique_ptr<Security::ErrorDetail::Pointer> edp(new Security::ErrorDetail::Pointer(
490 new Security::ErrorDetail(error_no, peer_cert, broken_cert)));
491 if (SSL_set_ex_data(ssl, ssl_ex_index_ssl_error_detail, edp.get()))
492 edp.release();
493 else
907831e6 494 debugs(83, 2, "failed to store a " << *peer_cert << " error detail: " << *edp);
4d16918e
CT
495 }
496
f484cdf5 497 return ok;
498}
499
621f4299 500void
983fab6e 501Ssl::ConfigurePeerVerification(Security::ContextPointer &ctx, const Security::ParsedPortFlags flags)
621f4299 502{
983fab6e 503 int mode;
504
505 // assume each flag is exclusive; flags creator must check this assumption
506 if (flags & SSL_FLAG_DONT_VERIFY_PEER) {
507 debugs(83, DBG_IMPORTANT, "SECURITY WARNING: Peer certificates are not verified for validity!");
d816f28d 508 debugs(83, DBG_IMPORTANT, "WARNING: UPGRADE: The DONT_VERIFY_PEER flag is deprecated. Remove the clientca= option to disable client certificates.");
983fab6e 509 mode = SSL_VERIFY_NONE;
510 }
511 else if (flags & SSL_FLAG_DELAYED_AUTH) {
512 debugs(83, DBG_PARSE_NOTE(3), "not requesting client certificates until ACL processing requires one");
513 mode = SSL_VERIFY_NONE;
514 }
515 else if (flags & SSL_FLAG_CONDITIONAL_AUTH) {
7c25db36 516 debugs(83, DBG_PARSE_NOTE(3), "will request the client certificate but ignore its absence");
983fab6e 517 mode = SSL_VERIFY_PEER;
518 }
519 else {
520 debugs(83, DBG_PARSE_NOTE(3), "Requiring client certificates.");
521 mode = SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
522 }
523
524 SSL_CTX_set_verify(ctx.get(), mode, (mode != SSL_VERIFY_NONE) ? ssl_verify_cb : nullptr);
525}
526
527void
528Ssl::DisablePeerVerification(Security::ContextPointer &ctx)
529{
530 debugs(83, DBG_PARSE_NOTE(3), "Not requiring any client certificates");
531 SSL_CTX_set_verify(ctx.get(),SSL_VERIFY_NONE,nullptr);
621f4299
AJ
532}
533
800967af
CT
534static int VerifyCtxCertificates(X509_STORE_CTX *ctx, STACK_OF(X509) *extraCerts);
535
536bool
537Ssl::VerifyConnCertificates(Security::Connection &sconn, const Ssl::X509_STACK_Pointer &extraCerts)
538{
539 const auto peerCertificatesChain = SSL_get_peer_cert_chain(&sconn);
540
541 // TODO: Replace debugs/return false with returning ErrorDetail::Pointer.
542 // Using Security::ErrorDetail terminology, errors in _this_ function are
543 // "non-validation errors", but VerifyCtxCertificates() errors may be
544 // "certificate validation errors". Callers detail SQUID_TLS_ERR_CONNECT.
545 // Some details should be created right here. Others extracted from OpenSSL.
546 // Why not throw? Most of the reasons detailed in the following commit apply
547 // here as well: https://github.com/measurement-factory/squid/commit/e862d33
548
549 if (!peerCertificatesChain || sk_X509_num(peerCertificatesChain) == 0) {
550 debugs(83, 2, "no server certificates");
551 return false;
552 }
553
554 const auto verificationStore = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(&sconn));
555 if (!verificationStore) {
556 debugs(83, 2, "no certificate store");
557 return false;
558 }
559
560 const X509_STORE_CTX_Pointer storeCtx(X509_STORE_CTX_new());
561 if (!storeCtx) {
562 debugs(83, 2, "cannot create X509_STORE_CTX; likely OOM");
563 return false;
564 }
565
566 const auto peerCert = sk_X509_value(peerCertificatesChain, 0);
567 if (!X509_STORE_CTX_init(storeCtx.get(), verificationStore, peerCert, peerCertificatesChain)) {
568 debugs(83, 2, "cannot initialize X509_STORE_CTX");
569 return false;
570 }
571
572#if defined(SSL_CERT_FLAG_SUITEB_128_LOS)
573 // overwrite context Suite B (RFC 5759) flags with connection non-defaults
574 // SSL_set_cert_flags() return type is long, but its implementation actually
575 // returns an unsigned long flags value expected by X509_STORE_CTX_set_flags
576 const unsigned long certFlags = SSL_set_cert_flags(&sconn, 0);
577 if (const auto suiteBflags = certFlags & SSL_CERT_FLAG_SUITEB_128_LOS)
578 X509_STORE_CTX_set_flags(storeCtx.get(), suiteBflags);
579#endif
580
581 if (!X509_STORE_CTX_set_ex_data(storeCtx.get(), SSL_get_ex_data_X509_STORE_CTX_idx(), &sconn)) {
582 debugs(83, 2, "cannot attach SSL object to X509_STORE_CTX");
583 return false;
584 }
585
586 // If we ever add DANE support to Squid, we will supply DANE details here:
587 // X509_STORE_CTX_set0_dane(storeCtx.get(), SSL_get0_dane(&sconn));
588
589 // tell OpenSSL we are verifying a server certificate
590 if (!X509_STORE_CTX_set_default(storeCtx.get(), "ssl_server")) {
591 debugs(83, 2, "cannot set default verification method to ssl_server");
592 return false;
593 }
594
595 // overwrite context "verification parameters" with connection non-defaults
596 const auto param = X509_STORE_CTX_get0_param(storeCtx.get());
597 if (!param) {
598 debugs(83, 2, "no context verification parameters");
599 return false;
600 }
601#if defined(HAVE_X509_VERIFY_PARAM_SET_AUTH_LEVEL)
602 X509_VERIFY_PARAM_set_auth_level(param, SSL_get_security_level(&sconn));
603#endif
604 if (!X509_VERIFY_PARAM_set1(param, SSL_get0_param(&sconn))) {
605 debugs(83, 2, "cannot overwrite context verification parameters");
606 return false;
607 }
608
609 // copy any connection "verify_callback function" to the validation context
610 // (\ref OpenSSL_vcb_disambiguation)
611 if (const auto cb = SSL_get_verify_callback(&sconn))
612 X509_STORE_CTX_set_verify_cb(storeCtx.get(), cb);
613
614 // verify the server certificate chain in the prepared validation context
615 if (VerifyCtxCertificates(storeCtx.get(), extraCerts.get()) <= 0) {
616 // see also: ssl_verify_cb() details errors via ssl_ex_index_ssl_errors
617 const auto verifyResult = X509_STORE_CTX_get_error(storeCtx.get());
618 debugs(83, 3, "verification failure: " << verifyResult << ' ' << X509_verify_cert_error_string(verifyResult));
619 return false;
620 }
621
622 debugs(83, 7, "success");
623 return true;
624}
625
626/* Ssl::VerifyCallbackParameters */
627
628Ssl::VerifyCallbackParameters *
629Ssl::VerifyCallbackParameters::Find(Security::Connection &sconn)
630{
631 return static_cast<VerifyCallbackParameters*>(SSL_get_ex_data(&sconn, ssl_ex_index_verify_callback_parameters));
632}
633
634Ssl::VerifyCallbackParameters *
635Ssl::VerifyCallbackParameters::New(Security::Connection &sconn)
636{
637 Must(!Find(sconn));
638 const auto parameters = new VerifyCallbackParameters();
639 if (!SSL_set_ex_data(&sconn, ssl_ex_index_verify_callback_parameters, parameters)) {
640 delete parameters;
641 throw TextException("SSL_set_ex_data() failed; likely OOM", Here());
642 }
643 return parameters;
644}
645
646Ssl::VerifyCallbackParameters &
647Ssl::VerifyCallbackParameters::At(Security::Connection &sconn)
648{
649 const auto parameters = Find(sconn);
650 Must(parameters);
651 return *parameters;
652}
653
815eaa44 654// "dup" function for SSL_get_ex_new_index("cert_err_check")
742236c7
AJ
655#if OPENSSL_VERSION_MAJOR >= 3
656static int
657ssl_dupAclChecklist(CRYPTO_EX_DATA *, const CRYPTO_EX_DATA *, void **,
658 int, long, void *)
659#elif SQUID_USE_CONST_CRYPTO_EX_DATA_DUP
2a268a06
CT
660static int
661ssl_dupAclChecklist(CRYPTO_EX_DATA *, const CRYPTO_EX_DATA *, void *,
662 int, long, void *)
663#else
815eaa44 664static int
665ssl_dupAclChecklist(CRYPTO_EX_DATA *, CRYPTO_EX_DATA *, void *,
26ac0430 666 int, long, void *)
2a268a06 667#endif
26ac0430 668{
815eaa44 669 // We do not support duplication of ACLCheckLists.
670 // If duplication is needed, we can count copies with cbdata.
671 assert(false);
672 return 0;
673}
674
675// "free" function for SSL_get_ex_new_index("cert_err_check")
676static void
677ssl_freeAclChecklist(void *, void *ptr, CRYPTO_EX_DATA *,
26ac0430
AJ
678 int, long, void *)
679{
815eaa44 680 delete static_cast<ACLChecklist *>(ptr); // may be NULL
681}
a7ad6e4e 682
4d16918e
CT
683// "free" function for SSL_get_ex_new_index("ssl_error_detail")
684static void
685ssl_free_ErrorDetail(void *, void *ptr, CRYPTO_EX_DATA *,
686 int, long, void *)
687{
83b053a0 688 const auto errDetail = static_cast<Security::ErrorDetail::Pointer*>(ptr);
4d16918e
CT
689 delete errDetail;
690}
691
fb2178bb 692static void
7a957a93 693ssl_free_SslErrors(void *, void *ptr, CRYPTO_EX_DATA *,
87f237a9 694 int, long, void *)
fb2178bb 695{
92e3827b 696 Security::CertErrors *errs = static_cast <Security::CertErrors*>(ptr);
7a957a93 697 delete errs;
fb2178bb
CT
698}
699
0ad3ff51
CT
700// "free" function for SSL_get_ex_new_index("ssl_ex_index_ssl_validation_counter")
701static void
702ssl_free_int(void *, void *ptr, CRYPTO_EX_DATA *,
3cc296c4 703 int, long, void *)
0ad3ff51
CT
704{
705 uint32_t *counter = static_cast <uint32_t *>(ptr);
706 delete counter;
707}
708
4747ea4c
CT
709/// \ingroup ServerProtocolSSLInternal
710/// Callback handler function to release STACK_OF(X509) "ex" data stored
711/// in an SSL object.
712static void
713ssl_free_CertChain(void *, void *ptr, CRYPTO_EX_DATA *,
714 int, long, void *)
715{
716 STACK_OF(X509) *certsChain = static_cast <STACK_OF(X509) *>(ptr);
717 sk_X509_pop_free(certsChain,X509_free);
718}
719
e7bcc25f
CT
720// "free" function for X509 certificates
721static void
722ssl_free_X509(void *, void *ptr, CRYPTO_EX_DATA *,
87f237a9 723 int, long, void *)
e7bcc25f
CT
724{
725 X509 *cert = static_cast <X509 *>(ptr);
726 X509_free(cert);
727}
728
c1d50c01 729// "free" function for SBuf
68920ad8
CT
730static void
731ssl_free_SBuf(void *, void *ptr, CRYPTO_EX_DATA *,
732 int, long, void *)
733{
734 SBuf *buf = static_cast <SBuf *>(ptr);
735 delete buf;
736}
737
800967af
CT
738/// "free" function for the ssl_ex_index_verify_callback_parameters entry
739static void
740ssl_free_VerifyCallbackParameters(void *, void *ptr, CRYPTO_EX_DATA *,
741 int, long, void *)
742{
743 delete static_cast<Ssl::VerifyCallbackParameters*>(ptr);
744}
745
0a28c16a
AJ
746void
747Ssl::Initialize(void)
f484cdf5 748{
56a35ad1
AR
749 static bool initialized = false;
750 if (initialized)
751 return;
752 initialized = true;
62e76326 753
24b30fdc 754 SQUID_OPENSSL_init_ssl();
62e76326 755
0a28c16a 756 if (::Config.SSL.ssl_engine) {
742236c7 757#if OPENSSL_VERSION_MAJOR < 3
bb4cc8e6 758 debugs(83, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: Support for ssl_engine is deprecated " <<
911833fc
AJ
759 "in Squids built with OpenSSL 1.x (like this Squid). " <<
760 "It is removed in Squids built with OpenSSL 3.0 or newer.");
742236c7 761#if !defined(OPENSSL_NO_ENGINE)
95c85af7 762 ENGINE_load_builtin_engines();
56a35ad1 763 ENGINE *e;
0a28c16a
AJ
764 if (!(e = ENGINE_by_id(::Config.SSL.ssl_engine)))
765 fatalf("Unable to find SSL engine '%s'\n", ::Config.SSL.ssl_engine);
56a35ad1
AR
766
767 if (!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
83b053a0 768 const auto ssl_error = ERR_get_error();
ea574635 769 fatalf("Failed to initialise SSL engine: %s\n", Security::ErrorString(ssl_error));
62e76326 770 }
742236c7
AJ
771#else /* OPENSSL_NO_ENGINE */
772 throw TextException("Cannot use ssl_engine in Squid built with OpenSSL configured to disable SSL engine support", Here());
773#endif
774
775#else /* OPENSSL_VERSION_MAJOR */
911833fc 776 throw TextException("Cannot use ssl_engine in Squid built with OpenSSL 3.0 or newer", Here());
a7ad6e4e 777#endif
742236c7 778 }
62e76326 779
0a28c16a 780 const char *defName = ::Config.SSL.certSignHash ? ::Config.SSL.certSignHash : SQUID_SSL_SIGN_HASH_IF_NONE;
3c26b00a
CT
781 Ssl::DefaultSignHash = EVP_get_digestbyname(defName);
782 if (!Ssl::DefaultSignHash)
783 fatalf("Sign hash '%s' is not supported\n", defName);
784
aee3523a
AR
785 ssl_ex_index_server = SSL_get_ex_new_index(0, (void *) "server", nullptr, nullptr, ssl_free_SBuf);
786 ssl_ctx_ex_index_dont_verify_domain = SSL_CTX_get_ex_new_index(0, (void *) "dont_verify_domain", nullptr, nullptr, nullptr);
787 ssl_ex_index_cert_error_check = SSL_get_ex_new_index(0, (void *) "cert_error_check", nullptr, &ssl_dupAclChecklist, &ssl_freeAclChecklist);
788 ssl_ex_index_ssl_error_detail = SSL_get_ex_new_index(0, (void *) "ssl_error_detail", nullptr, nullptr, &ssl_free_ErrorDetail);
789 ssl_ex_index_ssl_peeked_cert = SSL_get_ex_new_index(0, (void *) "ssl_peeked_cert", nullptr, nullptr, &ssl_free_X509);
790 ssl_ex_index_ssl_errors = SSL_get_ex_new_index(0, (void *) "ssl_errors", nullptr, nullptr, &ssl_free_SslErrors);
791 ssl_ex_index_ssl_cert_chain = SSL_get_ex_new_index(0, (void *) "ssl_cert_chain", nullptr, nullptr, &ssl_free_CertChain);
792 ssl_ex_index_ssl_validation_counter = SSL_get_ex_new_index(0, (void *) "ssl_validation_counter", nullptr, nullptr, &ssl_free_int);
800967af 793 ssl_ex_index_verify_callback_parameters = SSL_get_ex_new_index(0, (void *) "verify_callback_parameters", nullptr, nullptr, &ssl_free_VerifyCallbackParameters);
55369ae6
AR
794}
795
c75aba02 796bool
8b082ed9 797Ssl::InitServerContext(Security::ContextPointer &ctx, AnyP::PortCfg &)
86660d64 798{
9ad528b8 799 if (!ctx)
c75aba02 800 return false;
86660d64 801
c75aba02 802 return true;
a7ad6e4e 803}
804
c75aba02 805bool
983fab6e 806Ssl::InitClientContext(Security::ContextPointer &ctx, Security::PeerOptions &peer, Security::ParsedPortFlags fl)
d620ae0e 807{
64769c79 808 if (!ctx)
c75aba02 809 return false;
62e76326 810
d1d72d43
AJ
811 if (!peer.sslCipher.isEmpty()) {
812 debugs(83, 5, "Using chiper suite " << peer.sslCipher << ".");
62e76326 813
d1d72d43 814 const char *cipher = peer.sslCipher.c_str();
64769c79 815 if (!SSL_CTX_set_cipher_list(ctx.get(), cipher)) {
83b053a0 816 const auto ssl_error = ERR_get_error();
62e76326 817 fatalf("Failed to set SSL cipher suite '%s': %s\n",
ea574635 818 cipher, Security::ErrorString(ssl_error));
62e76326 819 }
a7ad6e4e 820 }
62e76326 821
332c979d
AJ
822 if (!peer.certs.empty()) {
823 // TODO: support loading multiple cert/key pairs
824 auto &keys = peer.certs.front();
825 if (!keys.certFile.isEmpty()) {
9259c796 826 debugs(83, 2, "loading client certificate from " << keys.certFile);
332c979d
AJ
827
828 const char *certfile = keys.certFile.c_str();
64769c79 829 if (!SSL_CTX_use_certificate_chain_file(ctx.get(), certfile)) {
83b053a0 830 const auto ssl_error = ERR_get_error();
332c979d 831 fatalf("Failed to acquire SSL certificate '%s': %s\n",
ea574635 832 certfile, Security::ErrorString(ssl_error));
332c979d 833 }
62e76326 834
9259c796 835 debugs(83, 2, "loading private key from " << keys.privateKeyFile);
332c979d 836 const char *keyfile = keys.privateKeyFile.c_str();
64769c79 837 ssl_ask_password(ctx.get(), keyfile);
62e76326 838
64769c79 839 if (!SSL_CTX_use_PrivateKey_file(ctx.get(), keyfile, SSL_FILETYPE_PEM)) {
83b053a0 840 const auto ssl_error = ERR_get_error();
332c979d 841 fatalf("Failed to acquire SSL private key '%s': %s\n",
ea574635 842 keyfile, Security::ErrorString(ssl_error));
332c979d 843 }
62e76326 844
332c979d 845 debugs(83, 5, "Comparing private and public SSL keys.");
62e76326 846
64769c79 847 if (!SSL_CTX_check_private_key(ctx.get())) {
83b053a0 848 const auto ssl_error = ERR_get_error();
332c979d 849 fatalf("SSL private key '%s' does not match public key '%s': %s\n",
ea574635 850 certfile, keyfile, Security::ErrorString(ssl_error));
332c979d 851 }
62e76326 852 }
a7ad6e4e 853 }
62e76326 854
cf487124 855 MaybeSetupRsaCallback(ctx);
f484cdf5 856
983fab6e 857 Ssl::ConfigurePeerVerification(ctx, fl);
f484cdf5 858
c75aba02 859 return true;
f484cdf5 860}
861
63be0a78 862/// \ingroup ServerProtocolSSLInternal
a7ad6e4e 863static const char *
864ssl_get_attribute(X509_NAME * name, const char *attribute_name)
865{
866 static char buffer[1024];
a7ad6e4e 867 buffer[0] = '\0';
868
869 if (strcmp(attribute_name, "DN") == 0) {
62e76326 870 X509_NAME_oneline(name, buffer, sizeof(buffer));
627059a5
AJ
871 } else {
872 int nid = OBJ_txt2nid(const_cast<char *>(attribute_name));
873 if (nid == 0) {
874 debugs(83, DBG_IMPORTANT, "WARNING: Unknown SSL attribute name '" << attribute_name << "'");
875 return nullptr;
876 }
877 X509_NAME_get_text_by_NID(name, nid, buffer, sizeof(buffer));
a7ad6e4e 878 }
62e76326 879
627059a5 880 return *buffer ? buffer : nullptr;
a7ad6e4e 881}
882
63be0a78 883/// \ingroup ServerProtocolSSLInternal
a7ad6e4e 884const char *
00352183 885Ssl::GetX509UserAttribute(X509 * cert, const char *attribute_name)
a7ad6e4e 886{
a7ad6e4e 887 X509_NAME *name;
23e6c4ae 888 const char *ret;
a7ad6e4e 889
a7ad6e4e 890 if (!cert)
aee3523a 891 return nullptr;
a7ad6e4e 892
5a4684b6 893 name = X509_get_subject_name(cert);
a7ad6e4e 894
23e6c4ae 895 ret = ssl_get_attribute(name, attribute_name);
896
23e6c4ae 897 return ret;
a7ad6e4e 898}
899
00352183
AR
900const char *
901Ssl::GetX509Fingerprint(X509 * cert, const char *)
902{
903 static char buf[1024];
904 if (!cert)
aee3523a 905 return nullptr;
960e100b 906
00352183
AR
907 unsigned int n;
908 unsigned char md[EVP_MAX_MD_SIZE];
909 if (!X509_digest(cert, EVP_sha1(), md, &n))
aee3523a 910 return nullptr;
00352183
AR
911
912 assert(3 * n + 1 < sizeof(buf));
913
914 char *s = buf;
915 for (unsigned int i=0; i < n; ++i, s += 3) {
916 const char term = (i + 1 < n) ? ':' : '\0';
917 snprintf(s, 4, "%02X%c", md[i], term);
918 }
919
920 return buf;
921}
922
12b5040f
DN
923SBuf
924Ssl::GetX509PEM(X509 * cert)
925{
926 assert(cert);
927
928 Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
929 PEM_write_bio_X509(bio.get(), cert);
930
931 char *ptr;
932 const auto len = BIO_get_mem_data(bio.get(), &ptr);
933 return SBuf(ptr, len);
934}
935
63be0a78 936/// \ingroup ServerProtocolSSLInternal
a7ad6e4e 937const char *
00352183 938Ssl::GetX509CAAttribute(X509 * cert, const char *attribute_name)
a7ad6e4e 939{
00352183 940
a7ad6e4e 941 X509_NAME *name;
23e6c4ae 942 const char *ret;
a7ad6e4e 943
a7ad6e4e 944 if (!cert)
aee3523a 945 return nullptr;
a7ad6e4e 946
5a4684b6 947 name = X509_get_issuer_name(cert);
a7ad6e4e 948
23e6c4ae 949 ret = ssl_get_attribute(name, attribute_name);
950
00352183
AR
951 return ret;
952}
953
954const char *sslGetUserAttribute(SSL *ssl, const char *attribute_name)
955{
956 if (!ssl)
aee3523a 957 return nullptr;
00352183
AR
958
959 X509 *cert = SSL_get_peer_certificate(ssl);
960
961 const char *attr = Ssl::GetX509UserAttribute(cert, attribute_name);
962
23e6c4ae 963 X509_free(cert);
00352183
AR
964 return attr;
965}
23e6c4ae 966
00352183
AR
967const char *sslGetCAAttribute(SSL *ssl, const char *attribute_name)
968{
969 if (!ssl)
aee3523a 970 return nullptr;
00352183
AR
971
972 X509 *cert = SSL_get_peer_certificate(ssl);
973
974 const char *attr = Ssl::GetX509CAAttribute(cert, attribute_name);
975
976 X509_free(cert);
977 return attr;
a7ad6e4e 978}
979
a7ad6e4e 980const char *
981sslGetUserEmail(SSL * ssl)
982{
e6ceef10 983 return sslGetUserAttribute(ssl, "emailAddress");
a7ad6e4e 984}
4ac9968f 985
12b5040f 986SBuf
4ac9968f 987sslGetUserCertificatePEM(SSL *ssl)
988{
12b5040f 989 assert(ssl);
4ac9968f 990
12b5040f
DN
991 if (const auto cert = SSL_get_peer_certificate(ssl))
992 return Ssl::GetX509PEM(cert);
4ac9968f 993
12b5040f 994 return SBuf();
4ac9968f 995}
3d61c476 996
12b5040f 997SBuf
3d61c476 998sslGetUserCertificateChainPEM(SSL *ssl)
999{
12b5040f 1000 assert(ssl);
3d61c476 1001
12b5040f 1002 auto chain = SSL_get_peer_cert_chain(ssl);
3d61c476 1003
1004 if (!chain)
1005 return sslGetUserCertificatePEM(ssl);
1006
12b5040f 1007 Ssl::BIO_Pointer bio(BIO_new(BIO_s_mem()));
3d61c476 1008
12b5040f 1009 for (int i = 0; i < sk_X509_num(chain); ++i) {
3d61c476 1010 X509 *cert = sk_X509_value(chain, i);
12b5040f 1011 PEM_write_bio_X509(bio.get(), cert);
3d61c476 1012 }
1013
12b5040f
DN
1014 char *ptr;
1015 const auto len = BIO_get_mem_data(bio.get(), &ptr);
1016 return SBuf(ptr, len);
3d61c476 1017}
454e8283 1018
95d2589c 1019/// Create SSL context and apply ssl certificate and private key to it.
0476ec45 1020Security::ContextPointer
cf487124 1021Ssl::createSSLContext(Security::CertPointer & x509, Security::PrivateKeyPointer & pkey, Security::ServerOptions &options)
95d2589c 1022{
cf487124 1023 Security::ContextPointer ctx(options.createBlankContext());
95d2589c 1024
0476ec45
AJ
1025 if (!SSL_CTX_use_certificate(ctx.get(), x509.get()))
1026 return Security::ContextPointer();
95d2589c 1027
0476ec45
AJ
1028 if (!SSL_CTX_use_PrivateKey(ctx.get(), pkey.get()))
1029 return Security::ContextPointer();
86660d64 1030
cf487124 1031 if (!options.updateContextConfig(ctx))
0476ec45 1032 return Security::ContextPointer();
86660d64 1033
0476ec45 1034 return ctx;
95d2589c
CT
1035}
1036
0476ec45 1037Security::ContextPointer
cf487124 1038Ssl::GenerateSslContextUsingPkeyAndCertFromMemory(const char * data, Security::ServerOptions &options, bool trusted)
95d2589c 1039{
f97700a0 1040 Security::CertPointer cert;
cf487124 1041 Security::PrivateKeyPointer pkey;
96993ee0 1042 if (!readCertAndPrivateKeyFromMemory(cert, pkey, data) || !cert || !pkey)
0476ec45 1043 return Security::ContextPointer();
95d2589c 1044
cf487124 1045 Security::ContextPointer ctx(createSSLContext(cert, pkey, options));
5107d2c4 1046 if (ctx && trusted)
cf487124 1047 Ssl::chainCertificatesToSSLContext(ctx, options);
5107d2c4 1048 return ctx;
95d2589c
CT
1049}
1050
0476ec45 1051Security::ContextPointer
cf487124 1052Ssl::GenerateSslContext(CertificateProperties const &properties, Security::ServerOptions &options, bool trusted)
95d2589c 1053{
f97700a0 1054 Security::CertPointer cert;
cf487124 1055 Security::PrivateKeyPointer pkey;
96993ee0 1056 if (!generateSslCertificate(cert, pkey, properties) || !cert || !pkey)
0476ec45 1057 return Security::ContextPointer();
95d2589c 1058
cf487124 1059 Security::ContextPointer ctx(createSSLContext(cert, pkey, options));
5107d2c4 1060 if (ctx && trusted)
cf487124 1061 Ssl::chainCertificatesToSSLContext(ctx, options);
5107d2c4 1062 return ctx;
95d2589c
CT
1063}
1064
d8f0ceab 1065void
cf487124 1066Ssl::chainCertificatesToSSLContext(Security::ContextPointer &ctx, Security::ServerOptions &options)
d8f0ceab 1067{
b23f5f9c 1068 assert(ctx);
d8f0ceab 1069 // Add signing certificate to the certificates chain
51e09c08 1070 X509 *signingCert = options.signingCa.cert.get();
b23f5f9c 1071 if (SSL_CTX_add_extra_chain_cert(ctx.get(), signingCert)) {
d8f0ceab 1072 // increase the certificate lock
6f2b8700 1073 X509_up_ref(signingCert);
d8f0ceab 1074 } else {
83b053a0 1075 const auto ssl_error = ERR_get_error();
ea574635 1076 debugs(33, DBG_IMPORTANT, "WARNING: can not add signing certificate to SSL context chain: " << Security::ErrorString(ssl_error));
d8f0ceab 1077 }
51e09c08
AJ
1078
1079 for (auto cert : options.signingCa.chain) {
1080 if (SSL_CTX_add_extra_chain_cert(ctx.get(), cert.get())) {
1081 // increase the certificate lock
1082 X509_up_ref(cert.get());
1083 } else {
1084 const auto error = ERR_get_error();
1085 debugs(83, DBG_IMPORTANT, "WARNING: can not add certificate to SSL dynamic context chain: " << Security::ErrorString(error));
1086 }
1087 }
d8f0ceab
CT
1088}
1089
1090void
b23f5f9c 1091Ssl::configureUnconfiguredSslContext(Security::ContextPointer &ctx, Ssl::CertSignAlgorithm signAlgorithm,AnyP::PortCfg &port)
d8f0ceab 1092{
b23f5f9c 1093 if (ctx && signAlgorithm == Ssl::algSignTrusted)
cf487124 1094 Ssl::chainCertificatesToSSLContext(ctx, port.secure);
d8f0ceab
CT
1095}
1096
d620ae0e 1097bool
8b082ed9 1098Ssl::configureSSL(SSL *ssl, CertificateProperties const &properties, AnyP::PortCfg &)
d620ae0e 1099{
f97700a0 1100 Security::CertPointer cert;
cf487124 1101 Security::PrivateKeyPointer pkey;
d620ae0e
CT
1102 if (!generateSslCertificate(cert, pkey, properties))
1103 return false;
1104
1105 if (!cert)
1106 return false;
1107
1108 if (!pkey)
1109 return false;
1110
1111 if (!SSL_use_certificate(ssl, cert.get()))
1112 return false;
1113
1114 if (!SSL_use_PrivateKey(ssl, pkey.get()))
1115 return false;
1116
1117 return true;
1118}
1119
1120bool
8b082ed9 1121Ssl::configureSSLUsingPkeyAndCertFromMemory(SSL *ssl, const char *data, AnyP::PortCfg &)
d620ae0e 1122{
f97700a0 1123 Security::CertPointer cert;
cf487124 1124 Security::PrivateKeyPointer pkey;
d620ae0e
CT
1125 if (!readCertAndPrivateKeyFromMemory(cert, pkey, data))
1126 return false;
1127
1128 if (!cert || !pkey)
1129 return false;
1130
1131 if (!SSL_use_certificate(ssl, cert.get()))
1132 return false;
1133
1134 if (!SSL_use_PrivateKey(ssl, pkey.get()))
1135 return false;
1136
1137 return true;
1138}
1139
b23f5f9c 1140bool
8b082ed9 1141Ssl::verifySslCertificate(const Security::ContextPointer &ctx, CertificateProperties const &)
95d2589c 1142{
b8649ee4
CT
1143#if HAVE_SSL_CTX_GET0_CERTIFICATE
1144 X509 * cert = SSL_CTX_get0_certificate(ctx.get());
1145#elif SQUID_USE_SSLGETCERTIFICATE_HACK
b8658552 1146 // SSL_get_certificate is buggy in openssl versions 1.0.1d and 1.0.1e
b23f5f9c 1147 // Try to retrieve certificate directly from Security::ContextPointer object
b23f5f9c 1148 X509 ***pCert = (X509 ***)ctx->cert;
b8658552 1149 X509 * cert = pCert && *pCert ? **pCert : NULL;
fc321c30 1150#elif SQUID_SSLGETCERTIFICATE_BUGGY
a1b1756c 1151 X509 * cert = nullptr;
fc321c30 1152 assert(0);
b8658552 1153#else
95d2589c 1154 // Temporary ssl for getting X509 certificate from SSL_CTX.
c96b5508 1155 Security::SessionPointer ssl(Security::NewSessionObject(ctx));
95d2589c 1156 X509 * cert = SSL_get_certificate(ssl.get());
b8658552
CT
1157#endif
1158 if (!cert)
1159 return false;
24b30fdc
EQ
1160 const auto time_notBefore = X509_getm_notBefore(cert);
1161 const auto time_notAfter = X509_getm_notAfter(cert);
5107d2c4 1162 return (X509_cmp_current_time(time_notBefore) < 0 && X509_cmp_current_time(time_notAfter) > 0);
95d2589c
CT
1163}
1164
428819f3 1165void
253749a8
CT
1166Ssl::setClientSNI(SSL *ssl, const char *fqdn)
1167{
428819f3
RB
1168 const Ip::Address test(fqdn);
1169 if (!test.isAnyAddr())
1170 return; // raw IP is inappropriate for SNI
1171
253749a8
CT
1172 //The SSL_CTRL_SET_TLSEXT_HOSTNAME is a openssl macro which indicates
1173 // if the TLS servername extension (SNI) is enabled in openssl library.
1174#if defined(SSL_CTRL_SET_TLSEXT_HOSTNAME)
1175 if (!SSL_set_tlsext_host_name(ssl, fqdn)) {
83b053a0 1176 const auto ssl_error = ERR_get_error();
253749a8 1177 debugs(83, 3, "WARNING: unable to set TLS servername extension (SNI): " <<
ea574635 1178 Security::ErrorString(ssl_error) << "\n");
253749a8 1179 }
253749a8 1180#else
34492237 1181 debugs(83, 7, "no support for TLS servername extension (SNI)");
253749a8
CT
1182#endif
1183}
1184
800967af
CT
1185const char *
1186Ssl::findIssuerUri(X509 *cert)
55369ae6
AR
1187{
1188 AUTHORITY_INFO_ACCESS *info;
1189 if (!cert)
168d2b30 1190 return nullptr;
aee3523a 1191 info = static_cast<AUTHORITY_INFO_ACCESS *>(X509_get_ext_d2i(cert, NID_info_access, nullptr, nullptr));
55369ae6 1192 if (!info)
168d2b30 1193 return nullptr;
55369ae6
AR
1194
1195 static char uri[MAX_URL];
1196 uri[0] = '\0';
1197
1198 for (int i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++) {
1199 ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(info, i);
1200 if (OBJ_obj2nid(ad->method) == NID_ad_ca_issuers) {
1201 if (ad->location->type == GEN_URI) {
2a268a06
CT
1202 xstrncpy(uri,
1203 reinterpret_cast<const char *>(
2a268a06 1204 ASN1_STRING_get0_data(ad->location->d.uniformResourceIdentifier)
ac756c8c 1205 ),
2a268a06 1206 sizeof(uri));
55369ae6
AR
1207 }
1208 break;
1209 }
1210 }
1211 AUTHORITY_INFO_ACCESS_free(info);
168d2b30 1212 return uri[0] != '\0' ? uri : nullptr;
55369ae6
AR
1213}
1214
866be11c
CT
1215bool
1216Ssl::loadCerts(const char *certsFile, Ssl::CertsIndexedList &list)
1217{
b05c1954 1218 const BIO_Pointer in(BIO_new_file(certsFile, "r"));
866be11c 1219 if (!in) {
d816f28d 1220 debugs(83, DBG_IMPORTANT, "ERROR: Failed to open '" << certsFile << "' to load certificates");
866be11c
CT
1221 return false;
1222 }
1223
ac1b16b5 1224 while (auto aCert = ReadOptionalCertificate(in)) {
907831e6
AR
1225 const auto name = Security::SubjectName(*aCert);
1226 list.insert(std::pair<SBuf, X509 *>(name, aCert.release()));
866be11c
CT
1227 }
1228 debugs(83, 4, "Loaded " << list.size() << " certificates from file: '" << certsFile << "'");
866be11c
CT
1229 return true;
1230}
1231
6c4905ef
CT
1232/// quickly find the issuer certificate of a certificate cert in the
1233/// Ssl::CertsIndexedList list
55369ae6 1234static X509 *
6c4905ef 1235findCertIssuerFast(Ssl::CertsIndexedList &list, X509 *cert)
55369ae6 1236{
907831e6
AR
1237 const auto name = Security::IssuerName(*cert);
1238 if (name.isEmpty())
aee3523a 1239 return nullptr;
55369ae6 1240
907831e6 1241 const auto ret = list.equal_range(name);
55369ae6
AR
1242 for (Ssl::CertsIndexedList::iterator it = ret.first; it != ret.second; ++it) {
1243 X509 *issuer = it->second;
907831e6 1244 if (Security::IssuedBy(*cert, *issuer)) {
55369ae6
AR
1245 return issuer;
1246 }
1247 }
aee3523a 1248 return nullptr;
55369ae6
AR
1249}
1250
6c4905ef 1251/// slowly find the issuer certificate of a given cert using linear search
800967af
CT
1252static X509 *
1253sk_x509_findIssuer(const STACK_OF(X509) *sk, X509 *cert)
55369ae6 1254{
800967af
CT
1255 if (!sk)
1256 return nullptr;
1257
1258 const auto certCount = sk_X509_num(sk);
1259 for (int i = 0; i < certCount; ++i) {
1260 const auto issuer = sk_X509_value(sk, i);
907831e6 1261 if (Security::IssuedBy(*cert, *issuer))
800967af 1262 return issuer;
55369ae6 1263 }
800967af 1264 return nullptr;
55369ae6
AR
1265}
1266
800967af
CT
1267/// finds issuer of a given certificate in CA store of the given connContext
1268/// \returns the cert issuer (after increasing its reference count) or nil
1269static X509 *
1270findIssuerInCaDb(X509 *cert, const Security::ContextPointer &connContext)
9fdbe165
CT
1271{
1272 if (!connContext)
800967af 1273 return nullptr;
9fdbe165
CT
1274
1275 X509_STORE_CTX *storeCtx = X509_STORE_CTX_new();
1276 if (!storeCtx) {
d816f28d 1277 debugs(83, DBG_IMPORTANT, "ERROR: Failed to allocate STORE_CTX object");
800967af 1278 return nullptr;
9fdbe165
CT
1279 }
1280
800967af 1281 X509 *issuer = nullptr;
9fdbe165
CT
1282 X509_STORE *store = SSL_CTX_get_cert_store(connContext.get());
1283 if (X509_STORE_CTX_init(storeCtx, store, nullptr, nullptr)) {
800967af
CT
1284 const auto ret = X509_STORE_CTX_get1_issuer(&issuer, storeCtx, cert);
1285 if (ret > 0) {
1286 assert(issuer);
907831e6 1287 debugs(83, 5, "found " << *issuer);
800967af
CT
1288 } else {
1289 debugs(83, ret < 0 ? 2 : 3, "not found or failure: " << ret);
1290 assert(!issuer);
1291 }
9fdbe165 1292 } else {
83b053a0 1293 const auto ssl_error = ERR_get_error();
d816f28d 1294 debugs(83, DBG_IMPORTANT, "ERROR: Failed to initialize STORE_CTX object: " << Security::ErrorString(ssl_error));
9fdbe165 1295 }
800967af 1296
9fdbe165
CT
1297 X509_STORE_CTX_free(storeCtx);
1298
800967af 1299 return issuer;
9fdbe165
CT
1300}
1301
800967af
CT
1302Security::CertPointer
1303Ssl::findIssuerCertificate(X509 *cert, const STACK_OF(X509) *serverCertificates, const Security::ContextPointer &context)
55369ae6 1304{
800967af 1305 Must(cert);
55369ae6 1306
800967af
CT
1307 // check certificate chain, if any
1308 if (const auto issuer = serverCertificates ? sk_x509_findIssuer(serverCertificates, cert) : nullptr) {
1309 X509_up_ref(issuer);
1310 return Security::CertPointer(issuer);
55369ae6 1311 }
55369ae6 1312
800967af 1313 // check untrusted certificates
9e779e40 1314 if (const auto issuer = findCertIssuerFast(SquidUntrustedCerts(), cert)) {
800967af
CT
1315 X509_up_ref(issuer);
1316 return Security::CertPointer(issuer);
55369ae6 1317 }
55369ae6 1318
800967af
CT
1319 // check trusted CA certificates
1320 if (const auto issuer = findIssuerInCaDb(cert, context)) {
1321 // no X509_up_ref(issuer) because findIssuerInCaDb() ups reference count
1322 return Security::CertPointer(issuer);
55369ae6 1323 }
800967af
CT
1324
1325 return Security::CertPointer(nullptr);
55369ae6
AR
1326}
1327
800967af
CT
1328bool
1329Ssl::missingChainCertificatesUrls(std::queue<SBuf> &URIs, const STACK_OF(X509) &serverCertificates, const Security::ContextPointer &context)
a34d1d2d 1330{
800967af
CT
1331 for (int i = 0; i < sk_X509_num(&serverCertificates); ++i) {
1332 const auto cert = sk_X509_value(&serverCertificates, i);
a34d1d2d 1333
800967af
CT
1334 if (findIssuerCertificate(cert, &serverCertificates, context))
1335 continue;
1336
1337 if (const auto issuerUri = findIssuerUri(cert)) {
1338 URIs.push(SBuf(issuerUri));
1339 } else {
800967af 1340 debugs(83, 3, "Issuer certificate for " <<
907831e6 1341 *cert <<
800967af
CT
1342 " is missing and its URI is not provided");
1343 }
a34d1d2d 1344 }
800967af
CT
1345
1346 debugs(83, (URIs.empty() ? 3 : 5), "found: " << URIs.size());
1347 return !URIs.empty();
a34d1d2d
CT
1348}
1349
55369ae6
AR
1350/// add missing issuer certificates to untrustedCerts
1351static void
800967af 1352completeIssuers(X509_STORE_CTX *ctx, STACK_OF(X509) &untrustedCerts)
55369ae6 1353{
800967af 1354 debugs(83, 2, "completing " << sk_X509_num(&untrustedCerts) <<
9e779e40 1355 " OpenSSL untrusted certs using " << Ssl::SquidUntrustedCerts().size() <<
800967af 1356 " configured untrusted certificates");
55369ae6 1357
2a268a06
CT
1358 const X509_VERIFY_PARAM *param = X509_STORE_CTX_get0_param(ctx);
1359 int depth = X509_VERIFY_PARAM_get_depth(param);
800967af
CT
1360 Security::CertPointer current;
1361 current.resetAndLock(X509_STORE_CTX_get0_cert(ctx));
55369ae6
AR
1362 int i = 0;
1363 for (i = 0; current && (i < depth); ++i) {
907831e6 1364 if (Security::SelfSigned(*current)) {
55369ae6 1365 // either ctx->cert is itself self-signed or untrustedCerts
2f8abb64 1366 // already contain the self-signed current certificate
55369ae6
AR
1367 break;
1368 }
1369
1370 // untrustedCerts is short, not worth indexing
800967af
CT
1371 const Security::ContextPointer nullCtx;
1372 auto issuer = Ssl::findIssuerCertificate(current.get(), &untrustedCerts, nullCtx);
55369ae6 1373 current = issuer;
800967af
CT
1374 if (issuer)
1375 sk_X509_push(&untrustedCerts, issuer.release());
55369ae6
AR
1376 }
1377
1378 if (i >= depth)
1379 debugs(83, 2, "exceeded the maximum certificate chain length: " << depth);
1380}
1381
800967af
CT
1382/// Validates certificates while consulting sslproxy_foreign_intermediate_certs
1383/// and, optionally, the given extra certificates.
1384/// \returns whatever OpenSSL X509_verify_cert() returns
55369ae6 1385static int
800967af 1386VerifyCtxCertificates(X509_STORE_CTX *ctx, STACK_OF(X509) *extraCerts)
55369ae6 1387{
55369ae6
AR
1388 // OpenSSL already maintains ctx->untrusted but we cannot modify
1389 // internal OpenSSL list directly. We have to give OpenSSL our own
1390 // list, but it must include certificates on the OpenSSL ctx->untrusted
2a268a06 1391 STACK_OF(X509) *oldUntrusted = X509_STORE_CTX_get0_untrusted(ctx);
800967af
CT
1392 // X509_chain_up_ref() increments cert references _and_ dupes the stack
1393 Ssl::X509_STACK_Pointer untrustedCerts(oldUntrusted ? X509_chain_up_ref(oldUntrusted) : sk_X509_new_null());
1394
1395 if (extraCerts) {
1396 for (int i = 0; i < sk_X509_num(extraCerts); ++i) {
1397 const auto cert = sk_X509_value(extraCerts, i);
1398 X509_up_ref(cert);
1399 sk_X509_push(untrustedCerts.get(), cert);
1400 }
55369ae6
AR
1401 }
1402
1403 // If the local untrusted certificates internal database is used
1404 // run completeIssuers to add missing certificates if possible.
9e779e40 1405 if (Ssl::SquidUntrustedCerts().size() > 0)
800967af 1406 completeIssuers(ctx, *untrustedCerts);
55369ae6 1407
800967af 1408 X509_STORE_CTX_set0_untrusted(ctx, untrustedCerts.get()); // No locking/unlocking, just sets ctx->untrusted
55369ae6 1409 int ret = X509_verify_cert(ctx);
24b30fdc 1410 X509_STORE_CTX_set0_untrusted(ctx, oldUntrusted); // Set back the old untrusted list
55369ae6
AR
1411 return ret;
1412}
1413
800967af
CT
1414/// \interface OpenSSL_vcb_disambiguation
1415///
1416/// OpenSSL has two very different concepts with nearly identical names:
1417///
1418/// a) A (replaceable) certificate verification function -- X509_verify_cert():
1419/// This function drives the entire certificate verification algorithm.
1420/// It can be called directly, but is usually called during SSL_connect().
1421/// OpenSSL calls this function a "verification callback function".
1422/// SSL_CTX_set_cert_verify_callback(3) replaces X509_verify_cert() default.
1423///
1424/// b) An (optional) certificate verification adjustment callback:
1425/// This function, if set, is called at the end of (a) to adjust (a) results.
1426/// It is never called directly, only from (a).
1427/// OpenSSL calls this function a "verify_callback function".
1428/// The SSL_CTX_set_verify(3) family of functions sets this function.
1429
1430/// Validates certificates while consulting sslproxy_foreign_intermediate_certs
1431/// but without using any dynamically downloaded intermediate certificates.
1432/// OpenSSL "verification callback function" (\ref OpenSSL_vcb_disambiguation)
1433static int
1434untrustedToStoreCtx_cb(X509_STORE_CTX *ctx, void *)
1435{
1436 debugs(83, 4, "Try to use pre-downloaded intermediate certificates");
1437 return VerifyCtxCertificates(ctx, nullptr);
1438}
1439
55369ae6
AR
1440void
1441Ssl::useSquidUntrusted(SSL_CTX *sslContext)
1442{
aee3523a 1443 SSL_CTX_set_cert_verify_callback(sslContext, untrustedToStoreCtx_cb, nullptr);
55369ae6
AR
1444}
1445
1446bool
1447Ssl::loadSquidUntrusted(const char *path)
1448{
9e779e40 1449 return Ssl::loadCerts(path, SquidUntrustedCerts());
55369ae6
AR
1450}
1451
1452void
1453Ssl::unloadSquidUntrusted()
1454{
9e779e40
EB
1455 if (SquidUntrustedCerts().size()) {
1456 for (const auto &i: SquidUntrustedCerts()) {
1457 X509_free(i.second);
55369ae6 1458 }
9e779e40 1459 SquidUntrustedCerts().clear();
55369ae6
AR
1460 }
1461}
1462
cf487124 1463bool Ssl::generateUntrustedCert(Security::CertPointer &untrustedCert, Security::PrivateKeyPointer &untrustedPkey, Security::CertPointer const &cert, Security::PrivateKeyPointer const & pkey)
95588170
CT
1464{
1465 // Generate the self-signed certificate, using a hard-coded subject prefix
1466 Ssl::CertificateProperties certProperties;
1467 if (const char *cn = CommonHostName(cert.get())) {
1468 certProperties.commonName = "Not trusted by \"";
1469 certProperties.commonName += cn;
1470 certProperties.commonName += "\"";
87f237a9 1471 } else if (const char *org = getOrganization(cert.get())) {
95588170
CT
1472 certProperties.commonName = "Not trusted by \"";
1473 certProperties.commonName += org;
1474 certProperties.commonName += "\"";
87f237a9 1475 } else
95588170
CT
1476 certProperties.commonName = "Not trusted";
1477 certProperties.setCommonName = true;
1478 // O, OU, and other CA subject fields will be mimicked
1479 // Expiration date and other common properties will be mimicked
1480 certProperties.signAlgorithm = Ssl::algSignSelf;
1481 certProperties.signWithPkey.resetAndLock(pkey.get());
1482 certProperties.mimicCert.resetAndLock(cert.get());
1483 return Ssl::generateSslCertificate(untrustedCert, untrustedPkey, certProperties);
1484}
1485
5107d2c4
CT
1486void Ssl::InRamCertificateDbKey(const Ssl::CertificateProperties &certProperties, SBuf &key)
1487{
1488 bool origSignatureAsKey = false;
70cfe22f
AJ
1489 if (certProperties.mimicCert) {
1490 if (auto *sig = Ssl::X509_get_signature(certProperties.mimicCert)) {
5107d2c4
CT
1491 origSignatureAsKey = true;
1492 key.append((const char *)sig->data, sig->length);
1493 }
1494 }
1495
1496 if (!origSignatureAsKey || certProperties.setCommonName) {
1497 // Use common name instead
1498 key.append(certProperties.commonName.c_str());
1499 }
1500 key.append(certProperties.setCommonName ? '1' : '0');
1501 key.append(certProperties.setValidAfter ? '1' : '0');
1502 key.append(certProperties.setValidBefore ? '1' : '0');
1503 key.append(certProperties.signAlgorithm != Ssl:: algSignEnd ? certSignAlgorithm(certProperties.signAlgorithm) : "-");
1504 key.append(certProperties.signHash ? EVP_MD_name(certProperties.signHash) : "-");
1505
1506 if (certProperties.mimicCert) {
64e64225
AR
1507 Ssl::BIO_Pointer bio(BIO_new_SBuf(&key));
1508 ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509), bio.get(), (ASN1_VALUE *)certProperties.mimicCert.get());
5107d2c4
CT
1509 }
1510}
1511
1512static int
1513bio_sbuf_create(BIO* bio)
1514{
1515 BIO_set_init(bio, 0);
aee3523a 1516 BIO_set_data(bio, nullptr);
5107d2c4
CT
1517 return 1;
1518}
1519
1520static int
1521bio_sbuf_destroy(BIO* bio)
1522{
1523 if (!bio)
1524 return 0;
1525 return 1;
1526}
1527
8b082ed9 1528static int
5107d2c4
CT
1529bio_sbuf_write(BIO* bio, const char* data, int len)
1530{
1531 SBuf *buf = static_cast<SBuf *>(BIO_get_data(bio));
64e64225 1532 // TODO: Convert exceptions into BIO errors
5107d2c4
CT
1533 buf->append(data, len);
1534 return len;
1535}
1536
8b082ed9
FC
1537static int
1538bio_sbuf_puts(BIO *bio, const char *data)
5107d2c4 1539{
64e64225 1540 // TODO: use bio_sbuf_write() instead
5107d2c4
CT
1541 SBuf *buf = static_cast<SBuf *>(BIO_get_data(bio));
1542 size_t oldLen = buf->length();
1543 buf->append(data);
1544 return buf->length() - oldLen;
1545}
1546
8b082ed9
FC
1547static long
1548bio_sbuf_ctrl(BIO *bio, int cmd, long /* num */, void *)
1549{
5107d2c4
CT
1550 SBuf *buf = static_cast<SBuf *>(BIO_get_data(bio));
1551 switch (cmd) {
1552 case BIO_CTRL_RESET:
64e64225 1553 // TODO: Convert exceptions into BIO errors
5107d2c4
CT
1554 buf->clear();
1555 return 1;
1556 case BIO_CTRL_FLUSH:
1557 return 1;
1558 default:
1559 return 0;
1560 }
1561}
1562
5107d2c4
CT
1563BIO *Ssl::BIO_new_SBuf(SBuf *buf)
1564{
1565#if HAVE_LIBCRYPTO_BIO_METH_NEW
64e64225 1566 static BIO_METHOD *BioSBufMethods = nullptr;
5107d2c4
CT
1567 if (!BioSBufMethods) {
1568 BioSBufMethods = BIO_meth_new(BIO_TYPE_MEM, "Squid-SBuf");
1569 BIO_meth_set_write(BioSBufMethods, bio_sbuf_write);
1570 BIO_meth_set_read(BioSBufMethods, nullptr);
1571 BIO_meth_set_puts(BioSBufMethods, bio_sbuf_puts);
1572 BIO_meth_set_gets(BioSBufMethods, nullptr);
1573 BIO_meth_set_ctrl(BioSBufMethods, bio_sbuf_ctrl);
1574 BIO_meth_set_create(BioSBufMethods, bio_sbuf_create);
1575 BIO_meth_set_destroy(BioSBufMethods, bio_sbuf_destroy);
1576 }
1577#else
64e64225
AR
1578 static BIO_METHOD *BioSBufMethods = new BIO_METHOD({
1579 BIO_TYPE_MEM,
1580 "Squid SBuf",
1581 bio_sbuf_write,
1582 nullptr,
1583 bio_sbuf_puts,
1584 nullptr,
1585 bio_sbuf_ctrl,
1586 bio_sbuf_create,
1587 bio_sbuf_destroy,
1588 NULL
1589 });
5107d2c4 1590#endif
64e64225
AR
1591 BIO *bio = BIO_new(BioSBufMethods);
1592 Must(bio);
5107d2c4
CT
1593 BIO_set_data(bio, buf);
1594 BIO_set_init(bio, 1);
1595 return bio;
1596}
1597
cb4f4424 1598#endif /* USE_OPENSSL */
f53969cc 1599