1#if defined(HAVE_CONFIG_H)
44#define RESIPROCATE_SUBSYSTEM Subsystem::SIP
50Helper::NonceHelperPtr Helper::mNonceHelperPtr;
62 for (i = 0; i < 4; i++)
64 j = (s[i] >> 4) & 0xf;
67 if(_l || j != 0 || k != 0)
74 _d[k++] = (j +
'a' - 10);
80 if(_l || j != 0 || k != 0)
87 _d[k++] = (j +
'a' - 10);
94 unsigned int i, res = 0;
96 for(i = 0; i < 8; i++)
98 if ((_s[i] >=
'0') && (_s[i] <=
'9'))
103 else if ((_s[i] >=
'a') && (_s[i] <=
'f'))
106 res += _s[i] -
'a' + 10;
108 else if ((_s[i] >=
'A') && (_s[i] <=
'F'))
111 res += _s[i] -
'A' + 10;
130 else if (lowerPercentage == 100 && upperPercentage == 100)
136 const int rnd =
Random::getRandom() % (upperPercentage - lowerPercentage) + lowerPercentage;
137 return (input * rnd) / 100;
144 std::unique_ptr<SipMessage> request(
new SipMessage);
146 rLine.
uri() = target.
uri();
147 request->header(h_To) = target;
149 request->header(h_MaxForwards).value() = 70;
150 request->header(h_CSeq).
method() = method;
151 request->header(h_CSeq).sequence() = 1;
152 request->header(h_From) = from;
154 request->header(h_Contacts).push_back(contact);
159 request->header(h_Vias).push_back(via);
161 return request.release();
181 std::unique_ptr<SipMessage> request(
new SipMessage);
192 request->header(h_To) = to;
194 request->header(h_MaxForwards).value() = 70;
195 request->header(h_CSeq).
method() = REGISTER;
196 request->header(h_CSeq).sequence() = 1;
197 request->header(h_From) = from;
200 resip_assert(!request->exists(h_Contacts) || request->header(h_Contacts).empty());
201 request->header(h_Contacts).push_back( contact );
204 request->header(h_Vias).push_back(via);
206 return request.release();
220 std::unique_ptr<SipMessage> request(
new SipMessage);
226 if (!transport.
empty())
228 rLine.
uri().
param(p_transport) = transport;
231 request->header(h_To) = to;
233 request->header(h_MaxForwards).value() = 70;
234 request->header(h_CSeq).
method() = REGISTER;
235 request->header(h_CSeq).sequence() = 1;
236 request->header(h_From) = to;
239 resip_assert(!request->exists(h_Contacts) || request->header(h_Contacts).empty());
240 request->header(h_Contacts).push_back( contact );
243 request->header(h_Vias).push_back(via);
245 return request.release();
265 std::unique_ptr<SipMessage> cancel(
new SipMessage);
270 cancel->header(h_MaxForwards).value() = 70;
271 cancel->header(h_To) = request.
header(h_To);
272 cancel->header(h_From) = request.
header(h_From);
274 if (request.
exists(h_ProxyAuthorizations))
276 cancel->header(h_ProxyAuthorizations) = request.
header(h_ProxyAuthorizations);
278 if (request.
exists(h_Authorizations))
280 cancel->header(h_Authorizations) = request.
header(h_Authorizations);
283 if (request.
exists(h_Routes))
285 cancel->header(h_Routes) = request.
header(h_Routes);
288 cancel->header(h_CSeq) = request.
header(h_CSeq);
289 cancel->header(h_CSeq).
method() = CANCEL;
290 cancel->header(h_Vias).push_back(request.
header(h_Vias).front());
292 return cancel.release();
301 std::unique_ptr<SipMessage> ack(
new SipMessage);
306 ack->header(h_MaxForwards).value() = 70;
308 ack->header(h_From) = request.
header(h_From);
309 ack->header(h_To) = response.
header(h_To);
310 ack->header(h_Vias).push_back(request.
header(h_Vias).front());
311 ack->header(h_CSeq) = request.
header(h_CSeq);
312 ack->header(h_CSeq).
method() = ACK;
313 if (request.
exists(h_Routes))
315 ack->header(h_Routes) = request.
header(h_Routes);
318 return ack.release();
331 std::unique_ptr<SipMessage> request(
new SipMessage);
333 rLine.
uri() = target.
uri();
335 request->header(h_To) = target;
337 request->header(h_MaxForwards).value() = 70;
338 request->header(h_CSeq).
method() = PUBLISH;
339 request->header(h_CSeq).sequence() = 1;
340 request->header(h_From) = from;
343 resip_assert(!request->exists(h_Contacts) || request->header(h_Contacts).empty());
344 request->header(h_Contacts).push_back( contact );
346 request->header(h_Vias).push_back(via);
348 return request.release();
361 std::unique_ptr<SipMessage> request(
new SipMessage);
363 rLine.
uri() = target.
uri();
365 request->header(h_To) = target;
367 request->header(h_MaxForwards).value() = 70;
368 request->header(h_CSeq).
method() = MESSAGE;
369 request->header(h_CSeq).sequence() = 1;
370 request->header(h_From) = from;
373 resip_assert(!request->exists(h_Contacts) || request->header(h_Contacts).empty());
374 request->header(h_Contacts).push_back( contact );
376 request->header(h_Vias).push_back(via);
378 return request.release();
391 std::unique_ptr<SipMessage> request(
new SipMessage);
393 rLine.
uri() = target.
uri();
395 request->header(h_To) = target;
397 request->header(h_MaxForwards).value() = 70;
398 request->header(h_CSeq).
method() = SUBSCRIBE;
399 request->header(h_CSeq).sequence() = 1;
400 request->header(h_From) = from;
403 resip_assert(!request->exists(h_Contacts) || request->header(h_Contacts).empty());
404 request->header(h_Contacts).push_front( contact );
406 request->header(h_Vias).push_front(via);
408 return request.release();
416 const Data& hostname,
419 DebugLog(<<
"Helper::makeResponse(" << request.
brief() <<
" code=" << responseCode <<
" reason=" << reason);
427 if (!warning.
empty())
432 warn.
text() = warning;
433 response.
header(h_Warnings).push_back(warn);
436 if(responseCode > 100 &&
453 if (responseCode >= 180 && responseCode < 300 && request.
exists(h_RecordRoutes))
455 response.
header(h_RecordRoutes) = request.
header(h_RecordRoutes);
461 if (responseCode/100 == 2 &&
462 !response.
exists(h_Contacts) &&
470 response.
header(h_Contacts).push_back(contact);
500 const Data& hostname,
503 makeResponse(response,request, responseCode, reason,hostname, warning);
508 response.
header(h_Contacts).push_back(myContact);
515 const Data& hostname,
520 std::unique_ptr<SipMessage> response(
new SipMessage);
522 makeResponse(*response, request, responseCode, reason, hostname, warning);
523 return response.release();
531 const Data& hostname,
536 std::unique_ptr<SipMessage> response(
new SipMessage);
538 makeResponse(*response, request, responseCode, reason, hostname, warning);
543 response->header(h_Contacts).clear();
544 response->header(h_Contacts).push_back(myContact);
545 return response.release();
552 const Data& additionalHeaders,
558 encodeStream <<
"SIP/2.0 " << responseCode <<
" ";
567 encodeStream << additionalHeaders;
568 encodeStream <<
"Content-Length: " << body.
size() <<
"\r\n\r\n";
574 const int* allowedMethods,
584 for (
int i = 1; i < upperBound; i++)
592 resp->
header(h_Allows).push_back(t);
599 for (
int i = 0; i < len; i++)
603 resp->
header(h_Allows).push_back(t);
612 switch (responseCode)
614 case 100: reason =
"Trying";
break;
615 case 180: reason =
"Ringing";
break;
616 case 181: reason =
"Call Is Being Forwarded";
break;
617 case 182: reason =
"Queued";
break;
618 case 183: reason =
"Session Progress";
break;
619 case 200: reason =
"OK";
break;
620 case 202: reason =
"Accepted";
break;
621 case 300: reason =
"Multiple Choices";
break;
622 case 301: reason =
"Moved Permanently";
break;
623 case 302: reason =
"Moved Temporarily";
break;
624 case 305: reason =
"Use Proxy";
break;
625 case 380: reason =
"Alternative Service";
break;
626 case 400: reason =
"Bad Request";
break;
627 case 401: reason =
"Unauthorized";
break;
628 case 402: reason =
"Payment Required";
break;
629 case 403: reason =
"Forbidden";
break;
630 case 404: reason =
"Not Found";
break;
631 case 405: reason =
"Method Not Allowed";
break;
632 case 406: reason =
"Not Acceptable";
break;
633 case 407: reason =
"Proxy Authentication Required";
break;
634 case 408: reason =
"Request Timeout";
break;
635 case 410: reason =
"Gone";
break;
636 case 412: reason =
"Precondition Failed";
break;
637 case 413: reason =
"Request Entity Too Large";
break;
638 case 414: reason =
"Request-URI Too Long";
break;
639 case 415: reason =
"Unsupported Media Type";
break;
640 case 416: reason =
"Unsupported URI Scheme";
break;
641 case 420: reason =
"Bad Extension";
break;
642 case 421: reason =
"Extension Required";
break;
643 case 422: reason =
"Session Interval Too Small";
break;
644 case 423: reason =
"Interval Too Brief";
break;
645 case 428: reason =
"Use Identity Header";
break;
646 case 430: reason =
"Flow failed";
break;
647 case 436: reason =
"Bad Identity Info";
break;
648 case 437: reason =
"Unsupported Credential";
break;
649 case 438: reason =
"Invalid Identity Header";
break;
650 case 439: reason =
"First Hop Lacks Outbound Support";
break;
651 case 480: reason =
"Temporarily Unavailable";
break;
652 case 481: reason =
"Call/Transaction Does Not Exist";
break;
653 case 482: reason =
"Loop Detected";
break;
654 case 483: reason =
"Too Many Hops";
break;
655 case 484: reason =
"Address Incomplete";
break;
656 case 485: reason =
"Ambiguous";
break;
657 case 486: reason =
"Busy Here";
break;
658 case 487: reason =
"Request Terminated";
break;
659 case 488: reason =
"Not Acceptable Here";
break;
660 case 489: reason =
"Event Package Not Supported";
break;
661 case 491: reason =
"Request Pending";
break;
662 case 493: reason =
"Undecipherable";
break;
663 case 500: reason =
"Server Internal Error";
break;
664 case 501: reason =
"Not Implemented";
break;
665 case 502: reason =
"Bad Gateway";
break;
666 case 503: reason =
"Service Unavailable";
break;
667 case 504: reason =
"Server Time-out";
break;
668 case 505: reason =
"Version Not Supported";
break;
669 case 513: reason =
"Message Too Large";
break;
670 case 600: reason =
"Busy Everywhere";
break;
671 case 603: reason =
"Decline";
break;
672 case 604: reason =
"Does Not Exist Anywhere";
break;
673 case 606: reason =
"Not Acceptable";
break;
694#if defined(__linux__) || defined(__APPLE__)
695 pid_t pid = getpid();
696 hostAndSalt.
append((
char*)&pid,
sizeof(pid));
699 pthread_t thread = pthread_self();
700 hostAndSalt.
append((
char*)&thread,
sizeof(thread));
703 DWORD proccessId = ::GetCurrentProcessId();
704 DWORD threadId = ::GetCurrentThreadId();
705 hostAndSalt.
append((
char*)&proccessId,
sizeof(proccessId));
706 hostAndSalt.
append((
char*)&threadId,
sizeof(threadId));
721 mNonceHelperPtr.mNonceHelper = nonceHelper;
727 if (mNonceHelperPtr.mNonceHelper == 0)
731 return mNonceHelperPtr.mNonceHelper;
744 if (!auth.
exists(p_algorithm))
751 Data algorithmName = auth.
param(p_algorithm);
785 const Data& password)
790 a1InputStream << username
811 a1sha512_256 << a1Input;
815 resultStream.flush();
824 if (resipA1HashString.
size() == 32)
826 if (digestType ==
MD5)
829 return resipA1HashString;
848 const char* anchor = (
const char*)pb.
position();
850 return pb.
data(anchor);
858 if (resipA1HashString.
size() == 32)
861 return digestType ==
MD5;
877 const Data& password,
886 const Data& resipPasswordHashA1,
896 const Data& passwordOrResipPasswordHashA1,
898 bool isPasswordHashResipA1)
900 DebugLog(<<
"Authenticating " << (isPasswordHashResipA1 ?
"with HA1" :
"") <<
": realm=" << realm <<
" expires=" << expiresDelta);
906 if (request.
exists(h_ProxyAuthorizations))
911 if (request.
exists(h_Authorizations))
918 DebugLog(<<
"No authentication headers. Failing request.");
928 for (; i != auths.
end(); i++)
930 if (i->exists(p_realm) &&
931 i->exists(p_nonce) &&
932 i->exists(p_response) &&
933 i->param(p_realm) == realm)
937 DebugLog(<<
"Scheme must be Digest");
944 DebugLog(<<
"Digest algorithm not supported");
954 if (expiresDelta > 0)
966 if (i->param(p_nonce) !=
makeNonce(request, then))
973 <<
" username=" << (i->param(p_username))
975 <<
" uri=" << i->param(p_uri)
976 <<
" nonce=" << i->param(p_nonce));
978 if (i->exists(p_qop))
982 if (i->exists(p_uri) && i->exists(p_cnonce) && i->exists(p_nc))
985 if (isPasswordHashResipA1)
1000 passwordOrResipPasswordHashA1,
1011 if (i->param(p_response) == responseDigest)
1023 InfoLog(<<
"Unsupported qop=" << i->param(p_qop));
1027 else if (i->exists(p_uri))
1029 Data responseDigest;
1030 if (isPasswordHashResipA1)
1042 passwordOrResipPasswordHashA1,
1051 if (i->param(p_response) == responseDigest)
1070std::pair<Helper::AuthResult,Data>
1073 const Data& resipPasswordHashA1,
1075 bool proxyAuthorization)
1078 DebugLog(<<
"Authenticating: realm=" << realm <<
" expires=" << expiresDelta);
1082 if (proxyAuthorization)
1084 if (request.
exists(h_ProxyAuthorizations))
1086 auths = &request.
header(h_ProxyAuthorizations);
1091 if (request.
exists(h_Authorizations))
1093 auths = &request.
header(h_Authorizations);
1101 if (i->exists(p_realm) &&
1102 i->exists(p_nonce) &&
1103 i->exists(p_response) &&
1104 i->param(p_realm) == realm)
1108 DebugLog(<<
"Scheme must be Digest");
1115 DebugLog(<<
"Digest algorithm not supported");
1125 if (expiresDelta > 0)
1131 return make_pair(
Expired, username);
1136 if (i->param(p_nonce) !=
makeNonce(request, then))
1139 <<
" received=" << i->param(p_nonce)
1140 <<
" then=" << then);
1145 if (i->exists(p_qop))
1149 if (i->exists(p_uri) && i->exists(p_cnonce) && i->exists(p_nc))
1161 if (i->exists(p_username))
1163 username = i->param(p_username);
1169 return make_pair(
Failed, username);
1175 InfoLog(<<
"Unsupported qop=" << i->param(p_qop));
1176 return make_pair(
Failed, username);
1179 else if (i->exists(p_uri))
1188 if (i->exists(p_username))
1190 username = i->param(p_username);
1196 return make_pair(
Failed, username);
1207 DebugLog(<<
"No authentication headers. Failing request.");
1208 return make_pair(
Failed, username);
1214 return makeChallenge(request, realm, useAuth, stale,
true, digestTypes);
1220 return makeChallenge(request, realm, useAuth, stale,
false, digestTypes);
1235 if (digestTypes.empty())
1241 for (
auto it = digestTypes.begin(); it != digestTypes.end(); ++it)
1243 addChallenge(*response, request, realm, useAuth, stale, proxy, *it);
1257 auth.
param(p_realm) = realm;
1260 auth.
param(p_qopOptions) =
"auth,auth-int";
1264 auth.
param(p_stale) =
"true";
1268 response.
header(h_ProxyAuthenticates).push_back(auth);
1272 response.
header(h_WWWAuthenticates).push_back(auth);
1288 if (challenge.
exists(p_qopOptions) && !challenge.
param(p_qopOptions).
empty())
1313 }
while (!pb.
eof());
1327 if (!nonceCountString.
empty())
1336 constexpr size_t bufSize = 128;
1340 std::snprintf(buf, bufSize,
"%08x", nonceCount);
1341 nonceCountString = buf;
1343 DebugLog(<<
"nonceCount is now: [" << nonceCountString <<
"]");
1356 if (!(challenge.
exists(p_nonce) && challenge.
exists(p_realm)))
1361 (!challenge.
exists(p_qop) ||
1370 const Data& username,
1371 const Data& password,
1373 unsigned int& nonceCount)
1384 if (challenge.
exists(h_ProxyAuthenticates))
1386 pChallengeAuthenticates = &challenge.
header(h_ProxyAuthenticates);
1387 pRequestAuthorizations = &request.
header(h_ProxyAuthorizations);
1389 else if (challenge.
exists(h_WWWAuthenticates))
1391 pChallengeAuthenticates = &challenge.
header(h_WWWAuthenticates);
1392 pRequestAuthorizations = &request.
header(h_Authorizations);
1400 for (
auto i = pChallengeAuthenticates->
begin(); i != pChallengeAuthenticates->
end(); i++)
1406 cnonce, nonceCount, nonceCountString));
1416 const Data& username,
1417 const Data& password,
1418 const Auth& challenge,
1420 unsigned int& nonceCount,
1421 Data& nonceCountString)
1425 if(!authQop.
empty())
1435 const Data& username,
1436 const Data& password,
1437 const Auth& challenge,
1439 const Data& authQop,
1440 const Data& nonceCountString,
1444 auth.
param(p_username) = username;
1446 auth.
param(p_realm) = challenge.
param(p_realm);
1448 auth.
param(p_nonce) = challenge.
param(p_nonce);
1455 auth.
param(p_uri) = digestUri;
1460 if (!authQop.
empty())
1464 challenge.
param(p_realm),
1467 challenge.
param(p_nonce),
1473 auth.
param(p_cnonce) = cnonce;
1474 auth.
param(p_nc) = nonceCountString;
1475 auth.
param(p_qop) = authQop;
1482 challenge.
param(p_realm),
1485 challenge.
param(p_nonce),
1490 if (challenge.
exists(p_algorithm))
1492 auth.
param(p_algorithm) = challenge.
param(p_algorithm);
1496 auth.
param(p_algorithm) =
"MD5";
1499 if (challenge.
exists(p_opaque) && challenge.
param(p_opaque).
size() > 0)
1501 auth.
param(p_opaque) = challenge.
param(p_opaque);
1507 const Data& username,
1508 const Data& resipPasswordHashA1,
1509 const Auth& challenge,
1511 unsigned int& nonceCount,
1512 Data& nonceCountString)
1516 if(!authQop.
empty())
1526 const Data& username,
1527 const Data& resipPasswordHashA1,
1528 const Auth& challenge,
1530 const Data& authQop,
1531 const Data& nonceCountString,
1535 auth.
param(p_username) = username;
1537 auth.
param(p_realm) = challenge.
param(p_realm);
1539 auth.
param(p_nonce) = challenge.
param(p_nonce);
1546 auth.
param(p_uri) = digestUri;
1551 if (!authQop.
empty())
1556 challenge.
param(p_nonce),
1562 auth.
param(p_cnonce) = cnonce;
1563 auth.
param(p_nc) = nonceCountString;
1564 auth.
param(p_qop) = authQop;
1572 challenge.
param(p_nonce),
1577 if (challenge.
exists(p_algorithm))
1579 auth.
param(p_algorithm) = challenge.
param(p_algorithm);
1583 auth.
param(p_algorithm) =
"MD5";
1586 if (challenge.
exists(p_opaque) && challenge.
param(p_opaque).
size() > 0)
1588 auth.
param(p_opaque) = challenge.
param(p_opaque);
1594 const Data& method,
const Data& digestUri,
const Data& nonce,
1595 const Data& qop,
const Data& cnonce,
const Data& cnonceCount,
1599#ifdef RESIP_DIGEST_LOGGING
1614 eStream << *entityBody;
1616#ifdef RESIP_DIGEST_LOGGING
1624#ifdef RESIP_DIGEST_LOGGING
1630#ifdef RESIP_DIGEST_LOGGING
1650#ifdef RESIP_DIGEST_LOGGING
1657 StackLog(<<
"response to be hashed (HA1:nonce:HA2) = " << _r);
1671 const Data& method,
const Data& digestUri,
const Data& nonce,
1672 const Data& qop,
const Data& cnonce,
const Data& cnonceCount,
1683 cnonce, cnonceCount, entity, digestType);
1703 if (request.
exists(h_Routes) &&
1712 request.
header(h_Routes).pop_front();
1724 if (!request.
empty(h_Routes) &&
1753 port = request.
const_header(h_Vias).front().sentPort();
1758 if (request.
const_header(h_Vias).front().exists(p_rport))
1764 port = request.
const_header(h_Vias).front().sentPort();
1769 if (port <= 0 || port > 65535)
1771 if(transportType ==
TLS ||
1772 transportType ==
DTLS)
1793 if (message.
empty(h_To) ||
1794 message.
empty(h_From) ||
1795 message.
empty(h_CSeq) ||
1797 message.
empty(h_Vias) ||
1798 message.
empty(h_Vias))
1800 InfoLog(<<
"Missing mandatory header fields (To, From, CSeq, Call-Id or Via)");
1802 if(reason) *reason=
"Missing mandatory header field";
1809 InfoLog(<<
"Malformed CSeq header");
1810 if(reason) *reason=
"Malformed CSeq header";
1816 InfoLog(<<
"Malformed topmost Via header");
1817 if(reason) *reason=
"Malformed topmost Via header";
1825 InfoLog(<<
"Illegal request line");
1826 if(reason) *reason=
"Malformed Request Line";
1832 InfoLog(<<
"Method mismatch btw Request Line and CSeq");
1833 if(reason) *reason=
"Method mismatch btw Request Line and CSeq";
1841 InfoLog(<<
"Malformed status line");
1842 if(reason) *reason=
"Malformed status line";
1851#if defined(USE_SSL) && !defined(OPENSSL_NO_BF)
1852#include <openssl/opensslv.h>
1853#include <openssl/blowfish.h>
1854#if OPENSSL_VERSION_NUMBER >= 0x30000000L
1855#include <openssl/evp.h>
1856#include <openssl/params.h>
1857#include <openssl/core_names.h>
1870 unsigned char ivec[8];
1883 const Data token(salt + instanceId +
sep + aor +
'\0' +
1887 + aor.
size() ) % 8))
1889 std::vector<unsigned char> out;
1891#if OPENSSL_VERSION_NUMBER < 0x30000000L
1892 out.resize(token.
size());
1895 BF_set_key(&fish, (
int)key.
size(), (
const unsigned char*)key.
data());
1897 BF_cbc_encrypt((
const unsigned char*)token.
data(),
1904 const EVP_CIPHER* pCipher = EVP_bf_cbc();
1905 std::size_t out_size = token.
size();
1906 int block_size = EVP_CIPHER_get_block_size(pCipher);
1909 std::size_t tail_size = out_size % block_size;
1911 out_size += block_size - tail_size;
1913 out.resize(out_size);
1915 std::unique_ptr<EVP_CIPHER_CTX, OpenSSLDeleter> pCipherCtx(EVP_CIPHER_CTX_new());
1917 throw std::bad_alloc();
1919 std::size_t keylen = key.
size();
1920 const OSSL_PARAM
params[] = {
1921 OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_KEYLEN, &keylen),
1922 OSSL_PARAM_construct_end()
1924 int res = EVP_EncryptInit_ex2(pCipherCtx.get(), pCipher,
1925 reinterpret_cast<const unsigned char*
>(key.
data()), ivec,
params);
1927 throw std::runtime_error(
"Failed to initialize encryption context");
1929 resip_assert(
static_cast<unsigned int>(EVP_CIPHER_CTX_get_iv_length(pCipherCtx.get())) <=
sizeof(ivec));
1931 int outlen =
static_cast<int>(out_size);
1932 res = EVP_EncryptUpdate(pCipherCtx.get(), out.data(), &outlen,
1933 reinterpret_cast<const unsigned char*
>(token.
data()), (
int)token.
size());
1936 resip_assert(
static_cast<unsigned int>(outlen) <= out_size);
1937 int outlen2 =
static_cast<int>(out_size - outlen);
1938 res = EVP_EncryptFinal_ex(pCipherCtx.get(), out.data() + outlen, &outlen2);
1942 resip_assert(
static_cast<unsigned int>(outlen) <= out_size);
1943 out.resize(
static_cast<unsigned int>(outlen));
1948 throw std::runtime_error(
"Failed to encrypt GRUU user part");
1954std::pair<Data, Data>
1958 unsigned char ivec[8];
1971 return std::pair<Data, Data>();
1978#if OPENSSL_VERSION_NUMBER < 0x30000000L
1980 BF_set_key(&fish, (
int)key.
size(), (
const unsigned char*)key.
data());
1982 BF_cbc_encrypt((
const unsigned char*)decoded.
data(),
1984 (
long)decoded.
size(),
1989 std::unique_ptr<EVP_CIPHER_CTX, OpenSSLDeleter> pCipherCtx(EVP_CIPHER_CTX_new());
1991 throw std::bad_alloc();
1993 std::size_t keylen = key.
size();
1994 const OSSL_PARAM
params[] = {
1995 OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_KEYLEN, &keylen),
1996 OSSL_PARAM_construct_end()
1998 int res = EVP_DecryptInit_ex2(pCipherCtx.get(), EVP_bf_cbc(),
1999 reinterpret_cast<const unsigned char*
>(key.
data()), ivec,
params);
2001 throw std::runtime_error(
"Failed to initialize decryption context");
2003 resip_assert(
static_cast<unsigned int>(EVP_CIPHER_CTX_get_iv_length(pCipherCtx.get())) <=
sizeof(ivec));
2005 const std::size_t out_size = out.size();
2006 int outlen =
static_cast<int>(out_size);
2007 res = EVP_DecryptUpdate(pCipherCtx.get(), out.data(), &outlen,
2008 reinterpret_cast<const unsigned char*
>(decoded.
data()), (
int)decoded.
size());
2011 resip_assert(
static_cast<unsigned int>(outlen) <= out_size);
2012 int outlen2 =
static_cast<int>(out_size - outlen);
2013 res = EVP_DecryptFinal_ex(pCipherCtx.get(), out.data() + outlen, &outlen2);
2017 resip_assert(
static_cast<unsigned int>(outlen) <= out_size);
2018 out.resize(
static_cast<unsigned int>(outlen));
2023 throw std::runtime_error(
"Failed to decrypt GRUU user part");
2031 return std::pair<Data, Data>();
2040 std::unique_ptr<SecurityAttributes> attributes)
2041 : mContents(std::move(contents)),
2042 mAttributes(std::move(attributes))
2048 const Data& signerAor,
2049 const Data& receiverAor,
2056 InfoLog( <<
"GREG1: " << *pk );
2071 InfoLog( <<
"GREG2: " << *mps );
2079 receiverAor, attributes, security);
2084 return mps->
parts().front()->clone();
2090 InfoLog( <<
"GREG3: " << *alt );
2091 for (MultipartAlternativeContents::Parts::reverse_iterator i = alt->
parts().rbegin();
2092 i != alt->
parts().rend(); ++i)
2105 InfoLog( <<
"GREG4: " << *mult );
2106 for (MultipartMixedContents::Parts::iterator i = mult->
parts().begin();
2107 i != mult->
parts().end(); ++i)
2110 attributes, security);
2120 return tree->
clone();
2145 std::unique_ptr<Contents> c(b);
2146 std::unique_ptr<SecurityAttributes> a(attr);
2152 const std::set<int>* additionalTransactionTerminatingResponses)
2158 if (additionalTransactionTerminatingResponses &&
2159 (additionalTransactionTerminatingResponses->end() != additionalTransactionTerminatingResponses->find(code)))
2213 if (response.
exists(h_RetryAfter))
2225 if (response.
exists(h_RetryAfter))
2286 for (MultipartAlternativeContents::Parts::reverse_iterator i = alt->
parts().rbegin();
2287 i != alt->
parts().rend(); ++i)
2314 for (MultipartMixedContents::Parts::iterator i = mult->
parts().begin();
2315 i != mult->
parts().end(); ++i)
2366 if(request.
header(h_Vias).front().exists(p_received))
2368 if(privateToPublicOnly)
2407 Vias::const_iterator it = request.
header(h_Vias).end();
2411 if(it->exists(p_received))
2417 address.
setPort(it->exists(p_rport) ? it->param(p_rport).port() : it->sentPort());
2433 address.
setPort(it->exists(p_rport) ? it->param(p_rport).port() : it->sentPort());
2439 if(it == request.
header(h_Vias).begin())
break;
static const Data GRUU("_GRUU")
static const Data pad("\0\0\0\0\0\0\0", 7)
static const Data cookie("z9hG4bK")
static const Data sep("[]")
static const int saltBytes(16)
static Data preferredTokens[]
Contents * extractFromPkcs7Recurse(Contents *tree, const Data &signerAor, const Data &receiverAor, SecurityAttributes *attributes, Security &security)
static Data digest("digest")
#define resip_assert(x)
This file needs to work for both C and C++ code.
Represents the "credentials" and "challenge" elements in the SIP grammar.
bool exists(const Param< Auth > ¶mType) const
const Data & param(const ExtensionParameter ¶m) const
Const accessor for non-natively-supported parameter types.
The abstract base-class for all exceptions thrown by resip code.
const Data & getMessage() const noexcept
Contents * checkSignature(MultipartSignedContents *, Data *signedBy, SignatureStatus *sigStat)
Contents * decrypt(const Data &decryptorAor, const Pkcs7Contents *)
Implements the makeNonce function in the same way as the original implementation of makeNonce within ...
Base class for all SIP body types.
virtual Contents * clone() const =0
returns a copy of a Contents object
An iostream that operates on an existing Data.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Data base64decode() const
Performs RFC 3548 Base 64 decoding of the contents of this data.
static const Data Empty
Constant that represents a zero-length data.
Data base64encode(bool useUrlSafe=false) const
Performs RFC 3548 Base 64 encoding of the contents of this data.
static const PreallocateType Preallocate
used only to disambiguate constructors
bool prefix(const Data &pre) const noexcept
Returns true if this Data starts with the bytes indicated by the passed-in Data.
Data & append(const char *str, size_type len)
Appends the specified number of bytes to the end of this Data.
Data substr(size_type first, size_type count=Data::npos) const
Copies a portion of this Data into a new Data.
bool empty() const noexcept
Checks whether the Data is empty.
size_type size() const noexcept
Returns the number of bytes in this Data.
size_type find(const Data &match, size_type start=0) const
Finds a specified sequence of bytes in this Data.
static const size_type npos
Represents an impossible position; returned to indicate failure to find.
Data md5(EncodingType type=HEX) const
Computes the MD5 hash of the current data.
const char * data() const noexcept
Returns a pointer to the contents of this Data.
void reserve(size_type capacity)
Guarantees that the underlying buffer used by the Data is at least the number of bytes specified.
Used to accumlate data written to the stream in a DigestBuffer and convert the data to Digest.
Data getHex()
Calls flush() on itself and returns the Digest data in hex format.
static const Data & getDigestName(DigestType digestType)
static bool isIpV6Address(const Data &ipAddress)
static const Data & getLocalHostName()
static bool isIpV4Address(const Data &ipAddress)
static Auth makeChallengeResponseAuthWithA1(const SipMessage &request, const Data &username, const Data &resipPasswordHashA1, const Auth &challenge, const Data &cnonce, unsigned int &nonceCount, Data &nonceCountString)
static SipMessage * makeChallenge(const SipMessage &request, const Data &realm, bool useAuth=true, bool stale=false, bool proxy=false, const std::vector< DigestType > &digestTypes=std::vector< DigestType >())
static Uri makeUri(const Data &aor, const Data &scheme=Symbols::DefaultSipScheme)
///////////////////////////////////////////////////////////////////////////////////////////
static SdpContents * getSdpRecurse(Contents *tree)
static AuthResult authenticateRequestWithA1(const SipMessage &request, const Data &realm, const Data &resipPasswordHashA1, int expiresDelta=0)
static Uri fromAor(const Data &aor, const Data &scheme=Symbols::DefaultSipScheme)
static Data makeResponseDigestWithA1(const Data &a1, const Data &method, const Data &digestUri, const Data &nonce, const Data &qop=Data::Empty, const Data &cnonce=Data::Empty, const Data &cnonceCount=Data::Empty, const Contents *entityBody=0, DigestType digestType=MD5)
static void updateNonceCount(unsigned int &nonceCount, Data &nonceCountString)
static Data extractA1FromResipA1HashString(const Data &resipA1HashString, DigestType digestType)
static const int tagSize
bytes in to-tag& from-tag, should prob. live somewhere else
static SipMessage * makePublish(const NameAddr &target, const NameAddr &from)
Create a Publish request with an empty Contact. See makeRequest.
static SipMessage * makeRegister(const NameAddr &to, const NameAddr &from)
Create a Register request with an empty Contact. See makeRequest.
static Data gruuUserPart(const Data &instanceId, const Data &aor, const Data &key)
static bool validateMessage(const SipMessage &message, resip::Data *reason=0)
static bool isClientBehindNAT(const SipMessage &request, bool privateToPublicOnly=true)
Looks at SIP headers and message source for a mismatch to make an assumption that the sender is behin...
static bool algorithmAndQopSupported(const Auth &challenge)
static void getResponseCodeReason(int responseCode, Data &reason)
Returns the default reason string for a particular response code.
static NonceHelper * getNonceHelper()
static SipMessage * makeInvite(const NameAddr &target, const NameAddr &from)
Make an invite request - Empty Contact and Via is added and will be populated by the stack when sent.
static void processStrictRoute(SipMessage &request)
static std::pair< Data, Data > fromGruuUserPart(const Data &gruuUserPart, const Data &key)
static SipMessage & addAuthorization(SipMessage &request, const SipMessage &challenge, const Data &username, const Data &password, const Data &cnonce, unsigned int &nonceCount)
static Data createResipA1HashString(const Data &username, const Data &realm, const Data &password)
static void setNonceHelper(NonceHelper *nonceHelper)
///////////////////////////////////////////////////////////////////////////////////////////
static void massageRoute(const SipMessage &request, NameAddr &route)
static SipMessage * makeProxyChallenge(const SipMessage &request, const Data &realm, bool useAuth=true, bool stale=false, const std::vector< DigestType > &digestTypes=std::vector< DigestType >())
static SipMessage * makeMessage(const NameAddr &target, const NameAddr &from)
Create a Message request with an empty Contact. See makeRequest.
static unsigned int hex2integer(const char *_s)
Converts a character string containing a hexidecimal value into an unsigned int.
static Data computeTag(int numBytes)
static std::unique_ptr< SdpContents > getSdp(Contents *tree)
static Data qopOption(const Auth &challenge)
static SipMessage * makeCancel(const SipMessage &request)
Make a new Cancel request for the specified request.
static void addChallenge(SipMessage &response, const SipMessage &request, const Data &realm, bool useAuth=true, bool stale=false, bool proxy=false, DigestType digestType=MD5)
static int getPortForReply(SipMessage &request)
static bool isDigestTypeSupportedInResipA1HashString(const Data &resipA1HashString, DigestType digestType)
static SipMessage * make405(const SipMessage &request, const int *allowedMethods=0, int nMethods=-1)
Make a 405 response to a provided request.
static ContentsSecAttrs extractFromPkcs7(const SipMessage &message, Security &security)
static void makeResponse(SipMessage &response, const SipMessage &request, int responseCode, const Data &reason=Data::Empty, const Data &hostname=Data::Empty, const Data &warning=Data::Empty)
Make a response to a provided request.
static Tuple getClientPublicAddress(const SipMessage &request)
Look at Via headers, and find the first public IP address closest to the sending client.
static int jitterValue(int input, int lowerPercentage, int upperPercentage, int minimum=0)
Used to jitter the expires in a SUBSCRIBE or REGISTER expires header.
static void makeRawResponse(Data &rawBuffer, const SipMessage &request, int responseCode, const Data &additionalHeaders=Data::Empty, const Data &body=Data::Empty)
static void integer2hex(char *_d, unsigned int _s, bool _l=true)
Converts an interger in a character string containing the hexidecimal representation of the integer.
static SipMessage * makeWWWChallenge(const SipMessage &request, const Data &realm, bool useAuth=true, bool stale=false, const std::vector< DigestType > &digestTypes=std::vector< DigestType >())
static SipMessage * makeRequest(const NameAddr &target, const NameAddr &from, const NameAddr &contact, MethodTypes method)
///////////////////////////////////////////////////////////////////////////////////////////
static AuthResult authenticateRequest(const SipMessage &request, const Data &realm, const Data &password, int expiresDelta=0)
static std::pair< AuthResult, Data > advancedAuthenticateRequest(const SipMessage &request, const Data &realm, const Data &resipPasswordHashA1, int expiresDelta=0, bool proxyAuthorization=true)
static Data makeResponseDigest(const Data &username, const Data &password, const Data &realm, const Data &method, const Data &digestUri, const Data &nonce, const Data &qop=Data::Empty, const Data &cnonce=Data::Empty, const Data &cnonceCount=Data::Empty, const Contents *entityBody=0, DigestType digestType=MD5)
static FailureMessageEffect determineFailureMessageEffect(const SipMessage &response, const std::set< int > *additionalTransactionTerminatingResponses=NULL)
static bool isDigestAlgorithmSupported(const Auth &auth, DigestType &digestType)
static Data computeUniqueBranch()
Creates and returns a unique branch parameter.
static SipMessage * makeFailureAck(const SipMessage &request, const SipMessage &response)
This interface should be used by the stack (TransactionState) to create an AckMsg to a failure respon...
static Auth makeChallengeResponseAuth(const SipMessage &request, const Data &username, const Data &password, const Auth &challenge, const Data &cnonce, unsigned int &nonceCount, Data &nonceCountString)
static Data makeNonce(const SipMessage &request, const Data ×tamp)
static SipMessage * makeSubscribe(const NameAddr &target, const NameAddr &from)
Create a Subscribe request with an empty Contact. See makeRequest.
static Data computeCallId()
bool isWellFormed() const
Returns true iff this element was parsed successfully, according to the implementation of parse().
virtual Brief brief() const
return a facet for brief encoding of message
SIP body type for holding Multipart-Alternative body contents (MIME content-type multipart/alternativ...
SIP body type for holding Multipart-Mixed body contents (MIME content-type multipart/mixed).
std::vector< Contents * > Parts
SIP body type for holding Multipart-Signed body contents (MIME content-type multipart/signed).
Represents the "name-addr" and the "addr-spec" elements in the RFC 3261 grammar.
const Data & param(const ExtensionParameter ¶m) const
Const accessor for non-natively-supported parameter types.
uint64_t getCreationTime()
virtual NonceHelper::Nonce parseNonce(const Data &nonce)=0
virtual Data makeNonce(const SipMessage &request, const Data ×tamp)=0
Provides string-parsing functionality with protection from buffer overflow.
CurrentPosition skipWhitespace()
CurrentPosition skipToChars(const char *cs)
CurrentPosition skipToChar(char c)
CurrentPosition position() const
CurrentPosition skipN(size_t count)
CurrentPosition skipChar()
void data(Data &data, const char *start) const
make the passed in data share memory with the buffer (uses Data::Share)
BaseException used to indicate parse failures.
const char * name() const noexcept override
bool empty() const
return true or false indicating whether the mParsers vector is empty or not
void append(const ParserContainerBase &rhs)
append the vector to the mParsers vector held locally
A const_iterator class (bidirectional)
An iterator class (bidirectional)
Container class for ParserCategory, used by SipMessage to represent multi-valued headers (Contact,...
iterator end()
Returns an iterator pointing to the last header field value.
iterator begin()
Returns an iterator pointing to the first header field value.
void push_back(const T &t)
Inserts a header field value at the back of this container.
SIP body type for holding PKCS7 contents (MIME content-type application/pkcs7-mime).
static int getRandom()
Returns a postive integer (31 bits) of randomness.
static Data getCryptoRandomHex(unsigned int numBytes)
Represents the "Request-Line" element in the RFC 3261 grammar.
const Data & getSipVersion() const
MethodTypes getMethod() const
Provides an interface to process and generate SDP bodies (MIME content-type application/sdp).
virtual Contents * clone() const
duplicate an SdpContents object
void setIdentity(const Data &identity)
void setSignatureStatus(SignatureStatus status)
void setSigner(const Data &signer)
Represents a SIP message.
void setRFC2543TransactionId(const Data &tid)
bool isRequest() const
Returns true if message is a request, false otherwise.
const Data & getRFC2543TransactionId() const
Calculates an MD5 hash over the Request-URI, To tag (for non-INVITE transactions),...
bool hasForceTarget() const
Contents * getContents() const
Retrieves the body of a SIP message.
void setForceTarget(const Uri &uri)
deal with a notion of an "out-of-band" forced target for SIP routing
bool empty(const HeaderBase &headerType) const
Returns true if the header field is present and non-empty, false otherwise.
const RequestLine & header(const RequestLineType &l) const
Returns the RequestLine. This is only valid for request messages.
bool isResponse() const
Returns true if message is a response, false otherwise.
const RequestLine & const_header(const RequestLineType &l) const
EncodeStream & encodeSingleHeader(Headers::Type type, EncodeStream &str) const
void setFromExternal()
Mark message as externally generated.
bool exists(const HeaderBase &headerType) const
Returns true if the given header field is present, false otherwise.
const Tuple & getSource() const
Returns the source tuple that the message was received from only makes sense for messages received fr...
bool isExternal() const
Check if SipMessage is to be treated as it came off the wire.
void setFromTU()
Mark message as internally generated.
static const int DefaultSipsPort
static const char * authInt
static const char * COLON
static const int DefaultSipPort
static const char * COMMA
static const char * Digest
static uint64_t getTimeSecs()
Returns the current clock time in seconds.
Represents the "token" element in the RFC 3261 grammar.
const Data & value() const
Gets the value (ie; no parameters) of this Token as a Data&.
Represents a network address.
bool isPrivateAddress() const
void setType(TransportType type)
static TransportType toTransport(const Data &)
Converts a string representation of transport type, i.e.
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
bool exists(const Param< Uri > ¶mType) const
const Data & param(const ExtensionParameter ¶m) const
Const accessor for non-natively-supported parameter types.
Represents the "via-parm" element in the RFC 3261 grammar.
Represents the "warning-value" element in the RFC 3261 grammar.
This file is used to handle compatibility fixes/tweaks so reSIProcate can function on multiple platfo...
dcm! – add UnusedChecking(_enum) below;
StatusLineType h_StatusLine
bool isEqualNoCase(const Data &left, const Data &right)
TransportType toTransportType(const resip::Data &transportName)
unsigned long long uint64_t
const Data & getMethodName(MethodTypes t)
TransportType
An enumeration of transport protocols.
RequestLineType h_RequestLine
bool isReliable(TransportType type)
Returns true if passed in transport type is a reliable transport protocol.
ContentsSecAttrs()=default