示例#1
0
static
void do_f2f3f5(uint8_t *key, uint8_t *rand, uint8_t *op, uint8_t *f2_exp,
               uint8_t *f5_exp, uint8_t *f3_exp)
{
    uint8_t res_f2[8];
    uint8_t res_f5[6];
    uint8_t res_f3[16];
    uint8_t res_f4[16];

    SetOPc(op);

    f2345(key, rand, res_f2, res_f3, res_f4, res_f5);

    if (compare_buffer(res_f2, 8, f2_exp, 8) != 0) {
        fail("Fail: f2");
    }

    if (compare_buffer(res_f5, 6, f5_exp, 6) != 0) {
        fail("Fail: f5");
    }

    if (compare_buffer(res_f3, 16, f3_exp, 16) != 0) {
        fail("Fail: f3");
    }
}
示例#2
0
int generate_vector(uint64_t imsi, uint8_t key[16], uint8_t plmn[3],
                    uint8_t sqn[6], auc_vector_t *vector)
{
    /* in E-UTRAN an authentication vector is composed of:
     * - RAND
     * - XRES
     * - AUTN
     * - KASME
     */

    uint8_t amf[] = { 0x80, 0x00 };
    uint8_t mac_a[8];
    uint8_t ck[16];
    uint8_t ik[16];
    uint8_t ak[6];
    int i;

    if (vector == NULL) {
        return EINVAL;
    }

    /* Compute MAC */
    f1(key, vector->rand, sqn, amf, mac_a);

    print_buffer("MAC_A   : ", mac_a, 8);
    print_buffer("SQN     : ", sqn, 6);
    print_buffer("RAND    : ", vector->rand, 16);

    /* Compute XRES, CK, IK, AK */
    f2345(key, vector->rand, vector->xres, ck, ik, ak);
    print_buffer("AK      : ", ak, 6);
    print_buffer("CK      : ", ck, 16);
    print_buffer("IK      : ", ik, 16);
    print_buffer("XRES    : ", vector->xres, 8);

    /* AUTN = SQN ^ AK || AMF || MAC */
    generate_autn(sqn, ak, amf, mac_a, vector->autn);

    print_buffer("AUTN    : ", vector->autn, 16);

    derive_kasme(ck, ik, plmn, sqn, ak, vector->kasme);
    print_buffer("KASME   : ", vector->kasme, 32);

    return 0;
}
static
void do_f4f5star(uint8_t *key, uint8_t *rand, uint8_t *op, uint8_t *f4_exp,
                 uint8_t *f5star_exp)
{
    uint8_t res_f2[8];
    uint8_t res_f5[6];
    uint8_t res_f3[16];
    uint8_t res_f4[16];
    uint8_t res_f5star[6];

    SetOPc(op);

    f2345(key, rand, res_f2, res_f3, res_f4, res_f5);
    if (compare_buffer(res_f4, 16, f4_exp, 16) != 0) {
        fail("Fail: f4");
    }
    f5star(key, rand, res_f5star);
    if (compare_buffer(res_f5star, 6, f5star_exp, 6) != 0) {
        fail("Fail: f5star");
    }
}
示例#4
0
/*
 * Create MD5-AKA1 digest response.
 */
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;
    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_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 (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_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;
    }

    /* Decode nonce */
    nonce_bin.slen = len = 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, &len);
    nonce_bin.slen = len;
    if (status != PJ_SUCCESS)
	return PJSIP_EAUTHINNONCE;

    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_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(k, chal_rand, res, ck, ik, ak, op);

    /* Compute sequence number SQN */
    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;
    }

    /* 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;

    /* Create a response */
    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_str_t resikck;
	const pj_str_t AKAv2_Passwd = { "http-digest-akav2-password", 26 };
	pj_uint8_t hmac_digest[16];
	char tmp_buf[48];
	int hmac64_len;

	resikck.slen = PJSIP_AKA_RESLEN + PJSIP_AKA_IKLEN + PJSIP_AKA_CKLEN;
	pj_assert(resikck.slen <= PJ_ARRAY_SIZE(tmp_buf));
	resikck.ptr = tmp_buf;
	pj_memcpy(resikck.ptr + 0, res, PJSIP_AKA_RESLEN);
	pj_memcpy(resikck.ptr + PJSIP_AKA_RESLEN, ik, PJSIP_AKA_IKLEN);
	pj_memcpy(resikck.ptr + PJSIP_AKA_RESLEN + PJSIP_AKA_IKLEN,
	          ck, PJSIP_AKA_CKLEN);

	pj_hmac_md5((const pj_uint8_t*)AKAv2_Passwd.ptr, AKAv2_Passwd.slen,
	            (const pj_uint8_t*)resikck.ptr, resikck.slen,
	            hmac_digest);

	aka_cred.data.slen = hmac64_len =
		PJ_BASE256_TO_BASE64_LEN(PJ_ARRAY_SIZE(hmac_digest));
	pj_assert(aka_cred.data.slen+1 <= PJ_ARRAY_SIZE(tmp_buf));
	aka_cred.data.ptr = tmp_buf;
	pj_base64_encode(hmac_digest, PJ_ARRAY_SIZE(hmac_digest),
	                 aka_cred.data.ptr, &len);
	aka_cred.data.slen = hmac64_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;
}
示例#5
0
//3GPP TS 35.205/6/7/8/9 and RFC 3310
int tsip_challenge_get_akares(tsip_challenge_t *self, char const *password, char** result)
{
#define SQN_XOR_AK() (AUTN + 0)
#define SERVER_DATA() (nonce + AKA_RAND_SIZE + AKA_AUTN_SIZE)

	// § ==> XOR
	// || ==> append

	AKA_RES_T akares;

	int ret = -1;
	tsk_size_t n;
	char *nonce = tsk_null;

	AKA_XXX_DECLARE(RAND);
	AKA_XXX_DECLARE(AK);
	AKA_XXX_DECLARE(AMF);
	AKA_XXX_DECLARE(CK);
	AKA_XXX_DECLARE(IK);
	AKA_XXX_DECLARE(K);
	AKA_XXX_DECLARE(SQN);
	AKA_XXX_DECLARE(MAC_A);
	AKA_XXX_DECLARE(AUTN);

	AKA_XXX_BZERO(RAND);
	AKA_XXX_BZERO(AK);
	AKA_XXX_BZERO(AMF);
	AKA_XXX_BZERO(CK);
	AKA_XXX_BZERO(IK);
	AKA_XXX_BZERO(K);
	AKA_XXX_BZERO(SQN);
	AKA_XXX_BZERO(MAC_A);
	AKA_XXX_BZERO(AUTN);

	/* RFC 3310 subclause 3.2: nonce = base64(RAND || AUTN || SERV_DATA) */
	n = tsk_base64_decode((const uint8_t*)self->nonce, tsk_strlen(self->nonce), &nonce);
	if(n > TSK_MD5_STRING_SIZE){
		TSK_DEBUG_ERROR("The IMS CORE returned an invalid nonce.");
		goto bail;
	}
	if(n < AKA_RAND_SIZE + AKA_AUTN_SIZE){
		TSK_DEBUG_ERROR("The nonce returned by the IMS CORE is too short to contain both [RAND] and [AUTHN]");
		goto bail;
	}
	else{
		/* Get RAND and AUTN */
		memcpy(RAND, nonce, AKA_RAND_SIZE);
		memcpy(AUTN, (nonce + AKA_RAND_SIZE), AKA_AUTN_SIZE);
	}

	/* Secret key */
	memcpy(K, password, (tsk_strlen(password) > AKA_K_SIZE ? AKA_K_SIZE : tsk_strlen(password)));

	/* 3GPP TS 35.205: AUTN = SQN[§AK] || AMF || MAC-A */
	memcpy(AMF, (AUTN + AKA_SQN_SIZE), AKA_AMF_SIZE);
	memcpy(MAC_A, (AUTN + AKA_SQN_SIZE + AKA_AMF_SIZE), AKA_MAC_A_SIZE);

	/* compute OP */
	ComputeOP(TSIP_CHALLENGE_STACK(self)->security.operator_id);

	/* Checks that we hold the same AMF */
	for(n=0; n<AKA_AMF_SIZE; n++){
		if(AMF[n] != TSIP_CHALLENGE_STACK(self)->security.amf[n]){
			TSK_DEBUG_ERROR("IMS-AKA error: AMF <> XAMF");
			goto bail;
		}
	}
	
	/* Calculate CK, IK and AK */
	f2345(K, RAND, akares, CK, IK, AK);

	/* Calculate SQN from SQN_XOR_AK */
	for(n=0; n<AKA_SQN_SIZE; n++){
		SQN[n] = (uint8_t) (SQN_XOR_AK()[n] ^ AK[n]);
	}

	/* Calculate XMAC_A */
	{
		AKA_MAC_A_T XMAC_A;
		memset(XMAC_A, '\0', sizeof(XMAC_A));
		
		f1(K, RAND, SQN, AMF, XMAC_A);
		if(!tsk_strnequals(MAC_A, XMAC_A, AKA_MAC_A_SIZE)){
			TSK_DEBUG_ERROR("IMS-AKA error: XMAC_A [%s] <> MAC_A[%s]", XMAC_A, MAC_A);
			goto bail;
		}
	}

	/* RFC 4169 subclause 3
		The HTTP Digest password is derived from base64 encoded PRF(RES || IK||CK, "http-digest-akav2-password") 
		or 
		PRF(XRES||IK||CK, "http-digest-akav2-password") instead of (RES) or (XRES) respectively.
		Where PRF ==> HMAC_MD5 function.
	*/
	if(TSIP_CHALLENGE_IS_AKAv2(self)){
		uint8_t res_ik_ck[AKA_RES_SIZE + AKA_IK_SIZE + AKA_CK_SIZE];
		tsk_md5digest_t md5_digest;

		memcpy(res_ik_ck, akares, AKA_RES_SIZE);
		memcpy((res_ik_ck + AKA_RES_SIZE), IK, AKA_IK_SIZE);
		memcpy((res_ik_ck + AKA_RES_SIZE + AKA_IK_SIZE), CK, AKA_CK_SIZE);

		if((ret = hmac_md5digest_compute((const uint8_t*)"http-digest-akav2-password", 26, (const char*)res_ik_ck, sizeof(res_ik_ck), md5_digest))){/* PRF(RES||IK||CK, ...) */
			TSK_DEBUG_ERROR("hmac_md5digest_compute() failed. AKAv2 response will be invalid.");

			ret = -3;
			goto bail;
		}
		else{/* b64(PRF(...)) */
			if(!tsk_base64_encode(md5_digest, sizeof(md5_digest), result)){
				TSK_DEBUG_ERROR("tsk_base64_encode() failed. AKAv2 response will be invalid.");

				ret = -4;
				goto bail;
			}
		}
	}
	else{
		*result = tsk_calloc(1, AKA_RES_SIZE + 1);
		memcpy(*result, akares, AKA_RES_SIZE);

		ret = 0;
	}

	/* Copy CK and IK */
	memcpy(self->ck, CK, AKA_CK_SIZE);
	memcpy(self->ik, IK, AKA_IK_SIZE);

bail:
	TSK_FREE(nonce);
	return ret;

#undef SQN_XOR_AK
#undef SERVER_DATA
}
/****************************************************************************
 **                                                                        **
 ** Name:        usim_api_authenticate()                                   **
 **                                                                        **
 ** Description: Performs mutual authentication of the USIM to the network,**
 **              checking whether authentication token AUTN can be accep-  **
 **              ted. If so, returns an authentication response RES and    **
 **              the ciphering and integrity keys.                         **
 **              In case of synch failure, returns a re-synchronization    **
 **              token AUTS.                                               **
 **                                                                        **
 **              3GPP TS 31.102, section 7.1.1.1                           **
 **                                                                        **
 **              Authentication and key generating function algorithms are **
 **              specified in 3GPP TS 35.206.                              **
 **                                                                        **
 ** Inputs:      rand_pP:          Random challenge number                    **
 **              autn_pP:          Authentication token                       **
 **                             AUTN = (SQN xor AK) || AMF || MAC          **
 **                                         48          16     64 bits     **
 **              Others:        Security key                               **
 **                                                                        **
 ** Outputs:     auts_pP:          Re-synchronization token                   **
 **              res_pP:           Authentication response                    **
 **              ck_pP:            Ciphering key                              **
 **              ik_pP             Integrity key                              **
 **                                                                        **
 **              Return:        RETURNerror, RETURNok                      **
 **              Others:        None                                       **
 **                                                                        **
 ***************************************************************************/
int usim_api_authenticate(const OctetString* rand_pP, const OctetString* autn_pP,
                          OctetString* auts_pP, OctetString* res_pP,
                          OctetString* ck_pP, OctetString* ik_pP)
{
  LOG_FUNC_IN;

  int rc;
  int i;

  LOG_TRACE(DEBUG, "USIM-API  - rand :%s",dump_octet_string(rand_pP));
  LOG_TRACE(DEBUG, "USIM-API  - autn :%s",dump_octet_string(autn_pP));

  /* Compute the authentication response RES = f2K (RAND) */
  /* Compute the cipher key CK = f3K (RAND) */
  /* Compute the integrity key IK = f4K (RAND) */
  /* Compute the anonymity key AK = f5K (RAND) */
#define USIM_API_AK_SIZE 6
  u8 ak[USIM_API_AK_SIZE];
  f2345(_usim_api_k, rand_pP->value,
        res_pP->value, ck_pP->value, ik_pP->value, ak);
  LOG_TRACE(DEBUG, "USIM-API  - res(f2)  :%s",dump_octet_string(res_pP));
  LOG_TRACE(DEBUG, "USIM-API  - ck(f3)   :%s",dump_octet_string(ck_pP));
  LOG_TRACE(DEBUG, "USIM-API  - ik(f4)   :%s",dump_octet_string(ik_pP));
  LOG_TRACE(DEBUG, "USIM-API  - ak(f5)   : %02X%02X%02X%02X%02X%02X",
            ak[0],ak[1],ak[2],ak[3],ak[4],ak[5]);

  /* Retrieve the sequence number SQN = (SQN ⊕ AK) ⊕ AK */
#define USIM_API_SQN_SIZE USIM_API_AK_SIZE
  u8 sqn[USIM_API_SQN_SIZE];

  for (i = 0; i < USIM_API_SQN_SIZE; i++) {
    sqn[i] = autn_pP->value[i] ^ ak[i];
  }

  LOG_TRACE(DEBUG, "USIM-API  - Retrieved SQN %02X%02X%02X%02X%02X%02X",
            sqn[0],sqn[1],sqn[2],sqn[3],sqn[4],sqn[5]);

  /* Compute XMAC = f1K (SQN || RAND || AMF) */
#define USIM_API_XMAC_SIZE 8
  u8 xmac[USIM_API_XMAC_SIZE];
  f1(_usim_api_k, rand_pP->value, sqn, &autn_pP->value[USIM_API_SQN_SIZE], xmac);
  LOG_TRACE(DEBUG,
            "USIM-API  - Computed XMAC %02X%02X%02X%02X%02X%02X%02X%02X",
            xmac[0],xmac[1],xmac[2],xmac[3],
            xmac[4],xmac[5],xmac[6],xmac[7]);

  /* Compare the XMAC with the MAC included in AUTN */
#define USIM_API_AMF_SIZE 2

  if ( memcmp(xmac, &autn_pP->value[USIM_API_SQN_SIZE + USIM_API_AMF_SIZE],
              USIM_API_XMAC_SIZE) != 0 ) {
    LOG_TRACE(INFO,
              "USIM-API  - Comparing the XMAC with the MAC included in AUTN Failed");
    //LOG_FUNC_RETURN (RETURNerror);
  } else {
    LOG_TRACE(INFO,
              "USIM-API  - Comparing the XMAC with the MAC included in AUTN Succeeded");
  }

  /* Verify that the received sequence number SQN is in the correct range */
  rc = _usim_api_check_sqn(*(uint32_t*)(sqn), sqn[USIM_API_SQN_SIZE - 1]);

  if (rc != RETURNok) {
    /* Synchronisation failure; compute the AUTS parameter */

    /* Concealed value of the counter SQNms in the USIM:
     * Conc(SQNMS) = SQNMS ⊕ f5*K(RAND) */
    f5star(_usim_api_k, rand_pP->value, ak);

#define USIM_API_SQNMS_SIZE USIM_API_SQN_SIZE
    u8 sqn_ms[USIM_API_SQNMS_SIZE];
    memset(sqn_ms, 0, USIM_API_SQNMS_SIZE);
#define USIM_API_SQN_MS_SIZE  3

    for (i = 0; i < USIM_API_SQN_MS_SIZE; i++) {
#warning "LG:BUG HERE TODO"
      sqn_ms[USIM_API_SQNMS_SIZE - i] =
        ((uint8_t*)(_usim_api_data.sqn_ms))[USIM_API_SQN_MS_SIZE - i];
    }

    u8 sqnms[USIM_API_SQNMS_SIZE];

    for (i = 0; i < USIM_API_SQNMS_SIZE; i++) {
      sqnms[i] = sqn_ms[i] ^ ak[i];
    }

    LOG_TRACE(DEBUG, "USIM-API  - SQNms %02X%02X%02X%02X%02X%02X",
              sqnms[0],sqnms[1],sqnms[2],sqnms[3],sqnms[4],sqnms[5]);

    /* Synchronisation message authentication code:
     * MACS = f1*K(SQNMS || RAND || AMF) */
#define USIM_API_MACS_SIZE USIM_API_XMAC_SIZE
    u8 macs[USIM_API_MACS_SIZE];
    f1star(_usim_api_k, rand_pP->value, sqn_ms,
           &rand_pP->value[USIM_API_SQN_SIZE], macs);
    LOG_TRACE(DEBUG, "USIM-API  - MACS %02X%02X%02X%02X%02X%02X%02X%02X",
              macs[0],macs[1],macs[2],macs[3],
              macs[4],macs[5],macs[6],macs[7]);

    /* Synchronisation authentication token:
     * AUTS = Conc(SQNMS) || MACS */
    memcpy(&auts_pP->value[0], sqnms, USIM_API_SQNMS_SIZE);
    memcpy(&auts_pP->value[USIM_API_SQNMS_SIZE], macs, USIM_API_MACS_SIZE);
  }

  LOG_FUNC_RETURN (RETURNok);
}