Coverage Report

Created: 2024-07-23 06:39

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