Centralized SIM/AKA notifications and client errors
This commit is contained in:
@@ -108,6 +108,40 @@ ENUM_NEXT(simaka_attribute_names, AT_IV, AT_RESULT_IND, AT_CLIENT_ERROR_CODE,
|
|||||||
"AT_RESULT_IND");
|
"AT_RESULT_IND");
|
||||||
ENUM_END(simaka_attribute_names, AT_RESULT_IND);
|
ENUM_END(simaka_attribute_names, AT_RESULT_IND);
|
||||||
|
|
||||||
|
|
||||||
|
ENUM_BEGIN(simaka_notification_names, SIM_GENERAL_FAILURE_AA, SIM_GENERAL_FAILURE_AA,
|
||||||
|
"General failure after authentication");
|
||||||
|
ENUM_NEXT(simaka_notification_names, SIM_TEMP_DENIED, SIM_TEMP_DENIED, SIM_GENERAL_FAILURE_AA,
|
||||||
|
"User has been temporarily denied access");
|
||||||
|
ENUM_NEXT(simaka_notification_names, SIM_NOT_SUBSCRIBED, SIM_NOT_SUBSCRIBED, SIM_TEMP_DENIED,
|
||||||
|
"User has not subscribed to the requested service");
|
||||||
|
ENUM_NEXT(simaka_notification_names, SIM_GENERAL_FAILURE, SIM_GENERAL_FAILURE, SIM_NOT_SUBSCRIBED,
|
||||||
|
"General failure");
|
||||||
|
ENUM_NEXT(simaka_notification_names, SIM_SUCCESS, SIM_SUCCESS, SIM_GENERAL_FAILURE,
|
||||||
|
"User has been successfully authenticated");
|
||||||
|
ENUM_END(simaka_notification_names, SIM_SUCCESS);
|
||||||
|
|
||||||
|
|
||||||
|
ENUM(simaka_client_error_names, SIM_UNABLE_TO_PROCESS, SIM_RANDS_NOT_FRESH,
|
||||||
|
"unable to process packet",
|
||||||
|
"unsupported version",
|
||||||
|
"insufficient number of challenges",
|
||||||
|
"RANDs are not fresh",
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an EAP-SIM/AKA attribute is skippable
|
||||||
|
*/
|
||||||
|
bool simaka_attribute_skippable(simaka_attribute_t attribute)
|
||||||
|
{
|
||||||
|
bool skippable = !(attribute >= 0 && attribute <= 127);
|
||||||
|
|
||||||
|
DBG1(DBG_IKE, "%sskippable EAP-SIM/AKA attribute %N",
|
||||||
|
skippable ? "ignoring " : "found non-",
|
||||||
|
simaka_attribute_names, attribute);
|
||||||
|
return skippable;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private data of an simaka_message_t object.
|
* Private data of an simaka_message_t object.
|
||||||
*/
|
*/
|
||||||
@@ -278,7 +312,7 @@ static bool parse(private_simaka_message_t *this, simaka_crypto_t *crypto,
|
|||||||
in = chunk_skip(in, 4);
|
in = chunk_skip(in, 4);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* attributes with an additional actual-length */
|
/* attributes with an additional actual-length in bits or bytes */
|
||||||
case AT_NEXT_PSEUDONYM:
|
case AT_NEXT_PSEUDONYM:
|
||||||
case AT_NEXT_REAUTH_ID:
|
case AT_NEXT_REAUTH_ID:
|
||||||
if (!this->encrypted)
|
if (!this->encrypted)
|
||||||
@@ -286,6 +320,7 @@ static bool parse(private_simaka_message_t *this, simaka_crypto_t *crypto,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
/* FALL */
|
/* FALL */
|
||||||
|
case AT_RES:
|
||||||
case AT_IDENTITY:
|
case AT_IDENTITY:
|
||||||
case AT_VERSION_LIST:
|
case AT_VERSION_LIST:
|
||||||
{
|
{
|
||||||
@@ -297,6 +332,10 @@ static bool parse(private_simaka_message_t *this, simaka_crypto_t *crypto,
|
|||||||
}
|
}
|
||||||
memcpy(&len, in.ptr + 2, 2);
|
memcpy(&len, in.ptr + 2, 2);
|
||||||
len = ntohs(len);
|
len = ntohs(len);
|
||||||
|
if (hdr->type == AT_RES)
|
||||||
|
{ /* AT_RES uses length encoding in bits */
|
||||||
|
len /= 8;
|
||||||
|
}
|
||||||
if (len > hdr->length * 4 || len > in.len)
|
if (len > hdr->length * 4 || len > in.len)
|
||||||
{
|
{
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -313,7 +352,6 @@ static bool parse(private_simaka_message_t *this, simaka_crypto_t *crypto,
|
|||||||
}
|
}
|
||||||
/* FALL */
|
/* FALL */
|
||||||
case AT_AUTN:
|
case AT_AUTN:
|
||||||
case AT_RES:
|
|
||||||
case AT_NONCE_MT:
|
case AT_NONCE_MT:
|
||||||
case AT_IV:
|
case AT_IV:
|
||||||
case AT_MAC:
|
case AT_MAC:
|
||||||
@@ -449,20 +487,17 @@ static bool verify(private_simaka_message_t *this,
|
|||||||
case AKA_AUTHENTICATION_REJECT:
|
case AKA_AUTHENTICATION_REJECT:
|
||||||
case AKA_SYNCHRONIZATION_FAILURE:
|
case AKA_SYNCHRONIZATION_FAILURE:
|
||||||
case AKA_IDENTITY:
|
case AKA_IDENTITY:
|
||||||
{
|
/* skip MAC if available */
|
||||||
if (this->mac.ptr)
|
|
||||||
{ /* invalid if it contains a MAC */
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
|
||||||
case SIM_CHALLENGE:
|
case SIM_CHALLENGE:
|
||||||
/* AKA_CHALLENGE: */
|
case AKA_CHALLENGE:
|
||||||
case SIM_REAUTHENTICATION:
|
case SIM_REAUTHENTICATION:
|
||||||
/* AKA_REAUTHENTICATION: */
|
/* AKA_REAUTHENTICATION: */
|
||||||
{
|
{
|
||||||
if (!this->mac.ptr || !signer)
|
if (!this->mac.ptr || !signer)
|
||||||
{ /* require MAC, but not found */
|
{ /* require MAC, but not found */
|
||||||
|
DBG1(DBG_IKE, "%N message requires a MAC, but none found",
|
||||||
|
simaka_subtype_names, this->hdr->subtype);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -475,13 +510,17 @@ static bool verify(private_simaka_message_t *this,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
if (!this->mac.ptr || !signer)
|
if (!this->mac.ptr || !signer)
|
||||||
{ /* require MAC, but not found */
|
{
|
||||||
|
DBG1(DBG_IKE, "%N message has a phase 0 notify, but "
|
||||||
|
"no MAC found", simaka_subtype_names, this->hdr->subtype);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
/* unknown message? */
|
/* unknown message? */
|
||||||
|
DBG1(DBG_IKE, "signature rule for %N messages missing",
|
||||||
|
simaka_subtype_names, this->hdr->subtype);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -580,15 +619,20 @@ static eap_payload_t* generate(private_simaka_message_t *this,
|
|||||||
*target = chunk_skip(*target, 4);
|
*target = chunk_skip(*target, 4);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* attributes with an additional actual-length */
|
/* attributes with an additional actual-length in bits or bytes */
|
||||||
case AT_NEXT_PSEUDONYM:
|
case AT_NEXT_PSEUDONYM:
|
||||||
case AT_NEXT_REAUTH_ID:
|
case AT_NEXT_REAUTH_ID:
|
||||||
case AT_IDENTITY:
|
case AT_IDENTITY:
|
||||||
case AT_VERSION_LIST:
|
case AT_VERSION_LIST:
|
||||||
|
case AT_RES:
|
||||||
{
|
{
|
||||||
u_int16_t len, padding;
|
u_int16_t len, padding;
|
||||||
|
|
||||||
len = htons(data.len);
|
len = htons(data.len);
|
||||||
|
if (type == AT_RES)
|
||||||
|
{ /* AT_RES uses length encoding in bits */
|
||||||
|
len *= 8;
|
||||||
|
}
|
||||||
memcpy(target->ptr + 2, &len, sizeof(len));
|
memcpy(target->ptr + 2, &len, sizeof(len));
|
||||||
memcpy(target->ptr + 4, data.ptr, data.len);
|
memcpy(target->ptr + 4, data.ptr, data.len);
|
||||||
hdr->length = data.len / 4 + 1;
|
hdr->length = data.len / 4 + 1;
|
||||||
@@ -605,7 +649,6 @@ static eap_payload_t* generate(private_simaka_message_t *this,
|
|||||||
case AT_NONCE_S:
|
case AT_NONCE_S:
|
||||||
case AT_NONCE_MT:
|
case AT_NONCE_MT:
|
||||||
case AT_AUTN:
|
case AT_AUTN:
|
||||||
case AT_RES:
|
|
||||||
{
|
{
|
||||||
hdr->length = 5;
|
hdr->length = 5;
|
||||||
memset(target->ptr + 2, 0, 2);
|
memset(target->ptr + 2, 0, 2);
|
||||||
@@ -682,7 +725,7 @@ static eap_payload_t* generate(private_simaka_message_t *this,
|
|||||||
switch (this->hdr->subtype)
|
switch (this->hdr->subtype)
|
||||||
{
|
{
|
||||||
case SIM_CHALLENGE:
|
case SIM_CHALLENGE:
|
||||||
/* AKA_CHALLENGE: */
|
case AKA_CHALLENGE:
|
||||||
case SIM_REAUTHENTICATION:
|
case SIM_REAUTHENTICATION:
|
||||||
/* AKA_REAUTHENTICATION: */
|
/* AKA_REAUTHENTICATION: */
|
||||||
/* TODO: Notifications without P bit */
|
/* TODO: Notifications without P bit */
|
||||||
|
|||||||
@@ -29,6 +29,8 @@
|
|||||||
typedef struct simaka_message_t simaka_message_t;
|
typedef struct simaka_message_t simaka_message_t;
|
||||||
typedef enum simaka_attribute_t simaka_attribute_t;
|
typedef enum simaka_attribute_t simaka_attribute_t;
|
||||||
typedef enum simaka_subtype_t simaka_subtype_t;
|
typedef enum simaka_subtype_t simaka_subtype_t;
|
||||||
|
typedef enum simaka_notification_t simaka_notification_t;
|
||||||
|
typedef enum simaka_client_error_t simaka_client_error_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subtypes of EAP-SIM/AKA messages
|
* Subtypes of EAP-SIM/AKA messages
|
||||||
@@ -88,6 +90,66 @@ enum simaka_attribute_t {
|
|||||||
*/
|
*/
|
||||||
extern enum_name_t *simaka_attribute_names;
|
extern enum_name_t *simaka_attribute_names;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notification codes used within AT_NOTIFICATION attribute.
|
||||||
|
*/
|
||||||
|
enum simaka_notification_t {
|
||||||
|
/* SIM General failure after authentication. (Implies failure) */
|
||||||
|
SIM_GENERAL_FAILURE_AA = 0,
|
||||||
|
/* AKA General failure after authentication. (Implies failure) */
|
||||||
|
AKA_GENERAL_FAILURE_AA = 0,
|
||||||
|
/* SIM General failure. (Implies failure, used before authentication) */
|
||||||
|
SIM_GENERAL_FAILURE = 16384,
|
||||||
|
/* AKA General failure. (Implies failure, used before authentication) */
|
||||||
|
AKA_GENERAL_FAILURE = 16384,
|
||||||
|
/* SIM User has been temporarily denied access to the requested service. */
|
||||||
|
SIM_TEMP_DENIED = 1026,
|
||||||
|
/* AKA User has been temporarily denied access to the requested service. */
|
||||||
|
AKA_TEMP_DENIED = 1026,
|
||||||
|
/* SIM User has not subscribed to the requested service. */
|
||||||
|
SIM_NOT_SUBSCRIBED = 1031,
|
||||||
|
/* AKA User has not subscribed to the requested service. */
|
||||||
|
AKA_NOT_SUBSCRIBED = 1031,
|
||||||
|
/* SIM Success. User has been successfully authenticated. */
|
||||||
|
SIM_SUCCESS = 32768,
|
||||||
|
/* AKA Success. User has been successfully authenticated. */
|
||||||
|
AKA_SUCCESS = 32768,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum names for simaka_notification_t
|
||||||
|
*/
|
||||||
|
extern enum_name_t *simaka_notification_names;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error codes sent in AT_CLIENT_ERROR_CODE attribute
|
||||||
|
*/
|
||||||
|
enum simaka_client_error_t {
|
||||||
|
/* AKA unable to process packet */
|
||||||
|
AKA_UNABLE_TO_PROCESS = 0,
|
||||||
|
/* SIM unable to process packet */
|
||||||
|
SIM_UNABLE_TO_PROCESS = 0,
|
||||||
|
/* SIM unsupported version */
|
||||||
|
SIM_UNSUPPORTED_VERSION = 1,
|
||||||
|
/* SIM insufficient number of challenges */
|
||||||
|
SIM_INSUFFICIENT_CHALLENGES = 2,
|
||||||
|
/* SIM RANDs are not fresh */
|
||||||
|
SIM_RANDS_NOT_FRESH = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum names for simaka_client_error_t
|
||||||
|
*/
|
||||||
|
extern enum_name_t *simaka_client_error_names;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an EAP-SIM/AKA attribute is "skippable".
|
||||||
|
*
|
||||||
|
* @param attribute attribute to check
|
||||||
|
* @return TRUE if attribute skippable, FALSE if non-skippable
|
||||||
|
*/
|
||||||
|
bool simaka_attribute_skippable(simaka_attribute_t attribute);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EAP-SIM and EAP-AKA message abstraction.
|
* EAP-SIM and EAP-AKA message abstraction.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user