--- /dev/null
+From bdbeb7c4b2b11efc2e59f5dee7aa4360a2bc9fff Mon Sep 17 00:00:00 2001
+From: sauwming <ming@teluu.com>
+Date: Thu, 22 Apr 2021 14:03:28 +0800
+Subject: [PATCH 90/90] Skip unsupported digest algorithm (#2408)
+
+Co-authored-by: Nanang Izzuddin <nanang@teluu.com>
+---
+ pjsip/src/pjsip/sip_auth_client.c | 32 +++++--
+ tests/pjsua/scripts-sipp/uas-auth-two-algo.py | 7 ++
+ .../pjsua/scripts-sipp/uas-auth-two-algo.xml | 83 +++++++++++++++++++
+ 3 files changed, 117 insertions(+), 5 deletions(-)
+ create mode 100644 tests/pjsua/scripts-sipp/uas-auth-two-algo.py
+ create mode 100644 tests/pjsua/scripts-sipp/uas-auth-two-algo.xml
+
+--- a/pjsip/src/pjsip/sip_auth_client.c
++++ b/pjsip/src/pjsip/sip_auth_client.c
+@@ -1042,7 +1042,7 @@ static pj_status_t process_auth( pj_pool
+ pjsip_hdr *hdr;
+ pj_status_t status;
+
+- /* See if we have sent authorization header for this realm */
++ /* See if we have sent authorization header for this realm (and scheme) */
+ hdr = tdata->msg->hdr.next;
+ while (hdr != &tdata->msg->hdr) {
+ if ((hchal->type == PJSIP_H_WWW_AUTHENTICATE &&
+@@ -1052,7 +1052,8 @@ static pj_status_t process_auth( pj_pool
+ {
+ sent_auth = (pjsip_authorization_hdr*) hdr;
+ if (pj_stricmp(&hchal->challenge.common.realm,
+- &sent_auth->credential.common.realm )==0)
++ &sent_auth->credential.common.realm)==0 &&
++ pj_stricmp(&hchal->scheme, &sent_auth->scheme)==0)
+ {
+ /* If this authorization has empty response, remove it. */
+ if (pj_stricmp(&sent_auth->scheme, &pjsip_DIGEST_STR)==0 &&
+@@ -1062,6 +1063,14 @@ static pj_status_t process_auth( pj_pool
+ hdr = hdr->next;
+ pj_list_erase(sent_auth);
+ continue;
++ } else
++ if (pj_stricmp(&sent_auth->scheme, &pjsip_DIGEST_STR)==0 &&
++ pj_stricmp(&sent_auth->credential.digest.algorithm,
++ &hchal->challenge.digest.algorithm)!=0)
++ {
++ /* Same 'digest' scheme but different algo */
++ hdr = hdr->next;
++ continue;
+ } else {
+ /* Found previous authorization attempt */
+ break;
+@@ -1155,9 +1164,10 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_reini
+ {
+ pjsip_tx_data *tdata;
+ const pjsip_hdr *hdr;
+- unsigned chal_cnt;
++ unsigned chal_cnt, auth_cnt;
+ pjsip_via_hdr *via;
+ pj_status_t status;
++ pj_status_t last_auth_err;
+
+ PJ_ASSERT_RETURN(sess && rdata && old_request && new_request,
+ PJ_EINVAL);
+@@ -1178,6 +1188,8 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_reini
+ */
+ hdr = rdata->msg_info.msg->hdr.next;
+ chal_cnt = 0;
++ auth_cnt = 0;
++ last_auth_err = PJSIP_EAUTHNOAUTH;
+ while (hdr != &rdata->msg_info.msg->hdr) {
+ pjsip_cached_auth *cached_auth;
+ const pjsip_www_authenticate_hdr *hchal;
+@@ -1222,8 +1234,13 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_reini
+ */
+ status = process_auth(tdata->pool, hchal, tdata->msg->line.req.uri,
+ tdata, sess, cached_auth, &hauth);
+- if (status != PJ_SUCCESS)
+- return status;
++ if (status != PJ_SUCCESS) {
++ last_auth_err = status;
++
++ /* Process next header. */
++ hdr = hdr->next;
++ continue;
++ }
+
+ if (pj_pool_get_used_size(cached_auth->pool) >
+ PJSIP_AUTH_CACHED_POOL_MAX_SIZE)
+@@ -1236,12 +1253,17 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_reini
+
+ /* Process next header. */
+ hdr = hdr->next;
++ auth_cnt++;
+ }
+
+ /* Check if challenge is present */
+ if (chal_cnt == 0)
+ return PJSIP_EAUTHNOCHAL;
+
++ /* Check if any authorization header has been created */
++ if (auth_cnt == 0)
++ return last_auth_err;
++
+ /* Remove branch param in Via header. */
+ via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
+ via->branch_param.slen = 0;
+--- /dev/null
++++ b/tests/pjsua/scripts-sipp/uas-auth-two-algo.py
+@@ -0,0 +1,7 @@
++# $Id$
++#
++import inc_const as const
++
++PJSUA = ["--null-audio --max-calls=1 --id=sip:a@localhost --username=a --realm=* --registrar=$SIPP_URI"]
++
++PJSUA_EXPECTS = [[0, "registration success", ""]]
+--- /dev/null
++++ b/tests/pjsua/scripts-sipp/uas-auth-two-algo.xml
+@@ -0,0 +1,83 @@
++<?xml version="1.0" encoding="ISO-8859-1" ?>
++<!DOCTYPE scenario SYSTEM "sipp.dtd">
++
++<scenario name="Basic UAS responder">
++ <recv request="REGISTER" crlf="true">
++ </recv>
++
++ <send>
++ <![CDATA[
++ SIP/2.0 100 Trying
++ [last_Via:];received=1.1.1.1;rport=1111
++ [last_From:]
++ [last_To:];tag=[call_number]
++ [last_Call-ID:]
++ [last_CSeq:]
++ Content-Length: 0
++ ]]>
++ </send>
++
++ <send>
++ <![CDATA[
++ SIP/2.0 401 Unauthorized
++ [last_Via:];received=1.1.1.1;rport=1111
++ [last_From:]
++ [last_To:];tag=[call_number]
++ [last_Call-ID:]
++ [last_CSeq:]
++ WWW-Authenticate: Digest realm="sip.linphone.org", nonce="PARV4gAAAADgw3asAADW8zsi5BEAAAAA", opaque="+GNywA==", algorithm=SHA-256, qop="auth"
++ WWW-Authenticate: Digest realm="sip.linphone.org", nonce="PARV4gAAAADgw3asAADW8zsi5BEAAAAA", opaque="+GNywA==", algorithm=MD5, qop="auth"
++ WWW-Authenticate: Digest realm="sip.linphone.org", nonce="PARV4gAAAADgw3asAADW8zsi5BEAAAAA", opaque="+GNywA==", algorithm=MD2, qop="auth"
++ Content-Length: 0
++ ]]>
++ </send>
++
++ <recv request="REGISTER" crlf="true">
++ <action>
++ <ereg regexp=".*"
++ search_in="hdr"
++ header="Authorization:"
++ assign_to="have_auth" />
++ </action>
++ </recv>
++
++ <nop next="resp_okay" test="have_auth" />
++
++ <send next="end">
++ <![CDATA[
++ SIP/2.0 403 no auth
++ [last_Via:];received=1.1.1.1;rport=1111
++ [last_From:]
++ [last_To:];tag=[call_number]
++ [last_Call-ID:]
++ [last_CSeq:]
++ [last_Contact:]
++ Content-Length: 0
++ ]]>
++ </send>
++
++ <label id="resp_okay" />
++
++ <send>
++ <![CDATA[
++ SIP/2.0 200 OK
++ [last_Via:];received=1.1.1.1;rport=1111
++ [last_From:]
++ [last_To:];tag=[call_number]
++ [last_Call-ID:]
++ [last_CSeq:]
++ [last_Contact:]
++ Content-Length: 0
++ ]]>
++ </send>
++
++ <label id="end" />
++
++ <!-- definition of the response time repartition table (unit is ms) -->
++ <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
++
++ <!-- definition of the call length repartition table (unit is ms) -->
++ <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
++
++</scenario>
++