2 * Copyright (C) 1996-2018 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"
27 // Compare function for tree search algorithms
29 aclHostDomainCompare( char *const &a
, char * const &b
)
31 const char *h
= static_cast<const char *>(a
);
32 const char *d
= static_cast<const char *>(b
);
33 debugs(28, 7, "Match:" << h
<< " <> " << d
);
34 return matchDomainName(h
, d
, mdnHonorWildcards
);
38 ACLServerNameData::match(const char *host
)
43 debugs(28, 3, "checking '" << host
<< "'");
45 char *h
= const_cast<char *>(host
);
46 char const * const * result
= domains
->find(h
, aclHostDomainCompare
);
48 debugs(28, 3, "'" << host
<< "' " << (result
? "found" : "NOT found"));
50 return (result
!= NULL
);
54 ACLData
<char const *> *
55 ACLServerNameData::clone() const
57 /* Splay trees don't clone yet. */
59 return new ACLServerNameData
;
62 /// A helper function to be used with Ssl::matchX509CommonNames().
63 /// \retval 0 when the name (cn or an alternate name) matches acl data
64 /// \retval 1 when the name does not match
65 template<class MatchType
>
67 check_cert_domain( void *check_data
, ASN1_STRING
*cn_data
)
70 ACLData
<MatchType
> * data
= (ACLData
<MatchType
> *)check_data
;
72 if (cn_data
->length
> (int)sizeof(cn
) - 1)
73 return 1; // ignore data that does not fit our buffer
75 char *s
= reinterpret_cast<char *>(cn_data
->data
);
77 for (int i
= 0; i
< cn_data
->length
; ++i
, ++d
, ++s
) {
79 return 1; // always a domain mismatch. contains 0x00
82 cn
[cn_data
->length
] = '\0';
83 debugs(28, 4, "Verifying certificate name/subjectAltName " << cn
);
90 ACLServerNameStrategy::match (ACLData
<MatchType
> * &data
, ACLFilledChecklist
*checklist
)
92 assert(checklist
!= NULL
&& checklist
->request
!= NULL
);
94 const char *serverName
= nullptr;
95 SBuf clientSniKeeper
; // because c_str() is not constant
96 if (ConnStateData
*conn
= checklist
->conn()) {
97 const char *clientRequestedServerName
= nullptr;
98 clientSniKeeper
= conn
->tlsClientSni();
99 if (clientSniKeeper
.isEmpty()) {
100 const char *host
= checklist
->request
->url
.host();
101 if (host
&& *host
) // paranoid first condition: host() is never nil
102 clientRequestedServerName
= host
;
104 clientRequestedServerName
= clientSniKeeper
.c_str();
107 X509
*peer_cert
= conn
->serverBump() ? conn
->serverBump()->serverCert
.get() : nullptr;
108 // use the client requested name if it matches the server
109 // certificate or if the certificate is not available
110 if (!peer_cert
|| Ssl::checkX509ServerValidity(peer_cert
, clientRequestedServerName
))
111 serverName
= clientRequestedServerName
;
112 } else if (useClientRequested
)
113 serverName
= clientRequestedServerName
;
114 else { // either no options or useServerProvided
115 if (X509
*peer_cert
= (conn
->serverBump() ? conn
->serverBump()->serverCert
.get() : nullptr))
116 return Ssl::matchX509CommonNames(peer_cert
, (void *)data
, check_cert_domain
<MatchType
>);
117 if (!useServerProvided
)
118 serverName
= clientRequestedServerName
;
125 return data
->match(serverName
);
129 ACLServerNameStrategy::options()
131 static const Acl::BooleanOption ClientRequested
;
132 static const Acl::BooleanOption ServerProvided
;
133 static const Acl::BooleanOption Consensus
;
134 static const Acl::Options MyOptions
= {
135 {"--client-requested", &ClientRequested
},
136 {"--server-provided", &ServerProvided
},
137 {"--consensus", &Consensus
}
140 ClientRequested
.linkWith(&useClientRequested
);
141 ServerProvided
.linkWith(&useServerProvided
);
142 Consensus
.linkWith(&useConsensus
);
147 ACLServerNameStrategy::valid() const
151 if (useClientRequested
)
153 if (useServerProvided
)
158 if (optionCount
> 1) {
159 debugs(28, DBG_CRITICAL
, "ERROR: Multiple options given for the server_name ACL");