2 * Copyright (C) 1996-2020 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
!= NULL
);
53 ACLData
<char const *> *
54 ACLServerNameData::clone() const
56 /* Splay trees don't clone yet. */
58 return new ACLServerNameData
;
61 /// A helper function to be used with Ssl::matchX509CommonNames().
62 /// \retval 0 when the name (cn or an alternate name) matches acl data
63 /// \retval 1 when the name does not match
64 template<class MatchType
>
66 check_cert_domain( void *check_data
, ASN1_STRING
*cn_data
)
69 ACLData
<MatchType
> * data
= (ACLData
<MatchType
> *)check_data
;
71 if (cn_data
->length
> (int)sizeof(cn
) - 1)
72 return 1; // ignore data that does not fit our buffer
74 char *s
= reinterpret_cast<char *>(cn_data
->data
);
76 for (int i
= 0; i
< cn_data
->length
; ++i
, ++d
, ++s
) {
78 return 1; // always a domain mismatch. contains 0x00
81 cn
[cn_data
->length
] = '\0';
82 debugs(28, 4, "Verifying certificate name/subjectAltName " << cn
);
89 ACLServerNameStrategy::match (ACLData
<MatchType
> * &data
, ACLFilledChecklist
*checklist
)
91 assert(checklist
!= NULL
&& checklist
->request
!= NULL
);
93 const char *serverName
= nullptr;
94 SBuf clientSniKeeper
; // because c_str() is not constant
95 if (ConnStateData
*conn
= checklist
->conn()) {
96 const char *clientRequestedServerName
= nullptr;
97 clientSniKeeper
= conn
->tlsClientSni();
98 if (clientSniKeeper
.isEmpty()) {
99 const char *host
= checklist
->request
->url
.host();
100 if (host
&& *host
) // paranoid first condition: host() is never nil
101 clientRequestedServerName
= host
;
103 clientRequestedServerName
= clientSniKeeper
.c_str();
106 X509
*peer_cert
= conn
->serverBump() ? conn
->serverBump()->serverCert
.get() : nullptr;
107 // use the client requested name if it matches the server
108 // certificate or if the certificate is not available
109 if (!peer_cert
|| Ssl::checkX509ServerValidity(peer_cert
, clientRequestedServerName
))
110 serverName
= clientRequestedServerName
;
111 } else if (useClientRequested
)
112 serverName
= clientRequestedServerName
;
113 else { // either no options or useServerProvided
114 if (X509
*peer_cert
= (conn
->serverBump() ? conn
->serverBump()->serverCert
.get() : nullptr))
115 return Ssl::matchX509CommonNames(peer_cert
, (void *)data
, check_cert_domain
<MatchType
>);
116 if (!useServerProvided
)
117 serverName
= clientRequestedServerName
;
124 return data
->match(serverName
);
128 ACLServerNameStrategy::options()
130 static const Acl::BooleanOption ClientRequested
;
131 static const Acl::BooleanOption ServerProvided
;
132 static const Acl::BooleanOption Consensus
;
133 static const Acl::Options MyOptions
= {
134 {"--client-requested", &ClientRequested
},
135 {"--server-provided", &ServerProvided
},
136 {"--consensus", &Consensus
}
139 ClientRequested
.linkWith(&useClientRequested
);
140 ServerProvided
.linkWith(&useServerProvided
);
141 Consensus
.linkWith(&useConsensus
);
146 ACLServerNameStrategy::valid() const
150 if (useClientRequested
)
152 if (useServerProvided
)
157 if (optionCount
> 1) {
158 debugs(28, DBG_CRITICAL
, "ERROR: Multiple options given for the server_name ACL");