Index: /pjproject/trunk/build.symbian/pjsip.mmp
===================================================================
--- /pjproject/trunk/build.symbian/pjsip.mmp	(revision 1499)
+++ /pjproject/trunk/build.symbian/pjsip.mmp	(revision 1500)
@@ -33,4 +33,5 @@
 // PJSIP-CORE files
 
+//SOURCE	sip_auth_aka.c
 SOURCE	sip_auth_client.c
 SOURCE	sip_auth_msg.c
Index: /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c
===================================================================
--- /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 1499)
+++ /pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 1500)
@@ -672,4 +672,9 @@
 	    cur_acc->cred_info[cur_acc->cred_count].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
 	    cur_acc->cred_info[cur_acc->cred_count].data = pj_str(pj_optarg);
+#if PJSIP_HAS_DIGEST_AKA_AUTH
+	    cur_acc->cred_info[cur_acc->cred_count].data_type |= PJSIP_CRED_DATA_EXT_AKA;
+	    cur_acc->cred_info[cur_acc->cred_count].ext.aka.k = pj_str(pj_optarg);
+	    cur_acc->cred_info[cur_acc->cred_count].ext.aka.cb = &pjsip_auth_create_aka_response;
+#endif
 	    break;
 
Index: /pjproject/trunk/pjsip/include/pjsip/print_util.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/print_util.h	(revision 1499)
+++ /pjproject/trunk/pjsip/include/pjsip/print_util.h	(revision 1500)
@@ -51,4 +51,15 @@
 	} while (0)
 
+#define copy_advance_pair_quote(buf,str1,len1,str2,quotebegin,quoteend) \
+	do { \
+		printed = len1+str2.slen+2; \
+		if (printed >= (endbuf-buf)) return -1;	\
+		pj_memcpy(buf,str1,len1); \
+		*(buf+len1)=quotebegin; \
+		pj_memcpy(buf+len1+1, str2.ptr, str2.slen); \
+		*(buf+printed-1) = quoteend; \
+		buf += printed; \
+	} while (0)
+
 #define copy_advance_pair_escape(buf,str1,len1,str2,unres)	\
 	do { \
@@ -86,5 +97,4 @@
 #define copy_advance 		copy_advance_check
 #define copy_advance_pair 	copy_advance_pair_check
-#define copy_advance_pair_quote	copy_advance_pair_quote_check
 
 #define copy_advance_pair_quote_cond(buf,str1,len1,str2,quotebegin,quoteend) \
Index: /pjproject/trunk/pjsip/include/pjsip/sip_auth.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_auth.h	(revision 1499)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_auth.h	(revision 1500)
@@ -122,7 +122,8 @@
 	 *  is being used, the \a data field of this #pjsip_cred_info is
 	 *  not used, but it still must be initialized to an empty string.
+	 * Please see \ref PJSIP_AUTH_AKA_API for more information.
 	 */
 	struct {
-	    pj_str_t	  k;	/**< Permanent key.			*/
+	    pj_str_t	  k;	/**< Permanent subscriber key.		*/
 	    pj_str_t	  op;	/**< Operator variant key.		*/
 	    pj_str_t	  amf;	/**< Authentication Management Field	*/
Index: /pjproject/trunk/pjsip/include/pjsip/sip_auth_aka.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_auth_aka.h	(revision 1499)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_auth_aka.h	(revision 1500)
@@ -30,47 +30,168 @@
 
 /**
- * @defgroup PJSIP_AUTH_AKA_API Digest AKA Authentication API's
+ * @defgroup PJSIP_AUTH_AKA_API Digest AKAv1 and AKAv2 Authentication API
  * @ingroup PJSIP_AUTH_API
- * @brief Digest AKA helper API.
+ * @brief Digest AKAv1 and AKAv2 Authentication API
  * @{
  *
- * This module currently exports one function, #pjsip_auth_create_akav1_response(),
- * which can be registered as the callback function in \a ext.aka.cb field
- * of #pjsip_cred_info structure, to calculate the MD5-AKAv1 digest
- * response.
- */
-
-
+ * This module implements HTTP digest authentication using Authentication
+ * and Key Agreement (AKA) version 1 and version 2 (AKAv1-MD5 and AKAv2-MD5),
+ * as specified in RFC 3310 and RFC 4169. SIP AKA authentication is used
+ * by 3GPP and IMS systems.
+ *
+ * @section pjsip_aka_using Using Digest AKA Authentication
+ *
+ * Support for digest AKA authentication is currently made optional, so
+ * application needs to declare \a PJSIP_HAS_DIGEST_AKA_AUTH to non-zero
+ * in <tt>config_site.h</tt> to enable AKA support:
+ *
+ @code
+   #define PJSIP_HAS_DIGEST_AKA_AUTH   1
+ @endcode
+
+ *
+ * In addition, application would need to link with <b>libmilenage</b>
+ * library from \a third_party directory.
+ *
+ * Application then specifies digest AKA credential by initializing the 
+ * authentication credential as follows:
+ *
+ @code
+
+    pjsip_cred_info cred;
+
+    pj_bzero(&cred, sizeof(cred));
+
+    cred.scheme = pj_str("Digest");
+    cred.realm = pj_str("ims-domain.test");
+    cred.username = pj_str("user@ims-domain.test");
+    cred.data_type = PJSIP_CRED_DATA_PLAIN_PASSWD | PJSIP_CRED_DATA_EXT_AKA;
+    cred.data = pj_str("password");
+
+    // AKA extended info
+    cred.ext.aka.k = pj_str("password");
+    cred.ext.aka.cb = &pjsip_auth_create_aka_response
+
+ @endcode
+ *
+ * Description:
+ * - To support AKA, application adds \a PJSIP_CRED_DATA_EXT_AKA flag in the
+ * \a data_type field. This indicates that extended information specific to
+ * AKA authentication is available in the credential, and that response 
+ * digest computation will use the callback function instead of the usual MD5
+ * digest computation.
+ *
+ * - The \a scheme for the credential is "Digest". 
+ *
+ * - The \a realm is the expected realm in the challenge. Application may 
+ * also specify wildcard realm ("*") if it wishes to respond to any realms 
+ * in the challenge.
+ *
+ * - The \a data field is optional. Application may fill this with the password
+ * if it wants to support both MD5 and AKA MD5 in a single credential. The
+ * pjsip_auth_create_aka_response() function will use this field if the
+ * challenge indicates "MD5" as the algorithm instead of "AKAv1-MD5" or
+ * "AKAv2-MD5".
+ *
+ * - The \a ext.aka.k field specifies the permanent subscriber key to be used
+ * for AKA authentication. Application may specify binary password containing
+ * NULL character in this key, since the length of the key is indicated in
+ * the \a slen field of the string.
+ *
+ * - The \a ext.aka.cb field specifies the callback function to calculate the
+ * response digest. Application can specify pjsip_auth_create_aka_response()
+ * in this field to use PJSIP's implementation, but it's free to provide
+ * it's own function.
+ *
+ * - Optionally application may set \a ext.aka.op and \a ext.aka.amf in the
+ * credential to specify AKA Operator variant key and AKA Authentication 
+ * Management Field information.
+ */
+
+/**
+ * Length of Authentication Key (AK) in bytes.
+ */
 #define PJSIP_AKA_AKLEN		6
+
+/**
+ * Length of Authentication Management Field (AMF) in bytes.
+ */
 #define PJSIP_AKA_AMFLEN	2
+
+/**
+ * Length of AUTN in bytes.
+ */
 #define PJSIP_AKA_AUTNLEN	16
+
+/**
+ * Length of Confidentiality Key (CK) in bytes.
+ */
 #define PJSIP_AKA_CKLEN		16
+
+/**
+ * Length of Integrity Key (AK) in bytes.
+ */
 #define PJSIP_AKA_IKLEN		16
+
+/**
+ * Length of permanent/subscriber Key (K) in bytes.
+ */
 #define PJSIP_AKA_KLEN		16
+
+/**
+ * Length of AKA authentication code in bytes.
+ */
+#define PJSIP_AKA_MACLEN	8
+
+/**
+ * Length of operator key in bytes.
+ */
 #define PJSIP_AKA_OPLEN		16
+
+/**
+ * Length of random challenge (RAND) in bytes.
+ */
 #define PJSIP_AKA_RANDLEN	16
+
+/**
+ * Length of response digest in bytes.
+ */
 #define PJSIP_AKA_RESLEN	8
-#define PJSIP_AKA_MACLEN	8
-
-/**
- * This function creates MD5 AKAv1 response for the specified challenge
- * in \a chal, based on the information in the credential \a cred.
+
+/**
+ * Length of sequence number (SQN) in bytes.
+ */
+#define PJSIP_AKA_SQNLEN	6
+
+/**
+ * This function creates MD5, AKAv1-MD5, or AKAv2-MD5 response for
+ * the specified challenge in \a chal, according to the algorithm 
+ * specified in the challenge, and based on the information in the 
+ * credential \a cred.
+ *
  * Application may register this function as \a ext.aka.cb field of
  * #pjsip_cred_info structure to make PJSIP automatically call this
- * function to calculate the response digest.
+ * function to calculate the response digest. To do so, it needs to
+ * add \a PJSIP_CRED_DATA_EXT_AKA flag in the \a data_type field of
+ * the credential, and fills up other AKA specific information in
+ * the credential.
  *
  * @param pool	    Pool to allocate memory.
  * @param chal	    The authentication challenge sent by server in 401
- *		    or 401 response, in either Proxy-Authenticate or
+ *		    or 401 response, as either Proxy-Authenticate or
  *		    WWW-Authenticate header.
- * @param cred	    The credential that has been selected by the framework
- *		    to authenticate against the challenge.
+ * @param cred	    The credential to be used.
  * @param method    The request method.
- * @param auth	    The authentication credential where the digest response
- *		    will be placed to.
+ * @param auth	    The digest credential where the digest response
+ *		    will be placed to. Upon calling this function, the
+ *		    nonce, nc, cnonce, qop, uri, and realm fields of
+ *		    this structure must have been set by caller. Upon
+ *		    return, the \a response field will be initialized
+ *		    by this function.
  *
  * @return	    PJ_SUCCESS if response has been created successfully.
  */
-PJ_DECL(pj_status_t) pjsip_auth_create_akav1(pj_pool_t *pool,
+PJ_DECL(pj_status_t) pjsip_auth_create_aka_response(
+					     pj_pool_t *pool,
 					     const pjsip_digest_challenge*chal,
 					     const pjsip_cred_info *cred,
Index: /pjproject/trunk/pjsip/include/pjsip/sip_config.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_config.h	(revision 1499)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_config.h	(revision 1500)
@@ -617,10 +617,11 @@
 
 /**
- * Specify support for IMS/3GPP digest AKA authentication.
- *
- * Default: 0 (disabled for now)
- */
-#ifndef PJSIP_HAS_DIGEST_AKAV1_AUTH
-#   define PJSIP_HAS_DIGEST_AKAV1_AUTH	    0
+ * Specify support for IMS/3GPP digest AKA authentication version 1 and 2
+ * (AKAv1-MD5 and AKAv2-MD5 respectively).
+ *
+ * Default: 0 (disabled, for now)
+ */
+#ifndef PJSIP_HAS_DIGEST_AKA_AUTH
+#   define PJSIP_HAS_DIGEST_AKA_AUTH	    0
 #endif
 
Index: /pjproject/trunk/pjsip/src/pjsip/sip_auth_aka.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_auth_aka.c	(revision 1499)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_auth_aka.c	(revision 1500)
@@ -21,4 +21,5 @@
 #include <pjlib-util/base64.h>
 #include <pjlib-util/md5.h>
+#include <pjlib-util/hmac_md5.h>
 #include <pj/assert.h>
 #include <pj/log.h>
@@ -26,5 +27,5 @@
 #include <pj/string.h>
 
-#if PJSIP_HAS_DIGEST_AKAV1_AUTH
+#if PJSIP_HAS_DIGEST_AKA_AUTH
 
 #include "../../third_party/milenage/milenage.h"
@@ -33,5 +34,6 @@
  * Create MD5-AKA1 digest response.
  */
-PJ_DEF(pj_status_t) pjsip_auth_create_akav1( pj_pool_t *pool,
+PJ_DEF(pj_status_t) pjsip_auth_create_aka_response( 
+					     pj_pool_t *pool,
 					     const pjsip_digest_challenge*chal,
 					     const pjsip_cred_info *cred,
@@ -40,10 +42,16 @@
 {
     pj_str_t nonce_bin;
-    pj_uint8_t *chal_rand, *chal_autn, *chal_mac;
+    int aka_version;
+    const pj_str_t pjsip_AKAv1_MD5 = { "AKAv1-MD5", 9 };
+    const pj_str_t pjsip_AKAv2_MD5 = { "AKAv2-MD5", 9 };
+    pj_uint8_t *chal_rand, *chal_sqnxoraka, *chal_mac;
+    pj_uint8_t k[PJSIP_AKA_KLEN];
+    pj_uint8_t op[PJSIP_AKA_OPLEN];
+    pj_uint8_t amf[PJSIP_AKA_AMFLEN];
     pj_uint8_t res[PJSIP_AKA_RESLEN];
     pj_uint8_t ck[PJSIP_AKA_CKLEN];
     pj_uint8_t ik[PJSIP_AKA_IKLEN];
     pj_uint8_t ak[PJSIP_AKA_AKLEN];
-    pj_uint8_t sqn[PJSIP_AKA_AUTNLEN];
+    pj_uint8_t sqn[PJSIP_AKA_SQNLEN];
     pj_uint8_t xmac[PJSIP_AKA_MACLEN];
     pjsip_cred_info aka_cred;
@@ -52,5 +60,9 @@
 
     /* Check the algorithm is supported. */
-    if (pj_stricmp2(&chal->algorithm, "md5") == 0) {
+    if (chal->algorithm.slen==0 || pj_stricmp2(&chal->algorithm, "md5") == 0) {
+	/*
+	 * A normal MD5 authentication is requested. Fallbackt to the usual
+	 * MD5 digest creation.
+	 */
 	pjsip_auth_create_digest(&auth->response, &auth->nonce, &auth->nc,
 				 &auth->cnonce, &auth->qop, &auth->uri,
@@ -58,5 +70,17 @@
 	return PJ_SUCCESS;
 
-    } else if (pj_stricmp2(&chal->algorithm, "AKAv1-MD5") != 0) {
+    } else if (pj_stricmp(&chal->algorithm, &pjsip_AKAv1_MD5) == 0) {
+	/*
+	 * AKA version 1 is requested.
+	 */
+	aka_version = 1;
+
+    } else if (pj_stricmp(&chal->algorithm, &pjsip_AKAv2_MD5) == 0) {
+	/*
+	 * AKA version 2 is requested.
+	 */
+	aka_version = 2;
+
+    } else {
 	/* Unsupported algorithm */
 	return PJSIP_EINVALIDALGORITHM;
@@ -71,34 +95,38 @@
 	return PJSIP_EAUTHINNONCE;
 
-    if (nonce_bin.slen < PJSIP_AKA_RANDLEN + PJSIP_AKA_AUTNLEN + PJSIP_AKA_MACLEN)
+    if (nonce_bin.slen < PJSIP_AKA_RANDLEN + PJSIP_AKA_AUTNLEN)
 	return PJSIP_EAUTHINNONCE;
 
     /* Get RAND, AUTN, and MAC */
-    chal_rand = (pj_uint8_t*) (nonce_bin.ptr + 0);
-    chal_autn = (pj_uint8_t*) (nonce_bin.ptr + PJSIP_AKA_RANDLEN);
-    chal_mac =  (pj_uint8_t*) (nonce_bin.ptr + PJSIP_AKA_RANDLEN + PJSIP_AKA_AUTNLEN);
+    chal_rand = (pj_uint8_t*)(nonce_bin.ptr + 0);
+    chal_sqnxoraka = (pj_uint8_t*) (nonce_bin.ptr + PJSIP_AKA_RANDLEN);
+    chal_mac = (pj_uint8_t*) (nonce_bin.ptr + PJSIP_AKA_RANDLEN + 
+			      PJSIP_AKA_SQNLEN + PJSIP_AKA_AMFLEN);
 
-    /* Verify credential */
-    PJ_ASSERT_RETURN(cred->ext.aka.k.slen == PJSIP_AKA_KLEN, PJSIP_EAUTHINAKACRED);
-    PJ_ASSERT_RETURN(cred->ext.aka.op.slen == PJSIP_AKA_OPLEN, PJSIP_EAUTHINAKACRED);
+    /* Copy k. op, and amf */
+    pj_bzero(k, sizeof(k));
+    pj_bzero(op, sizeof(op));
+    pj_bzero(amf, sizeof(amf));
+
+    if (cred->ext.aka.k.slen)
+	pj_memcpy(k, cred->ext.aka.k.ptr, cred->ext.aka.k.slen);
+    if (cred->ext.aka.op.slen)
+	pj_memcpy(op, cred->ext.aka.op.ptr, cred->ext.aka.op.slen);
+    if (cred->ext.aka.amf.slen)
+	pj_memcpy(amf, cred->ext.aka.amf.ptr, cred->ext.aka.amf.slen);
 
     /* Given key K and random challenge RAND, compute response RES,
      * confidentiality key CK, integrity key IK and anonymity key AK.
      */
-    f2345((pj_uint8_t*)cred->ext.aka.k.ptr, 
-	  chal_rand, 
-	  res, ck, ik, ak, 
-          (pj_uint8_t*)cred->ext.aka.op.ptr);
+    f2345(k, chal_rand, res, ck, ik, ak, op);
 
     /* Compute sequence number SQN */
-    for (i=0; i<PJSIP_AKA_AUTNLEN; ++i)
-	sqn[i] = (pj_uint8_t) (chal_autn[i] ^ ak[i]);
-
-    /* Compute XMAC */
-    f1((pj_uint8_t*)cred->ext.aka.k.ptr, chal_rand, sqn,
-       (pj_uint8_t*)cred->ext.aka.amf.ptr, xmac, 
-       (pj_uint8_t*)cred->ext.aka.op.ptr);
+    for (i=0; i<PJSIP_AKA_SQNLEN; ++i)
+	sqn[i] = (pj_uint8_t) (chal_sqnxoraka[i] ^ ak[i]);
 
     /* Verify MAC in the challenge */
+    /* Compute XMAC */
+    f1(k, chal_rand, sqn, amf, xmac, op);
+
     if (pj_memcmp(chal_mac, xmac, PJSIP_AKA_MACLEN) != 0) {
 	return PJSIP_EAUTHINNONCE;
@@ -110,11 +138,50 @@
     pj_memcpy(&aka_cred, cred, sizeof(aka_cred));
     aka_cred.data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
-    aka_cred.data.ptr = (char*)res;
-    aka_cred.data.slen = PJSIP_AKA_RESLEN;
 
     /* Create a response */
-    pjsip_auth_create_digest(&auth->response, &chal->nonce, 
-			     &auth->nc, &auth->cnonce, &auth->qop, &auth->uri,
-			     &chal->realm, &aka_cred, method);
+    if (aka_version == 1) {
+	/*
+	 * For AKAv1, the password is RES
+	 */
+	aka_cred.data.ptr = (char*)res;
+	aka_cred.data.slen = PJSIP_AKA_RESLEN;
+
+	pjsip_auth_create_digest(&auth->response, &chal->nonce, 
+				 &auth->nc, &auth->cnonce, &auth->qop, 
+				 &auth->uri, &chal->realm, &aka_cred, method);
+
+    } else if (aka_version == 2) {
+	/*
+	 * For AKAv2, password is base64 encoded [1] parameters:
+	 *    PRF(RES||IK||CK,"http-digest-akav2-password")
+	 *
+	 * The pseudo-random function (PRF) is HMAC-MD5 in this case.
+	 */
+	pj_hmac_md5_context ctx;
+	pj_uint8_t hmac_digest[16];
+	char hmac_digest64[24];
+	int out_len;
+
+	pj_hmac_md5_init(&ctx, (pj_uint8_t*)"http-digest-akav2-password", 26);
+	pj_hmac_md5_update(&ctx, res, PJSIP_AKA_RESLEN);
+	pj_hmac_md5_update(&ctx, ik, PJSIP_AKA_IKLEN);
+	pj_hmac_md5_update(&ctx, ck, PJSIP_AKA_CKLEN);
+	pj_hmac_md5_final(&ctx, hmac_digest);
+
+	out_len = sizeof(hmac_digest64);
+	status = pj_base64_encode(hmac_digest, 16, hmac_digest64, &out_len);
+	PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+
+	aka_cred.data.ptr = hmac_digest64;
+	aka_cred.data.slen = out_len;
+
+	pjsip_auth_create_digest(&auth->response, &chal->nonce, 
+				 &auth->nc, &auth->cnonce, &auth->qop, 
+				 &auth->uri, &chal->realm, &aka_cred, method);
+
+    } else {
+	pj_assert(!"Bug!");
+	return PJ_EBUG;
+    }
 
     /* Done */
@@ -123,4 +190,4 @@
 
 
-#endif	/* PJSIP_HAS_DIGEST_AKAV1_AUTH */
+#endif	/* PJSIP_HAS_DIGEST_AKA_AUTH */
 
Index: /pjproject/trunk/pjsip/src/pjsip/sip_auth_client.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_auth_client.c	(revision 1499)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_auth_client.c	(revision 1500)
@@ -49,4 +49,16 @@
 
 
+static void dup_bin(pj_pool_t *pool, pj_str_t *dst, const pj_str_t *src)
+{
+    dst->slen = src->slen;
+
+    if (dst->slen) {
+	dst->ptr = (char*) pj_pool_alloc(pool, src->slen);
+	pj_memcpy(dst->ptr, src->ptr, src->slen);
+    } else {
+	dst->ptr = NULL;
+    }
+}
+
 PJ_DEF(void) pjsip_cred_info_dup(pj_pool_t *pool,
 				 pjsip_cred_info *dst,
@@ -61,7 +73,7 @@
 
     if ((dst->data_type & EXT_MASK) == PJSIP_CRED_DATA_EXT_AKA) {
-	pj_strdup(pool, &dst->ext.aka.k, &src->ext.aka.k);
-	pj_strdup(pool, &dst->ext.aka.op, &src->ext.aka.op);
-	pj_strdup(pool, &dst->ext.aka.amf, &src->ext.aka.amf);
+	dup_bin(pool, &dst->ext.aka.k, &src->ext.aka.k);
+	dup_bin(pool, &dst->ext.aka.op, &src->ext.aka.op);
+	dup_bin(pool, &dst->ext.aka.amf, &src->ext.aka.amf);
     }
 }
@@ -223,7 +235,14 @@
 				   const pj_str_t *method)
 {
-    /* Check algorithm is supported. We only support MD5. */
-    if (chal->algorithm.slen && pj_stricmp(&chal->algorithm, &pjsip_MD5_STR))
+    const pj_str_t pjsip_AKAv1_MD5_STR = { "AKAv1-MD5", 9 };
+
+    /* Check algorithm is supported. We support MD5 and AKAv1-MD5. */
+    if (chal->algorithm.slen==0 ||
+	(pj_stricmp(&chal->algorithm, &pjsip_MD5_STR) ||
+	 pj_stricmp(&chal->algorithm, &pjsip_AKAv1_MD5_STR)))
     {
+	;
+    }
+    else {
 	PJ_LOG(4,(THIS_FILE, "Unsupported digest algorithm \"%.*s\"",
 		  chal->algorithm.slen, chal->algorithm.ptr));
@@ -236,7 +255,7 @@
     pj_strdup(pool, &cred->nonce, &chal->nonce);
     pj_strdup(pool, &cred->uri, uri);
-    cred->algorithm = pjsip_MD5_STR;
+    pj_strdup(pool, &cred->algorithm, &chal->algorithm);
     pj_strdup(pool, &cred->opaque, &chal->opaque);
-    
+
     /* Allocate memory. */
     cred->response.ptr = (char*) pj_pool_alloc(pool, PJSIP_MD5STRLEN);
@@ -471,6 +490,6 @@
 	    if ((c[i].data_type & EXT_MASK) == PJSIP_CRED_DATA_EXT_AKA) {
 
-#if !PJSIP_HAS_DIGEST_AKAV1_AUTH
-		pj_assert(!"PJSIP_HAS_DIGEST_AKAV1_AUTH is not enabled");
+#if !PJSIP_HAS_DIGEST_AKA_AUTH
+		pj_assert(!"PJSIP_HAS_DIGEST_AKA_AUTH is not enabled");
 		return PJSIP_EAUTHINAKACRED;
 #endif
@@ -480,13 +499,13 @@
 
 		/* Verify K len */
-		PJ_ASSERT_RETURN(c[i].ext.aka.k.slen == PJSIP_AKA_KLEN, 
+		PJ_ASSERT_RETURN(c[i].ext.aka.k.slen <= PJSIP_AKA_KLEN, 
 				 PJSIP_EAUTHINAKACRED);
 
 		/* Verify OP len */
-		PJ_ASSERT_RETURN(c[i].ext.aka.op.slen == PJSIP_AKA_OPLEN, 
+		PJ_ASSERT_RETURN(c[i].ext.aka.op.slen <= PJSIP_AKA_OPLEN, 
 				 PJSIP_EAUTHINAKACRED);
 
 		/* Verify AMF len */
-		PJ_ASSERT_RETURN(c[i].ext.aka.amf.slen == PJSIP_AKA_AMFLEN,
+		PJ_ASSERT_RETURN(c[i].ext.aka.amf.slen <= PJSIP_AKA_AMFLEN,
 				 PJSIP_EAUTHINAKACRED);
 
@@ -793,5 +812,16 @@
 			   &sent_auth->credential.common.realm )==0)
 	    {
-		break;
+		/* If this authorization has empty response, remove it. */
+		if (pj_stricmp(&sent_auth->scheme, &pjsip_DIGEST_STR)==0 &&
+		    sent_auth->credential.digest.response.slen == 0)
+		{
+		    /* This is empty authorization, remove it. */
+		    hdr = hdr->next;
+		    pj_list_erase(sent_auth);
+		    continue;
+		} else {
+		    /* Found previous authorization attempt */
+		    break;
+		}
 	    }
 	}
Index: /pjproject/trunk/pjsip/src/pjsip/sip_auth_msg.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_auth_msg.c	(revision 1499)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_auth_msg.c	(revision 1500)
@@ -72,7 +72,7 @@
     copy_advance_pair_quote_cond(buf, "username=", 9, cred->username, '"', '"');
     copy_advance_pair_quote_cond(buf, ", realm=", 8, cred->realm, '"', '"');
-    copy_advance_pair_quote_cond(buf, ", nonce=", 8, cred->nonce, '"', '"');
+    copy_advance_pair_quote(buf, ", nonce=", 8, cred->nonce, '"', '"');
     copy_advance_pair_quote_cond(buf, ", uri=", 6, cred->uri, '"', '"');
-    copy_advance_pair_quote_cond(buf, ", response=", 11, cred->response, '"', '"');
+    copy_advance_pair_quote(buf, ", response=", 11, cred->response, '"', '"');
     copy_advance_pair(buf, ", algorithm=", 12, cred->algorithm);
     copy_advance_pair_quote_cond(buf, ", cnonce=", 9, cred->cnonce, '"', '"');
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c	(revision 1499)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_acc.c	(revision 1500)
@@ -737,4 +737,25 @@
 	status = pjsip_regc_register(pjsua_var.acc[acc_id].regc, 1, 
 				     &tdata);
+
+	if (0 && status == PJ_SUCCESS && pjsua_var.acc[acc_id].cred_cnt) {
+	    pjsua_acc *acc = &pjsua_var.acc[acc_id];
+	    pjsip_authorization_hdr *h;
+	    char *uri;
+	    int d;
+
+	    uri = (char*) pj_pool_alloc(tdata->pool, acc->cfg.reg_uri.slen+10);
+	    d = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, tdata->msg->line.req.uri,
+				uri, acc->cfg.reg_uri.slen+10);
+	    pj_assert(d > 0);
+
+	    h = pjsip_authorization_hdr_create(tdata->pool);
+	    h->scheme = pj_str("Digest");
+	    h->credential.digest.username = acc->cred[0].username;
+	    h->credential.digest.realm = acc->srv_domain;
+	    h->credential.digest.uri = pj_str(uri);
+	    h->credential.digest.algorithm = pj_str("md5");
+
+	    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)h);
+	}
 
     } else {
