summaryrefslogtreecommitdiff
path: root/pjsip/src
diff options
context:
space:
mode:
authorBenny Prijono <bennylp@teluu.com>2007-10-15 07:04:59 +0000
committerBenny Prijono <bennylp@teluu.com>2007-10-15 07:04:59 +0000
commit4b289329774686a3e261fac70fbd902942cb9b1f (patch)
tree2afebdecbce79f65ab386003be09649736665f7a /pjsip/src
parentcee3cd46bbeec0bb7e76a5480e7cad9ee2f8cda5 (diff)
Continuing ticket #396: tested digest AKAv1, implemented AKAv2, and some works in the authentication framework to support it
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1500 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjsip/src')
-rw-r--r--pjsip/src/pjsip/sip_auth_aka.c127
-rw-r--r--pjsip/src/pjsip/sip_auth_client.c56
-rw-r--r--pjsip/src/pjsip/sip_auth_msg.c4
-rw-r--r--pjsip/src/pjsua-lib/pjsua_acc.c21
4 files changed, 163 insertions, 45 deletions
diff --git a/pjsip/src/pjsip/sip_auth_aka.c b/pjsip/src/pjsip/sip_auth_aka.c
index 284b8c0f..75d649ba 100644
--- a/pjsip/src/pjsip/sip_auth_aka.c
+++ b/pjsip/src/pjsip/sip_auth_aka.c
@@ -20,44 +20,68 @@
#include <pjsip/sip_errno.h>
#include <pjlib-util/base64.h>
#include <pjlib-util/md5.h>
+#include <pjlib-util/hmac_md5.h>
#include <pj/assert.h>
#include <pj/log.h>
#include <pj/pool.h>
#include <pj/string.h>
-#if PJSIP_HAS_DIGEST_AKAV1_AUTH
+#if PJSIP_HAS_DIGEST_AKA_AUTH
#include "../../third_party/milenage/milenage.h"
/*
* 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,
const pj_str_t *method,
pjsip_digest_credential *auth)
{
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;
int i, len;
pj_status_t status;
/* 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,
&auth->realm, cred, method);
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;
}
@@ -70,36 +94,40 @@ PJ_DEF(pj_status_t) pjsip_auth_create_akav1( pj_pool_t *pool,
if (status != PJ_SUCCESS)
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);
-
- /* 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);
+ 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);
+
+ /* 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]);
+ 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((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);
+ f1(k, chal_rand, sqn, amf, xmac, op);
- /* Verify MAC in the challenge */
if (pj_memcmp(chal_mac, xmac, PJSIP_AKA_MACLEN) != 0) {
return PJSIP_EAUTHINNONCE;
}
@@ -109,18 +137,57 @@ PJ_DEF(pj_status_t) pjsip_auth_create_akav1( pj_pool_t *pool,
*/
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 */
return PJ_SUCCESS;
}
-#endif /* PJSIP_HAS_DIGEST_AKAV1_AUTH */
+#endif /* PJSIP_HAS_DIGEST_AKA_AUTH */
diff --git a/pjsip/src/pjsip/sip_auth_client.c b/pjsip/src/pjsip/sip_auth_client.c
index 0a3049e2..2001270e 100644
--- a/pjsip/src/pjsip/sip_auth_client.c
+++ b/pjsip/src/pjsip/sip_auth_client.c
@@ -48,6 +48,18 @@
#define EXT_MASK 0x00F0
+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,
const pjsip_cred_info *src)
@@ -60,9 +72,9 @@ PJ_DEF(void) pjsip_cred_info_dup(pj_pool_t *pool,
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);
+ 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);
}
}
@@ -222,9 +234,16 @@ static pj_status_t respond_digest( pj_pool_t *pool,
pj_uint32_t nc,
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));
return PJSIP_EINVALIDALGORITHM;
@@ -235,9 +254,9 @@ static pj_status_t respond_digest( pj_pool_t *pool,
pj_strdup(pool, &cred->realm, &chal->realm);
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);
cred->response.slen = PJSIP_MD5STRLEN;
@@ -470,8 +489,8 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_set_credentials( pjsip_auth_clt_sess *sess,
*/
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
@@ -479,15 +498,15 @@ PJ_DEF(pj_status_t) pjsip_auth_clt_set_credentials( pjsip_auth_clt_sess *sess,
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,
+ 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);
sess->cred_info[i].ext.aka.cb = c[i].ext.aka.cb;
@@ -792,7 +811,18 @@ static pj_status_t process_auth( pj_pool_t *req_pool,
if (pj_stricmp(&hchal->challenge.common.realm,
&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;
+ }
}
}
hdr = hdr->next;
diff --git a/pjsip/src/pjsip/sip_auth_msg.c b/pjsip/src/pjsip/sip_auth_msg.c
index 5cb78527..39ddddde 100644
--- a/pjsip/src/pjsip/sip_auth_msg.c
+++ b/pjsip/src/pjsip/sip_auth_msg.c
@@ -71,9 +71,9 @@ static int print_digest_credential(pjsip_digest_credential *cred, char *buf, pj_
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, '"', '"');
copy_advance_pair_quote_cond(buf, ", opaque=", 9, cred->opaque, '"', '"');
diff --git a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c
index 07cba74f..482d6bbe 100644
--- a/pjsip/src/pjsua-lib/pjsua_acc.c
+++ b/pjsip/src/pjsua-lib/pjsua_acc.c
@@ -737,6 +737,27 @@ PJ_DEF(pj_status_t) pjsua_acc_set_registration( pjsua_acc_id acc_id,
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 {
if (pjsua_var.acc[acc_id].regc == NULL) {
PJ_LOG(3,(THIS_FILE, "Currently not registered"));