📄 helper.cxx
字号:
auth.param(p_cnonce) = cnonce;
auth.param(p_nc) = nonceCountString;
auth.param(p_qop) = authQop;
}
else
{
assert(challenge.exists(p_realm));
auth.param(p_response) = Helper::makeResponseMD5(username,
password,
challenge.param(p_realm),
getMethodName(request.header(h_RequestLine).getMethod()),
digestUri,
challenge.param(p_nonce));
}
if (challenge.exists(p_algorithm))
{
auth.param(p_algorithm) = challenge.param(p_algorithm);
}
else
{
auth.param(p_algorithm) = "MD5";
}
if (challenge.exists(p_opaque))
{
auth.param(p_opaque) = challenge.param(p_opaque);
}
return auth;
}
Data
Helper::qopOption(const Auth& challenge)
{
// priority-order list of preferred qop tokens
static Data preferredTokens[] =
{
Symbols::authInt,
Symbols::auth
};
bool found = false;
size_t index = 0;
if (challenge.exists(p_qopOptions) && !challenge.param(p_qopOptions).empty())
{
ParseBuffer pb(challenge.param(p_qopOptions).data(), challenge.param(p_qopOptions).size());
do
{
const char* anchor = pb.skipWhitespace();
pb.skipToChar(Symbols::COMMA[0]);
if (!pb.eof())
pb.skipChar();
Data q;
pb.data(q, anchor);
for (size_t i=0; i < sizeof(preferredTokens)/sizeof(*preferredTokens); i++)
{
if (q == preferredTokens[i])
{
// found a preferred token; is it higher priority?
if (!found || i < index)
{
found = true;
index = i;
}
}
}
}
while(!pb.eof());
}
if (found)
return preferredTokens[index];
return Data::Empty;
}
Auth
Helper::makeChallengeResponseAuthWithA1(const SipMessage& request,
const Data& username,
const Data& a1,
const Auth& challenge,
const Data& cnonce,
unsigned int& nonceCount,
Data& nonceCountString)
{
Auth auth;
auth.scheme() = "Digest";
auth.param(p_username) = username;
assert(challenge.exists(p_realm));
auth.param(p_realm) = challenge.param(p_realm);
assert(challenge.exists(p_nonce));
auth.param(p_nonce) = challenge.param(p_nonce);
Data digestUri;
{
DataStream s(digestUri);
//s << request.header(h_RequestLine).uri().host(); // wrong
s << request.header(h_RequestLine).uri(); // right
}
auth.param(p_uri) = digestUri;
Data authQop = qopOption(challenge);
if (!authQop.empty())
{
updateNonceCount(nonceCount, nonceCountString);
auth.param(p_response) = Helper::makeResponseMD5WithA1(a1,
getMethodName(request.header(h_RequestLine).getMethod()),
digestUri,
challenge.param(p_nonce),
authQop,
cnonce,
nonceCountString,
request.getContents());
auth.param(p_cnonce) = cnonce;
auth.param(p_nc) = nonceCountString;
auth.param(p_qop) = authQop;
}
else
{
assert(challenge.exists(p_realm));
auth.param(p_response) = Helper::makeResponseMD5WithA1(a1,
getMethodName(request.header(h_RequestLine).getMethod()),
digestUri,
challenge.param(p_nonce));
}
if (challenge.exists(p_algorithm))
{
auth.param(p_algorithm) = challenge.param(p_algorithm);
}
else
{
auth.param(p_algorithm) = "MD5";
}
if (challenge.exists(p_opaque))
{
auth.param(p_opaque) = challenge.param(p_opaque);
}
return auth;
}
//.dcm. all the auth stuff should be yanked out of helper and
//architected for algorithm independance
bool
Helper::algorithmAndQopSupported(const Auth& challenge)
{
if ( !(challenge.exists(p_nonce) && challenge.exists(p_realm)))
{
return false;
}
return (!challenge.exists(p_algorithm)
|| isEqualNoCase(challenge.param(p_algorithm), "MD5")
&& (!challenge.exists(p_qop)
|| isEqualNoCase(challenge.param(p_qop), Symbols::auth)
|| isEqualNoCase(challenge.param(p_qop), Symbols::authInt)));
}
SipMessage&
Helper::addAuthorization(SipMessage& request,
const SipMessage& challenge,
const Data& username,
const Data& password,
const Data& cnonce,
unsigned int& nonceCount)
{
Data nonceCountString = Data::Empty;
assert(challenge.isResponse());
assert(challenge.header(h_StatusLine).responseCode() == 401 ||
challenge.header(h_StatusLine).responseCode() == 407);
if (challenge.exists(h_ProxyAuthenticates))
{
const ParserContainer<Auth>& auths = challenge.header(h_ProxyAuthenticates);
for (ParserContainer<Auth>::const_iterator i = auths.begin();
i != auths.end(); i++)
{
request.header(h_ProxyAuthorizations).push_back(makeChallengeResponseAuth(request, username, password, *i,
cnonce, nonceCount, nonceCountString));
}
}
if (challenge.exists(h_WWWAuthenticates))
{
const ParserContainer<Auth>& auths = challenge.header(h_WWWAuthenticates);
for (ParserContainer<Auth>::const_iterator i = auths.begin();
i != auths.end(); i++)
{
request.header(h_Authorizations).push_back(makeChallengeResponseAuth(request, username, password, *i,
cnonce, nonceCount, nonceCountString));
}
}
return request;
}
Uri
Helper::makeUri(const Data& aor, const Data& scheme)
{
assert(!aor.prefix("sip:"));
assert(!aor.prefix("sips:"));
Data tmp(aor.size() + scheme.size() + 1, Data::Preallocate);
tmp += scheme;
tmp += Symbols::COLON;
tmp += aor;
Uri uri(tmp);
return uri;
}
void
Helper::processStrictRoute(SipMessage& request)
{
if (request.exists(h_Routes) &&
!request.header(h_Routes).empty() &&
!request.header(h_Routes).front().uri().exists(p_lr))
{
// The next hop is a strict router. Move the next hop into the
// Request-URI and move the ultimate destination to the end of the
// route list. Force the message target to be the next hop router.
request.header(h_Routes).push_back(NameAddr(request.header(h_RequestLine).uri()));
request.header(h_RequestLine).uri() = request.header(h_Routes).front().uri();
request.header(h_Routes).pop_front(); // !jf!
assert(!request.hasForceTarget());
request.setForceTarget(request.header(h_RequestLine).uri());
}
}
int
Helper::getPortForReply(SipMessage& request, bool returnDefault)
{
assert(request.isRequest());
int port = -1;
if (request.header(h_Vias).front().exists(p_rport))
{
port = request.getSource().getPort();
}
else
{
port = request.header(h_Vias).front().sentPort();
if (port <= 0 || port > 65535)
{
if(!returnDefault)
{
port=0;
}
else if(request.header(h_Vias).front().transport() == Symbols::TLS ||
request.header(h_Vias).front().transport() == Symbols::DTLS)
{
port = Symbols::DefaultSipsPort;
}
else
{
port = Symbols::DefaultSipPort;
}
}
}
assert(port != -1);
return port;
}
Uri
Helper::fromAor(const Data& aor, const Data& scheme)
{
return makeUri(aor, scheme);
}
bool
Helper::validateMessage(const SipMessage& message,resip::Data* reason)
{
if (!message.exists(h_To) ||
!message.exists(h_From) ||
!message.exists(h_CSeq) ||
!message.exists(h_CallId) ||
!message.exists(h_Vias) ||
message.header(h_Vias).empty())
{
InfoLog(<< "Missing mandatory header fields (To, From, CSeq, Call-Id or Via)");
DebugLog(<< message);
if(reason) *reason="Missing mandatory header field";
return false;
}
else
{
try
{
message.header(h_CSeq).checkParsed();
}
catch(ParseBuffer::Exception&)
{
InfoLog(<<"Malformed CSeq header");
if(reason) *reason="Malformed CSeq header";
return false;
}
try
{
message.header(h_Vias).front().checkParsed();
}
catch(ParseBuffer::Exception& e)
{
InfoLog(<<"Malformed topmost Via header: " << e);
if(reason) *reason="Malformed topmost Via header";
return false;
}
if (message.isRequest())
{
try
{
message.header(h_RequestLine).checkParsed();
}
catch(ParseBuffer::Exception& e)
{
InfoLog(<< "Illegal request line " << e);
if(reason) *reason="Malformed Request Line";
return false;
}
if(message.header(h_RequestLine).method()!=message.header(h_CSeq).method())
{
InfoLog(<< "Method mismatch btw Request Line and CSeq");
if(reason) *reason="Method mismatch btw Request Line and CSeq";
return false;
}
}
else
{
try
{
message.header(h_StatusLine).checkParsed();
}
catch(ParseBuffer::Exception& e)
{
InfoLog(<< "Malformed status line " << e);
if(reason) *reason="Malformed status line";
return false;
}
}
return true;
}
}
#if defined(USE_SSL)
#include <openssl/blowfish.h>
static const Data sep("[]");
static const Data pad("\0\0\0\0\0\0\0", 7);
static const Data GRUU("_GRUU");
static const int saltBytes(16);
Data
Helper::gruuUserPart(const Data& instanceId,
const Data& aor,
const Data& key)
{
unsigned char ivec[8];
ivec[0] = '\x6E';
ivec[1] = '\xE7';
ivec[2] = '\xB0';
ivec[3] = '\x4A';
ivec[4] = '\x45';
ivec[5] = '\x93';
ivec[6] = '\x7D';
ivec[7] = '\x51';
BF_KEY fish;
BF_set_key(&fish, key.size(), (const unsigned char*)key.data());
const Data salt(resip::Random::getRandomHex(saltBytes));
const Data token(salt + instanceId + sep + aor + '\0' +
pad.substr(0, (8 - ((salt.size() +
instanceId.size() +
sep.size() + 1
+ aor.size() ) % 8))
% 8));
auto_ptr <unsigned char> out(new unsigned char[token.size()]);
BF_cbc_encrypt((const unsigned char*)token.data(),
out.get(),
token.size(),
&fish,
ivec,
BF_ENCRYPT);
return GRUU + Data(out.get(),token.size()).base64encode(true/*safe URL*/);
}
std::pair<Data,Data>
Helper::fromGruuUserPart(const Data& gruuUserPart,
const Data& key)
{
unsigned char ivec[8];
ivec[0] = '\x6E';
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -