Separated 3gpp2 USIM card and provider functionality
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2008 Martin Willi
|
* Copyright (C) 2008-2009 Martin Willi
|
||||||
* Hochschule fuer Technik Rapperswil
|
* Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
@@ -25,32 +25,11 @@ typedef struct eap_aka_t eap_aka_t;
|
|||||||
|
|
||||||
#include <sa/authenticators/eap/eap_method.h>
|
#include <sa/authenticators/eap/eap_method.h>
|
||||||
|
|
||||||
/** check SEQ values as client for validity, disabled by default */
|
|
||||||
#ifndef SEQ_CHECK
|
|
||||||
# define SEQ_CHECK 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the eap_method_t interface using EAP-AKA.
|
* Implementation of the eap_method_t interface using EAP-AKA.
|
||||||
*
|
*
|
||||||
* EAP-AKA uses 3rd generation mobile phone standard authentication
|
* EAP-AKA uses 3rd generation mobile phone standard authentication
|
||||||
* mechanism for authentication. It is a mutual authentication
|
* mechanism for authentication, as defined RFC4187.
|
||||||
* mechanism which establishs a shared key and therefore supports EAP_ONLY
|
|
||||||
* authentication. This implementation follows the standard of the
|
|
||||||
* 3GPP2 (S.S0055) and not the one of 3GGP.
|
|
||||||
* The shared key used for authentication is from ipsec.secrets. The
|
|
||||||
* peers ID is used to query it.
|
|
||||||
* The AKA mechanism uses sequence numbers to detect replay attacks. The
|
|
||||||
* peer stores the sequence number normally in a USIM and accepts
|
|
||||||
* incremental sequence numbers (incremental for lifetime of the USIM). To
|
|
||||||
* prevent a complex sequence number management, this implementation uses
|
|
||||||
* a sequence number derived from time. It is initialized to the startup
|
|
||||||
* time of the daemon. As long as the (UTC) time of the system is not
|
|
||||||
* turned back while the daemon is not running, this method is secure.
|
|
||||||
* To enable time based SEQs, define SEQ_CHECK as 1. Default is to accept
|
|
||||||
* any SEQ numbers. This allows an attacker to do replay attacks. But since
|
|
||||||
* the server has proven his identity via IKE, such an attack is only
|
|
||||||
* possible between server and AAA (if any).
|
|
||||||
*/
|
*/
|
||||||
struct eap_aka_t {
|
struct eap_aka_t {
|
||||||
|
|
||||||
|
|||||||
@@ -29,42 +29,109 @@ struct private_eap_aka_3gpp2_card_t {
|
|||||||
*/
|
*/
|
||||||
eap_aka_3gpp2_card_t public;
|
eap_aka_3gpp2_card_t public;
|
||||||
|
|
||||||
/**
|
|
||||||
* IMSI, is ID_ANY for this software implementation
|
|
||||||
*/
|
|
||||||
identification_t *imsi;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AKA functions
|
* AKA functions
|
||||||
*/
|
*/
|
||||||
eap_aka_3gpp2_functions_t *f;
|
eap_aka_3gpp2_functions_t *f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* do sequence number checking?
|
||||||
|
*/
|
||||||
|
bool seq_check;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SQN stored in this pseudo-USIM
|
||||||
|
*/
|
||||||
|
char sqn[AKA_SQN_LEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of usim_card_t.get_imsi
|
* Functions from eap_aka_3gpp2_provider.c
|
||||||
*/
|
*/
|
||||||
static identification_t* get_imsi(private_eap_aka_3gpp2_card_t *this)
|
bool eap_aka_3gpp2_get_k(identification_t *id, char k[AKA_K_LEN]);
|
||||||
{
|
void eap_aka_3gpp2_get_sqn(char sqn[AKA_SQN_LEN], int offset);
|
||||||
return this->imsi;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of usim_card_t.get_quintuplet
|
* Implementation of usim_card_t.get_quintuplet
|
||||||
*/
|
*/
|
||||||
static status_t get_quintuplet(private_eap_aka_3gpp2_card_t *this,
|
static status_t get_quintuplet(private_eap_aka_3gpp2_card_t *this,
|
||||||
char rand[16], char autn[16],
|
identification_t *imsi, char rand[AKA_RAND_LEN],
|
||||||
char ck[16], char ik[16], char res[16])
|
char autn[AKA_AUTN_LEN], char ck[AKA_CK_LEN],
|
||||||
|
char ik[AKA_IK_LEN], char res[AKA_RES_LEN])
|
||||||
{
|
{
|
||||||
return FAILED;
|
char *amf, *mac;
|
||||||
|
char k[AKA_K_LEN], ak[AKA_AK_LEN], sqn[AKA_SQN_LEN], xmac[AKA_MAC_LEN];
|
||||||
|
|
||||||
|
if (!eap_aka_3gpp2_get_k(imsi, k))
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "no EAP key found for %Y to authenticate with AKA", imsi);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AUTN = SQN xor AK | AMF | MAC */
|
||||||
|
DBG3(DBG_IKE, "received autn %b", autn, sizeof(autn));
|
||||||
|
DBG3(DBG_IKE, "using K %b", k, sizeof(k));
|
||||||
|
DBG3(DBG_IKE, "using rand %b", rand, sizeof(rand));
|
||||||
|
memcpy(sqn, autn, sizeof(sqn));
|
||||||
|
amf = autn + sizeof(sqn);
|
||||||
|
mac = autn + sizeof(sqn) + AKA_AMF_LEN;
|
||||||
|
|
||||||
|
/* XOR anonymity key AK into SQN to decrypt it */
|
||||||
|
this->f->f5(this->f, k, rand, ak);
|
||||||
|
DBG3(DBG_IKE, "using ak %b", ak, sizeof(ak));
|
||||||
|
memxor(sqn, ak, sizeof(sqn));
|
||||||
|
DBG3(DBG_IKE, "using sqn %b", sqn, sizeof(sqn));
|
||||||
|
|
||||||
|
/* calculate expected MAC and compare against received one */
|
||||||
|
this->f->f1(this->f, k, rand, sqn, amf, xmac);
|
||||||
|
if (!memeq(mac, xmac, sizeof(xmac)))
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "received MAC does not match XMAC");
|
||||||
|
DBG3(DBG_IKE, "MAC %b\nXMAC %b", mac, AKA_MAC_LEN, xmac, AKA_MAC_LEN);
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->seq_check && memcmp(this->sqn, sqn, sizeof(sqn)) >= 0)
|
||||||
|
{
|
||||||
|
DBG3(DBG_IKE, "received SQN %b\ncurrent SQN %b",
|
||||||
|
sqn, sizeof(sqn), this->sqn, sizeof(this->sqn));
|
||||||
|
return INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update stored SQN to the received one */
|
||||||
|
memcpy(this->sqn, sqn, sizeof(sqn));
|
||||||
|
|
||||||
|
/* calculate RES */
|
||||||
|
this->f->f2(this->f, k, rand, res);
|
||||||
|
DBG3(DBG_IKE, "calculated rand %b", res, sizeof(res));
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of usim_card_t.resync
|
* Implementation of usim_card_t.resync
|
||||||
*/
|
*/
|
||||||
static bool resync(private_eap_aka_3gpp2_card_t *this,
|
static bool resync(private_eap_aka_3gpp2_card_t *this, identification_t *imsi,
|
||||||
char rand[16], char auts[16])
|
char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN])
|
||||||
{
|
{
|
||||||
return FALSE;
|
char amf[AKA_AMF_LEN], k[AKA_K_LEN], aks[AKA_AK_LEN], macs[AKA_MAC_LEN];
|
||||||
|
|
||||||
|
if (!eap_aka_3gpp2_get_k(imsi, k))
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "no EAP key found for %Y to resync AKA", imsi);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AMF is set to zero in resync */
|
||||||
|
memset(amf, 0, sizeof(amf));
|
||||||
|
this->f->f5star(this->f, k, rand, aks);
|
||||||
|
this->f->f1star(this->f, k, rand, this->sqn, amf, macs);
|
||||||
|
/* AUTS = SQN xor AKS | MACS */
|
||||||
|
memcpy(auts, this->sqn, sizeof(this->sqn));
|
||||||
|
memxor(auts, aks, sizeof(aks));
|
||||||
|
memcpy(auts + sizeof(aks), macs, sizeof(macs));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,7 +139,6 @@ static bool resync(private_eap_aka_3gpp2_card_t *this,
|
|||||||
*/
|
*/
|
||||||
static void destroy(private_eap_aka_3gpp2_card_t *this)
|
static void destroy(private_eap_aka_3gpp2_card_t *this)
|
||||||
{
|
{
|
||||||
this->imsi->destroy(this->imsi);
|
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,14 +149,20 @@ eap_aka_3gpp2_card_t *eap_aka_3gpp2_card_create(eap_aka_3gpp2_functions_t *f)
|
|||||||
{
|
{
|
||||||
private_eap_aka_3gpp2_card_t *this = malloc_thing(private_eap_aka_3gpp2_card_t);
|
private_eap_aka_3gpp2_card_t *this = malloc_thing(private_eap_aka_3gpp2_card_t);
|
||||||
|
|
||||||
this->public.card.get_imsi = (identification_t*(*)(usim_card_t*))get_imsi;
|
this->public.card.get_quintuplet = (status_t(*)(usim_card_t*, identification_t *imsi, char rand[16], char autn[16], char ck[16], char ik[16], char res[16]))get_quintuplet;
|
||||||
this->public.card.get_quintuplet = (status_t(*)(usim_card_t*, char rand[16], char autn[16], char ck[16], char ik[16], char res[16]))get_quintuplet;
|
this->public.card.resync = (bool(*)(usim_card_t*, identification_t *imsi, char rand[16], char auts[14]))resync;
|
||||||
this->public.card.resync = (bool(*)(usim_card_t*, char rand[16], char auts[16]))resync;
|
|
||||||
this->public.destroy = (void(*)(eap_aka_3gpp2_card_t*))destroy;
|
this->public.destroy = (void(*)(eap_aka_3gpp2_card_t*))destroy;
|
||||||
|
|
||||||
/* this software USIM can act with all identities */
|
|
||||||
this->imsi = identification_create_from_encoding(ID_ANY, chunk_empty);
|
|
||||||
this->f = f;
|
this->f = f;
|
||||||
|
this->seq_check = lib->settings->get_bool(lib->settings,
|
||||||
|
"charon.plugins.eap_aka_3gpp2.seq_check",
|
||||||
|
#ifdef SEQ_CHECK /* handle legacy compile time configuration as default */
|
||||||
|
TRUE);
|
||||||
|
#else /* !SEQ_CHECK */
|
||||||
|
FALSE);
|
||||||
|
#endif /* SEQ_CHECK */
|
||||||
|
|
||||||
|
eap_aka_3gpp2_get_sqn(this->sqn, 0);
|
||||||
|
|
||||||
return &this->public;
|
return &this->public;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ struct private_eap_aka_3gpp2_functions_t {
|
|||||||
prf_t *prf;
|
prf_t *prf;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PAYLOAD_LENGTH 64
|
#define AKA_PAYLOAD_LEN 64
|
||||||
|
|
||||||
#define F1 0x42
|
#define F1 0x42
|
||||||
#define F1STAR 0x43
|
#define F1STAR 0x43
|
||||||
@@ -170,8 +170,8 @@ static void mpz_mod_poly(mpz_t r, mpz_t a, mpz_t b)
|
|||||||
* Step 3 of the various fx() functions:
|
* Step 3 of the various fx() functions:
|
||||||
* XOR the key into the SHA1 IV
|
* XOR the key into the SHA1 IV
|
||||||
*/
|
*/
|
||||||
static void step3(prf_t *prf, u_char k[K_LENGTH], u_char payload[PAYLOAD_LENGTH],
|
static void step3(prf_t *prf, u_char k[AKA_K_LEN],
|
||||||
u_int8_t h[HASH_SIZE_SHA1])
|
u_char payload[AKA_PAYLOAD_LEN], u_int8_t h[HASH_SIZE_SHA1])
|
||||||
{
|
{
|
||||||
/* use the keyed hasher to build the hash */
|
/* use the keyed hasher to build the hash */
|
||||||
prf->set_key(prf, chunk_create(k, sizeof(k)));
|
prf->set_key(prf, chunk_create(k, sizeof(k)));
|
||||||
@@ -211,10 +211,10 @@ static void step4(u_char x[HASH_SIZE_SHA1])
|
|||||||
/**
|
/**
|
||||||
* Calculation function for f2(), f3(), f4()
|
* Calculation function for f2(), f3(), f4()
|
||||||
*/
|
*/
|
||||||
static void fx(prf_t *prf, u_char f, u_char k[K_LENGTH],
|
static void fx(prf_t *prf, u_char f, u_char k[AKA_K_LEN],
|
||||||
u_char rand[RAND_LENGTH], u_char out[MAC_LENGTH])
|
u_char rand[AKA_RAND_LEN], u_char out[AKA_MAC_LEN])
|
||||||
{
|
{
|
||||||
u_char payload[PAYLOAD_LENGTH];
|
u_char payload[AKA_PAYLOAD_LEN];
|
||||||
u_char h[HASH_SIZE_SHA1];
|
u_char h[HASH_SIZE_SHA1];
|
||||||
u_char i;
|
u_char i;
|
||||||
|
|
||||||
@@ -239,15 +239,15 @@ static void fx(prf_t *prf, u_char f, u_char k[K_LENGTH],
|
|||||||
/**
|
/**
|
||||||
* Calculation function of f1() and f1star()
|
* Calculation function of f1() and f1star()
|
||||||
*/
|
*/
|
||||||
static void f1x(prf_t *prf, u_int8_t f, u_char k[K_LENGTH],
|
static void f1x(prf_t *prf, u_int8_t f, u_char k[AKA_K_LEN],
|
||||||
u_char rand[RAND_LENGTH], u_char sqn[SQN_LENGTH],
|
u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN],
|
||||||
u_char amf[AMF_LENGTH], u_char mac[MAC_LENGTH])
|
u_char amf[AKA_AMF_LEN], u_char mac[AKA_MAC_LEN])
|
||||||
{
|
{
|
||||||
/* generate MAC = f1(FMK, SQN, RAND, AMF)
|
/* generate MAC = f1(FMK, SQN, RAND, AMF)
|
||||||
* K is loaded into hashers IV; FMK, RAND, SQN, AMF are XORed in a 512-bit
|
* K is loaded into hashers IV; FMK, RAND, SQN, AMF are XORed in a 512-bit
|
||||||
* payload which gets hashed
|
* payload which gets hashed
|
||||||
*/
|
*/
|
||||||
u_char payload[PAYLOAD_LENGTH];
|
u_char payload[AKA_PAYLOAD_LEN];
|
||||||
u_char h[HASH_SIZE_SHA1];
|
u_char h[HASH_SIZE_SHA1];
|
||||||
|
|
||||||
memset(payload, 0x5c, sizeof(payload));
|
memset(payload, 0x5c, sizeof(payload));
|
||||||
@@ -265,10 +265,10 @@ static void f1x(prf_t *prf, u_int8_t f, u_char k[K_LENGTH],
|
|||||||
/**
|
/**
|
||||||
* Calculation function of f5() and f5star()
|
* Calculation function of f5() and f5star()
|
||||||
*/
|
*/
|
||||||
static void f5x(prf_t *prf, u_char f, u_char k[K_LENGTH],
|
static void f5x(prf_t *prf, u_char f, u_char k[AKA_K_LEN],
|
||||||
u_char rand[RAND_LENGTH], u_char ak[AK_LENGTH])
|
u_char rand[AKA_RAND_LEN], u_char ak[AKA_AK_LEN])
|
||||||
{
|
{
|
||||||
u_char payload[PAYLOAD_LENGTH];
|
u_char payload[AKA_PAYLOAD_LEN];
|
||||||
u_char h[HASH_SIZE_SHA1];
|
u_char h[HASH_SIZE_SHA1];
|
||||||
|
|
||||||
memset(payload, 0x5c, sizeof(payload));
|
memset(payload, 0x5c, sizeof(payload));
|
||||||
@@ -284,9 +284,9 @@ static void f5x(prf_t *prf, u_char f, u_char k[K_LENGTH],
|
|||||||
/**
|
/**
|
||||||
* Calculate MAC from RAND, SQN, AMF using K
|
* Calculate MAC from RAND, SQN, AMF using K
|
||||||
*/
|
*/
|
||||||
static void f1(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
static void f1(private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
|
||||||
u_char rand[RAND_LENGTH], u_char sqn[SQN_LENGTH],
|
u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN],
|
||||||
u_char amf[AMF_LENGTH], u_char mac[MAC_LENGTH])
|
u_char amf[AKA_AMF_LEN], u_char mac[AKA_MAC_LEN])
|
||||||
{
|
{
|
||||||
f1x(this->prf, F1, k, rand, sqn, amf, mac);
|
f1x(this->prf, F1, k, rand, sqn, amf, mac);
|
||||||
DBG3(DBG_IKE, "MAC %b", mac, sizeof(mac));
|
DBG3(DBG_IKE, "MAC %b", mac, sizeof(mac));
|
||||||
@@ -295,9 +295,9 @@ static void f1(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
|||||||
/**
|
/**
|
||||||
* Calculate MACS from RAND, SQN, AMF using K
|
* Calculate MACS from RAND, SQN, AMF using K
|
||||||
*/
|
*/
|
||||||
static void f1star(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
static void f1star(private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
|
||||||
u_char rand[RAND_LENGTH], u_char sqn[SQN_LENGTH],
|
u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN],
|
||||||
u_char amf[AMF_LENGTH], u_char macs[MAC_LENGTH])
|
u_char amf[AKA_AMF_LEN], u_char macs[AKA_MAC_LEN])
|
||||||
{
|
{
|
||||||
f1x(this->prf, F1STAR, k, rand, sqn, amf, macs);
|
f1x(this->prf, F1STAR, k, rand, sqn, amf, macs);
|
||||||
DBG3(DBG_IKE, "MACS %b", macs, sizeof(macs));
|
DBG3(DBG_IKE, "MACS %b", macs, sizeof(macs));
|
||||||
@@ -306,8 +306,8 @@ static void f1star(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
|||||||
/**
|
/**
|
||||||
* Calculate RES from RAND using K
|
* Calculate RES from RAND using K
|
||||||
*/
|
*/
|
||||||
static void f2(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
static void f2(private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
|
||||||
u_char rand[RAND_LENGTH], u_char res[RES_LENGTH])
|
u_char rand[AKA_RAND_LEN], u_char res[AKA_RES_LEN])
|
||||||
{
|
{
|
||||||
fx(this->prf, F2, k, rand, res);
|
fx(this->prf, F2, k, rand, res);
|
||||||
DBG3(DBG_IKE, "RES %b", res, sizeof(res));
|
DBG3(DBG_IKE, "RES %b", res, sizeof(res));
|
||||||
@@ -316,8 +316,8 @@ static void f2(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
|||||||
/**
|
/**
|
||||||
* Calculate CK from RAND using K
|
* Calculate CK from RAND using K
|
||||||
*/
|
*/
|
||||||
static void f3(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
static void f3(private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
|
||||||
u_char rand[RAND_LENGTH], u_char ck[CK_LENGTH])
|
u_char rand[AKA_RAND_LEN], u_char ck[AKA_CK_LEN])
|
||||||
{
|
{
|
||||||
fx(this->prf, F3, k, rand, ck);
|
fx(this->prf, F3, k, rand, ck);
|
||||||
DBG3(DBG_IKE, "CK %b", ck, sizeof(ck));
|
DBG3(DBG_IKE, "CK %b", ck, sizeof(ck));
|
||||||
@@ -326,8 +326,8 @@ static void f3(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
|||||||
/**
|
/**
|
||||||
* Calculate IK from RAND using K
|
* Calculate IK from RAND using K
|
||||||
*/
|
*/
|
||||||
static void f4(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
static void f4(private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
|
||||||
u_char rand[RAND_LENGTH], u_char ik[IK_LENGTH])
|
u_char rand[AKA_RAND_LEN], u_char ik[AKA_IK_LEN])
|
||||||
{
|
{
|
||||||
fx(this->prf, F4, k, rand, ik);
|
fx(this->prf, F4, k, rand, ik);
|
||||||
DBG3(DBG_IKE, "IK %b", ik, sizeof(ik));
|
DBG3(DBG_IKE, "IK %b", ik, sizeof(ik));
|
||||||
@@ -336,8 +336,8 @@ static void f4(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
|||||||
/**
|
/**
|
||||||
* Calculate AK from a RAND using K
|
* Calculate AK from a RAND using K
|
||||||
*/
|
*/
|
||||||
static void f5(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
static void f5(private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
|
||||||
u_char rand[RAND_LENGTH], u_char ak[AK_LENGTH])
|
u_char rand[AKA_RAND_LEN], u_char ak[AKA_AK_LEN])
|
||||||
{
|
{
|
||||||
f5x(this->prf, F5, k, rand, ak);
|
f5x(this->prf, F5, k, rand, ak);
|
||||||
DBG3(DBG_IKE, "AK %b", ak, sizeof(ak));
|
DBG3(DBG_IKE, "AK %b", ak, sizeof(ak));
|
||||||
@@ -346,8 +346,8 @@ static void f5(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
|||||||
/**
|
/**
|
||||||
* Calculate AKS from a RAND using K
|
* Calculate AKS from a RAND using K
|
||||||
*/
|
*/
|
||||||
static void f5star(private_eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
static void f5star(private_eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
|
||||||
u_char rand[RAND_LENGTH], u_char aks[AK_LENGTH])
|
u_char rand[AKA_RAND_LEN], u_char aks[AKA_AK_LEN])
|
||||||
{
|
{
|
||||||
f5x(this->prf, F5STAR, k, rand, aks);
|
f5x(this->prf, F5STAR, k, rand, aks);
|
||||||
DBG3(DBG_IKE, "AKS %b", aks, sizeof(aks));
|
DBG3(DBG_IKE, "AKS %b", aks, sizeof(aks));
|
||||||
@@ -372,13 +372,13 @@ eap_aka_3gpp2_functions_t *eap_aka_3gpp2_functions_create()
|
|||||||
|
|
||||||
this = malloc_thing(private_eap_aka_3gpp2_functions_t);
|
this = malloc_thing(private_eap_aka_3gpp2_functions_t);
|
||||||
|
|
||||||
this->public.f1 = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], u_char rand[RAND_LENGTH], u_char sqn[SQN_LENGTH], u_char amf[AMF_LENGTH], u_char mac[MAC_LENGTH]))f1;
|
this->public.f1 = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN], u_char amf[AKA_AMF_LEN], u_char mac[AKA_MAC_LEN]))f1;
|
||||||
this->public.f1star = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], u_char rand[RAND_LENGTH], u_char sqn[SQN_LENGTH], u_char amf[AMF_LENGTH], u_char macs[MAC_LENGTH]))f1star;
|
this->public.f1star = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN], u_char amf[AKA_AMF_LEN], u_char macs[AKA_MAC_LEN]))f1star;
|
||||||
this->public.f2 = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], u_char rand[RAND_LENGTH], u_char res[RES_LENGTH]))f2;
|
this->public.f2 = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char res[AKA_RES_LEN]))f2;
|
||||||
this->public.f3 = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], u_char rand[RAND_LENGTH], u_char ck[CK_LENGTH]))f3;
|
this->public.f3 = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char ck[AKA_CK_LEN]))f3;
|
||||||
this->public.f4 = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], u_char rand[RAND_LENGTH], u_char ik[IK_LENGTH]))f4;
|
this->public.f4 = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char ik[AKA_IK_LEN]))f4;
|
||||||
this->public.f5 = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], u_char rand[RAND_LENGTH], u_char ak[AK_LENGTH]))f5;
|
this->public.f5 = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char ak[AKA_AK_LEN]))f5;
|
||||||
this->public.f5star = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH], u_char rand[RAND_LENGTH], u_char aks[AK_LENGTH]))f5star;
|
this->public.f5star = (void(*)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN], u_char rand[AKA_RAND_LEN], u_char aks[AKA_AK_LEN]))f5star;
|
||||||
this->public.destroy = (void(*)(eap_aka_3gpp2_functions_t*))destroy;
|
this->public.destroy = (void(*)(eap_aka_3gpp2_functions_t*))destroy;
|
||||||
|
|
||||||
this->prf = lib->crypto->create_prf(lib->crypto, PRF_KEYED_SHA1);
|
this->prf = lib->crypto->create_prf(lib->crypto, PRF_KEYED_SHA1);
|
||||||
|
|||||||
@@ -21,21 +21,14 @@
|
|||||||
#ifndef EAP_AKA_3GPP2_FUNCTIONS_H_
|
#ifndef EAP_AKA_3GPP2_FUNCTIONS_H_
|
||||||
#define EAP_AKA_3GPP2_FUNCTIONS_H_
|
#define EAP_AKA_3GPP2_FUNCTIONS_H_
|
||||||
|
|
||||||
#include <utils/enumerator.h>
|
#include <sa/authenticators/eap/usim_manager.h>
|
||||||
#include <utils/identification.h>
|
|
||||||
|
|
||||||
#define RAND_LENGTH 16
|
#define AKA_SQN_LEN 6
|
||||||
#define RES_LENGTH 16
|
#define AKA_K_LEN 16
|
||||||
#define SQN_LENGTH 6
|
#define AKA_MAC_LEN 8
|
||||||
#define K_LENGTH 16
|
#define AKA_AK_LEN 6
|
||||||
#define MAC_LENGTH 8
|
#define AKA_AMF_LEN 2
|
||||||
#define CK_LENGTH 16
|
#define AKA_FMK_LEN 4
|
||||||
#define IK_LENGTH 16
|
|
||||||
#define AK_LENGTH 6
|
|
||||||
#define AMF_LENGTH 2
|
|
||||||
#define FMK_LENGTH 4
|
|
||||||
#define AUTN_LENGTH (SQN_LENGTH + AMF_LENGTH + MAC_LENGTH)
|
|
||||||
#define AUTS_LENGTH (SQN_LENGTH + MAC_LENGTH)
|
|
||||||
|
|
||||||
typedef struct eap_aka_3gpp2_functions_t eap_aka_3gpp2_functions_t;
|
typedef struct eap_aka_3gpp2_functions_t eap_aka_3gpp2_functions_t;
|
||||||
|
|
||||||
@@ -53,9 +46,9 @@ struct eap_aka_3gpp2_functions_t {
|
|||||||
* @param amf authentication management field
|
* @param amf authentication management field
|
||||||
* @param mac buffer receiving mac MAC
|
* @param mac buffer receiving mac MAC
|
||||||
*/
|
*/
|
||||||
void (*f1)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
void (*f1)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
|
||||||
u_char rand[RAND_LENGTH], u_char sqn[SQN_LENGTH],
|
u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN],
|
||||||
u_char amf[AMF_LENGTH], u_char mac[MAC_LENGTH]);
|
u_char amf[AKA_AMF_LEN], u_char mac[AKA_MAC_LEN]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate MACS from RAND, SQN, AMF using K
|
* Calculate MACS from RAND, SQN, AMF using K
|
||||||
@@ -66,9 +59,9 @@ struct eap_aka_3gpp2_functions_t {
|
|||||||
* @param amf authentication management field
|
* @param amf authentication management field
|
||||||
* @param macs buffer receiving resynchronization mac MACS
|
* @param macs buffer receiving resynchronization mac MACS
|
||||||
*/
|
*/
|
||||||
void (*f1star)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
void (*f1star)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
|
||||||
u_char rand[RAND_LENGTH], u_char sqn[SQN_LENGTH],
|
u_char rand[AKA_RAND_LEN], u_char sqn[AKA_SQN_LEN],
|
||||||
u_char amf[AMF_LENGTH], u_char macs[MAC_LENGTH]);
|
u_char amf[AKA_AMF_LEN], u_char macs[AKA_MAC_LEN]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate RES from RAND using K
|
* Calculate RES from RAND using K
|
||||||
@@ -77,8 +70,8 @@ struct eap_aka_3gpp2_functions_t {
|
|||||||
* @param rand random value RAND
|
* @param rand random value RAND
|
||||||
* @param macs buffer receiving result RES
|
* @param macs buffer receiving result RES
|
||||||
*/
|
*/
|
||||||
void (*f2)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
void (*f2)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
|
||||||
u_char rand[RAND_LENGTH], u_char res[RES_LENGTH]);
|
u_char rand[AKA_RAND_LEN], u_char res[AKA_RES_LEN]);
|
||||||
/**
|
/**
|
||||||
* Calculate CK from RAND using K
|
* Calculate CK from RAND using K
|
||||||
*
|
*
|
||||||
@@ -86,8 +79,8 @@ struct eap_aka_3gpp2_functions_t {
|
|||||||
* @param rand random value RAND
|
* @param rand random value RAND
|
||||||
* @param macs buffer receiving encryption key CK
|
* @param macs buffer receiving encryption key CK
|
||||||
*/
|
*/
|
||||||
void (*f3)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
void (*f3)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
|
||||||
u_char rand[RAND_LENGTH], u_char ck[CK_LENGTH]);
|
u_char rand[AKA_RAND_LEN], u_char ck[AKA_CK_LEN]);
|
||||||
/**
|
/**
|
||||||
* Calculate IK from RAND using K
|
* Calculate IK from RAND using K
|
||||||
*
|
*
|
||||||
@@ -95,8 +88,8 @@ struct eap_aka_3gpp2_functions_t {
|
|||||||
* @param rand random value RAND
|
* @param rand random value RAND
|
||||||
* @param macs buffer receiving integrity key IK
|
* @param macs buffer receiving integrity key IK
|
||||||
*/
|
*/
|
||||||
void (*f4)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
void (*f4)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
|
||||||
u_char rand[RAND_LENGTH], u_char ik[IK_LENGTH]);
|
u_char rand[AKA_RAND_LEN], u_char ik[AKA_IK_LEN]);
|
||||||
/**
|
/**
|
||||||
* Calculate AK from a RAND using K
|
* Calculate AK from a RAND using K
|
||||||
*
|
*
|
||||||
@@ -104,8 +97,8 @@ struct eap_aka_3gpp2_functions_t {
|
|||||||
* @param rand random value RAND
|
* @param rand random value RAND
|
||||||
* @param macs buffer receiving anonymity key AK
|
* @param macs buffer receiving anonymity key AK
|
||||||
*/
|
*/
|
||||||
void (*f5)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
void (*f5)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
|
||||||
u_char rand[RAND_LENGTH], u_char ak[AK_LENGTH]);
|
u_char rand[AKA_RAND_LEN], u_char ak[AKA_AK_LEN]);
|
||||||
/**
|
/**
|
||||||
* Calculate AKS from a RAND using K
|
* Calculate AKS from a RAND using K
|
||||||
*
|
*
|
||||||
@@ -113,8 +106,8 @@ struct eap_aka_3gpp2_functions_t {
|
|||||||
* @param rand random value RAND
|
* @param rand random value RAND
|
||||||
* @param macs buffer receiving resynchronization anonymity key AKS
|
* @param macs buffer receiving resynchronization anonymity key AKS
|
||||||
*/
|
*/
|
||||||
void (*f5star)(eap_aka_3gpp2_functions_t *this, u_char k[K_LENGTH],
|
void (*f5star)(eap_aka_3gpp2_functions_t *this, u_char k[AKA_K_LEN],
|
||||||
u_char rand[RAND_LENGTH], u_char aks[AK_LENGTH]);
|
u_char rand[AKA_RAND_LEN], u_char aks[AKA_AK_LEN]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy a eap_aka_3gpp2_functions_t.
|
* Destroy a eap_aka_3gpp2_functions_t.
|
||||||
|
|||||||
@@ -15,6 +15,9 @@
|
|||||||
|
|
||||||
#include "eap_aka_3gpp2_provider.h"
|
#include "eap_aka_3gpp2_provider.h"
|
||||||
|
|
||||||
|
#include <daemon.h>
|
||||||
|
#include <credentials/keys/shared_key.h>
|
||||||
|
|
||||||
typedef struct private_eap_aka_3gpp2_provider_t private_eap_aka_3gpp2_provider_t;
|
typedef struct private_eap_aka_3gpp2_provider_t private_eap_aka_3gpp2_provider_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -31,25 +34,139 @@ struct private_eap_aka_3gpp2_provider_t {
|
|||||||
* AKA functions
|
* AKA functions
|
||||||
*/
|
*/
|
||||||
eap_aka_3gpp2_functions_t *f;
|
eap_aka_3gpp2_functions_t *f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* time based SQN, we use the same for all peers
|
||||||
|
*/
|
||||||
|
char sqn[AKA_SQN_LEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Authentication management field */
|
||||||
|
static char amf[AKA_AMF_LEN] = {0x00, 0x01};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a shared key K from the credential database
|
||||||
|
*/
|
||||||
|
bool eap_aka_3gpp2_get_k(identification_t *id, char k[AKA_K_LEN])
|
||||||
|
{
|
||||||
|
shared_key_t *shared;
|
||||||
|
chunk_t key;
|
||||||
|
|
||||||
|
shared = charon->credentials->get_shared(charon->credentials,
|
||||||
|
SHARED_EAP, id, NULL);
|
||||||
|
if (shared == NULL)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
key = shared->get_key(shared);
|
||||||
|
memset(k, '\0', sizeof(k));
|
||||||
|
memcpy(k, key.ptr, min(key.len, sizeof(k)));
|
||||||
|
shared->destroy(shared);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get SQN using current time
|
||||||
|
*/
|
||||||
|
void eap_aka_3gpp2_get_sqn(char sqn[AKA_SQN_LEN], int offset)
|
||||||
|
{
|
||||||
|
timeval_t time;
|
||||||
|
|
||||||
|
time_monotonic(&time);
|
||||||
|
/* set sqn to an integer containing seconds followed by most
|
||||||
|
* significant useconds */
|
||||||
|
time.tv_sec = htonl(time.tv_sec + offset);
|
||||||
|
/* usec's are never larger than 0x000f423f, so we shift the 12 first bits */
|
||||||
|
time.tv_usec <<= 12;
|
||||||
|
time.tv_usec = htonl(time.tv_usec);
|
||||||
|
memcpy(sqn, &time.tv_sec, 4);
|
||||||
|
memcpy(sqn + 4, &time.tv_usec, 2);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of usim_provider_t.get_quintuplet
|
* Implementation of usim_provider_t.get_quintuplet
|
||||||
*/
|
*/
|
||||||
static bool get_quintuplet(private_eap_aka_3gpp2_provider_t *this,
|
static bool get_quintuplet(private_eap_aka_3gpp2_provider_t *this,
|
||||||
identification_t *imsi, char rand[16], char xres[16],
|
identification_t *imsi, char rand[AKA_RAND_LEN],
|
||||||
char ck[16], char ik[16], char autn[16])
|
char xres[AKA_RES_LEN], char ck[AKA_CK_LEN],
|
||||||
|
char ik[AKA_IK_LEN], char autn[AKA_AUTN_LEN])
|
||||||
{
|
{
|
||||||
return FALSE;
|
rng_t *rng;
|
||||||
|
char mac[AKA_MAC_LEN], ak[AKA_AK_LEN], k[AKA_K_LEN];
|
||||||
|
|
||||||
|
/* generate RAND: we use a registered RNG, not f0() proposed in S.S0055 */
|
||||||
|
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
|
||||||
|
if (!rng)
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "generating RAND for AKA failed");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
rng->get_bytes(rng, AKA_RAND_LEN, rand);
|
||||||
|
rng->destroy(rng);
|
||||||
|
|
||||||
|
if (!eap_aka_3gpp2_get_k(imsi, k))
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "no EAP key found for %Y to authenticate with AKA", imsi);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MAC */
|
||||||
|
this->f->f1(this->f, k, rand, this->sqn, amf, mac);
|
||||||
|
/* AK */
|
||||||
|
this->f->f5(this->f, k, rand, ak);
|
||||||
|
/* XRES as expected from client */
|
||||||
|
this->f->f2(this->f, k, rand, xres);
|
||||||
|
/* AUTN = (SQN xor AK) || AMF || MAC */
|
||||||
|
memcpy(autn, this->sqn, sizeof(this->sqn));
|
||||||
|
memxor(autn, ak, sizeof(ak));
|
||||||
|
memcpy(autn + sizeof(this->sqn), amf, sizeof(amf));
|
||||||
|
memcpy(autn + sizeof(this->sqn) + sizeof(amf), mac, sizeof(mac));
|
||||||
|
DBG3(DBG_IKE, "AUTN %b", autn, sizeof(autn));
|
||||||
|
/* CK/IK */
|
||||||
|
this->f->f3(this->f, k, rand, ck);
|
||||||
|
DBG3(DBG_IKE, "CK %b", ck, sizeof(ck));
|
||||||
|
this->f->f4(this->f, k, rand, ik);
|
||||||
|
DBG3(DBG_IKE, "IK %b", ik, sizeof(ik));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of usim_provider_t.resync
|
* Implementation of usim_provider_t.resync
|
||||||
*/
|
*/
|
||||||
static bool resync(private_eap_aka_3gpp2_provider_t *this,
|
static bool resync(private_eap_aka_3gpp2_provider_t *this,
|
||||||
identification_t *imsi, char rand[16], char auts[16])
|
identification_t *imsi, char rand[AKA_RAND_LEN],
|
||||||
|
char auts[AKA_AUTS_LEN])
|
||||||
{
|
{
|
||||||
return FALSE;
|
char *sqn, *macs;
|
||||||
|
char aks[AKA_AK_LEN], k[AKA_K_LEN], amf[AKA_AMF_LEN], xmacs[AKA_MAC_LEN];
|
||||||
|
|
||||||
|
if (!eap_aka_3gpp2_get_k(imsi, k))
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "no EAP key found for %Y to authenticate with AKA", imsi);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AUTHS = (AK xor SQN) | MAC */
|
||||||
|
sqn = auts;
|
||||||
|
macs = auts + AKA_SQN_LEN;
|
||||||
|
this->f->f5star(this->f, k, rand, aks);
|
||||||
|
memxor(sqn, aks, sizeof(aks));
|
||||||
|
|
||||||
|
/* verify XMACS, AMF of zero is used in resynchronization */
|
||||||
|
memset(amf, 0, sizeof(amf));
|
||||||
|
this->f->f1star(this->f, k, rand, sqn, amf, xmacs);
|
||||||
|
if (!memeq(macs, xmacs, sizeof(xmacs)))
|
||||||
|
{
|
||||||
|
DBG1(DBG_IKE, "received MACS does not match XMACS");
|
||||||
|
DBG3(DBG_IKE, "MACS %b XMACS %b",
|
||||||
|
macs, AKA_MAC_LEN, xmacs, sizeof(xmacs));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
/* update stored SQN to received SQN + 1 */
|
||||||
|
memcpy(this->sqn, sqn, AKA_SQN_LEN);
|
||||||
|
chunk_increment(chunk_create(this->sqn, AKA_SQN_LEN));
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,10 +186,12 @@ eap_aka_3gpp2_provider_t *eap_aka_3gpp2_provider_create(
|
|||||||
private_eap_aka_3gpp2_provider_t *this = malloc_thing(private_eap_aka_3gpp2_provider_t);
|
private_eap_aka_3gpp2_provider_t *this = malloc_thing(private_eap_aka_3gpp2_provider_t);
|
||||||
|
|
||||||
this->public.provider.get_quintuplet = (bool(*)(usim_provider_t*, identification_t *imsi, char rand[16], char xres[16], char ck[16], char ik[16], char autn[16]))get_quintuplet;
|
this->public.provider.get_quintuplet = (bool(*)(usim_provider_t*, identification_t *imsi, char rand[16], char xres[16], char ck[16], char ik[16], char autn[16]))get_quintuplet;
|
||||||
this->public.provider.resync = (bool(*)(usim_provider_t*, identification_t *imsi, char rand[16], char auts[16]))resync;
|
this->public.provider.resync = (bool(*)(usim_provider_t*, identification_t *imsi, char rand[16], char auts[14]))resync;
|
||||||
this->public.destroy = (void(*)(eap_aka_3gpp2_provider_t*))destroy;
|
this->public.destroy = (void(*)(eap_aka_3gpp2_provider_t*))destroy;
|
||||||
|
|
||||||
this->f = f;
|
this->f = f;
|
||||||
|
/* use an offset to accept clock skew between client/server without resync */
|
||||||
|
eap_aka_3gpp2_get_sqn(this->sqn, 180);
|
||||||
|
|
||||||
return &this->public;
|
return &this->public;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,13 @@ typedef struct usim_manager_t usim_manager_t;
|
|||||||
typedef struct usim_card_t usim_card_t;
|
typedef struct usim_card_t usim_card_t;
|
||||||
typedef struct usim_provider_t usim_provider_t;
|
typedef struct usim_provider_t usim_provider_t;
|
||||||
|
|
||||||
|
#define AKA_RAND_LEN 16
|
||||||
|
#define AKA_RES_LEN 16
|
||||||
|
#define AKA_CK_LEN 16
|
||||||
|
#define AKA_IK_LEN 16
|
||||||
|
#define AKA_AUTN_LEN 16
|
||||||
|
#define AKA_AUTS_LEN 14
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for a USIM card (used by EAP-AKA client).
|
* Interface for a USIM card (used by EAP-AKA client).
|
||||||
*/
|
*/
|
||||||
@@ -45,8 +52,9 @@ struct usim_provider_t {
|
|||||||
* @return TRUE if quintuplet generated successfully
|
* @return TRUE if quintuplet generated successfully
|
||||||
*/
|
*/
|
||||||
bool (*get_quintuplet)(usim_provider_t *this, identification_t *imsi,
|
bool (*get_quintuplet)(usim_provider_t *this, identification_t *imsi,
|
||||||
char rand[16], char xres[16],
|
char rand[AKA_RAND_LEN], char xres[AKA_RES_LEN],
|
||||||
char ck[16], char ik[16], char autn[16]);
|
char ck[AKA_CK_LEN], char ik[AKA_IK_LEN],
|
||||||
|
char autn[AKA_AUTN_LEN]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process resynchroniusation request of a peer.
|
* Process resynchroniusation request of a peer.
|
||||||
@@ -57,7 +65,7 @@ struct usim_provider_t {
|
|||||||
* @return TRUE if resynchronized successfully
|
* @return TRUE if resynchronized successfully
|
||||||
*/
|
*/
|
||||||
bool (*resync)(usim_provider_t *this, identification_t *imsi,
|
bool (*resync)(usim_provider_t *this, identification_t *imsi,
|
||||||
char rand[16], char auts[16]);
|
char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,19 +73,13 @@ struct usim_provider_t {
|
|||||||
*/
|
*/
|
||||||
struct usim_card_t {
|
struct usim_card_t {
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the IMSI of this USIM.
|
|
||||||
*
|
|
||||||
* @return IMSI this USIM belongs to
|
|
||||||
*/
|
|
||||||
identification_t *(*get_imsi)(usim_card_t *this);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process authentication data and complete the quintuplet.
|
* Process authentication data and complete the quintuplet.
|
||||||
*
|
*
|
||||||
* If the received sequence number (in autn) is out of synf, INVALID_STATE
|
* If the received sequence number (in autn) is out of synf, INVALID_STATE
|
||||||
* is returned.
|
* is returned.
|
||||||
*
|
*
|
||||||
|
* @param imsi peer identity requesting quintuplet for
|
||||||
* @param rand random value rand
|
* @param rand random value rand
|
||||||
* @param autn authentication token autn
|
* @param autn authentication token autn
|
||||||
* @param ck buffer receiving encryption key ck
|
* @param ck buffer receiving encryption key ck
|
||||||
@@ -85,17 +87,21 @@ struct usim_card_t {
|
|||||||
* @param res buffer receiving authentication result res
|
* @param res buffer receiving authentication result res
|
||||||
* @return SUCCESS, FAILED, or INVALID_STATE if out of sync
|
* @return SUCCESS, FAILED, or INVALID_STATE if out of sync
|
||||||
*/
|
*/
|
||||||
status_t (*get_quintuplet)(usim_card_t *this, char rand[16], char autn[16],
|
status_t (*get_quintuplet)(usim_card_t *this, identification_t *imsi,
|
||||||
char ck[16], char ik[16], char res[16]);
|
char rand[AKA_RAND_LEN], char autn[AKA_AUTN_LEN],
|
||||||
|
char ck[AKA_CK_LEN], char ik[AKA_IK_LEN],
|
||||||
|
char res[AKA_RES_LEN]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request parameter to start resynchronization.
|
* Request parameter to start resynchronization.
|
||||||
*
|
*
|
||||||
|
* @param imsi peer identity requesting quintuplet for
|
||||||
* @param in random value rand
|
* @param in random value rand
|
||||||
* @param auts resynchronization parameter auts
|
* @param auts resynchronization parameter auts
|
||||||
* @return TRUE if parameter generated successfully
|
* @return TRUE if parameter generated successfully
|
||||||
*/
|
*/
|
||||||
bool (*resync)(usim_card_t *this, char rand[16], char auts[16]);
|
bool (*resync)(usim_card_t *this, identification_t *imsi,
|
||||||
|
char rand[AKA_RAND_LEN], char auts[AKA_AUTS_LEN]);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user