add authentication request
This commit is contained in:
@@ -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 ) {
|
|||||||
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 @@
|
|||||||
#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 {
|
|||||||
} 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*/
|
||||||
|
|||||||
@@ -1,4 +1,16 @@
|
|||||||
|
|
||||||
|
/* 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[] = {
|
|||||||
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)) {
|
|||||||
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)) {
|
|||||||
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 {
|
|||||||
} authenticationresponseHeader_t;
|
} authenticationresponseHeader_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//AUTHENTICATION RESULT
|
//AUTHENTICATION RESULT
|
||||||
|
|||||||
@@ -0,0 +1,184 @@
|
|||||||
|
#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
|
||||||
@@ -0,0 +1,337 @@
|
|||||||
|
/*
|
||||||
|
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
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
|
#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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
*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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#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) {
|
|||||||
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:
|
|||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
SGSsessionmanagementmessages:
|
|
||||||
|
case SGSsessionmanagementmessages:
|
||||||
SGSabortUE(msg, UE);
|
SGSabortUE(msg, UE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#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 @@
|
|||||||
/* 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 @@
|
|||||||
* 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 @@
|
|||||||
#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 {
|
|||||||
* 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
|
||||||
|
|||||||
Reference in New Issue
Block a user