/[resiprocate]/main/resip/stack/Helper.cxx
ViewVC logotype

Contents of /main/resip/stack/Helper.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 5415 - (show annotations) (download)
Thu Sep 15 12:57:21 2005 UTC (14 years, 4 months ago) by sgodin
File size: 55067 byte(s)
fix for setting correct reason text for NIT responses
1 #if defined(HAVE_CONFIG_H)
2 #include "resip/stack/config.hxx"
3 #endif
4
5 #include <string.h>
6 #include <iomanip>
7 #include <algorithm>
8 #include <memory>
9
10 #include "resip/stack/Auth.hxx"
11 #include "resip/stack/Helper.hxx"
12 #include "rutil/Coders.hxx"
13 #include "resip/stack/Uri.hxx"
14 #include "rutil/Logger.hxx"
15 #include "rutil/Random.hxx"
16 #include "rutil/Timer.hxx"
17 #include "rutil/DataStream.hxx"
18 #include "rutil/MD5Stream.hxx"
19 #include "rutil/DnsUtil.hxx"
20 #include "rutil/compat.hxx"
21 #include "rutil/ParseBuffer.hxx"
22 #include "resip/stack/SipMessage.hxx"
23 #include "resip/stack/Security.hxx"
24 //#include "resip/stack/SecurityAttributes.hxx"
25 //#include "resip/stack/Contents.hxx"
26 #include "resip/stack/Pkcs7Contents.hxx"
27 #include "resip/stack/MultipartSignedContents.hxx"
28 #include "resip/stack/MultipartMixedContents.hxx"
29 #include "resip/stack/MultipartAlternativeContents.hxx"
30 #include "rutil/WinLeakCheck.hxx"
31
32 using namespace resip;
33 using namespace std;
34
35 #define RESIPROCATE_SUBSYSTEM Subsystem::SIP
36
37 const int Helper::tagSize = 4;
38
39 SipMessage*
40 Helper::makeRequest(const NameAddr& target, const NameAddr& from, const NameAddr& contact, MethodTypes method)
41 {
42 SipMessage* request = new SipMessage;
43 RequestLine rLine(method);
44 rLine.uri() = target.uri();
45 request->header(h_To) = target;
46 request->header(h_RequestLine) = rLine;
47 request->header(h_MaxForwards).value() = 70;
48 request->header(h_CSeq).method() = method;
49 request->header(h_CSeq).sequence() = 1;
50 request->header(h_From) = from;
51 request->header(h_From).param(p_tag) = Helper::computeTag(Helper::tagSize);
52 request->header(h_Contacts).push_back(contact);
53 request->header(h_CallId).value() = Helper::computeCallId();
54 //request->header(h_ContentLength).value() = 0;
55
56 Via via;
57 request->header(h_Vias).push_back(via);
58
59 return request;
60 }
61
62 SipMessage*
63 Helper::makeRequest(const NameAddr& target, const NameAddr& from, MethodTypes method)
64 {
65 NameAddr contact;
66 return makeRequest(target, from, contact, method);
67 }
68
69 SipMessage*
70 Helper::makeRegister(const NameAddr& to, const NameAddr& from)
71 {
72 NameAddr contact;
73 return makeRegister(to, from, contact);
74 }
75
76 SipMessage*
77 Helper::makeRegister(const NameAddr& to, const NameAddr& from, const NameAddr& contact)
78 {
79 SipMessage* request = new SipMessage;
80 RequestLine rLine(REGISTER);
81
82 rLine.uri().scheme() = to.uri().scheme();
83 rLine.uri().host() = to.uri().host();
84 rLine.uri().port() = to.uri().port();
85 if (to.uri().exists(p_transport))
86 {
87 rLine.uri().param(p_transport) = to.uri().param(p_transport);
88 }
89
90 request->header(h_To) = to;
91 request->header(h_RequestLine) = rLine;
92 request->header(h_MaxForwards).value() = 70;
93 request->header(h_CSeq).method() = REGISTER;
94 request->header(h_CSeq).sequence() = 1;
95 request->header(h_From) = from;
96 request->header(h_From).param(p_tag) = Helper::computeTag(Helper::tagSize);
97 request->header(h_CallId).value() = Helper::computeCallId();
98 assert(!request->exists(h_Contacts) || request->header(h_Contacts).empty());
99 request->header(h_Contacts).push_back( contact );
100
101 Via via;
102 request->header(h_Vias).push_back(via);
103
104 return request;
105 }
106
107 SipMessage*
108 Helper::makeRegister(const NameAddr& to,const Data& transport)
109 {
110 NameAddr contact;
111 return makeRegister(to, transport, contact);
112
113 }
114
115 SipMessage*
116 Helper::makeRegister(const NameAddr& to, const Data& transport, const NameAddr& contact)
117 {
118 SipMessage* request = new SipMessage;
119 RequestLine rLine(REGISTER);
120
121 rLine.uri().scheme() = to.uri().scheme();
122 rLine.uri().host() = to.uri().host();
123 rLine.uri().port() = to.uri().port();
124 if (!transport.empty())
125 {
126 rLine.uri().param(p_transport) = transport;
127 }
128
129 request->header(h_To) = to;
130 request->header(h_RequestLine) = rLine;
131 request->header(h_MaxForwards).value() = 70;
132 request->header(h_CSeq).method() = REGISTER;
133 request->header(h_CSeq).sequence() = 1;
134 request->header(h_From) = to;
135 request->header(h_From).param(p_tag) = Helper::computeTag(Helper::tagSize);
136 request->header(h_CallId).value() = Helper::computeCallId();
137 assert(!request->exists(h_Contacts) || request->header(h_Contacts).empty());
138 request->header(h_Contacts).push_back( contact );
139
140 Via via;
141 request->header(h_Vias).push_back(via);
142
143 return request;
144 }
145
146
147 SipMessage*
148 Helper::makePublish(const NameAddr& target, const NameAddr& from)
149 {
150 NameAddr contact;
151 return makePublish(target, from, contact);
152 }
153
154 SipMessage*
155 Helper::makePublish(const NameAddr& target, const NameAddr& from, const NameAddr& contact)
156 {
157 SipMessage* request = new SipMessage;
158 RequestLine rLine(PUBLISH);
159 rLine.uri() = target.uri();
160
161 request->header(h_To) = target;
162 request->header(h_RequestLine) = rLine;
163 request->header(h_MaxForwards).value() = 70;
164 request->header(h_CSeq).method() = PUBLISH;
165 request->header(h_CSeq).sequence() = 1;
166 request->header(h_From) = from;
167 request->header(h_From).param(p_tag) = Helper::computeTag(Helper::tagSize);
168 request->header(h_CallId).value() = Helper::computeCallId();
169 assert(!request->exists(h_Contacts) || request->header(h_Contacts).empty());
170 request->header(h_Contacts).push_back( contact );
171 Via via;
172 request->header(h_Vias).push_back(via);
173
174 return request;
175 }
176
177 SipMessage*
178 Helper::makeMessage(const NameAddr& target, const NameAddr& from)
179 {
180 NameAddr contact;
181 return makeMessage(target, from, contact);
182 }
183
184 SipMessage*
185 Helper::makeMessage(const NameAddr& target, const NameAddr& from, const NameAddr& contact)
186 {
187 SipMessage* request = new SipMessage;
188 RequestLine rLine(MESSAGE);
189 rLine.uri() = target.uri();
190
191 request->header(h_To) = target;
192 request->header(h_RequestLine) = rLine;
193 request->header(h_MaxForwards).value() = 70;
194 request->header(h_CSeq).method() = MESSAGE;
195 request->header(h_CSeq).sequence() = 1;
196 request->header(h_From) = from;
197 request->header(h_From).param(p_tag) = Helper::computeTag(Helper::tagSize);
198 request->header(h_CallId).value() = Helper::computeCallId();
199 assert(!request->exists(h_Contacts) || request->header(h_Contacts).empty());
200 request->header(h_Contacts).push_back( contact );
201 Via via;
202 request->header(h_Vias).push_back(via);
203
204 return request;
205 }
206
207
208 SipMessage*
209 Helper::makeSubscribe(const NameAddr& target, const NameAddr& from)
210 {
211 NameAddr contact;
212 return makeSubscribe(target, from, contact);
213 }
214
215 SipMessage*
216 Helper::makeSubscribe(const NameAddr& target, const NameAddr& from, const NameAddr& contact)
217 {
218 SipMessage* request = new SipMessage;
219 RequestLine rLine(SUBSCRIBE);
220 rLine.uri() = target.uri();
221
222 request->header(h_To) = target;
223 request->header(h_RequestLine) = rLine;
224 request->header(h_MaxForwards).value() = 70;
225 request->header(h_CSeq).method() = SUBSCRIBE;
226 request->header(h_CSeq).sequence() = 1;
227 request->header(h_From) = from;
228 request->header(h_From).param(p_tag) = Helper::computeTag(Helper::tagSize);
229 request->header(h_CallId).value() = Helper::computeCallId();
230 assert(!request->exists(h_Contacts) || request->header(h_Contacts).empty());
231 request->header(h_Contacts).push_front( contact );
232 Via via;
233 request->header(h_Vias).push_front(via);
234
235 return request;
236 }
237
238 int
239 Helper::jitterValue(int input, int lowerPercentage, int upperPercentage, int minimum)
240 {
241 assert(upperPercentage >= lowerPercentage);
242 if (input < minimum)
243 {
244 return input;
245 }
246 else if (lowerPercentage == 100 && upperPercentage == 100)
247 {
248 return input;
249 }
250 else
251 {
252 const int rnd = Random::getRandom() % (upperPercentage-lowerPercentage) + lowerPercentage;
253 return (input * rnd) / 100;
254 }
255 }
256
257 SipMessage*
258 Helper::makeInvite(const NameAddr& target, const NameAddr& from)
259 {
260 return Helper::makeRequest(target, from, INVITE);
261 }
262
263 SipMessage*
264 Helper::makeInvite(const NameAddr& target, const NameAddr& from, const NameAddr& contact)
265 {
266 return Helper::makeRequest(target, from, contact, INVITE);
267 }
268
269
270 void
271 Helper::makeResponse(SipMessage& response,
272 const SipMessage& request,
273 int responseCode,
274 const NameAddr& myContact,
275 const Data& reason,
276 const Data& hostname,
277 const Data& warning)
278 {
279 makeResponse(response,request, responseCode, reason,hostname, warning);
280 // in general, this should not create a Contact header since only requests
281 // that create a dialog (or REGISTER requests) should produce a response with
282 // a contact(s).
283 response.header(h_Contacts).clear();
284 response.header(h_Contacts).push_back(myContact);
285 }
286
287
288 void
289 Helper::makeResponse(SipMessage& response,
290 const SipMessage& request,
291 int responseCode,
292 const Data& reason,
293 const Data& hostname,
294 const Data& warning)
295 {
296 DebugLog(<< "Helper::makeResponse(" << request.brief() << " code=" << responseCode << " reason=" << reason);
297 response.header(h_StatusLine).responseCode() = responseCode;
298 response.header(h_From) = request.header(h_From);
299 response.header(h_To) = request.header(h_To);
300 response.header(h_CallId) = request.header(h_CallId);
301 response.header(h_CSeq) = request.header(h_CSeq);
302 response.header(h_Vias) = request.header(h_Vias);
303
304 if (!warning.empty())
305 {
306 WarningCategory warn;
307 warn.code() = 499;
308 warn.hostname() = hostname;
309 warn.text() = warning;
310 response.header(h_Warnings).push_back(warn);
311 }
312
313 // Only generate a To: tag if one doesn't exist. Think Re-INVITE.
314 // No totag for failure responses or 100s
315 if (!response.header(h_To).exists(p_tag) && responseCode > 100)
316 {
317 response.header(h_To).param(p_tag) = Helper::computeTag(Helper::tagSize);
318 }
319
320 response.setRFC2543TransactionId(request.getRFC2543TransactionId());
321 //response.header(h_ContentLength).value() = 0;
322
323 if (responseCode >= 180 && responseCode < 300 && request.exists(h_RecordRoutes))
324 {
325 response.header(h_RecordRoutes) = request.header(h_RecordRoutes);
326 }
327
328 if (responseCode/100 == 2)
329 {
330 // in general, this should not create a Contact header since only requests
331 // that create a dialog (or REGISTER requests) should produce a response with
332 // a contact(s).
333
334 NameAddr contact;
335 response.header(h_Contacts).push_back(contact);
336 }
337
338 if (request.isExternal())
339 {
340 response.setFromTU();
341 }
342 else
343 {
344 response.setFromExternal();
345 }
346
347 if (reason.size())
348 {
349 response.header(h_StatusLine).reason() = reason;
350 }
351 else
352 {
353 getResponseCodeReason(responseCode, response.header(h_StatusLine).reason());
354 }
355 }
356
357 SipMessage*
358 Helper::makeResponse(const SipMessage& request,
359 int responseCode,
360 const NameAddr& myContact,
361 const Data& reason,
362 const Data& hostname,
363 const Data& warning)
364 {
365 SipMessage* response = new SipMessage;
366 makeResponse(*response, request, responseCode, reason, hostname, warning);
367
368 // in general, this should not create a Contact header since only requests
369 // that create a dialog (or REGISTER requests) should produce a response with
370 // a contact(s).
371 response->header(h_Contacts).clear();
372 response->header(h_Contacts).push_back(myContact);
373 return response;
374 }
375
376
377 SipMessage*
378 Helper::makeResponse(const SipMessage& request,
379 int responseCode,
380 const Data& reason,
381 const Data& hostname,
382 const Data& warning)
383 {
384 SipMessage* response = new SipMessage;
385 makeResponse(*response, request, responseCode, reason, hostname, warning);
386 return response;
387 }
388
389 void
390 Helper::getResponseCodeReason(int responseCode, Data& reason)
391 {
392 switch (responseCode)
393 {
394 case 100: reason = "Trying"; break;
395 case 180: reason = "Ringing"; break;
396 case 181: reason = "Call Is Being Forwarded"; break;
397 case 182: reason = "Queued"; break;
398 case 183: reason = "Session Progress"; break;
399 case 200: reason = "OK"; break;
400 case 202: reason = "Accepted"; break;
401 case 300: reason = "Multiple Choices"; break;
402 case 301: reason = "Moved Permanently"; break;
403 case 302: reason = "Moved Temporarily"; break;
404 case 305: reason = "Use Proxy"; break;
405 case 380: reason = "Alternative Service"; break;
406 case 400: reason = "Bad Request"; break;
407 case 401: reason = "Unauthorized"; break;
408 case 402: reason = "Payment Required"; break;
409 case 403: reason = "Forbidden"; break;
410 case 404: reason = "Not Found"; break;
411 case 405: reason = "Method Not Allowed"; break;
412 case 406: reason = "Not Acceptable"; break;
413 case 407: reason = "Proxy Authentication Required"; break;
414 case 408: reason = "Request Timeout"; break;
415 case 410: reason = "Gone"; break;
416 case 412: reason = "Precondition Failed"; break;
417 case 413: reason = "Request Entity Too Large"; break;
418 case 414: reason = "Request-URI Too Long"; break;
419 case 415: reason = "Unsupported Media Type"; break;
420 case 416: reason = "Unsupported URI Scheme"; break;
421 case 420: reason = "Bad Extension"; break;
422 case 421: reason = "Extension Required"; break;
423 case 422: reason = "Session Interval Too Small"; break;
424 case 423: reason = "Interval Too Brief"; break;
425 case 480: reason = "Temporarily Unavailable"; break;
426 case 481: reason = "Call/Transaction Does Not Exist"; break;
427 case 482: reason = "Loop Detected"; break;
428 case 483: reason = "Too Many Hops"; break;
429 case 484: reason = "Address Incomplete"; break;
430 case 485: reason = "Ambiguous"; break;
431 case 486: reason = "Busy Here"; break;
432 case 487: reason = "Request Terminated"; break;
433 case 488: reason = "Not Acceptable Here"; break;
434 case 489: reason = "Event Package Not Supported"; break;
435 case 491: reason = "Request Pending"; break;
436 case 493: reason = "Undecipherable"; break;
437 case 500: reason = "Server Internal Error"; break;
438 case 501: reason = "Not Implemented"; break;
439 case 502: reason = "Bad Gateway"; break;
440 case 503: reason = "Service Unavailable"; break;
441 case 504: reason = "Server Time-out"; break;
442 case 505: reason = "Version Not Supported"; break;
443 case 513: reason = "Message Too Large"; break;
444 case 600: reason = "Busy Everywhere"; break;
445 case 603: reason = "Decline"; break;
446 case 604: reason = "Does Not Exist Anywhere"; break;
447 case 606: reason = "Not Acceptable"; break;
448 }
449 }
450
451 SipMessage*
452 Helper::makeCancel(const SipMessage& request)
453 {
454 assert(request.isRequest());
455 assert(request.header(h_RequestLine).getMethod() == INVITE);
456 SipMessage* cancel = new SipMessage;
457
458 RequestLine rLine(CANCEL, request.header(h_RequestLine).getSipVersion());
459 rLine.uri() = request.header(h_RequestLine).uri();
460 cancel->header(h_RequestLine) = rLine;
461 cancel->header(h_To) = request.header(h_To);
462 cancel->header(h_From) = request.header(h_From);
463 cancel->header(h_CallId) = request.header(h_CallId);
464 if (request.exists(h_ProxyAuthorizations))
465 {
466 cancel->header(h_ProxyAuthorizations) = request.header(h_ProxyAuthorizations);
467 }
468 if (request.exists(h_Authorizations))
469 {
470 cancel->header(h_Authorizations) = request.header(h_Authorizations);
471 }
472
473 if (request.exists(h_Routes))
474 {
475 cancel->header(h_Routes) = request.header(h_Routes);
476 }
477
478 cancel->header(h_CSeq) = request.header(h_CSeq);
479 cancel->header(h_CSeq).method() = CANCEL;
480 cancel->header(h_Vias).push_back(request.header(h_Vias).front());
481
482 return cancel;
483 }
484
485
486 SipMessage*
487 Helper::makeFailureAck(const SipMessage& request, const SipMessage& response)
488 {
489 assert (request.header(h_Vias).size() >= 1);
490 assert (request.header(h_RequestLine).getMethod() == INVITE);
491
492 SipMessage* ack = new SipMessage;
493
494 RequestLine rLine(ACK, request.header(h_RequestLine).getSipVersion());
495 rLine.uri() = request.header(h_RequestLine).uri();
496 ack->header(h_RequestLine) = rLine;
497
498 ack->header(h_CallId) = request.header(h_CallId);
499 ack->header(h_From) = request.header(h_From);
500 ack->header(h_To) = response.header(h_To); // to get to-tag
501 ack->header(h_Vias).push_back(request.header(h_Vias).front());
502 ack->header(h_CSeq) = request.header(h_CSeq);
503 ack->header(h_CSeq).method() = ACK;
504 if (request.exists(h_Routes))
505 {
506 ack->header(h_Routes) = request.header(h_Routes);
507 }
508
509 return ack;
510 }
511
512
513 Data
514 Helper::computeUniqueBranch()
515 {
516 static const Data cookie("z9hG4bK"); // magic cookie per rfc2543bis-09
517
518 Data result(16, Data::Preallocate);
519 result += cookie;
520 result += Random::getRandomHex(4);
521 result += "C1";
522 result += Random::getRandomHex(2);
523 return result;
524 }
525
526
527 Data
528 Helper::computeCallId()
529 {
530 // !jf! need to include host as well (should cache it)
531 static Data hostname = Symbols::AT_SIGN + DnsUtil::getLocalHostName().base64encode(true);
532 return Random::getRandomHex(8) + hostname;
533 }
534
535
536 Data
537 Helper::computeTag(int numBytes)
538 {
539 return Random::getRandomHex(4);
540 }
541
542 // !jf! this should be settable by the application in case a group of apps
543 // (e.g. proxies) want to share the same secret
544 static Data privateKey("asdfklsadflkj"); // Random::getRandomHex(1));
545
546 Data
547 Helper::makeNonce(const SipMessage& request, const Data& timestamp)
548 {
549 Data nonce(100, Data::Preallocate);
550 nonce += timestamp;
551 nonce += Symbols::COLON;
552 Data noncePrivate(100, Data::Preallocate);
553 noncePrivate += timestamp;
554 noncePrivate += Symbols::COLON;
555 //!jf! don't include the Call-Id since it might not be the same.
556 //noncePrivate += request.header(h_CallId).value();
557 noncePrivate += request.header(h_From).uri().user();
558 noncePrivate += privateKey;
559 nonce += noncePrivate.md5();
560 return nonce;
561 }
562
563 Data
564 Helper::makeResponseMD5WithA1(const Data& a1,
565 const Data& method, const Data& digestUri, const Data& nonce,
566 const Data& qop, const Data& cnonce, const Data& cnonceCount,
567 const Contents* entityBody)
568 {
569 MD5Stream a2;
570 a2 << method
571 << Symbols::COLON
572 << digestUri;
573
574 if (qop == Symbols::authInt)
575 {
576 if (entityBody)
577 {
578 MD5Stream eStream;
579 eStream << *entityBody;
580 a2 << Symbols::COLON << eStream.getHex();
581 }
582 else
583 {
584 static Data noBody = MD5Stream().getHex();
585 a2 << Symbols::COLON << noBody;
586 }
587 }
588
589 MD5Stream r;
590 r << a1
591 << Symbols::COLON
592 << nonce
593 << Symbols::COLON;
594
595 if (!qop.empty())
596 {
597 r << cnonceCount
598 << Symbols::COLON
599 << cnonce
600 << Symbols::COLON
601 << qop
602 << Symbols::COLON;
603 }
604 r << a2.getHex();
605
606 return r.getHex();
607 }
608
609 //RFC 2617 3.2.2.1
610 Data
611 Helper::makeResponseMD5(const Data& username, const Data& password, const Data& realm,
612 const Data& method, const Data& digestUri, const Data& nonce,
613 const Data& qop, const Data& cnonce, const Data& cnonceCount,
614 const Contents *entity)
615 {
616 MD5Stream a1;
617 a1 << username
618 << Symbols::COLON
619 << realm
620 << Symbols::COLON
621 << password;
622 a1.flush();
623
624 return makeResponseMD5WithA1(a1.getHex(), method, digestUri, nonce, qop,
625 cnonce, cnonceCount, entity);
626 }
627
628 std::pair<Helper::AuthResult,Data>
629 Helper::advancedAuthenticateRequest(const SipMessage& request,
630 const Data& realm,
631 const Data& a1,
632 int expiresDelta)
633 {
634 Data username;
635 DebugLog(<< "Authenticating: realm=" << realm << " expires=" << expiresDelta);
636 //DebugLog(<< request);
637
638 if (request.exists(h_ProxyAuthorizations))
639 {
640 const ParserContainer<Auth>& auths = request.header(h_ProxyAuthorizations);
641 for (ParserContainer<Auth>::const_iterator i = auths.begin(); i != auths.end(); i++)
642 {
643 if (i->exists(p_realm) &&
644 i->exists(p_nonce) &&
645 i->exists(p_response) &&
646 i->param(p_realm) == realm)
647 {
648 ParseBuffer pb(i->param(p_nonce).data(), i->param(p_nonce).size());
649 if (!pb.eof() && !isdigit(*pb.position()))
650 {
651 DebugLog(<< "Invalid nonce; expected timestamp.");
652 return make_pair(BadlyFormed,username);
653 }
654 const char* anchor = pb.position();
655 pb.skipToChar(Symbols::COLON[0]);
656
657 if (pb.eof())
658 {
659 DebugLog(<< "Invalid nonce; expected timestamp terminator.");
660 return make_pair(BadlyFormed,username);
661 }
662
663 Data then;
664 pb.data(then, anchor);
665 if (expiresDelta > 0)
666 {
667 unsigned int now = (unsigned int)(Timer::getTimeMs()/1000);
668 if ((unsigned int)then.convertUInt64() + expiresDelta < now)
669 {
670 DebugLog(<< "Nonce has expired.");
671 return make_pair(Expired,username);
672 }
673 }
674 if (i->param(p_nonce) != makeNonce(request, then))
675 {
676 InfoLog(<< "Not my nonce.");
677 return make_pair(Failed,username);
678 }
679
680 if (i->exists(p_qop))
681 {
682 if (i->param(p_qop) == Symbols::auth || i->param(p_qop) == Symbols::authInt)
683 {
684 if (i->param(p_response) == makeResponseMD5WithA1(a1,
685 getMethodName(request.header(h_RequestLine).getMethod()),
686 i->param(p_uri),
687 i->param(p_nonce),
688 i->param(p_qop),
689 i->param(p_cnonce),
690 i->param(p_nc),
691 request.getContents()))
692 {
693 if(i->exists(p_username))
694 {
695 username = i->param(p_username);
696 }
697 return make_pair(Authenticated,username);
698 }
699 else
700 {
701 return make_pair(Failed,username);
702 }
703 }
704 else
705 {
706 InfoLog (<< "Unsupported qop=" << i->param(p_qop));
707 return make_pair(Failed,username);
708 }
709 }
710 else if (i->param(p_response) == makeResponseMD5WithA1(a1,
711 getMethodName(request.header(h_RequestLine).getMethod()),
712 i->param(p_uri),
713 i->param(p_nonce)))
714 {
715 if(i->exists(p_username))
716 {
717 username = i->param(p_username);
718 }
719 return make_pair(Authenticated,username);
720 }
721 else
722 {
723 return make_pair(Failed,username);
724 }
725 }
726 else
727 {
728 return make_pair(BadlyFormed,username);
729 }
730 }
731 return make_pair(BadlyFormed,username);
732 }
733 DebugLog (<< "No authentication headers. Failing request.");
734 return make_pair(Failed,username);
735 }
736
737 // !jf! note that this only authenticates a ProxyAuthenticate header, need to
738 // add support for WWWAuthenticate as well!!
739 Helper::AuthResult
740 Helper::authenticateRequest(const SipMessage& request,
741 const Data& realm,
742 const Data& password,
743 int expiresDelta)
744 {
745 DebugLog(<< "Authenticating: realm=" << realm << " expires=" << expiresDelta);
746 //DebugLog(<< request);
747
748 if (request.exists(h_ProxyAuthorizations))
749 {
750 const ParserContainer<Auth>& auths = request.header(h_ProxyAuthorizations);
751 for (ParserContainer<Auth>::const_iterator i = auths.begin(); i != auths.end(); i++)
752 {
753 if (i->exists(p_realm) &&
754 i->exists(p_nonce) &&
755 i->exists(p_response) &&
756 i->param(p_realm) == realm)
757 {
758 ParseBuffer pb(i->param(p_nonce).data(), i->param(p_nonce).size());
759 if (!pb.eof() && !isdigit(*pb.position()))
760 {
761 DebugLog(<< "Invalid nonce; expected timestamp.");
762 return BadlyFormed;
763 }
764 const char* anchor = pb.position();
765 pb.skipToChar(Symbols::COLON[0]);
766
767 if (pb.eof())
768 {
769 DebugLog(<< "Invalid nonce; expected timestamp terminator.");
770 return BadlyFormed;
771 }
772
773 Data then;
774 pb.data(then, anchor);
775 if (expiresDelta > 0)
776 {
777 unsigned int now = (unsigned int)(Timer::getTimeMs()/1000);
778 if ((unsigned int)then.convertUInt64() + expiresDelta < now)
779 {
780 DebugLog(<< "Nonce has expired.");
781 return Expired;
782 }
783 }
784 if (i->param(p_nonce) != makeNonce(request, then))
785 {
786 InfoLog(<< "Not my nonce.");
787 return Failed;
788 }
789
790 InfoLog (<< " username=" << (i->param(p_username))
791 << " password=" << password
792 << " realm=" << realm
793 << " method=" << getMethodName(request.header(h_RequestLine).getMethod())
794 << " uri=" << i->param(p_uri)
795 << " nonce=" << i->param(p_nonce));
796
797 if (i->exists(p_qop))
798 {
799 if (i->param(p_qop) == Symbols::auth || i->param(p_qop) == Symbols::authInt)
800 {
801 if (i->param(p_response) == makeResponseMD5(i->param(p_username),
802 password,
803 realm,
804 getMethodName(request.header(h_RequestLine).getMethod()),
805 i->param(p_uri),
806 i->param(p_nonce),
807 i->param(p_qop),
808 i->param(p_cnonce),
809 i->param(p_nc)),
810 request.getContents())
811 {
812 return Authenticated;
813 }
814 else
815 {
816 return Failed;
817 }
818 }
819 else
820 {
821 InfoLog (<< "Unsupported qop=" << i->param(p_qop));
822 return Failed;
823 }
824 }
825 else if (i->param(p_response) == makeResponseMD5(i->param(p_username),
826 password,
827 realm,
828 getMethodName(request.header(h_RequestLine).getMethod()),
829 i->param(p_uri),
830 i->param(p_nonce)))
831 {
832 return Authenticated;
833 }
834 else
835 {
836 return Failed;
837 }
838 }
839 else
840 {
841 return BadlyFormed;
842 }
843 }
844 return BadlyFormed;
845 }
846 DebugLog (<< "No authentication headers. Failing request.");
847 return Failed;
848 }
849
850 Helper::AuthResult
851 Helper::authenticateRequestWithA1(const SipMessage& request,
852 const Data& realm,
853 const Data& hA1,
854 int expiresDelta)
855 {
856 DebugLog(<< "Authenticating with HA1: realm=" << realm << " expires=" << expiresDelta);
857 //DebugLog(<< request);
858
859 if (request.exists(h_ProxyAuthorizations))
860 {
861 const ParserContainer<Auth>& auths = request.header(h_ProxyAuthorizations);
862 for (ParserContainer<Auth>::const_iterator i = auths.begin(); i != auths.end(); i++)
863 {
864 if (i->exists(p_realm) &&
865 i->exists(p_nonce) &&
866 i->exists(p_response) &&
867 i->param(p_realm) == realm)
868 {
869 ParseBuffer pb(i->param(p_nonce).data(), i->param(p_nonce).size());
870 if (!pb.eof() && !isdigit(*pb.position()))
871 {
872 DebugLog(<< "Invalid nonce; expected timestamp.");
873 return BadlyFormed;
874 }
875 const char* anchor = pb.position();
876 pb.skipToChar(Symbols::COLON[0]);
877
878 if (pb.eof())
879 {
880 DebugLog(<< "Invalid nonce; expected timestamp terminator.");
881 return BadlyFormed;
882 }
883
884 Data then;
885 pb.data(then, anchor);
886 if (expiresDelta > 0)
887 {
888 int now = (int)(Timer::getTimeMs()/1000);
889 if (then.convertInt() + expiresDelta < now)
890 {
891 DebugLog(<< "Nonce has expired.");
892 return Expired;
893 }
894 }
895 if (i->param(p_nonce) != makeNonce(request, then))
896 {
897 InfoLog(<< "Not my nonce.");
898 return Failed;
899 }
900
901 InfoLog (<< " username=" << (i->param(p_username))
902 << " H(A1)=" << hA1
903 << " realm=" << realm
904 << " method=" << getMethodName(request.header(h_RequestLine).getMethod())
905 << " uri=" << i->param(p_uri)
906 << " nonce=" << i->param(p_nonce));
907
908 if (i->exists(p_qop))
909 {
910 if (i->param(p_qop) == Symbols::auth || i->param(p_qop) == Symbols::authInt)
911 {
912 if (i->param(p_response) == makeResponseMD5WithA1(hA1,
913 getMethodName(request.header(h_RequestLine).getMethod()),
914 i->param(p_uri),
915 i->param(p_nonce),
916 i->param(p_qop),
917 i->param(p_cnonce),
918 i->param(p_nc),
919 request.getContents()))
920 {
921 return Authenticated;
922 }
923 else
924 {
925 return Failed;
926 }
927 }
928 else
929 {
930 InfoLog (<< "Unsupported qop=" << i->param(p_qop));
931 return Failed;
932 }
933 }
934 else if (i->param(p_response) == makeResponseMD5WithA1(hA1,
935 getMethodName(request.header(h_RequestLine).getMethod()),
936 i->param(p_uri),
937 i->param(p_nonce)))
938 {
939 return Authenticated;
940 }
941 else
942 {
943 return Failed;
944 }
945 }
946 else
947 {
948 return BadlyFormed;
949 }
950 }
951 return BadlyFormed;
952 }
953 DebugLog (<< "No authentication headers. Failing request.");
954 return Failed;
955 }
956
957 SipMessage*
958 Helper::make405(const SipMessage& request,
959 const int* allowedMethods,
960 int len )
961 {
962 SipMessage* resp = Helper::makeResponse(request, 405);
963
964 if (len < 0)
965 {
966 int upperBound = static_cast<int>(MAX_METHODS);
967
968 // The UNKNOWN method name is the first in the enum
969 for (int i = 1 ; i < upperBound; i ++)
970 {
971 int last = 0;
972
973 // ENUMS must be contiguous in order for this to work.
974 assert( i - last <= 1);
975 Token t;
976 t.value() = getMethodName(static_cast<resip::MethodTypes>(i));
977 resp->header(h_Allows).push_back(t);
978 last = i;
979 }
980 }
981 else
982 {
983 // use user's list
984 for ( int i = 0 ; i < len ; i++)
985 {
986 Token t;
987 t.value() = getMethodName(static_cast<resip::MethodTypes>(allowedMethods[i]));
988 resp->header(h_Allows).push_back(t);
989 }
990 }
991 return resp;
992 }
993
994
995 SipMessage*
996 Helper::makeProxyChallenge(const SipMessage& request, const Data& realm, bool useAuth, bool stale)
997 {
998 Auth auth;
999 auth.scheme() = "Digest";
1000 Data timestamp((unsigned int)(Timer::getTimeMs()/1000));
1001 auth.param(p_nonce) = makeNonce(request, timestamp);
1002 auth.param(p_algorithm) = "MD5";
1003 auth.param(p_realm) = realm;
1004 if (useAuth)
1005 {
1006 auth.param(p_qopOptions) = "auth,auth-int";
1007 }
1008 if (stale)
1009 {
1010 auth.param(p_stale) = "true";
1011 }
1012 SipMessage *response = Helper::makeResponse(request, 407);
1013 response->header(h_ProxyAuthenticates).push_back(auth);
1014 return response;
1015 }
1016
1017 void updateNonceCount(unsigned int& nonceCount, Data& nonceCountString)
1018 {
1019 if (!nonceCountString.empty())
1020 {
1021 return;
1022 }
1023 nonceCount++;
1024 {
1025 DataStream s(nonceCountString);
1026
1027 s << std::setw(8) << std::setfill('0') << std::hex << nonceCount;
1028 }
1029 DebugLog(<< "nonceCount is now: [" << nonceCountString << "]");
1030 }
1031
1032
1033 Auth
1034 Helper::makeChallengeResponseAuth(SipMessage& request,
1035 const Data& username,
1036 const Data& password,
1037 const Auth& challenge,
1038 const Data& cnonce,
1039 unsigned int& nonceCount,
1040 Data& nonceCountString)
1041 {
1042 Auth auth;
1043 auth.scheme() = "Digest";
1044 auth.param(p_username) = username;
1045 assert(challenge.exists(p_realm));
1046 auth.param(p_realm) = challenge.param(p_realm);
1047 assert(challenge.exists(p_nonce));
1048 auth.param(p_nonce) = challenge.param(p_nonce);
1049 Data digestUri;
1050 {
1051 DataStream s(digestUri);
1052 //s << request.header(h_RequestLine).uri().host(); // wrong
1053 s << request.header(h_RequestLine).uri(); // right
1054 }
1055 auth.param(p_uri) = digestUri;
1056
1057 Data authQop = qopOption(challenge);
1058 if (!authQop.empty())
1059 {
1060 updateNonceCount(nonceCount, nonceCountString);
1061 auth.param(p_response) = Helper::makeResponseMD5(username,
1062 password,
1063 challenge.param(p_realm),
1064 getMethodName(request.header(h_RequestLine).getMethod()),
1065 digestUri,
1066 challenge.param(p_nonce),
1067 authQop,
1068 cnonce,
1069 nonceCountString,
1070 request.getContents());
1071 auth.param(p_cnonce) = cnonce;
1072 auth.param(p_nc) = nonceCountString;
1073 auth.param(p_qop) = authQop;
1074 }
1075 else
1076 {
1077 assert(challenge.exists(p_realm));
1078 auth.param(p_response) = Helper::makeResponseMD5(username,
1079 password,
1080 challenge.param(p_realm),
1081 getMethodName(request.header(h_RequestLine).getMethod()),
1082 digestUri,
1083 challenge.param(p_nonce));
1084 }
1085
1086 if (challenge.exists(p_algorithm))
1087 {
1088 auth.param(p_algorithm) = challenge.param(p_algorithm);
1089 }
1090 else
1091 {
1092 auth.param(p_algorithm) = "MD5";
1093 }
1094
1095 if (challenge.exists(p_opaque))
1096 {
1097 auth.param(p_opaque) = challenge.param(p_opaque);
1098 }
1099
1100 return auth;
1101 }
1102
1103 Data
1104 Helper::qopOption(const Auth& challenge)
1105 {
1106 // priority-order list of preferred qop tokens
1107 static Data preferredTokens[] =
1108 {
1109 Symbols::authInt,
1110 Symbols::auth
1111 };
1112
1113 bool found = false;
1114 size_t index = 0;
1115 if (challenge.exists(p_qopOptions) && !challenge.param(p_qopOptions).empty())
1116 {
1117 ParseBuffer pb(challenge.param(p_qopOptions).data(), challenge.param(p_qopOptions).size());
1118 do
1119 {
1120 const char* anchor = pb.skipWhitespace();
1121 pb.skipToChar(Symbols::COMMA[0]);
1122 if (!pb.eof())
1123 pb.skipChar();
1124 Data q;
1125 pb.data(q, anchor);
1126 for (size_t i=0; i < sizeof(preferredTokens)/sizeof(*preferredTokens); i++)
1127 {
1128 if (q == preferredTokens[i])
1129 {
1130 // found a preferred token; is it higher priority?
1131 if (!found || i < index)
1132 {
1133 found = true;
1134 index = i;
1135 }
1136 }
1137 }
1138 }
1139 while(!pb.eof());
1140 }
1141
1142 if (found)
1143 return preferredTokens[index];
1144
1145 return Data::Empty;
1146
1147 }
1148
1149
1150 Auth
1151 Helper::makeChallengeResponseAuthWithA1(const SipMessage& request,
1152 const Data& username,
1153 const Data& a1,
1154 const Auth& challenge,
1155 const Data& cnonce,
1156 unsigned int& nonceCount,
1157 Data& nonceCountString)
1158 {
1159 Auth auth;
1160 auth.scheme() = "Digest";
1161 auth.param(p_username) = username;
1162 assert(challenge.exists(p_realm));
1163 auth.param(p_realm) = challenge.param(p_realm);
1164 assert(challenge.exists(p_nonce));
1165 auth.param(p_nonce) = challenge.param(p_nonce);
1166 Data digestUri;
1167 {
1168 DataStream s(digestUri);
1169 //s << request.header(h_RequestLine).uri().host(); // wrong
1170 s << request.header(h_RequestLine).uri(); // right
1171 }
1172 auth.param(p_uri) = digestUri;
1173
1174 Data authQop = qopOption(challenge);
1175 if (!authQop.empty())
1176 {
1177 updateNonceCount(nonceCount, nonceCountString);
1178 auth.param(p_response) = Helper::makeResponseMD5WithA1(a1,
1179 getMethodName(request.header(h_RequestLine).getMethod()),
1180 digestUri,
1181 challenge.param(p_nonce),
1182 authQop,
1183 cnonce,
1184 nonceCountString,
1185 request.getContents());
1186 auth.param(p_cnonce) = cnonce;
1187 auth.param(p_nc) = nonceCountString;
1188 auth.param(p_qop) = authQop;
1189 }
1190 else
1191 {
1192 assert(challenge.exists(p_realm));
1193 auth.param(p_response) = Helper::makeResponseMD5WithA1(a1,
1194 getMethodName(request.header(h_RequestLine).getMethod()),
1195 digestUri,
1196 challenge.param(p_nonce));
1197 }
1198
1199 if (challenge.exists(p_algorithm))
1200 {
1201 auth.param(p_algorithm) = challenge.param(p_algorithm);
1202 }
1203 else
1204 {
1205 auth.param(p_algorithm) = "MD5";
1206 }
1207
1208 if (challenge.exists(p_opaque))
1209 {
1210 auth.param(p_opaque) = challenge.param(p_opaque);
1211 }
1212
1213 return auth;
1214 }
1215
1216
1217 SipMessage&
1218 Helper::addAuthorization(SipMessage& request,
1219 const SipMessage& challenge,
1220 const Data& username,
1221 const Data& password,
1222 const Data& cnonce,
1223 unsigned int& nonceCount)
1224 {
1225 Data nonceCountString = Data::Empty;
1226
1227 assert(challenge.isResponse());
1228 assert(challenge.header(h_StatusLine).responseCode() == 401 ||
1229 challenge.header(h_StatusLine).responseCode() == 407);
1230
1231 if (challenge.exists(h_ProxyAuthenticates))
1232 {
1233 const ParserContainer<Auth>& auths = challenge.header(h_ProxyAuthenticates);
1234 for (ParserContainer<Auth>::const_iterator i = auths.begin();
1235 i != auths.end(); i++)
1236 {
1237 request.header(h_ProxyAuthorizations).push_back(makeChallengeResponseAuth(request, username, password, *i,
1238 cnonce, nonceCount, nonceCountString));
1239 }
1240 }
1241 if (challenge.exists(h_WWWAuthenticates))
1242 {
1243 const ParserContainer<Auth>& auths = challenge.header(h_WWWAuthenticates);
1244 for (ParserContainer<Auth>::const_iterator i = auths.begin();
1245 i != auths.end(); i++)
1246 {
1247 request.header(h_Authorizations).push_back(makeChallengeResponseAuth(request, username, password, *i,
1248 cnonce, nonceCount, nonceCountString));
1249 }
1250 }
1251 return request;
1252 }
1253
1254 Uri
1255 Helper::makeUri(const Data& aor, const Data& scheme)
1256 {
1257 assert(!aor.prefix("sip:"));
1258 assert(!aor.prefix("sips:"));
1259
1260 Data tmp(aor.size() + scheme.size() + 1, Data::Preallocate);
1261 tmp += scheme;
1262 tmp += Symbols::COLON;
1263 tmp += aor;
1264 Uri uri(tmp);
1265 return uri;
1266 }
1267
1268 void
1269 Helper::processStrictRoute(SipMessage& request)
1270 {
1271 if (request.exists(h_Routes) &&
1272 !request.header(h_Routes).empty() &&
1273 !request.header(h_Routes).front().uri().exists(p_lr))
1274 {
1275 // The next hop is a strict router. Move the next hop into the
1276 // Request-URI and move the ultimate destination to the end of the
1277 // route list. Force the message target to be the next hop router.
1278 request.header(h_Routes).push_back(NameAddr(request.header(h_RequestLine).uri()));
1279 request.header(h_RequestLine).uri() = request.header(h_Routes).front().uri();
1280 request.header(h_Routes).pop_front(); // !jf!
1281 assert(!request.hasForceTarget());
1282 request.setForceTarget(request.header(h_RequestLine).uri());
1283 }
1284 }
1285
1286 int
1287 Helper::getPortForReply(SipMessage& request)
1288 {
1289 assert(request.isRequest());
1290 int port = -1;
1291 if (request.header(h_Vias).front().exists(p_rport))
1292 {
1293 port = request.getSource().getPort();
1294 }
1295 else
1296 {
1297 port = request.header(h_Vias).front().sentPort();
1298 if (port <= 0 || port > 65535)
1299 {
1300 port = Symbols::DefaultSipPort;
1301 }
1302 }
1303 assert(port != -1);
1304 return port;
1305 }
1306
1307 Uri
1308 Helper::fromAor(const Data& aor, const Data& scheme)
1309 {
1310 return makeUri(aor, scheme);
1311 }
1312
1313 bool
1314 Helper::validateMessage(const SipMessage& message)
1315 {
1316 if (!message.exists(h_To) ||
1317 !message.exists(h_From) ||
1318 !message.exists(h_CSeq) ||
1319 !message.exists(h_CallId) ||
1320 !message.exists(h_Vias) ||
1321 message.header(h_Vias).empty())
1322 {
1323 InfoLog(<< "Missing mandatory header fields (To, From, CSeq, Call-Id or Via)");
1324 DebugLog(<< message);
1325 return false;
1326 }
1327 else
1328 {
1329 return true;
1330 }
1331 }
1332
1333 #if defined(USE_SSL)
1334 #include <openssl/blowfish.h>
1335
1336 static const Data sep("[]");
1337 static const Data pad("\0\0\0\0\0\0\0", 7);
1338 static const Data GRUU("_GRUU");
1339 static const int saltBytes(16);
1340
1341 Data
1342 Helper::gruuUserPart(const Data& instanceId,
1343 const Data& aor,
1344 const Data& key)
1345 {
1346 unsigned char ivec[8];
1347
1348 ivec[0] = '\x6E';
1349 ivec[1] = '\xE7';
1350 ivec[2] = '\xB0';
1351 ivec[3] = '\x4A';
1352 ivec[4] = '\x45';
1353 ivec[5] = '\x93';
1354 ivec[6] = '\x7D';
1355 ivec[7] = '\x51';
1356
1357 BF_KEY fish;
1358 BF_set_key(&fish, key.size(), (const unsigned char*)key.data());
1359
1360 const Data salt(resip::Random::getRandomHex(saltBytes));
1361
1362 const Data token(salt + instanceId + sep + aor + '\0' +
1363 pad.substr(0, (8 - ((salt.size() +
1364 instanceId.size() +
1365 sep.size() + 1
1366 + aor.size() ) % 8))
1367 % 8));
1368 auto_ptr <unsigned char> out(new unsigned char[token.size()]);
1369 BF_cbc_encrypt((const unsigned char*)token.data(),
1370 out.get(),
1371 token.size(),
1372 &fish,
1373 ivec,
1374 BF_ENCRYPT);
1375
1376 return GRUU + Data(out.get(),token.size()).base64encode(true/*safe URL*/);
1377 }
1378
1379 std::pair<Data,Data>
1380 Helper::fromGruuUserPart(const Data& gruuUserPart,
1381 const Data& key)
1382 {
1383 unsigned char ivec[8];
1384
1385 ivec[0] = '\x6E';
1386 ivec[1] = '\xE7';
1387 ivec[2] = '\xB0';
1388 ivec[3] = '\x4A';
1389 ivec[4] = '\x45';
1390 ivec[5] = '\x93';
1391 ivec[6] = '\x7D';
1392 ivec[7] = '\x51';
1393
1394 static const std::pair<Data, Data> empty;
1395
1396 if (gruuUserPart.size() < GRUU.size())
1397 {
1398 return empty;
1399 }
1400
1401 const Data gruu = gruuUserPart.substr(GRUU.size());
1402
1403 BF_KEY fish;
1404 BF_set_key(&fish, key.size(), (const unsigned char*)key.data());
1405
1406 const Data decoded = gruu.base64decode();
1407
1408 auto_ptr <unsigned char> out(new unsigned char[gruuUserPart.size()+1]);
1409 BF_cbc_encrypt((const unsigned char*)decoded.data(),
1410 out.get(),
1411 decoded.size(),
1412 &fish,
1413 ivec,
1414 BF_DECRYPT);
1415 const Data pair(out.get(), decoded.size());
1416
1417 Data::size_type pos = pair.find(sep);
1418 if (pos == Data::npos)
1419 {
1420 return empty;
1421 }
1422
1423 return std::make_pair(pair.substr(2*saltBytes, pos), // strip out the salt
1424 pair.substr(pos+sep.size()).c_str());
1425 }
1426 #endif
1427 Helper::ContentsSecAttrs::ContentsSecAttrs()
1428 : mContents(0),
1429 mAttributes(0)
1430 {}
1431
1432 Helper::ContentsSecAttrs::ContentsSecAttrs(std::auto_ptr<Contents> contents,
1433 std::auto_ptr<SecurityAttributes> attributes)
1434 : mContents(contents),
1435 mAttributes(attributes)
1436 {}
1437
1438 Helper::ContentsSecAttrs::ContentsSecAttrs(const ContentsSecAttrs& rhs)
1439 : mContents(rhs.mContents),
1440 mAttributes(rhs.mAttributes)
1441 {}
1442
1443 Helper::ContentsSecAttrs&
1444 Helper::ContentsSecAttrs::operator=(const ContentsSecAttrs& rhs)
1445 {
1446 if (&rhs != this)
1447 {
1448 mContents = rhs.mContents;
1449 mAttributes = rhs.mAttributes;
1450 }
1451 return *this;
1452 }
1453
1454
1455 Contents*
1456 extractFromPkcs7Recurse(Contents* tree,
1457 const Data& signerAor,
1458 const Data& receiverAor,
1459 SecurityAttributes* attributes,
1460 Security& security)
1461 {
1462 Pkcs7Contents* pk;
1463 if ((pk = dynamic_cast<Pkcs7Contents*>(tree)))
1464 {
1465 InfoLog( << "GREG1: " << *pk );
1466 #if defined(USE_SSL)
1467 Contents* contents = security.decrypt(receiverAor, pk);
1468 if (contents)
1469 {
1470 attributes->setEncrypted();
1471 }
1472 return contents;
1473 #else
1474 return 0;
1475 #endif
1476 }
1477 MultipartSignedContents* mps;
1478 if ((mps = dynamic_cast<MultipartSignedContents*>(tree)))
1479 {
1480 InfoLog( << "GREG2: " << *mps );
1481 #if defined(USE_SSL)
1482 Data signer;
1483 SignatureStatus sigStatus;
1484 Contents* b = extractFromPkcs7Recurse(security.checkSignature(mps,
1485 &signer,
1486 &sigStatus),
1487 signerAor,
1488 receiverAor, attributes, security);
1489 attributes->setSigner(signer);
1490 attributes->setSignatureStatus(sigStatus);
1491 return b->clone();
1492 #else
1493 return mps->parts().front()->clone();
1494 #endif
1495 }
1496 MultipartAlternativeContents* alt;
1497 if ((alt = dynamic_cast<MultipartAlternativeContents*>(tree)))
1498 {
1499 InfoLog( << "GREG3: " << *alt );
1500 for (MultipartAlternativeContents::Parts::reverse_iterator i = alt->parts().rbegin();
1501 i != alt->parts().rend(); ++i)
1502 {
1503 Contents* b = extractFromPkcs7Recurse(*i, signerAor, receiverAor, attributes, security);
1504 if (b)
1505 {
1506 return b;
1507 }
1508 }
1509 }
1510
1511 MultipartMixedContents* mult;
1512 if ((mult = dynamic_cast<MultipartMixedContents*>(tree)))
1513 {
1514 InfoLog( << "GREG4: " << *mult );
1515 for (MultipartMixedContents::Parts::iterator i = mult->parts().begin();
1516 i != mult->parts().end(); ++i)
1517 {
1518 Contents* b = extractFromPkcs7Recurse(*i, signerAor, receiverAor,
1519 attributes, security);
1520 if (b)
1521 {
1522 return b;
1523 }
1524 };
1525
1526 return 0;
1527 }
1528
1529 return tree->clone();
1530 }
1531
1532 Helper::ContentsSecAttrs
1533 Helper::extractFromPkcs7(const SipMessage& message,
1534 Security& security)
1535 {
1536 SecurityAttributes* attr = new SecurityAttributes;
1537 // .dlb. currently flattening SecurityAttributes?
1538 //attr->setIdentity(message.getIdentity());
1539 attr->setIdentity(message.header(h_From).uri().getAor());
1540 Contents *b = message.getContents();
1541 if (b)
1542 {
1543 Data fromAor(message.header(h_From).uri().getAor());
1544 Data toAor(message.header(h_To).uri().getAor());
1545 if (message.isRequest())
1546 {
1547 b = extractFromPkcs7Recurse(b, fromAor, toAor, attr, security);
1548 }
1549 else // its a response
1550 {
1551 b = extractFromPkcs7Recurse(b, toAor, fromAor, attr, security);
1552 }
1553 }
1554 std::auto_ptr<Contents> c(b);
1555 std::auto_ptr<SecurityAttributes> a(attr);
1556 return ContentsSecAttrs(c, a);
1557 }
1558
1559 Helper::FailureMessageEffect
1560 Helper::determineFailureMessageEffect(const SipMessage& response)
1561 {
1562 assert(response.isResponse());
1563 int code = response.header(h_StatusLine).statusCode();
1564 assert(code >= 400);
1565
1566 switch(code)
1567 {
1568 case 404:
1569 case 410:
1570 case 416:
1571 case 480: // but maybe not, still not quite decided:
1572 case 481:
1573 case 482: // but maybe not, still not quite decided:
1574 case 484:
1575 case 485:
1576 case 502:
1577 case 604:
1578 return DialogTermination;
1579 case 403:
1580 case 489: //only for only subscription
1581 case 408: //again, maybe not. This seems best.
1582 return UsageTermination;
1583 case 400:
1584 case 401:
1585 case 402:
1586 case 405: //doesn't agree w/ -00 of dialogusage
1587 case 406:
1588 case 412:
1589 case 413:
1590 case 414:
1591 case 415:
1592 case 420:
1593 case 421:
1594 case 423:
1595
1596 case 429: // but if this the refer creating the Subscription, no sub will be created.
1597 case 486:
1598 case 487:
1599 case 488:
1600 case 491:
1601 case 493:
1602 case 494:
1603 case 505:
1604 case 513:
1605 case 603:
1606 case 606:
1607 return TransactionTermination;
1608 case 483: // who knows, gravefully terminate or just destroy dialog
1609 case 501:
1610 return ApplicationDependant;
1611 default:
1612 if (code < 600)
1613 {
1614 if (response.exists(h_RetryAfter))
1615
1616 {
1617 return RetryAfter;
1618 }
1619 else
1620 {
1621 return OptionalRetryAfter;
1622 }
1623 }
1624 else
1625 {
1626 if (response.exists(h_RetryAfter))
1627 {
1628 return RetryAfter;
1629 }
1630 else
1631 {
1632 return ApplicationDependant;
1633 }
1634 }
1635 }
1636 }
1637
1638 /* ====================================================================
1639 * The Vovida Software License, Version 1.0
1640 *
1641 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
1642 *
1643 * Redistribution and use in source and binary forms, with or without
1644 * modification, are permitted provided that the following conditions
1645 * are met:
1646 *
1647 * 1. Redistributions of source code must retain the above copyright
1648 * notice, this list of conditions and the following disclaimer.
1649 *
1650 * 2. Redistributions in binary form must reproduce the above copyright
1651 * notice, this list of conditions and the following disclaimer in
1652 * the documentation and/or other materials provided with the
1653 * distribution.
1654 *
1655 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
1656 * and "Vovida Open Communication Application Library (VOCAL)" must
1657 * not be used to endorse or promote products derived from this
1658 * software without prior written permission. For written
1659 * permission, please contact vocal@vovida.org.
1660 *
1661 * 4. Products derived from this software may not be called "VOCAL", nor
1662 * may "VOCAL" appear in their name, without prior written
1663 * permission of Vovida Networks, Inc.
1664 *
1665 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
1666 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1667 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
1668 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
1669 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
1670 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
1671 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
1672 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1673 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
1674 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1675 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1676 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1677 * DAMAGE.
1678 *
1679 * ====================================================================
1680 *
1681 * This software consists of voluntary contributions made by Vovida
1682 * Networks, Inc. and many individuals on behalf of Vovida Networks,
1683 * Inc. For more information on Vovida Networks, Inc., please see
1684 * <http://www.vovida.org/>.
1685 *
1686 */

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27