// Initialize the chain value. void CallId::initialize() { NetMd5Codec encoder; // Get the start time. OsTime currentTime; OsDateTime::getCurTime(currentTime); encoder.hash(¤tTime, sizeof(currentTime)); // Get the process ID. PID processId; processId = OsProcess::getCurrentPID(); encoder.hash(&processId, sizeof(processId)); // Get the host identity. UtlString thisHost; OsSocket::getHostIp(&thisHost); encoder.hash(thisHost); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "CallId::initialize sChainValue"); // Save the initial hash used to seed the sequence encoder.appendBase64Sig(sChainValue); // Note initialization is done. sChainValueInitialized = true; }
/// Encodes identity info void SipXauthIdentity::encode(UtlString & identityValue, const UtlString & callId, const UtlString & fromTag, const OsDateTime & timestamp, DialogRule bindRule ) { // calculate timestamp OsTime osTime; timestamp.cvtToTimeSinceEpoch(osTime); long seconds = osTime.seconds(); char stamp[65]; sprintf(stamp, "%lX", seconds); UtlString strSignature(stamp); strSignature.append(SignatureFieldSeparator); // signature-hash=MD5(<timestamp><secret><from-tag><call-id><identity>) NetMd5Codec signatureHash; signatureHash.hash(stamp); signatureHash.hash(sSignatureSecret); if (requireDialogBinding == bindRule) { signatureHash.hash(fromTag); signatureHash.hash(callId); } else { strSignature.append(SignatureFieldSeparator); } signatureHash.hash(mIdentity); UtlString strSignatureHash; signatureHash.appendHashValue(strSignature); Url encodedUrl(mIdentity); encodedUrl.setScheme(Url::SipUrlScheme); encodedUrl.setUrlParameter(SignatureUrlParamName, strSignature.data()); encodedUrl.toString(identityValue); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipXauthIdentity::encode " "identity '%s'", identityValue.data() ); }
void SignedUrl::computeSignature( const UtlString& userInfo, const UtlString& hostPort, UtlString& signature ) { // signature-hash=MD5(<secret><userinfo><hostport>) NetMd5Codec signatureHash; signatureHash.hash( sSignatureSecret ); if( !userInfo.isNull() ) { signatureHash.hash( userInfo ); } signatureHash.hash( hostPort ); signature.remove(0); signatureHash.appendHashValue( signature ); }
// Compute the next chain value. void CallId::nextValue() { NetMd5Codec encoder; // If we haven't initialized yet, do so. if (!sChainValueInitialized) { initialize(); } // Use the previous chain value to seed the next one encoder.hash(sChainValue); // Get the time and hash it into the next value OsTime currentTime; OsDateTime::getCurTime(currentTime); encoder.hash(¤tTime, sizeof(currentTime)); // Replace the old chain value with the new one sChainValue.remove(0); encoder.appendBase64Sig(sChainValue); }
/// Check the signature and parse the identity bool SipXauthIdentity::decode(const UtlString& identityValue, const UtlString& callId, const UtlString& fromTag, DialogRule bindRule ) { /** * See SipXauthIdentity Encoding comment at the top of the file */ Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipXauthIdentity::decode " "parse '%s'", identityValue.data() ); mIdentity.remove(0); mIsValidIdentity = FALSE; bool decodeError = false; // false iff the identity was correctly signed and successfully parsed UtlString decodedIdentity; unsigned long epochTimestamp = 0; UtlString timestamp; UtlString actualSignatureHash; bool isBound = false; Url encodedUrl(identityValue, Url::NameAddr); if (Url::SipUrlScheme == encodedUrl.getScheme()) { // Only proceed if the URL parsing succeeded // Extract the identity encodedUrl.getIdentity(decodedIdentity); // Extract signature parameter UtlString signatureParamValue; if (encodedUrl.getUrlParameter(SignatureUrlParamName, signatureParamValue)) { // only proceed if signature parameter was found RegEx signatureRegEx(SignatureRegEx); if (signatureRegEx.Search(signatureParamValue)) { UtlString secondSeparator; isBound = ( signatureRegEx.MatchString(&secondSeparator,2) && secondSeparator.isNull()); // there is only one ':' separator if ( (requireDialogBinding == bindRule) // must be bound && ! isBound ) { decodeError = true; Os::Logger::instance().log(FAC_SIP, PRI_WARNING, "SipXauthIdentity::decode " "'%s' is an unbound identity", identityValue.data() ); } else { // extract timestamp if ( !signatureRegEx.MatchString(×tamp,1) || !from_string(epochTimestamp, timestamp) ) { decodeError = true; Os::Logger::instance().log(FAC_SIP, PRI_WARNING, "SipXauthIdentity::decode " "'%s' invalid timestamp", identityValue.data() ); } // extract signature else if (!signatureRegEx.MatchString(&actualSignatureHash,3)) { decodeError = true; Os::Logger::instance().log(FAC_SIP, PRI_WARNING, "SipXauthIdentity::decode '%s' missing hash", identityValue.data() ); } } } else { decodeError = true; Os::Logger::instance().log(FAC_SIP, PRI_WARNING, "SipXauthIdentity::decode " "'%s' invalid signature format", identityValue.data() ); } } else { decodeError = true; Os::Logger::instance().log(FAC_SIP, PRI_WARNING, "SipXauthIdentity::decode " "'%s' missing '%s' param", identityValue.data(), SignatureUrlParamName ); } } else { decodeError = true; Os::Logger::instance().log(FAC_SIP, PRI_WARNING, "SipXauthIdentity::decode " "'%s' URL parsing failed", identityValue.data() ); } // validate timestamp if (!decodeError && !sSignatureValidityInterval.isNoWait()) { // timestamp validity check if (epochTimestamp + sSignatureValidityInterval.seconds() < OsDateTime::getSecsSinceEpoch()) { decodeError = true; OsDateTime generateDate(OsTime(epochTimestamp,0)); UtlString generateTimeString; generateDate.getIsoTimeStringZ(generateTimeString); Os::Logger::instance().log(FAC_SIP, PRI_WARNING, "SipXauthIdentity::decode(%s)" " timestamp '%lX' from '%s' too old with interval of '%d' seconds", identityValue.data(), epochTimestamp, generateTimeString.data(), sSignatureValidityInterval.seconds() ); } } // validate signature hash if (!decodeError) { UtlString validSignature; // signature-hash=MD5(<timestamp><secret><from-tag><call-id><identity>) NetMd5Codec signatureHash; signatureHash.hash(timestamp); signatureHash.hash(sSignatureSecret); if (isBound) { signatureHash.hash(fromTag); signatureHash.hash(callId); } signatureHash.hash(decodedIdentity); signatureHash.appendHashValue(validSignature); if (validSignature.compareTo(actualSignatureHash) == 0) { // the signature checks out mIdentity = decodedIdentity; mIsValidIdentity = TRUE; } else { Os::Logger::instance().log(FAC_SIP, PRI_WARNING, "SipXauthIdentity::decode " "'%s' invalid signature '%s' != '%s'", identityValue.data(), actualSignatureHash.data(), validSignature.data() ); } } return mIsValidIdentity; }