reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
CertificateAuthenticator.cxx
Go to the documentation of this file.
1
2#if defined(HAVE_CONFIG_H)
3 #include "config.h"
4#endif
5
6#include "rutil/DnsUtil.hxx"
11#include "rutil/Logger.hxx"
13
17#include "repro/Proxy.hxx"
19#include "repro/UserStore.hxx"
23#include "rutil/ParseBuffer.hxx"
25
26#define RESIPROCATE_SUBSYSTEM resip::Subsystem::REPRO
27
28using namespace resip;
29using namespace repro;
30using namespace std;
31
33
35 Dispatcher* authRequestDispatcher,
36 resip::SipStack* stack,
37 AclStore& aclStore,
38 bool thirdPartyRequiresCertificate) :
39 Processor("CertificateAuthenticator"),
40 mAuthRequestDispatcher(authRequestDispatcher),
41 mAclStore(aclStore),
42 mThirdPartyRequiresCertificate(thirdPartyRequiresCertificate)
43{
44}
45
47 Dispatcher* authRequestDispatcher,
48 resip::SipStack* stack,
49 AclStore& aclStore,
50 bool thirdPartyRequiresCertificate,
51 CommonNameMappings& commonNameMappings) :
52 Processor("CertificateAuthenticator"),
53 mAuthRequestDispatcher(authRequestDispatcher),
54 mAclStore(aclStore),
55 mThirdPartyRequiresCertificate(thirdPartyRequiresCertificate),
56 mCommonNameMappings(commonNameMappings)
57{
58}
59
63
66{
67 DebugLog(<< "Monkey handling request: " << *this << "; reqcontext = " << rc);
68
69 Message *message = rc.getCurrentEvent();
70
71 SipMessage *sipMessage = dynamic_cast<SipMessage*>(message);
72 TlsPeerIdentityInfo *tpaInfo = dynamic_cast<TlsPeerIdentityInfo*>(message);
73 Proxy &proxy = rc.getProxy();
74
75 if (sipMessage)
76 {
77 if (sipMessage->method() == ACK ||
78 sipMessage->method() == BYE)
79 {
80 return Continue;
81 }
82
83 if (sipMessage->header(h_To).exists(p_tag))
84 {
85 // If a tag is present, the UAS will validate the
86 // tag or reject the request
87 DebugLog(<<"To-tag detected, allowing a request that claims to belong to an existing dialog");
88 return Continue;
89 }
90
91 // if there was no Proxy-Auth header already, and the request is purportedly From
92 // one of our domains, send a challenge, unless this is from a trusted node in one
93 // of "our" domains (ex: from a gateway).
94 //
95 // Note that other monkeys can still challenge the request later if needed
96 // for other reasons (for example, the StaticRoute monkey)
97 if(!sipMessage->header(h_From).isWellFormed() ||
98 sipMessage->header(h_From).isAllContacts() )
99 {
100 InfoLog(<<"Malformed From header: cannot verify against any certificate. Rejecting.");
101 rc.sendResponse(*unique_ptr<SipMessage>
102 (Helper::makeResponse(*sipMessage, 400, "Malformed From header")));
103 return SkipAllChains;
104 }
105 Uri claimedUri = sipMessage->header(h_From).uri();
106 if(sipMessage->method() == REFER && sipMessage->exists(h_ReferredBy))
107 {
108 if(!sipMessage->header(h_ReferredBy).isWellFormed() ||
109 sipMessage->header(h_ReferredBy).isAllContacts() )
110 {
111 InfoLog(<<"Malformed Referred-By header: cannot verify against any certificate. Rejecting.");
112 rc.sendResponse(*unique_ptr<SipMessage>
113 (Helper::makeResponse(*sipMessage, 400, "Malformed Referred-By header")));
114 return SkipAllChains;
115 }
116 // For REFER requests, we authenticate the Referred-By header
117 // instead of the From header
118 claimedUri = sipMessage->header(h_ReferredBy).uri();
119 }
120
121 // Get the certificate from the peer
122 if(sipMessage->isExternal() && !isSecure(sipMessage->getSource().getType()))
123 {
124 DebugLog(<<"Can't validate certificate on non-TLS connection");
125 return Continue;
126 }
127
128 const std::list<resip::Data> &peerNames = sipMessage->getTlsPeerNames();
129
130 if(isTrustedSource(peerNames))
131 {
132 DebugLog(<< "Matched trusted peer by certificate in ACL");
134 // Simulate the behavior of IsTrustedNode monkey:
136 return Continue;
137 }
138
139 if (proxy.isMyDomain(claimedUri.host()))
140 {
142 {
143 DebugLog(<<"from trusted node, skipping checks");
144 return Continue;
145 }
146 // peerNames is empty if client certificate mode is `optional'
147 // or if the message didn't come in on TLS transport
148 if(peerNames.empty())
149 {
150 DebugLog(<<"peerNames is empty, allowing the message without further inspection");
151 return Continue;
152 }
153 AsyncBool _auth = authorizedForThisIdentity(rc, peerNames, claimedUri);
154 if(_auth == True)
155 {
157 DebugLog(<<"authorized");
158 return Continue;
159 }
160 else if(_auth == Async)
161 {
162 DebugLog(<<"waiting for async authorization");
163 return WaitingForEvent;
164 }
165 DebugLog(<<"not authorized");
166 rc.sendResponse(*unique_ptr<SipMessage>
167 (Helper::makeResponse(*sipMessage, 403, "Authentication Failed for peer cert")));
168 return SkipAllChains;
169 }
170 else
171 {
172 // peerNames is empty if client certificate mode is `optional'
173 // or if the message didn't come in on TLS transport
174 if(peerNames.empty())
175 {
177 {
178 DebugLog(<<"third party requires certificate");
179 rc.sendResponse(*unique_ptr<SipMessage>
180 (Helper::makeResponse(*sipMessage, 403, "Mutual TLS required to handle that message")));
181 return SkipAllChains;
182 }
183 else
184 {
185 DebugLog(<<"third party does not require certificate, allowing the message without further inspection");
186 return Continue;
187 }
188 }
189 AsyncBool _auth = authorizedForThisIdentity(rc, peerNames, claimedUri);
190 if(_auth == True)
191 {
193 DebugLog(<<"authorized");
194 return Continue;
195 }
196 else if(_auth == Async)
197 {
198 DebugLog(<<"waiting for async authorization");
199 return WaitingForEvent;
200 }
201 DebugLog(<<"not authorized");
202 rc.sendResponse(*unique_ptr<SipMessage>
203 (Helper::makeResponse(*sipMessage, 403, "Authentication Failed for peer cert")));
204 return SkipAllChains;
205 }
206 }
207 else if (tpaInfo)
208 {
209 DebugLog(<<"handling TlsPeerIdentityInfo");
210 sipMessage = &rc.getOriginalRequest();
211 if(tpaInfo->authorized())
212 {
213 DebugLog(<<"authorized");
214 return Continue;
215 }
216 else
217 {
218 DebugLog(<<"not authorized");
219 rc.sendResponse(*unique_ptr<SipMessage>
220 (Helper::makeResponse(*sipMessage, 403, "Authentication Failed for peer cert")));
221 return SkipAllChains;
222 }
223 }
224
225 DebugLog(<<"not a recognized message type");
226 return Continue;
227}
228
229bool
230CertificateAuthenticator::isTrustedSource(const std::list<Data>& peerNames)
231{
232 return mAclStore.isTlsPeerNameTrusted(peerNames);
233}
234
237 resip::Uri &fromUri)
238{
239 Data aor = fromUri.getAorNoPort();
240 Data domain = fromUri.host();
241
242 std::list<Data>::const_iterator it = peerNames.begin();
243 for(; it != peerNames.end(); ++it)
244 {
245 const Data& i = *it;
246 if(i == aor)
247 {
248 DebugLog(<< "Matched certificate name " << i << " against full AoR " << aor);
249 return True;
250 }
251 if(i == domain)
252 {
253 DebugLog(<< "Matched certificate name " << i << " against domain " << domain);
254 return True;
255 }
256 CommonNameMappings::iterator _mapping =
257 mCommonNameMappings.find(i);
258 if(_mapping != mCommonNameMappings.end())
259 {
260 DebugLog(<< "CN mapping(s) exist for the certificate " << i);
261 PermittedFromAddresses& permitted = _mapping->second;
262 if(permitted.find(aor) != permitted.end())
263 {
264 DebugLog(<< "Matched certificate name " << i << " against full AoR " << aor << " by common name mappings");
265 return True;
266 }
267 if(permitted.find(domain) != permitted.end())
268 {
269 DebugLog(<< "Matched certificate name " << i << " against domain " << domain << " by common name mappings");
270 return True;
271 }
272 }
273 DebugLog(<< "Certificate name " << i << " doesn't match AoR " << aor << " or domain " << domain);
274 }
275
276 if(mCommonNameMappings.size() == 0)
277 {
278 DebugLog(<<"mCommonNameMappings is empty, trying database");
279 TlsPeerIdentityInfo* tpaInfo = new TlsPeerIdentityInfo(*this, context.getTransactionId(), &(context.getProxy()));
280 for(it = peerNames.begin(); it != peerNames.end(); ++it)
281 {
282 tpaInfo->peerNames().insert(*it);
283 }
284 tpaInfo->identities().insert(aor);
285 tpaInfo->identities().insert(domain);
286 std::unique_ptr<ApplicationMessage> app(tpaInfo);
288 return Async;
289 }
290
291 // catch-all: access denied
292 DebugLog(<< "message content didn't match any peer name");
293 return False;
294}
295
296void
297CertificateAuthenticator::dump(EncodeStream &os) const
298{
299 os << "CertificateAuthentication monkey" << std::endl;
300}
301
302/* ====================================================================
303 *
304 * Copyright (c) 2012 Daniel Pocock All rights reserved.
305 *
306 * Redistribution and use in source and binary forms, with or without
307 * modification, are permitted provided that the following conditions
308 * are met:
309 *
310 * 1. Redistributions of source code must retain the above copyright
311 * notice, this list of conditions and the following disclaimer.
312 *
313 * 2. Redistributions in binary form must reproduce the above copyright
314 * notice, this list of conditions and the following disclaimer in
315 * the documentation and/or other materials provided with the
316 * distribution.
317 *
318 * 3. Neither the name of the author(s) nor the names of any contributors
319 * may be used to endorse or promote products derived from this software
320 * without specific prior written permission.
321 *
322 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
323 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
324 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
325 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
326 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
327 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
328 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
329 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
330 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
332 * SUCH DAMAGE.
333 *
334 * ====================================================================
335 *
336 */
#define DebugLog(args_)
Definition Logger.hxx:128
#define InfoLog(args_)
Definition Logger.hxx:131
bool isTlsPeerNameTrusted(const std::list< resip::Data > &tlsPeerNames)
Definition AclStore.cxx:497
static resip::KeyValueStore::Key mCertificateVerifiedKey
resip::CommonNameMappings mCommonNameMappings
bool isTrustedSource(const std::list< resip::Data > &peerNames)
resip::AsyncBool authorizedForThisIdentity(RequestContext &context, const std::list< resip::Data > &peerNames, resip::Uri &fromUri)
virtual processor_action_t process(RequestContext &)
virtual void dump(EncodeStream &os) const
CertificateAuthenticator(ProxyConfig &config, resip::Dispatcher *authRequestDispatcher, resip::SipStack *stack, AclStore &aclStore, bool thirdPartyRequiresCertificate=true)
static resip::KeyValueStore::Key mFromTrustedNodeKey
static resip::KeyValueStore::Key allocateRequestKeyValueStoreKey()
Definition Proxy.cxx:58
resip::SipMessage & getOriginalRequest()
Returns the SipMessage associated with the server transaction.
resip::Message * getCurrentEvent()
Returns the event that we are currently working on.
void sendResponse(resip::SipMessage &response)
resip::KeyValueStore & getKeyValueStore()
resip::Data getTransactionId() const
const std::set< resip::Data > & identities() const
const std::set< resip::Data > & peerNames() const
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
const char * begin() const noexcept
Returns a pointer to the beginning of the buffer used by the Data.
Definition Data.hxx:642
A generic thread-bank class.
virtual bool post(std::unique_ptr< resip::ApplicationMessage > &work)
Posts a message to this thread bank.
static void makeResponse(SipMessage &response, const SipMessage &request, int responseCode, const Data &reason=Data::Empty, const Data &hostname=Data::Empty, const Data &warning=Data::Empty)
Make a response to a provided request.
Definition Helper.cxx:412
void setBoolValue(Key key, bool value)
const bool & getBoolValue(Key key) const
bool isWellFormed() const
Returns true iff this element was parsed successfully, according to the implementation of parse().
The base-class used for message-passing.
Definition Message.hxx:21
const Uri & uri() const
Represents a SIP message.
const std::list< Data > & getTlsPeerNames() const
const RequestLine & header(const RequestLineType &l) const
Returns the RequestLine. This is only valid for request messages.
bool exists(const HeaderBase &headerType) const
Returns true if the given header field is present, false otherwise.
const Tuple & getSource() const
Returns the source tuple that the message was received from only makes sense for messages received fr...
bool isExternal() const
Check if SipMessage is to be treated as it came off the wire.
resip::MethodTypes method() const
returns the method type of the message
This is the primary point of interaction between the app-layer and the stack.
Definition SipStack.hxx:160
bool isMyDomain(const Data &domain) const
Returns true iff domain matches one of the domains that this TransactionUser is responsible for.
TransportType getType() const
Definition Tuple.hxx:122
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
Definition Uri.hxx:22
Data getAorNoPort() const
Definition Uri.cxx:1087
Data & host()
Definition Uri.hxx:40
This Class is used to implement a primitive form of RPC using loose XML formatting.
dcm! – add UnusedChecking(_enum) below;
std::map< Data, PermittedFromAddresses > CommonNameMappings
bool isSecure(TransportType type)
Returns true if passed in transport type is a secure transport protocol.
std::set< Data > PermittedFromAddresses