mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
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/thread-common.h"
|
||||
#include <openair3/NAS/NR_UE/nr_user_def.h>
|
||||
#include <openair3/NAS/gNB/network_process_nas.h>
|
||||
|
||||
// Raphael : missing
|
||||
pthread_cond_t nfapi_sync_cond;
|
||||
@@ -761,8 +762,14 @@ int main( int argc, char **argv ) {
|
||||
mlockall(MCL_CURRENT | MCL_FUTURE);
|
||||
|
||||
char * resp;
|
||||
nr_user_nas_t UErrc={0};
|
||||
int size=identityResponse(&resp, &UErrc);
|
||||
nr_user_nas_t UErrc={0};
|
||||
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) {
|
||||
load_softscope("nr",PHY_vars_UE_g[0][0]);
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
#include "NR_TAG.h"
|
||||
|
||||
#include <openair3/NAS/COMMON/NR_NAS_defs.h>
|
||||
#include <openair3/UICC/usim_interface.h>
|
||||
|
||||
|
||||
/* Defs */
|
||||
@@ -282,7 +283,8 @@ typedef struct NR_preamble_ue {
|
||||
} NR_preamble_ue;
|
||||
|
||||
typedef struct {
|
||||
boolean_t fiveG_connected;
|
||||
boolean_t fiveG_connected;
|
||||
uicc_t *uicc;
|
||||
} NRUEcontext_t;
|
||||
|
||||
/*! \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
|
||||
typedef enum {
|
||||
SGSsessionmanagementmessages=0x2e, //LTEbox: 0xC0 ???
|
||||
@@ -190,6 +202,12 @@ static const cause_text_info_t cause_secu_text_info[] = {
|
||||
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,
|
||||
//! Tasks id of each task
|
||||
typedef enum {
|
||||
@@ -226,7 +244,8 @@ typedef struct __attribute__((packed)) {
|
||||
Security_header_t sh:8;
|
||||
SGSmobilitymanagementmessages_t mt:8;
|
||||
uint16_t len;
|
||||
} Identityresponse_t;
|
||||
}
|
||||
Identityresponse_t;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
Identityresponse_t common;
|
||||
@@ -246,16 +265,24 @@ typedef struct __attribute__((packed)) {
|
||||
int protectScheme:4;
|
||||
int spare:4;
|
||||
uint8_t hplmnId;
|
||||
} IdentityresponseIMSI_t;
|
||||
|
||||
typedef struct {
|
||||
}
|
||||
IdentityresponseIMSI_t;
|
||||
|
||||
typedef struct __attribute__((packed)) {
|
||||
Extendedprotocoldiscriminator_t epd:8;
|
||||
Security_header_t sh:8;
|
||||
SGSmobilitymanagementmessages_t mt:8;
|
||||
int ngKSI:4;
|
||||
int spare:4;
|
||||
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 {
|
||||
Extendedprotocoldiscriminator_t epd:8;
|
||||
@@ -264,4 +291,5 @@ typedef struct {
|
||||
} authenticationresponseHeader_t;
|
||||
|
||||
|
||||
|
||||
//AUTHENTICATION RESULT
|
||||
|
||||
184
openair3/NAS/COMMON/aes.h
Normal file
184
openair3/NAS/COMMON/aes.h
Normal file
@@ -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
|
||||
337
openair3/NAS/COMMON/milenage.h
Normal file
337
openair3/NAS/COMMON/milenage.h
Normal file
@@ -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>
|
||||
|
||||
typedef struct {
|
||||
uicc_t * uicc;
|
||||
uicc_t *uicc;
|
||||
} nr_user_nas_t;
|
||||
|
||||
#define myCalloc(var, type) type * var=(type*)calloc(sizeof(type),1);
|
||||
|
||||
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");
|
||||
|
||||
// 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 respSize=sizeof(IdentityresponseIMSI_t) + (msinL+1)/2;
|
||||
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.len=htons(respSize-sizeof(Identityresponse_t));
|
||||
resp->mi=SUCI;
|
||||
resp->mcc1=UE->uicc->imsi[0]-'0';
|
||||
resp->mcc2=UE->uicc->imsi[1]-'0';
|
||||
resp->mcc3=UE->uicc->imsi[2]-'0';
|
||||
resp->mnc1=UE->uicc->imsi[3]-'0';
|
||||
resp->mnc2=UE->uicc->imsi[4]-'0';
|
||||
resp->mnc3=UE->uicc->nmc_size==2? 0xF : UE->uicc->imsi[3]-'0';
|
||||
resp->mcc1=UE->uicc->imsiStr[0]-'0';
|
||||
resp->mcc2=UE->uicc->imsiStr[1]-'0';
|
||||
resp->mcc3=UE->uicc->imsiStr[2]-'0';
|
||||
resp->mnc1=UE->uicc->imsiStr[3]-'0';
|
||||
resp->mnc2=UE->uicc->imsiStr[4]-'0';
|
||||
resp->mnc3=UE->uicc->nmc_size==2? 0xF : UE->uicc->imsiStr[3]-'0';
|
||||
// TBD: routing to fill (FF ?)
|
||||
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+=2;
|
||||
@@ -105,7 +105,6 @@ int identityResponse(void **msg, nr_user_nas_t *UE) {
|
||||
*out=((*(ptr-1)-'0')) | 0xF0;
|
||||
|
||||
*msg=resp;
|
||||
log_dump(NAS, resp, respSize, LOG_DUMP_CHAR, "\n");
|
||||
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) {
|
||||
}
|
||||
@@ -33,25 +35,29 @@ void processNAS(void *msg, NRUEcontext_t *UE) {
|
||||
SGSabortUE(msg, UE);
|
||||
else {
|
||||
switch (header->epd) {
|
||||
SGSmobilitymanagementmessages:
|
||||
|
||||
case SGSmobilitymanagementmessages:
|
||||
switch (header->mt) {
|
||||
Registrationrequest:
|
||||
case Registrationrequest:
|
||||
SGSregistrationReq(msg, UE);
|
||||
break;
|
||||
DeregistrationrequestUEoriginating:
|
||||
|
||||
case DeregistrationrequestUEoriginating:
|
||||
SGSderegistrationUEReq(msg, UE);
|
||||
break;
|
||||
Authenticationresponse:
|
||||
|
||||
case Authenticationresponse:
|
||||
SGSauthenticationResp(msg, UE);
|
||||
break;
|
||||
Identityresponse:
|
||||
|
||||
case Identityresponse:
|
||||
SGSidentityResp(msg, UE);
|
||||
break;
|
||||
Securitymodecomplete:
|
||||
|
||||
case Securitymodecomplete:
|
||||
SGSsecurityModeComplete(msg, UE);
|
||||
break;
|
||||
Registrationcomplete:
|
||||
|
||||
case Registrationcomplete:
|
||||
SGSregistrationComplete(msg, UE);
|
||||
break;
|
||||
|
||||
@@ -60,7 +66,8 @@ Registrationcomplete:
|
||||
}
|
||||
|
||||
break;
|
||||
SGSsessionmanagementmessages:
|
||||
|
||||
case SGSsessionmanagementmessages:
|
||||
SGSabortUE(msg, UE);
|
||||
break;
|
||||
|
||||
@@ -75,10 +82,60 @@ SGSsessionmanagementmessages:
|
||||
*/
|
||||
|
||||
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) {
|
||||
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) {
|
||||
*msg=NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
16
openair3/NAS/gNB/network_process_nas.h
Normal file
16
openair3/NAS/gNB/network_process_nas.h
Normal file
@@ -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 */
|
||||
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define UICC_PARAMS_DESC {\
|
||||
{"imsi", "USIM IMSI\n", 0, strptr:&(uicc->imsi), defstrval:"", TYPE_STRING, 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 },\
|
||||
{"opc", "USIM OPc\n", 0, strptr:&(uicc->opc), 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 },\
|
||||
{"key", "USIM Ki\n", 0, strptr:&(uicc->keyStr), 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 *uicc=(uicc_t *)calloc(sizeof(uicc_t),1);
|
||||
paramdef_t uicc_params[] = UICC_PARAMS_DESC;
|
||||
int ret = config_get( uicc_params,sizeof(uicc_params)/sizeof(paramdef_t),sectionName);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
#ifndef USIM_INTERFACE_H
|
||||
#define USIM_INTERFACE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
@@ -34,9 +36,15 @@
|
||||
#include "common_lib.h"
|
||||
|
||||
typedef struct {
|
||||
char *imsi;
|
||||
char *key;
|
||||
char *opc;
|
||||
char *imsiStr;
|
||||
char *keyStr;
|
||||
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;
|
||||
} uicc_t;
|
||||
|
||||
@@ -44,3 +52,4 @@ typedef struct {
|
||||
* Read the configuration file, section name variable to be able to manage several UICC
|
||||
*/
|
||||
uicc_t *init_uicc(char *sectionName);
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user