]> git.ipfire.org Git - thirdparty/squid.git/blob - src/acl/ServerName.cc
55fa787d3b9554583bd021b63b7db5226ce0f22e
[thirdparty/squid.git] / src / acl / ServerName.cc
1 /*
2 * Copyright (C) 1996-2022 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 28 Access Control */
10
11 #include "squid.h"
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"
17 #include "fde.h"
18 #include "http/Stream.h"
19 #include "HttpRequest.h"
20 #include "ipcache.h"
21 #include "SquidString.h"
22 #include "ssl/bio.h"
23 #include "ssl/ServerBump.h"
24 #include "ssl/support.h"
25
26 // Compare function for tree search algorithms
27 static int
28 aclHostDomainCompare( char *const &a, char * const &b)
29 {
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);
34 }
35
36 bool
37 ACLServerNameData::match(const char *host)
38 {
39 if (host == nullptr)
40 return 0;
41
42 debugs(28, 3, "checking '" << host << "'");
43
44 char *h = const_cast<char *>(host);
45 char const * const * result = domains->find(h, aclHostDomainCompare);
46
47 debugs(28, 3, "'" << host << "' " << (result ? "found" : "NOT found"));
48
49 return (result != nullptr);
50
51 }
52
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>
57 int
58 check_cert_domain( void *check_data, ASN1_STRING *cn_data)
59 {
60 char cn[1024];
61 ACLData<MatchType> * data = (ACLData<MatchType> *)check_data;
62
63 if (cn_data->length > (int)sizeof(cn) - 1)
64 return 1; // ignore data that does not fit our buffer
65
66 char *s = reinterpret_cast<char *>(cn_data->data);
67 char *d = cn;
68 for (int i = 0; i < cn_data->length; ++i, ++d, ++s) {
69 if (*s == '\0')
70 return 1; // always a domain mismatch. contains 0x00
71 *d = *s;
72 }
73 cn[cn_data->length] = '\0';
74 debugs(28, 4, "Verifying certificate name/subjectAltName " << cn);
75 if (data->match(cn))
76 return 0;
77 return 1;
78 }
79
80 int
81 ACLServerNameStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist)
82 {
83 assert(checklist != nullptr && checklist->request != nullptr);
84
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;
94 } else
95 clientRequestedServerName = clientSniKeeper.c_str();
96
97 if (useConsensus) {
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;
110 }
111 }
112
113 if (!serverName)
114 serverName = "none";
115
116 return data->match(serverName);
117 }
118
119 const Acl::Options &
120 ACLServerNameStrategy::options()
121 {
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);
129 return MyOptions;
130 }
131
132 bool
133 ACLServerNameStrategy::valid() const
134 {
135 int optionCount = 0;
136
137 if (useClientRequested)
138 optionCount++;
139 if (useServerProvided)
140 optionCount++;
141 if (useConsensus)
142 optionCount++;
143
144 if (optionCount > 1) {
145 debugs(28, DBG_CRITICAL, "ERROR: Multiple options given for the server_name ACL");
146 return false;
147 }
148 return true;
149 }
150