Coverage Report

Created: 2025-10-12 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/resiprocate/resip/stack/Helper.cxx
Line
Count
Source
1
#if defined(HAVE_CONFIG_H)
2
#include "config.h"
3
#endif
4
5
//#include <ctype.h>
6
#include <cstring>
7
#include <iomanip>
8
#include <algorithm>
9
#include <memory>
10
#include <new>
11
#include <utility>
12
#include <vector>
13
14
#include "resip/stack/Auth.hxx"
15
#include "resip/stack/BasicNonceHelper.hxx"
16
#include "resip/stack/Helper.hxx"
17
#include "resip/stack/NonceHelper.hxx"
18
#include "rutil/Coders.hxx"
19
#include "resip/stack/Uri.hxx"
20
#include "rutil/Logger.hxx"
21
#include "rutil/Random.hxx"
22
#include "rutil/Timer.hxx"
23
#include "rutil/DataStream.hxx"
24
#include "rutil/MD5Stream.hxx"
25
#include "rutil/DnsUtil.hxx"
26
#include "rutil/compat.hxx"
27
#include "rutil/ParseBuffer.hxx"
28
#include "rutil/TransportType.hxx"
29
#include "resip/stack/SipMessage.hxx"
30
#include "resip/stack/Pkcs7Contents.hxx"
31
#include "resip/stack/MultipartSignedContents.hxx"
32
#include "resip/stack/MultipartMixedContents.hxx"
33
#include "resip/stack/MultipartAlternativeContents.hxx"
34
#include "rutil/WinLeakCheck.hxx"
35
36
#ifdef USE_SSL
37
#include "resip/stack/ssl/Security.hxx"
38
#include "rutil/ssl/OpenSSLDeleter.hxx"
39
#endif
40
41
using namespace resip;
42
using namespace std;
43
44
#define RESIPROCATE_SUBSYSTEM Subsystem::SIP
45
46
const int Helper::tagSize = 4;
47
48
// !jf! this should be settable by the application in case a group of apps
49
// (e.g. proxies) want to share the same secret
50
Helper::NonceHelperPtr Helper::mNonceHelperPtr;
51
52
void Helper::integer2hex(char* _d, unsigned int _s, bool _l)
53
59.2k
{
54
59.2k
   int i;
55
59.2k
   unsigned char j;
56
59.2k
   int k = 0;
57
59.2k
   char* s;
58
59
59.2k
   _s = htonl(_s);
60
59.2k
   s = (char*)&_s;
61
62
296k
   for (i = 0; i < 4; i++) 
63
237k
   {
64
237k
      j = (s[i] >> 4) & 0xf;
65
237k
      if (j <= 9) 
66
213k
      {
67
213k
         if(_l || j != 0 || k != 0)
68
31.8k
         {
69
31.8k
            _d[k++] = (j + '0');
70
31.8k
         }
71
213k
      }
72
24.0k
      else 
73
24.0k
      {
74
24.0k
         _d[k++] = (j + 'a' - 10);
75
24.0k
      }
76
77
237k
      j = s[i] & 0xf;
78
237k
      if (j <= 9) 
79
207k
      {
80
207k
         if(_l || j != 0 || k != 0)
81
55.8k
         {
82
55.8k
            _d[k++] = (j + '0');
83
55.8k
         }
84
207k
      }
85
29.0k
      else 
86
29.0k
      {
87
29.0k
         _d[k++] = (j + 'a' - 10);
88
29.0k
      }
89
237k
   }
90
59.2k
}
91
92
unsigned int Helper::hex2integer(const char* _s)
93
7.62k
{
94
7.62k
   unsigned int i, res = 0;
95
96
13.4k
   for(i = 0; i < 8; i++) 
97
12.9k
   {
98
12.9k
      if ((_s[i] >= '0') && (_s[i] <= '9')) 
99
1.12k
      {
100
1.12k
         res *= 16;
101
1.12k
         res += _s[i] - '0';
102
1.12k
      }
103
11.8k
      else if ((_s[i] >= 'a') && (_s[i] <= 'f')) 
104
640
      {
105
640
         res *= 16;
106
640
         res += _s[i] - 'a' + 10;
107
640
      } 
108
11.1k
      else if ((_s[i] >= 'A') && (_s[i] <= 'F')) 
109
4.09k
      {
110
4.09k
         res *= 16;
111
4.09k
         res += _s[i] - 'A' + 10;
112
4.09k
      }
113
7.09k
      else 
114
7.09k
      {
115
7.09k
         return res;
116
7.09k
      }
117
12.9k
   }
118
119
531
   return res;
120
7.62k
}
121
122
SipMessage*
123
Helper::makeRequest(const NameAddr& target, const NameAddr& from, const NameAddr& contact, MethodTypes method)
124
0
{
125
0
   std::unique_ptr<SipMessage> request(new SipMessage);
126
0
   RequestLine rLine(method);
127
0
   rLine.uri() = target.uri();
128
0
   request->header(h_To) = target;
129
0
   request->header(h_RequestLine) = rLine;
130
0
   request->header(h_MaxForwards).value() = 70;
131
0
   request->header(h_CSeq).method() = method;
132
0
   request->header(h_CSeq).sequence() = 1;
133
0
   request->header(h_From) = from;
134
0
   request->header(h_From).param(p_tag) = Helper::computeTag(Helper::tagSize);
135
0
   request->header(h_Contacts).push_back(contact);
136
0
   request->header(h_CallId).value() = Helper::computeCallId();
137
   //request->header(h_ContentLength).value() = 0;
138
   
139
0
   Via via;
140
0
   request->header(h_Vias).push_back(via);
141
   
142
0
   return request.release();
143
0
}
144
145
SipMessage*
146
Helper::makeRequest(const NameAddr& target, const NameAddr& from, MethodTypes method)
147
0
{
148
0
   NameAddr contact;
149
0
   return makeRequest(target, from, contact, method);
150
0
}
151
152
SipMessage*
153
Helper::makeRegister(const NameAddr& to, const NameAddr& from)
154
0
{
155
0
   NameAddr contact;
156
0
   return makeRegister(to, from, contact);
157
0
}
158
159
SipMessage*
160
Helper::makeRegister(const NameAddr& to, const NameAddr& from, const NameAddr& contact)
161
0
{
162
0
   std::unique_ptr<SipMessage> request(new SipMessage);
163
0
   RequestLine rLine(REGISTER);
164
165
0
   rLine.uri().scheme() = to.uri().scheme();
166
0
   rLine.uri().host() = to.uri().host();
167
0
   rLine.uri().port() = to.uri().port();
168
0
   if (to.uri().exists(p_transport))
169
0
   {
170
0
      rLine.uri().param(p_transport) = to.uri().param(p_transport);
171
0
   }
172
173
0
   request->header(h_To) = to;
174
0
   request->header(h_RequestLine) = rLine;
175
0
   request->header(h_MaxForwards).value() = 70;
176
0
   request->header(h_CSeq).method() = REGISTER;
177
0
   request->header(h_CSeq).sequence() = 1;
178
0
   request->header(h_From) = from;
179
0
   request->header(h_From).param(p_tag) = Helper::computeTag(Helper::tagSize);
180
0
   request->header(h_CallId).value() = Helper::computeCallId();
181
0
   resip_assert(!request->exists(h_Contacts) || request->header(h_Contacts).empty());
182
0
   request->header(h_Contacts).push_back( contact );
183
   
184
0
   Via via;
185
0
   request->header(h_Vias).push_back(via);
186
   
187
0
   return request.release();
188
0
}
189
190
SipMessage*
191
Helper::makeRegister(const NameAddr& to,const Data& transport)
192
0
{
193
0
   NameAddr contact;
194
0
   return makeRegister(to, transport, contact);
195
   
196
0
}
197
198
SipMessage*
199
Helper::makeRegister(const NameAddr& to, const Data& transport, const NameAddr& contact)
200
0
{
201
0
   std::unique_ptr<SipMessage> request(new SipMessage);
202
0
   RequestLine rLine(REGISTER);
203
204
0
   rLine.uri().scheme() = to.uri().scheme();
205
0
   rLine.uri().host() = to.uri().host();
206
0
   rLine.uri().port() = to.uri().port();
207
0
   if (!transport.empty())
208
0
   {
209
0
      rLine.uri().param(p_transport) = transport;
210
0
   }
211
212
0
   request->header(h_To) = to;
213
0
   request->header(h_RequestLine) = rLine;
214
0
   request->header(h_MaxForwards).value() = 70;
215
0
   request->header(h_CSeq).method() = REGISTER;
216
0
   request->header(h_CSeq).sequence() = 1;
217
0
   request->header(h_From) = to;
218
0
   request->header(h_From).param(p_tag) = Helper::computeTag(Helper::tagSize);
219
0
   request->header(h_CallId).value() = Helper::computeCallId();
220
0
   resip_assert(!request->exists(h_Contacts) || request->header(h_Contacts).empty());
221
0
   request->header(h_Contacts).push_back( contact );
222
   
223
0
   Via via;
224
0
   request->header(h_Vias).push_back(via);
225
   
226
0
   return request.release();
227
0
}
228
229
230
SipMessage*
231
Helper::makePublish(const NameAddr& target, const NameAddr& from)
232
0
{
233
0
   NameAddr contact;
234
0
   return makePublish(target, from, contact);
235
0
}
236
237
SipMessage*
238
Helper::makePublish(const NameAddr& target, const NameAddr& from, const NameAddr& contact)
239
0
{
240
0
   std::unique_ptr<SipMessage> request(new SipMessage);
241
0
   RequestLine rLine(PUBLISH);
242
0
   rLine.uri() = target.uri();
243
244
0
   request->header(h_To) = target;
245
0
   request->header(h_RequestLine) = rLine;
246
0
   request->header(h_MaxForwards).value() = 70;
247
0
   request->header(h_CSeq).method() = PUBLISH;
248
0
   request->header(h_CSeq).sequence() = 1;
249
0
   request->header(h_From) = from;
250
0
   request->header(h_From).param(p_tag) = Helper::computeTag(Helper::tagSize);
251
0
   request->header(h_CallId).value() = Helper::computeCallId();
252
0
   resip_assert(!request->exists(h_Contacts) || request->header(h_Contacts).empty());
253
0
   request->header(h_Contacts).push_back( contact );
254
0
   Via via;
255
0
   request->header(h_Vias).push_back(via);
256
   
257
0
   return request.release();
258
0
}
259
260
SipMessage*
261
Helper::makeMessage(const NameAddr& target, const NameAddr& from)
262
0
{
263
0
   NameAddr contact;
264
0
   return makeMessage(target, from, contact);
265
0
}
266
267
SipMessage*
268
Helper::makeMessage(const NameAddr& target, const NameAddr& from, const NameAddr& contact)
269
0
{
270
0
   std::unique_ptr<SipMessage> request(new SipMessage);
271
0
   RequestLine rLine(MESSAGE);
272
0
   rLine.uri() = target.uri();
273
274
0
   request->header(h_To) = target;
275
0
   request->header(h_RequestLine) = rLine;
276
0
   request->header(h_MaxForwards).value() = 70;
277
0
   request->header(h_CSeq).method() = MESSAGE;
278
0
   request->header(h_CSeq).sequence() = 1;
279
0
   request->header(h_From) = from;
280
0
   request->header(h_From).param(p_tag) = Helper::computeTag(Helper::tagSize);
281
0
   request->header(h_CallId).value() = Helper::computeCallId();
282
0
   resip_assert(!request->exists(h_Contacts) || request->header(h_Contacts).empty());
283
0
   request->header(h_Contacts).push_back( contact );
284
0
   Via via;
285
0
   request->header(h_Vias).push_back(via);
286
   
287
0
   return request.release();
288
0
}
289
290
291
SipMessage*
292
Helper::makeSubscribe(const NameAddr& target, const NameAddr& from)
293
0
{
294
0
   NameAddr contact;
295
0
   return makeSubscribe(target, from, contact);
296
0
}
297
298
SipMessage*
299
Helper::makeSubscribe(const NameAddr& target, const NameAddr& from, const NameAddr& contact)
300
0
{
301
0
   std::unique_ptr<SipMessage> request(new SipMessage);
302
0
   RequestLine rLine(SUBSCRIBE);
303
0
   rLine.uri() = target.uri();
304
305
0
   request->header(h_To) = target;
306
0
   request->header(h_RequestLine) = rLine;
307
0
   request->header(h_MaxForwards).value() = 70;
308
0
   request->header(h_CSeq).method() = SUBSCRIBE;
309
0
   request->header(h_CSeq).sequence() = 1;
310
0
   request->header(h_From) = from;
311
0
   request->header(h_From).param(p_tag) = Helper::computeTag(Helper::tagSize);
312
0
   request->header(h_CallId).value() = Helper::computeCallId();
313
0
   resip_assert(!request->exists(h_Contacts) || request->header(h_Contacts).empty());
314
0
   request->header(h_Contacts).push_front( contact );
315
0
   Via via;
316
0
   request->header(h_Vias).push_front(via);
317
   
318
0
   return request.release();
319
0
}
320
321
int
322
Helper::jitterValue(int input, int lowerPercentage, int upperPercentage, int minimum)
323
0
{
324
0
   resip_assert(upperPercentage >= lowerPercentage);
325
0
   if (input < minimum)
326
0
   {
327
0
      return input;
328
0
   }
329
0
   else if (lowerPercentage == 100 && upperPercentage == 100)
330
0
   {
331
0
      return input;
332
0
   }
333
0
   else
334
0
   {
335
0
      const int rnd = Random::getRandom() % (upperPercentage-lowerPercentage) + lowerPercentage;
336
0
      return (input * rnd) / 100;
337
0
   }
338
0
}
339
340
SipMessage*
341
Helper::makeInvite(const NameAddr& target, const NameAddr& from)
342
0
{
343
0
   return Helper::makeRequest(target, from, INVITE);
344
0
}
345
346
SipMessage*
347
Helper::makeInvite(const NameAddr& target, const NameAddr& from, const NameAddr& contact)
348
0
{
349
0
   return Helper::makeRequest(target, from, contact, INVITE);
350
0
}
351
352
353
void
354
Helper::makeResponse(SipMessage& response, 
355
                     const SipMessage& request, 
356
                     int responseCode, 
357
                     const NameAddr& myContact, 
358
                     const Data& reason,
359
                     const Data& hostname,
360
                     const Data& warning)
361
0
{
362
0
   makeResponse(response,request, responseCode, reason,hostname, warning);
363
   // in general, this should not create a Contact header since only requests
364
   // that create a dialog (or REGISTER requests) should produce a response with
365
   // a contact(s). 
366
0
   response.header(h_Contacts).clear();
367
0
   response.header(h_Contacts).push_back(myContact);
368
0
}
369
370
371
void
372
Helper::makeResponse(SipMessage& response, 
373
                     const SipMessage& request, 
374
                     int responseCode, 
375
                     const Data& reason,
376
                     const Data& hostname,
377
                     const Data& warning)
378
0
{
379
0
   DebugLog(<< "Helper::makeResponse(" << request.brief() << " code=" << responseCode << " reason=" << reason);
380
0
   response.header(h_StatusLine).responseCode() = responseCode;
381
0
   response.header(h_From) = request.header(h_From);
382
0
   response.header(h_To) = request.header(h_To);
383
0
   response.header(h_CallId) = request.header(h_CallId);
384
0
   response.header(h_CSeq) = request.header(h_CSeq);
385
0
   response.header(h_Vias) = request.header(h_Vias);
386
387
0
   if (!warning.empty())
388
0
   {
389
0
      WarningCategory warn;
390
0
      warn.code() = 399;
391
0
      warn.hostname() = hostname;
392
0
      warn.text() = warning;
393
0
      response.header(h_Warnings).push_back(warn);
394
0
   }
395
396
0
   if(responseCode > 100 &&
397
0
      response.const_header(h_To).isWellFormed() &&
398
0
      !response.const_header(h_To).exists(p_tag))
399
0
   {
400
      // Only generate a To: tag if one doesn't exist.  Think Re-INVITE.   
401
      // No totag for failure responses or 100s   
402
      // ?bwc? Should we be generating to-tags for failure responses or not?
403
      // The comments say no, but the code says yes. Which is it?
404
0
      response.header(h_To).param(p_tag) = Helper::computeTag(Helper::tagSize);
405
0
   }
406
407
   // .bwc. This will only throw if the topmost Via is malformed, and that 
408
   // should have been caught at the transport level.
409
0
   response.setRFC2543TransactionId(request.getRFC2543TransactionId());
410
   
411
   //response.header(h_ContentLength).value() = 0;
412
   
413
0
   if (responseCode >= 180 && responseCode < 300 && request.exists(h_RecordRoutes))
414
0
   {
415
0
      response.header(h_RecordRoutes) = request.header(h_RecordRoutes);
416
0
   }
417
418
   // .bwc. If CSeq is malformed, basicCheck would have already attempted to
419
   // parse it, meaning we won't throw here (we never try to parse the same
420
   // thing twice, see LazyParser::checkParsed())
421
0
   if (responseCode/100 == 2 &&
422
0
         !response.exists(h_Contacts) &&
423
0
         !(response.const_header(h_CSeq).method()==CANCEL) )
424
0
   {
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
      
429
0
      NameAddr contact;
430
0
      response.header(h_Contacts).push_back(contact);
431
0
   }
432
433
0
   if (request.isExternal())
434
0
   {
435
0
       response.setFromTU();
436
0
   }
437
0
   else
438
0
   {
439
       // This makes a response to an internally generated request look like it's 
440
       // external even though it isn't
441
0
       response.setFromExternal();
442
0
   }
443
444
0
   if (reason.size())
445
0
   {
446
0
      response.header(h_StatusLine).reason() = reason;
447
0
   }
448
0
   else
449
0
   {
450
0
      getResponseCodeReason(responseCode, response.header(h_StatusLine).reason());
451
0
   }
452
0
}
453
454
SipMessage*
455
Helper::makeResponse(const SipMessage& request, 
456
                     int responseCode, 
457
                     const NameAddr& myContact, 
458
                     const Data& reason, 
459
                     const Data& hostname, 
460
                     const Data& warning)
461
0
{
462
   // .bwc. Exception safety. Catch/rethrow is dicey because we can't rethrow
463
   // resip::BaseException, since it is abstract.
464
0
   std::unique_ptr<SipMessage> response(new SipMessage);
465
466
0
   makeResponse(*response, request, responseCode, reason, hostname, warning);
467
468
   // in general, this should not create a Contact header since only requests
469
   // that create a dialog (or REGISTER requests) should produce a response with
470
   // a contact(s). 
471
0
   response->header(h_Contacts).clear();
472
0
   response->header(h_Contacts).push_back(myContact);
473
0
   return response.release();
474
0
}
475
476
477
SipMessage*
478
Helper::makeResponse(const SipMessage& request, 
479
                     int responseCode, 
480
                     const Data& reason, 
481
                     const Data& hostname, 
482
                     const Data& warning)
483
0
{
484
   // .bwc. Exception safety. Catch/rethrow is dicey because we can't rethrow
485
   // resip::BaseException, since it is abstract.
486
0
   std::unique_ptr<SipMessage> response(new SipMessage);
487
   
488
0
   makeResponse(*response, request, responseCode, reason, hostname, warning);
489
0
   return response.release();
490
0
}
491
492
void
493
Helper::makeRawResponse(Data& raw,
494
                        const SipMessage& msg, 
495
                        int responseCode,
496
                        const Data& additionalHeaders,
497
                        const Data& body)
498
0
{
499
0
   raw.reserve(256);
500
0
   {
501
0
      DataStream encodeStream(raw);
502
0
      encodeStream << "SIP/2.0 " << responseCode << " ";
503
0
      Data reason;
504
0
      getResponseCodeReason(responseCode, reason);
505
0
      encodeStream << reason << Symbols::CRLF;
506
0
      msg.encodeSingleHeader(Headers::Via,encodeStream);
507
0
      msg.encodeSingleHeader(Headers::To,encodeStream);
508
0
      msg.encodeSingleHeader(Headers::From,encodeStream);
509
0
      msg.encodeSingleHeader(Headers::CallID,encodeStream);
510
0
      msg.encodeSingleHeader(Headers::CSeq,encodeStream);
511
0
      encodeStream << additionalHeaders;
512
0
      encodeStream << "Content-Length: " << body.size() << "\r\n\r\n";
513
0
   }
514
0
}
515
516
void   
517
Helper::getResponseCodeReason(int responseCode, Data& reason)
518
0
{
519
0
   switch (responseCode)
520
0
   {
521
0
      case 100: reason = "Trying"; break;
522
0
      case 180: reason = "Ringing"; break;
523
0
      case 181: reason = "Call Is Being Forwarded"; break;
524
0
      case 182: reason = "Queued"; break;
525
0
      case 183: reason = "Session Progress"; break;
526
0
      case 200: reason = "OK"; break;
527
0
      case 202: reason = "Accepted"; break;
528
0
      case 300: reason = "Multiple Choices"; break;
529
0
      case 301: reason = "Moved Permanently"; break;
530
0
      case 302: reason = "Moved Temporarily"; break;
531
0
      case 305: reason = "Use Proxy"; break;
532
0
      case 380: reason = "Alternative Service"; break;
533
0
      case 400: reason = "Bad Request"; break;
534
0
      case 401: reason = "Unauthorized"; break;
535
0
      case 402: reason = "Payment Required"; break;
536
0
      case 403: reason = "Forbidden"; break;
537
0
      case 404: reason = "Not Found"; break;
538
0
      case 405: reason = "Method Not Allowed"; break;
539
0
      case 406: reason = "Not Acceptable"; break;
540
0
      case 407: reason = "Proxy Authentication Required"; break;
541
0
      case 408: reason = "Request Timeout"; break;
542
0
      case 410: reason = "Gone"; break;
543
0
      case 412: reason = "Precondition Failed"; break;
544
0
      case 413: reason = "Request Entity Too Large"; break;
545
0
      case 414: reason = "Request-URI Too Long"; break;
546
0
      case 415: reason = "Unsupported Media Type"; break;
547
0
      case 416: reason = "Unsupported URI Scheme"; break;
548
0
      case 420: reason = "Bad Extension"; break;
549
0
      case 421: reason = "Extension Required"; break;
550
0
      case 422: reason = "Session Interval Too Small"; break;
551
0
      case 423: reason = "Interval Too Brief"; break;
552
0
      case 430: reason = "Flow failed"; break;
553
0
      case 439: reason = "First Hop Lacks Outbound Support"; break;
554
0
      case 480: reason = "Temporarily Unavailable"; break;
555
0
      case 481: reason = "Call/Transaction Does Not Exist"; break;
556
0
      case 482: reason = "Loop Detected"; break;
557
0
      case 483: reason = "Too Many Hops"; break;
558
0
      case 484: reason = "Address Incomplete"; break;
559
0
      case 485: reason = "Ambiguous"; break;
560
0
      case 486: reason = "Busy Here"; break;
561
0
      case 487: reason = "Request Terminated"; break;
562
0
      case 488: reason = "Not Acceptable Here"; break;
563
0
      case 489: reason = "Event Package Not Supported"; break;
564
0
      case 491: reason = "Request Pending"; break;
565
0
      case 493: reason = "Undecipherable"; break;
566
0
      case 500: reason = "Server Internal Error"; break;
567
0
      case 501: reason = "Not Implemented"; break;
568
0
      case 502: reason = "Bad Gateway"; break;
569
0
      case 503: reason = "Service Unavailable"; break;
570
0
      case 504: reason = "Server Time-out"; break;
571
0
      case 505: reason = "Version Not Supported"; break;
572
0
      case 513: reason = "Message Too Large"; break;
573
0
      case 600: reason = "Busy Everywhere"; break;
574
0
      case 603: reason = "Decline"; break;
575
0
      case 604: reason = "Does Not Exist Anywhere"; break;
576
0
      case 606: reason = "Not Acceptable"; break;
577
0
   }
578
0
}
579
580
SipMessage*
581
Helper::makeCancel(const SipMessage& request)
582
0
{
583
0
   resip_assert(request.isRequest());
584
0
   resip_assert(request.header(h_RequestLine).getMethod() == INVITE);
585
0
   std::unique_ptr<SipMessage> cancel(new SipMessage);
586
587
0
   RequestLine rLine(CANCEL, request.header(h_RequestLine).getSipVersion());
588
0
   rLine.uri() = request.header(h_RequestLine).uri();
589
0
   cancel->header(h_RequestLine) = rLine;
590
0
   cancel->header(h_MaxForwards).value() = 70;
591
0
   cancel->header(h_To) = request.header(h_To);
592
0
   cancel->header(h_From) = request.header(h_From);
593
0
   cancel->header(h_CallId) = request.header(h_CallId);
594
0
   if (request.exists(h_ProxyAuthorizations))
595
0
   {
596
0
      cancel->header(h_ProxyAuthorizations) = request.header(h_ProxyAuthorizations);
597
0
   }
598
0
   if (request.exists(h_Authorizations))
599
0
   {
600
0
      cancel->header(h_Authorizations) = request.header(h_Authorizations);
601
0
   }
602
   
603
0
   if (request.exists(h_Routes))
604
0
   {
605
0
      cancel->header(h_Routes) = request.header(h_Routes);
606
0
   }
607
   
608
0
   cancel->header(h_CSeq) = request.header(h_CSeq);
609
0
   cancel->header(h_CSeq).method() = CANCEL;
610
0
   cancel->header(h_Vias).push_back(request.header(h_Vias).front());
611
612
0
   return cancel.release();
613
0
}
614
615
616
SipMessage*
617
Helper::makeFailureAck(const SipMessage& request, const SipMessage& response)
618
0
{
619
0
   resip_assert (request.header(h_Vias).size() >= 1);
620
0
   resip_assert (request.header(h_RequestLine).getMethod() == INVITE);
621
   
622
0
   std::unique_ptr<SipMessage> ack(new SipMessage);
623
624
0
   RequestLine rLine(ACK, request.header(h_RequestLine).getSipVersion());
625
0
   rLine.uri() = request.header(h_RequestLine).uri();
626
0
   ack->header(h_RequestLine) = rLine;
627
0
   ack->header(h_MaxForwards).value() = 70;
628
0
   ack->header(h_CallId) = request.header(h_CallId);
629
0
   ack->header(h_From) = request.header(h_From);
630
0
   ack->header(h_To) = response.header(h_To); // to get to-tag
631
0
   ack->header(h_Vias).push_back(request.header(h_Vias).front());
632
0
   ack->header(h_CSeq) = request.header(h_CSeq);
633
0
   ack->header(h_CSeq).method() = ACK;
634
0
   if (request.exists(h_Routes))
635
0
   {
636
0
      ack->header(h_Routes) = request.header(h_Routes);
637
0
   }
638
   
639
0
   return ack.release();
640
0
}
641
642
643
static const Data cookie("z9hG4bK"); // magic cookie per rfc3261   
644
Data 
645
Helper::computeUniqueBranch()
646
0
{
647
0
   Data result(16, Data::Preallocate);
648
0
   result += cookie;
649
0
   result += Random::getRandomHex(4);
650
0
   result += "C1";
651
0
   result += Random::getRandomHex(2);
652
0
   return result;
653
0
}
654
655
Data
656
Helper::computeCallId()
657
0
{
658
0
   Data hostAndSalt(DnsUtil::getLocalHostName() + Random::getRandomHex(16));
659
0
#ifndef USE_SSL // .bwc. None of this is neccessary if we're using openssl
660
0
#if defined(__linux__) || defined(__APPLE__)
661
0
   pid_t pid = getpid();
662
0
   hostAndSalt.append((char*)&pid,sizeof(pid));
663
0
#endif
664
#ifdef __APPLE__
665
   pthread_t thread = pthread_self();
666
   hostAndSalt.append((char*)&thread,sizeof(thread));
667
#endif
668
#ifdef WIN32
669
   DWORD proccessId = ::GetCurrentProcessId();
670
   DWORD threadId = ::GetCurrentThreadId();
671
   hostAndSalt.append((char*)&proccessId,sizeof(proccessId));
672
   hostAndSalt.append((char*)&threadId,sizeof(threadId));
673
#endif
674
0
#endif // of USE_SSL
675
0
   return hostAndSalt.md5(Data::BASE64);
676
0
}
677
678
Data
679
Helper::computeTag(int numBytes)
680
0
{
681
0
   return Random::getRandomHex(numBytes);
682
0
}
683
684
void
685
Helper::setNonceHelper(NonceHelper *nonceHelper)
686
0
{
687
0
   mNonceHelperPtr.mNonceHelper = nonceHelper;
688
0
}
689
690
NonceHelper* 
691
Helper::getNonceHelper()
692
0
{
693
0
   if (mNonceHelperPtr.mNonceHelper == 0)
694
0
   {
695
0
      mNonceHelperPtr.mNonceHelper = new BasicNonceHelper();
696
0
   }
697
0
   return mNonceHelperPtr.mNonceHelper;
698
0
}
699
700
701
Data
702
Helper::makeNonce(const SipMessage& request, const Data& timestamp)
703
0
{
704
0
   return getNonceHelper()->makeNonce(request, timestamp);
705
0
}
706
707
static Data noBody = MD5Stream().getHex();
708
Data 
709
Helper::makeResponseMD5WithA1(const Data& a1,
710
                              const Data& method, const Data& digestUri, const Data& nonce,
711
                              const Data& qop, const Data& cnonce, const Data& cnonceCount,
712
                              const Contents* entityBody)
713
0
{
714
#ifdef RESIP_DIGEST_LOGGING
715
   Data _a2;
716
   DataStream a2(_a2);
717
#else
718
0
   MD5Stream a2;
719
0
#endif
720
0
   a2 << method
721
0
      << Symbols::COLON
722
0
      << digestUri;
723
724
0
   if (qop == Symbols::authInt)
725
0
   {
726
0
      if (entityBody)
727
0
      {
728
0
         MD5Stream eStream;
729
0
         eStream << *entityBody;
730
0
         a2 << Symbols::COLON << eStream.getHex();
731
#ifdef RESIP_DIGEST_LOGGING
732
         StackLog(<<"auth-int, body length = " << eStream.bytesTaken());
733
#endif
734
0
      }
735
0
      else
736
0
      {
737
0
         a2 << Symbols::COLON << noBody;
738
#ifdef RESIP_DIGEST_LOGGING
739
         StackLog(<<"auth-int, no body");
740
#endif
741
0
      }
742
0
   }
743
   
744
#ifdef RESIP_DIGEST_LOGGING
745
   Data _r;
746
   DataStream r(_r);
747
#else
748
0
   MD5Stream r;
749
0
#endif
750
0
   r << a1
751
0
     << Symbols::COLON
752
0
     << nonce
753
0
     << Symbols::COLON;
754
755
0
   if (!qop.empty())
756
0
   {
757
0
      r << cnonceCount
758
0
        << Symbols::COLON
759
0
        << cnonce
760
0
        << Symbols::COLON
761
0
        << qop
762
0
        << Symbols::COLON;
763
0
   }
764
#ifdef RESIP_DIGEST_LOGGING
765
   a2.flush();
766
   StackLog(<<"A2 = " << _a2);
767
   MD5Stream a2md5;
768
   a2md5 << _a2;
769
   r << a2md5.getHex();
770
   r.flush();
771
   StackLog(<<"response to be hashed (HA1:nonce:HA2) = " << _r);
772
   MD5Stream rmd5;
773
   rmd5 << _r;
774
   return rmd5.getHex();
775
#else
776
0
   r << a2.getHex();
777
778
0
   return r.getHex();
779
0
#endif
780
0
}
781
782
//RFC 2617 3.2.2.1
783
Data 
784
Helper::makeResponseMD5(const Data& username, const Data& password, const Data& realm, 
785
                        const Data& method, const Data& digestUri, const Data& nonce,
786
                        const Data& qop, const Data& cnonce, const Data& cnonceCount,
787
                        const Contents *entity)
788
0
{
789
0
   MD5Stream a1;
790
0
   a1 << username
791
0
      << Symbols::COLON
792
0
      << realm
793
0
      << Symbols::COLON
794
0
      << password;
795
 
796
0
   return makeResponseMD5WithA1(a1.getHex(), method, digestUri, nonce, qop, 
797
0
                                cnonce, cnonceCount, entity);
798
0
}
799
800
static Data digest("digest");
801
std::pair<Helper::AuthResult,Data>
802
Helper::advancedAuthenticateRequest(const SipMessage& request, 
803
                                    const Data& realm,
804
                                    const Data& a1,
805
                                    int expiresDelta,
806
                                    bool proxyAuthorization)
807
0
{
808
0
   Data username;
809
0
   DebugLog(<< "Authenticating: realm=" << realm << " expires=" << expiresDelta);
810
   //DebugLog(<< request);
811
   
812
0
   const ParserContainer<Auth>* auths = 0;
813
0
   if(proxyAuthorization)
814
0
   {
815
0
      if(request.exists(h_ProxyAuthorizations))
816
0
      {
817
0
         auths = &request.header(h_ProxyAuthorizations);
818
0
      }
819
0
   }
820
0
   else
821
0
   {
822
0
      if(request.exists(h_Authorizations))
823
0
      {
824
0
         auths = &request.header(h_Authorizations);
825
0
      }
826
0
   }
827
828
0
   if (auths)
829
0
   {
830
0
      for (ParserContainer<Auth>::const_iterator i = auths->begin(); i != auths->end(); i++)
831
0
      {
832
0
         if (i->exists(p_realm) && 
833
0
             i->exists(p_nonce) &&
834
0
             i->exists(p_response) &&
835
0
             i->param(p_realm) == realm)
836
0
         {
837
0
            if(!isEqualNoCase(i->scheme(),digest))
838
0
            {
839
0
               DebugLog(<< "Scheme must be Digest");
840
0
               continue;
841
0
            }
842
            /* ParseBuffer pb(i->param(p_nonce).data(), i->param(p_nonce).size());
843
            if (!pb.eof() && !isdigit(static_cast< unsigned char >(*pb.position())))
844
            {
845
               DebugLog(<< "Invalid nonce; expected timestamp.");
846
               return make_pair(BadlyFormed,username);
847
            }
848
            const char* anchor = pb.position();
849
            pb.skipToChar(Symbols::COLON[0]);
850
851
            if (pb.eof())
852
            {
853
               DebugLog(<< "Invalid nonce; expected timestamp terminator.");
854
               return make_pair(BadlyFormed,username);
855
            }
856
857
            Data then;
858
            pb.data(then, anchor); 
859
            if (expiresDelta > 0)
860
            {
861
               unsigned int now = (unsigned int)(Timer::getTimeMs()/1000);
862
               if ((unsigned int)then.convertUInt64() + expiresDelta < now)
863
               {
864
                  DebugLog(<< "Nonce has expired.");
865
                  return make_pair(Expired,username);
866
               }
867
            } */
868
869
0
            NonceHelper::Nonce x_nonce = getNonceHelper()->parseNonce(i->param(p_nonce)); 
870
0
            if(x_nonce.getCreationTime() == 0) 
871
0
               return make_pair(BadlyFormed,username);
872
873
0
            if (expiresDelta > 0)
874
0
            {
875
0
               uint64_t now = Timer::getTimeSecs();
876
0
               if (x_nonce.getCreationTime() + expiresDelta < now)
877
0
               {
878
0
                  DebugLog(<< "Nonce has expired.");
879
0
                  return make_pair(Expired,username);
880
0
               }
881
0
            }
882
883
0
            Data then(x_nonce.getCreationTime());
884
0
            if (i->param(p_nonce) != makeNonce(request, then))
885
0
            {
886
0
               InfoLog(<< "Not my nonce. expected=" << makeNonce(request, then) 
887
0
                       << " received=" << i->param(p_nonce)
888
0
                       << " then=" << then);
889
               
890
0
               return make_pair(BadlyFormed,username);
891
0
            }
892
         
893
0
            if (i->exists(p_qop))
894
0
            {
895
0
               if (i->param(p_qop) == Symbols::auth || i->param(p_qop)  == Symbols::authInt)
896
0
               {
897
0
                  if(i->exists(p_uri) && i->exists(p_cnonce) && i->exists(p_nc))
898
0
                  {
899
0
                     if (i->param(p_response) == makeResponseMD5WithA1(a1,
900
0
                                                               getMethodName(request.header(h_RequestLine).getMethod()),
901
0
                                                               i->param(p_uri),
902
0
                                                               i->param(p_nonce),
903
0
                                                               i->param(p_qop),
904
0
                                                               i->param(p_cnonce),
905
0
                                                               i->param(p_nc),
906
0
                                                               request.getContents()))
907
0
                     {
908
0
                        if(i->exists(p_username))
909
0
                        {
910
0
                           username = i->param(p_username);
911
0
                        }
912
0
                        return make_pair(Authenticated,username);
913
0
                     }
914
0
                     else
915
0
                     {
916
0
                        return make_pair(Failed,username);
917
0
                     }
918
0
                  }
919
0
               }
920
0
               else
921
0
               {
922
0
                  InfoLog (<< "Unsupported qop=" << i->param(p_qop));
923
0
                  return make_pair(Failed,username);
924
0
               }
925
0
            }
926
0
            else if(i->exists(p_uri))
927
0
            {
928
0
               if (i->param(p_response) == makeResponseMD5WithA1(a1,
929
0
                                                               getMethodName(request.header(h_RequestLine).getMethod()),
930
0
                                                               i->param(p_uri),
931
0
                                                               i->param(p_nonce)))
932
0
               {
933
0
                  if(i->exists(p_username))
934
0
                  {
935
0
                     username = i->param(p_username);
936
0
                  }
937
0
                  return make_pair(Authenticated,username);
938
0
               }
939
0
               else
940
0
               {
941
0
                  return make_pair(Failed,username);
942
0
               }
943
0
            }
944
0
         }
945
0
         else
946
0
         {
947
0
            return make_pair(BadlyFormed,username);
948
0
         }
949
0
      }
950
0
      return make_pair(BadlyFormed,username);
951
0
   }
952
0
   DebugLog (<< "No authentication headers. Failing request.");
953
0
   return make_pair(Failed,username);
954
0
}
955
956
Helper::AuthResult
957
Helper::authenticateRequest(const SipMessage& request, 
958
                            const Data& realm,
959
                            const Data& password,
960
                            int expiresDelta)
961
0
{
962
0
   DebugLog(<< "Authenticating: realm=" << realm << " expires=" << expiresDelta);
963
   //DebugLog(<< request);
964
965
   // !bwc! Somewhat inefficient. Maybe optimize later.
966
0
   ParserContainer<Auth> auths;
967
968
0
   if(request.exists(h_ProxyAuthorizations))
969
0
   {
970
0
      auths.append(request.header(h_ProxyAuthorizations));
971
0
   }
972
   
973
0
   if(request.exists(h_Authorizations))
974
0
   {
975
0
      auths.append(request.header(h_Authorizations));
976
0
   }
977
978
0
   if(auths.empty())
979
0
   {
980
0
      DebugLog (<< "No authentication headers. Failing request.");
981
0
      return Failed;
982
0
   }
983
984
   // ?bwc? Why is const_iterator& operator=(const iterator& rhs)
985
   // not working properly?
986
   //ParserContainer<Auth>::const_iterator i = auths.begin();
987
   
988
0
   ParserContainer<Auth>::iterator i = auths.begin();
989
         
990
0
   for (; i != auths.end(); i++)
991
0
   {
992
0
      if (i->exists(p_realm) && 
993
0
          i->exists(p_nonce) &&
994
0
          i->exists(p_response) &&
995
0
          i->param(p_realm) == realm)
996
0
      {
997
0
         if(!isEqualNoCase(i->scheme(),digest))
998
0
         {
999
0
            DebugLog(<< "Scheme must be Digest");
1000
0
            continue;
1001
0
         }
1002
         /*
1003
         ParseBuffer pb(i->param(p_nonce).data(), i->param(p_nonce).size());
1004
         if (!pb.eof() && !isdigit(static_cast< unsigned char >(*pb.position())))
1005
         {
1006
            DebugLog(<< "Invalid nonce; expected timestamp.");
1007
            return BadlyFormed;
1008
         }
1009
         const char* anchor = pb.position();
1010
         pb.skipToChar(Symbols::COLON[0]);
1011
1012
         if (pb.eof())
1013
         {
1014
            DebugLog(<< "Invalid nonce; expected timestamp terminator.");
1015
            return BadlyFormed;
1016
         }
1017
1018
         Data then;
1019
         pb.data(then, anchor);
1020
         */
1021
0
         NonceHelper::Nonce x_nonce = getNonceHelper()->parseNonce(i->param(p_nonce));
1022
0
         if(x_nonce.getCreationTime() == 0)
1023
0
            return BadlyFormed;
1024
1025
1026
         
1027
         
1028
         
1029
0
         if (expiresDelta > 0)
1030
0
         {
1031
0
            uint64_t now = Timer::getTimeSecs();
1032
0
            if (x_nonce.getCreationTime() + expiresDelta < now)
1033
0
            {
1034
0
               DebugLog(<< "Nonce has expired.");
1035
0
               return Expired;
1036
0
            }
1037
0
         }
1038
1039
0
         Data then(x_nonce.getCreationTime());
1040
0
         if (i->param(p_nonce) != makeNonce(request, then))
1041
0
         {
1042
0
            InfoLog(<< "Not my nonce.");
1043
0
            return Failed;
1044
0
         }
1045
      
1046
0
         InfoLog (<< " username=" << (i->param(p_username))
1047
0
                  << " password=" << password
1048
0
                  << " realm=" << realm
1049
0
                  << " method=" << getMethodName(request.header(h_RequestLine).getMethod())
1050
0
                  << " uri=" << i->param(p_uri)
1051
0
                  << " nonce=" << i->param(p_nonce));
1052
         
1053
0
         if (i->exists(p_qop))
1054
0
         {
1055
0
            if (i->param(p_qop) == Symbols::auth || i->param(p_qop) == Symbols::authInt)
1056
0
            {
1057
0
               if(i->exists(p_uri) && i->exists(p_cnonce) && i->exists(p_nc))
1058
0
               {
1059
0
                  if (i->param(p_response) == makeResponseMD5(i->param(p_username), 
1060
0
                                                            password,
1061
0
                                                            realm, 
1062
0
                                                            getMethodName(request.header(h_RequestLine).getMethod()),
1063
0
                                                            i->param(p_uri),
1064
0
                                                            i->param(p_nonce),
1065
0
                                                            i->param(p_qop),
1066
0
                                                            i->param(p_cnonce),
1067
0
                                                            i->param(p_nc),
1068
0
                                                            request.getContents()))
1069
0
                  {
1070
0
                     return Authenticated;
1071
0
                  }
1072
0
                  else
1073
0
                  {
1074
0
                     return Failed;
1075
0
                  }
1076
0
               }
1077
0
            }
1078
0
            else
1079
0
            {
1080
0
               InfoLog (<< "Unsupported qop=" << i->param(p_qop));
1081
0
               return Failed;
1082
0
            }
1083
0
         }
1084
0
         else if(i->exists(p_uri))
1085
0
         {
1086
         
1087
0
            if (i->param(p_response) == makeResponseMD5(i->param(p_username), 
1088
0
                                                            password,
1089
0
                                                            realm, 
1090
0
                                                            getMethodName(request.header(h_RequestLine).getMethod()),
1091
0
                                                            i->param(p_uri),
1092
0
                                                            i->param(p_nonce)))
1093
0
            {
1094
0
               return Authenticated;
1095
0
            }
1096
0
            else
1097
0
            {
1098
0
               return Failed;
1099
0
            }
1100
0
         }
1101
0
      }
1102
0
      else
1103
0
      {
1104
0
         return BadlyFormed;
1105
0
      }
1106
0
   }
1107
1108
0
   return BadlyFormed;
1109
1110
0
}
1111
1112
Helper::AuthResult
1113
Helper::authenticateRequestWithA1(const SipMessage& request, 
1114
                                  const Data& realm,
1115
                                  const Data& hA1,
1116
                                  int expiresDelta)
1117
0
{
1118
0
   DebugLog(<< "Authenticating with HA1: realm=" << realm << " expires=" << expiresDelta);
1119
   //DebugLog(<< request);
1120
1121
   // !bwc! Somewhat inefficient. Maybe optimize later.
1122
0
   ParserContainer<Auth> auths;
1123
   
1124
0
   if(request.exists(h_ProxyAuthorizations))
1125
0
   {
1126
0
      auths.append(request.header(h_ProxyAuthorizations));
1127
0
   }
1128
   
1129
0
   if(request.exists(h_Authorizations))
1130
0
   {
1131
0
      auths.append(request.header(h_Authorizations));
1132
0
   }
1133
1134
0
   if(auths.empty())
1135
0
   {
1136
0
      DebugLog (<< "No authentication headers. Failing request.");
1137
0
      return Failed;
1138
0
   }
1139
1140
   // ?bwc? Why is const_iterator& operator=(const iterator& rhs)
1141
   // not working properly?
1142
   //ParserContainer<Auth>::const_iterator i = auths.begin();
1143
   
1144
0
   ParserContainer<Auth>::iterator i = auths.begin();
1145
      
1146
0
   for (;i != auths.end(); i++) 
1147
0
   {
1148
0
      if (i->exists(p_realm) && 
1149
0
          i->exists(p_nonce) &&
1150
0
          i->exists(p_response) &&
1151
0
          i->param(p_realm) == realm)
1152
0
      {
1153
0
         if(!isEqualNoCase(i->scheme(),digest))
1154
0
         {
1155
0
            DebugLog(<< "Scheme must be Digest");
1156
0
            continue;
1157
0
         }
1158
         /*
1159
         ParseBuffer pb(i->param(p_nonce).data(), i->param(p_nonce).size());
1160
         if (!pb.eof() && !isdigit(static_cast< unsigned char >(*pb.position())))
1161
         {
1162
            DebugLog(<< "Invalid nonce; expected timestamp.");
1163
            return BadlyFormed;
1164
         }
1165
         const char* anchor = pb.position();
1166
         pb.skipToChar(Symbols::COLON[0]);
1167
1168
         if (pb.eof())
1169
         {
1170
            DebugLog(<< "Invalid nonce; expected timestamp terminator.");
1171
            return BadlyFormed;
1172
         }
1173
1174
         Data then;
1175
         pb.data(then, anchor);
1176
         */
1177
1178
0
         NonceHelper::Nonce x_nonce = getNonceHelper()->parseNonce(i->param(p_nonce));
1179
0
         if(x_nonce.getCreationTime() == 0)
1180
0
            return BadlyFormed;
1181
1182
1183
1184
0
         if (expiresDelta > 0)
1185
0
         {
1186
0
            uint64_t now = Timer::getTimeSecs();
1187
0
            if (x_nonce.getCreationTime() + expiresDelta < now)
1188
0
            {
1189
0
               DebugLog(<< "Nonce has expired.");
1190
0
               return Expired;
1191
0
            }
1192
0
         }
1193
1194
0
         Data then(x_nonce.getCreationTime());
1195
1196
0
         if (i->param(p_nonce) != makeNonce(request, then))
1197
0
         {
1198
0
            InfoLog(<< "Not my nonce.");
1199
0
            return Failed;
1200
0
         }
1201
      
1202
0
         InfoLog (<< " username=" << (i->param(p_username))
1203
0
                  << " H(A1)=" << hA1
1204
0
                  << " realm=" << realm
1205
0
                  << " method=" << getMethodName(request.header(h_RequestLine).getMethod())
1206
0
                  << " uri=" << i->param(p_uri)
1207
0
                  << " nonce=" << i->param(p_nonce));
1208
         
1209
0
         if (i->exists(p_qop))
1210
0
         {
1211
0
            if (i->param(p_qop) == Symbols::auth || i->param(p_qop) == Symbols::authInt)
1212
0
            {
1213
0
               if(i->exists(p_uri) && i->exists(p_cnonce) && i->exists(p_nc))
1214
0
               {
1215
0
                  if (i->param(p_response) == makeResponseMD5WithA1(hA1, 
1216
0
                                                                  getMethodName(request.header(h_RequestLine).getMethod()),
1217
0
                                                                  i->param(p_uri),
1218
0
                                                                  i->param(p_nonce),
1219
0
                                                                  i->param(p_qop),
1220
0
                                                                  i->param(p_cnonce),
1221
0
                                                                  i->param(p_nc),
1222
0
                                                                  request.getContents()))
1223
0
                  {
1224
0
                     return Authenticated;
1225
0
                  }
1226
0
                  else
1227
0
                  {
1228
0
                     return Failed;
1229
0
                  }
1230
0
               }
1231
0
            }
1232
0
            else
1233
0
            {
1234
0
               InfoLog (<< "Unsupported qop=" << i->param(p_qop));
1235
0
               return Failed;
1236
0
            }
1237
0
         }
1238
0
         else if(i->exists(p_uri))
1239
0
         {
1240
0
            if (i->param(p_response) == makeResponseMD5WithA1(hA1,
1241
0
                                                                  getMethodName(request.header(h_RequestLine).getMethod()),
1242
0
                                                                  i->param(p_uri),
1243
0
                                                                  i->param(p_nonce)))
1244
0
            {
1245
0
               return Authenticated;
1246
0
            }
1247
0
            else
1248
0
            {
1249
0
               return Failed;
1250
0
            }
1251
0
         }
1252
0
      }
1253
0
      else
1254
0
      {
1255
0
         return BadlyFormed;
1256
0
      }
1257
0
   }
1258
1259
0
   return BadlyFormed;
1260
1261
0
}
1262
1263
SipMessage*
1264
Helper::make405(const SipMessage& request,
1265
                const int* allowedMethods,
1266
                int len )
1267
0
{
1268
0
    SipMessage* resp = Helper::makeResponse(request, 405);
1269
1270
0
    if (len < 0)
1271
0
    {
1272
0
        int upperBound = static_cast<int>(MAX_METHODS);
1273
1274
        // The UNKNOWN method name is the first in the enum
1275
0
        for (int i = 1 ; i < upperBound; i ++)
1276
0
        {
1277
0
            int last = 0;
1278
1279
            // ENUMS must be contiguous in order for this to work.
1280
0
            resip_assert( i - last <= 1);
1281
0
            Token t;
1282
0
            t.value() = getMethodName(static_cast<resip::MethodTypes>(i));
1283
0
            resp->header(h_Allows).push_back(t);
1284
0
            last = i;
1285
0
        }
1286
0
    }
1287
0
    else
1288
0
    {
1289
        // use user's list
1290
0
        for ( int i = 0 ; i < len ; i++)
1291
0
        {
1292
0
            Token t;
1293
0
            t.value() = getMethodName(static_cast<resip::MethodTypes>(allowedMethods[i]));
1294
0
            resp->header(h_Allows).push_back(t);
1295
0
        }
1296
0
    }
1297
0
    return resp;
1298
0
}
1299
1300
1301
SipMessage*
1302
Helper::makeProxyChallenge(const SipMessage& request, const Data& realm, bool useAuth, bool stale)
1303
0
{
1304
0
   return makeChallenge(request,realm,useAuth,stale,true);
1305
0
}
1306
1307
SipMessage*
1308
Helper::makeWWWChallenge(const SipMessage& request, const Data& realm, bool useAuth, bool stale)
1309
0
{
1310
0
   return makeChallenge(request,realm,useAuth,stale,false);
1311
0
}
1312
1313
SipMessage*
1314
Helper::makeChallenge(const SipMessage& request, const Data& realm, bool useAuth, bool stale, bool proxy)
1315
0
{
1316
0
   Auth auth;
1317
0
   auth.scheme() = Symbols::Digest;
1318
0
   Data timestamp(Timer::getTimeSecs());
1319
0
   auth.param(p_nonce) = makeNonce(request, timestamp);
1320
0
   auth.param(p_algorithm) = "MD5";
1321
0
   auth.param(p_realm) = realm;
1322
0
   if (useAuth)
1323
0
   {
1324
0
      auth.param(p_qopOptions) = "auth,auth-int";
1325
0
   }
1326
0
   if (stale)
1327
0
   {
1328
0
      auth.param(p_stale) = "true";
1329
0
   }
1330
0
   SipMessage *response;
1331
0
   if(proxy)
1332
0
   {
1333
0
      response = Helper::makeResponse(request, 407);
1334
0
      response->header(h_ProxyAuthenticates).push_back(auth);
1335
0
   }
1336
0
   else
1337
0
   {
1338
0
      response = Helper::makeResponse(request, 401);
1339
0
      response->header(h_WWWAuthenticates).push_back(auth);
1340
0
   }
1341
0
   return response;
1342
0
}
1343
1344
void 
1345
Helper::updateNonceCount(unsigned int& nonceCount, Data& nonceCountString)
1346
0
{
1347
0
   if (!nonceCountString.empty())
1348
0
   {
1349
0
      return;
1350
0
   }
1351
0
   nonceCount++;
1352
0
   {
1353
      //DataStream s(nonceCountString);
1354
      
1355
      //s << std::setw(8) << std::setfill('0') << std::hex << nonceCount;
1356
0
     constexpr size_t bufSize = 128;
1357
0
      char buf[bufSize];
1358
0
     *buf = 0;
1359
1360
0
     std::snprintf(buf,bufSize,"%08x",nonceCount);
1361
0
     nonceCountString = buf;
1362
0
   }
1363
0
   DebugLog(<< "nonceCount is now: [" << nonceCountString << "]");
1364
0
}
1365
1366
1367
Auth 
1368
Helper::makeChallengeResponseAuth(const SipMessage& request,
1369
                                  const Data& username,
1370
                                  const Data& password,
1371
                                  const Auth& challenge,
1372
                                  const Data& cnonce,
1373
                                  unsigned int& nonceCount,
1374
                                  Data& nonceCountString)
1375
0
{
1376
0
   Auth auth;
1377
0
   Data authQop = qopOption(challenge);
1378
0
   if(!authQop.empty())
1379
0
   {
1380
0
       updateNonceCount(nonceCount, nonceCountString);
1381
0
   }
1382
0
   makeChallengeResponseAuth(request, username, password, challenge, cnonce, authQop, nonceCountString, auth);
1383
0
   return auth;
1384
0
}
1385
1386
void
1387
Helper::makeChallengeResponseAuth(const SipMessage& request,
1388
                                  const Data& username,
1389
                                  const Data& password,
1390
                                  const Auth& challenge,
1391
                                  const Data& cnonce,
1392
                                  const Data& authQop,
1393
                                  const Data& nonceCountString,
1394
                                  Auth& auth)
1395
0
{
1396
0
   auth.scheme() = Symbols::Digest;
1397
0
   auth.param(p_username) = username;
1398
0
   resip_assert(challenge.exists(p_realm));
1399
0
   auth.param(p_realm) = challenge.param(p_realm);
1400
0
   resip_assert(challenge.exists(p_nonce));
1401
0
   auth.param(p_nonce) = challenge.param(p_nonce);
1402
0
   Data digestUri;
1403
0
   {
1404
0
      DataStream s(digestUri);
1405
      //s << request.header(h_RequestLine).uri().host(); // wrong 
1406
0
      s << request.header(h_RequestLine).uri(); // right 
1407
0
   }
1408
0
   auth.param(p_uri) = digestUri;
1409
1410
0
   if (!authQop.empty())
1411
0
   {
1412
0
      auth.param(p_response) = Helper::makeResponseMD5(username, 
1413
0
                                                       password,
1414
0
                                                       challenge.param(p_realm), 
1415
0
                                                       getMethodName(request.header(h_RequestLine).getMethod()), 
1416
0
                                                       digestUri, 
1417
0
                                                       challenge.param(p_nonce),
1418
0
                                                       authQop,
1419
0
                                                       cnonce,
1420
0
                                                       nonceCountString,
1421
0
                                                       request.getContents());
1422
0
      auth.param(p_cnonce) = cnonce;
1423
0
      auth.param(p_nc) = nonceCountString;
1424
0
      auth.param(p_qop) = authQop;
1425
0
   }
1426
0
   else
1427
0
   {
1428
0
      resip_assert(challenge.exists(p_realm));
1429
0
      auth.param(p_response) = Helper::makeResponseMD5(username, 
1430
0
                                                       password,
1431
0
                                                       challenge.param(p_realm), 
1432
0
                                                       getMethodName(request.header(h_RequestLine).getMethod()),
1433
0
                                                       digestUri, 
1434
0
                                                       challenge.param(p_nonce));
1435
0
   }
1436
   
1437
0
   if (challenge.exists(p_algorithm))
1438
0
   {
1439
0
      auth.param(p_algorithm) = challenge.param(p_algorithm);
1440
0
   }
1441
0
   else
1442
0
   {
1443
0
      auth.param(p_algorithm) = "MD5";
1444
0
   }
1445
1446
0
   if (challenge.exists(p_opaque) && challenge.param(p_opaque).size() > 0)
1447
0
   {
1448
0
      auth.param(p_opaque) = challenge.param(p_opaque);
1449
0
   }
1450
0
}
1451
1452
// priority-order list of preferred qop tokens
1453
static Data preferredTokens[] = 
1454
{
1455
   "auth-int",
1456
   "auth"
1457
};
1458
static size_t pTokenSize=sizeof(preferredTokens)/sizeof(*preferredTokens);
1459
Data
1460
Helper::qopOption(const Auth& challenge)
1461
0
{
1462
0
   bool found = false;
1463
0
   size_t index = pTokenSize;
1464
0
   if (challenge.exists(p_qopOptions) && !challenge.param(p_qopOptions).empty())
1465
0
   {
1466
0
      ParseBuffer pb(challenge.param(p_qopOptions).data(), challenge.param(p_qopOptions).size());
1467
0
      do
1468
0
      {
1469
0
         const char* anchor = pb.skipWhitespace();
1470
0
         pb.skipToChar(Symbols::COMMA[0]);
1471
0
         Data q;
1472
0
         pb.data(q, anchor);
1473
0
         if (!pb.eof())
1474
0
            pb.skipChar();
1475
0
         for (size_t i=0; i < pTokenSize; i++) 
1476
0
         {
1477
0
            if (q == preferredTokens[i]) 
1478
0
            {
1479
               // found a preferred token; is it higher priority?
1480
0
               if (i < index) 
1481
0
               {
1482
0
                  found = true;
1483
0
                  index = i;
1484
0
               }
1485
0
            }
1486
0
         }
1487
0
      }
1488
0
      while(!pb.eof());
1489
0
   }
1490
1491
0
   if (found)
1492
0
      return preferredTokens[index];
1493
1494
0
   return Data::Empty;
1495
   
1496
0
}
1497
   
1498
1499
Auth 
1500
Helper::makeChallengeResponseAuthWithA1(const SipMessage& request,
1501
                                        const Data& username,
1502
                                        const Data& passwordHashA1,
1503
                                        const Auth& challenge,
1504
                                        const Data& cnonce,
1505
                                        unsigned int& nonceCount,
1506
                                        Data& nonceCountString)
1507
0
{
1508
0
   Auth auth;
1509
0
   Data authQop = qopOption(challenge);
1510
0
   if(!authQop.empty())
1511
0
   {
1512
0
       updateNonceCount(nonceCount, nonceCountString);
1513
0
   }
1514
0
   makeChallengeResponseAuthWithA1(request, username, passwordHashA1, challenge, cnonce, authQop, nonceCountString, auth);
1515
0
   return auth;
1516
0
}
1517
1518
void
1519
Helper::makeChallengeResponseAuthWithA1(const SipMessage& request,
1520
                                        const Data& username,
1521
                                        const Data& passwordHashA1,
1522
                                        const Auth& challenge,
1523
                                        const Data& cnonce,
1524
                                        const Data& authQop,
1525
                                        const Data& nonceCountString,
1526
                                        Auth& auth)
1527
0
{
1528
0
   auth.scheme() = Symbols::Digest;
1529
0
   auth.param(p_username) = username;
1530
0
   resip_assert(challenge.exists(p_realm));
1531
0
   auth.param(p_realm) = challenge.param(p_realm);
1532
0
   resip_assert(challenge.exists(p_nonce));
1533
0
   auth.param(p_nonce) = challenge.param(p_nonce);
1534
0
   Data digestUri;
1535
0
   {
1536
0
      DataStream s(digestUri);
1537
      //s << request.const_header(h_RequestLine).uri().host(); // wrong 
1538
0
      s << request.const_header(h_RequestLine).uri(); // right 
1539
0
   }
1540
0
   auth.param(p_uri) = digestUri;
1541
1542
0
   if (!authQop.empty())
1543
0
   {
1544
0
      auth.param(p_response) = Helper::makeResponseMD5WithA1(passwordHashA1,
1545
0
                                                             getMethodName(request.header(h_RequestLine).getMethod()), 
1546
0
                                                             digestUri, 
1547
0
                                                             challenge.param(p_nonce),
1548
0
                                                             authQop,
1549
0
                                                             cnonce,
1550
0
                                                             nonceCountString,
1551
0
                                                             request.getContents());
1552
0
      auth.param(p_cnonce) = cnonce;
1553
0
      auth.param(p_nc) = nonceCountString;
1554
0
      auth.param(p_qop) = authQop;
1555
0
   }
1556
0
   else
1557
0
   {
1558
0
      resip_assert(challenge.exists(p_realm));
1559
0
      auth.param(p_response) = Helper::makeResponseMD5WithA1(passwordHashA1,
1560
0
                                                             getMethodName(request.header(h_RequestLine).getMethod()),
1561
0
                                                             digestUri, 
1562
0
                                                             challenge.param(p_nonce));
1563
0
   }
1564
   
1565
0
   if (challenge.exists(p_algorithm))
1566
0
   {
1567
0
      auth.param(p_algorithm) = challenge.param(p_algorithm);
1568
0
   }
1569
0
   else
1570
0
   {
1571
0
      auth.param(p_algorithm) = "MD5";
1572
0
   }
1573
1574
0
   if (challenge.exists(p_opaque) && challenge.param(p_opaque).size() > 0)
1575
0
   {
1576
0
      auth.param(p_opaque) = challenge.param(p_opaque);
1577
0
   }
1578
0
}
1579
   
1580
//.dcm. all the auth stuff should be yanked out of helper and
1581
//architected for algorithm independance
1582
bool 
1583
Helper::algorithmAndQopSupported(const Auth& challenge)
1584
0
{
1585
0
   if ( !(challenge.exists(p_nonce) && challenge.exists(p_realm)))
1586
0
   {
1587
0
      return false;
1588
0
   }
1589
0
   return ((!challenge.exists(p_algorithm) 
1590
0
            || isEqualNoCase(challenge.param(p_algorithm), "MD5"))
1591
0
           && (!challenge.exists(p_qop) 
1592
0
               || isEqualNoCase(challenge.param(p_qop), Symbols::auth)
1593
0
               || isEqualNoCase(challenge.param(p_qop), Symbols::authInt)));
1594
0
}
1595
1596
SipMessage& 
1597
Helper::addAuthorization(SipMessage& request,
1598
                         const SipMessage& challenge,
1599
                         const Data& username,
1600
                         const Data& password,
1601
                         const Data& cnonce,
1602
                         unsigned int& nonceCount)
1603
0
{
1604
0
   Data nonceCountString = Data::Empty;
1605
   
1606
0
   resip_assert(challenge.isResponse());
1607
0
   resip_assert(challenge.header(h_StatusLine).responseCode() == 401 ||
1608
0
          challenge.header(h_StatusLine).responseCode() == 407);
1609
1610
0
   if (challenge.exists(h_ProxyAuthenticates))
1611
0
   {
1612
0
      const ParserContainer<Auth>& auths = challenge.header(h_ProxyAuthenticates);
1613
0
      for (ParserContainer<Auth>::const_iterator i = auths.begin();
1614
0
           i != auths.end(); i++)
1615
0
      {
1616
0
         request.header(h_ProxyAuthorizations).push_back(makeChallengeResponseAuth(request, username, password, *i, 
1617
0
                                                                                    cnonce, nonceCount, nonceCountString));
1618
0
      }
1619
0
   }
1620
0
   if (challenge.exists(h_WWWAuthenticates))
1621
0
   {
1622
0
      const ParserContainer<Auth>& auths = challenge.header(h_WWWAuthenticates);
1623
0
      for (ParserContainer<Auth>::const_iterator i = auths.begin();
1624
0
           i != auths.end(); i++)
1625
0
      {
1626
0
         request.header(h_Authorizations).push_back(makeChallengeResponseAuth(request, username, password, *i,
1627
0
                                                                               cnonce, nonceCount, nonceCountString));
1628
0
      }
1629
0
   }
1630
0
   return request;
1631
0
}
1632
      
1633
Uri
1634
Helper::makeUri(const Data& aor, const Data& scheme)
1635
0
{
1636
0
   resip_assert(!aor.prefix("sip:"));
1637
0
   resip_assert(!aor.prefix("sips:"));
1638
   
1639
0
   Data tmp(aor.size() + scheme.size() + 1, Data::Preallocate);
1640
0
   tmp += scheme;
1641
0
   tmp += Symbols::COLON;
1642
0
   tmp += aor;
1643
0
   Uri uri(tmp);
1644
0
   return uri;
1645
0
}
1646
1647
void
1648
Helper::processStrictRoute(SipMessage& request)
1649
0
{
1650
0
   if (request.exists(h_Routes) && 
1651
0
       !request.const_header(h_Routes).empty() &&
1652
0
       !request.const_header(h_Routes).front().uri().exists(p_lr))
1653
0
   {
1654
      // The next hop is a strict router.  Move the next hop into the
1655
      // Request-URI and move the ultimate destination to the end of the
1656
      // route list.  Force the message target to be the next hop router.
1657
0
      request.header(h_Routes).push_back(NameAddr(request.const_header(h_RequestLine).uri()));
1658
0
      request.header(h_RequestLine).uri() = request.const_header(h_Routes).front().uri();
1659
0
      request.header(h_Routes).pop_front(); // !jf!
1660
0
      resip_assert(!request.hasForceTarget());
1661
0
      request.setForceTarget(request.const_header(h_RequestLine).uri());
1662
0
   }
1663
0
}
1664
1665
void
1666
Helper::massageRoute(const SipMessage& request, NameAddr& rt)
1667
0
{
1668
0
   resip_assert(request.isRequest());
1669
   // .bwc. Let's not record-route with a tel uri or something, shall we?
1670
   // If the topmost route header is malformed, we can get along without.
1671
0
   if (!request.empty(h_Routes) && 
1672
0
       request.header(h_Routes).front().isWellFormed() &&
1673
0
       (request.header(h_Routes).front().uri().scheme() == "sip" ||
1674
0
        request.header(h_Routes).front().uri().scheme() == "sips" ))
1675
0
   {
1676
0
      rt.uri().scheme() = request.header(h_Routes).front().uri().scheme();
1677
0
   }
1678
0
   else if(request.header(h_RequestLine).uri().scheme() == "sip" ||
1679
0
           request.header(h_RequestLine).uri().scheme() == "sips")
1680
0
   {
1681
0
      rt.uri().scheme() = request.header(h_RequestLine).uri().scheme();
1682
0
   }
1683
   
1684
0
   rt.uri().param(p_lr);
1685
0
}
1686
1687
int
1688
Helper::getPortForReply(SipMessage& request)
1689
0
{
1690
0
   resip_assert(request.isRequest());
1691
0
   int port = 0;
1692
0
   TransportType transportType = toTransportType(
1693
0
      request.const_header(h_Vias).front().transport());
1694
0
   if(isReliable(transportType))
1695
0
   {
1696
      // 18.2.2 - bullet 1 and 2 
1697
0
      port = request.getSource().getPort();
1698
0
      if(port == 0) // .slg. not sure if it makes sense for sourcePort to be 0
1699
0
      {
1700
0
         port = request.const_header(h_Vias).front().sentPort();
1701
0
      }
1702
0
   }
1703
0
   else   // unreliable transport 18.2.2 bullets 3 and 4
1704
0
   {
1705
0
      if (request.const_header(h_Vias).front().exists(p_rport))
1706
0
      {
1707
0
         port = request.getSource().getPort();
1708
0
      }
1709
0
      else
1710
0
      {
1711
0
         port = request.const_header(h_Vias).front().sentPort();
1712
0
      }
1713
0
   }
1714
1715
   // If we haven't got a valid port yet, then use the default
1716
0
   if (port <= 0 || port > 65535) 
1717
0
   {
1718
0
      if(transportType == TLS ||
1719
0
         transportType == DTLS)
1720
0
      {
1721
0
         port = Symbols::DefaultSipsPort;
1722
0
      }
1723
0
      else
1724
0
      {
1725
0
         port = Symbols::DefaultSipPort;
1726
0
      }
1727
0
   }
1728
0
   return port;
1729
0
}
1730
1731
Uri 
1732
Helper::fromAor(const Data& aor, const Data& scheme)
1733
0
{
1734
0
   return makeUri(aor, scheme);
1735
0
}
1736
1737
bool
1738
Helper::validateMessage(const SipMessage& message,resip::Data* reason)
1739
0
{
1740
0
   if (message.empty(h_To) || 
1741
0
       message.empty(h_From) || 
1742
0
       message.empty(h_CSeq) || 
1743
0
       message.empty(h_CallId) || 
1744
0
       message.empty(h_Vias) ||
1745
0
       message.empty(h_Vias))
1746
0
   {
1747
0
      InfoLog(<< "Missing mandatory header fields (To, From, CSeq, Call-Id or Via)");
1748
0
      DebugLog(<< message);
1749
0
      if(reason) *reason="Missing mandatory header field";
1750
0
      return false;
1751
0
   }
1752
0
   else
1753
0
   {
1754
0
      if(!message.header(h_CSeq).isWellFormed())
1755
0
      {
1756
0
         InfoLog(<<"Malformed CSeq header");
1757
0
         if(reason) *reason="Malformed CSeq header";
1758
0
         return false;
1759
0
      }
1760
      
1761
0
      if(!message.header(h_Vias).front().isWellFormed())
1762
0
      {
1763
0
         InfoLog(<<"Malformed topmost Via header");
1764
0
         if(reason) *reason="Malformed topmost Via header";
1765
0
         return false;
1766
0
      }
1767
      
1768
0
      if (message.isRequest())
1769
0
      {
1770
0
         if(!message.header(h_RequestLine).isWellFormed())
1771
0
         {
1772
0
            InfoLog(<< "Illegal request line");
1773
0
            if(reason) *reason="Malformed Request Line";
1774
0
            return false;            
1775
0
         }
1776
         
1777
0
         if(message.header(h_RequestLine).method()!=message.header(h_CSeq).method())
1778
0
         {
1779
0
            InfoLog(<< "Method mismatch btw Request Line and CSeq");
1780
0
            if(reason) *reason="Method mismatch btw Request Line and CSeq";
1781
0
            return false;
1782
0
         }
1783
0
      }
1784
0
      else
1785
0
      {
1786
0
         if(!message.header(h_StatusLine).isWellFormed())
1787
0
         {
1788
0
            InfoLog(<< "Malformed status line");
1789
0
            if(reason) *reason="Malformed status line";
1790
0
            return false;            
1791
0
         }
1792
0
      }
1793
      
1794
0
      return true;
1795
0
   }
1796
0
}
1797
1798
#if defined(USE_SSL) && !defined(OPENSSL_NO_BF)
1799
#include <openssl/opensslv.h>
1800
#include <openssl/blowfish.h>
1801
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
1802
#include <openssl/evp.h>
1803
#include <openssl/params.h>
1804
#include <openssl/core_names.h>
1805
#endif
1806
1807
static const Data sep("[]");
1808
static const Data pad("\0\0\0\0\0\0\0", 7);
1809
static const Data GRUU("_GRUU");
1810
static const int saltBytes(16);
1811
1812
Data
1813
Helper::gruuUserPart(const Data& instanceId,
1814
                     const Data& aor,
1815
                     const Data& key)
1816
{
1817
   unsigned char ivec[8];      
1818
1819
   ivec[0] = '\x6E';
1820
   ivec[1] = '\xE7';
1821
   ivec[2] = '\xB0';
1822
   ivec[3] = '\x4A';
1823
   ivec[4] = '\x45';
1824
   ivec[5] = '\x93';
1825
   ivec[6] = '\x7D';
1826
   ivec[7] = '\x51';
1827
1828
   const Data salt(resip::Random::getRandomHex(saltBytes));
1829
1830
   const Data token(salt + instanceId + sep + aor + '\0' +
1831
                    pad.substr(0, (8 - ((salt.size() + 
1832
                                         instanceId.size() + 
1833
                                         sep.size() + 1 
1834
                                         + aor.size() ) % 8))
1835
                               % 8));
1836
   std::vector<unsigned char> out;
1837
1838
#if OPENSSL_VERSION_NUMBER < 0x30000000L
1839
   out.resize(token.size());
1840
1841
   BF_KEY fish;
1842
   BF_set_key(&fish, (int)key.size(), (const unsigned char*)key.data());
1843
1844
   BF_cbc_encrypt((const unsigned char*)token.data(),
1845
                  &out[0],
1846
                  (long)token.size(),
1847
                  &fish,
1848
                  ivec,
1849
                  BF_ENCRYPT);
1850
#else
1851
   const EVP_CIPHER* pCipher = EVP_bf_cbc();
1852
   std::size_t out_size = token.size();
1853
   int block_size = EVP_CIPHER_get_block_size(pCipher);
1854
   if (block_size > 1)
1855
   {
1856
      std::size_t tail_size = out_size % block_size;
1857
      if (tail_size > 0)
1858
         out_size += block_size - tail_size;
1859
   }
1860
   out.resize(out_size);
1861
1862
   std::unique_ptr<EVP_CIPHER_CTX, OpenSSLDeleter> pCipherCtx(EVP_CIPHER_CTX_new());
1863
   if (!pCipherCtx)
1864
      throw std::bad_alloc();
1865
1866
   std::size_t keylen = key.size();
1867
   const OSSL_PARAM params[] = {
1868
      OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_KEYLEN, &keylen),
1869
      OSSL_PARAM_construct_end()
1870
   };
1871
   int res = EVP_EncryptInit_ex2(pCipherCtx.get(), pCipher,
1872
      reinterpret_cast<const unsigned char*>(key.data()), ivec, params);
1873
   if (res <= 0)
1874
      throw std::runtime_error("Failed to initialize encryption context");
1875
1876
   resip_assert(static_cast<unsigned int>(EVP_CIPHER_CTX_get_iv_length(pCipherCtx.get())) <= sizeof(ivec));
1877
1878
   int outlen = static_cast<int>(out_size);
1879
   res = EVP_EncryptUpdate(pCipherCtx.get(), out.data(), &outlen,
1880
      reinterpret_cast<const unsigned char*>(token.data()), token.size());
1881
   if (res > 0)
1882
   {
1883
      resip_assert(static_cast<unsigned int>(outlen) <= out_size);
1884
      int outlen2 = static_cast<int>(out_size - outlen);
1885
      res = EVP_EncryptFinal_ex(pCipherCtx.get(), out.data() + outlen, &outlen2);
1886
      if (res > 0)
1887
      {
1888
         outlen += outlen2;
1889
         resip_assert(static_cast<unsigned int>(outlen) <= out_size);
1890
         out.resize(static_cast<unsigned int>(outlen));
1891
      }
1892
   }
1893
1894
   if (res <= 0)
1895
      throw std::runtime_error("Failed to encrypt GRUU user part");
1896
#endif
1897
1898
   return GRUU + Data(out.data(), (Data::size_type)out.size()).base64encode(true/*safe URL*/);
1899
}
1900
1901
std::pair<Data, Data>
1902
Helper::fromGruuUserPart(const Data& gruuUserPart,
1903
                         const Data& key)
1904
{
1905
   unsigned char ivec[8];      
1906
1907
   ivec[0] = '\x6E';
1908
   ivec[1] = '\xE7';
1909
   ivec[2] = '\xB0';
1910
   ivec[3] = '\x4A';
1911
   ivec[4] = '\x45';
1912
   ivec[5] = '\x93';
1913
   ivec[6] = '\x7D';
1914
   ivec[7] = '\x51';
1915
1916
   if (gruuUserPart.size() < GRUU.size())
1917
   {
1918
      return std::pair<Data, Data>();
1919
   }
1920
1921
   const Data gruu = gruuUserPart.substr(GRUU.size());
1922
   const Data decoded = gruu.base64decode();
1923
   std::vector<unsigned char> out(gruuUserPart.size() + 1);
1924
1925
#if OPENSSL_VERSION_NUMBER < 0x30000000L
1926
   BF_KEY fish;
1927
   BF_set_key(&fish, (int)key.size(), (const unsigned char*)key.data());
1928
1929
   BF_cbc_encrypt((const unsigned char*)decoded.data(),
1930
                  &out[0],
1931
                  (long)decoded.size(),
1932
                  &fish,
1933
                  ivec,
1934
                  BF_DECRYPT);
1935
#else
1936
   std::unique_ptr<EVP_CIPHER_CTX, OpenSSLDeleter> pCipherCtx(EVP_CIPHER_CTX_new());
1937
   if (!pCipherCtx)
1938
      throw std::bad_alloc();
1939
1940
   std::size_t keylen = key.size();
1941
   const OSSL_PARAM params[] = {
1942
       OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_KEYLEN, &keylen),
1943
       OSSL_PARAM_construct_end()
1944
   };
1945
   int res = EVP_DecryptInit_ex2(pCipherCtx.get(), EVP_bf_cbc(),
1946
      reinterpret_cast<const unsigned char*>(key.data()), ivec, params);
1947
   if (res <= 0)
1948
      throw std::runtime_error("Failed to initialize decryption context");
1949
1950
   resip_assert(static_cast<unsigned int>(EVP_CIPHER_CTX_get_iv_length(pCipherCtx.get())) <= sizeof(ivec));
1951
1952
   const std::size_t out_size = out.size();
1953
   int outlen = static_cast<int>(out_size);
1954
   res = EVP_DecryptUpdate(pCipherCtx.get(), out.data(), &outlen,
1955
      reinterpret_cast<const unsigned char*>(decoded.data()), decoded.size());
1956
   if (res > 0)
1957
   {
1958
      resip_assert(static_cast<unsigned int>(outlen) <= out_size);
1959
      int outlen2 = static_cast<int>(out_size - outlen);
1960
      res = EVP_DecryptFinal_ex(pCipherCtx.get(), out.data() + outlen, &outlen2);
1961
      if (res > 0)
1962
      {
1963
         outlen += outlen2;
1964
         resip_assert(static_cast<unsigned int>(outlen) <= out_size);
1965
         out.resize(static_cast<unsigned int>(outlen));
1966
      }
1967
   }
1968
1969
   if (res <= 0)
1970
      throw std::runtime_error("Failed to decrypt GRUU user part");
1971
#endif
1972
1973
   const Data pair(out.data(), (Data::size_type)out.size());
1974
1975
   Data::size_type pos = pair.find(sep);
1976
   if (pos == Data::npos)
1977
   {
1978
      return std::pair<Data, Data>();
1979
   }
1980
1981
   return std::make_pair(pair.substr(2*saltBytes, pos), // strip out the salt
1982
                         pair.substr(pos+sep.size()));
1983
}
1984
#endif
1985
1986
Helper::ContentsSecAttrs::ContentsSecAttrs(std::unique_ptr<Contents> contents,
1987
                                           std::unique_ptr<SecurityAttributes> attributes)
1988
0
   : mContents(std::move(contents)),
1989
0
     mAttributes(std::move(attributes))
1990
0
{}
1991
1992
1993
Contents*
1994
extractFromPkcs7Recurse(Contents* tree,
1995
                        const Data& signerAor,
1996
                        const Data& receiverAor,
1997
                        SecurityAttributes* attributes,
1998
                        Security& security)
1999
0
{
2000
0
   Pkcs7Contents* pk;
2001
0
   if ((pk = dynamic_cast<Pkcs7Contents*>(tree)))
2002
0
   {
2003
0
      InfoLog( << "GREG1: " << *pk );
2004
#if defined(USE_SSL)
2005
      Contents* contents = security.decrypt(receiverAor, pk);
2006
      if (contents)
2007
      {
2008
         attributes->setEncrypted();
2009
      }
2010
      return contents;
2011
#else
2012
0
      return 0;
2013
0
#endif
2014
0
   }
2015
0
   MultipartSignedContents* mps;
2016
0
   if ((mps = dynamic_cast<MultipartSignedContents*>(tree)))
2017
0
   {
2018
0
      InfoLog( << "GREG2: " << *mps );
2019
#if defined(USE_SSL)
2020
      Data signer;
2021
      SignatureStatus sigStatus;
2022
      Contents* b = extractFromPkcs7Recurse(security.checkSignature(mps, 
2023
                                                                    &signer,
2024
                                                                    &sigStatus),
2025
                                            signerAor,
2026
                                            receiverAor, attributes, security);
2027
      attributes->setSigner(signer);
2028
      attributes->setSignatureStatus(sigStatus);
2029
      return b->clone();
2030
#else
2031
0
      return mps->parts().front()->clone();
2032
0
#endif      
2033
0
   }
2034
0
   MultipartAlternativeContents* alt;
2035
0
   if ((alt = dynamic_cast<MultipartAlternativeContents*>(tree)))
2036
0
   {
2037
0
      InfoLog( << "GREG3: " << *alt );
2038
0
      for (MultipartAlternativeContents::Parts::reverse_iterator i = alt->parts().rbegin();
2039
0
           i != alt->parts().rend(); ++i)
2040
0
      {
2041
0
         Contents* b = extractFromPkcs7Recurse(*i, signerAor, receiverAor, attributes, security);
2042
0
         if (b)
2043
0
         {
2044
0
            return b;
2045
0
         }
2046
0
      }
2047
0
   }
2048
2049
0
   MultipartMixedContents* mult;
2050
0
   if ((mult = dynamic_cast<MultipartMixedContents*>(tree)))
2051
0
   {
2052
0
      InfoLog( << "GREG4: " << *mult );
2053
0
      for (MultipartMixedContents::Parts::iterator i = mult->parts().begin();
2054
0
           i != mult->parts().end(); ++i)
2055
0
      {
2056
0
         Contents* b = extractFromPkcs7Recurse(*i, signerAor, receiverAor,
2057
0
                                               attributes, security);
2058
0
         if (b)
2059
0
         {
2060
0
            return b;
2061
0
         }
2062
0
      };
2063
2064
0
      return 0;
2065
0
   }
2066
2067
0
   return tree->clone();
2068
0
}
2069
2070
Helper::ContentsSecAttrs
2071
Helper::extractFromPkcs7(const SipMessage& message, 
2072
                         Security& security)
2073
0
{
2074
0
   SecurityAttributes* attr = new SecurityAttributes;
2075
   // .dlb. currently flattening SecurityAttributes?
2076
   //attr->setIdentity(message.getIdentity());
2077
0
   attr->setIdentity(message.header(h_From).uri().getAor());
2078
0
   Contents *b = message.getContents();
2079
0
   if (b) 
2080
0
   {
2081
0
      Data fromAor(message.header(h_From).uri().getAor());
2082
0
      Data toAor(message.header(h_To).uri().getAor());
2083
0
      if (message.isRequest())
2084
0
      {
2085
0
         b = extractFromPkcs7Recurse(b, fromAor, toAor, attr, security);
2086
0
      }
2087
0
      else // its a response
2088
0
      {
2089
0
         b = extractFromPkcs7Recurse(b, toAor, fromAor, attr, security);
2090
0
      }
2091
0
   }
2092
0
   std::unique_ptr<Contents> c(b);
2093
0
   std::unique_ptr<SecurityAttributes> a(attr);
2094
0
   return ContentsSecAttrs(std::move(c), std::move(a));
2095
0
}
2096
2097
Helper::FailureMessageEffect 
2098
Helper::determineFailureMessageEffect(const SipMessage& response,
2099
    const std::set<int>* additionalTransactionTerminatingResponses)
2100
0
{
2101
0
   resip_assert(response.isResponse());
2102
0
   int code = response.header(h_StatusLine).statusCode();
2103
0
   resip_assert(code >= 400);
2104
   
2105
0
   if (additionalTransactionTerminatingResponses &&
2106
0
       (additionalTransactionTerminatingResponses->end() != additionalTransactionTerminatingResponses->find(code)))
2107
0
   {
2108
0
      return Helper::TransactionTermination;
2109
0
   }
2110
2111
0
   switch(code)
2112
0
   {
2113
0
      case 404:
2114
0
      case 410:
2115
0
      case 416:
2116
0
      case 480:  // but maybe not, still not quite decided:
2117
0
      case 481:
2118
0
      case 482: // but maybe not, still not quite decided:
2119
0
      case 484:
2120
0
      case 485:
2121
0
      case 502:
2122
0
      case 604:
2123
0
         return DialogTermination;
2124
0
      case 403:
2125
0
      case 489: //only for only subscription
2126
0
      case 408:  //again, maybe not. This seems best.
2127
0
         return UsageTermination;      
2128
0
      case 400:
2129
0
      case 401:
2130
0
      case 402:
2131
0
      case 405:  //doesn't agree w/  -00 of dialogusage
2132
0
      case 406:
2133
0
      case 412:
2134
0
      case 413:
2135
0
      case 414:
2136
0
      case 415:
2137
0
      case 420:
2138
0
      case 421:
2139
0
      case 423:
2140
2141
0
      case 429: // but if this the refer creating the Subscription, no sub will be created.
2142
0
      case 486:
2143
0
      case 487:
2144
0
      case 488:
2145
0
      case 491: 
2146
0
      case 493:
2147
0
      case 494:
2148
0
      case 500:
2149
0
      case 505:
2150
0
      case 513:
2151
0
      case 603:
2152
0
      case 606:
2153
0
         return TransactionTermination;
2154
0
      case 483: // who knows, gravefully terminate or just destroy dialog
2155
0
      case 501:
2156
0
         return ApplicationDependant;
2157
0
      default:
2158
0
         if (code < 600)
2159
0
         {
2160
0
            if (response.exists(h_RetryAfter))
2161
2162
0
            {
2163
0
               return RetryAfter;
2164
0
            }
2165
0
            else
2166
0
            {
2167
0
               return OptionalRetryAfter;
2168
0
            }
2169
0
         }
2170
0
         else
2171
0
         {
2172
0
            if (response.exists(h_RetryAfter))
2173
0
            {
2174
0
               return RetryAfter;
2175
0
            }
2176
0
            else
2177
0
            {
2178
0
               return ApplicationDependant;
2179
0
            }
2180
0
         }
2181
0
   }
2182
0
}
2183
2184
SdpContents* getSdpRecurse(Contents* tree)
2185
0
{
2186
0
   if (dynamic_cast<SdpContents*>(tree))
2187
0
   {
2188
0
      return static_cast<SdpContents*>(tree);
2189
0
   }
2190
2191
0
   MultipartSignedContents* mps;
2192
0
   if ((mps = dynamic_cast<MultipartSignedContents*>(tree)))
2193
0
   {
2194
0
      try
2195
0
      {
2196
0
         MultipartSignedContents::Parts::const_iterator it = mps->parts().begin();
2197
0
         Contents* contents = getSdpRecurse(*it);
2198
0
         return static_cast<SdpContents*>(contents);
2199
0
      }
2200
0
      catch (ParseException& e)
2201
0
      {
2202
0
         ErrLog(<< e.name() << endl << e.getMessage());       
2203
0
      }
2204
0
      catch (BaseException& e)
2205
0
      {
2206
0
         ErrLog(<< e.name() << endl << e.getMessage());
2207
0
      }
2208
2209
0
      return 0;
2210
0
   }
2211
2212
0
   MultipartAlternativeContents* alt;
2213
0
   if ((alt = dynamic_cast<MultipartAlternativeContents*>(tree)))
2214
0
   {
2215
0
      try
2216
0
      {
2217
0
         for (MultipartAlternativeContents::Parts::reverse_iterator i = alt->parts().rbegin();
2218
0
              i != alt->parts().rend(); ++i)
2219
0
         {
2220
0
            Contents* contents = getSdpRecurse(*i);
2221
0
            if (contents)
2222
0
            {
2223
0
               return static_cast<SdpContents*>(contents);
2224
0
            }
2225
0
         }
2226
0
      }
2227
0
      catch (ParseException& e)
2228
0
      {
2229
0
         ErrLog(<< e.name() << endl << e.getMessage());
2230
0
      }
2231
0
      catch (BaseException& e)
2232
0
      {
2233
0
         ErrLog(<< e.name() << endl << e.getMessage());
2234
0
      }
2235
2236
0
      return 0;
2237
0
   }
2238
2239
0
   MultipartMixedContents* mult;
2240
0
   if ((mult = dynamic_cast<MultipartMixedContents*>(tree)))
2241
0
   {
2242
2243
0
      try
2244
0
      {
2245
0
         for (MultipartMixedContents::Parts::iterator i = mult->parts().begin();
2246
0
              i != mult->parts().end(); ++i)
2247
0
         {
2248
0
            Contents* contents = getSdpRecurse(*i);
2249
0
            if (contents)
2250
0
            {
2251
0
               return static_cast<SdpContents*>(contents);
2252
0
            }
2253
0
         }
2254
0
      }
2255
0
      catch (ParseException& e)
2256
0
      {
2257
0
         ErrLog(<< e.name() << endl << e.getMessage());
2258
0
      }
2259
0
      catch (BaseException& e)
2260
0
      {
2261
0
         ErrLog(<< e.name() << endl << e.getMessage());
2262
0
      }
2263
2264
0
      return 0;
2265
0
   }
2266
2267
0
   return 0;
2268
0
}
2269
2270
unique_ptr<SdpContents> Helper::getSdp(Contents* tree)
2271
0
{
2272
0
   if (tree) 
2273
0
   {
2274
0
      SdpContents* sdp = getSdpRecurse(tree);
2275
2276
0
      if (sdp)
2277
0
      {
2278
0
         DebugLog(<< "Got sdp" << endl);
2279
0
         return unique_ptr<SdpContents>(static_cast<SdpContents*>(sdp->clone()));
2280
0
      }
2281
0
   }
2282
2283
   //DebugLog(<< "No sdp" << endl);
2284
0
   return nullptr;
2285
0
}
2286
2287
bool 
2288
Helper::isClientBehindNAT(const SipMessage& request, bool privateToPublicOnly)
2289
0
{
2290
0
   resip_assert(request.isRequest());
2291
0
   resip_assert(!request.header(h_Vias).empty());
2292
2293
   // If received parameter is on top Via, then the source of the message doesn't match
2294
   // the address provided in the via.  Assume this is because the sender is behind a NAT.
2295
   // The assumption here is that this SipStack instance is the first hop in a public SIP server
2296
   // architecture, and that clients are directly connected to this instance.
2297
0
   if(request.header(h_Vias).front().exists(p_received))
2298
0
   {
2299
0
      if(privateToPublicOnly)
2300
0
      {
2301
         // Ensure the via host is an IP address (note: web-rtc uses hostnames here instead)
2302
0
         if(DnsUtil::isIpV4Address(request.header(h_Vias).front().sentHost()) 
2303
0
#ifdef USE_IPV6
2304
0
             || DnsUtil::isIpV6Address(request.header(h_Vias).front().sentHost())
2305
0
#endif
2306
0
             )
2307
0
         {
2308
0
            if(Tuple(request.header(h_Vias).front().sentHost(), 0, UNKNOWN_TRANSPORT).isPrivateAddress() &&
2309
0
                !Tuple(request.header(h_Vias).front().param(p_received), 0, UNKNOWN_TRANSPORT).isPrivateAddress())
2310
0
            {
2311
0
                return true;
2312
0
            }
2313
0
            else
2314
0
            {
2315
0
                return false;
2316
0
            }
2317
0
         }
2318
0
         else
2319
0
         {
2320
             // In this case the via host is likely a hostname (possible with web-rtc) and we will assume the
2321
             // client is behind a NAT, even though we don't know for sure
2322
0
             return !Tuple(request.header(h_Vias).front().param(p_received), 0, UNKNOWN_TRANSPORT).isPrivateAddress();
2323
0
         }
2324
0
      }
2325
0
      return true;
2326
0
   }
2327
0
   return false;
2328
0
}
2329
2330
Tuple
2331
Helper::getClientPublicAddress(const SipMessage& request)
2332
0
{
2333
0
   resip_assert(request.isRequest());
2334
0
   resip_assert(!request.header(h_Vias).empty());
2335
2336
   // Iterate through Via's starting at the bottom (closest to the client).  Return the first
2337
   // public address found from received parameter if present, or Via host.
2338
0
   Vias::const_iterator it = request.header(h_Vias).end();
2339
0
   while(true)
2340
0
   {
2341
0
      it--;
2342
0
      if(it->exists(p_received))
2343
0
      {
2344
         // Check IP from received parameter
2345
0
         Tuple address(it->param(p_received), 0, UNKNOWN_TRANSPORT);
2346
0
         if(!address.isPrivateAddress())
2347
0
         {
2348
0
            address.setPort(it->exists(p_rport) ? it->param(p_rport).port() : it->sentPort());
2349
0
            address.setType(Tuple::toTransport(it->transport()));
2350
0
            return address;
2351
0
         }
2352
0
      }
2353
2354
      // Check IP from Via sentHost
2355
0
      if(DnsUtil::isIpV4Address(it->sentHost())  // Ensure the via host is an IP address (note: web-rtc uses hostnames here instead)
2356
0
#ifdef USE_IPV6
2357
0
          || DnsUtil::isIpV6Address(it->sentHost())
2358
0
#endif
2359
0
          )
2360
0
      {
2361
0
         Tuple address(it->sentHost(), 0, UNKNOWN_TRANSPORT);
2362
0
         if(!address.isPrivateAddress())
2363
0
         {
2364
0
            address.setPort(it->exists(p_rport) ? it->param(p_rport).port() : it->sentPort());
2365
0
            address.setType(Tuple::toTransport(it->transport()));
2366
0
            return address;
2367
0
         }
2368
0
      }
2369
2370
0
      if(it == request.header(h_Vias).begin()) break;
2371
0
   }
2372
0
   return Tuple();
2373
0
}
2374
2375
2376
/* ====================================================================
2377
 * The Vovida Software License, Version 1.0 
2378
 * 
2379
 * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
2380
 * 
2381
 * Redistribution and use in source and binary forms, with or without
2382
 * modification, are permitted provided that the following conditions
2383
 * are met:
2384
 * 
2385
 * 1. Redistributions of source code must retain the above copyright
2386
 *    notice, this list of conditions and the following disclaimer.
2387
 * 
2388
 * 2. Redistributions in binary form must reproduce the above copyright
2389
 *    notice, this list of conditions and the following disclaimer in
2390
 *    the documentation and/or other materials provided with the
2391
 *    distribution.
2392
 * 
2393
 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
2394
 *    and "Vovida Open Communication Application Library (VOCAL)" must
2395
 *    not be used to endorse or promote products derived from this
2396
 *    software without prior written permission. For written
2397
 *    permission, please contact vocal@vovida.org.
2398
 *
2399
 * 4. Products derived from this software may not be called "VOCAL", nor
2400
 *    may "VOCAL" appear in their name, without prior written
2401
 *    permission of Vovida Networks, Inc.
2402
 * 
2403
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
2404
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2405
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
2406
 * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
2407
 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
2408
 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
2409
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2410
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2411
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
2412
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2413
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
2414
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
2415
 * DAMAGE.
2416
 * 
2417
 * ====================================================================
2418
 * 
2419
 * This software consists of voluntary contributions made by Vovida
2420
 * Networks, Inc. and many individuals on behalf of Vovida Networks,
2421
 * Inc.  For more information on Vovida Networks, Inc., please see
2422
 * <http://www.vovida.org/>.
2423
 *
2424
 */