/// 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()
                 );
}
示例#2
0
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 );
}
/// 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(&timestamp,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;
}