Commit 0ee578f4 authored by Laurent's avatar Laurent

add authentication request

parent 59964b0f
...@@ -86,6 +86,7 @@ unsigned short config_frames[4] = {2,9,11,13}; ...@@ -86,6 +86,7 @@ unsigned short config_frames[4] = {2,9,11,13};
#include "executables/softmodem-common.h" #include "executables/softmodem-common.h"
#include "executables/thread-common.h" #include "executables/thread-common.h"
#include <openair3/NAS/NR_UE/nr_user_def.h> #include <openair3/NAS/NR_UE/nr_user_def.h>
#include <openair3/NAS/gNB/network_process_nas.h>
// Raphael : missing // Raphael : missing
pthread_cond_t nfapi_sync_cond; pthread_cond_t nfapi_sync_cond;
...@@ -761,8 +762,14 @@ int main( int argc, char **argv ) { ...@@ -761,8 +762,14 @@ int main( int argc, char **argv ) {
mlockall(MCL_CURRENT | MCL_FUTURE); mlockall(MCL_CURRENT | MCL_FUTURE);
char * resp; char * resp;
nr_user_nas_t UErrc={0}; nr_user_nas_t UErrc={0};
int size=identityResponse(&resp, &UErrc); NRUEcontext_t UEnas={0};
int size=identityRequest((void**)&resp, &UEnas);
log_dump(NAS, resp, size, LOG_DUMP_CHAR," identity Request:\n" );;
size=identityResponse((void**)&resp, &UErrc);
log_dump(NAS, resp, size, LOG_DUMP_CHAR," identity Response:\n" );;
size=authenticationRequest((void**)&resp, &UEnas);
log_dump(NAS, resp, size, LOG_DUMP_CHAR," authentication request:\n" );;
if(IS_SOFTMODEM_DOFORMS) { if(IS_SOFTMODEM_DOFORMS) {
load_softscope("nr",PHY_vars_UE_g[0][0]); load_softscope("nr",PHY_vars_UE_g[0][0]);
......
...@@ -69,6 +69,7 @@ ...@@ -69,6 +69,7 @@
#include "NR_TAG.h" #include "NR_TAG.h"
#include <openair3/NAS/COMMON/NR_NAS_defs.h> #include <openair3/NAS/COMMON/NR_NAS_defs.h>
#include <openair3/UICC/usim_interface.h>
/* Defs */ /* Defs */
...@@ -282,7 +283,8 @@ typedef struct NR_preamble_ue { ...@@ -282,7 +283,8 @@ typedef struct NR_preamble_ue {
} NR_preamble_ue; } NR_preamble_ue;
typedef struct { typedef struct {
boolean_t fiveG_connected; boolean_t fiveG_connected;
uicc_t *uicc;
} NRUEcontext_t; } NRUEcontext_t;
/*! \brief UE list used by gNB to order UEs/CC for scheduling*/ /*! \brief UE list used by gNB to order UEs/CC for scheduling*/
......
/* TS 24.007 possible L3 formats:
Table 11.1: Formats of information elements
Format Meaning IEI present LI present Value part present
T Type only yes no no
V Value only no no yes
TV Type and Value yes no yes
LV Length and Value no yes yes
TLV Type, Length and Value yes yes yes
LV-E Length and Value no yes yes
TLV-E Type, Length and Value yes yes yes
*/
//TS 24.501, chap 9.2 => TS 24.007 //TS 24.501, chap 9.2 => TS 24.007
typedef enum { typedef enum {
SGSsessionmanagementmessages=0x2e, //LTEbox: 0xC0 ??? SGSsessionmanagementmessages=0x2e, //LTEbox: 0xC0 ???
...@@ -190,6 +202,12 @@ static const cause_text_info_t cause_secu_text_info[] = { ...@@ -190,6 +202,12 @@ static const cause_text_info_t cause_secu_text_info[] = {
FOREACH_CAUSE_SECU(CAUSE_TEXT) FOREACH_CAUSE_SECU(CAUSE_TEXT)
}; };
// IEI (information element identifier) are spread in each message definition
#define IEI_RAND 0x21
#define IEI_AUTN 0x20
#define IEI_EAP 0x78
#define IEI_AuthenticationResponse 0x2d
#define CAUSE_ENUM(LabEl, nUmID ) LabEl = nUmID, #define CAUSE_ENUM(LabEl, nUmID ) LabEl = nUmID,
//! Tasks id of each task //! Tasks id of each task
typedef enum { typedef enum {
...@@ -226,7 +244,8 @@ typedef struct __attribute__((packed)) { ...@@ -226,7 +244,8 @@ typedef struct __attribute__((packed)) {
Security_header_t sh:8; Security_header_t sh:8;
SGSmobilitymanagementmessages_t mt:8; SGSmobilitymanagementmessages_t mt:8;
uint16_t len; uint16_t len;
} Identityresponse_t; }
Identityresponse_t;
typedef struct __attribute__((packed)) { typedef struct __attribute__((packed)) {
Identityresponse_t common; Identityresponse_t common;
...@@ -246,16 +265,24 @@ typedef struct __attribute__((packed)) { ...@@ -246,16 +265,24 @@ typedef struct __attribute__((packed)) {
int protectScheme:4; int protectScheme:4;
int spare:4; int spare:4;
uint8_t hplmnId; uint8_t hplmnId;
} IdentityresponseIMSI_t; }
IdentityresponseIMSI_t;
typedef struct {
typedef struct __attribute__((packed)) {
Extendedprotocoldiscriminator_t epd:8; Extendedprotocoldiscriminator_t epd:8;
Security_header_t sh:8; Security_header_t sh:8;
SGSmobilitymanagementmessages_t mt:8; SGSmobilitymanagementmessages_t mt:8;
int ngKSI:4; int ngKSI:4;
int spare:4; int spare:4;
int ABBALen:8; int ABBALen:8;
} authenticationrequestHeader_t; int ABBA:16;
uint8_t ieiRAND;
uint8_t RAND[16];
uint8_t ieiAUTN;
uint8_t AUTNlen;
uint8_t AUTN[16];
}
authenticationrequestHeader_t;
typedef struct { typedef struct {
Extendedprotocoldiscriminator_t epd:8; Extendedprotocoldiscriminator_t epd:8;
...@@ -264,4 +291,5 @@ typedef struct { ...@@ -264,4 +291,5 @@ typedef struct {
} authenticationresponseHeader_t; } authenticationresponseHeader_t;
//AUTHENTICATION RESULT //AUTHENTICATION RESULT
#ifndef AES_H
#define EAS_H
// Implemented from Wikipedia description and OpenAir HSS
/*--------------------- Rijndael S box table ----------------------*/
static const uint8_t S[256] = {
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
};
/*------- This array does the multiplication by x in GF(2^8) ------*/
static const uint8_t Xtime[256] = {
0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94,
96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126,
128, 130, 132, 134, 136, 138, 140, 142, 144, 146, 148, 150, 152, 154, 156, 158,
160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, 184, 186, 188, 190,
192, 194, 196, 198, 200, 202, 204, 206, 208, 210, 212, 214, 216, 218, 220, 222,
224, 226, 228, 230, 232, 234, 236, 238, 240, 242, 244, 246, 248, 250, 252, 254,
27, 25, 31, 29, 19, 17, 23, 21, 11, 9, 15, 13, 3, 1, 7, 5,
59, 57, 63, 61, 51, 49, 55, 53, 43, 41, 47, 45, 35, 33, 39, 37,
91, 89, 95, 93, 83, 81, 87, 85, 75, 73, 79, 77, 67, 65, 71, 69,
123, 121, 127, 125, 115, 113, 119, 117, 107, 105, 111, 109, 99, 97, 103, 101,
155, 153, 159, 157, 147, 145, 151, 149, 139, 137, 143, 141, 131, 129, 135, 133,
187, 185, 191, 189, 179, 177, 183, 181, 171, 169, 175, 173, 163, 161, 167, 165,
219, 217, 223, 221, 211, 209, 215, 213, 203, 201, 207, 205, 195, 193, 199, 197,
251, 249, 255, 253, 243, 241, 247, 245, 235, 233, 239, 237, 227, 225, 231, 229
};
/*-------------------------------------------------------------------
Rijndael key schedule function. Takes 16-byte key and creates
all Rijndael's internal subkeys ready for encryption.
-----------------------------------------------------------------*/
static inline void RijndaelKeySchedule (const uint8_t key[16], uint8_t roundKeys[11][4][4]) {
//first round key equals key
for (int i = 0; i < 16; i++)
roundKeys[0][i & 0x03][i >> 2] = key[i];
//now calculate round keys
uint8_t roundConst = 1;
for (int i = 0; i < 10; i++) {
int next=i+1;
roundKeys[next][0][0] = S[roundKeys[i][1][3]]
^ roundKeys[i][0][0] ^ roundConst;
roundKeys[next][1][0] = S[roundKeys[i][2][3]]
^ roundKeys[i][1][0];
roundKeys[next][2][0] = S[roundKeys[i][3][3]]
^ roundKeys[i][2][0];
roundKeys[next][3][0] = S[roundKeys[i][0][3]]
^ roundKeys[i][3][0];
for (int j = 0; j < 4; j++) {
roundKeys[next][j][1] = roundKeys[i][j][1] ^ roundKeys[next][j][0];
roundKeys[next][j][2] = roundKeys[i][j][2] ^ roundKeys[next][j][1];
roundKeys[next][j][3] = roundKeys[i][j][3] ^ roundKeys[next][j][2];
}
roundConst = Xtime[roundConst];
}
return;
}
/* Round key addition function */
static inline void KeyAdd (uint8_t state[4][4], uint8_t roundKeys[11][4][4], int round) {
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
state[i][j] ^= roundKeys[round][i][j];
return;
}
/* Byte substitution transformation */
static inline void ByteSub (uint8_t state[4][4]) {
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
state[i][j] = S[state[i][j]];
return;
}
/* Row shift transformation */
static inline void ShiftRow (uint8_t state[4][4]) {
// left rotate row 1 by 1
uint8_t temp = state[1][0];
state[1][0] = state[1][1];
state[1][1] = state[1][2];
state[1][2] = state[1][3];
state[1][3] = temp;
//left rotate row 2 by 2
temp = state[2][0];
state[2][0] = state[2][2];
state[2][2] = temp;
temp = state[2][1];
state[2][1] = state[2][3];
state[2][3] = temp;
// left rotate row 3 by 3
temp = state[3][0];
state[3][0] = state[3][3];
state[3][3] = state[3][2];
state[3][2] = state[3][1];
state[3][1] = temp;
return;
}
/* MixColumn transformation*/
static inline void MixColumn ( uint8_t state[4][4]) {
// do one column at a time
for (int i = 0; i < 4; i++) {
uint8_t temp = state[0][i] ^ state[1][i] ^ state[2][i] ^ state[3][i];
uint8_t tmp0 = state[0][i];
// Xtime array does multiply by x in GF2^8
uint8_t tmp = Xtime[state[0][i] ^ state[1][i]];
state[0][i] ^= temp ^ tmp;
tmp = Xtime[state[1][i] ^ state[2][i]];
state[1][i] ^= temp ^ tmp;
tmp = Xtime[state[2][i] ^ state[3][i]];
state[2][i] ^= temp ^ tmp;
tmp = Xtime[state[3][i] ^ tmp0];
state[3][i] ^= temp ^ tmp;
}
return;
}
/*-------------------------------------------------------------------
Rijndael encryption function. Takes 16-byte input and creates
16-byte output (using round keys already derived from 16-byte
key).
-----------------------------------------------------------------*/
static inline void RijndaelEncrypt ( const uint8_t input[16], uint8_t output[16], uint8_t roundKeys[11][4][4]) {
uint8_t state[4][4];
int r;
// initialise state array from input byte string
for (int i = 0; i < 16; i++)
state[i & 0x3][i >> 2] = input[i];
// add first round_key
KeyAdd (state, roundKeys, 0);
// do lots of full rounds
for (r = 1; r <= 9; r++) {
ByteSub (state);
ShiftRow (state);
MixColumn (state);
KeyAdd (state, roundKeys, r);
}
// final round
ByteSub (state);
ShiftRow (state);
KeyAdd (state, roundKeys, r);
// produce output byte string from state array
for (int i = 0; i < 16; i++)
output[i] = state[i & 0x3][i >> 2];
return;
}
static inline void aes_128_encrypt_block(const uint8_t *key, const uint8_t *clear, uint8_t *cyphered) {
uint8_t roundKeys[11][4][4];
RijndaelKeySchedule(key, roundKeys);
RijndaelEncrypt (clear, cyphered, roundKeys);
}
#endif
/*
Adpatatipn of SW from hereafter license
Author: laurent.thomas@open-cells.com
*/
/*
3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
Copyright (c) 2006-2007 <j@w1.fi>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.
Alternatively, this software may be distributed under the terms of BSD
license.
See README and COPYING for more details.
This file implements an example authentication algorithm defined for 3GPP
AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow
EAP-AKA to be tested properly with real USIM cards.
This implementations assumes that the r1..r5 and c1..c5 constants defined in
TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00,
c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to
be AES (Rijndael).
*/
#ifndef MILENAGE_H
#define MILENAGE_H
#include <openair3/NAS/COMMON/aes.h>
#define u8 uint8_t
/**
milenage_f1 - Milenage f1 and f1* algorithms
@opc: OPc = 128-bit value derived from OP and K
@k: K = 128-bit subscriber key
@_rand: RAND = 128-bit random challenge
@sqn: SQN = 48-bit sequence number
@amf: AMF = 16-bit authentication management field
@mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL
@mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL
Returns: true on success, false on failure
*/
bool milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand,
const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s) {
u8 tmp1[16], tmp2[16], tmp3[16];
int i;
/* tmp1 = TEMP = E_K(RAND XOR OP_C) */
for (i = 0; i < 16; i++)
tmp1[i] = _rand[i] ^ opc[i];
aes_128_encrypt_block(k, tmp1, tmp1);
/* tmp2 = IN1 = SQN || AMF || SQN || AMF */
memcpy(tmp2, sqn, 6);
memcpy(tmp2 + 6, amf, 2);
memcpy(tmp2 + 8, tmp2, 8);
/* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */
/* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */
for (i = 0; i < 16; i++)
tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i];
/* XOR with TEMP = E_K(RAND XOR OP_C) */
for (i = 0; i < 16; i++)
tmp3[i] ^= tmp1[i];
/* XOR with c1 (= ..00, i.e., NOP) */
/* f1 || f1* = E_K(tmp3) XOR OP_c */
aes_128_encrypt_block(k, tmp3, tmp1);
for (i = 0; i < 16; i++)
tmp1[i] ^= opc[i];
if (mac_a)
memcpy(mac_a, tmp1, 8); /* f1 */
if (mac_s)
memcpy(mac_s, tmp1 + 8, 8); /* f1* */
return true;
}
/**
milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms
@opc: OPc = 128-bit value derived from OP and K
@k: K = 128-bit subscriber key
@_rand: RAND = 128-bit random challenge
@res: Buffer for RES = 64-bit signed response (f2), or %NULL
@ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
@ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
@ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL
@akstar: Buffer for AK = 48-bit anonymity key (f5*), or %NULL
Returns: true on success, false on failure
*/
bool milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand,
u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar) {
u8 tmp1[16], tmp2[16], tmp3[16];
int i;
/* tmp2 = TEMP = E_K(RAND XOR OP_C) */
for (i = 0; i < 16; i++)
tmp1[i] = _rand[i] ^ opc[i];
aes_128_encrypt_block(k, tmp1, tmp2);
/* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */
/* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */
/* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */
/* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */
/* f2 and f5 */
/* rotate by r2 (= 0, i.e., NOP) */
for (i = 0; i < 16; i++)
tmp1[i] = tmp2[i] ^ opc[i];
tmp1[15] ^= 1; /* XOR c2 (= ..01) */
/* f5 || f2 = E_K(tmp1) XOR OP_c */
aes_128_encrypt_block(k, tmp1, tmp3);
for (i = 0; i < 16; i++)
tmp3[i] ^= opc[i];
if (res)
memcpy(res, tmp3 + 8, 8); /* f2 */
if (ak)
memcpy(ak, tmp3, 6); /* f5 */
/* f3 */
if (ck) {
/* rotate by r3 = 0x20 = 4 bytes */
for (i = 0; i < 16; i++)
tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i];
tmp1[15] ^= 2; /* XOR c3 (= ..02) */
aes_128_encrypt_block(k, tmp1, ck);
for (i = 0; i < 16; i++)
ck[i] ^= opc[i];
}
/* f4 */
if (ik) {
/* rotate by r4 = 0x40 = 8 bytes */
for (i = 0; i < 16; i++)
tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i];
tmp1[15] ^= 4; /* XOR c4 (= ..04) */
aes_128_encrypt_block(k, tmp1, ik);
for (i = 0; i < 16; i++)
ik[i] ^= opc[i];
}
/* f5* */
if (akstar) {
/* rotate by r5 = 0x60 = 12 bytes */
for (i = 0; i < 16; i++)
tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i];
tmp1[15] ^= 8; /* XOR c5 (= ..08) */
aes_128_encrypt_block(k, tmp1, tmp1);
for (i = 0; i < 6; i++)
akstar[i] = tmp1[i] ^ opc[i];
}
return true;
}
/**
milenage_generate - Generate AKA AUTN,IK,CK,RES
@opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
@amf: AMF = 16-bit authentication management field
@k: K = 128-bit subscriber key
@sqn: SQN = 48-bit sequence number
@_rand: RAND = 128-bit random challenge
@autn: Buffer for AUTN = 128-bit authentication token
@ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
@ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
@res: Buffer for RES = 64-bit signed response (f2), or %NULL
@res_len: Max length for res; set to used length or 0 on failure
*/
bool milenage_generate(const u8 *opc, const u8 *amf, const u8 *k,
const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik,
u8 *ck, u8 *res) {
int i;
u8 mac_a[8], ak[6];
if (!milenage_f1(opc, k, _rand, sqn, amf, mac_a, NULL) ||
!milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL))
return false;
/* AUTN = (SQN ^ AK) || AMF || MAC */
for (i = 0; i < 6; i++)
autn[i] = sqn[i] ^ ak[i];
memcpy(autn + 6, amf, 2);
memcpy(autn + 8, mac_a, 8);
return true;
}
/**
milenage_auts - Milenage AUTS validation
@opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
@k: K = 128-bit subscriber key
@_rand: RAND = 128-bit random challenge
@auts: AUTS = 112-bit authentication token from client
@sqn: Buffer for SQN = 48-bit sequence number
Returns: 0 = success (sqn filled), -1 on failure
*/
#define p(a) printf("%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", (int)((a)[0]), (int)((a)[1]), (int)((a)[2]), (int)((a)[3]),(int)((a)[4]), (int)((a)[5]));
bool milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts,
u8 *sqn) {
u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
u8 ak[6], mac_s[8];
int i;
if (!milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
return false;
for (i = 0; i < 6; i++)
sqn[i] = auts[i] ^ ak[i];
//p(sqn);
if (!milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) ||
memcmp(mac_s, auts + 6, 8) != 0)
return false;
return true;
}
/**
gsm_milenage - Generate GSM-Milenage (3GPP TS 55.205) authentication triplet
@opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
@k: K = 128-bit subscriber key
@_rand: RAND = 128-bit random challenge
@sres: Buffer for SRES = 32-bit SRES
@kc: Buffer for Kc = 64-bit Kc
Returns: 0 on success, -1 on failure
*/
bool gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, u8 *kc) {
u8 res[8], ck[16], ik[16];
int i;
if (milenage_f2345(opc, k, _rand, res, ck, ik, NULL, NULL))
return false;
for (i = 0; i < 8; i++)
kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8];
#ifdef GSM_MILENAGE_ALT_SRES
memcpy(sres, res, 4);
#else /* GSM_MILENAGE_ALT_SRES */
for (i = 0; i < 4; i++)
sres[i] = res[i] ^ res[i + 4];
#endif /* GSM_MILENAGE_ALT_SRES */
return true;
}
/**
milenage_generate - Generate AKA AUTN,IK,CK,RES
@opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
@k: K = 128-bit subscriber key
@sqn: SQN = 48-bit sequence number
@_rand: RAND = 128-bit random challenge
@autn: AUTN = 128-bit authentication token
@ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
@ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
@res: Buffer for RES = 64-bit signed response (f2), or %NULL
@res_len: Variable that will be set to RES length
@auts: 112-bit buffer for AUTS
Returns: 0 on success, -1 on failure, or -2 on synchronization failure
*/
int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand,
const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len,
u8 *auts) {
int i;
u8 mac_a[8], ak[6], rx_sqn[6];
const u8 *amf;
if (milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL))
return -1;
*res_len = 8;
/* AUTN = (SQN ^ AK) || AMF || MAC */
for (i = 0; i < 6; i++)
rx_sqn[i] = autn[i] ^ ak[i];
if (memcmp(rx_sqn, sqn, 6) <= 0) {
u8 auts_amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
return -1;
for (i = 0; i < 6; i++)
auts[i] = sqn[i] ^ ak[i];
if (milenage_f1(opc, k, _rand, sqn, auts_amf, NULL, auts + 6))
return -1;
return -2;
}
amf = autn + 6;
if (milenage_f1(opc, k, _rand, rx_sqn, amf, mac_a, NULL))
return -1;
if (memcmp(mac_a, autn + 8, 8) != 0) {
printf( "Milenage: MAC mismatch\n");
return -1;
}
return 0;
}
void milenage_opc_gen(const u8 *k, const u8 *op, u8 *opc) {
int i;
/* Encrypt OP using K */
aes_128_encrypt_block(k, op, opc);
/* XOR the resulting Ek(OP) with OP */
for (i = 0; i < 16; i++)
opc[i] = opc[i] ^ op[i];
}
#endif
#ifndef NR_USER_DEF_H
#define NR_USER_DEF_H
#include <openair3/UICC/usim_interface.h> #include <openair3/UICC/usim_interface.h>
typedef struct { typedef struct {
uicc_t * uicc; uicc_t *uicc;
} nr_user_nas_t; } nr_user_nas_t;
#define myCalloc(var, type) type * var=(type*)calloc(sizeof(type),1);
int identityResponse(void **msg, nr_user_nas_t *UE); int identityResponse(void **msg, nr_user_nas_t *UE);
#endif
...@@ -76,7 +76,7 @@ int identityResponse(void **msg, nr_user_nas_t *UE) { ...@@ -76,7 +76,7 @@ int identityResponse(void **msg, nr_user_nas_t *UE) {
UE->uicc=init_uicc("uicc"); UE->uicc=init_uicc("uicc");
// TS 24.501 9.11.3.4 // TS 24.501 9.11.3.4
int imsiL=strlen(UE->uicc->imsi); int imsiL=strlen(UE->uicc->imsiStr);
int msinL=imsiL-3-UE->uicc->nmc_size; int msinL=imsiL-3-UE->uicc->nmc_size;
int respSize=sizeof(IdentityresponseIMSI_t) + (msinL+1)/2; int respSize=sizeof(IdentityresponseIMSI_t) + (msinL+1)/2;
IdentityresponseIMSI_t *resp=(IdentityresponseIMSI_t *) calloc(respSize,1); IdentityresponseIMSI_t *resp=(IdentityresponseIMSI_t *) calloc(respSize,1);
...@@ -85,17 +85,17 @@ int identityResponse(void **msg, nr_user_nas_t *UE) { ...@@ -85,17 +85,17 @@ int identityResponse(void **msg, nr_user_nas_t *UE) {
resp->common.mt=Identityresponse; resp->common.mt=Identityresponse;
resp->common.len=htons(respSize-sizeof(Identityresponse_t)); resp->common.len=htons(respSize-sizeof(Identityresponse_t));
resp->mi=SUCI; resp->mi=SUCI;
resp->mcc1=UE->uicc->imsi[0]-'0'; resp->mcc1=UE->uicc->imsiStr[0]-'0';
resp->mcc2=UE->uicc->imsi[1]-'0'; resp->mcc2=UE->uicc->imsiStr[1]-'0';
resp->mcc3=UE->uicc->imsi[2]-'0'; resp->mcc3=UE->uicc->imsiStr[2]-'0';
resp->mnc1=UE->uicc->imsi[3]-'0'; resp->mnc1=UE->uicc->imsiStr[3]-'0';
resp->mnc2=UE->uicc->imsi[4]-'0'; resp->mnc2=UE->uicc->imsiStr[4]-'0';
resp->mnc3=UE->uicc->nmc_size==2? 0xF : UE->uicc->imsi[3]-'0'; resp->mnc3=UE->uicc->nmc_size==2? 0xF : UE->uicc->imsiStr[3]-'0';
// TBD: routing to fill (FF ?) // TBD: routing to fill (FF ?)
char *out=(char *)(resp+1); char *out=(char *)(resp+1);
char *ptr=UE->uicc->imsi + 3 + UE->uicc->nmc_size; char *ptr=UE->uicc->imsiStr + 3 + UE->uicc->nmc_size;
while ( ptr < UE->uicc->imsi+strlen(UE->uicc->imsi) ) { while ( ptr < UE->uicc->imsiStr+strlen(UE->uicc->imsiStr) ) {
*out=((*(ptr+1)-'0')<<4) | (*(ptr) -'0'); *out=((*(ptr+1)-'0')<<4) | (*(ptr) -'0');
out++; out++;
ptr+=2; ptr+=2;
...@@ -105,7 +105,6 @@ int identityResponse(void **msg, nr_user_nas_t *UE) { ...@@ -105,7 +105,6 @@ int identityResponse(void **msg, nr_user_nas_t *UE) {
*out=((*(ptr-1)-'0')) | 0xF0; *out=((*(ptr-1)-'0')) | 0xF0;
*msg=resp; *msg=resp;
log_dump(NAS, resp, respSize, LOG_DUMP_CHAR, "\n");
return respSize; return respSize;
} }
......
#include <openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h> #include <openair3/NAS/NR_UE/nr_user_def.h>
#include <openair3/NAS/COMMON/milenage.h>
#include <openair3/NAS/gNB/network_process_nas.h>
void SGSabortUE(void *msg, NRUEcontext_t *UE) { void SGSabortUE(void *msg, NRUEcontext_t *UE) {
} }
...@@ -33,25 +35,29 @@ void processNAS(void *msg, NRUEcontext_t *UE) { ...@@ -33,25 +35,29 @@ void processNAS(void *msg, NRUEcontext_t *UE) {
SGSabortUE(msg, UE); SGSabortUE(msg, UE);
else { else {
switch (header->epd) { switch (header->epd) {
SGSmobilitymanagementmessages: case SGSmobilitymanagementmessages:
switch (header->mt) { switch (header->mt) {
Registrationrequest: case Registrationrequest:
SGSregistrationReq(msg, UE); SGSregistrationReq(msg, UE);
break; break;
DeregistrationrequestUEoriginating:
case DeregistrationrequestUEoriginating:
SGSderegistrationUEReq(msg, UE); SGSderegistrationUEReq(msg, UE);
break; break;
Authenticationresponse:
case Authenticationresponse:
SGSauthenticationResp(msg, UE); SGSauthenticationResp(msg, UE);
break; break;
Identityresponse:
case Identityresponse:
SGSidentityResp(msg, UE); SGSidentityResp(msg, UE);
break; break;
Securitymodecomplete:
case Securitymodecomplete:
SGSsecurityModeComplete(msg, UE); SGSsecurityModeComplete(msg, UE);
break; break;
Registrationcomplete:
case Registrationcomplete:
SGSregistrationComplete(msg, UE); SGSregistrationComplete(msg, UE);
break; break;
...@@ -60,7 +66,8 @@ Registrationcomplete: ...@@ -60,7 +66,8 @@ Registrationcomplete:
} }
break; break;
SGSsessionmanagementmessages:
case SGSsessionmanagementmessages:
SGSabortUE(msg, UE); SGSabortUE(msg, UE);
break; break;
...@@ -75,10 +82,60 @@ SGSsessionmanagementmessages: ...@@ -75,10 +82,60 @@ SGSsessionmanagementmessages:
*/ */
int identityRequest(void **msg, NRUEcontext_t *UE) { int identityRequest(void **msg, NRUEcontext_t *UE) {
myCalloc(req, Identityrequest_t);
req->epd=SGSmobilitymanagementmessages;
req->sh=0;
req->mt=Identityrequest;
req->it=SUCI;
*msg=req;
return sizeof(Identityrequest_t);
} }
int authenticationRequest(void **msg, NRUEcontext_t *UE) { int authenticationRequest(void **msg, NRUEcontext_t *UE) {
if (UE->uicc == NULL)
// config file section hardcoded as "uicc", nevertheless it opens to manage several UEs or a multi SIM UE
UE->uicc=init_uicc("uicc");
myCalloc(req, authenticationrequestHeader_t);
req->epd=SGSmobilitymanagementmessages;
req->sh=0;
req->mt=Authenticationrequest;
// native security context => bit 4 to 0
// probably from TS 33.501, table A-8.1
// N-NAS-int-alg (Native NAS integrity)
/*
N-NAS-enc-alg 0x01
N-NAS-int-alg 0x02
N-RRC-enc-alg 0x03
N-RRC-int-alg 0x04
N-UP-enc-alg 0x05
N-UP-int-alg 0x06
*/
req->ngKSI=2;
// TS 33.501, Annex A.7.1: Initial set of security features defined for 5GS.
req->ABBALen=2;
req->ABBA=0;
//rand (TV)
req->ieiRAND=IEI_RAND;
FILE *h=fopen("/dev/random","r");
if ( sizeof(req->RAND) != fread(req->RAND,1,sizeof(req->RAND),h) )
LOG_E(NAS, "can't read /dev/random\n");
fclose(h);
// challenge/AUTN (TLV)
req->ieiAUTN=IEI_AUTN;
req->AUTNlen=sizeof(req->AUTN);
uint8_t ik[16], ck[16], res[8];
milenage_generate(UE->uicc->opc, UE->uicc->amf, UE->uicc->key,
UE->uicc->sqn, req->RAND, req->AUTN, ik, ck, res);
// EAP message (TLV-E)
// not developped
*msg=req;
return sizeof(authenticationrequestHeader_t);
} }
int securityModeCommand(void **msg, NRUEcontext_t *UE) { int securityModeCommand(void **msg, NRUEcontext_t *UE) {
*msg=NULL;
return 0;
} }
#ifndef NET_PROCESS_NAS_H
#define NET_PROCESS_NAS_H
#include <openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h>
void SGSabortUE(void *msg, NRUEcontext_t *UE) ;
void SGSregistrationReq(void *msg, NRUEcontext_t *UE);
void SGSderegistrationUEReq(void *msg, NRUEcontext_t *UE);
void SGSauthenticationResp(void *msg, NRUEcontext_t *UE);
void SGSidentityResp(void *msg, NRUEcontext_t *UE);
void SGSsecurityModeComplete(void *msg, NRUEcontext_t *UE);
void SGSregistrationComplete(void *msg, NRUEcontext_t *UE);
void processNAS(void *msg, NRUEcontext_t *UE);
int identityRequest(void **msg, NRUEcontext_t *UE);
int authenticationRequest(void **msg, NRUEcontext_t *UE);
int securityModeCommand(void **msg, NRUEcontext_t *UE);
#endif
...@@ -33,18 +33,38 @@ ...@@ -33,18 +33,38 @@
/* optname helpstr paramflags XXXptr defXXXval type numelt */ /* optname helpstr paramflags XXXptr defXXXval type numelt */
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
#define UICC_PARAMS_DESC {\ #define UICC_PARAMS_DESC {\
{"imsi", "USIM IMSI\n", 0, strptr:&(uicc->imsi), defstrval:"", TYPE_STRING, 0 },\ {"imsi", "USIM IMSI\n", 0, strptr:&(uicc->imsiStr), defstrval:"", TYPE_STRING, 0 },\
{"nmc_size" "number of digits in NMC", 0, iptr:&(uicc->nmc_size), defintval:2, TYPE_INT, 0 },\ {"nmc_size" "number of digits in NMC", 0, iptr:&(uicc->nmc_size), defintval:2, TYPE_INT, 0 },\
{"key", "USIM Ki\n", 0, strptr:&(uicc->key), defstrval:"", TYPE_STRING, 0 },\ {"key", "USIM Ki\n", 0, strptr:&(uicc->keyStr), defstrval:"", TYPE_STRING, 0 },\
{"opc", "USIM OPc\n", 0, strptr:&(uicc->opc), defstrval:"", TYPE_STRING, 0 },\ {"opc", "USIM OPc\n", 0, strptr:&(uicc->opcStr), defstrval:"", TYPE_STRING, 0 },\
{"amf", "USIM amf\n", 0, strptr:&(uicc->amfStr), defstrval:"8000", TYPE_STRING, 0 },\
{"sqn", "USIM sqn\n", 0, strptr:&(uicc->sqnStr), defstrval:"000000", TYPE_STRING, 0 },\
}; };
const char *hexTable="0123456789abcdef";
static inline void to_hex(char *in, uint8_t *out, bool swap) {
if (swap)
for (size_t i=0; in[i]!=0; i++) {
out+=hexTable[in[i] & 0xf];
out+=hexTable[in[i]>>4 & 0xf];
} else {
for (size_t i=0; in[i]!=0; i++) {
out+=hexTable[in[i]>>4 & 0xf];
out+=hexTable[in[i] & 0xf];
}
}
}
uicc_t *init_uicc(char *sectionName) { uicc_t *init_uicc(char *sectionName) {
uicc_t *uicc=(uicc_t *)calloc(sizeof(uicc_t),1); uicc_t *uicc=(uicc_t *)calloc(sizeof(uicc_t),1);
paramdef_t uicc_params[] = UICC_PARAMS_DESC; paramdef_t uicc_params[] = UICC_PARAMS_DESC;
int ret = config_get( uicc_params,sizeof(uicc_params)/sizeof(paramdef_t),sectionName); int ret = config_get( uicc_params,sizeof(uicc_params)/sizeof(paramdef_t),sectionName);
AssertFatal(ret >= 0, "configuration couldn't be performed"); AssertFatal(ret >= 0, "configuration couldn't be performed");
LOG_I(HW, "UICC simulation: IMSI=%s, Ki=%s, OPc=%s\n", uicc->imsi, uicc->key, uicc->opc); LOG_I(HW, "UICC simulation: IMSI=%s, Ki=%s, OPc=%s\n", uicc->imsiStr, uicc->keyStr, uicc->opcStr);
to_hex(uicc->keyStr,uicc->key, false);
to_hex(uicc->opcStr,uicc->opc, false);
to_hex(uicc->sqnStr,uicc->sqn, false);
to_hex(uicc->amfStr,uicc->amf, false);
return uicc; return uicc;
} }
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
* For more information about the OpenAirInterface (OAI) Software Alliance: * For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org * contact@openairinterface.org
*/ */
#ifndef USIM_INTERFACE_H
#define USIM_INTERFACE_H
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
...@@ -34,9 +36,15 @@ ...@@ -34,9 +36,15 @@
#include "common_lib.h" #include "common_lib.h"
typedef struct { typedef struct {
char *imsi; char *imsiStr;
char *key; char *keyStr;
char *opc; char *opcStr;
char *amfStr;
char *sqnStr;
uint8_t key[16];
uint8_t opc[16];
uint8_t amf[2];
uint8_t sqn[6];
int nmc_size; int nmc_size;
} uicc_t; } uicc_t;
...@@ -44,3 +52,4 @@ typedef struct { ...@@ -44,3 +52,4 @@ typedef struct {
* Read the configuration file, section name variable to be able to manage several UICC * Read the configuration file, section name variable to be able to manage several UICC
*/ */
uicc_t *init_uicc(char *sectionName); uicc_t *init_uicc(char *sectionName);
#endif
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