/[resiprocate]/branches/b-directory-reorg/sip/resiprocate/Helper.cxx
ViewVC logotype

Contents of /branches/b-directory-reorg/sip/resiprocate/Helper.cxx

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:eol-style LF

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27