Commit 6855c4f9 authored by Lionel Gauthier's avatar Lionel Gauthier

encryption tested OK with EEA1 and NAS UE/CN from EURECOM: TO DO test with dongle in real time.

git-svn-id: http://svn.eurecom.fr/openair4G/trunk@5599 818b1a75-f10b-46b9-bf7c-635c3b92a50f
parent db3383e7
...@@ -77,7 +77,8 @@ static int _nas_message_plain_decode(const char* buffer, ...@@ -77,7 +77,8 @@ static int _nas_message_plain_decode(const char* buffer,
nas_message_plain_t* msg, int length); nas_message_plain_t* msg, int length);
static int _nas_message_protected_decode(const char* buffer, static int _nas_message_protected_decode(const char* buffer,
nas_message_security_header_t* header, nas_message_security_header_t* header,
nas_message_plain_t* msg, int length); nas_message_plain_t* msg, int length,
const emm_security_context_t * const emm_security_context);
/* Functions used to encode layer 3 NAS messages */ /* Functions used to encode layer 3 NAS messages */
static int _nas_message_header_encode(char* buffer, static int _nas_message_header_encode(char* buffer,
...@@ -99,7 +100,9 @@ static int _nas_message_decrypt( ...@@ -99,7 +100,9 @@ static int _nas_message_decrypt(
UInt8_t type, UInt8_t type,
UInt32_t code, UInt32_t code,
UInt8_t seq, UInt8_t seq,
int length); int length,
const emm_security_context_t * const emm_security_context);
static int static int
_nas_message_encrypt( _nas_message_encrypt(
...@@ -181,7 +184,7 @@ nas_message_encrypt( ...@@ -181,7 +184,7 @@ nas_message_encrypt(
/* Compute the NAS message authentication code */ /* Compute the NAS message authentication code */
UInt32_t mac = _nas_message_get_mac( UInt32_t mac = _nas_message_get_mac(
outbuf + offset, outbuf + offset,
length - offset, bytes + size - offset,
#ifdef NAS_MME #ifdef NAS_MME
SECU_DIRECTION_DOWNLINK, SECU_DIRECTION_DOWNLINK,
#else #else
...@@ -331,7 +334,8 @@ int nas_message_decrypt( ...@@ -331,7 +334,8 @@ int nas_message_decrypt(
header->security_header_type, header->security_header_type,
header->message_authentication_code, header->message_authentication_code,
header->sequence_number, header->sequence_number,
length - size); length - size,
emm_security_context);
bytes = length - size; bytes = length - size;
} }
else { else {
...@@ -418,13 +422,18 @@ int nas_message_decode( ...@@ -418,13 +422,18 @@ int nas_message_decode(
#endif #endif
/* Decode security protected NAS message */ /* Decode security protected NAS message */
bytes = _nas_message_protected_decode(buffer + size, &msg->header, bytes = _nas_message_protected_decode(buffer + size,
&msg->plain, length - size); &msg->header,
&msg->plain,
length - size,
emm_security_context);
} }
else { else {
/* Decode plain NAS message */ /* Decode plain NAS message */
bytes = _nas_message_plain_decode(buffer, &msg->header, bytes = _nas_message_plain_decode(buffer,
&msg->plain, length); &msg->header,
&msg->plain,
length);
} }
if (bytes < 0) { if (bytes < 0) {
...@@ -666,15 +675,15 @@ _nas_message_plain_decode( ...@@ -666,15 +675,15 @@ _nas_message_plain_decode(
/**************************************************************************** /****************************************************************************
** ** ** **
** Name: _nas_message_protected_decode() ** ** Name: _nas_message_protected_decode() **
** ** ** **
** Description: Decode security protected NAS message ** ** Description: Decode security protected NAS message **
** ** ** **
** Inputs: buffer: Pointer to the buffer containing the secu- ** ** Inputs: buffer: Pointer to the buffer containing the secu- **
** rity protected NAS message data ** ** rity protected NAS message data **
** header: Header of the security protected NAS mes- ** ** header: Header of the security protected NAS message **
** sage ** ** length: Number of bytes that should be decoded **
** length: Number of bytes that should be decoded ** ** emm_security_context: security context **
** Others: None ** ** Others: None **
** ** ** **
** Outputs: msg: Decoded NAS message ** ** Outputs: msg: Decoded NAS message **
...@@ -688,7 +697,8 @@ static int _nas_message_protected_decode( ...@@ -688,7 +697,8 @@ static int _nas_message_protected_decode(
const char *buffer, const char *buffer,
nas_message_security_header_t *header, nas_message_security_header_t *header,
nas_message_plain_t *msg, nas_message_plain_t *msg,
int length) int length,
const emm_security_context_t * const emm_security_context)
{ {
LOG_FUNC_IN; LOG_FUNC_IN;
...@@ -699,10 +709,13 @@ static int _nas_message_protected_decode( ...@@ -699,10 +709,13 @@ static int _nas_message_protected_decode(
{ {
/* Decrypt the security protected NAS message */ /* Decrypt the security protected NAS message */
header->protocol_discriminator = header->protocol_discriminator =
_nas_message_decrypt(plain_msg, buffer, _nas_message_decrypt(plain_msg,
buffer,
header->security_header_type, header->security_header_type,
header->message_authentication_code, header->message_authentication_code,
header->sequence_number, length); header->sequence_number,
length,
emm_security_context);
/* Decode the decrypted message as plain NAS message */ /* Decode the decrypted message as plain NAS message */
bytes = _nas_message_plain_decode(plain_msg, header, msg, length); bytes = _nas_message_plain_decode(plain_msg, header, msg, length);
free(plain_msg); free(plain_msg);
...@@ -820,20 +833,20 @@ static int _nas_message_plain_encode( ...@@ -820,20 +833,20 @@ static int _nas_message_plain_encode(
/**************************************************************************** /****************************************************************************
** ** ** **
** Name: _nas_message_protected_encode() ** ** Name: _nas_message_protected_encode() **
** ** ** **
** Description: Encode security protected NAS message ** ** Description: Encode security protected NAS message **
** ** ** **
** Inputs msg: Security protected NAS message structure ** ** Inputs msg: Security protected NAS message structure **
** to encode ** ** to encode **
** length: Maximal capacity of the output buffer ** ** length: Maximal capacity of the output buffer **
** Others: None ** ** Others: None **
** ** ** **
** Outputs: buffer: Pointer to the encoded data buffer ** ** Outputs: buffer: Pointer to the encoded data buffer **
** Return: The number of bytes in the buffer if the ** ** Return: The number of bytes in the buffer if the **
** data have been successfully encoded; ** ** data have been successfully encoded; **
** A negative error code otherwise. ** ** A negative error code otherwise. **
** Others: None ** ** Others: None **
** ** ** **
***************************************************************************/ ***************************************************************************/
static int _nas_message_protected_encode( static int _nas_message_protected_encode(
...@@ -889,7 +902,7 @@ static int _nas_message_protected_encode( ...@@ -889,7 +902,7 @@ static int _nas_message_protected_encode(
** Description: Decrypt security protected NAS message ** ** Description: Decrypt security protected NAS message **
** ** ** **
** Inputs src: Pointer to the encrypted data buffer ** ** Inputs src: Pointer to the encrypted data buffer **
** type: The security header type ** ** security_header_type: The security header type **
** code: The message authentication code ** ** code: The message authentication code **
** seq: The sequence number ** ** seq: The sequence number **
** length: Maximal capacity of the output buffer ** ** length: Maximal capacity of the output buffer **
...@@ -904,24 +917,140 @@ static int _nas_message_protected_encode( ...@@ -904,24 +917,140 @@ static int _nas_message_protected_encode(
static int _nas_message_decrypt( static int _nas_message_decrypt(
char *dest, char *dest,
const char *src, const char *src,
UInt8_t type, UInt8_t security_header_type,
UInt32_t code, UInt32_t code,
UInt8_t seq, UInt8_t seq,
int length) int length,
const emm_security_context_t * const emm_security_context)
{ {
nas_stream_cipher_t stream_cipher;
uint32_t count;
uint8_t direction;
LOG_FUNC_IN; LOG_FUNC_IN;
int size = 0; int size = 0;
nas_message_security_header_t header; nas_message_security_header_t header;
/* TODO: run the uncyphering algorithm */ #ifdef NAS_MME
memcpy(dest, src, length); direction = SECU_DIRECTION_UPLINK;
#else
direction = SECU_DIRECTION_DOWNLINK;
#endif
switch (security_header_type) {
case SECURITY_HEADER_TYPE_NOT_PROTECTED:
case SECURITY_HEADER_TYPE_SERVICE_REQUEST:
case SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED:
case SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED_NEW:
LOG_TRACE(DEBUG,
"No decryption of message according to security header type 0x%02x",
security_header_type);
memcpy(dest, src, length);
LOG_FUNC_RETURN (length);
break;
case SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED_CYPHERED:
case SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED_CYPHERED_NEW:
switch (emm_security_context->selected_algorithms.encryption) {
case NAS_SECURITY_ALGORITHMS_EEA1: {
if (direction == SECU_DIRECTION_UPLINK) {
count = 0x00000000 ||
((emm_security_context->ul_count.overflow && 0x0000FFFF) << 8) ||
(emm_security_context->ul_count.seq_num & 0x000000FF);
} else {
count = 0x00000000 ||
((emm_security_context->dl_count.overflow && 0x0000FFFF) << 8) ||
(emm_security_context->dl_count.seq_num & 0x000000FF);
}
LOG_TRACE(DEBUG,
"NAS_SECURITY_ALGORITHMS_EEA1 dir %s count.seq_num %u count %u",
(direction == SECU_DIRECTION_UPLINK) ? "UPLINK":"DOWNLINK",
(direction == SECU_DIRECTION_UPLINK) ? emm_security_context->ul_count.seq_num:emm_security_context->dl_count.seq_num,
count);
stream_cipher.key = emm_security_context->knas_enc.value;
stream_cipher.key_length = AUTH_KNAS_ENC_SIZE;
stream_cipher.count = count;
stream_cipher.bearer = 0x00; //33.401 section 8.1.1
stream_cipher.direction = direction;
stream_cipher.message = src;
/* length in bits */
stream_cipher.blength = length << 3;
nas_stream_encrypt_eea1(&stream_cipher, dest);
/* Decode the first octet (security header type or EPS bearer identity,
* and protocol discriminator) */
DECODE_U8(dest, *(UInt8_t*)(&header), size);
LOG_FUNC_RETURN (header.protocol_discriminator);
}break;
case NAS_SECURITY_ALGORITHMS_EEA2: {
if (direction == SECU_DIRECTION_UPLINK) {
count = 0x00000000 ||
((emm_security_context->ul_count.overflow && 0x0000FFFF) << 8) ||
(emm_security_context->ul_count.seq_num & 0x000000FF);
} else {
count = 0x00000000 ||
((emm_security_context->dl_count.overflow && 0x0000FFFF) << 8) ||
(emm_security_context->dl_count.seq_num & 0x000000FF);
}
LOG_TRACE(DEBUG,
"NAS_SECURITY_ALGORITHMS_EEA2 dir %s count.seq_num %u count %u",
(direction == SECU_DIRECTION_UPLINK) ? "UPLINK":"DOWNLINK",
(direction == SECU_DIRECTION_UPLINK) ? emm_security_context->ul_count.seq_num:emm_security_context->dl_count.seq_num,
count);
stream_cipher.key = emm_security_context->knas_enc.value;
stream_cipher.key_length = AUTH_KNAS_ENC_SIZE;
stream_cipher.count = count;
stream_cipher.bearer = 0x00; //33.401 section 8.1.1
stream_cipher.direction = direction;
stream_cipher.message = src;
/* length in bits */
stream_cipher.blength = length << 3;
nas_stream_encrypt_eea1(&stream_cipher, dest);
/* Decode the first octet (security header type or EPS bearer identity,
* and protocol discriminator) */
DECODE_U8(dest, *(UInt8_t*)(&header), size);
LOG_FUNC_RETURN (header.protocol_discriminator);
}break;
/* Decode the first octet (security header type or EPS bearer identity, case NAS_SECURITY_ALGORITHMS_EEA0:
* and protocol discriminator) */ LOG_TRACE(DEBUG,
DECODE_U8(src, *(UInt8_t*)(&header), size); "NAS_SECURITY_ALGORITHMS_EEA0 dir %d ul_count.seq_num %d dl_count.seq_num %d",
direction,
emm_security_context->ul_count.seq_num,
emm_security_context->dl_count.seq_num);
memcpy(dest, src, length);
/* Decode the first octet (security header type or EPS bearer identity,
* and protocol discriminator) */
DECODE_U8(dest, *(UInt8_t*)(&header), size);
LOG_FUNC_RETURN (header.protocol_discriminator);
break;
default:
LOG_TRACE(ERROR,
"Unknown Cyphering protection algorithm %d",
emm_security_context->selected_algorithms.encryption);
memcpy(dest, src, length);
/* Decode the first octet (security header type or EPS bearer identity,
* and protocol discriminator) */
DECODE_U8(dest, *(UInt8_t*)(&header), size);
LOG_FUNC_RETURN (header.protocol_discriminator);
break;
}
break;
default:
LOG_TRACE(ERROR,
"Unknown security header type %u", security_header_type);
LOG_FUNC_RETURN (0);
};
LOG_FUNC_RETURN (header.protocol_discriminator);
} }
/**************************************************************************** /****************************************************************************
...@@ -931,7 +1060,7 @@ static int _nas_message_decrypt( ...@@ -931,7 +1060,7 @@ static int _nas_message_decrypt(
** Description: Encrypt plain NAS message ** ** Description: Encrypt plain NAS message **
** ** ** **
** Inputs src: Pointer to the decrypted data buffer ** ** Inputs src: Pointer to the decrypted data buffer **
** type: The security header type ** ** security_header_type: The security header type **
** code: The message authentication code ** ** code: The message authentication code **
** seq: The sequence number ** ** seq: The sequence number **
** direction: The sequence number ** ** direction: The sequence number **
...@@ -948,13 +1077,15 @@ static int _nas_message_decrypt( ...@@ -948,13 +1077,15 @@ static int _nas_message_decrypt(
static int _nas_message_encrypt( static int _nas_message_encrypt(
char *dest, char *dest,
const char *src, const char *src,
UInt8_t type, UInt8_t security_header_type,
UInt32_t code, UInt32_t code,
UInt8_t seq, UInt8_t seq,
int const direction, int const direction,
int length, int length,
const emm_security_context_t * const emm_security_context) const emm_security_context_t * const emm_security_context)
{ {
nas_stream_cipher_t stream_cipher;
uint32_t count;
LOG_FUNC_IN; LOG_FUNC_IN;
if (!emm_security_context) { if (!emm_security_context) {
...@@ -963,46 +1094,103 @@ static int _nas_message_encrypt( ...@@ -963,46 +1094,103 @@ static int _nas_message_encrypt(
LOG_FUNC_RETURN (0); LOG_FUNC_RETURN (0);
} }
switch (emm_security_context->selected_algorithms.encryption) { switch (security_header_type) {
case SECURITY_HEADER_TYPE_NOT_PROTECTED:
case SECURITY_HEADER_TYPE_SERVICE_REQUEST:
case SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED:
case SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED_NEW:
LOG_TRACE(DEBUG,
"No encryption of message according to security header type 0x%02x",
security_header_type);
memcpy(dest, src, length);
LOG_FUNC_RETURN (length);
break;
case NAS_SECURITY_ALGORITHMS_EEA1: { case SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED_CYPHERED:
LOG_TRACE(WARNING, case SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED_CYPHERED_NEW:
"TODO NAS_SECURITY_ALGORITHMS_EEA1 dir %d ul_count.seq_num %d dl_count.seq_num %d", switch (emm_security_context->selected_algorithms.encryption) {
direction,
emm_security_context->ul_count.seq_num,
emm_security_context->dl_count.seq_num);
memcpy(dest, src, length);
LOG_FUNC_RETURN (length);
}break; case NAS_SECURITY_ALGORITHMS_EEA1: {
if (direction == SECU_DIRECTION_UPLINK) {
count = 0x00000000 ||
((emm_security_context->ul_count.overflow && 0x0000FFFF) << 8) ||
(emm_security_context->ul_count.seq_num & 0x000000FF);
} else {
count = 0x00000000 ||
((emm_security_context->dl_count.overflow && 0x0000FFFF) << 8) ||
(emm_security_context->dl_count.seq_num & 0x000000FF);
}
LOG_TRACE(DEBUG,
"NAS_SECURITY_ALGORITHMS_EEA1 dir %s count.seq_num %u count %u",
(direction == SECU_DIRECTION_UPLINK) ? "UPLINK":"DOWNLINK",
(direction == SECU_DIRECTION_UPLINK) ? emm_security_context->ul_count.seq_num:emm_security_context->dl_count.seq_num,
count);
stream_cipher.key = emm_security_context->knas_enc.value;
stream_cipher.key_length = AUTH_KNAS_ENC_SIZE;
stream_cipher.count = count;
stream_cipher.bearer = 0x00; //33.401 section 8.1.1
stream_cipher.direction = direction;
stream_cipher.message = src;
/* length in bits */
stream_cipher.blength = length << 3;
nas_stream_encrypt_eea1(&stream_cipher, dest);
case NAS_SECURITY_ALGORITHMS_EEA2: { LOG_FUNC_RETURN (length);
LOG_TRACE(WARNING,
"TODO NAS_SECURITY_ALGORITHMS_EEA2 dir %d ul_count.seq_num %d dl_count.seq_num %d",
direction,
emm_security_context->ul_count.seq_num,
emm_security_context->dl_count.seq_num);
memcpy(dest, src, length);
LOG_FUNC_RETURN (length);
}break; }break;
case NAS_SECURITY_ALGORITHMS_EEA0: case NAS_SECURITY_ALGORITHMS_EEA2: {
LOG_TRACE(DEBUG, if (direction == SECU_DIRECTION_UPLINK) {
"NAS_SECURITY_ALGORITHMS_EEA0 dir %d ul_count.seq_num %d dl_count.seq_num %d", count = 0x00000000 ||
direction, ((emm_security_context->ul_count.overflow && 0x0000FFFF) << 8) ||
emm_security_context->ul_count.seq_num, (emm_security_context->ul_count.seq_num & 0x000000FF);
emm_security_context->dl_count.seq_num); } else {
memcpy(dest, src, length); count = 0x00000000 ||
LOG_FUNC_RETURN (length); ((emm_security_context->dl_count.overflow && 0x0000FFFF) << 8) ||
(emm_security_context->dl_count.seq_num & 0x000000FF);
}
LOG_TRACE(DEBUG,
"NAS_SECURITY_ALGORITHMS_EEA2 dir %s count.seq_num %u count %u",
(direction == SECU_DIRECTION_UPLINK) ? "UPLINK":"DOWNLINK",
(direction == SECU_DIRECTION_UPLINK) ? emm_security_context->ul_count.seq_num:emm_security_context->dl_count.seq_num,
count);
stream_cipher.key = emm_security_context->knas_enc.value;
stream_cipher.key_length = AUTH_KNAS_ENC_SIZE;
stream_cipher.count = count;
stream_cipher.bearer = 0x00; //33.401 section 8.1.1
stream_cipher.direction = direction;
stream_cipher.message = src;
/* length in bits */
stream_cipher.blength = length << 3;
nas_stream_encrypt_eea2(&stream_cipher, dest);
break; LOG_FUNC_RETURN (length);
default: }break;
LOG_TRACE(ERROR,
"Unknown Cyphering protection algorithm %d", case NAS_SECURITY_ALGORITHMS_EEA0:
emm_security_context->selected_algorithms.encryption); LOG_TRACE(DEBUG,
break; "NAS_SECURITY_ALGORITHMS_EEA0 dir %d ul_count.seq_num %d dl_count.seq_num %d",
direction,
emm_security_context->ul_count.seq_num,
emm_security_context->dl_count.seq_num);
memcpy(dest, src, length);
LOG_FUNC_RETURN (length);
break;
default:
LOG_TRACE(ERROR,
"Unknown Cyphering protection algorithm %d",
emm_security_context->selected_algorithms.encryption);
break;
}
break;
default:
LOG_TRACE(ERROR,
"Unknown security header type %u", security_header_type);
LOG_FUNC_RETURN (0);
} }
LOG_FUNC_RETURN (length); LOG_FUNC_RETURN (length);
} }
......
...@@ -1144,15 +1144,15 @@ static int _security_select_algorithms( ...@@ -1144,15 +1144,15 @@ static int _security_select_algorithms(
LOG_FUNC_RETURN (rc); LOG_FUNC_RETURN (rc);
} }
if (ue_eeaP & (0x80 >> NAS_SECURITY_ALGORITHMS_EEA0)) { if (ue_eeaP & (0x80 >> NAS_SECURITY_ALGORITHMS_EEA1)) {
LOG_TRACE(DEBUG,"Selected NAS_SECURITY_ALGORITHMS_EEA1");
*mme_eeaP = NAS_SECURITY_ALGORITHMS_EEA1;
} else if (ue_eeaP & (0x80 >> NAS_SECURITY_ALGORITHMS_EEA0)) {
LOG_TRACE(DEBUG,"Selected NAS_SECURITY_ALGORITHMS_EEA0"); LOG_TRACE(DEBUG,"Selected NAS_SECURITY_ALGORITHMS_EEA0");
*mme_eeaP = NAS_SECURITY_ALGORITHMS_EEA0; *mme_eeaP = NAS_SECURITY_ALGORITHMS_EEA0;
} else if (ue_eeaP & (0x80 >> NAS_SECURITY_ALGORITHMS_EEA2)) { } else if (ue_eeaP & (0x80 >> NAS_SECURITY_ALGORITHMS_EEA2)) {
LOG_TRACE(DEBUG,"Selected NAS_SECURITY_ALGORITHMS_EEA2"); LOG_TRACE(DEBUG,"Selected NAS_SECURITY_ALGORITHMS_EEA2");
*mme_eeaP = NAS_SECURITY_ALGORITHMS_EEA2; *mme_eeaP = NAS_SECURITY_ALGORITHMS_EEA2;
} else if (ue_eeaP & (0x80 >> NAS_SECURITY_ALGORITHMS_EEA1)) {
LOG_TRACE(DEBUG,"Selected NAS_SECURITY_ALGORITHMS_EEA1");
*mme_eeaP = NAS_SECURITY_ALGORITHMS_EEA1;
} else { } else {
LOG_FUNC_RETURN (rc); LOG_FUNC_RETURN (rc);
} }
......
...@@ -120,7 +120,7 @@ int emm_msg_decode(EMM_msg *msg, uint8_t *buffer, uint32_t len) ...@@ -120,7 +120,7 @@ int emm_msg_decode(EMM_msg *msg, uint8_t *buffer, uint32_t len)
buffer += header_result; buffer += header_result;
len -= header_result; len -= header_result;
LOG_TRACE(INFO, "EMM-MSG - Message Type %02x", msg->header.message_type); LOG_TRACE(INFO, "EMM-MSG - Message Type 0x%02x", msg->header.message_type);
switch(msg->header.message_type) { switch(msg->header.message_type) {
case EMM_INFORMATION: case EMM_INFORMATION:
......
...@@ -60,7 +60,7 @@ Description Implements the utility used to generate data stored in the ...@@ -60,7 +60,7 @@ Description Implements the utility used to generate data stored in the
#define KSI USIM_KSI_NOT_AVAILABLE #define KSI USIM_KSI_NOT_AVAILABLE
#define KSI_ASME USIM_KSI_NOT_AVAILABLE #define KSI_ASME USIM_KSI_NOT_AVAILABLE
#define INT_ALGO USIM_INT_EIA1 #define INT_ALGO USIM_INT_EIA1
#define ENC_ALGO USIM_ENC_EEA0 #define ENC_ALGO USIM_ENC_EEA1
#define SECURITY_ALGORITHMS (ENC_ALGO | INT_ALGO) #define SECURITY_ALGORITHMS (ENC_ALGO | INT_ALGO)
#define MIN_TAC 0x0000 #define MIN_TAC 0x0000
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment