2 * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
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.
9 /* DEBUG: section 28 Access Control */
12 #include "acl/DomainData.h"
13 #include "acl/FilledChecklist.h"
14 #include "acl/RegexData.h"
15 #include "acl/ServerName.h"
16 #include "client_side.h"
18 #include "http/Stream.h"
19 #include "HttpRequest.h"
21 #include "SquidString.h"
23 #include "ssl/ServerBump.h"
24 #include "ssl/support.h"
26 // Compare function for tree search algorithms
28 aclHostDomainCompare( char *const &a
, char * const &b
)
30 const char *h
= static_cast<const char *>(a
);
31 const char *d
= static_cast<const char *>(b
);
32 debugs(28, 7, "Match:" << h
<< " <> " << d
);
33 return matchDomainName(h
, d
, mdnHonorWildcards
);
37 ACLServerNameData::match(const char *host
)
42 debugs(28, 3, "checking '" << host
<< "'");
44 char *h
= const_cast<char *>(host
);
45 char const * const * result
= domains
->find(h
, aclHostDomainCompare
);
47 debugs(28, 3, "'" << host
<< "' " << (result
? "found" : "NOT found"));
49 return (result
!= nullptr);
53 /// A helper function to be used with Ssl::matchX509CommonNames().
54 /// \retval 0 when the name (cn or an alternate name) matches acl data
55 /// \retval 1 when the name does not match
56 template<class MatchType
>
58 check_cert_domain( void *check_data
, ASN1_STRING
*cn_data
)
61 ACLData
<MatchType
> * data
= (ACLData
<MatchType
> *)check_data
;
63 if (cn_data
->length
> (int)sizeof(cn
) - 1)
64 return 1; // ignore data that does not fit our buffer
66 char *s
= reinterpret_cast<char *>(cn_data
->data
);
68 for (int i
= 0; i
< cn_data
->length
; ++i
, ++d
, ++s
) {
70 return 1; // always a domain mismatch. contains 0x00
73 cn
[cn_data
->length
] = '\0';
74 debugs(28, 4, "Verifying certificate name/subjectAltName " << cn
);
81 ACLServerNameStrategy::match (ACLData
<MatchType
> * &data
, ACLFilledChecklist
*checklist
)
83 assert(checklist
!= nullptr && checklist
->request
!= nullptr);
85 const char *serverName
= nullptr;
86 SBuf clientSniKeeper
; // because c_str() is not constant
87 if (ConnStateData
*conn
= checklist
->conn()) {
88 const char *clientRequestedServerName
= nullptr;
89 clientSniKeeper
= conn
->tlsClientSni();
90 if (clientSniKeeper
.isEmpty()) {
91 const char *host
= checklist
->request
->url
.host();
92 if (host
&& *host
) // paranoid first condition: host() is never nil
93 clientRequestedServerName
= host
;
95 clientRequestedServerName
= clientSniKeeper
.c_str();
98 X509
*peer_cert
= conn
->serverBump() ? conn
->serverBump()->serverCert
.get() : nullptr;
99 // use the client requested name if it matches the server
100 // certificate or if the certificate is not available
101 if (!peer_cert
|| Ssl::checkX509ServerValidity(peer_cert
, clientRequestedServerName
))
102 serverName
= clientRequestedServerName
;
103 } else if (useClientRequested
)
104 serverName
= clientRequestedServerName
;
105 else { // either no options or useServerProvided
106 if (X509
*peer_cert
= (conn
->serverBump() ? conn
->serverBump()->serverCert
.get() : nullptr))
107 return Ssl::matchX509CommonNames(peer_cert
, (void *)data
, check_cert_domain
<MatchType
>);
108 if (!useServerProvided
)
109 serverName
= clientRequestedServerName
;
116 return data
->match(serverName
);
120 ACLServerNameStrategy::options()
122 static const Acl::BooleanOption
ClientRequested("--client-requested");
123 static const Acl::BooleanOption
ServerProvided("--server-provided");
124 static const Acl::BooleanOption
Consensus("--consensus");
125 static const Acl::Options MyOptions
= { &ClientRequested
, &ServerProvided
, &Consensus
};
126 ClientRequested
.linkWith(&useClientRequested
);
127 ServerProvided
.linkWith(&useServerProvided
);
128 Consensus
.linkWith(&useConsensus
);
133 ACLServerNameStrategy::valid() const
137 if (useClientRequested
)
139 if (useServerProvided
)
144 if (optionCount
> 1) {
145 debugs(28, DBG_CRITICAL
, "ERROR: Multiple options given for the server_name ACL");