Ignore:
Timestamp:
Oct 15, 2007 7:04:59 AM (15 years ago)
Author:
bennylp
Message:

Continuing ticket #396: tested digest AKAv1, implemented AKAv2, and some works in the authentication framework to support it

File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/src/pjsip/sip_auth_aka.c

    r1492 r1500  
    2121#include <pjlib-util/base64.h> 
    2222#include <pjlib-util/md5.h> 
     23#include <pjlib-util/hmac_md5.h> 
    2324#include <pj/assert.h> 
    2425#include <pj/log.h> 
     
    2627#include <pj/string.h> 
    2728 
    28 #if PJSIP_HAS_DIGEST_AKAV1_AUTH 
     29#if PJSIP_HAS_DIGEST_AKA_AUTH 
    2930 
    3031#include "../../third_party/milenage/milenage.h" 
     
    3334 * Create MD5-AKA1 digest response. 
    3435 */ 
    35 PJ_DEF(pj_status_t) pjsip_auth_create_akav1( pj_pool_t *pool, 
     36PJ_DEF(pj_status_t) pjsip_auth_create_aka_response(  
     37                                             pj_pool_t *pool, 
    3638                                             const pjsip_digest_challenge*chal, 
    3739                                             const pjsip_cred_info *cred, 
     
    4042{ 
    4143    pj_str_t nonce_bin; 
    42     pj_uint8_t *chal_rand, *chal_autn, *chal_mac; 
     44    int aka_version; 
     45    const pj_str_t pjsip_AKAv1_MD5 = { "AKAv1-MD5", 9 }; 
     46    const pj_str_t pjsip_AKAv2_MD5 = { "AKAv2-MD5", 9 }; 
     47    pj_uint8_t *chal_rand, *chal_sqnxoraka, *chal_mac; 
     48    pj_uint8_t k[PJSIP_AKA_KLEN]; 
     49    pj_uint8_t op[PJSIP_AKA_OPLEN]; 
     50    pj_uint8_t amf[PJSIP_AKA_AMFLEN]; 
    4351    pj_uint8_t res[PJSIP_AKA_RESLEN]; 
    4452    pj_uint8_t ck[PJSIP_AKA_CKLEN]; 
    4553    pj_uint8_t ik[PJSIP_AKA_IKLEN]; 
    4654    pj_uint8_t ak[PJSIP_AKA_AKLEN]; 
    47     pj_uint8_t sqn[PJSIP_AKA_AUTNLEN]; 
     55    pj_uint8_t sqn[PJSIP_AKA_SQNLEN]; 
    4856    pj_uint8_t xmac[PJSIP_AKA_MACLEN]; 
    4957    pjsip_cred_info aka_cred; 
     
    5260 
    5361    /* Check the algorithm is supported. */ 
    54     if (pj_stricmp2(&chal->algorithm, "md5") == 0) { 
     62    if (chal->algorithm.slen==0 || pj_stricmp2(&chal->algorithm, "md5") == 0) { 
     63        /* 
     64         * A normal MD5 authentication is requested. Fallbackt to the usual 
     65         * MD5 digest creation. 
     66         */ 
    5567        pjsip_auth_create_digest(&auth->response, &auth->nonce, &auth->nc, 
    5668                                 &auth->cnonce, &auth->qop, &auth->uri, 
     
    5870        return PJ_SUCCESS; 
    5971 
    60     } else if (pj_stricmp2(&chal->algorithm, "AKAv1-MD5") != 0) { 
     72    } else if (pj_stricmp(&chal->algorithm, &pjsip_AKAv1_MD5) == 0) { 
     73        /* 
     74         * AKA version 1 is requested. 
     75         */ 
     76        aka_version = 1; 
     77 
     78    } else if (pj_stricmp(&chal->algorithm, &pjsip_AKAv2_MD5) == 0) { 
     79        /* 
     80         * AKA version 2 is requested. 
     81         */ 
     82        aka_version = 2; 
     83 
     84    } else { 
    6185        /* Unsupported algorithm */ 
    6286        return PJSIP_EINVALIDALGORITHM; 
     
    7195        return PJSIP_EAUTHINNONCE; 
    7296 
    73     if (nonce_bin.slen < PJSIP_AKA_RANDLEN + PJSIP_AKA_AUTNLEN + PJSIP_AKA_MACLEN) 
     97    if (nonce_bin.slen < PJSIP_AKA_RANDLEN + PJSIP_AKA_AUTNLEN) 
    7498        return PJSIP_EAUTHINNONCE; 
    7599 
    76100    /* Get RAND, AUTN, and MAC */ 
    77     chal_rand = (pj_uint8_t*) (nonce_bin.ptr + 0); 
    78     chal_autn = (pj_uint8_t*) (nonce_bin.ptr + PJSIP_AKA_RANDLEN); 
    79     chal_mac =  (pj_uint8_t*) (nonce_bin.ptr + PJSIP_AKA_RANDLEN + PJSIP_AKA_AUTNLEN); 
     101    chal_rand = (pj_uint8_t*)(nonce_bin.ptr + 0); 
     102    chal_sqnxoraka = (pj_uint8_t*) (nonce_bin.ptr + PJSIP_AKA_RANDLEN); 
     103    chal_mac = (pj_uint8_t*) (nonce_bin.ptr + PJSIP_AKA_RANDLEN +  
     104                              PJSIP_AKA_SQNLEN + PJSIP_AKA_AMFLEN); 
    80105 
    81     /* Verify credential */ 
    82     PJ_ASSERT_RETURN(cred->ext.aka.k.slen == PJSIP_AKA_KLEN, PJSIP_EAUTHINAKACRED); 
    83     PJ_ASSERT_RETURN(cred->ext.aka.op.slen == PJSIP_AKA_OPLEN, PJSIP_EAUTHINAKACRED); 
     106    /* Copy k. op, and amf */ 
     107    pj_bzero(k, sizeof(k)); 
     108    pj_bzero(op, sizeof(op)); 
     109    pj_bzero(amf, sizeof(amf)); 
     110 
     111    if (cred->ext.aka.k.slen) 
     112        pj_memcpy(k, cred->ext.aka.k.ptr, cred->ext.aka.k.slen); 
     113    if (cred->ext.aka.op.slen) 
     114        pj_memcpy(op, cred->ext.aka.op.ptr, cred->ext.aka.op.slen); 
     115    if (cred->ext.aka.amf.slen) 
     116        pj_memcpy(amf, cred->ext.aka.amf.ptr, cred->ext.aka.amf.slen); 
    84117 
    85118    /* Given key K and random challenge RAND, compute response RES, 
    86119     * confidentiality key CK, integrity key IK and anonymity key AK. 
    87120     */ 
    88     f2345((pj_uint8_t*)cred->ext.aka.k.ptr,  
    89           chal_rand,  
    90           res, ck, ik, ak,  
    91           (pj_uint8_t*)cred->ext.aka.op.ptr); 
     121    f2345(k, chal_rand, res, ck, ik, ak, op); 
    92122 
    93123    /* Compute sequence number SQN */ 
    94     for (i=0; i<PJSIP_AKA_AUTNLEN; ++i) 
    95         sqn[i] = (pj_uint8_t) (chal_autn[i] ^ ak[i]); 
    96  
    97     /* Compute XMAC */ 
    98     f1((pj_uint8_t*)cred->ext.aka.k.ptr, chal_rand, sqn, 
    99        (pj_uint8_t*)cred->ext.aka.amf.ptr, xmac,  
    100        (pj_uint8_t*)cred->ext.aka.op.ptr); 
     124    for (i=0; i<PJSIP_AKA_SQNLEN; ++i) 
     125        sqn[i] = (pj_uint8_t) (chal_sqnxoraka[i] ^ ak[i]); 
    101126 
    102127    /* Verify MAC in the challenge */ 
     128    /* Compute XMAC */ 
     129    f1(k, chal_rand, sqn, amf, xmac, op); 
     130 
    103131    if (pj_memcmp(chal_mac, xmac, PJSIP_AKA_MACLEN) != 0) { 
    104132        return PJSIP_EAUTHINNONCE; 
     
    110138    pj_memcpy(&aka_cred, cred, sizeof(aka_cred)); 
    111139    aka_cred.data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; 
    112     aka_cred.data.ptr = (char*)res; 
    113     aka_cred.data.slen = PJSIP_AKA_RESLEN; 
    114140 
    115141    /* Create a response */ 
    116     pjsip_auth_create_digest(&auth->response, &chal->nonce,  
    117                              &auth->nc, &auth->cnonce, &auth->qop, &auth->uri, 
    118                              &chal->realm, &aka_cred, method); 
     142    if (aka_version == 1) { 
     143        /* 
     144         * For AKAv1, the password is RES 
     145         */ 
     146        aka_cred.data.ptr = (char*)res; 
     147        aka_cred.data.slen = PJSIP_AKA_RESLEN; 
     148 
     149        pjsip_auth_create_digest(&auth->response, &chal->nonce,  
     150                                 &auth->nc, &auth->cnonce, &auth->qop,  
     151                                 &auth->uri, &chal->realm, &aka_cred, method); 
     152 
     153    } else if (aka_version == 2) { 
     154        /* 
     155         * For AKAv2, password is base64 encoded [1] parameters: 
     156         *    PRF(RES||IK||CK,"http-digest-akav2-password") 
     157         * 
     158         * The pseudo-random function (PRF) is HMAC-MD5 in this case. 
     159         */ 
     160        pj_hmac_md5_context ctx; 
     161        pj_uint8_t hmac_digest[16]; 
     162        char hmac_digest64[24]; 
     163        int out_len; 
     164 
     165        pj_hmac_md5_init(&ctx, (pj_uint8_t*)"http-digest-akav2-password", 26); 
     166        pj_hmac_md5_update(&ctx, res, PJSIP_AKA_RESLEN); 
     167        pj_hmac_md5_update(&ctx, ik, PJSIP_AKA_IKLEN); 
     168        pj_hmac_md5_update(&ctx, ck, PJSIP_AKA_CKLEN); 
     169        pj_hmac_md5_final(&ctx, hmac_digest); 
     170 
     171        out_len = sizeof(hmac_digest64); 
     172        status = pj_base64_encode(hmac_digest, 16, hmac_digest64, &out_len); 
     173        PJ_ASSERT_RETURN(status==PJ_SUCCESS, status); 
     174 
     175        aka_cred.data.ptr = hmac_digest64; 
     176        aka_cred.data.slen = out_len; 
     177 
     178        pjsip_auth_create_digest(&auth->response, &chal->nonce,  
     179                                 &auth->nc, &auth->cnonce, &auth->qop,  
     180                                 &auth->uri, &chal->realm, &aka_cred, method); 
     181 
     182    } else { 
     183        pj_assert(!"Bug!"); 
     184        return PJ_EBUG; 
     185    } 
    119186 
    120187    /* Done */ 
     
    123190 
    124191 
    125 #endif  /* PJSIP_HAS_DIGEST_AKAV1_AUTH */ 
     192#endif  /* PJSIP_HAS_DIGEST_AKA_AUTH */ 
    126193 
Note: See TracChangeset for help on using the changeset viewer.