reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
TlsPeerAuthManager.cxx
Go to the documentation of this file.
1#include "rutil/ResipAssert.h"
2
9#include "rutil/Logger.hxx"
11
12#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
13
14using namespace resip;
15using namespace std;
16
17TlsPeerAuthManager::TlsPeerAuthManager(DialogUsageManager& dum, TargetCommand::Target& target, const std::set<Data>& trustedPeers, bool thirdPartyRequiresCertificate) :
18 DumFeature(dum, target),
19 mTrustedPeers(trustedPeers),
20 mThirdPartyRequiresCertificate(thirdPartyRequiresCertificate)
21{
22}
23
24TlsPeerAuthManager::TlsPeerAuthManager(DialogUsageManager& dum, TargetCommand::Target& target, const std::set<Data>& trustedPeers, bool thirdPartyRequiresCertificate, CommonNameMappings& commonNameMappings) :
25 DumFeature(dum, target),
26 mTrustedPeers(trustedPeers),
27 mThirdPartyRequiresCertificate(thirdPartyRequiresCertificate),
28 mCommonNameMappings(commonNameMappings)
29{
30}
31
33{
34 InfoLog(<< "~TlsPeerAuthManager: " << mMessages.size() << " messages in memory when destroying.");
35}
36
37// !bwc! We absolutely, positively, MUST NOT throw here. This is because in
38// DialogUsageManager::process(), we do not know if a DumFeature has taken
39// ownership of msg until we get a return. If we throw, the ownership of msg
40// is unknown. This is unacceptable.
43{
44 SipMessage* sipMessage = dynamic_cast<SipMessage*>(msg);
45 TlsPeerIdentityInfoMessage* tpiMessage = dynamic_cast<TlsPeerIdentityInfoMessage*>(msg);
46
47 if (sipMessage)
48 {
50 switch ( handle(sipMessage) )
51 {
53 InfoLog(<< "TlsPeerAuth rejected request " << sipMessage->brief());
57 default: // includes Authorized, Skipped
59 }
60 }
61
62 if (tpiMessage)
63 {
64 Message* result = handleTlsPeerIdentityInfo(tpiMessage);
65 if (result)
66 {
67 postCommand(unique_ptr<Message>(result));
69 }
70 else
71 {
72 InfoLog(<< "TlsPeerAuth rejected request " << *tpiMessage);
74 }
75 }
76
77 // Catch-all (handles something that was not a SipMessage)
78 return FeatureDone;
79}
80
83 const Data& transactionId,
84 const std::list<resip::Data> &peerNames,
85 resip::Uri &fromUri)
86{
87 Data aor = fromUri.getAorNoPort();
88 Data domain = fromUri.host();
89
90 std::list<Data>::const_iterator it = peerNames.begin();
91 for(; it != peerNames.end(); ++it)
92 {
93 const Data& i = *it;
94 if(i == aor)
95 {
96 DebugLog(<< "Matched certificate name " << i << " against full AoR " << aor);
97 return True;
98 }
99 if(i == domain)
100 {
101 DebugLog(<< "Matched certificate name " << i << " against domain " << domain);
102 return True;
103 }
104 CommonNameMappings::iterator _mapping =
105 mCommonNameMappings.find(i);
106 if(_mapping != mCommonNameMappings.end())
107 {
108 DebugLog(<< "CN mapping(s) exist for the certificate " << i);
109 PermittedFromAddresses& permitted = _mapping->second;
110 if(permitted.find(aor) != permitted.end())
111 {
112 DebugLog(<< "Matched certificate name " << i << " against full AoR " << aor << " by common name mappings");
113 return True;
114 }
115 if(permitted.find(domain) != permitted.end())
116 {
117 DebugLog(<< "Matched certificate name " << i << " against domain " << domain << " by common name mappings");
118 return True;
119 }
120 }
121 DebugLog(<< "Certificate name " << i << " doesn't match AoR " << aor << " or domain " << domain);
122 }
123
124 if (mCommonNameMappings.empty())
125 {
126 DebugLog(<<"mCommonNameMappings is empty, trying async");
127 TlsPeerIdentityInfoMessage* tpaInfo = new TlsPeerIdentityInfoMessage(transactionId, &mDum);
128 for(it = peerNames.begin(); it != peerNames.end(); ++it)
129 {
130 tpaInfo->peerNames().insert(*it);
131 }
132 tpaInfo->identities().insert(aor);
133 tpaInfo->identities().insert(domain);
134 return asyncLookup(tpaInfo);
135 }
136
137 // catch-all: access denied
138 DebugLog(<< "message content didn't match any peer name");
139 return False;
140}
141
142// return true if request has been consumed
145{
146 //InfoLog( << "trying to do auth" );
147 if (!sipMessage->isRequest() ||
148 sipMessage->header(h_RequestLine).method() == ACK ||
149 sipMessage->header(h_RequestLine).method() == CANCEL)
150 {
151 // Do not inspect ACKs or CANCELs
152 return Skipped;
153 }
154
155 if(!sipMessage->header(h_From).isWellFormed() ||
156 sipMessage->header(h_From).isAllContacts() )
157 {
158 InfoLog(<<"Malformed From header: cannot verify against any certificate. Rejecting.");
159 auto response = std::make_shared<SipMessage>();
160 Helper::makeResponse(*response, *sipMessage, 400, "Malformed From header");
161 mDum.send(response);
162 return Rejected;
163 }
164 Uri claimedUri = sipMessage->header(h_From).uri();
165 if(sipMessage->method() == REFER && sipMessage->exists(h_ReferredBy))
166 {
167 if(!sipMessage->header(h_ReferredBy).isWellFormed() ||
168 sipMessage->header(h_ReferredBy).isAllContacts() )
169 {
170 InfoLog(<<"Malformed Referred-By header: cannot verify against any certificate. Rejecting.");
171 auto response = std::make_shared<SipMessage>();
172 Helper::makeResponse(*response, *sipMessage, 400, "Malformed Referred-By header");
173 mDum.send(response);
174 return Rejected;
175 }
176 // For REFER requests, we authenticate the Referred-By header
177 // instead of the From header
178 claimedUri = sipMessage->header(h_ReferredBy).uri();
179 }
180
181 // We are only concerned with connections over TLS
182 if(!sipMessage->isExternal() || !isSecure(sipMessage->getSource().getType()))
183 {
184 DebugLog(<<"Can't validate certificate on non-TLS connection");
185 return Skipped;
186 }
187
188 if(isTrustedSource(*sipMessage))
189 {
190 DebugLog(<<"from trusted node, skipping checks");
191 return Authorized;
192 }
193
194 const std::list<resip::Data> &peerNames = sipMessage->getTlsPeerNames();
195 if (mDum.isMyDomain(claimedUri.host()))
196 {
197 // peerNames is empty if client certificate mode is `optional'
198 // or if the message didn't come in on TLS transport
199 if (!requiresAuthorization(*sipMessage))
200 {
201 DebugLog(<<"authorization not required for this message");
202 return Skipped;
203 }
204
205 if(peerNames.empty())
206 {
207 DebugLog(<<"peerNames is empty, allowing the message without further inspection");
208 return Skipped;
209 }
210
211 AsyncBool _auth = authorizedForThisIdentity(sipMessage->getTransactionId(), peerNames, claimedUri);
212 if(_auth == True)
213 {
214 DebugLog(<<"authorized");
215 return Authorized;
216 }
217 else if(_auth == Async)
218 {
219 mMessages[sipMessage->getTransactionId()] = sipMessage;
220 DebugLog(<<"waiting for async authorization");
221 return RequestedInfo;
222 }
223 DebugLog(<<"not authorized");
224 auto response = std::make_shared<SipMessage>();
225 Helper::makeResponse(*response, *sipMessage, 403, "Authorization Failed for peer cert");
226 mDum.send(response);
227 return Rejected;
228 }
229 else
230 {
231 // peerNames is empty if client certificate mode is `optional'
232 // or if the message didn't come in on TLS transport
233 if(peerNames.empty())
234 {
235 if(mThirdPartyRequiresCertificate)
236 {
237 DebugLog(<<"third party requires certificate");
238 auto response = std::make_shared<SipMessage>();
239 Helper::makeResponse(*response, *sipMessage, 403, "Mutual TLS required to handle that message");
240 mDum.send(response);
241 return Rejected;
242 }
243 else
244 {
245 DebugLog(<<"third party does not require certificate, allowing the message without further inspection");
246 return Skipped;
247 }
248 }
249 AsyncBool _auth = authorizedForThisIdentity(sipMessage->getTransactionId(), peerNames, claimedUri);
250 if(_auth == True)
251 {
252 DebugLog(<<"authorized");
253 return Authorized;
254 }
255 else if(_auth == Async)
256 {
257 mMessages[sipMessage->getTransactionId()] = sipMessage;
258 DebugLog(<<"waiting for async authorization");
259 return RequestedInfo;
260 }
261 DebugLog(<<"not authorized");
262 auto response = std::make_shared<SipMessage>();
263 Helper::makeResponse(*response, *sipMessage, 403, "Authorization Failed for peer cert");
264 mDum.send(response);
265 return Rejected;
266 }
267
268 InfoLog(<< "Skipping some message that we didn't explicitly handle");
269 return Skipped;
270}
271
274{
275 resip_assert(tpiInfo);
276
277 MessageMap::iterator it = mMessages.find(tpiInfo->getTransactionId());
278 resip_assert(it != mMessages.end());
279 SipMessage* request = it->second;
280 mMessages.erase(it);
281
282 if(tpiInfo->authorized())
283 {
284 DebugLog(<<"authorized");
285 return request;
286 }
287
288 DebugLog(<<"not authorized");
289 auto response = std::make_shared<SipMessage>();
290 Helper::makeResponse(*response, *request, 403, "Authentication Failed for peer cert.");
291 mDum.send(response);
292 delete request;
293 return 0;
294}
295
298{
299 delete info;
300 return False;
301}
302
303bool
305{
306 // everything must be authorized, over-ride this method
307 // to implement some other policy
308 return true;
309}
310
311bool
313{
314 // over-ride this method to implement some other policy
315
316 const std::list<resip::Data> &peerNames = msg.getTlsPeerNames();
317 std::list<Data>::const_iterator it = peerNames.begin();
318 for(; it != peerNames.end(); ++it)
319 {
320 const Data& i = *it;
321 if(mTrustedPeers.find(i) != mTrustedPeers.end())
322 {
323 DebugLog(<< "Matched certificate name " << i << " is a trusted peer");
324 return true;
325 }
326 }
327
328 return false;
329}
330
331/* ====================================================================
332 *
333 * Copyright (c) 2012 Daniel Pocock All rights reserved.
334 *
335 * Redistribution and use in source and binary forms, with or without
336 * modification, are permitted provided that the following conditions
337 * are met:
338 *
339 * 1. Redistributions of source code must retain the above copyright
340 * notice, this list of conditions and the following disclaimer.
341 *
342 * 2. Redistributions in binary form must reproduce the above copyright
343 * notice, this list of conditions and the following disclaimer in
344 * the documentation and/or other materials provided with the
345 * distribution.
346 *
347 * 3. Neither the name of the author(s) nor the names of any contributors
348 * may be used to endorse or promote products derived from this software
349 * without specific prior written permission.
350 *
351 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS "AS IS" AND
352 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
353 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
354 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
355 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
356 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
357 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
358 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
359 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
360 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361 * SUCH DAMAGE.
362 *
363 * ====================================================================
364 *
365 */
#define DebugLog(args_)
Definition Logger.hxx:128
#define InfoLog(args_)
Definition Logger.hxx:131
#define resip_assert(x)
This file needs to work for both C and C++ code.
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
void send(std::shared_ptr< SipMessage > request)
virtual const Data & getTransactionId() const
DialogUsageManager & mDum
virtual void postCommand(std::unique_ptr< Message > message)
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
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
virtual Brief brief() const
return a facet for brief encoding of message
Definition Message.cxx:16
const Uri & uri() const
MethodTypes & method()
Represents a SIP message.
const std::list< Data > & getTlsPeerNames() const
bool isRequest() const
Returns true if message is a request, false otherwise.
const RequestLine & header(const RequestLineType &l) const
Returns the RequestLine. This is only valid for request messages.
virtual const Data & getTransactionId() const
Returns the transaction id from the branch or if 2543, the computed hash.
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
virtual bool isTrustedSource(const SipMessage &msg)
should return true if the request should be trusted based on the source/transport default implementat...
virtual ProcessingResult process(Message *msg)
virtual AsyncBool asyncLookup(TlsPeerIdentityInfoMessage *info)
virtual SipMessage * handleTlsPeerIdentityInfo(TlsPeerIdentityInfoMessage *tpiInfo)
TlsPeerAuthManager(DialogUsageManager &dum, TargetCommand::Target &target, const std::set< Data > &trustedPeers, bool thirdPartyRequiresCertificate=true)
virtual bool requiresAuthorization(const SipMessage &msg)
should return true if the request must be challenged The default is to challenge all requests - overr...
virtual AsyncBool authorizedForThisIdentity(const resip::Data &transactionId, const std::list< resip::Data > &peerNames, resip::Uri &fromUri)
should return true if the passed in user is authorized for the provided uri
virtual Result handle(SipMessage *sipMsg)
const std::set< resip::Data > & identities() const
const std::set< resip::Data > & peerNames() const
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
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
RequestLineType h_RequestLine
Definition Headers.cxx:347