diff options
author | Benny Prijono <bennylp@teluu.com> | 2007-10-10 11:37:56 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2007-10-10 11:37:56 +0000 |
commit | a3354959d1493f86392296ab0e78512e633abf40 (patch) | |
tree | 8e73a0994d92c5b97d77cf43165f2bc84d5313a3 /pjsip | |
parent | 0cb2d5b9e84601bb822a300c48a4ea8397d85850 (diff) |
Ticket #396: initial implementation of digest AKA (akav1-md5) authentication for IMS/3GPP
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1488 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip')
-rw-r--r-- | pjsip/build/pjsip_core.dsp | 8 | ||||
-rw-r--r-- | pjsip/include/pjsip.h | 1 | ||||
-rw-r--r-- | pjsip/include/pjsip/sip_auth.h | 103 | ||||
-rw-r--r-- | pjsip/include/pjsip/sip_auth_aka.h | 91 | ||||
-rw-r--r-- | pjsip/include/pjsip/sip_errno.h | 10 | ||||
-rw-r--r-- | pjsip/include/pjsua-lib/pjsua.h | 16 | ||||
-rw-r--r-- | pjsip/src/pjsip/sip_auth_aka.c | 121 | ||||
-rw-r--r-- | pjsip/src/pjsip/sip_auth_client.c | 103 | ||||
-rw-r--r-- | pjsip/src/pjsip/sip_errno.c | 2 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_core.c | 10 |
10 files changed, 409 insertions, 56 deletions
diff --git a/pjsip/build/pjsip_core.dsp b/pjsip/build/pjsip_core.dsp index 2cd4fc06..245985a2 100644 --- a/pjsip/build/pjsip_core.dsp +++ b/pjsip/build/pjsip_core.dsp @@ -164,6 +164,10 @@ SOURCE=..\src\pjsip\sip_transport_udp.c # PROP Default_Filter ""
# Begin Source File
+SOURCE=..\src\pjsip\sip_auth_aka.c
+# End Source File
+# Begin Source File
+
SOURCE=..\src\pjsip\sip_auth_client.c
# End Source File
# Begin Source File
@@ -308,6 +312,10 @@ SOURCE=..\include\pjsip\sip_auth.h # End Source File
# Begin Source File
+SOURCE=..\include\pjsip\sip_auth_aka.h
+# End Source File
+# Begin Source File
+
SOURCE=..\include\pjsip\sip_auth_msg.h
# End Source File
# Begin Source File
diff --git a/pjsip/include/pjsip.h b/pjsip/include/pjsip.h index 867bb1e5..3e9b4137 100644 --- a/pjsip/include/pjsip.h +++ b/pjsip/include/pjsip.h @@ -45,6 +45,7 @@ /* Authentication. */ #include <pjsip/sip_auth.h> +#include <pjsip/sip_auth_aka.h> /* Transaction layer. */ #include <pjsip/sip_transaction.h> diff --git a/pjsip/include/pjsip/sip_auth.h b/pjsip/include/pjsip/sip_auth.h index 1ae6c1f6..521adfaa 100644 --- a/pjsip/include/pjsip/sip_auth.h +++ b/pjsip/include/pjsip/sip_auth.h @@ -46,11 +46,14 @@ PJ_BEGIN_DECL #define PJSIP_MD5STRLEN 32 -/** Type of data in the credential information. */ +/** Type of data in the credential information in #pjsip_cred_info. */ typedef enum pjsip_cred_data_type { - PJSIP_CRED_DATA_PLAIN_PASSWD, /**< Plain text password. */ - PJSIP_CRED_DATA_DIGEST /**< Hashed digest. */ + PJSIP_CRED_DATA_PLAIN_PASSWD=0, /**< Plain text password. */ + PJSIP_CRED_DATA_DIGEST =1, /**< Hashed digest. */ + + PJSIP_CRED_DATA_EXT_AKA =16 /**< Extended AKA info is available */ + } pjsip_cred_data_type; /** Authentication's quality of protection (qop) type. */ @@ -63,13 +66,43 @@ typedef enum pjsip_auth_qop_type } pjsip_auth_qop_type; +/** + * Type of callback function to create authentication response. + * Application can specify this callback in \a cb field of the credential info + * (#pjsip_cred_info) and specifying PJSIP_CRED_DATA_DIGEST_CALLBACK as + * \a data_type. When this function is called, most of the fields in the + * \a auth authentication response will have been filled by the framework. + * Application normally should just need to calculate the response digest + * of the authentication response. + * + * @param pool Pool to allocate memory from if application needs to. + * @param chal The authentication challenge sent by server in 401 + * or 401 response, in either Proxy-Authenticate or + * WWW-Authenticate header. + * @param cred The credential that has been selected by the framework + * to authenticate against the challenge. + * @param auth The authentication response which application needs to + * calculate the response digest. + * + * @return Application may return non-PJ_SUCCESS to abort the + * authentication process. When this happens, the + * framework will return failure to the original function + * that requested authentication. + */ +typedef pj_status_t (*pjsip_cred_cb)(pj_pool_t *pool, + const pjsip_digest_challenge *chal, + const pjsip_cred_info *cred, + const pj_str_t *method, + pjsip_digest_credential *auth); + + /** * This structure describes credential information. * A credential information is a static, persistent information that identifies * username and password required to authorize to a specific realm. * * Note that since PJSIP 0.7.0.1, it is possible to make a credential that is - * valid for any realms, by setting the realm to star/asterisk character, + * valid for any realms, by setting the realm to star/wildcard character, * i.e. realm = pj_str("*");. */ struct pjsip_cred_info @@ -82,6 +115,21 @@ struct pjsip_cred_info int data_type; /**< Type of data (0 for plaintext passwd). */ pj_str_t data; /**< The data, which can be a plaintext password or a hashed digest. */ + + /** Extended data */ + union { + /** Digest AKA credential information. Note that when AKA credential + * 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. + */ + struct { + pj_str_t k; /**< Permanent key. */ + pj_str_t op; /**< Operator variant key. */ + pj_str_t amf; /**< Authentication Management Field */ + pjsip_cred_cb cb; /**< Callback to create AKA digest. */ + } aka; + + } ext; }; /** @@ -150,6 +198,17 @@ typedef struct pjsip_auth_clt_sess /** + * Duplicate a credential info. + * + * @param pool The memory pool. + * @param dst Destination credential. + * @param src Source credential. + */ +PJ_DECL(void) pjsip_cred_info_dup(pj_pool_t *pool, + pjsip_cred_info *dst, + const pjsip_cred_info *src); + +/** * Type of function to lookup credential for the specified name. * * @param pool Pool to initialize the credential info. @@ -349,22 +408,36 @@ PJ_DECL(pj_status_t) pjsip_auth_srv_challenge( pjsip_auth_srv *auth_srv, pj_bool_t stale, pjsip_tx_data *tdata); +/** + * Helper function to create MD5 digest out of the specified + * parameters. + * + * @param result String to store the response digest. This string + * must have been preallocated by caller with the + * buffer at least PJSIP_MD5STRLEN (32 bytes) in size. + * @param nonce Optional nonce. + * @param nc Nonce count. + * @param cnonce Optional cnonce. + * @param qop Optional qop. + * @param uri URI. + * @param realm Realm. + * @param cred_info Credential info. + * @param method SIP method. + */ +PJ_DECL(void) pjsip_auth_create_digest(pj_str_t *result, + const pj_str_t *nonce, + const pj_str_t *nc, + const pj_str_t *cnonce, + const pj_str_t *qop, + const pj_str_t *uri, + const pj_str_t *realm, + const pjsip_cred_info *cred_info, + const pj_str_t *method); /** * @} */ -/* Internal function defined in sip_auth_client.c */ -void pjsip_auth_create_digest( pj_str_t *result, - const pj_str_t *nonce, - const pj_str_t *nc, - const pj_str_t *cnonce, - const pj_str_t *qop, - const pj_str_t *uri, - const pj_str_t *realm, - const pjsip_cred_info *cred_info, - const pj_str_t *method); - PJ_END_DECL diff --git a/pjsip/include/pjsip/sip_auth_aka.h b/pjsip/include/pjsip/sip_auth_aka.h new file mode 100644 index 00000000..c5c2a60d --- /dev/null +++ b/pjsip/include/pjsip/sip_auth_aka.h @@ -0,0 +1,91 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __PJSIP_AUTH_SIP_AUTH_AKA_H__ +#define __PJSIP_AUTH_SIP_AUTH_AKA_H__ + +/** + * @file sip_auth_aka.h + * @brief SIP Digest AKA Authorization Module. + */ + +#include <pjsip/sip_auth.h> + +PJ_BEGIN_DECL + +/** + * @defgroup PJSIP_AUTH_AKA_API Digest AKA Authentication API's + * @ingroup PJSIP_AUTH_API + * @brief Digest AKA helper 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. + */ + + +#define PJSIP_AKA_AKLEN 6 +#define PJSIP_AKA_AMFLEN 2 +#define PJSIP_AKA_AUTNLEN 16 +#define PJSIP_AKA_CKLEN 16 +#define PJSIP_AKA_IKLEN 16 +#define PJSIP_AKA_KLEN 16 +#define PJSIP_AKA_OPLEN 16 +#define PJSIP_AKA_RANDLEN 16 +#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. + * 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. + * + * @param pool Pool to allocate memory. + * @param chal The authentication challenge sent by server in 401 + * or 401 response, in either Proxy-Authenticate or + * WWW-Authenticate header. + * @param cred The credential that has been selected by the framework + * to authenticate against the challenge. + * @param method The request method. + * @param auth The authentication credential where the digest response + * will be placed to. + * + * @return PJ_SUCCESS if response has been created successfully. + */ +PJ_DECL(pj_status_t) pjsip_auth_create_akav1(pj_pool_t *pool, + const pjsip_digest_challenge*chal, + const pjsip_cred_info *cred, + const pj_str_t *method, + pjsip_digest_credential *auth); + + +/** + * @} + */ + + + +PJ_END_DECL + + +#endif /* __PJSIP_AUTH_SIP_AUTH_AKA_H__ */ + diff --git a/pjsip/include/pjsip/sip_errno.h b/pjsip/include/pjsip/sip_errno.h index 0e5ae2f1..0b793a9c 100644 --- a/pjsip/include/pjsip/sip_errno.h +++ b/pjsip/include/pjsip/sip_errno.h @@ -381,6 +381,16 @@ PJ_BEGIN_DECL * keeps rejecting our authorization request with stale=true. */ #define PJSIP_EAUTHSTALECOUNT (PJSIP_ERRNO_START_PJSIP + 111) /* 171111 */ +/** + * @hideinitializer + * Invalid nonce value in the challenge. + */ +#define PJSIP_EAUTHINNONCE (PJSIP_ERRNO_START_PJSIP + 112) /* 171112 */ +/** + * @hideinitializer + * Invalid AKA credential. + */ +#define PJSIP_EAUTHINAKACRED (PJSIP_ERRNO_START_PJSIP + 113) /* 171113 */ /************************************************************ diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index fad79178..91856d2c 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -1029,20 +1029,8 @@ typedef struct pjsua_config PJ_DECL(void) pjsua_config_default(pjsua_config *cfg); -/** - * Duplicate credential. - * - * @param pool The memory pool. - * @param dst Destination credential. - * @param src Source credential. - * - * \par Python: - * Not applicable (for now). Probably we could just assign one credential - * variable to another, but this has not been tested. - */ -PJ_DECL(void) pjsip_cred_dup( pj_pool_t *pool, - pjsip_cred_info *dst, - const pjsip_cred_info *src); +/* The implementation has been moved to sip_auth.h */ +#define pjsip_cred_dup pjsip_cred_info_dup /** diff --git a/pjsip/src/pjsip/sip_auth_aka.c b/pjsip/src/pjsip/sip_auth_aka.c new file mode 100644 index 00000000..b88ddb7c --- /dev/null +++ b/pjsip/src/pjsip/sip_auth_aka.c @@ -0,0 +1,121 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <pjsip/sip_auth_aka.h> +#include <pjsip/sip_errno.h> +#include <pjlib-util/base64.h> +#include <pjlib-util/md5.h> +#include <pj/assert.h> +#include <pj/log.h> +#include <pj/pool.h> +#include <pj/string.h> + +#include "../../third_party/milenage/milenage.h" + +/* + * Create MD5-AKA1 digest response. + */ +PJ_DEF(pj_status_t) pjsip_auth_create_akav1( pj_pool_t *pool, + const pjsip_digest_challenge*chal, + const pjsip_cred_info *cred, + const pj_str_t *method, + pjsip_digest_credential *auth) +{ + pj_str_t nonce_bin; + pj_uint8_t *chal_rand, *chal_autn, *chal_mac; + 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 xmac[PJSIP_AKA_MACLEN]; + pjsip_cred_info aka_cred; + int i; + pj_status_t status; + + /* Check the algorithm is supported. */ + if (pj_stricmp2(&chal->algorithm, "md5") == 0) { + pjsip_auth_create_digest(&auth->response, &auth->nonce, &auth->nc, + &auth->cnonce, &auth->qop, &auth->uri, + &auth->realm, cred, method); + return PJ_SUCCESS; + + } else if (pj_stricmp2(&chal->algorithm, "AKAv1-MD5") != 0) { + /* Unsupported algorithm */ + return PJSIP_EINVALIDALGORITHM; + } + + /* Decode nonce */ + nonce_bin.slen = PJ_BASE64_TO_BASE256_LEN(chal->nonce.slen); + nonce_bin.ptr = pj_pool_alloc(pool, nonce_bin.slen + 1); + status = pj_base64_decode(&chal->nonce, (pj_uint8_t*)nonce_bin.ptr, + &nonce_bin.slen); + if (status != PJ_SUCCESS) + return PJSIP_EAUTHINNONCE; + + if (nonce_bin.slen < PJSIP_AKA_RANDLEN + PJSIP_AKA_AUTNLEN + PJSIP_AKA_MACLEN) + 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); + + /* 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); + + /* 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); + + /* 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); + + /* Verify MAC in the challenge */ + if (pj_memcmp(chal_mac, xmac, PJSIP_AKA_MACLEN) != 0) { + return PJSIP_EAUTHINNONCE; + } + + /* Build a temporary credential info to create MD5 digest, using + * "res" as the password. + */ + 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); + + /* Done */ + return PJ_SUCCESS; +} + diff --git a/pjsip/src/pjsip/sip_auth_client.c b/pjsip/src/pjsip/sip_auth_client.c index 7978da27..88cd3e94 100644 --- a/pjsip/src/pjsip/sip_auth_client.c +++ b/pjsip/src/pjsip/sip_auth_client.c @@ -19,6 +19,7 @@ #include <pjsip/sip_auth.h> #include <pjsip/sip_auth_parser.h> /* just to get pjsip_DIGEST_STR */ +#include <pjsip/sip_auth_aka.h> #include <pjsip/sip_transport.h> #include <pjsip/sip_endpoint.h> #include <pjsip/sip_errno.h> @@ -43,6 +44,28 @@ # define AUTH_TRACE_(expr) #endif +#define PASSWD_MASK 0x000F +#define EXT_MASK 0x00F0 + + +PJ_DEF(void) pjsip_cred_info_dup(pj_pool_t *pool, + pjsip_cred_info *dst, + const pjsip_cred_info *src) +{ + pj_memcpy(dst, src, sizeof(pjsip_cred_info)); + + pj_strdup_with_null(pool, &dst->realm, &src->realm); + pj_strdup_with_null(pool, &dst->scheme, &src->scheme); + pj_strdup_with_null(pool, &dst->username, &src->username); + pj_strdup_with_null(pool, &dst->data, &src->data); + + 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); + } +} + /* Transform digest to string. * output must be at least PJSIP_MD5STRLEN+1 bytes. @@ -63,15 +86,15 @@ static void digest2str(const unsigned char digest[], char *output) * Create response digest based on the parameters and store the * digest ASCII in 'result'. */ -void pjsip_auth_create_digest( pj_str_t *result, - const pj_str_t *nonce, - const pj_str_t *nc, - const pj_str_t *cnonce, - const pj_str_t *qop, - const pj_str_t *uri, - const pj_str_t *realm, - const pjsip_cred_info *cred_info, - const pj_str_t *method) +PJ_DEF(void) pjsip_auth_create_digest( pj_str_t *result, + const pj_str_t *nonce, + const pj_str_t *nc, + const pj_str_t *cnonce, + const pj_str_t *qop, + const pj_str_t *uri, + const pj_str_t *realm, + const pjsip_cred_info *cred_info, + const pj_str_t *method) { char ha1[PJSIP_MD5STRLEN]; char ha2[PJSIP_MD5STRLEN]; @@ -82,7 +105,7 @@ void pjsip_auth_create_digest( pj_str_t *result, AUTH_TRACE_((THIS_FILE, "Begin creating digest")); - if (cred_info->data_type == PJSIP_CRED_DATA_PLAIN_PASSWD) { + if ((cred_info->data_type & PASSWD_MASK) == PJSIP_CRED_DATA_PLAIN_PASSWD) { /*** *** ha1 = MD5(username ":" realm ":" password) ***/ @@ -96,9 +119,11 @@ void pjsip_auth_create_digest( pj_str_t *result, digest2str(digest, ha1); - } else if (cred_info->data_type == PJSIP_CRED_DATA_DIGEST) { + } else if ((cred_info->data_type & PASSWD_MASK) == PJSIP_CRED_DATA_DIGEST) { pj_assert(cred_info->data.slen == 32); pj_memcpy( ha1, cred_info->data.ptr, cred_info->data.slen ); + } else { + pj_assert(!"Invalid data_type"); } AUTH_TRACE_((THIS_FILE, " ha1=%.32s", ha1)); @@ -220,9 +245,17 @@ static pj_status_t respond_digest( pj_pool_t *pool, if (chal->qop.slen == 0) { /* Server doesn't require quality of protection. */ - /* Convert digest to string and store in chal->response. */ - pjsip_auth_create_digest( &cred->response, &cred->nonce, NULL, NULL, - NULL, uri, &chal->realm, cred_info, method); + if ((cred_info->data_type & EXT_MASK) == PJSIP_CRED_DATA_EXT_AKA) { + /* Call application callback to create the response digest */ + return (*cred_info->ext.aka.cb)(pool, chal, cred_info, + method, cred); + } + else { + /* Convert digest to string and store in chal->response. */ + pjsip_auth_create_digest( &cred->response, &cred->nonce, NULL, + NULL, NULL, uri, &chal->realm, + cred_info, method); + } } else if (has_auth_qop(pool, &chal->qop)) { /* Server requires quality of protection. @@ -239,9 +272,16 @@ static pj_status_t respond_digest( pj_pool_t *pool, pj_strdup(pool, &cred->cnonce, &dummy_cnonce); } - pjsip_auth_create_digest( &cred->response, &cred->nonce, &cred->nc, - cnonce, &pjsip_AUTH_STR, uri, &chal->realm, - cred_info, method ); + if ((cred_info->data_type & EXT_MASK) == PJSIP_CRED_DATA_EXT_AKA) { + /* Call application callback to create the response digest */ + return (*cred_info->ext.aka.cb)(pool, chal, cred_info, + method, cred); + } + else { + pjsip_auth_create_digest( &cred->response, &cred->nonce, + &cred->nc, cnonce, &pjsip_AUTH_STR, + uri, &chal->realm, cred_info, method ); + } } else { /* Server requires quality protection that we don't support. */ @@ -424,6 +464,35 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_set_credentials( pjsip_auth_clt_sess *sess, pj_pool_alloc(sess->pool, cred_cnt * sizeof(*c)); for (i=0; i<cred_cnt; ++i) { sess->cred_info[i].data_type = c[i].data_type; + + /* When data_type is PJSIP_CRED_DATA_EXT_AKA, + * callback must be specified. + */ + if ((c[i].data_type & EXT_MASK) == PJSIP_CRED_DATA_EXT_AKA) { + /* Callback must be specified */ + PJ_ASSERT_RETURN(c[i].ext.aka.cb != NULL, PJ_EINVAL); + + /* Verify K len */ + 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, + PJSIP_EAUTHINAKACRED); + + /* Verify AMF len */ + PJ_ASSERT_RETURN(c[i].ext.aka.amf.slen == PJSIP_AKA_AMFLEN, + PJSIP_EAUTHINAKACRED); + + sess->cred_info[i].ext.aka.cb = c[i].ext.aka.cb; + pj_strdup(sess->pool, &sess->cred_info[i].ext.aka.k, + &c[i].ext.aka.k); + pj_strdup(sess->pool, &sess->cred_info[i].ext.aka.op, + &c[i].ext.aka.op); + pj_strdup(sess->pool, &sess->cred_info[i].ext.aka.amf, + &c[i].ext.aka.amf); + } + pj_strdup(sess->pool, &sess->cred_info[i].scheme, &c[i].scheme); pj_strdup(sess->pool, &sess->cred_info[i].realm, &c[i].realm); pj_strdup(sess->pool, &sess->cred_info[i].username, &c[i].username); diff --git a/pjsip/src/pjsip/sip_errno.c b/pjsip/src/pjsip/sip_errno.c index dd2724e9..2a6e9306 100644 --- a/pjsip/src/pjsip/sip_errno.c +++ b/pjsip/src/pjsip/sip_errno.c @@ -102,6 +102,8 @@ static const struct PJ_BUILD_ERR( PJSIP_EAUTHINVALIDREALM, "Invalid authorization realm"), PJ_BUILD_ERR( PJSIP_EAUTHINVALIDDIGEST,"Invalid authorization digest" ), PJ_BUILD_ERR( PJSIP_EAUTHSTALECOUNT, "Maximum number of stale retries exceeded"), + PJ_BUILD_ERR( PJSIP_EAUTHINNONCE, "Invalid nonce value in authentication challenge"), + PJ_BUILD_ERR( PJSIP_EAUTHINAKACRED, "Invalid AKA credential"), /* UA/dialog layer. */ PJ_BUILD_ERR( PJSIP_EMISSINGTAG, "Missing From/To tag parameter" ), diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c index 80617605..29cee191 100644 --- a/pjsip/src/pjsua-lib/pjsua_core.c +++ b/pjsip/src/pjsua-lib/pjsua_core.c @@ -81,16 +81,6 @@ PJ_DEF(void) pjsua_config_default(pjsua_config *cfg) cfg->thread_cnt = 1; } -PJ_DEF(void) pjsip_cred_dup( pj_pool_t *pool, - pjsip_cred_info *dst, - const pjsip_cred_info *src) -{ - pj_strdup_with_null(pool, &dst->realm, &src->realm); - pj_strdup_with_null(pool, &dst->scheme, &src->scheme); - pj_strdup_with_null(pool, &dst->username, &src->username); - pj_strdup_with_null(pool, &dst->data, &src->data); -} - PJ_DEF(void) pjsua_config_dup(pj_pool_t *pool, pjsua_config *dst, const pjsua_config *src) |