void DoOpenUrl(LPSTR tokenResp, LPSTR url) { ptrA encodedUrl(mir_urlEncode(url)), encodedToken(mir_urlEncode(tokenResp)); size_t size = mir_strlen(TOKEN_AUTH_URL) + 1 + mir_strlen(encodedToken) + mir_strlen(encodedUrl); LPSTR composedUrl = (LPSTR)alloca(size); mir_snprintf(composedUrl, size, TOKEN_AUTH_URL, encodedToken, encodedUrl); Utils_OpenUrl(composedUrl); }
/// 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() ); }
/// 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; }