[OpenSIPS-Users] DIGEST AUTH with no uac_auth function(CSeq trouble workaround)

neumann itsroot at gmail.com
Thu Jan 22 16:29:32 CET 2015


If someone interesting this is set of routes to make Digest authorization manually(with no uac_auth)
I would be grateful if somebody optimizes this workaround or find security troubles.

route[dispatch_out] {
     #For testing, I used the dispatcher module
     #You can create your own search method register data for proxy in this cfg is «hardcoded» val $avp(registrant)=6
     #Now I use gateway attributes in dr_gateways table
     #Username and password and aor I get from registrant table
    $avp(registrant)=6;
     #dispatcher set 1001 is set contain proxy which need to auth
     #lets go!

    if(!ds_select_domain("1001","8")){
       send_reply("404", "No destination");
       exit;
    }
     #clearing auth flag
    resetflag(7);
     #get auth data from registrant table
    avp_db_query("select username, password, aor from registrant where id=$avp(registrant)","$avp(stored_username);$avp(stored_password);$avp(stored_aor)");
     #build new From-hdr with registrant data
    uac_replace_from("$avp(stored_username)", "$avp(stored_aor)");
     #build new To-hdr with registrant data
    $avp(stored_to)="sip:" + $(ru{uri.user}) + "@" + $(avp(stored_to){uri.host}) + ":" + $(ru{uri.port});
    uac_replace_to("$avp(stored_to)");

    t_on_failure("rtf_dispatch_out");
    t_on_reply("auth_reply");
    t_relay();
    exit;
}

onreply_route[auth_reply] {
    if ( t_check_status("401|407") ) {
        #if is not first "unauthorized"  - do nothing (see below)
        if (isflagset(7)) {
            return;
        }
        #special route to parce WWW-Atuh hdr
         route(parse_digest);
     } else if ( t_check_status("200") ) {
         #special route to decrease cseq(see below)
        route(dec_cseq);
     }
}

route[parse_digest]{
    #saving Auth HDR of 401/407 reply
    $avp(stored_digest)=$hdr(WWW-Authenticate);
    xlog("L_INFO", "Route PARSE_DIGEST orig WWW-Authenticate header is $hdr(WWW-Authenticate);");

    #some transformations for parse
    avp_subst("$avp(stored_digest)", "/, /;/g");
    avp_subst("$avp(stored_digest)", "/Digest //g");
    avp_subst("$avp(stored_digest)", "/\"//g");
    xlog("L_INFO", "Route PARSE_DIGEST digest params is $avp(stored_digest)");

    #use script transformations to get values of HDR and save it in AVPs
    $avp(stored_realm)=$(avp(stored_digest){param.value,realm});
    $avp(stored_nonce)=$(avp(stored_digest){param.value,nonce});
    if $(avp(stored_digest){param.exist,algorithm}) {
        $avp(stored_algorithm)=$(avp(stored_digest){param.value,algorithm});
    } else {
        $avp(stored_algorithm)="MD5";
    }
    if $(avp(stored_digest){param.exist,qop}) {
        $avp(stored_qop)=$(avp(stored_digest){param.value,qop});
    } else {
        $avp(stored_qop)="none";
    }

    xlog("L_INFO", "Route PARSE_DIGEST digest algorithm is $avp(stored_algorithm)");
    xlog("L_INFO", "Route PARSE_DIGEST digest realm is $avp(stored_realm)");
    xlog("L_INFO", "Route PARSE_DIGEST digest nonce is $avp(stored_nonce)");
    xlog("L_INFO", "Route PARSE_DIGEST digest qop is $avp(stored_qop)");

    return;
}

#failure route - processing 401/407 error and send new invite with Authorization HDR
failure_route[rtf_dispatch_out]{
    xlog("L_INFO", "DISPATCHER OUTBOUND FILED");
     if ( t_check_status("401|407") ) {
          if (isflagset(7)) {
              #If its not first «unauthorized» - registration data is wrong
               t_reply("503","Authentication failed");
               exit;
          }

        #go to route wich append auth HDR
        route(append_authorize);
        #route which increase cseq 
        route(inc_cseq);
        t_on_failure("rtf_dispatch_out");
        t_relay();
        exit;
     }

    if (t_was_cancelled()) {
        exit;
    }

    #this is standard part of dispatcher failure route
    xlog("L_INFO", "IAM IN FAILURE ROUTE DISPATCH\n");
    ds_mark_dst("p");
    xlog("L_INFO", "IAM SELECT NEW DESTINATION\n");
    if (ds_next_domain()) {
        $avp(final_reply_timeout) = 2;
        t_on_failure("rtf_dispatch_out");
        t_relay();
        exit;
    }
}


#this route to append Authorization HDR to second invite
route[append_authorize] {
    xlog("L_INFO", "Route APPEND_AUTHORIZE orig ruri is $ru");
    #saving ruri for use it for build response
    $avp(stored_ruri)="sip:" + $(ru{uri.user}) + "@" + $(ru{uri.host});
    xlog("L_INFO", "Route APPEND_AUTHORIZE parsed ruri is $avp(stored_ruri)");

    #calculate ha1
    $avp(ha1)=$avp(stored_username) + ":" + $avp(stored_realm) + ":" + $avp(stored_password);
    xlog("L_INFO", "Route APPEND_AUTHORIZE ha1 is $avp(ha1)");
    $avp(ha1)=$(avp(ha1){s.md5});
    xlog("L_INFO", "Route APPEND_AUTHORIZE ha1 is $avp(ha1)");

    #switch for different types of qop
    switch($avp(stored_qop))
    {
        case "none":
            $avp(ha2)=$rm + ":" + $avp(stored_ruri);
            xlog("L_INFO", "Route APPEND_AUTHORIZE $rm ha2 is $avp(ha2)");
            $avp(ha2)=$(avp(ha2){s.md5});
            xlog("L_INFO", "Route APPEND_AUTHORIZE $rm ha2 is $avp(ha2)");

            $avp(auth_response)=$avp(ha1) + ":" + $avp(stored_nonce) + ":" + $avp(ha2);
            xlog("L_INFO", "Route APPEND_AUTHORIZE auth_response is $avp(auth_response)");
            $avp(auth_response)=$(avp(auth_response){s.md5});
            xlog("L_INFO", "Route APPEND_AUTHORIZE auth_response is $avp(auth_response)");

            $avp(auth_hdr)="Authorization: Digest username=\"" +
            $avp(stored_username) +
            "\", realm=\"" +
            $avp(stored_realm) +
            "\", nonce=\"" +
            $avp(stored_nonce) +
            "\", uri=\"" +
            $avp(stored_ruri) +
            "\", response=\"" +
            $avp(auth_response) +
            "\", algorithm=" +
            $avp(stored_algorithm) +
            "\r\n";
        break;

        case "auth":
            $avp(ha2)=$rm + ":" + $avp(stored_ruri);
            xlog("L_INFO", "Route APPEND_AUTHORIZE $rm ha2 is $avp(ha2)");
            $avp(ha2)=$(avp(ha2){s.md5});
            xlog("L_INFO", "Route APPEND_AUTHORIZE $rm ha2 is $avp(ha2)");
            $avp(stored_cnonce)=$(RANDOM{s.dec2hex});
            #xlog("random testing $(RANDOM{s.dec2hex})\n");
            $avp(nc)="00000001";

            $avp(auth_response)=$avp(ha1) + ":" + $avp(stored_nonce) + ":00000001:" + $avp(stored_cnonce) + ":auth:" + $avp(ha2);
            xlog("L_INFO", "Route APPEND_AUTHORIZE auth_response is $avp(auth_response)");
            $avp(auth_response)=$(avp(auth_response){s.md5});
            xlog("L_INFO", "Route APPEND_AUTHORIZE auth_response is $avp(auth_response)");

            $avp(auth_hdr)="Authorization: Digest username=\"" +
            $avp(stored_username) +
            "\", realm=\"" +
            $avp(stored_realm) +
            "\", nonce=\"" +
            $avp(stored_nonce) +
            "\", uri=\"" +
            $avp(stored_ruri) +
            "\", response=\"" +
            $avp(auth_response) +
            "\", algorithm=" +
            $avp(stored_algorithm) +
            "\", qop=auth" +
            ", cnonce=\"" +
            $avp(stored_cnonce) +
            "\", nc=00000001" +
            "\r\n";

        break;

        case "auth-int":
               #TODO
            xlog("L_INFO", "Route APPEND_AUTHORIZE not supported qop auth-int");
        break;

        default:
            xlog("L_INFO", "Route APPEND_AUTHORIZE unexpected qop is $avp(stored_qop)");
    }

    xlog("L_INFO", "Route APPEND_AUTHORIZE auth_hdr is <$avp(auth_hdr)>");
    #Append HDR to Invite
    if (append_hf("$avp(auth_hdr)")) {
        setflag(7);
    }

    return;
}

#two short routes to inc or dec cseq value
#it use dialog module!!!!!!
#I need dlg_flag for check manual cseq updating
---------------------------------------------------------
…...
route[inc_cseq]{
    if(remove_hf("CSeq")){
        $var(cseq) = $(cs{s.int}) + 1;
        $var(cseq) = "CSeq: " + $var(cseq) + " " + $rm + "\r\n";
        append_hf("$var(cseq)");
        if (!is_dlg_flag_set("7")) {
            set_dlg_flag("7");
        }
        xlog("L_INFO", "INCREASE CSEQ NEW IS <$var(cseq)>");
    }
    return;
}

route[dec_cseq]{
    if(remove_hf("CSeq")){
        $var(cseq) = $(cs{s.int}) - 1;
        $var(cseq) = "CSeq: " + $var(cseq) + " " + $rm + "\r\n";
        append_hf("$var(cseq)");
        if (!is_dlg_flag_set("7")) {
            set_dlg_flag("7");
        }
        xlog("L_INFO", "DECREASE CSEQ NEW IS<$var(cseq)>");
    }
    return;
}

#and in standard part of route logic
#that looks like this:
     if (has_totag()) {
          if (loose_route() || match_dialog() ) {
               if (is_method("BYE")) {
                    setflag(ACC_DO); # do accounting ...
                    setflag(ACC_FAILED); # ... even if the transaction fails
               } else if (is_method("INVITE")) {
                    record_route();
               } else if (is_method("ACK")) {
                #Decreasing cseq back
                if (is_dlg_flag_set("7")) {
                    route(inc_cseq);
                }
               }
               …………..
     }
…...
---------------------------------------------------------



Thanks!


————————————

Timofeev Dmitry
VoIP Engineer
Linux, Asterisk, Freeswitch, Cisco solutions
Skype: itsroot
icq: 227227933



-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.opensips.org/pipermail/users/attachments/20150122/fa1442d5/attachment-0001.htm>


More information about the Users mailing list